JPS mappings for incremental compilation refactoring: kotlin-nullability rules

GitOrigin-RevId: e7e1a379817130ec993ef344c6ee356b6e2aedc6
This commit is contained in:
Eugene Zhuravlev
2023-12-21 17:50:16 +01:00
committed by intellij-monorepo-bot
parent 72804c4018
commit aaa7098aab
10 changed files with 104 additions and 12 deletions

View File

@@ -0,0 +1,18 @@
<component name="libraryTable">
<library name="jetbrains.kotlinx.metadata.jvm" type="repository">
<properties include-transitive-deps="false" maven-id="org.jetbrains.kotlinx:kotlinx-metadata-jvm:0.8.0">
<verification>
<artifact url="file://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-metadata-jvm/0.8.0/kotlinx-metadata-jvm-0.8.0.jar">
<sha256sum>6030de49e7fc2ca8009e1221213035694b97494044aa99bcfb0c8e0e73984d4d</sha256sum>
</artifact>
</verification>
</properties>
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-metadata-jvm/0.8.0/kotlinx-metadata-jvm-0.8.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-metadata-jvm/0.8.0/kotlinx-metadata-jvm-0.8.0-sources.jar!/" />
</SOURCES>
</library>
</component>

View File

@@ -78,7 +78,7 @@ suspend fun buildCommunityStandaloneJpsBuilder(targetDir: Path,
"jna", "OroMatcher", "ASM", "protobuf", "cli-parser", "Log4J", "jgoodies-forms", "Eclipse",
"netty-codec-http", "lz4-java", "commons-codec", "commons-logging", "http-client", "slf4j-api", "plexus-utils",
"jetbrains-annotations", "gson", "jps-javac-extension", "fastutil-min", "kotlin-stdlib",
"commons-lang3", "maven-resolver-provider", "netty-buffer", "aalto-xml", "caffeine"
"commons-lang3", "maven-resolver-provider", "netty-buffer", "aalto-xml", "caffeine", "jetbrains.kotlinx.metadata.jvm"
)) {
layout.withProjectLibrary(it, LibraryPackMode.STANDALONE_MERGED)
}

View File

@@ -69,5 +69,7 @@
<orderEntry type="module" module-name="intellij.platform.runtime.repository" />
<orderEntry type="module" module-name="intellij.platform.util.zip" />
<orderEntry type="library" name="caffeine" level="project" />
<orderEntry type="library" name="jetbrains.kotlinx.metadata.jvm" level="project" />
<orderEntry type="library" scope="PROVIDED" name="kotlin-stdlib" level="project" />
</component>
</module>

View File

@@ -23,6 +23,7 @@ import io.netty.channel.EventLoopGroup;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.resolver.AddressResolverGroup;
import io.netty.util.NetUtil;
import kotlinx.metadata.jvm.JvmMetadataUtil;
import net.n3.nanoxml.IXMLBuilder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -38,7 +39,8 @@ import org.jetbrains.jps.model.serialization.JpsProjectLoader;
import org.jetbrains.org.objectweb.asm.ClassVisitor;
import org.jetbrains.org.objectweb.asm.ClassWriter;
import javax.tools.*;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -112,6 +114,7 @@ public final class ClasspathBootstrap {
addToClassPath(cp, ClassPathUtil.getUtilClasses());
ClassPathUtil.addKotlinStdlib(cp);
addToClassPath(JvmMetadataUtil.class, cp); // kotlin metadata parsing
addToClassPath(cp, COMMON_REQUIRED_CLASSES);
addToClassPath(ClassWriter.class, cp); // asm

View File

@@ -5,6 +5,12 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Ref;
import com.intellij.util.ArrayUtil;
import com.intellij.util.SmartList;
import kotlinx.metadata.Attributes;
import kotlinx.metadata.KmClass;
import kotlinx.metadata.KmFunction;
import kotlinx.metadata.KmValueParameter;
import kotlinx.metadata.jvm.JvmExtensionsKt;
import kotlinx.metadata.jvm.JvmMethodSignature;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.dependency.NodeBuilder;
@@ -559,6 +565,12 @@ public final class JvmClassNodeBuilder extends ClassVisitor implements NodeBuild
};
}
private KmClass findKmClass() {
KotlinMeta meta = (KotlinMeta)Iterators.find(myMetadata, md-> md instanceof KotlinMeta);
return meta != null? meta.getKmClass() : null;
}
@Override
public MethodVisitor visitMethod(final int access, final String n, final String desc, final String signature, final String[] exceptions) {
final Ref<Object> defaultValue = Ref.create();
@@ -570,6 +582,25 @@ public final class JvmClassNodeBuilder extends ClassVisitor implements NodeBuild
@Override
public void visitEnd() {
if ((access & Opcodes.ACC_SYNTHETIC) == 0 || (access & Opcodes.ACC_BRIDGE) > 0) {
KmClass kmClass = findKmClass();
if (kmClass != null) {
KmFunction func = Iterators.find(kmClass.getFunctions(), f -> {
JvmMethodSignature sign = JvmExtensionsKt.getSignature(f);
return sign != null && n.equals(sign.getName()) && desc.equals(sign.getDescriptor());
});
if (func != null) {
if (Attributes.isNullable(func.getReturnType())) {
annotations.add(KotlinMeta.KOTLIN_NULLABLE);
}
int paramIndex = 0;
for (KmValueParameter parameter : func.getValueParameters()) {
if (Attributes.isNullable(parameter.getType())) {
paramAnnotations.add(new ParamAnnotation(paramIndex, KotlinMeta.KOTLIN_NULLABLE));
}
paramIndex++;
}
}
}
myMethods.add(new JvmMethod(new JVMFlags(access), signature, n, desc, annotations, paramAnnotations, Iterators.asIterable(exceptions), defaultValue.get()));
}
}

View File

@@ -1,6 +1,9 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.jps.dependency.java;
import kotlinx.metadata.KmClass;
import kotlinx.metadata.jvm.KotlinClassHeader;
import kotlinx.metadata.jvm.KotlinClassMetadata;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.dependency.GraphDataInput;
@@ -15,6 +18,8 @@ import java.util.Arrays;
* The created annotation instance can be further introspected with <a href="https://github.com/JetBrains/kotlin/tree/master/libraries/kotlinx-metadata/jvm">kotlinx-metadata-jvm</a> library
*/
public final class KotlinMeta implements JvmMetadata {
public static final TypeRepr.ClassType KOTLIN_NULLABLE = new TypeRepr.ClassType("org/jetbrains/annotations/depgraph/KotlinNullable");
private static final String[] EMPTY_STRING_ARRAY = new String[0];
private static final int[] EMPTY_INT_ARRAY = new int[0];
@@ -98,4 +103,26 @@ public final class KotlinMeta implements JvmMetadata {
public Integer getExtraInt() {
return myExtraInt;
}
private KotlinClassMetadata[] myKmClass; // cached
public KotlinClassMetadata getClassMetadata() {
if (myKmClass == null) {
try {
myKmClass = new KotlinClassMetadata[] {KotlinClassMetadata.readLenient(new KotlinClassHeader(
getKind(), getVersion(), getData1(), getData2(), getExtraString(), getPackageName(), getExtraInt()
))};
}
catch (Throwable e) {
myKmClass = new KotlinClassMetadata[] {null};
}
}
return myKmClass[0];
}
public KmClass getKmClass() {
KotlinClassMetadata classMetadata = getClassMetadata();
return classMetadata instanceof KotlinClassMetadata.Class? ((KotlinClassMetadata.Class)classMetadata).getKmClass() : null;
}
}

View File

@@ -73,6 +73,19 @@ public final class KotlinAwareJavaDifferentiateStrategy extends JvmDifferentiate
return true;
}
@Override
public boolean processChangedMethod(DifferentiateContext context, JvmClass changedClass, Difference.Change<JvmMethod, JvmMethod.Diff> change, Utils future, Utils present) {
if (
find(change.getDiff().paramAnnotations().removed(), annot -> KotlinMeta.KOTLIN_NULLABLE.equals(annot.type)) != null ||
find(change.getDiff().annotations().added(), annot -> KotlinMeta.KOTLIN_NULLABLE.equals(annot)) != null) {
JvmMethod changedMethod = change.getPast();
debug("One of method's parameters or method's return value has become non-nullable; affecting method usages ", changedMethod);
affectMemberUsages(context, changedClass.getReferenceID(), changedMethod, future.collectSubclassesWithoutMethod(changedClass.getReferenceID(), changedMethod));
}
return true;
}
private static void affectConflictingExtensionMethods(DifferentiateContext context, JvmClass cls, JvmMethod clsMethod, @Nullable TypeRepr.ClassType samType, Utils utils) {
if (clsMethod.isPrivate() || clsMethod.isConstructor()) {
return;

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@file:Suppress("ReplaceJavaStaticMethodWithKotlinAnalog")
package org.jetbrains.intellij.build
@@ -636,6 +636,10 @@ object CommunityLibraryLicenses {
url = "https://github.com/JetBrains/jediterm",
licenseUrl = "https://github.com/JetBrains/jediterm/blob/master/LICENSE-LGPLv3.txt")
.suppliedByOrganizations(Suppliers.JETBRAINS),
LibraryLicense(name = "jetbrains.kotlinx.metadata.jvm", libraryName = "jetbrains.kotlinx.metadata.jvm",
url = "https://github.com/JetBrains/kotlin")
.apache("https://github.com/JetBrains/kotlin/blob/master/license/LICENSE.txt")
.suppliedByOrganizations(Suppliers.JETBRAINS),
LibraryLicense(name = "JetBrains Annotations", libraryName = "jetbrains-annotations",
url = "https://github.com/JetBrains/java-annotations")
.apache("https://github.com/JetBrains/java-annotations/blob/master/LICENSE.txt"),

View File

@@ -92,6 +92,7 @@ object JavaPluginLayout {
// used in JPS - do not use uber jar
spec.withProjectLibrary("jgoodies-common", LibraryPackMode.STANDALONE_MERGED)
spec.withProjectLibrary("jps-javac-extension", LibraryPackMode.STANDALONE_MERGED)
spec.withProjectLibrary("jetbrains.kotlinx.metadata.jvm", LibraryPackMode.STANDALONE_MERGED)
// gpl-cpe license - do not use uber jar
spec.withProjectLibrary("jb-jdi", LibraryPackMode.STANDALONE_MERGED)

View File

@@ -7,24 +7,18 @@ End of files
Compiling files:
src/A.kt
End of files
After build round. Marked as dirty by Kotlin:
src/AChild.kt
src/useAChild.kt
Exit code: ADDITIONAL_PASS_REQUIRED
Exit code: OK
------------------------------------------
Cleaning output files:
out/production/module/META-INF/module.kotlin_module
out/production/module/foo/AChild.class
out/production/module/foo/UseAChildKt.class
End of files
Compiling files:
src/AChild.kt
src/useAChild.kt
End of files
Exit code: ABORT
------------------------------------------
COMPILATION FAILED
Null can not be a value of a non-null type Any
================ Step #2 =================
@@ -33,8 +27,7 @@ Cleaning output files:
End of files
Compiling files:
src/A.kt
src/AChild.kt
src/useAChild.kt
End of files
Exit code: OK
------------------------------------------
------------------------------------------