From d022bb0248a3f199ea0bc671b93dc30c5052c292 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Thu, 21 Jan 2021 17:12:46 +0100 Subject: [PATCH 001/260] Switch default JVM target to 1.8 #KT-29405 Fixed --- .../OriginCollectingClassBuilderFactory.kt | 4 +- .../arguments/K2JVMCompilerArguments.kt | 2 +- .../org/jetbrains/kotlin/config/JvmTarget.kt | 2 +- .../FirBlackBoxCodegenTestGenerated.java | 12 ++++ .../codegen/FirBytecodeTextTestGenerated.java | 12 +++- .../ultraLightClasses/typeAnnotations.java | 14 ++-- compiler/testData/cli/jvm/help.out | 2 +- .../box/annotations/typeAnnotationOnJdk6.kt | 1 + .../callWithIncorrectNumberOfArguments_1_6.kt | 71 +++++++++++++++++++ .../annotations/onTypes/arrayKClass.kt | 1 + .../codegen/box/super/interfaceHashCode.kt | 1 - .../box/super/interfaceHashCode_1_6.kt | 11 +++ .../boxingOptimization/hashCodeOnNonNull.kt | 11 +++ .../bytecodeText/boxingOptimization/kt7224.kt | 2 +- .../boxingOptimization/unsafeRemoving.kt | 5 +- .../hashCode/{hashCode.kt => hashCode_1_6.kt} | 2 + .../skipCallToUnderlyingValueOfInlineClass.kt | 6 +- .../unsignedIntCompare_before.kt | 1 + .../wrongInlineTarget/output.txt | 36 +++++----- .../wrongInlineTarget/warningsOnly_1_3.txt | 12 ++-- .../diagnostics/tests/generics/kt9203.fir.kt | 11 --- .../diagnostics/tests/generics/kt9203.kt | 4 +- .../tests/j+k/defaultMethods.fir.kt | 1 + .../diagnostics/tests/j+k/defaultMethods.kt | 1 + .../defaultMethodsIndirectInheritance.fir.kt | 1 + .../j+k/defaultMethodsIndirectInheritance.kt | 1 + .../tests/j+k/defaultMethods_warning.fir.kt | 3 +- .../tests/j+k/defaultMethods_warning.kt | 3 +- ...nheritanceStaticMethodFromInterface.fir.kt | 32 --------- .../inheritanceStaticMethodFromInterface.kt | 3 +- .../tests/j+k/traitDefaultCall.fir.kt | 1 + .../diagnostics/tests/j+k/traitDefaultCall.kt | 1 + ...gateFlexibilityFromOtherConstraints.fir.kt | 32 --------- ...ropagateFlexibilityFromOtherConstraints.kt | 5 +- .../tests/targetedBuiltIns/stream.fir.kt | 13 ---- .../tests/targetedBuiltIns/stream.kt | 4 +- .../annotations/jvmStatic/functions_LL13.kt | 2 +- .../interfaceCompanion_LL13_16.fir.kt | 2 + .../jvmStatic/interfaceCompanion_LL13_16.kt | 2 + .../targetedBuiltIns/blackListed.kt | 2 +- .../codegen/BlackBoxCodegenTestGenerated.java | 12 ++++ .../codegen/BytecodeTextTestGenerated.java | 12 +++- .../IrBlackBoxCodegenTestGenerated.java | 12 ++++ .../codegen/IrBytecodeTextTestGenerated.java | 12 +++- .../LightAnalysisModeTestGenerated.java | 10 +++ .../CompileKotlinAgainstCustomBinariesTest.kt | 4 +- .../gradle/GradleFacetImportTest.kt | 4 +- .../platform/impl/JvmIdePlatformKind.kt | 2 +- .../checker/JvmStaticUsagesRuntime.kt | 2 +- .../jdk8/overrideCollectionStream.kt.after | 1 - .../kotlin/gradle/dsl/KotlinJvmOptions.kt | 4 +- .../kotlin/gradle/dsl/KotlinJvmOptionsBase.kt | 4 +- 52 files changed, 247 insertions(+), 164 deletions(-) create mode 100644 compiler/testData/codegen/box/functions/bigArity/callWithIncorrectNumberOfArguments_1_6.kt create mode 100644 compiler/testData/codegen/box/super/interfaceHashCode_1_6.kt create mode 100644 compiler/testData/codegen/bytecodeText/boxingOptimization/hashCodeOnNonNull.kt rename compiler/testData/codegen/bytecodeText/hashCode/{hashCode.kt => hashCode_1_6.kt} (93%) delete mode 100644 compiler/testData/diagnostics/tests/generics/kt9203.fir.kt delete mode 100644 compiler/testData/diagnostics/tests/j+k/inheritanceStaticMethodFromInterface.fir.kt delete mode 100644 compiler/testData/diagnostics/tests/platformTypes/propagateFlexibilityFromOtherConstraints.fir.kt delete mode 100644 compiler/testData/diagnostics/tests/targetedBuiltIns/stream.fir.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/OriginCollectingClassBuilderFactory.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/OriginCollectingClassBuilderFactory.kt index d9b3869893f..238cd25f13d 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/OriginCollectingClassBuilderFactory.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/OriginCollectingClassBuilderFactory.kt @@ -58,7 +58,7 @@ class OriginCollectingClassBuilderFactory(private val builderMode: ClassBuilderM } override fun asBytes(builder: ClassBuilder): ByteArray { - val classWriter = ClassWriter(0) + val classWriter = ClassWriter(ClassWriter.COMPUTE_FRAMES or ClassWriter.COMPUTE_MAXS) (builder as OriginCollectingClassBuilder).classNode.accept(classWriter) return classWriter.toByteArray() } @@ -66,4 +66,4 @@ class OriginCollectingClassBuilderFactory(private val builderMode: ClassBuilderM override fun asText(builder: ClassBuilder) = throw UnsupportedOperationException() override fun close() {} -} \ No newline at end of file +} diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt index cd7237ce2ad..4cb5d5804ec 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt @@ -71,7 +71,7 @@ class K2JVMCompilerArguments : CommonCompilerArguments() { @Argument( value = "-jvm-target", valueDescription = "", - description = "Target version of the generated JVM bytecode (1.6, 1.8, 9, 10, 11, 12, 13, 14 or 15), default is 1.6" + description = "Target version of the generated JVM bytecode (1.6, 1.8, 9, 10, 11, 12, 13, 14 or 15), default is 1.8" ) var jvmTarget: String? by NullableStringFreezableVar(JvmTarget.DEFAULT.description) diff --git a/compiler/config.jvm/src/org/jetbrains/kotlin/config/JvmTarget.kt b/compiler/config.jvm/src/org/jetbrains/kotlin/config/JvmTarget.kt index 69ebe32e62b..df3a0df53f1 100644 --- a/compiler/config.jvm/src/org/jetbrains/kotlin/config/JvmTarget.kt +++ b/compiler/config.jvm/src/org/jetbrains/kotlin/config/JvmTarget.kt @@ -36,7 +36,7 @@ enum class JvmTarget( companion object { @JvmField - val DEFAULT = JVM_1_6 + val DEFAULT = JVM_1_8 @JvmStatic fun fromString(string: String) = values().find { it.description == string } diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index 6441ede6b42..188314799ea 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -14315,6 +14315,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/functions/bigArity/callWithIncorrectNumberOfArguments.kt"); } + @Test + @TestMetadata("callWithIncorrectNumberOfArguments_1_6.kt") + public void testCallWithIncorrectNumberOfArguments_1_6() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/callWithIncorrectNumberOfArguments_1_6.kt"); + } + @Test @TestMetadata("function255.kt") public void testFunction255() throws Exception { @@ -35848,6 +35854,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/super/interfaceHashCode.kt"); } + @Test + @TestMetadata("interfaceHashCode_1_6.kt") + public void testInterfaceHashCode_1_6() throws Exception { + runTest("compiler/testData/codegen/box/super/interfaceHashCode_1_6.kt"); + } + @Test @TestMetadata("kt14243.kt") public void testKt14243() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java index 115fc4cd7da..5fad7f402f5 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java @@ -640,6 +640,12 @@ public class FirBytecodeTextTestGenerated extends AbstractFirBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/boxingOptimization/fold.kt"); } + @Test + @TestMetadata("hashCodeOnNonNull.kt") + public void testHashCodeOnNonNull() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/boxingOptimization/hashCodeOnNonNull.kt"); + } + @Test @TestMetadata("inlineClassesAndInlinedLambda.kt") public void testInlineClassesAndInlinedLambda() throws Exception { @@ -3119,9 +3125,9 @@ public class FirBytecodeTextTestGenerated extends AbstractFirBytecodeTextTest { } @Test - @TestMetadata("hashCode.kt") - public void testHashCode() throws Exception { - runTest("compiler/testData/codegen/bytecodeText/hashCode/hashCode.kt"); + @TestMetadata("hashCode_1_6.kt") + public void testHashCode_1_6() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/hashCode/hashCode_1_6.kt"); } @Test diff --git a/compiler/testData/asJava/ultraLightClasses/typeAnnotations.java b/compiler/testData/asJava/ultraLightClasses/typeAnnotations.java index d10d935f4f7..d5473375e39 100644 --- a/compiler/testData/asJava/ultraLightClasses/typeAnnotations.java +++ b/compiler/testData/asJava/ultraLightClasses/typeAnnotations.java @@ -1,41 +1,41 @@ @java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) -@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.PARAMETER}) +@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.TYPE_USE}) @kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.TYPE}) public abstract @interface A0 /* A0*/ { } @java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) -@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.PARAMETER}) +@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.TYPE_USE}) @kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.TYPE}) public abstract @interface A1 /* A1*/ { } @java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) -@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.PARAMETER}) +@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.TYPE_USE}) @kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.TYPE}) public abstract @interface A2 /* A2*/ { } @java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) -@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.PARAMETER}) +@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.TYPE_USE}) @kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.TYPE}) public abstract @interface A3 /* A3*/ { } @java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) -@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.PARAMETER}) +@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.TYPE_USE}) @kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.TYPE}) public abstract @interface A4 /* A4*/ { } @java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) -@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.PARAMETER}) +@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.TYPE_USE}) @kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.TYPE}) public abstract @interface A5 /* A5*/ { } @java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) -@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.PARAMETER}) +@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.TYPE_USE}) @kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.TYPE}) public abstract @interface A6 /* A6*/ { } diff --git a/compiler/testData/cli/jvm/help.out b/compiler/testData/cli/jvm/help.out index cad39163ca3..e552148ed9b 100644 --- a/compiler/testData/cli/jvm/help.out +++ b/compiler/testData/cli/jvm/help.out @@ -6,7 +6,7 @@ where possible options include: -include-runtime Include Kotlin runtime into the resulting JAR -java-parameters Generate metadata for Java 1.8 reflection on method parameters -jdk-home Include a custom JDK from the specified location into the classpath instead of the default JAVA_HOME - -jvm-target Target version of the generated JVM bytecode (1.6, 1.8, 9, 10, 11, 12, 13, 14 or 15), default is 1.6 + -jvm-target Target version of the generated JVM bytecode (1.6, 1.8, 9, 10, 11, 12, 13, 14 or 15), default is 1.8 -module-name Name of the generated .kotlin_module file -no-jdk Don't automatically include the Java runtime into the classpath -no-reflect Don't automatically include Kotlin reflection into the classpath diff --git a/compiler/testData/codegen/box/annotations/typeAnnotationOnJdk6.kt b/compiler/testData/codegen/box/annotations/typeAnnotationOnJdk6.kt index 0e2d9aea7e6..b5be1dfdeb4 100644 --- a/compiler/testData/codegen/box/annotations/typeAnnotationOnJdk6.kt +++ b/compiler/testData/codegen/box/annotations/typeAnnotationOnJdk6.kt @@ -1,5 +1,6 @@ // TARGET_BACKEND: JVM // WITH_RUNTIME +// JVM_TARGET: 1.6 @Target(AnnotationTarget.TYPE) annotation class A diff --git a/compiler/testData/codegen/box/functions/bigArity/callWithIncorrectNumberOfArguments_1_6.kt b/compiler/testData/codegen/box/functions/bigArity/callWithIncorrectNumberOfArguments_1_6.kt new file mode 100644 index 00000000000..37aa0ab9500 --- /dev/null +++ b/compiler/testData/codegen/box/functions/bigArity/callWithIncorrectNumberOfArguments_1_6.kt @@ -0,0 +1,71 @@ +// !LANGUAGE: +FunctionTypesWithBigArity +// WITH_RUNTIME +// TARGET_BACKEND: JVM +// JVM_TARGET: 1.6 +// FILE: J.java + +// import kotlin.jvm.functions.Arity; +import kotlin.jvm.functions.FunctionN; +import kotlin.Unit; +import java.util.Arrays; + +public class J { + // TODO: uncomment arity as soon as Arity is introduced + public static void test(/* @Arity(30) */ FunctionN f) { + Object o = new Object(); + for (int i = 0; i < 42; i++) { + if (i == 30) continue; + + Object[] args = new Object[i]; + Arrays.fill(args, o); + try { + f.invoke(args); + } catch (IllegalArgumentException e) { + // OK + + if (!e.getMessage().contains("30")) { + throw new AssertionError("Exception must specify the expected number of arguments: " + e.getMessage(), e); + } + + continue; + } catch (Throwable e) { + throw new AssertionError( + "Incorrect exception (IllegalArgumentException expected): " + e.getClass().getName() + ", i = " + i, e + ); + } + throw new AssertionError("IllegalArgumentException expected, but nothing was thrown, i = " + i); + } + } +} + +// FILE: K.kt + +fun foo( + p00: Any?, p01: Any?, p02: Any?, p03: Any?, p04: Any?, p05: Any?, p06: Any?, p07: Any?, p08: Any?, p09: Any?, + p10: Any?, p11: Any?, p12: Any?, p13: Any?, p14: Any?, p15: Any?, p16: Any?, p17: Any?, p18: Any?, p19: Any?, + p20: Any?, p21: Any?, p22: Any?, p23: Any?, p24: Any?, p25: Any?, p26: Any?, p27: Any?, p28: Any?, p29: Any? +) {} + +class Fun : (Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, + Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?) -> Unit { + override fun invoke( + p00: Any?, p01: Any?, p02: Any?, p03: Any?, p04: Any?, p05: Any?, p06: Any?, p07: Any?, p08: Any?, p09: Any?, + p10: Any?, p11: Any?, p12: Any?, p13: Any?, p14: Any?, p15: Any?, p16: Any?, p17: Any?, p18: Any?, p19: Any?, + p20: Any?, p21: Any?, p22: Any?, p23: Any?, p24: Any?, p25: Any?, p26: Any?, p27: Any?, p28: Any?, p29: Any? + ) {} +} + +fun box(): String { + val lambda: Function30< + Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, + Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, + Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, + Unit> = { _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ -> } + @Suppress("DEPRECATION_ERROR") + J.test(lambda as kotlin.jvm.functions.FunctionN) + @Suppress("DEPRECATION_ERROR") + J.test(::foo as kotlin.jvm.functions.FunctionN) + @Suppress("DEPRECATION_ERROR") + J.test(Fun() as kotlin.jvm.functions.FunctionN) + return "OK" +} diff --git a/compiler/testData/codegen/box/reflection/annotations/onTypes/arrayKClass.kt b/compiler/testData/codegen/box/reflection/annotations/onTypes/arrayKClass.kt index 0db0871261d..3ba21ac9a59 100644 --- a/compiler/testData/codegen/box/reflection/annotations/onTypes/arrayKClass.kt +++ b/compiler/testData/codegen/box/reflection/annotations/onTypes/arrayKClass.kt @@ -1,6 +1,7 @@ // IGNORE_BACKEND_FIR: JVM_IR // TARGET_BACKEND: JVM // WITH_REFLECT +// JVM_TARGET: 1.6 import kotlin.reflect.KClass diff --git a/compiler/testData/codegen/box/super/interfaceHashCode.kt b/compiler/testData/codegen/box/super/interfaceHashCode.kt index 7a6aeff7fa3..c88e69af2cf 100644 --- a/compiler/testData/codegen/box/super/interfaceHashCode.kt +++ b/compiler/testData/codegen/box/super/interfaceHashCode.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR interface I class C : I { fun foo() = super.hashCode() } diff --git a/compiler/testData/codegen/box/super/interfaceHashCode_1_6.kt b/compiler/testData/codegen/box/super/interfaceHashCode_1_6.kt new file mode 100644 index 00000000000..87bd1e88336 --- /dev/null +++ b/compiler/testData/codegen/box/super/interfaceHashCode_1_6.kt @@ -0,0 +1,11 @@ +// TARGET_BACKEND: JVM +// IGNORE_BACKEND_FIR: JVM_IR +// JVM_TARGET: 1.6 + +interface I +class C : I { fun foo() = super.hashCode() } + +fun box(): String { + C().foo() + return "OK" +} diff --git a/compiler/testData/codegen/bytecodeText/boxingOptimization/hashCodeOnNonNull.kt b/compiler/testData/codegen/bytecodeText/boxingOptimization/hashCodeOnNonNull.kt new file mode 100644 index 00000000000..4553487d949 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/boxingOptimization/hashCodeOnNonNull.kt @@ -0,0 +1,11 @@ +// IGNORE_BACKEND: JVM_IR +// IGNORE_BACKEND_FIR: JVM_IR + +fun foo() { + val x: Int? = 6 + val hc = x!!.hashCode() +} + +// 1 java/lang/Integer.hashCode \(I\)I +// 0 java/lang/Integer.valueOf +// 0 intValue diff --git a/compiler/testData/codegen/bytecodeText/boxingOptimization/kt7224.kt b/compiler/testData/codegen/bytecodeText/boxingOptimization/kt7224.kt index ec6fa03d080..0308a417e90 100644 --- a/compiler/testData/codegen/bytecodeText/boxingOptimization/kt7224.kt +++ b/compiler/testData/codegen/bytecodeText/boxingOptimization/kt7224.kt @@ -4,4 +4,4 @@ fun box(): String { return "OK" } -// 1 INVOKESTATIC java/lang/Integer.valueOf \ No newline at end of file +// 0 INVOKESTATIC java/lang/Integer.valueOf diff --git a/compiler/testData/codegen/bytecodeText/boxingOptimization/unsafeRemoving.kt b/compiler/testData/codegen/bytecodeText/boxingOptimization/unsafeRemoving.kt index 0c211227755..7d9625025f8 100644 --- a/compiler/testData/codegen/bytecodeText/boxingOptimization/unsafeRemoving.kt +++ b/compiler/testData/codegen/bytecodeText/boxingOptimization/unsafeRemoving.kt @@ -15,9 +15,6 @@ fun foo() { val b = arrayOfNulls(4) b[100] = 5 - val x: Int? = 6 - val hc = x!!.hashCode() - val y: Int? = 7 val z: Int? = 8 val res = y === z @@ -26,5 +23,5 @@ fun foo() { val c2: Any = if (1 != one) 0 else "abc" } -// 9 java/lang/Integer.valueOf +// 8 java/lang/Integer.valueOf // 0 intValue diff --git a/compiler/testData/codegen/bytecodeText/hashCode/hashCode.kt b/compiler/testData/codegen/bytecodeText/hashCode/hashCode_1_6.kt similarity index 93% rename from compiler/testData/codegen/bytecodeText/hashCode/hashCode.kt rename to compiler/testData/codegen/bytecodeText/hashCode/hashCode_1_6.kt index 19a7de41578..6bec2e9f0b0 100644 --- a/compiler/testData/codegen/bytecodeText/hashCode/hashCode.kt +++ b/compiler/testData/codegen/bytecodeText/hashCode/hashCode_1_6.kt @@ -1,3 +1,5 @@ +// JVM_TARGET: 1.6 + fun box(): String { true.hashCode() 1.toByte().hashCode() diff --git a/compiler/testData/codegen/bytecodeText/inlineClasses/skipCallToUnderlyingValueOfInlineClass.kt b/compiler/testData/codegen/bytecodeText/inlineClasses/skipCallToUnderlyingValueOfInlineClass.kt index 644a4d128e9..bef3467606b 100644 --- a/compiler/testData/codegen/bytecodeText/inlineClasses/skipCallToUnderlyingValueOfInlineClass.kt +++ b/compiler/testData/codegen/bytecodeText/inlineClasses/skipCallToUnderlyingValueOfInlineClass.kt @@ -9,7 +9,7 @@ inline class UInt(val value: Int) fun test(u1: UInt, u2: UInt) { val a = u1.value - val b = u1.value.hashCode() // box int to call hashCode + val b = u1.value.hashCode() val c = u1.value + u2.value } @@ -18,5 +18,5 @@ fun test(u1: UInt, u2: UInt) { // 0 INVOKESTATIC UInt\$Erased.box // 0 INVOKEVIRTUAL UInt.unbox -// 1 valueOf -// 0 intValue \ No newline at end of file +// 0 valueOf +// 0 intValue diff --git a/compiler/testData/codegen/bytecodeText/unsignedTypes/unsignedIntCompare_before.kt b/compiler/testData/codegen/bytecodeText/unsignedTypes/unsignedIntCompare_before.kt index d08c93ab158..9c9f26a2f4e 100644 --- a/compiler/testData/codegen/bytecodeText/unsignedTypes/unsignedIntCompare_before.kt +++ b/compiler/testData/codegen/bytecodeText/unsignedTypes/unsignedIntCompare_before.kt @@ -1,4 +1,5 @@ // WITH_RUNTIME +// JVM_TARGET: 1.6 val ua = 1234U val ub = 5678U diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/output.txt b/compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/output.txt index f1948e7258a..e5f08789d19 100644 --- a/compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/output.txt +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/output.txt @@ -1,55 +1,55 @@ -compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:6:5: error: cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6. Please specify proper '-jvm-target' option +compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:6:5: error: cannot inline bytecode built with JVM target 11 into bytecode that is being built with JVM target 1.8. Please specify proper '-jvm-target' option inlineFun {} ^ -compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:7:5: error: cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6. Please specify proper '-jvm-target' option +compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:7:5: error: cannot inline bytecode built with JVM target 11 into bytecode that is being built with JVM target 1.8. Please specify proper '-jvm-target' option inlineGetter ^ -compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:8:5: error: cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6. Please specify proper '-jvm-target' option +compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:8:5: error: cannot inline bytecode built with JVM target 11 into bytecode that is being built with JVM target 1.8. Please specify proper '-jvm-target' option inlineGetter = 1 ^ -compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:11:5: error: cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6. Please specify proper '-jvm-target' option +compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:11:5: error: cannot inline bytecode built with JVM target 11 into bytecode that is being built with JVM target 1.8. Please specify proper '-jvm-target' option inlineSetter = 1 ^ -compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:13:5: error: cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6. Please specify proper '-jvm-target' option +compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:13:5: error: cannot inline bytecode built with JVM target 11 into bytecode that is being built with JVM target 1.8. Please specify proper '-jvm-target' option allInline ^ -compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:14:5: error: cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6. Please specify proper '-jvm-target' option +compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:14:5: error: cannot inline bytecode built with JVM target 11 into bytecode that is being built with JVM target 1.8. Please specify proper '-jvm-target' option allInline = 1 ^ -compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:17:10: error: cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6. Please specify proper '-jvm-target' option +compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:17:10: error: cannot inline bytecode built with JVM target 11 into bytecode that is being built with JVM target 1.8. Please specify proper '-jvm-target' option base.inlineFunBase {} ^ -compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:18:10: error: cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6. Please specify proper '-jvm-target' option +compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:18:10: error: cannot inline bytecode built with JVM target 11 into bytecode that is being built with JVM target 1.8. Please specify proper '-jvm-target' option base.inlineGetterBase ^ -compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:19:10: error: cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6. Please specify proper '-jvm-target' option +compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:19:10: error: cannot inline bytecode built with JVM target 11 into bytecode that is being built with JVM target 1.8. Please specify proper '-jvm-target' option base.inlineGetterBase = 1 ^ -compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:22:10: error: cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6. Please specify proper '-jvm-target' option +compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:22:10: error: cannot inline bytecode built with JVM target 11 into bytecode that is being built with JVM target 1.8. Please specify proper '-jvm-target' option base.inlineSetterBase = 1 ^ -compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:24:10: error: cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6. Please specify proper '-jvm-target' option +compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:24:10: error: cannot inline bytecode built with JVM target 11 into bytecode that is being built with JVM target 1.8. Please specify proper '-jvm-target' option base.allInlineBase ^ -compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:25:10: error: cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6. Please specify proper '-jvm-target' option +compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:25:10: error: cannot inline bytecode built with JVM target 11 into bytecode that is being built with JVM target 1.8. Please specify proper '-jvm-target' option base.allInlineBase = 1 ^ -compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:32:9: error: cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6. Please specify proper '-jvm-target' option +compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:32:9: error: cannot inline bytecode built with JVM target 11 into bytecode that is being built with JVM target 1.8. Please specify proper '-jvm-target' option inlineFunBase {} ^ -compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:33:9: error: cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6. Please specify proper '-jvm-target' option +compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:33:9: error: cannot inline bytecode built with JVM target 11 into bytecode that is being built with JVM target 1.8. Please specify proper '-jvm-target' option inlineGetterBase ^ -compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:34:9: error: cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6. Please specify proper '-jvm-target' option +compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:34:9: error: cannot inline bytecode built with JVM target 11 into bytecode that is being built with JVM target 1.8. Please specify proper '-jvm-target' option inlineGetterBase = 1 ^ -compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:37:9: error: cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6. Please specify proper '-jvm-target' option +compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:37:9: error: cannot inline bytecode built with JVM target 11 into bytecode that is being built with JVM target 1.8. Please specify proper '-jvm-target' option inlineSetterBase = 1 ^ -compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:39:9: error: cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6. Please specify proper '-jvm-target' option +compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:39:9: error: cannot inline bytecode built with JVM target 11 into bytecode that is being built with JVM target 1.8. Please specify proper '-jvm-target' option allInlineBase ^ -compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:40:9: error: cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6. Please specify proper '-jvm-target' option +compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/source.kt:40:9: error: cannot inline bytecode built with JVM target 11 into bytecode that is being built with JVM target 1.8. Please specify proper '-jvm-target' option allInlineBase = 1 ^ COMPILATION_ERROR diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/warningsOnly_1_3.txt b/compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/warningsOnly_1_3.txt index 451f29a417b..410b9f229b7 100644 --- a/compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/warningsOnly_1_3.txt +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/warningsOnly_1_3.txt @@ -1,20 +1,20 @@ warning: language version 1.3 is deprecated and its support will be removed in a future version of Kotlin -compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/warningsOnly_1_3.kt:8:9: warning: cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6. Please specify proper '-jvm-target' option +compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/warningsOnly_1_3.kt:8:9: warning: cannot inline bytecode built with JVM target 11 into bytecode that is being built with JVM target 1.8. Please specify proper '-jvm-target' option inlineFunBase {} ^ -compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/warningsOnly_1_3.kt:9:9: warning: cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6. Please specify proper '-jvm-target' option +compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/warningsOnly_1_3.kt:9:9: warning: cannot inline bytecode built with JVM target 11 into bytecode that is being built with JVM target 1.8. Please specify proper '-jvm-target' option inlineGetterBase ^ -compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/warningsOnly_1_3.kt:10:9: warning: cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6. Please specify proper '-jvm-target' option +compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/warningsOnly_1_3.kt:10:9: warning: cannot inline bytecode built with JVM target 11 into bytecode that is being built with JVM target 1.8. Please specify proper '-jvm-target' option inlineGetterBase = 1 ^ -compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/warningsOnly_1_3.kt:13:9: warning: cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6. Please specify proper '-jvm-target' option +compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/warningsOnly_1_3.kt:13:9: warning: cannot inline bytecode built with JVM target 11 into bytecode that is being built with JVM target 1.8. Please specify proper '-jvm-target' option inlineSetterBase = 1 ^ -compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/warningsOnly_1_3.kt:15:9: warning: cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6. Please specify proper '-jvm-target' option +compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/warningsOnly_1_3.kt:15:9: warning: cannot inline bytecode built with JVM target 11 into bytecode that is being built with JVM target 1.8. Please specify proper '-jvm-target' option allInlineBase ^ -compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/warningsOnly_1_3.kt:16:9: warning: cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6. Please specify proper '-jvm-target' option +compiler/testData/compileKotlinAgainstCustomBinaries/wrongInlineTarget/warningsOnly_1_3.kt:16:9: warning: cannot inline bytecode built with JVM target 11 into bytecode that is being built with JVM target 1.8. Please specify proper '-jvm-target' option allInlineBase = 1 ^ OK diff --git a/compiler/testData/diagnostics/tests/generics/kt9203.fir.kt b/compiler/testData/diagnostics/tests/generics/kt9203.fir.kt deleted file mode 100644 index dffc4eb33e4..00000000000 --- a/compiler/testData/diagnostics/tests/generics/kt9203.fir.kt +++ /dev/null @@ -1,11 +0,0 @@ -// !WITH_NEW_INFERENCE -// FULL_JDK - -import java.util.stream.Collectors -import java.util.stream.IntStream - -fun main() { - val xs = IntStream.range(0, 10).mapToObj { it.toString() } - .collect(Collectors.toList()) - xs[0] -} diff --git a/compiler/testData/diagnostics/tests/generics/kt9203.kt b/compiler/testData/diagnostics/tests/generics/kt9203.kt index 93fcc651c8a..1ca1e4242b3 100644 --- a/compiler/testData/diagnostics/tests/generics/kt9203.kt +++ b/compiler/testData/diagnostics/tests/generics/kt9203.kt @@ -1,11 +1,11 @@ -// !WITH_NEW_INFERENCE +// FIR_IDENTICAL // FULL_JDK import java.util.stream.Collectors import java.util.stream.IntStream fun main() { - val xs = IntStream.range(0, 10).mapToObj { it.toString() } + val xs = IntStream.range(0, 10).mapToObj { it.toString() } .collect(Collectors.toList()) xs[0] } diff --git a/compiler/testData/diagnostics/tests/j+k/defaultMethods.fir.kt b/compiler/testData/diagnostics/tests/j+k/defaultMethods.fir.kt index d0eeee7ed9c..fb89c234e71 100644 --- a/compiler/testData/diagnostics/tests/j+k/defaultMethods.fir.kt +++ b/compiler/testData/diagnostics/tests/j+k/defaultMethods.fir.kt @@ -1,3 +1,4 @@ +// !JVM_TARGET: 1.6 // FILE: JavaInterface.java public interface JavaInterface { diff --git a/compiler/testData/diagnostics/tests/j+k/defaultMethods.kt b/compiler/testData/diagnostics/tests/j+k/defaultMethods.kt index 1c9e5b23dfe..dd18837b387 100644 --- a/compiler/testData/diagnostics/tests/j+k/defaultMethods.kt +++ b/compiler/testData/diagnostics/tests/j+k/defaultMethods.kt @@ -1,3 +1,4 @@ +// !JVM_TARGET: 1.6 // FILE: JavaInterface.java public interface JavaInterface { diff --git a/compiler/testData/diagnostics/tests/j+k/defaultMethodsIndirectInheritance.fir.kt b/compiler/testData/diagnostics/tests/j+k/defaultMethodsIndirectInheritance.fir.kt index 6aafef0fac0..45be799023e 100644 --- a/compiler/testData/diagnostics/tests/j+k/defaultMethodsIndirectInheritance.fir.kt +++ b/compiler/testData/diagnostics/tests/j+k/defaultMethodsIndirectInheritance.fir.kt @@ -1,3 +1,4 @@ +// !JVM_TARGET: 1.6 // FILE: JavaInterfaceBase.java public interface JavaInterfaceBase { diff --git a/compiler/testData/diagnostics/tests/j+k/defaultMethodsIndirectInheritance.kt b/compiler/testData/diagnostics/tests/j+k/defaultMethodsIndirectInheritance.kt index c4b862e0bba..d10532a2fd1 100644 --- a/compiler/testData/diagnostics/tests/j+k/defaultMethodsIndirectInheritance.kt +++ b/compiler/testData/diagnostics/tests/j+k/defaultMethodsIndirectInheritance.kt @@ -1,3 +1,4 @@ +// !JVM_TARGET: 1.6 // FILE: JavaInterfaceBase.java public interface JavaInterfaceBase { diff --git a/compiler/testData/diagnostics/tests/j+k/defaultMethods_warning.fir.kt b/compiler/testData/diagnostics/tests/j+k/defaultMethods_warning.fir.kt index 298332fb21a..00e24b30071 100644 --- a/compiler/testData/diagnostics/tests/j+k/defaultMethods_warning.fir.kt +++ b/compiler/testData/diagnostics/tests/j+k/defaultMethods_warning.fir.kt @@ -1,4 +1,5 @@ -//!LANGUAGE: -DefaultMethodsCallFromJava6TargetError +// !LANGUAGE: -DefaultMethodsCallFromJava6TargetError +// !JVM_TARGET: 1.6 // FILE: JavaInterface.java public interface JavaInterface { diff --git a/compiler/testData/diagnostics/tests/j+k/defaultMethods_warning.kt b/compiler/testData/diagnostics/tests/j+k/defaultMethods_warning.kt index 24b07f902fc..dd2e491be89 100644 --- a/compiler/testData/diagnostics/tests/j+k/defaultMethods_warning.kt +++ b/compiler/testData/diagnostics/tests/j+k/defaultMethods_warning.kt @@ -1,4 +1,5 @@ -//!LANGUAGE: -DefaultMethodsCallFromJava6TargetError +// !LANGUAGE: -DefaultMethodsCallFromJava6TargetError +// !JVM_TARGET: 1.6 // FILE: JavaInterface.java public interface JavaInterface { diff --git a/compiler/testData/diagnostics/tests/j+k/inheritanceStaticMethodFromInterface.fir.kt b/compiler/testData/diagnostics/tests/j+k/inheritanceStaticMethodFromInterface.fir.kt deleted file mode 100644 index 28d47637209..00000000000 --- a/compiler/testData/diagnostics/tests/j+k/inheritanceStaticMethodFromInterface.fir.kt +++ /dev/null @@ -1,32 +0,0 @@ -// FILE: I.java - -public interface I { - int a = 1; - static void foo() {} -} - -// FILE: C.java - -public class C implements I { - static int b = 1; - static void bar() {} -} - -// FILE: test.kt - -class K : C() - -fun main() { - I.a - I.foo() - - C.a - C.b - C.foo() - C.bar() - - K.a - K.b - K.foo() - K.bar() -} diff --git a/compiler/testData/diagnostics/tests/j+k/inheritanceStaticMethodFromInterface.kt b/compiler/testData/diagnostics/tests/j+k/inheritanceStaticMethodFromInterface.kt index 4abe3f79e7f..eeef118f7dc 100644 --- a/compiler/testData/diagnostics/tests/j+k/inheritanceStaticMethodFromInterface.kt +++ b/compiler/testData/diagnostics/tests/j+k/inheritanceStaticMethodFromInterface.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // FILE: I.java public interface I { @@ -18,7 +19,7 @@ class K : C() fun main() { I.a - I.foo() + I.foo() C.a C.b diff --git a/compiler/testData/diagnostics/tests/j+k/traitDefaultCall.fir.kt b/compiler/testData/diagnostics/tests/j+k/traitDefaultCall.fir.kt index e49d86b7fc5..0dc00cfd49a 100644 --- a/compiler/testData/diagnostics/tests/j+k/traitDefaultCall.fir.kt +++ b/compiler/testData/diagnostics/tests/j+k/traitDefaultCall.fir.kt @@ -1,3 +1,4 @@ +// !JVM_TARGET: 1.6 // FILE: Test.java public interface Test { default String test() { diff --git a/compiler/testData/diagnostics/tests/j+k/traitDefaultCall.kt b/compiler/testData/diagnostics/tests/j+k/traitDefaultCall.kt index 6531848b7c6..ebe5049641c 100644 --- a/compiler/testData/diagnostics/tests/j+k/traitDefaultCall.kt +++ b/compiler/testData/diagnostics/tests/j+k/traitDefaultCall.kt @@ -1,3 +1,4 @@ +// !JVM_TARGET: 1.6 // FILE: Test.java public interface Test { default String test() { diff --git a/compiler/testData/diagnostics/tests/platformTypes/propagateFlexibilityFromOtherConstraints.fir.kt b/compiler/testData/diagnostics/tests/platformTypes/propagateFlexibilityFromOtherConstraints.fir.kt deleted file mode 100644 index 4cbcd0abc0a..00000000000 --- a/compiler/testData/diagnostics/tests/platformTypes/propagateFlexibilityFromOtherConstraints.fir.kt +++ /dev/null @@ -1,32 +0,0 @@ -// FULL_JDK -// FILE: test.kt - -@file:Suppress("UNUSED_PARAMETER") - -import java.util.Comparator - -abstract class DataView { - abstract val presentationName: String -} - -fun comboBox( - model: SortedComboBoxModel, - graphProperty: GraphProperty, -) {} - -class GraphProperty - -fun test() { - val presentationName: (DataView) -> String = { it.presentationName } - val parentComboBoxModel/*: SortedComboBoxModel*/ = SortedComboBoxModel(Comparator.comparing(presentationName)) - comboBox(parentComboBoxModel, GraphProperty()) -} - -// FILE: SortedComboBoxModel.java - -import java.util.Comparator; - -public class SortedComboBoxModel { - public SortedComboBoxModel(Comparator comparator) { - } -} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/platformTypes/propagateFlexibilityFromOtherConstraints.kt b/compiler/testData/diagnostics/tests/platformTypes/propagateFlexibilityFromOtherConstraints.kt index de37642cfb4..5f79bc7bbf8 100644 --- a/compiler/testData/diagnostics/tests/platformTypes/propagateFlexibilityFromOtherConstraints.kt +++ b/compiler/testData/diagnostics/tests/platformTypes/propagateFlexibilityFromOtherConstraints.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // FULL_JDK // FILE: test.kt @@ -18,7 +19,7 @@ class GraphProperty fun test() { val presentationName: (DataView) -> String = { it.presentationName } - val parentComboBoxModel/*: SortedComboBoxModel*/ = SortedComboBoxModel(Comparator.comparing(presentationName)) + val parentComboBoxModel/*: SortedComboBoxModel*/ = SortedComboBoxModel(Comparator.comparing(presentationName)) comboBox(parentComboBoxModel, GraphProperty()) } @@ -29,4 +30,4 @@ import java.util.Comparator; public class SortedComboBoxModel { public SortedComboBoxModel(Comparator comparator) { } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/targetedBuiltIns/stream.fir.kt b/compiler/testData/diagnostics/tests/targetedBuiltIns/stream.fir.kt deleted file mode 100644 index 0073efb8034..00000000000 --- a/compiler/testData/diagnostics/tests/targetedBuiltIns/stream.fir.kt +++ /dev/null @@ -1,13 +0,0 @@ -// !WITH_NEW_INFERENCE -// FULL_JDK - -import java.util.stream.* - -interface A : Collection { - override fun stream(): Stream = Stream.of() -} - -fun foo(x: List, y: A) { - x.stream().filter { it.length > 0 }.collect(Collectors.toList()) - y.stream().filter { it.length > 0 } -} diff --git a/compiler/testData/diagnostics/tests/targetedBuiltIns/stream.kt b/compiler/testData/diagnostics/tests/targetedBuiltIns/stream.kt index 678abf38109..5848f2ca42f 100644 --- a/compiler/testData/diagnostics/tests/targetedBuiltIns/stream.kt +++ b/compiler/testData/diagnostics/tests/targetedBuiltIns/stream.kt @@ -1,10 +1,10 @@ -// !WITH_NEW_INFERENCE +// FIR_IDENTICAL // FULL_JDK import java.util.stream.* interface A : Collection { - override fun stream(): Stream = Stream.of() + override fun stream(): Stream = Stream.of() } fun foo(x: List, y: A) { diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmStatic/functions_LL13.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmStatic/functions_LL13.kt index 7acdbf84d90..621f6dc93c7 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmStatic/functions_LL13.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmStatic/functions_LL13.kt @@ -28,7 +28,7 @@ class A { interface B { companion object { - @JvmStatic fun a1() { + @JvmStatic fun a1() { } } diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmStatic/interfaceCompanion_LL13_16.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmStatic/interfaceCompanion_LL13_16.fir.kt index 073edc66c0f..be8b42471bc 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmStatic/interfaceCompanion_LL13_16.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmStatic/interfaceCompanion_LL13_16.fir.kt @@ -1,5 +1,7 @@ // !DIAGNOSTICS: -UNUSED_VARIABLE // !LANGUAGE: +JvmStaticInInterface +// !JVM_TARGET: 1.6 + interface B { companion object { @JvmStatic fun a1() { diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmStatic/interfaceCompanion_LL13_16.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmStatic/interfaceCompanion_LL13_16.kt index 15b17fc94ef..a0837b30a80 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmStatic/interfaceCompanion_LL13_16.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmStatic/interfaceCompanion_LL13_16.kt @@ -1,5 +1,7 @@ // !DIAGNOSTICS: -UNUSED_VARIABLE // !LANGUAGE: +JvmStaticInInterface +// !JVM_TARGET: 1.6 + interface B { companion object { @JvmStatic fun a1() { diff --git a/compiler/testData/diagnostics/testsWithStdLib/targetedBuiltIns/blackListed.kt b/compiler/testData/diagnostics/testsWithStdLib/targetedBuiltIns/blackListed.kt index 5738db9fc65..45bb362072c 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/targetedBuiltIns/blackListed.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/targetedBuiltIns/blackListed.kt @@ -2,7 +2,7 @@ abstract class A : MutableList { override fun sort(/*0*/ p0: java.util.Comparator) { - super.sort(p0) + super.sort(p0) } } diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index 241a846a4dd..fa8a769400f 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -14315,6 +14315,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/functions/bigArity/callWithIncorrectNumberOfArguments.kt"); } + @Test + @TestMetadata("callWithIncorrectNumberOfArguments_1_6.kt") + public void testCallWithIncorrectNumberOfArguments_1_6() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/callWithIncorrectNumberOfArguments_1_6.kt"); + } + @Test @TestMetadata("function255.kt") public void testFunction255() throws Exception { @@ -36048,6 +36054,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/super/interfaceHashCode.kt"); } + @Test + @TestMetadata("interfaceHashCode_1_6.kt") + public void testInterfaceHashCode_1_6() throws Exception { + runTest("compiler/testData/codegen/box/super/interfaceHashCode_1_6.kt"); + } + @Test @TestMetadata("kt14243.kt") public void testKt14243() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeTextTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeTextTestGenerated.java index bd3bd77533e..6c133049b2c 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeTextTestGenerated.java @@ -640,6 +640,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/boxingOptimization/fold.kt"); } + @Test + @TestMetadata("hashCodeOnNonNull.kt") + public void testHashCodeOnNonNull() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/boxingOptimization/hashCodeOnNonNull.kt"); + } + @Test @TestMetadata("inlineClassesAndInlinedLambda.kt") public void testInlineClassesAndInlinedLambda() throws Exception { @@ -2987,9 +2993,9 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { } @Test - @TestMetadata("hashCode.kt") - public void testHashCode() throws Exception { - runTest("compiler/testData/codegen/bytecodeText/hashCode/hashCode.kt"); + @TestMetadata("hashCode_1_6.kt") + public void testHashCode_1_6() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/hashCode/hashCode_1_6.kt"); } @Test diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index f89dfecb257..baa98bc5e7a 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -14315,6 +14315,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/functions/bigArity/callWithIncorrectNumberOfArguments.kt"); } + @Test + @TestMetadata("callWithIncorrectNumberOfArguments_1_6.kt") + public void testCallWithIncorrectNumberOfArguments_1_6() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/callWithIncorrectNumberOfArguments_1_6.kt"); + } + @Test @TestMetadata("function255.kt") public void testFunction255() throws Exception { @@ -35848,6 +35854,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/super/interfaceHashCode.kt"); } + @Test + @TestMetadata("interfaceHashCode_1_6.kt") + public void testInterfaceHashCode_1_6() throws Exception { + runTest("compiler/testData/codegen/box/super/interfaceHashCode_1_6.kt"); + } + @Test @TestMetadata("kt14243.kt") public void testKt14243() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java index 697ca637506..22ab68493f9 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java @@ -640,6 +640,12 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/boxingOptimization/fold.kt"); } + @Test + @TestMetadata("hashCodeOnNonNull.kt") + public void testHashCodeOnNonNull() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/boxingOptimization/hashCodeOnNonNull.kt"); + } + @Test @TestMetadata("inlineClassesAndInlinedLambda.kt") public void testInlineClassesAndInlinedLambda() throws Exception { @@ -3119,9 +3125,9 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest { } @Test - @TestMetadata("hashCode.kt") - public void testHashCode() throws Exception { - runTest("compiler/testData/codegen/bytecodeText/hashCode/hashCode.kt"); + @TestMetadata("hashCode_1_6.kt") + public void testHashCode_1_6() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/hashCode/hashCode_1_6.kt"); } @Test diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 45e0b541a0d..bd4b3d744f3 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -12582,6 +12582,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/functions/bigArity/callWithIncorrectNumberOfArguments.kt"); } + @TestMetadata("callWithIncorrectNumberOfArguments_1_6.kt") + public void testCallWithIncorrectNumberOfArguments_1_6() throws Exception { + runTest("compiler/testData/codegen/box/functions/bigArity/callWithIncorrectNumberOfArguments_1_6.kt"); + } + @TestMetadata("function255.kt") public void testFunction255() throws Exception { runTest("compiler/testData/codegen/box/functions/bigArity/function255.kt"); @@ -29503,6 +29508,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/super/interfaceHashCode.kt"); } + @TestMetadata("interfaceHashCode_1_6.kt") + public void testInterfaceHashCode_1_6() throws Exception { + runTest("compiler/testData/codegen/box/super/interfaceHashCode_1_6.kt"); + } + @TestMetadata("kt14243.kt") public void testKt14243() throws Exception { runTest("compiler/testData/codegen/box/super/kt14243.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt index 7e218e9c4c1..0aa78345f81 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt @@ -526,9 +526,9 @@ class CompileKotlinAgainstCustomBinariesTest : AbstractKotlinCompilerIntegration } fun testWrongInlineTarget() { - val library = compileLibrary("library", additionalOptions = listOf("-jvm-target", "1.8")) + val library = compileLibrary("library", additionalOptions = listOf("-jvm-target", "11")) - compileKotlin("source.kt", tmpdir, listOf(library)) + compileKotlin("source.kt", tmpdir, listOf(library), additionalOptions = listOf("-jvm-target", "1.8")) compileKotlin( "warningsOnly_1_3.kt", tmpdir, listOf(library), diff --git a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleFacetImportTest.kt b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleFacetImportTest.kt index 7e318a4ba72..a043149a357 100644 --- a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleFacetImportTest.kt +++ b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleFacetImportTest.kt @@ -104,7 +104,7 @@ class GradleFacetImportTest : GradleImportingTestCase() { Assert.assertFalse(compilerArguments!!.autoAdvanceLanguageVersion) Assert.assertFalse(compilerArguments!!.autoAdvanceApiVersion) Assert.assertEquals(JvmPlatforms.jvm16, targetPlatform) - Assert.assertEquals("1.6", (compilerArguments as K2JVMCompilerArguments).jvmTarget) + Assert.assertEquals("1.8", (compilerArguments as K2JVMCompilerArguments).jvmTarget) Assert.assertEquals( "-Xallow-no-source-files -Xdump-declarations-to=tmpTest", compilerSettings!!.additionalArguments @@ -158,7 +158,7 @@ class GradleFacetImportTest : GradleImportingTestCase() { Assert.assertEquals("1.3", languageLevel!!.versionString) Assert.assertEquals("1.0", apiLevel!!.versionString) Assert.assertEquals(JvmPlatforms.jvm16, targetPlatform) - Assert.assertEquals("1.6", (compilerArguments as K2JVMCompilerArguments).jvmTarget) + Assert.assertEquals("1.8", (compilerArguments as K2JVMCompilerArguments).jvmTarget) Assert.assertEquals( "-Xallow-no-source-files -Xdump-declarations-to=tmpTest", compilerSettings!!.additionalArguments diff --git a/idea/idea-jps-common/src/org/jetbrains/kotlin/platform/impl/JvmIdePlatformKind.kt b/idea/idea-jps-common/src/org/jetbrains/kotlin/platform/impl/JvmIdePlatformKind.kt index 125b8313cab..378d3da152d 100644 --- a/idea/idea-jps-common/src/org/jetbrains/kotlin/platform/impl/JvmIdePlatformKind.kt +++ b/idea/idea-jps-common/src/org/jetbrains/kotlin/platform/impl/JvmIdePlatformKind.kt @@ -38,7 +38,7 @@ object JvmIdePlatformKind : IdePlatformKind() { message = "IdePlatform is deprecated and will be removed soon, please, migrate to org.jetbrains.kotlin.platform.TargetPlatform", level = DeprecationLevel.ERROR ) - override fun getDefaultPlatform(): Platform = Platform(JvmTarget.JVM_1_6) + override fun getDefaultPlatform(): Platform = Platform(JvmTarget.DEFAULT) override fun createArguments(): CommonCompilerArguments { return K2JVMCompilerArguments() diff --git a/idea/testData/checker/JvmStaticUsagesRuntime.kt b/idea/testData/checker/JvmStaticUsagesRuntime.kt index b703a912be2..0232e2efcbf 100644 --- a/idea/testData/checker/JvmStaticUsagesRuntime.kt +++ b/idea/testData/checker/JvmStaticUsagesRuntime.kt @@ -31,7 +31,7 @@ class A { @JvmStatic interface B { companion object { - @JvmStatic fun a1() { + @JvmStatic fun a1() { } } diff --git a/idea/testData/codeInsight/overrideImplement/jdk8/overrideCollectionStream.kt.after b/idea/testData/codeInsight/overrideImplement/jdk8/overrideCollectionStream.kt.after index 40ba4e99cd2..0a11604d3fa 100644 --- a/idea/testData/codeInsight/overrideImplement/jdk8/overrideCollectionStream.kt.after +++ b/idea/testData/codeInsight/overrideImplement/jdk8/overrideCollectionStream.kt.after @@ -1,4 +1,3 @@ -// ERROR: Super calls to Java default methods are prohibited in JVM target 1.6. Recompile with '-jvm-target 1.8' import java.util.stream.Stream abstract class A : List { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinJvmOptions.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinJvmOptions.kt index 2cb72665d13..700199bfcbd 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinJvmOptions.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinJvmOptions.kt @@ -23,9 +23,9 @@ interface KotlinJvmOptions : org.jetbrains.kotlin.gradle.dsl.KotlinCommonOption var jdkHome: kotlin.String? /** - * Target version of the generated JVM bytecode (1.6, 1.8, 9, 10, 11, 12, 13, 14 or 15), default is 1.6 + * Target version of the generated JVM bytecode (1.6, 1.8, 9, 10, 11, 12, 13, 14 or 15), default is 1.8 * Possible values: "1.6", "1.8", "9", "10", "11", "12", "13", "14", "15" - * Default value: "1.6" + * Default value: "1.8" */ var jvmTarget: kotlin.String diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinJvmOptionsBase.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinJvmOptionsBase.kt index db21b3735dc..b0d0f1263d2 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinJvmOptionsBase.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinJvmOptionsBase.kt @@ -62,7 +62,7 @@ internal abstract class KotlinJvmOptionsBase : org.jetbrains.kotlin.gradle.dsl.K private var jvmTargetField: kotlin.String? = null override var jvmTarget: kotlin.String - get() = jvmTargetField ?: "1.6" + get() = jvmTargetField ?: "1.8" set(value) { jvmTargetField = value } @@ -137,7 +137,7 @@ internal fun org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments.fi includeRuntime = false javaParameters = false jdkHome = null - jvmTarget = "1.6" + jvmTarget = "1.8" moduleName = null noJdk = false noReflect = true From 64e97225b8aefb2156b08a8af22e047a2d7379d8 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Thu, 21 Jan 2021 15:29:44 +0100 Subject: [PATCH 002/260] Light classes: map annotation targets depending on JVM target Since the default JVM target (`JvmTarget.DEFAULT`) is now 1.8, the changed test started to fail. This change fixes it. --- .../elements/KtToJvmAnnotationsConverter.kt | 36 ++++++++++++------- .../SpecialAnnotationsOnAnnotationClass.java | 6 ++-- .../SpecialAnnotationsOnAnnotationClass.kt | 2 +- 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtToJvmAnnotationsConverter.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtToJvmAnnotationsConverter.kt index 30a78d43dac..f8961b2280d 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtToJvmAnnotationsConverter.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtToJvmAnnotationsConverter.kt @@ -14,10 +14,12 @@ import com.intellij.psi.PsiNameValuePair import org.jetbrains.kotlin.asJava.classes.KtUltraLightSimpleAnnotation import org.jetbrains.kotlin.asJava.classes.KtUltraLightSupport import org.jetbrains.kotlin.builtins.StandardNames.FqNames +import org.jetbrains.kotlin.config.JvmTarget import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.constants.ArrayValue import org.jetbrains.kotlin.resolve.constants.EnumValue +import java.util.* private const val JAVA_LANG_ANNOTATION_DOCUMENTED = "java.lang.annotation.Documented" @@ -49,18 +51,27 @@ private fun PsiAnnotation.extractArrayAnnotationFqNames(attributeName: String): .map { "${it.first.asSingleFqName().asString()}.${it.second.identifier}" } } -private val javaAnnotationElementTypeId = ClassId.fromString("java.lang.annotation.ElementType") -private val targetMapping = hashMapOf( - "kotlin.annotation.AnnotationTarget.CLASS" to EnumValue(javaAnnotationElementTypeId, Name.identifier("TYPE")), - "kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS" to EnumValue(javaAnnotationElementTypeId, Name.identifier("ANNOTATION_TYPE")), - "kotlin.annotation.AnnotationTarget.FIELD" to EnumValue(javaAnnotationElementTypeId, Name.identifier("FIELD")), - "kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE" to EnumValue(javaAnnotationElementTypeId, Name.identifier("LOCAL_VARIABLE")), - "kotlin.annotation.AnnotationTarget.VALUE_PARAMETER" to EnumValue(javaAnnotationElementTypeId, Name.identifier("PARAMETER")), - "kotlin.annotation.AnnotationTarget.CONSTRUCTOR" to EnumValue(javaAnnotationElementTypeId, Name.identifier("CONSTRUCTOR")), - "kotlin.annotation.AnnotationTarget.FUNCTION" to EnumValue(javaAnnotationElementTypeId, Name.identifier("METHOD")), - "kotlin.annotation.AnnotationTarget.PROPERTY_GETTER" to EnumValue(javaAnnotationElementTypeId, Name.identifier("METHOD")), - "kotlin.annotation.AnnotationTarget.PROPERTY_SETTER" to EnumValue(javaAnnotationElementTypeId, Name.identifier("METHOD")) -) +private val targetMappings = EnumMap>(JvmTarget::class.java).also { result -> + val javaAnnotationElementTypeId = ClassId.fromString("java.lang.annotation.ElementType") + val jdk6 = hashMapOf( + "kotlin.annotation.AnnotationTarget.CLASS" to EnumValue(javaAnnotationElementTypeId, Name.identifier("TYPE")), + "kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS" to EnumValue(javaAnnotationElementTypeId, Name.identifier("ANNOTATION_TYPE")), + "kotlin.annotation.AnnotationTarget.FIELD" to EnumValue(javaAnnotationElementTypeId, Name.identifier("FIELD")), + "kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE" to EnumValue(javaAnnotationElementTypeId, Name.identifier("LOCAL_VARIABLE")), + "kotlin.annotation.AnnotationTarget.VALUE_PARAMETER" to EnumValue(javaAnnotationElementTypeId, Name.identifier("PARAMETER")), + "kotlin.annotation.AnnotationTarget.CONSTRUCTOR" to EnumValue(javaAnnotationElementTypeId, Name.identifier("CONSTRUCTOR")), + "kotlin.annotation.AnnotationTarget.FUNCTION" to EnumValue(javaAnnotationElementTypeId, Name.identifier("METHOD")), + "kotlin.annotation.AnnotationTarget.PROPERTY_GETTER" to EnumValue(javaAnnotationElementTypeId, Name.identifier("METHOD")), + "kotlin.annotation.AnnotationTarget.PROPERTY_SETTER" to EnumValue(javaAnnotationElementTypeId, Name.identifier("METHOD")) + ) + val jdk8AndLater = HashMap(jdk6).apply { + put("kotlin.annotation.AnnotationTarget.TYPE_PARAMETER", EnumValue(javaAnnotationElementTypeId, Name.identifier("TYPE_PARAMETER"))) + put("kotlin.annotation.AnnotationTarget.TYPE", EnumValue(javaAnnotationElementTypeId, Name.identifier("TYPE_USE"))) + } + for (target in JvmTarget.values()) { + result[target] = if (target >= JvmTarget.JVM_1_8) jdk8AndLater else jdk6 + } +} internal fun PsiAnnotation.tryConvertAsTarget(support: KtUltraLightSupport): KtLightAbstractAnnotation? { @@ -71,6 +82,7 @@ internal fun PsiAnnotation.tryConvertAsTarget(support: KtUltraLightSupport): KtL attributeValues ?: return null + val targetMapping = targetMappings.getValue(support.typeMapper.jvmTarget) val convertedValues = attributeValues.mapNotNull { targetMapping[it] }.distinct() val targetAttributes = "value" to ArrayValue(convertedValues) { module -> module.builtIns.array.defaultType } diff --git a/compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass.java b/compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass.java index e82640d994c..b9372c88d94 100644 --- a/compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass.java +++ b/compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass.java @@ -1,11 +1,11 @@ @java.lang.annotation.Documented() @java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.SOURCE) -@java.lang.annotation.Target(value = {}) +@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.TYPE_PARAMETER, java.lang.annotation.ElementType.TYPE_USE}) @kotlin.annotation.MustBeDocumented() @kotlin.annotation.Repeatable() @kotlin.annotation.Retention(value = kotlin.annotation.AnnotationRetention.SOURCE) -@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.TYPE_PARAMETER}) +@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.TYPE_PARAMETER, kotlin.annotation.AnnotationTarget.TYPE}) public abstract @interface Anno /* Anno*/ { public abstract int i();// i() -} \ No newline at end of file +} diff --git a/compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass.kt b/compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass.kt index 25433768b75..16242f5b9b4 100644 --- a/compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass.kt +++ b/compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass.kt @@ -1,7 +1,7 @@ // Anno @Retention(AnnotationRetention.SOURCE) -@Target(AnnotationTarget.TYPE_PARAMETER) +@Target(AnnotationTarget.TYPE_PARAMETER, AnnotationTarget.TYPE) @MustBeDocumented @Repeatable annotation class Anno(val i: Int) From adfa8c788ca97e4ba173fc51a10853171ff0f62b Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Mon, 25 Jan 2021 18:59:38 +0100 Subject: [PATCH 003/260] Light classes: use JVM target from the module Using "JVM_1_8" always resulted in incorrect mapping of Kotlin annotation targets to Java element types. The change in AbstractKotlinRenderLogTest is needed because while CliTraceHolder.module is technically a descriptor leak, it was never detected by this test accidentally, because of the depth cutoff equal to 10, which started to not be enough after the minor refactoring of replacing `Delegates.notNull` with `lateinit`. --- .../CliLightClassGenerationSupport.kt | 23 ++++-- .../kotlin/cli/jvm/compiler/CliTrace.kt | 19 +++-- .../kotlin/frontend/java/di/injection.kt | 5 +- .../load/java/AbstractJavaClassFinder.kt | 14 +++- .../resolve/jvm/JvmCodeAnalyzerInitializer.kt | 23 ++++++ .../kotlin/resolve/CodeAnalyzerInitializer.kt | 21 +----- .../javac/components/JavacBasedClassFinder.kt | 12 ++- .../asJava/builder/LightClassBuilder.kt | 2 + .../builder/LightClassConstructionContext.kt | 10 ++- ...ecialAnnotationsOnAnnotationClass_1_6.java | 11 +++ ...SpecialAnnotationsOnAnnotationClass_1_6.kt | 8 ++ .../annotationTargets_1_6.java | 16 ++++ .../annotationTargets_1_6.kt | 9 +++ .../CompilerLightClassTestGenerated.java | 5 ++ .../lightClasses/IDELightClassContexts.kt | 35 +++++++-- .../resolve/IDELightClassGenerationSupport.kt | 5 +- .../classes/FirClassLoadingTestGenerated.java | 5 ++ .../classes/FirLightClassTestGenerated.java | 5 ++ .../UltraLightClassLoadingTestGenerated.java | 5 ++ .../UltraLightClassSanityTestGenerated.java | 5 ++ .../resolve/AbstractIdeLightClassTest.kt | 74 ++++++++++--------- .../IdeCompiledLightClassTestGenerated.java | 5 ++ .../resolve/IdeLightClassTestGenerated.java | 5 ++ .../tests/AbstractKotlinRenderLogTest.kt | 4 +- 24 files changed, 234 insertions(+), 92 deletions(-) create mode 100644 compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/JvmCodeAnalyzerInitializer.kt create mode 100644 compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass_1_6.java create mode 100644 compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass_1_6.kt create mode 100644 compiler/testData/asJava/ultraLightClasses/annotationTargets_1_6.java create mode 100644 compiler/testData/asJava/ultraLightClasses/annotationTargets_1_6.kt diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/CliLightClassGenerationSupport.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/CliLightClassGenerationSupport.kt index 6cb009f43ad..127ca48593a 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/CliLightClassGenerationSupport.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/CliLightClassGenerationSupport.kt @@ -23,11 +23,17 @@ import org.jetbrains.kotlin.asJava.builder.InvalidLightClassDataHolder import org.jetbrains.kotlin.asJava.builder.LightClassConstructionContext import org.jetbrains.kotlin.asJava.builder.LightClassDataHolder import org.jetbrains.kotlin.asJava.builder.LightClassDataHolderImpl -import org.jetbrains.kotlin.asJava.classes.* +import org.jetbrains.kotlin.asJava.classes.KtUltraLightSupport +import org.jetbrains.kotlin.asJava.classes.cleanFromAnonymousTypes +import org.jetbrains.kotlin.asJava.classes.lazyPub +import org.jetbrains.kotlin.asJava.classes.tryGetPredefinedName import org.jetbrains.kotlin.codegen.ClassBuilderMode import org.jetbrains.kotlin.codegen.JvmCodegenUtil import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper -import org.jetbrains.kotlin.config.* +import org.jetbrains.kotlin.config.JvmAnalysisFlags +import org.jetbrains.kotlin.config.JvmTarget +import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.load.java.components.JavaDeprecationSettings import org.jetbrains.kotlin.name.Name @@ -57,7 +63,8 @@ class CliLightClassGenerationSupport( private class CliLightClassSupport( private val project: Project, - override val languageVersionSettings: LanguageVersionSettings + override val languageVersionSettings: LanguageVersionSettings, + private val jvmTarget: JvmTarget ) : KtUltraLightSupport { // This is the way to untie CliLightClassSupport and CliLightClassGenerationSupport to prevent descriptors leak @@ -88,7 +95,7 @@ class CliLightClassGenerationSupport( moduleName, languageVersionSettings, useOldInlineClassesManglingScheme = false, - jvmTarget = JvmTarget.JVM_1_8, + jvmTarget = jvmTarget, typePreprocessor = KotlinType::cleanFromAnonymousTypes, namePreprocessor = ::tryGetPredefinedName ) @@ -96,7 +103,7 @@ class CliLightClassGenerationSupport( } private val ultraLightSupport: KtUltraLightSupport by lazyPub { - CliLightClassSupport(project, traceHolder.languageVersionSettings) + CliLightClassSupport(project, traceHolder.languageVersionSettings, traceHolder.jvmTarget) } override fun getUltraLightClassSupport(element: KtElement): KtUltraLightSupport { @@ -129,7 +136,9 @@ class CliLightClassGenerationSupport( } private fun getContext(): LightClassConstructionContext = - LightClassConstructionContext(traceHolder.bindingContext, traceHolder.module) + LightClassConstructionContext( + traceHolder.bindingContext, traceHolder.module, null /* TODO: traceHolder.languageVersionSettings? */, traceHolder.jvmTarget + ) override fun resolveToDescriptor(declaration: KtDeclaration): DeclarationDescriptor? { return traceHolder.bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, declaration) @@ -140,4 +149,4 @@ class CliLightClassGenerationSupport( override fun analyzeAnnotation(element: KtAnnotationEntry) = traceHolder.bindingContext.get(BindingContext.ANNOTATION, element) override fun analyzeWithContent(element: KtClassOrObject) = traceHolder.bindingContext -} \ No newline at end of file +} diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/CliTrace.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/CliTrace.kt index 16a55f3edfb..790140a1943 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/CliTrace.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/CliTrace.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.cli.jvm.compiler import org.jetbrains.annotations.TestOnly +import org.jetbrains.kotlin.config.JvmTarget import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.psi.KtDeclaration @@ -13,30 +14,32 @@ import org.jetbrains.kotlin.psi.KtPsiUtil import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.BindingTraceContext -import org.jetbrains.kotlin.resolve.CodeAnalyzerInitializer +import org.jetbrains.kotlin.resolve.jvm.JvmCodeAnalyzerInitializer import org.jetbrains.kotlin.resolve.lazy.KotlinCodeAnalyzer import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice import org.jetbrains.kotlin.util.slicedMap.WritableSlice -import kotlin.properties.Delegates -class CliTraceHolder : CodeAnalyzerInitializer { - var bindingContext: BindingContext by Delegates.notNull() +class CliTraceHolder : JvmCodeAnalyzerInitializer() { + lateinit var bindingContext: BindingContext private set - var module: ModuleDescriptor by Delegates.notNull() + lateinit var module: ModuleDescriptor private set - var languageVersionSettings: LanguageVersionSettings by Delegates.notNull() + lateinit var languageVersionSettings: LanguageVersionSettings + private set + lateinit var jvmTarget: JvmTarget private set - override fun initialize( trace: BindingTrace, module: ModuleDescriptor, codeAnalyzer: KotlinCodeAnalyzer, - languageVersionSettings: LanguageVersionSettings + languageVersionSettings: LanguageVersionSettings, + jvmTarget: JvmTarget ) { this.bindingContext = trace.bindingContext this.module = module this.languageVersionSettings = languageVersionSettings + this.jvmTarget = jvmTarget if (trace !is CliBindingTrace) { throw IllegalArgumentException("Shared trace is expected to be subclass of ${CliBindingTrace::class.java.simpleName} class") diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/frontend/java/di/injection.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/frontend/java/di/injection.kt index 4758ae4a7f0..43fc9f78fe7 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/frontend/java/di/injection.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/frontend/java/di/injection.kt @@ -47,7 +47,6 @@ import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver import org.jetbrains.kotlin.resolve.jvm.JvmDiagnosticComponents import org.jetbrains.kotlin.resolve.jvm.multiplatform.OptionalAnnotationPackageFragmentProvider import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices -import org.jetbrains.kotlin.resolve.lazy.KotlinCodeAnalyzer import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory fun createContainerForLazyResolveWithJava( @@ -95,7 +94,9 @@ fun createContainerForLazyResolveWithJava( } fun StorageComponentContainer.initializeJavaSpecificComponents(bindingTrace: BindingTrace) { - get().initialize(bindingTrace, get(), get()) + get().initialize( + bindingTrace, codeAnalyzer = get(), languageVersionSettings = get(), jvmTarget = get() + ) } fun StorageComponentContainer.configureJavaSpecificComponents( diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/AbstractJavaClassFinder.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/AbstractJavaClassFinder.kt index 3363737904c..b946ea25b74 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/AbstractJavaClassFinder.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/AbstractJavaClassFinder.kt @@ -20,17 +20,18 @@ import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.VirtualFile import com.intellij.psi.search.DelegatingGlobalSearchScope import com.intellij.psi.search.GlobalSearchScope +import org.jetbrains.kotlin.config.JvmTarget import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.idea.KotlinFileType import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.CodeAnalyzerInitializer +import org.jetbrains.kotlin.resolve.jvm.JvmCodeAnalyzerInitializer import org.jetbrains.kotlin.resolve.jvm.TopPackageNamesProvider import org.jetbrains.kotlin.resolve.lazy.KotlinCodeAnalyzer import javax.annotation.PostConstruct import javax.inject.Inject abstract class AbstractJavaClassFinder : JavaClassFinder { - protected lateinit var project: Project protected lateinit var javaSearchScope: GlobalSearchScope @@ -50,8 +51,15 @@ abstract class AbstractJavaClassFinder : JavaClassFinder { } @PostConstruct - open fun initialize(trace: BindingTrace, codeAnalyzer: KotlinCodeAnalyzer, languageVersionSettings: LanguageVersionSettings) { - CodeAnalyzerInitializer.getInstance(project).initialize(trace, codeAnalyzer.moduleDescriptor, codeAnalyzer, languageVersionSettings) + open fun initialize( + trace: BindingTrace, + codeAnalyzer: KotlinCodeAnalyzer, + languageVersionSettings: LanguageVersionSettings, + jvmTarget: JvmTarget, + ) { + (CodeAnalyzerInitializer.getInstance(project) as? JvmCodeAnalyzerInitializer)?.initialize( + trace, codeAnalyzer.moduleDescriptor, codeAnalyzer, languageVersionSettings, jvmTarget + ) } inner class FilterOutKotlinSourceFilesScope(baseScope: GlobalSearchScope) : DelegatingGlobalSearchScope(baseScope), diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/JvmCodeAnalyzerInitializer.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/JvmCodeAnalyzerInitializer.kt new file mode 100644 index 00000000000..e6f2c68d70b --- /dev/null +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/JvmCodeAnalyzerInitializer.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.resolve.jvm + +import org.jetbrains.kotlin.config.JvmTarget +import org.jetbrains.kotlin.config.LanguageVersionSettings +import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.resolve.BindingTrace +import org.jetbrains.kotlin.resolve.CodeAnalyzerInitializer +import org.jetbrains.kotlin.resolve.lazy.KotlinCodeAnalyzer + +abstract class JvmCodeAnalyzerInitializer : CodeAnalyzerInitializer { + abstract fun initialize( + trace: BindingTrace, + module: ModuleDescriptor, + codeAnalyzer: KotlinCodeAnalyzer, + languageVersionSettings: LanguageVersionSettings, + jvmTarget: JvmTarget, + ) +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/CodeAnalyzerInitializer.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/CodeAnalyzerInitializer.kt index 8778524846e..a8d1c72a2ee 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/CodeAnalyzerInitializer.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/CodeAnalyzerInitializer.kt @@ -18,35 +18,16 @@ package org.jetbrains.kotlin.resolve import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.project.Project -import org.jetbrains.kotlin.config.LanguageVersionSettings -import org.jetbrains.kotlin.descriptors.ModuleDescriptor -import org.jetbrains.kotlin.resolve.lazy.KotlinCodeAnalyzer interface CodeAnalyzerInitializer { - fun initialize( - trace: BindingTrace, - module: ModuleDescriptor, - codeAnalyzer: KotlinCodeAnalyzer, - languageVersionSettings: LanguageVersionSettings - ) - fun createTrace(): BindingTrace companion object { fun getInstance(project: Project): CodeAnalyzerInitializer = - ServiceManager.getService(project, CodeAnalyzerInitializer::class.java)!! + ServiceManager.getService(project, CodeAnalyzerInitializer::class.java)!! } } class DummyCodeAnalyzerInitializer : CodeAnalyzerInitializer { - override fun initialize( - trace: BindingTrace, - module: ModuleDescriptor, - codeAnalyzer: KotlinCodeAnalyzer, - languageVersionSettings: LanguageVersionSettings - ) { - // Do nothing - } - override fun createTrace(): BindingTrace = BindingTraceContext(true) } diff --git a/compiler/javac-wrapper/src/org/jetbrains/kotlin/javac/components/JavacBasedClassFinder.kt b/compiler/javac-wrapper/src/org/jetbrains/kotlin/javac/components/JavacBasedClassFinder.kt index b41fc2e1873..cb3b5ab5cad 100644 --- a/compiler/javac-wrapper/src/org/jetbrains/kotlin/javac/components/JavacBasedClassFinder.kt +++ b/compiler/javac-wrapper/src/org/jetbrains/kotlin/javac/components/JavacBasedClassFinder.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.javac.components +import org.jetbrains.kotlin.config.JvmTarget import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.javac.JavacWrapper import org.jetbrains.kotlin.load.java.AbstractJavaClassFinder @@ -25,12 +26,16 @@ import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.lazy.KotlinCodeAnalyzer class JavacBasedClassFinder : AbstractJavaClassFinder() { - private lateinit var javac: JavacWrapper - override fun initialize(trace: BindingTrace, codeAnalyzer: KotlinCodeAnalyzer, languageVersionSettings: LanguageVersionSettings) { + override fun initialize( + trace: BindingTrace, + codeAnalyzer: KotlinCodeAnalyzer, + languageVersionSettings: LanguageVersionSettings, + jvmTarget: JvmTarget, + ) { javac = JavacWrapper.getInstance(project) - super.initialize(trace, codeAnalyzer, languageVersionSettings) + super.initialize(trace, codeAnalyzer, languageVersionSettings, jvmTarget) } override fun findClass(request: JavaClassFinder.Request) = @@ -40,5 +45,4 @@ class JavacBasedClassFinder : AbstractJavaClassFinder() { override fun findPackage(fqName: FqName) = javac.findPackage(fqName, javaSearchScope) override fun knownClassNamesInPackage(packageFqName: FqName) = javac.knownClassNamesInPackage(packageFqName) - } diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/builder/LightClassBuilder.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/builder/LightClassBuilder.kt index 3f78b51acba..1b6b29a3e8e 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/builder/LightClassBuilder.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/builder/LightClassBuilder.kt @@ -25,6 +25,7 @@ import com.intellij.psi.impl.java.stubs.PsiJavaFileStub import com.intellij.psi.impl.java.stubs.impl.PsiJavaFileStubImpl import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.config.JVMConfigurationKeys import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.KtFile @@ -53,6 +54,7 @@ fun buildLightClass( context.languageVersionSettings?.let { CompilerConfiguration().apply { languageVersionSettings = it + put(JVMConfigurationKeys.JVM_TARGET, context.jvmTarget) isReadOnly = true } } ?: CompilerConfiguration.EMPTY diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/builder/LightClassConstructionContext.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/builder/LightClassConstructionContext.kt index f3f42df0d43..30165a36e34 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/builder/LightClassConstructionContext.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/builder/LightClassConstructionContext.kt @@ -16,12 +16,14 @@ package org.jetbrains.kotlin.asJava.builder +import org.jetbrains.kotlin.config.JvmTarget import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.resolve.BindingContext open class LightClassConstructionContext( - val bindingContext: BindingContext, - val module: ModuleDescriptor, - val languageVersionSettings: LanguageVersionSettings? = null -) \ No newline at end of file + val bindingContext: BindingContext, + val module: ModuleDescriptor, + val languageVersionSettings: LanguageVersionSettings?, + val jvmTarget: JvmTarget, +) diff --git a/compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass_1_6.java b/compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass_1_6.java new file mode 100644 index 00000000000..b5f1f83c580 --- /dev/null +++ b/compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass_1_6.java @@ -0,0 +1,11 @@ +@java.lang.annotation.Documented() +@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.SOURCE) +@java.lang.annotation.Target(value = {}) +@kotlin.annotation.MustBeDocumented() +@kotlin.annotation.Repeatable() +@kotlin.annotation.Retention(value = kotlin.annotation.AnnotationRetention.SOURCE) +@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.TYPE_PARAMETER, kotlin.annotation.AnnotationTarget.TYPE}) +public abstract @interface Anno /* Anno*/ { + public abstract int i();// i() + +} diff --git a/compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass_1_6.kt b/compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass_1_6.kt new file mode 100644 index 00000000000..b1196da6bb9 --- /dev/null +++ b/compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass_1_6.kt @@ -0,0 +1,8 @@ +// Anno +// JVM_TARGET: 1.6 + +@Retention(AnnotationRetention.SOURCE) +@Target(AnnotationTarget.TYPE_PARAMETER, AnnotationTarget.TYPE) +@MustBeDocumented +@Repeatable +annotation class Anno(val i: Int) diff --git a/compiler/testData/asJava/ultraLightClasses/annotationTargets_1_6.java b/compiler/testData/asJava/ultraLightClasses/annotationTargets_1_6.java new file mode 100644 index 00000000000..37de513eb55 --- /dev/null +++ b/compiler/testData/asJava/ultraLightClasses/annotationTargets_1_6.java @@ -0,0 +1,16 @@ +@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) +@kotlin.annotation.Target() +public abstract @interface A0 /* A0*/ { +} + +@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) +@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.PARAMETER}) +@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.TYPE}) +public abstract @interface A1 /* A1*/ { +} + +@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) +@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.PARAMETER}) +@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.TYPE, kotlin.annotation.AnnotationTarget.TYPE_PARAMETER}) +public abstract @interface A2 /* A2*/ { +} \ No newline at end of file diff --git a/compiler/testData/asJava/ultraLightClasses/annotationTargets_1_6.kt b/compiler/testData/asJava/ultraLightClasses/annotationTargets_1_6.kt new file mode 100644 index 00000000000..013fc1dfb9d --- /dev/null +++ b/compiler/testData/asJava/ultraLightClasses/annotationTargets_1_6.kt @@ -0,0 +1,9 @@ +// CHECK_BY_JAVA_FILE +// JVM_TARGET: 1.6 + +@Target() +annotation class A0 +@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.TYPE) +annotation class A1 +@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.TYPE, AnnotationTarget.TYPE_PARAMETER) +annotation class A2 diff --git a/compiler/tests-gen/org/jetbrains/kotlin/asJava/CompilerLightClassTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/asJava/CompilerLightClassTestGenerated.java index b20a2d87734..d4cd77b162d 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/asJava/CompilerLightClassTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/asJava/CompilerLightClassTestGenerated.java @@ -149,6 +149,11 @@ public class CompilerLightClassTestGenerated extends AbstractCompilerLightClassT runTest("compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass.kt"); } + @TestMetadata("SpecialAnnotationsOnAnnotationClass_1_6.kt") + public void testSpecialAnnotationsOnAnnotationClass_1_6() throws Exception { + runTest("compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass_1_6.kt"); + } + @TestMetadata("StubOrderForOverloads.kt") public void testStubOrderForOverloads() throws Exception { runTest("compiler/testData/asJava/lightClasses/StubOrderForOverloads.kt"); diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/lightClasses/IDELightClassContexts.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/lightClasses/IDELightClassContexts.kt index 0189152cb63..313e01d6130 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/lightClasses/IDELightClassContexts.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/lightClasses/IDELightClassContexts.kt @@ -34,6 +34,7 @@ import org.jetbrains.kotlin.idea.compiler.IDELanguageSettingsProvider import org.jetbrains.kotlin.idea.project.IdeaEnvironment import org.jetbrains.kotlin.idea.project.ResolveElementCache import org.jetbrains.kotlin.idea.project.languageVersionSettings +import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.stubindex.KotlinOverridableInternalMembersShortNameIndex import org.jetbrains.kotlin.incremental.components.ExpectActualTracker import org.jetbrains.kotlin.incremental.components.LookupTracker @@ -69,12 +70,13 @@ import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.WrappedTypeFactory import org.jetbrains.kotlin.utils.sure - class IDELightClassConstructionContext( - bindingContext: BindingContext, module: ModuleDescriptor, + bindingContext: BindingContext, + module: ModuleDescriptor, languageVersionSettings: LanguageVersionSettings, + jvmTarget: JvmTarget, val mode: Mode -) : LightClassConstructionContext(bindingContext, module, languageVersionSettings) { +) : LightClassConstructionContext(bindingContext, module, languageVersionSettings, jvmTarget) { enum class Mode { LIGHT, EXACT @@ -106,6 +108,7 @@ internal object IDELightClassContexts { bindingContext, resolutionFacade.moduleDescriptor, classOrObject.languageVersionSettings, + resolutionFacade.jvmTarget, EXACT ) } @@ -122,6 +125,7 @@ internal object IDELightClassContexts { bindingContext, resolutionFacade.moduleDescriptor, classOrObject.languageVersionSettings, + resolutionFacade.jvmTarget, EXACT ) } @@ -132,20 +136,24 @@ internal object IDELightClassContexts { bindingContext, resolutionFacade.moduleDescriptor, classOrObject.languageVersionSettings, + resolutionFacade.jvmTarget, EXACT ) } fun contextForFacade(files: List): LightClassConstructionContext { + val resolutionFacade = files.first().getResolutionFacade() + @OptIn(FrontendInternals::class) - val resolveSession = files.first().getResolutionFacade().getFrontendService(ResolveSession::class.java) + val resolveSession = resolutionFacade.getFrontendService(ResolveSession::class.java) forceResolvePackageDeclarations(files, resolveSession) return IDELightClassConstructionContext( resolveSession.bindingContext, resolveSession.moduleDescriptor, files.first().languageVersionSettings, + resolutionFacade.jvmTarget, EXACT ) } @@ -161,21 +169,26 @@ internal object IDELightClassContexts { bindingContext, resolutionFacade.moduleDescriptor, script.languageVersionSettings, + resolutionFacade.jvmTarget, EXACT ) } ForceResolveUtil.forceResolveAllContents(descriptor) - return IDELightClassConstructionContext(bindingContext, resolutionFacade.moduleDescriptor, script.languageVersionSettings, EXACT) + return IDELightClassConstructionContext( + bindingContext, resolutionFacade.moduleDescriptor, script.languageVersionSettings, resolutionFacade.jvmTarget, + EXACT + ) } fun lightContextForClassOrObject(classOrObject: KtClassOrObject): LightClassConstructionContext? { if (!isDummyResolveApplicable(classOrObject)) return null + val resolutionFacade = classOrObject.getResolutionFacade() val resolveSession = setupAdHocResolve( classOrObject.project, - classOrObject.getResolutionFacade().moduleDescriptor, + resolutionFacade.moduleDescriptor, listOf(classOrObject.containingKtFile) ) @@ -188,13 +201,15 @@ internal object IDELightClassContexts { resolveSession.bindingContext, resolveSession.moduleDescriptor, classOrObject.languageVersionSettings, + resolutionFacade.jvmTarget, LIGHT ) } fun lightContextForFacade(files: List): LightClassConstructionContext { val representativeFile = files.first() - val resolveSession = setupAdHocResolve(representativeFile.project, representativeFile.getResolutionFacade().moduleDescriptor, files) + val resolutionFacade = representativeFile.getResolutionFacade() + val resolveSession = setupAdHocResolve(representativeFile.project, resolutionFacade.moduleDescriptor, files) forceResolvePackageDeclarations(files, resolveSession) @@ -202,10 +217,15 @@ internal object IDELightClassContexts { resolveSession.bindingContext, resolveSession.moduleDescriptor, files.first().languageVersionSettings, + resolutionFacade.jvmTarget, LIGHT ) } + @OptIn(FrontendInternals::class) + private val ResolutionFacade.jvmTarget: JvmTarget + get() = getFrontendService(JvmTarget::class.java) + private fun isDummyResolveApplicable(classOrObject: KtClassOrObject): Boolean { if (classOrObject.hasModifier(KtTokens.INLINE_KEYWORD)) return false @@ -447,4 +467,3 @@ internal object IDELightClassContexts { } } } - diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt index 00c01264e52..81a5c035f45 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt @@ -31,9 +31,12 @@ import org.jetbrains.kotlin.idea.FrontendInternals import org.jetbrains.kotlin.idea.caches.lightClasses.IDELightClassContexts import org.jetbrains.kotlin.idea.caches.lightClasses.LazyLightClassDataHolder import org.jetbrains.kotlin.idea.project.languageVersionSettings +import org.jetbrains.kotlin.idea.project.platform import org.jetbrains.kotlin.idea.resolve.frontendService import org.jetbrains.kotlin.idea.stubindex.KotlinTypeAliasShortNameIndex import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.platform.jvm.JdkPlatform +import org.jetbrains.kotlin.platform.subplatformsOfType import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver @@ -82,7 +85,7 @@ class IDELightClassGenerationSupport(project: Project) : LightClassGenerationSup BindingContext.EMPTY, ClassBuilderMode.LIGHT_CLASSES, moduleName, languageVersionSettings, useOldInlineClassesManglingScheme = false, - jvmTarget = JvmTarget.JVM_1_8, + jvmTarget = module?.platform?.subplatformsOfType()?.firstOrNull()?.targetVersion ?: JvmTarget.DEFAULT, typePreprocessor = KotlinType::cleanFromAnonymousTypes, namePreprocessor = ::tryGetPredefinedName ) diff --git a/idea/idea-fir/tests/org/jetbrains/kotlin/asJava/classes/FirClassLoadingTestGenerated.java b/idea/idea-fir/tests/org/jetbrains/kotlin/asJava/classes/FirClassLoadingTestGenerated.java index f76176205ec..205bd151375 100644 --- a/idea/idea-fir/tests/org/jetbrains/kotlin/asJava/classes/FirClassLoadingTestGenerated.java +++ b/idea/idea-fir/tests/org/jetbrains/kotlin/asJava/classes/FirClassLoadingTestGenerated.java @@ -29,6 +29,11 @@ public class FirClassLoadingTestGenerated extends AbstractFirClassLoadingTest { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/asJava/ultraLightClasses"), Pattern.compile("^(.+)\\.(kt|kts)$"), null, true); } + @TestMetadata("annotationTargets_1_6.kt") + public void testAnnotationTargets_1_6() throws Exception { + runTest("compiler/testData/asJava/ultraLightClasses/annotationTargets_1_6.kt"); + } + @TestMetadata("annotationWithSetParamPropertyModifier.kt") public void testAnnotationWithSetParamPropertyModifier() throws Exception { runTest("compiler/testData/asJava/ultraLightClasses/annotationWithSetParamPropertyModifier.kt"); diff --git a/idea/idea-fir/tests/org/jetbrains/kotlin/asJava/classes/FirLightClassTestGenerated.java b/idea/idea-fir/tests/org/jetbrains/kotlin/asJava/classes/FirLightClassTestGenerated.java index 06606e3307b..b71f544de78 100644 --- a/idea/idea-fir/tests/org/jetbrains/kotlin/asJava/classes/FirLightClassTestGenerated.java +++ b/idea/idea-fir/tests/org/jetbrains/kotlin/asJava/classes/FirLightClassTestGenerated.java @@ -149,6 +149,11 @@ public class FirLightClassTestGenerated extends AbstractFirLightClassTest { runTest("compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass.kt"); } + @TestMetadata("SpecialAnnotationsOnAnnotationClass_1_6.kt") + public void testSpecialAnnotationsOnAnnotationClass_1_6() throws Exception { + runTest("compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass_1_6.kt"); + } + @TestMetadata("StubOrderForOverloads.kt") public void testStubOrderForOverloads() throws Exception { runTest("compiler/testData/asJava/lightClasses/StubOrderForOverloads.kt"); diff --git a/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassLoadingTestGenerated.java b/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassLoadingTestGenerated.java index 092946c7d3d..aa5b88b4a16 100644 --- a/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassLoadingTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassLoadingTestGenerated.java @@ -29,6 +29,11 @@ public class UltraLightClassLoadingTestGenerated extends AbstractUltraLightClass KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/asJava/ultraLightClasses"), Pattern.compile("^(.+)\\.(kt|kts)$"), null, true); } + @TestMetadata("annotationTargets_1_6.kt") + public void testAnnotationTargets_1_6() throws Exception { + runTest("compiler/testData/asJava/ultraLightClasses/annotationTargets_1_6.kt"); + } + @TestMetadata("annotationWithSetParamPropertyModifier.kt") public void testAnnotationWithSetParamPropertyModifier() throws Exception { runTest("compiler/testData/asJava/ultraLightClasses/annotationWithSetParamPropertyModifier.kt"); diff --git a/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassSanityTestGenerated.java b/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassSanityTestGenerated.java index c8aeb52ff76..b21d568ccae 100644 --- a/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassSanityTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassSanityTestGenerated.java @@ -149,6 +149,11 @@ public class UltraLightClassSanityTestGenerated extends AbstractUltraLightClassS runTest("compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass.kt"); } + @TestMetadata("SpecialAnnotationsOnAnnotationClass_1_6.kt") + public void testSpecialAnnotationsOnAnnotationClass_1_6() throws Exception { + runTest("compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass_1_6.kt"); + } + @TestMetadata("StubOrderForOverloads.kt") public void testStubOrderForOverloads() throws Exception { runTest("compiler/testData/asJava/lightClasses/StubOrderForOverloads.kt"); diff --git a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/AbstractIdeLightClassTest.kt b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/AbstractIdeLightClassTest.kt index c57ff31b513..fb29c585dd8 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/AbstractIdeLightClassTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/AbstractIdeLightClassTest.kt @@ -19,7 +19,6 @@ import org.jetbrains.kotlin.asJava.builder.LightClassConstructionContext import org.jetbrains.kotlin.asJava.builder.StubComputationTracker import org.jetbrains.kotlin.asJava.classes.KtLightClass import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade -import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration import org.jetbrains.kotlin.asJava.elements.* import org.jetbrains.kotlin.asJava.toLightClass import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime @@ -29,8 +28,10 @@ import org.jetbrains.kotlin.idea.caches.resolve.LightClassLazinessChecker.Tracke import org.jetbrains.kotlin.idea.completion.test.withServiceRegistered import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager import org.jetbrains.kotlin.idea.perf.forceUsingOldLightClassesForTest +import org.jetbrains.kotlin.idea.test.CompilerTestDirectives import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor +import org.jetbrains.kotlin.idea.test.withCustomCompilerOptions import org.jetbrains.kotlin.load.java.JvmAnnotationNames import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtFile @@ -39,14 +40,13 @@ import org.jetbrains.kotlin.test.MockLibraryUtilExt import org.jetbrains.kotlin.test.util.KtTestUtil import org.jetbrains.kotlin.utils.keysToMap import org.jetbrains.plugins.groovy.lang.psi.impl.stringValue -import org.junit.Assert import java.io.File import kotlin.test.assertEquals import kotlin.test.assertNotNull import kotlin.test.assertTrue abstract class AbstractIdeLightClassTest : KotlinLightCodeInsightFixtureTestCase() { - fun doTest(unused: String) { + fun doTest(@Suppress("UNUSED_PARAMETER") unused: String) { forceUsingOldLightClassesForTest() val fileName = fileName() val extraFilePath = when { @@ -54,30 +54,31 @@ abstract class AbstractIdeLightClassTest : KotlinLightCodeInsightFixtureTestCase else -> error("Invalid test data extension") } - val testFiles = if (File(testDataPath, extraFilePath).isFile) listOf(fileName, extraFilePath) else listOf(fileName) + withCustomCompilerOptions(File(testDataPath, fileName).readText(), project, module) { + val testFiles = if (File(testDataPath, extraFilePath).isFile) listOf(fileName, extraFilePath) else listOf(fileName) + val lazinessMode = lazinessModeByFileText() + myFixture.configureByFiles(*testFiles.toTypedArray()) + if ((myFixture.file as? KtFile)?.isScript() == true) { + ScriptConfigurationManager.updateScriptDependenciesSynchronously(myFixture.file) + } - val lazinessMode = lazinessModeByFileText() - myFixture.configureByFiles(*testFiles.toTypedArray()) - if ((myFixture.file as? KtFile)?.isScript() == true) { - ScriptConfigurationManager.updateScriptDependenciesSynchronously(myFixture.file) - } - - val ktFile = myFixture.file as KtFile - val testData = testDataFile() - testLightClass( - KotlinTestUtils.replaceExtension(testData, "java"), - testData, - { LightClassTestCommon.removeEmptyDefaultImpls(it) }, - { fqName -> - val tracker = LightClassLazinessChecker.Tracker(fqName) - project.withServiceRegistered(tracker) { - findClass(fqName, ktFile, project)?.apply { - LightClassLazinessChecker.check(this as KtLightClass, tracker, lazinessMode) - tracker.allowLevel(EXACT) - PsiElementChecker.checkPsiElementStructure(this) + val ktFile = myFixture.file as KtFile + val testData = testDataFile() + testLightClass( + KotlinTestUtils.replaceExtension(testData, "java"), + testData, + { LightClassTestCommon.removeEmptyDefaultImpls(it) }, + { fqName -> + val tracker = LightClassLazinessChecker.Tracker(fqName) + project.withServiceRegistered(tracker) { + findClass(fqName, ktFile, project)?.apply { + LightClassLazinessChecker.check(this as KtLightClass, tracker, lazinessMode) + tracker.allowLevel(EXACT) + PsiElementChecker.checkPsiElementStructure(this) + } } - } - }) + }) + } } private fun lazinessModeByFileText(): LightClassLazinessChecker.Mode { @@ -105,11 +106,16 @@ abstract class AbstractIdeCompiledLightClassTest : KotlinDaemonAnalyzerTestCase( val filePathWithoutExtension = "${KtTestUtil.getTestsRoot(this::class.java)}/${getTestName(false)}" val testFile = File("$filePathWithoutExtension.kt").takeIf { it.exists() } ?: File("$filePathWithoutExtension.kts").takeIf { it.exists() } + ?: error("Test file not found!") - Assert.assertNotNull("Test file not found!", testFile) - + val extraOptions = KotlinTestUtils.parseDirectives(testFile.readText())[ + CompilerTestDirectives.JVM_TARGET_DIRECTIVE.substringBefore(":") + ]?.let { jvmTarget -> + listOf("-jvm-target", jvmTarget) + } ?: emptyList() val libraryJar = MockLibraryUtilExt.compileJvmLibraryToJar( - testFile!!.canonicalPath, libName(), + testFile.canonicalPath, libName(), + extraOptions = extraOptions, extraClasspath = listOf(ForTestCompileRuntime.jetbrainsAnnotationsForTests().path) ) val jarUrl = "jar://" + FileUtilRt.toSystemIndependentName(libraryJar.absolutePath) + "!/" @@ -123,11 +129,13 @@ abstract class AbstractIdeCompiledLightClassTest : KotlinDaemonAnalyzerTestCase( val expectedFile = KotlinTestUtils.replaceExtension( testDataFile, "compiled.java" ).let { if (it.exists()) it else KotlinTestUtils.replaceExtension(testDataFile, "java") } - testLightClass(expectedFile, testDataFile, { it }, { - findClass(it, null, project)?.apply { - PsiElementChecker.checkPsiElementStructure(this) - } - }) + withCustomCompilerOptions(testDataFile.readText(), project, module) { + testLightClass(expectedFile, testDataFile, { it }, { + findClass(it, null, project)?.apply { + PsiElementChecker.checkPsiElementStructure(this) + } + }) + } } } diff --git a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeCompiledLightClassTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeCompiledLightClassTestGenerated.java index 24bc5519203..90778617ed2 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeCompiledLightClassTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeCompiledLightClassTestGenerated.java @@ -149,6 +149,11 @@ public class IdeCompiledLightClassTestGenerated extends AbstractIdeCompiledLight runTest("compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass.kt"); } + @TestMetadata("SpecialAnnotationsOnAnnotationClass_1_6.kt") + public void testSpecialAnnotationsOnAnnotationClass_1_6() throws Exception { + runTest("compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass_1_6.kt"); + } + @TestMetadata("StubOrderForOverloads.kt") public void testStubOrderForOverloads() throws Exception { runTest("compiler/testData/asJava/lightClasses/StubOrderForOverloads.kt"); diff --git a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeLightClassTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeLightClassTestGenerated.java index a9c4476370c..4f292bc941a 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeLightClassTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeLightClassTestGenerated.java @@ -149,6 +149,11 @@ public class IdeLightClassTestGenerated extends AbstractIdeLightClassTest { runTest("compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass.kt"); } + @TestMetadata("SpecialAnnotationsOnAnnotationClass_1_6.kt") + public void testSpecialAnnotationsOnAnnotationClass_1_6() throws Exception { + runTest("compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass_1_6.kt"); + } + @TestMetadata("StubOrderForOverloads.kt") public void testStubOrderForOverloads() throws Exception { runTest("compiler/testData/asJava/lightClasses/StubOrderForOverloads.kt"); diff --git a/plugins/uast-kotlin/tests/AbstractKotlinRenderLogTest.kt b/plugins/uast-kotlin/tests/AbstractKotlinRenderLogTest.kt index bfe90246da6..5a03238a2da 100644 --- a/plugins/uast-kotlin/tests/AbstractKotlinRenderLogTest.kt +++ b/plugins/uast-kotlin/tests/AbstractKotlinRenderLogTest.kt @@ -1,6 +1,5 @@ package org.jetbrains.uast.test.kotlin -import com.intellij.openapi.util.Conditions import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile import com.intellij.psi.PsiRecursiveElementVisitor @@ -9,6 +8,7 @@ import com.intellij.util.PairProcessor import com.intellij.util.ref.DebugReflectionUtil import junit.framework.TestCase import junit.framework.TestCase.* +import org.jetbrains.kotlin.cli.jvm.compiler.CliTraceHolder import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.psi.KtElement @@ -152,7 +152,7 @@ fun checkDescriptorsLeak(node: UElement) { 10, mapOf(node to node.javaClass.name), Any::class.java, - Conditions.alwaysTrue(), + { it !is CliTraceHolder }, PairProcessor { value, backLink -> descriptorsClasses.find { it.isInstance(value) }?.let { TestCase.fail("""Leaked descriptor ${it.qualifiedName} in ${node.javaClass.name}\n$backLink""") From e9436da858e0b49f7d3a34b397c5b705fd71347e Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Thu, 28 Jan 2021 14:50:39 +0100 Subject: [PATCH 004/260] Change logic of applying JVM target from AGP options Now that the default JVM target is 1.8, we have to add the JVM target 1.6 explicitly if the Android project is configured with source/target 1.6, and not do anything if it's configured with 1.8. #KT-31027 --- .../AbstractKotlinAndroidGradleTests.kt | 34 +++++++++---------- .../kotlin/gradle/plugin/KotlinPlugin.kt | 6 ++-- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/AbstractKotlinAndroidGradleTests.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/AbstractKotlinAndroidGradleTests.kt index a7bf583801c..9074011f5ed 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/AbstractKotlinAndroidGradleTests.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/AbstractKotlinAndroidGradleTests.kt @@ -867,21 +867,7 @@ fun getSomething() = 10 fun testDetectAndroidJava8() = with(Project("AndroidProject")) { setupWorkingDir() - val kotlinJvmTarget18Regex = Regex("Kotlin compiler args: .* -jvm-target 1.8") - - gradleBuildScript("Lib").appendText( - "\n" + """ - android.compileOptions { - sourceCompatibility JavaVersion.VERSION_1_6 - targetCompatibility JavaVersion.VERSION_1_6 - } - """.trimIndent() - ) - - build(":Lib:assembleDebug", "-Pkotlin.setJvmTargetFromAndroidCompileOptions=true") { - assertSuccessful() - assertNotContains(kotlinJvmTarget18Regex) - } + val kotlinJvmTarget16Regex = Regex("Kotlin compiler args: .* -jvm-target 1.6") gradleBuildScript("Lib").appendText( "\n" + """ @@ -892,14 +878,28 @@ fun getSomething() = 10 """.trimIndent() ) + build(":Lib:assembleDebug", "-Pkotlin.setJvmTargetFromAndroidCompileOptions=true") { + assertSuccessful() + assertNotContains(kotlinJvmTarget16Regex) + } + + gradleBuildScript("Lib").appendText( + "\n" + """ + android.compileOptions { + sourceCompatibility JavaVersion.VERSION_1_6 + targetCompatibility JavaVersion.VERSION_1_6 + } + """.trimIndent() + ) + build("clean", ":Lib:assembleDebug") { assertSuccessful() - assertNotContains(kotlinJvmTarget18Regex) + assertNotContains(kotlinJvmTarget16Regex) } build(":Lib:assembleDebug", "-Pkotlin.setJvmTargetFromAndroidCompileOptions=true") { assertSuccessful() - assertContainsRegex(kotlinJvmTarget18Regex) + assertContainsRegex(kotlinJvmTarget16Regex) } } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt index 2195f8c040f..1d56732bf87 100755 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt @@ -950,9 +950,9 @@ abstract class AbstractAndroidProjectHandler(private val kotlinConfigurationTool private fun applyAndroidJavaVersion(baseExtension: BaseExtension, kotlinOptions: KotlinJvmOptions) { val javaVersion = - listOf(baseExtension.compileOptions.sourceCompatibility, baseExtension.compileOptions.targetCompatibility).min()!! - if (javaVersion >= JavaVersion.VERSION_1_8) - kotlinOptions.jvmTarget = "1.8" + minOf(baseExtension.compileOptions.sourceCompatibility, baseExtension.compileOptions.targetCompatibility) + if (javaVersion == JavaVersion.VERSION_1_6) + kotlinOptions.jvmTarget = "1.6" } private fun preprocessVariant( From d8549d6292491e858547dc953aeb88342d718eb1 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Fri, 29 Jan 2021 19:12:48 +0100 Subject: [PATCH 005/260] Build: fix inaccurate change to the logic of useIRForLibraries --- libraries/commonConfiguration.gradle | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/commonConfiguration.gradle b/libraries/commonConfiguration.gradle index fa1dcc5495b..6fc1f54f027 100644 --- a/libraries/commonConfiguration.gradle +++ b/libraries/commonConfiguration.gradle @@ -208,8 +208,10 @@ ext.configureLegacyPublishing = { Project project -> ext.configureJvmIrBackend = { Project project -> project.tasks.withType(KotlinCompile.class) { task -> task.kotlinOptions { - useIR = project.kotlinBuildProperties.useIRForLibraries - freeCompilerArgs += "-Xuse-old-backend" + if (!project.kotlinBuildProperties.useIRForLibraries) { + useIR = false + freeCompilerArgs += "-Xuse-old-backend" + } } } } From 5c0231b727d923d8c5037fd35742671c07c6f0bc Mon Sep 17 00:00:00 2001 From: eugenpolytechnic Date: Fri, 29 Jan 2021 23:57:19 +0300 Subject: [PATCH 006/260] FIR: introduce CatchParameterChecker --- ...TouchedTilContractsPhaseTestGenerated.java | 5 +++ .../testData/resolve/catchParameter.fir.txt | 20 +++++++++++ .../testData/resolve/catchParameter.kt | 13 +++++++ .../runners/FirDiagnosticTestGenerated.java | 6 ++++ ...DiagnosticsWithLightTreeTestGenerated.java | 6 ++++ .../kotlin/fir/checkers/generator/Main.kt | 2 ++ .../expression/ComposedExpressionCheckers.kt | 4 +++ .../checkers/expression/ExpressionCheckers.kt | 2 ++ .../expression/FirExpressionCheckerAliases.kt | 2 ++ .../expression/FirCatchParameterChecker.kt | 35 +++++++++++++++++++ .../ExpressionCheckersDiagnosticComponent.kt | 2 +- .../diagnostics/FirDefaultErrorMessages.kt | 15 ++++++++ .../fir/analysis/diagnostics/FirErrors.kt | 7 ++-- .../fir/checkers/CommonExpressionCheckers.kt | 4 +++ .../controlStructures/catchGenerics.fir.kt | 6 ++-- .../controlStructures/catchWithDefault.fir.kt | 4 +-- 16 files changed, 123 insertions(+), 10 deletions(-) create mode 100644 compiler/fir/analysis-tests/testData/resolve/catchParameter.fir.txt create mode 100644 compiler/fir/analysis-tests/testData/resolve/catchParameter.kt create mode 100644 compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirCatchParameterChecker.kt diff --git a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java index 18e275d1142..bc3dcee379d 100644 --- a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java +++ b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java @@ -54,6 +54,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract runTest("compiler/fir/analysis-tests/testData/resolve/cast.kt"); } + @TestMetadata("catchParameter.kt") + public void testCatchParameter() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/catchParameter.kt"); + } + @TestMetadata("companion.kt") public void testCompanion() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/companion.kt"); diff --git a/compiler/fir/analysis-tests/testData/resolve/catchParameter.fir.txt b/compiler/fir/analysis-tests/testData/resolve/catchParameter.fir.txt new file mode 100644 index 00000000000..1e253b1f2dd --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/catchParameter.fir.txt @@ -0,0 +1,20 @@ +FILE: catchParameter.kt + public final fun test(): R|kotlin/Unit| { + try { + } + catch (e: R|kotlin/NullPointerException| = R|java/lang/NullPointerException.NullPointerException|()) { + } + + try { + } + catch (e: R|T|) { + } + + } + public final inline fun anotherTest(): R|kotlin/Unit| { + try { + } + catch (e: R|T|) { + } + + } \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/resolve/catchParameter.kt b/compiler/fir/analysis-tests/testData/resolve/catchParameter.kt new file mode 100644 index 00000000000..0a0f2b86410 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/catchParameter.kt @@ -0,0 +1,13 @@ +fun test() { + try { + + } catch (e: NullPointerException = NullPointerException()) { + + } + + try {} catch (e: T) {} +} + +inline fun anotherTest() { + try {} catch (e: T) {} +} \ No newline at end of file diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java index 0a8480423e5..3ee6cbb889b 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java @@ -56,6 +56,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest { runTest("compiler/fir/analysis-tests/testData/resolve/cast.kt"); } + @Test + @TestMetadata("catchParameter.kt") + public void testCatchParameter() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/catchParameter.kt"); + } + @Test @TestMetadata("companion.kt") public void testCompanion() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java index 5715994f8f3..2248bdb9a1b 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java @@ -59,6 +59,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos runTest("compiler/fir/analysis-tests/testData/resolve/cast.kt"); } + @Test + @TestMetadata("catchParameter.kt") + public void testCatchParameter() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/catchParameter.kt"); + } + @Test @TestMetadata("companion.kt") public void testCompanion() throws Exception { diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/Main.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/Main.kt index 41ec1d4a3a1..1aafa0e2f4b 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/Main.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/Main.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.expressions.FirFunctionCall import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression import org.jetbrains.kotlin.fir.expressions.FirStatement import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment +import org.jetbrains.kotlin.fir.expressions.FirTryExpression import java.io.File fun main(args: Array) { @@ -21,6 +22,7 @@ fun main(args: Array) { alias("QualifiedAccessChecker") alias("FunctionCallChecker") alias("VariableAssignmentChecker") + alias("TryExpressionChecker") } val declarationPackage = "org.jetbrains.kotlin.fir.analysis.checkers.declaration" diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/ComposedExpressionCheckers.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/ComposedExpressionCheckers.kt index 842faa079dc..f4e8d19e20a 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/ComposedExpressionCheckers.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/ComposedExpressionCheckers.kt @@ -21,11 +21,14 @@ internal class ComposedExpressionCheckers : ExpressionCheckers() { get() = _functionCallCheckers override val variableAssignmentCheckers: Set get() = _variableAssignmentCheckers + override val tryExpressionCheckers: Set + get() = _tryExpressionCheckers private val _basicExpressionCheckers: MutableSet = mutableSetOf() private val _qualifiedAccessCheckers: MutableSet = mutableSetOf() private val _functionCallCheckers: MutableSet = mutableSetOf() private val _variableAssignmentCheckers: MutableSet = mutableSetOf() + private val _tryExpressionCheckers: MutableSet = mutableSetOf() @CheckersComponentInternal internal fun register(checkers: ExpressionCheckers) { @@ -33,5 +36,6 @@ internal class ComposedExpressionCheckers : ExpressionCheckers() { _qualifiedAccessCheckers += checkers.allQualifiedAccessCheckers _functionCallCheckers += checkers.allFunctionCallCheckers _variableAssignmentCheckers += checkers.allVariableAssignmentCheckers + _tryExpressionCheckers += checkers.allTryExpressionCheckers } } diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/ExpressionCheckers.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/ExpressionCheckers.kt index 73101389aa4..72e167d29e2 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/ExpressionCheckers.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/ExpressionCheckers.kt @@ -21,9 +21,11 @@ abstract class ExpressionCheckers { open val qualifiedAccessCheckers: Set = emptySet() open val functionCallCheckers: Set = emptySet() open val variableAssignmentCheckers: Set = emptySet() + open val tryExpressionCheckers: Set = emptySet() @CheckersComponentInternal internal val allBasicExpressionCheckers: Set get() = basicExpressionCheckers @CheckersComponentInternal internal val allQualifiedAccessCheckers: Set get() = qualifiedAccessCheckers + allBasicExpressionCheckers @CheckersComponentInternal internal val allFunctionCallCheckers: Set get() = functionCallCheckers + allQualifiedAccessCheckers @CheckersComponentInternal internal val allVariableAssignmentCheckers: Set get() = variableAssignmentCheckers + allBasicExpressionCheckers + @CheckersComponentInternal internal val allTryExpressionCheckers: Set get() = tryExpressionCheckers + allBasicExpressionCheckers } diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirExpressionCheckerAliases.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirExpressionCheckerAliases.kt index 5ff7f6070cd..3f7f70d9f3d 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirExpressionCheckerAliases.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirExpressionCheckerAliases.kt @@ -13,9 +13,11 @@ package org.jetbrains.kotlin.fir.analysis.checkers.expression import org.jetbrains.kotlin.fir.expressions.FirFunctionCall import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression import org.jetbrains.kotlin.fir.expressions.FirStatement +import org.jetbrains.kotlin.fir.expressions.FirTryExpression import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment typealias FirBasicExpressionChecker = FirExpressionChecker typealias FirQualifiedAccessChecker = FirExpressionChecker typealias FirFunctionCallChecker = FirExpressionChecker typealias FirVariableAssignmentChecker = FirExpressionChecker +typealias FirTryExpressionChecker = FirExpressionChecker diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirCatchParameterChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirCatchParameterChecker.kt new file mode 100644 index 00000000000..4205522572c --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirCatchParameterChecker.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.analysis.checkers.expression + +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors +import org.jetbrains.kotlin.fir.expressions.FirTryExpression +import org.jetbrains.kotlin.fir.types.ConeTypeParameterType +import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef + +object FirCatchParameterChecker : FirTryExpressionChecker() { + override fun check(expression: FirTryExpression, context: CheckerContext, reporter: DiagnosticReporter) { + for (catchEntry in expression.catches) { + val catchParameter = catchEntry.parameter + + if (catchParameter.defaultValue != null) + reporter.report(catchParameter.source?.let { FirErrors.CATCH_PARAMETER_WITH_DEFAULT_VALUE.on(it) }) + + val typeRef = catchParameter.returnTypeRef + if (typeRef is FirResolvedTypeRef && typeRef.type is ConeTypeParameterType) { + val isReified = (typeRef.type as ConeTypeParameterType).lookupTag.typeParameterSymbol.fir.isReified + + if (isReified) { + reporter.report(catchParameter.source?.let { FirErrors.REIFIED_TYPE_IN_CATCH_CLAUSE.on(it) }) + } else { + reporter.report(catchParameter.source?.let { FirErrors.TYPE_PARAMETER_IN_CATCH_CLAUSE.on(it) }) + } + } + } + } +} \ No newline at end of file diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ExpressionCheckersDiagnosticComponent.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ExpressionCheckersDiagnosticComponent.kt index 8f737d23862..ba5376b9c2a 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ExpressionCheckersDiagnosticComponent.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ExpressionCheckersDiagnosticComponent.kt @@ -73,7 +73,7 @@ class ExpressionCheckersDiagnosticComponent(collector: AbstractDiagnosticCollect } override fun visitTryExpression(tryExpression: FirTryExpression, data: CheckerContext) { - checkers.basicExpressionCheckers.check(tryExpression, data, reporter) + checkers.tryExpressionCheckers.check(tryExpression, data, reporter) } override fun visitClassReferenceExpression(classReferenceExpression: FirClassReferenceExpression, data: CheckerContext) { diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt index 4da06ddfe13..edae7bea6ab 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt @@ -34,6 +34,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ASSIGN_OPERATOR_A import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.BREAK_OR_CONTINUE_OUTSIDE_A_LOOP import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CAN_BE_VAL +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CATCH_PARAMETER_WITH_DEFAULT_VALUE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CLASS_IN_SUPERTYPE_FOR_ENUM import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.COMPONENT_FUNCTION_AMBIGUITY import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.COMPONENT_FUNCTION_MISSING @@ -118,6 +119,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_RETURN_ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_SETTER_PARAMETER_TYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_SINGLE_EXPRESSION_STRING_TEMPLATE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_VISIBILITY_MODIFIER +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REIFIED_TYPE_IN_CATCH_CLAUSE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REPEATED_MODIFIER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RETURN_NOT_ALLOWED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RETURN_TYPE_MISMATCH_ON_OVERRIDE @@ -135,6 +137,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_MISMATCH import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETERS_IN_ENUM import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETERS_IN_OBJECT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_AS_SUPERTYPE +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_IN_CATCH_CLAUSE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNINITIALIZED_VARIABLE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNRESOLVED_LABEL import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNRESOLVED_REFERENCE @@ -337,6 +340,18 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension { TO_STRING, DECLARATION_NAME ) // # + map.put( + CATCH_PARAMETER_WITH_DEFAULT_VALUE, + "Catch clause parameter may not have a default value" + ) + map.put( + REIFIED_TYPE_IN_CATCH_CLAUSE, + "Reified type is forbidden for catch parameter" + ) + map.put( + TYPE_PARAMETER_IN_CATCH_CLAUSE, + "Type parameter is forbidden for catch parameter" + ) // Redeclarations map.put(MANY_COMPANION_OBJECTS, "Only one companion object is allowed per class") diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index 83ee92ce381..6b9c5751864 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -12,16 +12,12 @@ import org.jetbrains.kotlin.fir.FirEffectiveVisibility import org.jetbrains.kotlin.fir.FirSourceElement import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration -import org.jetbrains.kotlin.fir.expressions.FirExpression -import org.jetbrains.kotlin.fir.expressions.FirStatement import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.types.ConeKotlinType -import org.jetbrains.kotlin.fir.types.FirTypeRef import org.jetbrains.kotlin.lexer.KtModifierKeywordToken import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.types.KotlinType object FirErrors { // Miscellaneous @@ -139,6 +135,9 @@ object FirErrors { val RETURN_TYPE_MISMATCH_ON_OVERRIDE by error2() val PROPERTY_TYPE_MISMATCH_ON_OVERRIDE by error2() val VAR_TYPE_MISMATCH_ON_OVERRIDE by error2() + val CATCH_PARAMETER_WITH_DEFAULT_VALUE by error0() + val REIFIED_TYPE_IN_CATCH_CLAUSE by error0() + val TYPE_PARAMETER_IN_CATCH_CLAUSE by error0() // Redeclarations val MANY_COMPANION_OBJECTS by error0() diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonExpressionCheckers.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonExpressionCheckers.kt index f93b89239f3..4ffda04a3ec 100644 --- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonExpressionCheckers.kt +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonExpressionCheckers.kt @@ -24,4 +24,8 @@ object CommonExpressionCheckers : ExpressionCheckers() { FirSealedClassConstructorCallChecker, ) override val functionCallCheckers: Set = setOf() + + override val tryExpressionCheckers: Set = setOf( + FirCatchParameterChecker + ) } diff --git a/compiler/testData/diagnostics/tests/controlStructures/catchGenerics.fir.kt b/compiler/testData/diagnostics/tests/controlStructures/catchGenerics.fir.kt index 44d55d0b17a..aa49bfb5632 100644 --- a/compiler/testData/diagnostics/tests/controlStructures/catchGenerics.fir.kt +++ b/compiler/testData/diagnostics/tests/controlStructures/catchGenerics.fir.kt @@ -17,10 +17,10 @@ fun bar() { inline fun tryCatch(lazy: () -> R, failure: (E) -> R): R = try { lazy() - } catch (e: E) { + } catch (e: E) { failure(e) } fun tryCatch() { - try { } catch (e: T) { } -} \ No newline at end of file + try { } catch (e: T) { } +} diff --git a/compiler/testData/diagnostics/tests/controlStructures/catchWithDefault.fir.kt b/compiler/testData/diagnostics/tests/controlStructures/catchWithDefault.fir.kt index 8e568f28604..bac12215b6a 100644 --- a/compiler/testData/diagnostics/tests/controlStructures/catchWithDefault.fir.kt +++ b/compiler/testData/diagnostics/tests/controlStructures/catchWithDefault.fir.kt @@ -1,3 +1,3 @@ fun test() { - try { } catch (e: Exception = Exception()) { } -} \ No newline at end of file + try { } catch (e: Exception = Exception()) { } +} From 9ad88a5a0d7f8ee40c9556bd7d6054ab54a45d97 Mon Sep 17 00:00:00 2001 From: eugenpolytechnic Date: Sun, 31 Jan 2021 17:37:11 +0300 Subject: [PATCH 007/260] FIR: introduce parameter type is Throwable check --- .../testData/resolve/catchParameter.fir.txt | 25 ++++++++++++++-- .../testData/resolve/catchParameter.kt | 16 ++++++++-- .../fir/analysis/checkers/FirHelpers.kt | 9 +++--- .../expression/FirCatchParameterChecker.kt | 29 +++++++++++++++---- .../deadCode/deadCodeDifferentExamples.fir.kt | 4 +-- 5 files changed, 67 insertions(+), 16 deletions(-) diff --git a/compiler/fir/analysis-tests/testData/resolve/catchParameter.fir.txt b/compiler/fir/analysis-tests/testData/resolve/catchParameter.fir.txt index 1e253b1f2dd..5041043b1c8 100644 --- a/compiler/fir/analysis-tests/testData/resolve/catchParameter.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolve/catchParameter.fir.txt @@ -1,5 +1,6 @@ FILE: catchParameter.kt - public final fun test(): R|kotlin/Unit| { + public final typealias StringType = R|kotlin/String| + public final fun test(): R|kotlin/Unit| { try { } catch (e: R|kotlin/NullPointerException| = R|java/lang/NullPointerException.NullPointerException|()) { @@ -10,6 +11,26 @@ FILE: catchParameter.kt catch (e: R|T|) { } + try { + } + catch (e: R|() -> kotlin/Int|) { + } + + try { + } + catch (e: R|StringType|) { + } + + try { + } + catch (e: R|kotlin/Int| = Int(5)) { + } + + try { + } + catch (e: R|kotlin/Throwable|) { + } + } public final inline fun anotherTest(): R|kotlin/Unit| { try { @@ -17,4 +38,4 @@ FILE: catchParameter.kt catch (e: R|T|) { } - } \ No newline at end of file + } diff --git a/compiler/fir/analysis-tests/testData/resolve/catchParameter.kt b/compiler/fir/analysis-tests/testData/resolve/catchParameter.kt index 0a0f2b86410..e1a5d34d99e 100644 --- a/compiler/fir/analysis-tests/testData/resolve/catchParameter.kt +++ b/compiler/fir/analysis-tests/testData/resolve/catchParameter.kt @@ -1,4 +1,6 @@ -fun test() { +typealias StringType = String + +fun test() { try { } catch (e: NullPointerException = NullPointerException()) { @@ -6,8 +8,16 @@ fun test() { } try {} catch (e: T) {} + + try {} catch (e: () -> Int) {} + + try {} catch (e: StringType) {} + + try {} catch (e: Int = 5) {} + + try {} catch (e: Throwable) {} } inline fun anotherTest() { - try {} catch (e: T) {} -} \ No newline at end of file + try {} catch (e: T) {} +} diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt index 2b5a7f6f0d4..d6920b5813a 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirHelpers.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSymbolOwner +import org.jetbrains.kotlin.fir.analysis.cfa.FirReturnsImpliesAnalyzer.isSupertypeOf import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.diagnostics.modalityModifier import org.jetbrains.kotlin.fir.analysis.diagnostics.overrideModifier @@ -22,18 +23,18 @@ import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression import org.jetbrains.kotlin.fir.expressions.impl.FirEmptyExpressionBlock import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference import org.jetbrains.kotlin.fir.resolve.firSymbolProvider +import org.jetbrains.kotlin.fir.resolve.fullyExpandedType import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.resolve.transformers.firClassLike import org.jetbrains.kotlin.fir.scopes.ProcessorAction import org.jetbrains.kotlin.fir.scopes.processOverriddenFunctions import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope +import org.jetbrains.kotlin.fir.symbols.StandardClassIds import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol -import org.jetbrains.kotlin.fir.types.ConeClassLikeType -import org.jetbrains.kotlin.fir.types.ConeKotlinType -import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef -import org.jetbrains.kotlin.fir.types.FirTypeRef +import org.jetbrains.kotlin.fir.typeCheckerContext +import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.lexer.KtModifierKeywordToken import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.KtModifierList diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirCatchParameterChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirCatchParameterChecker.kt index 4205522572c..5a58000782c 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirCatchParameterChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirCatchParameterChecker.kt @@ -5,31 +5,50 @@ package org.jetbrains.kotlin.fir.analysis.checkers.expression +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.analysis.cfa.FirReturnsImpliesAnalyzer.isSupertypeOf import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.expressions.FirTryExpression +import org.jetbrains.kotlin.fir.resolve.fullyExpandedType +import org.jetbrains.kotlin.fir.symbols.StandardClassIds +import org.jetbrains.kotlin.fir.typeCheckerContext +import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.fir.types.ConeTypeParameterType import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef +import org.jetbrains.kotlin.fir.types.constructClassLikeType object FirCatchParameterChecker : FirTryExpressionChecker() { + private val throwable = StandardClassIds.byName("Throwable") + .constructClassLikeType(emptyArray(), false) + override fun check(expression: FirTryExpression, context: CheckerContext, reporter: DiagnosticReporter) { for (catchEntry in expression.catches) { val catchParameter = catchEntry.parameter if (catchParameter.defaultValue != null) - reporter.report(catchParameter.source?.let { FirErrors.CATCH_PARAMETER_WITH_DEFAULT_VALUE.on(it) }) + catchParameter.source?.let { reporter.report(FirErrors.CATCH_PARAMETER_WITH_DEFAULT_VALUE.on(it)) } val typeRef = catchParameter.returnTypeRef - if (typeRef is FirResolvedTypeRef && typeRef.type is ConeTypeParameterType) { - val isReified = (typeRef.type as ConeTypeParameterType).lookupTag.typeParameterSymbol.fir.isReified + if (typeRef !is FirResolvedTypeRef) return + + val coneType = typeRef.type + if (coneType is ConeTypeParameterType) { + val isReified = coneType.lookupTag.typeParameterSymbol.fir.isReified if (isReified) { - reporter.report(catchParameter.source?.let { FirErrors.REIFIED_TYPE_IN_CATCH_CLAUSE.on(it) }) + catchParameter.source?.let { reporter.report(FirErrors.REIFIED_TYPE_IN_CATCH_CLAUSE.on(it)) } } else { - reporter.report(catchParameter.source?.let { FirErrors.TYPE_PARAMETER_IN_CATCH_CLAUSE.on(it) }) + catchParameter.source?.let { reporter.report(FirErrors.TYPE_PARAMETER_IN_CATCH_CLAUSE.on(it)) } } } + + if (!coneType.isThrowable(context.session)) + catchParameter.source?.let { reporter.report(FirErrors.TYPE_MISMATCH.on(it, throwable, coneType)) } } } + + private fun ConeKotlinType.isThrowable(session: FirSession) = + throwable.isSupertypeOf(session.typeCheckerContext, this.fullyExpandedType(session)) } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeDifferentExamples.fir.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeDifferentExamples.fir.kt index 9da253daa3b..5d076cdc2e1 100644 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeDifferentExamples.fir.kt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/deadCode/deadCodeDifferentExamples.fir.kt @@ -109,7 +109,7 @@ fun t7() : Int { return 1 2 } - catch (e : Any) { + catch (e : Any) { 2 } return 1 // this is OK, like in Java @@ -120,7 +120,7 @@ fun t8() : Int { return 1 2 } - catch (e : Any) { + catch (e : Any) { return 1 2 } From 8f675fe757ff6d5aeff74f4aedfc3d0135795382 Mon Sep 17 00:00:00 2001 From: Pavel Kirpichenkov Date: Mon, 1 Feb 2021 12:48:49 +0300 Subject: [PATCH 008/260] Split combined test into two to avoid flaky behaviour Prevent simultaneous access to the library directory --- .../anonymousObjectTypeMetadata.kt | 13 ++ .../library/privateObjects.kt | 154 ++++++++++++++++++ .../output.txt | 10 ++ .../CompileKotlinAgainstCustomBinariesTest.kt | 2 + 4 files changed, 179 insertions(+) create mode 100644 compiler/testData/compileKotlinAgainstCustomBinaries/anonymousObjectTypeMetadataKlib/anonymousObjectTypeMetadata.kt create mode 100644 compiler/testData/compileKotlinAgainstCustomBinaries/anonymousObjectTypeMetadataKlib/library/privateObjects.kt create mode 100644 compiler/testData/compileKotlinAgainstCustomBinaries/anonymousObjectTypeMetadataKlib/output.txt diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/anonymousObjectTypeMetadataKlib/anonymousObjectTypeMetadata.kt b/compiler/testData/compileKotlinAgainstCustomBinaries/anonymousObjectTypeMetadataKlib/anonymousObjectTypeMetadata.kt new file mode 100644 index 00000000000..67f75708502 --- /dev/null +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/anonymousObjectTypeMetadataKlib/anonymousObjectTypeMetadata.kt @@ -0,0 +1,13 @@ +package test + +import lib.* + +val w = W() +val v1 = fn() +val v2 = O.o() +val v3 = w.w() + +// private +val e1 = o3 +val e2 = w.o7 +val e3 = O.o10 diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/anonymousObjectTypeMetadataKlib/library/privateObjects.kt b/compiler/testData/compileKotlinAgainstCustomBinaries/anonymousObjectTypeMetadataKlib/library/privateObjects.kt new file mode 100644 index 00000000000..55d262d7c5b --- /dev/null +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/anonymousObjectTypeMetadataKlib/library/privateObjects.kt @@ -0,0 +1,154 @@ +package lib + +interface I1 { + fun i1() {} +} + +interface I2 { + fun i2() {} +} + +interface I3 : I2, I1 + +open class C { + fun c() {} +} + +open class G { + fun g() {} +} + +private val o1 = object { fun foo() {} } +private val o2 = object : I1 {} +private val o3 = object : I1, I2 {} +private val o4 = object : I3 {} +private val o5 = object : C() {} +private val o6 = object : C(), I1, I2 {} +private val o7 = object : C(), I3 {} +private val o8 = object : G() {} +private val o9 = object : G(), I1, I2 {} +private val o10 = object : G(), I3 {} + +private val o11 = object { + inner class D { + fun df() {} + } + fun d(): D = D() +}.d() + +private val o12 = { + class L { + fun l() {} + } + L() +}() + +private val o13 = { + class L { + inner class L1 { + inner class L2 { + fun l2() {} + } + } + } + + L().L1().L2() +}() + +fun fn() { + o1.foo() + o2.i1() + o3.i1() + o3.i2() + o4.i1() + o4.i2() + o5.c() + o6.c() + o6.i1() + o6.i2() + o7.c() + o7.i1() + o7.i2() + o8.g() + o9.g() + o9.i1() + o9.i2() + o10.g() + o10.i1() + o10.i2() + o11.df() + o12.l() + o13.l2() +} + +class W { + private val o1 = object { fun foo() {} } + private val o2 = object : I1 {} + private val o3 = object : I1, I2 {} + private val o4 = object : I3 {} + private val o5 = object : C() {} + private val o6 = object : C(), I1, I2 {} + private val o7 = object : C(), I3 {} + private val o8 = object : G() {} + private val o9 = object : G(), I1, I2 {} + private val o10 = object : G(), I3 {} + + fun w() { + o1.foo() + o2.i1() + o3.i1() + o3.i2() + o4.i1() + o4.i2() + o5.c() + o6.c() + o6.i1() + o6.i2() + o7.c() + o7.i1() + o7.i2() + o8.g() + o9.g() + o9.i1() + o9.i2() + o10.g() + o10.i1() + o10.i2() + } +} + +object O { + private val o1 = object { fun foo() {} } + private val o2 = object : I1 {} + private val o3 = object : I1, I2 {} + private val o4 = object : I3 {} + private val o5 = object : C() {} + private val o6 = object : C(), I1, I2 {} + private val o7 = object : C(), I3 {} + private val o8 = object : G() {} + private val o9 = object : G(), I1, I2 {} + private val o10 = object : G(), I3 {} + + fun o() { + o1.foo() + o2.i1() + o3.i1() + o3.i2() + o4.i1() + o4.i2() + o5.c() + o6.c() + o6.i1() + o6.i2() + o7.c() + o7.i1() + o7.i2() + o8.g() + o9.g() + o9.i1() + o9.i2() + o10.g() + o10.i1() + o10.i2() + } +} diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/anonymousObjectTypeMetadataKlib/output.txt b/compiler/testData/compileKotlinAgainstCustomBinaries/anonymousObjectTypeMetadataKlib/output.txt new file mode 100644 index 00000000000..716e70f42b9 --- /dev/null +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/anonymousObjectTypeMetadataKlib/output.txt @@ -0,0 +1,10 @@ +compiler/testData/compileKotlinAgainstCustomBinaries/anonymousObjectTypeMetadataKlib/anonymousObjectTypeMetadata.kt:11:10: error: cannot access 'o3': it is private in file +val e1 = o3 + ^ +compiler/testData/compileKotlinAgainstCustomBinaries/anonymousObjectTypeMetadataKlib/anonymousObjectTypeMetadata.kt:12:12: error: cannot access 'o7': it is private in 'W' +val e2 = w.o7 + ^ +compiler/testData/compileKotlinAgainstCustomBinaries/anonymousObjectTypeMetadataKlib/anonymousObjectTypeMetadata.kt:13:12: error: cannot access 'o10': it is private in 'O' +val e3 = O.o10 + ^ +COMPILATION_ERROR diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt index 0aa78345f81..0f3e6d047ec 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt @@ -714,7 +714,9 @@ class CompileKotlinAgainstCustomBinariesTest : AbstractKotlinCompilerIntegration listOf(library), K2MetadataCompiler(), ) + } + fun testAnonymousObjectTypeMetadataKlib() { val klibLibrary = compileCommonLibrary( libraryName = "library", listOf("-Xexpect-actual-linker"), From 558338f997056e58d707506b3f2341c5af9094c2 Mon Sep 17 00:00:00 2001 From: Vladimir Dolzhenko Date: Thu, 10 Dec 2020 21:34:07 +0100 Subject: [PATCH 009/260] Lazy diagnostics API in frontend Relates to #KT-37702 --- .../kotlin/analyzer/AnalysisResult.kt | 6 +- .../kotlin/diagnostics/DiagnosticSink.java | 9 ++ .../diagnostics/rendering/RenderingContext.kt | 20 ++-- .../kotlin/resolve/AbstractFilteringTrace.kt | 2 + .../kotlin/resolve/DelegatingBindingTrace.kt | 13 +++ .../kotlin/resolve/diagnostics/Diagnostics.kt | 6 +- .../DiagnosticsWithSuppression.java | 11 ++ .../diagnostics/KotlinSuppressCache.kt | 13 ++- .../MutableDiagnosticsWithSuppression.kt | 26 +++++ .../LockBasedLazyResolveStorageManager.kt | 1 - .../idea/caches/resolve/resolutionApi.kt | 6 +- .../kotlin/idea/resolve/ResolutionFacade.kt | 4 +- .../resolve/ModuleResolutionFacadeImpl.kt | 8 +- .../caches/resolve/PerFileAnalysisCache.kt | 100 ++++++++++++------ .../caches/resolve/ProjectResolutionFacade.kt | 10 +- .../resolve/ResolutionFacadeWithDebugInfo.kt | 8 +- .../impl/KotlinResolutionFacadeForRepl.kt | 6 +- 17 files changed, 186 insertions(+), 63 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalysisResult.kt b/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalysisResult.kt index 73717ca991f..e8c7a5001f4 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalysisResult.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/analyzer/AnalysisResult.kt @@ -52,9 +52,9 @@ open class AnalysisResult protected constructor( fun isError(): Boolean = this is InternalError || this is CompilationError fun throwIfError() { - when { - this is InternalError -> throw IllegalStateException("failed to analyze: " + error, error) - this is CompilationError -> throw CompilationErrorException() + when (this) { + is InternalError -> throw IllegalStateException("failed to analyze: $error", error) + is CompilationError -> throw CompilationErrorException() } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/DiagnosticSink.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/DiagnosticSink.java index 37d6a6fbb14..30043b68da1 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/DiagnosticSink.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/DiagnosticSink.java @@ -53,6 +53,15 @@ public interface DiagnosticSink { } }; + interface DiagnosticsCallback { + void callback(Diagnostic diagnostic); + } + void report(@NotNull Diagnostic diagnostic); + + default void setCallback(@NotNull DiagnosticsCallback callback) { } + + default void resetCallback() { } + boolean wantsDiagnostics(); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/RenderingContext.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/RenderingContext.kt index ff7304fa24d..aa726637803 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/RenderingContext.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/RenderingContext.kt @@ -48,16 +48,16 @@ sealed class RenderingContext { } @JvmStatic - fun fromDiagnostic(d: Diagnostic): RenderingContext { - val parameters = when (d) { - is SimpleDiagnostic<*> -> listOf() - is DiagnosticWithParameters1<*, *> -> listOf(d.a) - is DiagnosticWithParameters2<*, *, *> -> listOf(d.a, d.b) - is DiagnosticWithParameters3<*, *, *, *> -> listOf(d.a, d.b, d.c) - is ParametrizedDiagnostic<*> -> error("Unexpected diagnostic: ${d::class.java}") - else -> listOf() - } - return Impl(parameters) + fun parameters(d: Diagnostic): List = when (d) { + is SimpleDiagnostic<*> -> listOf() + is DiagnosticWithParameters1<*, *> -> listOf(d.a) + is DiagnosticWithParameters2<*, *, *> -> listOf(d.a, d.b) + is DiagnosticWithParameters3<*, *, *, *> -> listOf(d.a, d.b, d.c) + is ParametrizedDiagnostic<*> -> error("Unexpected diagnostic: ${d::class.java}") + else -> listOf() } + + @JvmStatic + fun fromDiagnostic(d: Diagnostic): RenderingContext = Impl(parameters(d)) } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AbstractFilteringTrace.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AbstractFilteringTrace.kt index 3ef6e842a1f..e98c6e2c2fd 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AbstractFilteringTrace.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AbstractFilteringTrace.kt @@ -37,6 +37,8 @@ abstract class AbstractFilteringTrace( } override fun report(diagnostic: Diagnostic) { + diagnosticsCallback?.callback(diagnostic) + parentTrace.report(diagnostic) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatingBindingTrace.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatingBindingTrace.kt index 59c1c93dc27..b54b1cba8e3 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatingBindingTrace.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatingBindingTrace.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve import com.google.common.collect.ImmutableMap import org.jetbrains.annotations.TestOnly import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.diagnostics.DiagnosticSink import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.resolve.diagnostics.BindingContextSuppressCache import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics @@ -156,6 +157,18 @@ open class DelegatingBindingTrace( mutableDiagnostics.report(diagnostic) } + protected var diagnosticsCallback: DiagnosticSink.DiagnosticsCallback? = null + + override fun setCallback(callback: DiagnosticSink.DiagnosticsCallback) { + diagnosticsCallback = callback + mutableDiagnostics?.setCallback(callback) + } + + override fun resetCallback() { + diagnosticsCallback = null + mutableDiagnostics?.resetCallback() + } + override fun wantsDiagnostics(): Boolean = mutableDiagnostics != null override fun toString(): String = name diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/Diagnostics.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/Diagnostics.kt index 80e4c0f0c03..04231909f5a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/Diagnostics.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/Diagnostics.kt @@ -16,9 +16,10 @@ package org.jetbrains.kotlin.resolve.diagnostics -import com.intellij.psi.PsiElement import com.intellij.openapi.util.ModificationTracker +import com.intellij.psi.PsiElement import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.diagnostics.DiagnosticSink.DiagnosticsCallback import org.jetbrains.kotlin.diagnostics.GenericDiagnostics interface Diagnostics : GenericDiagnostics { @@ -37,6 +38,9 @@ interface Diagnostics : GenericDiagnostics { fun noSuppression(): Diagnostics + fun setCallback(callback: DiagnosticsCallback) {} + fun resetCallback() {} + companion object { val EMPTY: Diagnostics = object : Diagnostics { override fun noSuppression(): Diagnostics = this diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/DiagnosticsWithSuppression.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/DiagnosticsWithSuppression.java index 4463565bd84..f759209c551 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/DiagnosticsWithSuppression.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/DiagnosticsWithSuppression.java @@ -23,6 +23,7 @@ import kotlin.collections.CollectionsKt; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.TestOnly; import org.jetbrains.kotlin.diagnostics.Diagnostic; +import org.jetbrains.kotlin.diagnostics.DiagnosticSink; import java.util.Collection; import java.util.Iterator; @@ -73,6 +74,16 @@ public class DiagnosticsWithSuppression implements Diagnostics { throw new IllegalStateException("Trying to obtain modification tracker for readonly DiagnosticsWithSuppression."); } + @Override + public void setCallback(@NotNull DiagnosticSink.DiagnosticsCallback callback) { + + } + + @Override + public void resetCallback() { + + } + @TestOnly @NotNull public Collection getDiagnostics() { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/KotlinSuppressCache.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/KotlinSuppressCache.kt index d870fc079c3..259de46c32a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/KotlinSuppressCache.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/KotlinSuppressCache.kt @@ -24,10 +24,7 @@ import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.Severity -import org.jetbrains.kotlin.psi.KtAnnotated -import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.psi.KtStubbedPsiUtil -import org.jetbrains.kotlin.psi.doNotAnalyze +import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.constants.ArrayValue import org.jetbrains.kotlin.resolve.constants.StringValue @@ -111,7 +108,12 @@ abstract class KotlinSuppressCache { This way we need no more lookups than the number of suppress() annotations from here to the root. */ - private fun isSuppressedByAnnotated(suppressionKey: String, severity: Severity, annotated: KtAnnotated, debugDepth: Int): Boolean { + private fun isSuppressedByAnnotated( + suppressionKey: String, + severity: Severity, + annotated: KtAnnotated, + debugDepth: Int + ): Boolean { val suppressor = getOrCreateSuppressor(annotated) if (suppressor.isSuppressed(suppressionKey, severity)) return true @@ -140,6 +142,7 @@ abstract class KotlinSuppressCache { private fun getSuppressingStrings(annotated: KtAnnotated): Set { val builder = ImmutableSet.builder() + for (annotationDescriptor in getSuppressionAnnotations(annotated)) { processAnnotation(builder, annotationDescriptor) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/MutableDiagnosticsWithSuppression.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/MutableDiagnosticsWithSuppression.kt index 7157dfdec02..ddbf703cce7 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/MutableDiagnosticsWithSuppression.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/MutableDiagnosticsWithSuppression.kt @@ -22,12 +22,16 @@ import com.intellij.psi.util.CachedValueProvider import com.intellij.util.CachedValueImpl import org.jetbrains.annotations.TestOnly import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.diagnostics.DiagnosticSink +import org.jetbrains.kotlin.psi.KtAnnotationEntry +import org.jetbrains.kotlin.psi.KtStubbedPsiUtil class MutableDiagnosticsWithSuppression( private val suppressCache: KotlinSuppressCache, private val delegateDiagnostics: Diagnostics, ) : Diagnostics { private val diagnosticList = ArrayList() + private var diagnosticsCallback: DiagnosticSink.DiagnosticsCallback? = null //NOTE: CachedValuesManager is not used because it requires Project passed to this object private val cache = CachedValueImpl { @@ -43,16 +47,38 @@ class MutableDiagnosticsWithSuppression( override fun forElement(psiElement: PsiElement) = readonlyView().forElement(psiElement) override fun noSuppression() = readonlyView().noSuppression() + override fun setCallback(callback: DiagnosticSink.DiagnosticsCallback) { + assert(diagnosticsCallback == null) { "diagnostic callback has been already registered" } + diagnosticsCallback = callback + delegateDiagnostics.setCallback(callback) + } + + override fun resetCallback() { + diagnosticsCallback = null + delegateDiagnostics.resetCallback() + } + //essential that this list is readonly fun getOwnDiagnostics(): List { return diagnosticList } fun report(diagnostic: Diagnostic) { + onFlyDiagnosticsCallback(diagnostic)?.callback(diagnostic) + diagnosticList.add(diagnostic) modificationTracker.incModificationCount() } + private fun onFlyDiagnosticsCallback(diagnostic: Diagnostic): DiagnosticSink.DiagnosticsCallback? = + diagnosticsCallback.takeIf { + diagnosticsCallback != null && + // Due to a potential recursion in filter.invoke (via LazyAnnotations) do not try to report + // diagnostic on fly if it happened in annotations + KtStubbedPsiUtil.getPsiOrStubParent(diagnostic.psiElement, KtAnnotationEntry::class.java, false) == null && + suppressCache.filter.invoke(diagnostic) + } + fun clear() { diagnosticList.clear() modificationTracker.incModificationCount() diff --git a/compiler/frontend/src/org/jetbrains/kotlin/storage/LockBasedLazyResolveStorageManager.kt b/compiler/frontend/src/org/jetbrains/kotlin/storage/LockBasedLazyResolveStorageManager.kt index cf1aa29901e..e9db0d08abf 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/storage/LockBasedLazyResolveStorageManager.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/storage/LockBasedLazyResolveStorageManager.kt @@ -22,7 +22,6 @@ import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice import org.jetbrains.kotlin.util.slicedMap.WritableSlice -import org.jetbrains.kotlin.resolve.TraceEntryFilter import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics import com.intellij.util.containers.ContainerUtil import org.jetbrains.kotlin.psi.KtExpression diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/caches/resolve/resolutionApi.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/caches/resolve/resolutionApi.kt index 5c4e2c629a3..443eacba99e 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/caches/resolve/resolutionApi.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/caches/resolve/resolutionApi.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.idea.FrontendInternals +import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.* @@ -167,8 +168,11 @@ inline fun T.analyzeWithContent(): BindingContext where T : KtDeclar * @ref [org.jetbrains.kotlin.idea.caches.resolve.PerFileAnalysisCache] */ fun KtFile.analyzeWithAllCompilerChecks(vararg extraFiles: KtFile): AnalysisResult = + this.analyzeWithAllCompilerChecks(null, *extraFiles) + +fun KtFile.analyzeWithAllCompilerChecks(callback: ((Diagnostic) -> Unit)?, vararg extraFiles: KtFile): AnalysisResult = KotlinCacheService.getInstance(project).getResolutionFacade(listOf(this) + extraFiles.toList()) - .analyzeWithAllCompilerChecks(listOf(this)) + .analyzeWithAllCompilerChecks(listOf(this), callback) /** * This function is expected to produce the same result as compiler for the given element and its children (including diagnostics, diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/resolve/ResolutionFacade.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/resolve/ResolutionFacade.kt index 91b8fb6c346..6124878609c 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/resolve/ResolutionFacade.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/resolve/ResolutionFacade.kt @@ -12,6 +12,8 @@ import org.jetbrains.kotlin.analyzer.ModuleInfo import org.jetbrains.kotlin.analyzer.ResolverForProject import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.diagnostics.DiagnosticSink import org.jetbrains.kotlin.idea.FrontendInternals import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtElement @@ -24,7 +26,7 @@ interface ResolutionFacade { fun analyze(element: KtElement, bodyResolveMode: BodyResolveMode = BodyResolveMode.FULL): BindingContext fun analyze(elements: Collection, bodyResolveMode: BodyResolveMode): BindingContext - fun analyzeWithAllCompilerChecks(elements: Collection): AnalysisResult + fun analyzeWithAllCompilerChecks(elements: Collection, callback: DiagnosticSink.DiagnosticsCallback? = null): AnalysisResult fun resolveToDescriptor(declaration: KtDeclaration, bodyResolveMode: BodyResolveMode = BodyResolveMode.FULL): DeclarationDescriptor diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ModuleResolutionFacadeImpl.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ModuleResolutionFacadeImpl.kt index ec92de74a0e..39e05c2e189 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ModuleResolutionFacadeImpl.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ModuleResolutionFacadeImpl.kt @@ -26,6 +26,7 @@ import org.jetbrains.kotlin.container.tryGetService import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.idea.FrontendInternals +import org.jetbrains.kotlin.diagnostics.DiagnosticSink import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo import org.jetbrains.kotlin.idea.project.ResolveElementCache import org.jetbrains.kotlin.idea.resolve.ResolutionFacade @@ -75,11 +76,14 @@ internal class ModuleResolutionFacadeImpl( } } - override fun analyzeWithAllCompilerChecks(elements: Collection): AnalysisResult { + override fun analyzeWithAllCompilerChecks( + elements: Collection, + callback: DiagnosticSink.DiagnosticsCallback? + ): AnalysisResult { ResolveInDispatchThreadManager.assertNoResolveInDispatchThread() return runWithCancellationCheck { - projectFacade.getAnalysisResultsForElements(elements) + projectFacade.getAnalysisResultsForElements(elements, callback) } } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/PerFileAnalysisCache.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/PerFileAnalysisCache.kt index 91bf8671418..84c206f2acd 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/PerFileAnalysisCache.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/PerFileAnalysisCache.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.context.withModule import org.jetbrains.kotlin.context.withProject import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.diagnostics.DiagnosticSink import org.jetbrains.kotlin.diagnostics.DiagnosticUtils import org.jetbrains.kotlin.frontend.di.createContainerForLazyBodyResolve import org.jetbrains.kotlin.idea.caches.project.getModuleInfo @@ -89,32 +90,50 @@ internal class PerFileAnalysisCache(val file: KtFile, componentProvider: Compone return null } - internal fun getAnalysisResults(element: KtElement): AnalysisResult { + internal fun getAnalysisResults(element: KtElement, callback: DiagnosticSink.DiagnosticsCallback? = null): AnalysisResult { check(element) val analyzableParent = KotlinResolveDataProvider.findAnalyzableParent(element) ?: return AnalysisResult.EMPTY + fun handleResult(result: AnalysisResult, callback: DiagnosticSink.DiagnosticsCallback?): AnalysisResult { + callback?.let { result.bindingContext.diagnostics.forEach(it::callback) } + return result + } + return guardLock.guarded { // step 1: perform incremental analysis IF it is applicable - getIncrementalAnalysisResult()?.let { return@guarded it } + getIncrementalAnalysisResult(callback)?.let { + return@guarded handleResult(it, callback) + } // cache does not contain AnalysisResult per each kt/psi element // instead it looks up analysis for its parents - see lookUp(analyzableElement) // step 2: return result if it is cached lookUp(analyzableParent)?.let { - return@guarded it + return@guarded handleResult(it, callback) } + val localDiagnostics = mutableSetOf() + val localCallback = if (callback != null) { d: Diagnostic -> + localDiagnostics.add(d) + callback.callback(d) + } else null + // step 3: perform analyze of analyzableParent as nothing has been cached yet - val result = analyze(analyzableParent) + val result = analyze(analyzableParent, null, localCallback) + + // some of diagnostics could be not handled with a callback - send out the rest + callback?.let { c -> + result.bindingContext.diagnostics.filterNot { it in localDiagnostics }.forEach(c::callback) + } cache[analyzableParent] = result return@guarded result } } - private fun getIncrementalAnalysisResult(): AnalysisResult? { + private fun getIncrementalAnalysisResult(callback: DiagnosticSink.DiagnosticsCallback?): AnalysisResult? { updateFileResultFromCache() val inBlockModifications = file.inBlockModifications @@ -151,7 +170,9 @@ internal class PerFileAnalysisCache(val file: KtFile, componentProvider: Compone ) } - val newResult = analyze(inBlockModification, trace) + callback?.let { trace.parentDiagnosticsApartElement.forEach(it::callback) } + + val newResult = analyze(inBlockModification, trace, callback) analysisResult = wrapResult(result, newResult, trace) } file.clearInBlockModifications() @@ -224,7 +245,11 @@ internal class PerFileAnalysisCache(val file: KtFile, componentProvider: Compone } } - private fun analyze(analyzableElement: KtElement, bindingTrace: BindingTrace? = null): AnalysisResult { + private fun analyze( + analyzableElement: KtElement, + bindingTrace: BindingTrace?, + callback: DiagnosticSink.DiagnosticsCallback? + ): AnalysisResult { ProgressIndicatorProvider.checkCanceled() val project = analyzableElement.project @@ -242,7 +267,8 @@ internal class PerFileAnalysisCache(val file: KtFile, componentProvider: Compone codeFragmentAnalyzer, bodyResolveCache, analyzableElement, - bindingTrace + bindingTrace, + callback ) } catch (e: ProcessCanceledException) { throw e @@ -412,12 +438,14 @@ private object KotlinResolveDataProvider { codeFragmentAnalyzer: CodeFragmentAnalyzer, bodyResolveCache: BodyResolveCache, analyzableElement: KtElement, - bindingTrace: BindingTrace? + bindingTrace: BindingTrace?, + callback: DiagnosticSink.DiagnosticsCallback? ): AnalysisResult { try { if (analyzableElement is KtCodeFragment) { val bodyResolveMode = BodyResolveMode.PARTIAL_FOR_COMPLETION - val bindingContext = codeFragmentAnalyzer.analyzeCodeFragment(analyzableElement, bodyResolveMode).bindingContext + val trace: BindingTrace = codeFragmentAnalyzer.analyzeCodeFragment(analyzableElement, bodyResolveMode) + val bindingContext = trace.bindingContext return AnalysisResult.success(bindingContext, moduleDescriptor) } @@ -427,34 +455,40 @@ private object KotlinResolveDataProvider { allowSliceRewrite = true ) - val moduleInfo = analyzableElement.containingFile.getModuleInfo() + val moduleInfo = analyzableElement.containingKtFile.getModuleInfo() val targetPlatform = moduleInfo.platform - /* - Note that currently we *have* to re-create LazyTopDownAnalyzer with custom trace in order to disallow resolution of - bodies in top-level trace (trace from DI-container). - Resolving bodies in top-level trace may lead to memory leaks and incorrect resolution, because top-level - trace isn't invalidated on in-block modifications (while body resolution surely does) + callback?.let { trace.setCallback(it) } - Also note that for function bodies, we'll create DelegatingBindingTrace in ResolveElementCache anyways - (see 'functionAdditionalResolve'). However, this trace is still needed, because we have other - codepaths for other KtDeclarationWithBodies (like property accessors/secondary constructors/class initializers) - */ - val lazyTopDownAnalyzer = createContainerForLazyBodyResolve( - //TODO: should get ModuleContext - globalContext.withProject(project).withModule(moduleDescriptor), - resolveSession, - trace, - targetPlatform, - bodyResolveCache, - targetPlatform.findAnalyzerServices(project), - analyzableElement.languageVersionSettings, - IdeaModuleStructureOracle(), - IdeMainFunctionDetectorFactory() - ).get() + try { + /* + Note that currently we *have* to re-create LazyTopDownAnalyzer with custom trace in order to disallow resolution of + bodies in top-level trace (trace from DI-container). + Resolving bodies in top-level trace may lead to memory leaks and incorrect resolution, because top-level + trace isn't invalidated on in-block modifications (while body resolution surely does) - lazyTopDownAnalyzer.analyzeDeclarations(TopDownAnalysisMode.TopLevelDeclarations, listOf(analyzableElement)) + Also note that for function bodies, we'll create DelegatingBindingTrace in ResolveElementCache anyways + (see 'functionAdditionalResolve'). However, this trace is still needed, because we have other + codepaths for other KtDeclarationWithBodies (like property accessors/secondary constructors/class initializers) + */ + val lazyTopDownAnalyzer = createContainerForLazyBodyResolve( + //TODO: should get ModuleContext + globalContext.withProject(project).withModule(moduleDescriptor), + resolveSession, + trace, + targetPlatform, + bodyResolveCache, + targetPlatform.findAnalyzerServices(project), + analyzableElement.languageVersionSettings, + IdeaModuleStructureOracle(), + IdeMainFunctionDetectorFactory() + ).get() + + lazyTopDownAnalyzer.analyzeDeclarations(TopDownAnalysisMode.TopLevelDeclarations, listOf(analyzableElement)) + } finally { + trace.resetCallback() + } return AnalysisResult.success(trace.bindingContext, moduleDescriptor) } catch (e: ProcessCanceledException) { diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ProjectResolutionFacade.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ProjectResolutionFacade.kt index 14c2100ab61..416bd50016b 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ProjectResolutionFacade.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ProjectResolutionFacade.kt @@ -17,6 +17,7 @@ import org.jetbrains.kotlin.analyzer.* import org.jetbrains.kotlin.context.GlobalContextImpl import org.jetbrains.kotlin.context.withProject import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.diagnostics.DiagnosticSink import org.jetbrains.kotlin.idea.caches.project.* import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo import org.jetbrains.kotlin.idea.caches.trackers.KotlinCodeBlockModificationListener @@ -143,10 +144,13 @@ internal class ProjectResolutionFacade( internal fun findModuleDescriptor(ideaModuleInfo: IdeaModuleInfo): ModuleDescriptor { return cachedResolverForProject.descriptorForModule(ideaModuleInfo) } - + internal fun getResolverForProject(): ResolverForProject = cachedResolverForProject - internal fun getAnalysisResultsForElements(elements: Collection): AnalysisResult { + internal fun getAnalysisResultsForElements( + elements: Collection, + callback: DiagnosticSink.DiagnosticsCallback? = null + ): AnalysisResult { assert(elements.isNotEmpty()) { "elements collection should not be empty" } val cache = analysisResultsSimpleLock.guarded { @@ -157,7 +161,7 @@ internal class ProjectResolutionFacade( val containingKtFile = it.containingKtFile val perFileCache = cache[containingKtFile] try { - perFileCache.getAnalysisResults(it) + perFileCache.getAnalysisResults(it, callback) } catch (e: Throwable) { if (e is ControlFlowException) { throw e diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ResolutionFacadeWithDebugInfo.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ResolutionFacadeWithDebugInfo.kt index 685dd37ef16..3ba69c97048 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ResolutionFacadeWithDebugInfo.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ResolutionFacadeWithDebugInfo.kt @@ -18,6 +18,7 @@ import org.jetbrains.kotlin.analyzer.ResolverForProject import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.idea.FrontendInternals +import org.jetbrains.kotlin.diagnostics.DiagnosticSink import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo import org.jetbrains.kotlin.idea.caches.project.getNullableModuleInfo import org.jetbrains.kotlin.idea.resolve.ResolutionFacade @@ -52,9 +53,12 @@ private class ResolutionFacadeWithDebugInfo( } } - override fun analyzeWithAllCompilerChecks(elements: Collection): AnalysisResult { + override fun analyzeWithAllCompilerChecks( + elements: Collection, + callback: DiagnosticSink.DiagnosticsCallback? + ): AnalysisResult { return wrapExceptions({ ResolvingWhat(elements) }) { - delegate.analyzeWithAllCompilerChecks(elements) + delegate.analyzeWithAllCompilerChecks(elements, callback) } } diff --git a/plugins/scripting/scripting-ide-services/src/org/jetbrains/kotlin/scripting/ide_services/compiler/impl/KotlinResolutionFacadeForRepl.kt b/plugins/scripting/scripting-ide-services/src/org/jetbrains/kotlin/scripting/ide_services/compiler/impl/KotlinResolutionFacadeForRepl.kt index 218befbfda1..a4865652e55 100644 --- a/plugins/scripting/scripting-ide-services/src/org/jetbrains/kotlin/scripting/ide_services/compiler/impl/KotlinResolutionFacadeForRepl.kt +++ b/plugins/scripting/scripting-ide-services/src/org/jetbrains/kotlin/scripting/ide_services/compiler/impl/KotlinResolutionFacadeForRepl.kt @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.container.ComponentProvider import org.jetbrains.kotlin.container.getService import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.diagnostics.DiagnosticSink import org.jetbrains.kotlin.idea.FrontendInternals import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.psi.KtDeclaration @@ -72,7 +73,10 @@ class KotlinResolutionFacadeForRepl( throw UnsupportedOperationException() } - override fun analyzeWithAllCompilerChecks(elements: Collection): AnalysisResult { + override fun analyzeWithAllCompilerChecks( + elements: Collection, + callback: DiagnosticSink.DiagnosticsCallback? + ): AnalysisResult { throw UnsupportedOperationException() } From 913c298be858b63e472cfd6c58af11702b3a101d Mon Sep 17 00:00:00 2001 From: Vladimir Dolzhenko Date: Thu, 19 Nov 2020 13:38:38 +0100 Subject: [PATCH 010/260] Kotlin highlight passes are reworked #KT-37702 Fixed --- .../kotlin/generators/tests/GenerateTests.kt | 4 +- .../generators/tests/GenerateTests.kt.as41 | 2 +- .../generators/tests/GenerateTests.kt.as42 | 2 +- .../KotlinIdeaAnalysisBundle.properties | 2 + ...BindingContextAwareHighlightingPassBase.kt | 47 +++ .../AbstractKotlinHighlightingPass.kt | 293 +++++++++++++++++ .../highlighter/AnnotationPresentationInfo.kt | 85 +++-- .../highlighter/CalculatingIntentionAction.kt | 30 ++ .../highlighter/DebugInfoHighlightingPass.kt | 100 ++++++ .../DuplicateJvmSignatureAnnotator.kt | 50 --- .../DuplicateJvmSignatureHighlightPass.kt | 74 +++++ .../idea/highlighter/ElementAnnotator.kt | 214 +++++++++++++ .../highlighter/KotlinHighlightingUtil.kt | 11 +- .../idea/highlighter/KotlinPsiChecker.kt | 295 ------------------ .../VariablesHighlightingVisitor.kt | 23 +- .../FromUnresolvedNamesCompletion.kt | 5 +- ...ExpressionsSmartcastHighlightingVisitor.kt | 11 +- .../FirAfterResolveHighlightingVisitor.kt | 8 + .../VariableReferenceHighlightingVisitor.kt | 4 +- ... AbstractFirKotlinHighlightingPassTest.kt} | 2 +- ...rKotlinHighlightingPassTestGenerated.java} | 19 +- .../AbstractHighlightingPassBase.kt | 84 +++++ .../BeforeResolveHighlightingVisitor.kt | 14 +- .../idea/highlighter/HighlightingVisitor.kt | 28 +- .../KotlinBeforeResolveHighlightingPass.kt | 42 +-- .../kotlin/idea/util/ApplicationUtils.kt | 2 + .../idea/perf/PerformanceProjectsTest.kt | 77 ++++- .../resources-descriptors/META-INF/plugin.xml | 3 + .../META-INF/plugin.xml.201 | 3 + .../META-INF/plugin.xml.as41 | 3 + .../META-INF/plugin.xml.as42 | 3 + idea/resources/META-INF/plugin-common.xml | 5 - .../highlighter/KotlinHighlightingPass.kt | 45 +++ .../KotlinPsiCheckerAndHighlightingUpdater.kt | 30 -- .../inspections/KotlinCleanupInspection.kt | 4 +- idea/testData/checker/AnnotationSupressing.kt | 32 ++ ...> AbstractKotlinHighlightingPassTest.java} | 2 +- ...kt => KotlinHighlightingPassCustomTest.kt} | 2 +- ...kt => KotlinHighlightingPassSealedTest.kt} | 2 +- ... KotlinHighlightingPassTestGenerated.java} | 29 +- .../AbstractCodeFragmentAutoImportTest.kt | 4 +- .../AbstractCodeFragmentHighlightingTest.kt | 4 +- .../highlighter/AbstractDslHighlighterTest.kt | 8 +- .../AbstractLocalInspectionTest.kt | 27 +- .../ide/test/AbstractParcelizeCheckerTest.kt | 6 +- tests/mute-common.csv | 2 +- 46 files changed, 1206 insertions(+), 536 deletions(-) create mode 100644 idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AbstractBindingContextAwareHighlightingPassBase.kt create mode 100644 idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AbstractKotlinHighlightingPass.kt create mode 100644 idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/CalculatingIntentionAction.kt create mode 100644 idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/DebugInfoHighlightingPass.kt delete mode 100644 idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/DuplicateJvmSignatureAnnotator.kt create mode 100644 idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/DuplicateJvmSignatureHighlightPass.kt create mode 100644 idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/ElementAnnotator.kt delete mode 100644 idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinPsiChecker.kt rename idea/idea-fir/tests/org/jetbrains/kotlin/checkers/{AbstractFirPsiCheckerTest.kt => AbstractFirKotlinHighlightingPassTest.kt} (95%) rename idea/idea-fir/tests/org/jetbrains/kotlin/checkers/{FirPsiCheckerTestGenerated.java => FirKotlinHighlightingPassTestGenerated.java} (97%) create mode 100644 idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/AbstractHighlightingPassBase.kt create mode 100644 idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightingPass.kt delete mode 100644 idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinPsiCheckerAndHighlightingUpdater.kt create mode 100644 idea/testData/checker/AnnotationSupressing.kt rename idea/tests/org/jetbrains/kotlin/checkers/{AbstractPsiCheckerTest.java => AbstractKotlinHighlightingPassTest.java} (97%) rename idea/tests/org/jetbrains/kotlin/checkers/{PsiCheckerCustomTest.kt => KotlinHighlightingPassCustomTest.kt} (94%) rename idea/tests/org/jetbrains/kotlin/checkers/{PsiCheckerSealedTest.kt => KotlinHighlightingPassSealedTest.kt} (92%) rename idea/tests/org/jetbrains/kotlin/checkers/{PsiCheckerTestGenerated.java => KotlinHighlightingPassTestGenerated.java} (97%) diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index a2e92eb3b75..2cfbf41962c 100644 --- a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -312,7 +312,7 @@ fun main(args: Array) { model("resolve/resolveModeComparison") } - testClass { + testClass { model("checker", recursive = false) model("checker/regression") model("checker/recovery") @@ -1092,7 +1092,7 @@ fun main(args: Array) { model("resolve/references", pattern = KT_WITHOUT_DOTS_IN_NAME) } - testClass { + testClass { model("checker", recursive = false) model("checker/regression") model("checker/recovery") diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as41 b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as41 index ddae3330f6c..51ef15e2838 100644 --- a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as41 +++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as41 @@ -239,7 +239,7 @@ fun main(args: Array) { model("resolve/partialBodyResolve") } - testClass { + testClass { model("checker", recursive = false) model("checker/regression") model("checker/recovery") diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as42 b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as42 index c74929eb79b..7e525475af3 100644 --- a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as42 +++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt.as42 @@ -235,7 +235,7 @@ fun main(args: Array) { model("resolve/partialBodyResolve") } - testClass { + testClass { model("checker", recursive = false) model("checker/regression") model("checker/recovery") diff --git a/idea/idea-analysis/resources/messages/KotlinIdeaAnalysisBundle.properties b/idea/idea-analysis/resources/messages/KotlinIdeaAnalysisBundle.properties index f2e8aaddbe2..455b56a9cfe 100644 --- a/idea/idea-analysis/resources/messages/KotlinIdeaAnalysisBundle.properties +++ b/idea/idea-analysis/resources/messages/KotlinIdeaAnalysisBundle.properties @@ -40,6 +40,8 @@ html.type.mismatch.table.tr.td.required.td.td.0.td.tr.tr.td.found.td.td.1.td.tr. intention.suppress.family=Suppress Warnings intention.suppress.text=Suppress ''{0}'' for {1} {2} +intention.calculating.text=Quick fix is being calculated ... + special.module.for.files.not.under.source.root= sdk.0= sources.for.library.0= diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AbstractBindingContextAwareHighlightingPassBase.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AbstractBindingContextAwareHighlightingPassBase.kt new file mode 100644 index 00000000000..919daceea10 --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AbstractBindingContextAwareHighlightingPassBase.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.highlighter + +import com.intellij.lang.annotation.AnnotationHolder +import com.intellij.lang.annotation.Annotator +import com.intellij.openapi.editor.Document +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiRecursiveElementVisitor +import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithAllCompilerChecks +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.resolve.BindingContext + +@Suppress("UnstableApiUsage") +abstract class AbstractBindingContextAwareHighlightingPassBase( + file: KtFile, + document: Document +) : AbstractHighlightingPassBase(file, document) { + + private val cachedAnnotator by lazy { annotator } + + protected abstract val annotator: Annotator + + private var bindingContext: BindingContext? = null + + protected fun bindingContext(): BindingContext = bindingContext ?: error("bindingContext has to be acquired") + + protected open fun buildBindingContext(holder: AnnotationHolder): BindingContext = + file.analyzeWithAllCompilerChecks().also { it.throwIfError() }.bindingContext + + override fun runAnnotatorWithContext(element: PsiElement, holder: AnnotationHolder) { + bindingContext = buildBindingContext(holder) + try { + element.accept(object : PsiRecursiveElementVisitor() { + override fun visitElement(element: PsiElement) { + cachedAnnotator.annotate(element, holder) + super.visitElement(element) + } + }) + } finally { + bindingContext = null + } + } +} \ No newline at end of file diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AbstractKotlinHighlightingPass.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AbstractKotlinHighlightingPass.kt new file mode 100644 index 00000000000..3e9ae6bd035 --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AbstractKotlinHighlightingPass.kt @@ -0,0 +1,293 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.highlighter + +import com.intellij.codeInsight.daemon.impl.Divider +import com.intellij.codeInsight.intention.IntentionAction +import com.intellij.lang.annotation.Annotation +import com.intellij.lang.annotation.AnnotationHolder +import com.intellij.lang.annotation.Annotator +import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.editor.Document +import com.intellij.openapi.util.Key +import com.intellij.openapi.util.TextRange +import com.intellij.psi.PsiElement +import com.intellij.util.CommonProcessors +import com.intellij.util.containers.MultiMap +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.diagnostics.DiagnosticFactory +import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.diagnostics.rendering.RenderingContext +import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithAllCompilerChecks +import org.jetbrains.kotlin.idea.quickfix.QuickFixes +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtNameReferenceExpression +import org.jetbrains.kotlin.psi.KtParameter +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.types.KotlinType +import java.lang.reflect.* +import java.util.* + +abstract class AbstractKotlinHighlightingPass(file: KtFile, document: Document) : + AbstractBindingContextAwareHighlightingPassBase(file, document) { + override val annotator: Annotator + get() = KotlinAfterAnalysisAnnotator() + + private inner class KotlinAfterAnalysisAnnotator : Annotator { + override fun annotate(element: PsiElement, holder: AnnotationHolder) { + val bindingContext = bindingContext() + getAfterAnalysisVisitor(holder, bindingContext).forEach { visitor -> element.accept(visitor) } + } + } + + override fun buildBindingContext(holder: AnnotationHolder): BindingContext { + val dividedElements: List = ArrayList() + Divider.divideInsideAndOutsideAllRoots( + file, file.textRange, file.textRange, { true }, + CommonProcessors.CollectProcessor(dividedElements) + ) + // TODO: for the sake of check that element belongs to the file + // for some reason analyzeWithAllCompilerChecks could return psiElements those do not belong to the file + // see [ScriptConfigurationHighlightingTestGenerated$Highlighting.testCustomExtension] + val elements = dividedElements.flatMap(Divider.DividedElements::inside).toSet() + + // annotate diagnostics on fly: show diagnostics as soon as front-end reports them + // don't create quick fixes as it could require some resolve + val annotationByDiagnostic = mutableMapOf() + val annotationByTextRange = mutableMapOf() + + // render of on-fly diagnostics with descriptors could lead to recursion + fun checkIfDescriptor(candidate: Any?): Boolean = + candidate is DeclarationDescriptor || candidate is Collection<*> && candidate.any(::checkIfDescriptor) + + val analysisResult = + file.analyzeWithAllCompilerChecks({ + val element = it.psiElement + if (element in elements && + it !in annotationByDiagnostic && + !RenderingContext.parameters(it).any(::checkIfDescriptor) + ) { + annotateDiagnostic(element, holder, it, annotationByDiagnostic, annotationByTextRange) + } + }).also { it.throwIfError() } + // resolve is done! + + val bindingContext = analysisResult.bindingContext + + cleanUpCalculatingAnnotations(annotationByTextRange) + // TODO: for some reasons it could be duplicated diagnostics for the same factory + // see [PsiCheckerTestGenerated$Checker.testRedeclaration] + val diagnostics = bindingContext.diagnostics.asSequence().filter { it.psiElement in elements }.toSet() + + if (diagnostics.isNotEmpty()) { + // annotate diagnostics those were not possible to render on fly + diagnostics.asSequence().filterNot { it in annotationByDiagnostic }.forEach { + annotateDiagnostic(it.psiElement, holder, it, annotationByDiagnostic, calculatingInProgress = false) + } + // apply quick fixes for all diagnostics grouping by element + diagnostics.groupBy(Diagnostic::psiElement).forEach { + annotateQuickFixes(it.key, it.value, annotationByDiagnostic) + } + } + return bindingContext + } + + private fun annotateDiagnostic( + element: PsiElement, + holder: AnnotationHolder, + diagnostic: Diagnostic, + annotationByDiagnostic: MutableMap? = null, + annotationByTextRange: MutableMap? = null, + calculatingInProgress: Boolean = true + ) = annotateDiagnostics(element, holder, listOf(diagnostic), annotationByDiagnostic, annotationByTextRange, true, calculatingInProgress) + + private fun cleanUpCalculatingAnnotations(annotationByTextRange: Map) { + annotationByTextRange.values.forEach { annotation -> + annotation.quickFixes?.removeIf { + it.quickFix is CalculatingIntentionAction + } + } + } + + private fun annotateDiagnostics( + element: PsiElement, + holder: AnnotationHolder, + diagnostics: List, + annotationByDiagnostic: MutableMap? = null, + annotationByTextRange: MutableMap? = null, + noFixes: Boolean = false, + calculatingInProgress: Boolean = false + ) = annotateDiagnostics( + file, element, holder, diagnostics, annotationByDiagnostic, annotationByTextRange, + ::shouldSuppressUnusedParameter, + noFixes = noFixes, calculatingInProgress = calculatingInProgress + ) + + /** + * [diagnostics] has to belong to the same element + */ + private fun annotateQuickFixes( + element: PsiElement, + diagnostics: List, + annotationByDiagnostic: MutableMap + ) { + if (diagnostics.isEmpty()) return + + assertBelongsToTheSameElement(element, diagnostics) + + val shouldHighlightErrors = + KotlinHighlightingUtil.shouldHighlightErrors( + if (element.isPhysical) file else element + ) + + if (shouldHighlightErrors) { + ElementAnnotator(element) { param -> + shouldSuppressUnusedParameter(param) + }.registerDiagnosticsQuickFixes(diagnostics, annotationByDiagnostic) + } + } + + protected open fun shouldSuppressUnusedParameter(parameter: KtParameter): Boolean = false + + companion object { + fun createQuickFixes(diagnostic: Diagnostic): Collection = + createQuickFixes(listOfNotNull(diagnostic))[diagnostic] + + private val UNRESOLVED_KEY = Key("KotlinHighlightingPass.UNRESOLVED_KEY") + + fun wasUnresolved(element: KtNameReferenceExpression) = element.getUserData(UNRESOLVED_KEY) != null + + fun getAfterAnalysisVisitor(holder: AnnotationHolder, bindingContext: BindingContext) = arrayOf( + PropertiesHighlightingVisitor(holder, bindingContext), + FunctionsHighlightingVisitor(holder, bindingContext), + VariablesHighlightingVisitor(holder, bindingContext), + TypeKindHighlightingVisitor(holder, bindingContext) + ) + + private fun assertBelongsToTheSameElement(element: PsiElement, diagnostics: Collection) { + assert(diagnostics.all { it.psiElement == element }) + } + + fun annotateDiagnostics( + file: KtFile, + element: PsiElement, + holder: AnnotationHolder, + diagnostics: Collection, + annotationByDiagnostic: MutableMap? = null, + annotationByTextRange: MutableMap? = null, + shouldSuppressUnusedParameter: (KtParameter) -> Boolean = { false }, + noFixes: Boolean = false, + calculatingInProgress: Boolean = false + ) { + if (diagnostics.isEmpty()) return + + assertBelongsToTheSameElement(element, diagnostics) + + if (element is KtNameReferenceExpression) { + val unresolved = diagnostics.any { it.factory == Errors.UNRESOLVED_REFERENCE } + element.putUserData(UNRESOLVED_KEY, if (unresolved) Unit else null) + } + + val shouldHighlightErrors = + KotlinHighlightingUtil.shouldHighlightErrors( + if (element.isPhysical) file else element + ) + + if (shouldHighlightErrors) { + val elementAnnotator = ElementAnnotator(element) { param -> + shouldSuppressUnusedParameter(param) + } + elementAnnotator.registerDiagnosticsAnnotations( + holder, diagnostics, annotationByDiagnostic, + annotationByTextRange, + noFixes = noFixes, calculatingInProgress = calculatingInProgress + ) + } + } + } +} + + +internal fun createQuickFixes(similarDiagnostics: Collection): MultiMap { + val first = similarDiagnostics.minByOrNull { it.toString() } + val factory = similarDiagnostics.first().getRealDiagnosticFactory() + + val actions = MultiMap() + + val intentionActionsFactories = QuickFixes.getInstance().getActionFactories(factory) + for (intentionActionsFactory in intentionActionsFactories) { + val allProblemsActions = intentionActionsFactory.createActionsForAllProblems(similarDiagnostics) + if (allProblemsActions.isNotEmpty()) { + actions.putValues(first, allProblemsActions) + } else { + for (diagnostic in similarDiagnostics) { + actions.putValues(diagnostic, intentionActionsFactory.createActions(diagnostic)) + } + } + } + + for (diagnostic in similarDiagnostics) { + actions.putValues(diagnostic, QuickFixes.getInstance().getActions(diagnostic.factory)) + } + + actions.values().forEach { NoDeclarationDescriptorsChecker.check(it::class.java) } + + return actions +} + +private fun Diagnostic.getRealDiagnosticFactory(): DiagnosticFactory<*> = + when (factory) { + Errors.PLUGIN_ERROR -> Errors.PLUGIN_ERROR.cast(this).a.factory + Errors.PLUGIN_WARNING -> Errors.PLUGIN_WARNING.cast(this).a.factory + Errors.PLUGIN_INFO -> Errors.PLUGIN_INFO.cast(this).a.factory + else -> factory + } + +private object NoDeclarationDescriptorsChecker { + private val LOG = Logger.getInstance(NoDeclarationDescriptorsChecker::class.java) + + private val checkedQuickFixClasses = Collections.synchronizedSet(HashSet>()) + + fun check(quickFixClass: Class<*>) { + if (!checkedQuickFixClasses.add(quickFixClass)) return + + for (field in quickFixClass.declaredFields) { + checkType(field.genericType, field) + } + + quickFixClass.superclass?.let { check(it) } + } + + private fun checkType(type: Type, field: Field) { + when (type) { + is Class<*> -> { + if (DeclarationDescriptor::class.java.isAssignableFrom(type) || KotlinType::class.java.isAssignableFrom(type)) { + LOG.error( + "QuickFix class ${field.declaringClass.name} contains field ${field.name} that holds ${type.simpleName}. " + + "This leads to holding too much memory through this quick-fix instance. " + + "Possible solution can be wrapping it using KotlinIntentionActionFactoryWithDelegate." + ) + } + + if (IntentionAction::class.java.isAssignableFrom(type)) { + check(type) + } + + } + + is GenericArrayType -> checkType(type.genericComponentType, field) + + is ParameterizedType -> { + if (Collection::class.java.isAssignableFrom(type.rawType as Class<*>)) { + type.actualTypeArguments.forEach { checkType(it, field) } + } + } + + is WildcardType -> type.upperBounds.forEach { checkType(it, field) } + } + } +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AnnotationPresentationInfo.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AnnotationPresentationInfo.kt index cd8bd2cb27a..0c15bd0e46e 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AnnotationPresentationInfo.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AnnotationPresentationInfo.kt @@ -8,10 +8,9 @@ package org.jetbrains.kotlin.idea.highlighter import com.intellij.codeInsight.intention.EmptyIntentionAction import com.intellij.codeInsight.intention.IntentionAction import com.intellij.codeInspection.ProblemHighlightType -import com.intellij.lang.annotation.AnnotationBuilder +import com.intellij.lang.annotation.Annotation import com.intellij.lang.annotation.AnnotationHolder import com.intellij.lang.annotation.HighlightSeverity -import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.editor.colors.TextAttributesKey import com.intellij.openapi.util.TextRange import com.intellij.util.containers.MultiMap @@ -20,6 +19,8 @@ import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.Severity import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages import org.jetbrains.kotlin.idea.inspections.KotlinUniversalQuickFix +import org.jetbrains.kotlin.idea.util.application.isApplicationInternalMode +import org.jetbrains.kotlin.idea.util.application.isUnitTestMode class AnnotationPresentationInfo( val ranges: List, @@ -28,32 +29,59 @@ class AnnotationPresentationInfo( val textAttributes: TextAttributesKey? = null ) { - fun processDiagnostics(holder: AnnotationHolder, diagnostics: List, fixesMap: MultiMap) { + fun processDiagnostics( + holder: AnnotationHolder, + diagnostics: Collection, + annotationBuilderByDiagnostic: MutableMap? = null, + annotationByTextRange: MutableMap?, + fixesMap: MultiMap?, + calculatingInProgress: Boolean + ) { for (range in ranges) { for (diagnostic in diagnostics) { - val fixes = fixesMap[diagnostic] create(diagnostic, range, holder) { annotation -> - fixes.forEach { - when (it) { - is KotlinUniversalQuickFix -> annotation.newFix(it).universal().registerFix() - is IntentionAction -> annotation.newFix(it).registerFix() - } + annotationBuilderByDiagnostic?.put(diagnostic, annotation) + if (fixesMap != null) { + applyFixes(fixesMap, diagnostic, annotation) } - - if (diagnostic.severity == Severity.WARNING) { - annotation.problemGroup(KotlinSuppressableWarningProblemGroup(diagnostic.factory)) - - if (fixes.isEmpty()) { - // if there are no quick fixes we need to register an EmptyIntentionAction to enable 'suppress' actions - annotation.newFix(EmptyIntentionAction(diagnostic.factory.name!!)).registerFix() - } + if (calculatingInProgress && annotationByTextRange?.containsKey(range) == false) { + annotationByTextRange[range] = annotation + annotation.registerFix(CalculatingIntentionAction(), range) } } } } } - private fun create(diagnostic: Diagnostic, range: TextRange, holder: AnnotationHolder, consumer: (AnnotationBuilder) -> Unit) { + internal fun applyFixes( + fixesMap: MultiMap, + diagnostic: Diagnostic, + annotation: Annotation + ) { + val fixes = fixesMap[diagnostic] + val textRange = TextRange(annotation.startOffset, annotation.endOffset) + fixes.forEach { + when (it) { + is KotlinUniversalQuickFix -> { + annotation.registerBatchFix(it, textRange, null) + annotation.registerFix(it, textRange) + } + is IntentionAction -> { + annotation.registerFix(it, textRange) + } + } + } + + if (diagnostic.severity == Severity.WARNING) { + if (fixes.isEmpty()) { + // if there are no quick fixes we need to register an EmptyIntentionAction to enable 'suppress' actions + //annotation.newFix(EmptyIntentionAction(diagnostic.factory.name)).registerFix() + annotation.registerFix(EmptyIntentionAction(diagnostic.factory.name), textRange) + } + } + } + + private fun create(diagnostic: Diagnostic, range: TextRange, holder: AnnotationHolder, consumer: (Annotation) -> Unit) { val severity = when (diagnostic.severity) { Severity.ERROR -> HighlightSeverity.ERROR Severity.WARNING -> if (highlightType == ProblemHighlightType.WEAK_WARNING) { @@ -62,18 +90,26 @@ class AnnotationPresentationInfo( Severity.INFO -> HighlightSeverity.WEAK_WARNING } - holder.newAnnotation(severity, nonDefaultMessage ?: getDefaultMessage(diagnostic)) + + val message = nonDefaultMessage ?: getDefaultMessage(diagnostic) + holder.newAnnotation(severity, message) .range(range) .tooltip(getMessage(diagnostic)) .also { builder -> highlightType?.let { builder.highlightType(it) } } .also { builder -> textAttributes?.let { builder.textAttributes(it) } } - .also { consumer(it) } + .also { + if (diagnostic.severity == Severity.WARNING) { + it.problemGroup(KotlinSuppressableWarningProblemGroup(diagnostic.factory)) + } + } .create() + @Suppress("UNCHECKED_CAST") + (holder as? List)?.last()?.let(consumer::invoke) } private fun getMessage(diagnostic: Diagnostic): String { var message = IdeErrorMessages.render(diagnostic) - if (ApplicationManager.getApplication().isInternal || ApplicationManager.getApplication().isUnitTestMode) { + if (isApplicationInternalMode() || isUnitTestMode()) { val factoryName = diagnostic.factory.name message = if (message.startsWith("")) { "[$factoryName] ${message.substring("".length)}" @@ -89,10 +125,11 @@ class AnnotationPresentationInfo( private fun getDefaultMessage(diagnostic: Diagnostic): String { val message = DefaultErrorMessages.render(diagnostic) - if (ApplicationManager.getApplication().isInternal || ApplicationManager.getApplication().isUnitTestMode) { - return "[${diagnostic.factory.name}] $message" + return if (isApplicationInternalMode() || isUnitTestMode()) { + "[${diagnostic.factory.name}] $message" + } else { + message } - return message } } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/CalculatingIntentionAction.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/CalculatingIntentionAction.kt new file mode 100644 index 00000000000..488af96bdf8 --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/CalculatingIntentionAction.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.highlighter + +import com.intellij.codeInsight.intention.AbstractEmptyIntentionAction +import com.intellij.codeInsight.intention.LowPriorityAction +import com.intellij.icons.AllIcons +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Iconable +import com.intellij.psi.PsiFile +import org.jetbrains.kotlin.idea.KotlinIdeaAnalysisBundle +import javax.swing.Icon + +class CalculatingIntentionAction : AbstractEmptyIntentionAction(), LowPriorityAction, Iconable { + override fun getText(): String = KotlinIdeaAnalysisBundle.message("intention.calculating.text") + + override fun getFamilyName(): String = KotlinIdeaAnalysisBundle.message("intention.calculating.text") + + override fun isAvailable(project: Project, editor: Editor, file: PsiFile): Boolean = true + + override fun equals(other: Any?): Boolean = this === other || other is CalculatingIntentionAction + + override fun hashCode(): Int = 42 + + override fun getIcon(@Iconable.IconFlags flags: Int): Icon = AllIcons.Actions.Preview +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/DebugInfoHighlightingPass.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/DebugInfoHighlightingPass.kt new file mode 100644 index 00000000000..beec88a4edb --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/DebugInfoHighlightingPass.kt @@ -0,0 +1,100 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.highlighter + +import com.intellij.codeHighlighting.* +import com.intellij.lang.annotation.AnnotationHolder +import com.intellij.lang.annotation.Annotator +import com.intellij.lang.annotation.HighlightSeverity +import com.intellij.openapi.editor.Document +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.editor.colors.TextAttributesKey +import com.intellij.openapi.progress.ProcessCanceledException +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import org.jetbrains.kotlin.checkers.utils.DebugInfoUtil +import org.jetbrains.kotlin.idea.KotlinPluginUtil +import org.jetbrains.kotlin.idea.util.ProjectRootsUtil +import org.jetbrains.kotlin.idea.util.application.isApplicationInternalMode +import org.jetbrains.kotlin.psi.KtCodeFragment +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtReferenceExpression + +class DebugInfoHighlightingPass(file: KtFile, document: Document) : AbstractBindingContextAwareHighlightingPassBase(file, document) { + override val annotator: Annotator + get() = DebugInfoAnnotator() + + private inner class DebugInfoAnnotator : Annotator { + override fun annotate(element: PsiElement, holder: AnnotationHolder) { + if (element is KtFile && element !is KtCodeFragment) { + fun errorAnnotation( + expression: PsiElement, + message: String, + textAttributes: TextAttributesKey? = KotlinHighlightingColors.DEBUG_INFO + ) = + holder.newAnnotation(HighlightSeverity.ERROR, "[DEBUG] $message") + .range(expression.textRange) + .also { + textAttributes?.let { ta -> it.textAttributes(ta) } + } + .create() + + try { + DebugInfoUtil.markDebugAnnotations(element, bindingContext(), object : DebugInfoUtil.DebugInfoReporter() { + override fun reportElementWithErrorType(expression: KtReferenceExpression) = + errorAnnotation(expression, "Resolved to error element", KotlinHighlightingColors.RESOLVED_TO_ERROR) + + override fun reportMissingUnresolved(expression: KtReferenceExpression) = + errorAnnotation( + expression, + "Reference is not resolved to anything, but is not marked unresolved" + ) + + override fun reportUnresolvedWithTarget(expression: KtReferenceExpression, target: String) = + errorAnnotation( + expression, + "Reference marked as unresolved is actually resolved to $target" + ) + }) + } catch (e: ProcessCanceledException) { + throw e + } catch (e: Throwable) { + // TODO + errorAnnotation(element, e.javaClass.canonicalName + ": " + e.message, null) + e.printStackTrace() + } + + } + } + } + + class Factory : TextEditorHighlightingPassFactory { + override fun createHighlightingPass(file: PsiFile, editor: Editor): TextEditorHighlightingPass? { + return if (file is KtFile && + (isApplicationInternalMode() && (KotlinPluginUtil.isSnapshotVersion() || KotlinPluginUtil.isDevVersion())) && + ProjectRootsUtil.isInProjectOrLibSource(file) + ) { + DebugInfoHighlightingPass(file, editor.document) + } else { + null + } + } + } + + class Registrar : TextEditorHighlightingPassFactoryRegistrar { + override fun registerHighlightingPassFactory(registrar: TextEditorHighlightingPassRegistrar, project: Project) { + registrar.registerTextEditorHighlightingPass( + Factory(), + /* runAfterCompletionOf = */ intArrayOf(Pass.UPDATE_ALL), + /* runAfterStartingOf = */ null, + /* runIntentionsPassAfter = */ false, + /* forcedPassId = */ -1 + ) + } + } + +} \ No newline at end of file diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/DuplicateJvmSignatureAnnotator.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/DuplicateJvmSignatureAnnotator.kt deleted file mode 100644 index 56818c1b443..00000000000 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/DuplicateJvmSignatureAnnotator.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2010-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.kotlin.idea.highlighter - -import com.intellij.lang.annotation.AnnotationHolder -import com.intellij.lang.annotation.Annotator -import com.intellij.psi.PsiElement -import org.jetbrains.kotlin.asJava.* -import org.jetbrains.kotlin.idea.caches.project.getModuleInfo -import org.jetbrains.kotlin.idea.caches.resolve.* -import org.jetbrains.kotlin.idea.project.TargetPlatformDetector -import org.jetbrains.kotlin.idea.util.ProjectRootsUtil -import org.jetbrains.kotlin.psi.KtDeclaration -import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.platform.jvm.isJvm - -class DuplicateJvmSignatureAnnotator : Annotator { - override fun annotate(element: PsiElement, holder: AnnotationHolder) { - if (element !is KtFile && element !is KtDeclaration) return - if (!ProjectRootsUtil.isInProjectSource(element)) return - - val file = element.containingFile - if (file !is KtFile || !TargetPlatformDetector.getPlatform(file).isJvm()) return - - val otherDiagnostics = when (element) { - is KtDeclaration -> element.analyzeWithContent() - is KtFile -> element.analyzeWithContent() - else -> throw AssertionError("DuplicateJvmSignatureAnnotator: should not get here! Element: ${element.text}") - }.diagnostics - - val moduleScope = element.getModuleInfo().contentScope() - val diagnostics = getJvmSignatureDiagnostics(element, otherDiagnostics, moduleScope) ?: return - - KotlinPsiChecker().annotateElement(element, holder, diagnostics) - } -} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/DuplicateJvmSignatureHighlightPass.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/DuplicateJvmSignatureHighlightPass.kt new file mode 100644 index 00000000000..ca1bba3a9e8 --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/DuplicateJvmSignatureHighlightPass.kt @@ -0,0 +1,74 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.highlighter + +import com.intellij.codeHighlighting.* +import com.intellij.lang.annotation.AnnotationHolder +import com.intellij.lang.annotation.Annotator +import com.intellij.openapi.editor.Document +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import org.jetbrains.kotlin.asJava.getJvmSignatureDiagnostics +import org.jetbrains.kotlin.idea.caches.project.getModuleInfo +import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithContent +import org.jetbrains.kotlin.idea.highlighter.AbstractKotlinHighlightingPass.Companion.annotateDiagnostics +import org.jetbrains.kotlin.idea.project.TargetPlatformDetector +import org.jetbrains.kotlin.idea.util.ProjectRootsUtil +import org.jetbrains.kotlin.platform.jvm.isJvm +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.psi.KtFile + +class DuplicateJvmSignatureHighlightPass(file: KtFile, document: Document) : + AbstractBindingContextAwareHighlightingPassBase(file, document) { + override val annotator: Annotator + get() = DuplicateJvmSignatureAnnotator() + + inner class DuplicateJvmSignatureAnnotator : Annotator { + override fun annotate(element: PsiElement, holder: AnnotationHolder) { + if (element !is KtFile && element !is KtDeclaration) return + + val otherDiagnostics = when (element) { + is KtDeclaration -> element.analyzeWithContent() + is KtFile -> element.analyzeWithContent() + else -> throw AssertionError("DuplicateJvmSignatureAnnotator: should not get here! Element: ${element.text}") + }.diagnostics + + val moduleScope = element.getModuleInfo().contentScope() + val diagnostics = getJvmSignatureDiagnostics(element, otherDiagnostics, moduleScope) ?: return + + val diagnosticsForElement = diagnostics.forElement(element).toSet() + + annotateDiagnostics(file, element, holder, diagnosticsForElement) + } + } + + class Factory : TextEditorHighlightingPassFactory { + override fun createHighlightingPass(file: PsiFile, editor: Editor): TextEditorHighlightingPass? { + return if (file is KtFile && + ProjectRootsUtil.isInProjectSource(file) && + TargetPlatformDetector.getPlatform(file).isJvm() + ) { + DuplicateJvmSignatureHighlightPass(file, editor.document) + } else { + null + } + } + } + + class Registrar : TextEditorHighlightingPassFactoryRegistrar { + override fun registerHighlightingPassFactory(registrar: TextEditorHighlightingPassRegistrar, project: Project) { + registrar.registerTextEditorHighlightingPass( + Factory(), + /* runAfterCompletionOf = */ intArrayOf(Pass.UPDATE_ALL), + /* runAfterStartingOf = */ null, + /* runIntentionsPassAfter = */ false, + /* forcedPassId = */ -1 + ) + } + } +} \ No newline at end of file diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/ElementAnnotator.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/ElementAnnotator.kt new file mode 100644 index 00000000000..82467f68b1f --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/ElementAnnotator.kt @@ -0,0 +1,214 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.highlighter + +import com.intellij.codeInsight.intention.IntentionAction +import com.intellij.codeInspection.ProblemHighlightType +import com.intellij.lang.annotation.Annotation +import com.intellij.lang.annotation.AnnotationHolder +import com.intellij.openapi.diagnostic.ControlFlowException +import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.editor.colors.CodeInsightColors +import com.intellij.openapi.util.TextRange +import com.intellij.psi.MultiRangeReference +import com.intellij.psi.PsiElement +import com.intellij.util.containers.MultiMap +import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments +import org.jetbrains.kotlin.config.KotlinFacetSettingsProvider +import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.diagnostics.Severity +import org.jetbrains.kotlin.idea.references.mainReference +import org.jetbrains.kotlin.idea.util.module +import org.jetbrains.kotlin.psi.KtParameter +import org.jetbrains.kotlin.psi.KtReferenceExpression + +internal class ElementAnnotator( + private val element: PsiElement, + private val shouldSuppressUnusedParameter: (KtParameter) -> Boolean +) { + fun registerDiagnosticsAnnotations( + holder: AnnotationHolder, + diagnostics: Collection, + annotationByDiagnostic: MutableMap?, + annotationByTextRange: MutableMap?, + noFixes: Boolean, + calculatingInProgress: Boolean + ) = diagnostics.groupBy { it.factory } + .forEach { + registerSameFactoryDiagnosticsAnnotations( + holder, + it.value, + annotationByDiagnostic, + annotationByTextRange, + noFixes, + calculatingInProgress + ) + } + + private fun registerSameFactoryDiagnosticsAnnotations( + holder: AnnotationHolder, + diagnostics: Collection, + annotationByDiagnostic: MutableMap?, + annotationByTextRange: MutableMap?, + noFixes: Boolean, + calculatingInProgress: Boolean + ) { + val presentationInfo = presentationInfo(diagnostics) ?: return + setUpAnnotations( + holder, + diagnostics, + presentationInfo, + annotationByDiagnostic, + annotationByTextRange, + noFixes, + calculatingInProgress + ) + } + + fun registerDiagnosticsQuickFixes( + diagnostics: List, + annotationByDiagnostic: MutableMap + ) = diagnostics.groupBy { it.factory } + .forEach { registerDiagnosticsSameFactoryQuickFixes(it.value, annotationByDiagnostic) } + + private fun registerDiagnosticsSameFactoryQuickFixes( + diagnostics: List, + annotationByDiagnostic: MutableMap + ) { + val presentationInfo = presentationInfo(diagnostics) ?: return + val fixesMap = createFixesMap(diagnostics) ?: return + + diagnostics.forEach { + val annotation = annotationByDiagnostic[it] ?: return + + presentationInfo.applyFixes(fixesMap, it, annotation) + } + } + + private fun presentationInfo(diagnostics: Collection): AnnotationPresentationInfo? { + if (diagnostics.isEmpty() || !diagnostics.any { it.isValid }) return null + + val diagnostic = diagnostics.first() + // hack till the root cause #KT-21246 is fixed + if (isUnstableAbiClassDiagnosticForModulesWithEnabledUnstableAbi(diagnostic)) return null + + val factory = diagnostic.factory + + assert(diagnostics.all { it.psiElement == element && it.factory == factory }) + + val ranges = diagnostic.textRanges + val presentationInfo: AnnotationPresentationInfo = when (factory.severity) { + Severity.ERROR -> { + when (factory) { + in Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS -> { + val referenceExpression = element as KtReferenceExpression + val reference = referenceExpression.mainReference + if (reference is MultiRangeReference) { + AnnotationPresentationInfo( + ranges = reference.ranges.map { it.shiftRight(referenceExpression.textOffset) }, + highlightType = ProblemHighlightType.LIKE_UNKNOWN_SYMBOL + ) + } else { + AnnotationPresentationInfo(ranges, highlightType = ProblemHighlightType.LIKE_UNKNOWN_SYMBOL) + } + } + + Errors.ILLEGAL_ESCAPE -> AnnotationPresentationInfo( + ranges, textAttributes = KotlinHighlightingColors.INVALID_STRING_ESCAPE + ) + + Errors.REDECLARATION -> AnnotationPresentationInfo( + ranges = listOf(diagnostic.textRanges.first()), nonDefaultMessage = "" + ) + + else -> { + AnnotationPresentationInfo( + ranges, + highlightType = if (factory == Errors.INVISIBLE_REFERENCE) + ProblemHighlightType.LIKE_UNKNOWN_SYMBOL + else + null + ) + } + } + } + Severity.WARNING -> { + if (factory == Errors.UNUSED_PARAMETER && shouldSuppressUnusedParameter(element as KtParameter)) { + return null + } + + AnnotationPresentationInfo( + ranges, + textAttributes = when (factory) { + Errors.DEPRECATION -> CodeInsightColors.DEPRECATED_ATTRIBUTES + Errors.UNUSED_ANONYMOUS_PARAMETER -> CodeInsightColors.WEAK_WARNING_ATTRIBUTES + else -> null + }, + highlightType = when (factory) { + in Errors.UNUSED_ELEMENT_DIAGNOSTICS -> ProblemHighlightType.LIKE_UNUSED_SYMBOL + Errors.UNUSED_ANONYMOUS_PARAMETER -> ProblemHighlightType.WEAK_WARNING + else -> null + } + ) + } + Severity.INFO -> AnnotationPresentationInfo(ranges, highlightType = ProblemHighlightType.INFORMATION) + } + return presentationInfo + } + + private fun setUpAnnotations( + holder: AnnotationHolder, + diagnostics: Collection, + data: AnnotationPresentationInfo, + annotationByDiagnostic: MutableMap?, + annotationByTextRange: MutableMap?, + noFixes: Boolean, + calculatingInProgress: Boolean + ) { + val fixesMap = + createFixesMap(diagnostics, noFixes) + + data.processDiagnostics(holder, diagnostics, annotationByDiagnostic, annotationByTextRange, fixesMap, calculatingInProgress) + } + + private fun createFixesMap( + diagnostics: Collection, + noFixes: Boolean = false + ): MultiMap? = if (noFixes) { + null + } else { + try { + createQuickFixes(diagnostics) + } catch (e: Exception) { + if (e is ControlFlowException) { + throw e + } + LOG.error(e) + MultiMap() + } + } + + private fun isUnstableAbiClassDiagnosticForModulesWithEnabledUnstableAbi(diagnostic: Diagnostic): Boolean { + val factory = diagnostic.factory + if (factory != Errors.IR_WITH_UNSTABLE_ABI_COMPILED_CLASS && factory != Errors.FIR_COMPILED_CLASS) return false + + val module = element.module ?: return false + val moduleFacetSettings = KotlinFacetSettingsProvider.getInstance(element.project)?.getSettings(module) ?: return false + return when (factory) { + Errors.IR_WITH_UNSTABLE_ABI_COMPILED_CLASS -> + moduleFacetSettings.isCompilerSettingPresent(K2JVMCompilerArguments::useIR) && + !moduleFacetSettings.isCompilerSettingPresent(K2JVMCompilerArguments::useOldBackend) + Errors.FIR_COMPILED_CLASS -> + moduleFacetSettings.isCompilerSettingPresent(K2JVMCompilerArguments::useFir) + else -> error(factory) + } + } + + companion object { + val LOG = Logger.getInstance(ElementAnnotator::class.java) + } +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightingUtil.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightingUtil.kt index f2656bc597c..e53d590fe0a 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightingUtil.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightingUtil.kt @@ -34,7 +34,10 @@ import kotlin.script.experimental.api.ScriptDiagnostic object KotlinHighlightingUtil { fun shouldHighlight(psiElement: PsiElement): Boolean { val ktFile = psiElement.containingFile as? KtFile ?: return false + return shouldHighlightFile(ktFile) + } + fun shouldHighlightFile(ktFile: KtFile): Boolean { if (ktFile is KtCodeFragment && ktFile.context != null) { return true } @@ -52,8 +55,12 @@ object KotlinHighlightingUtil { return ProjectRootsUtil.isInProjectOrLibraryContent(ktFile) && ktFile.getModuleInfo() !is NotUnderContentRootModuleInfo } - fun shouldHighlightErrors(psiElement: PsiElement): Boolean { - val ktFile = psiElement.containingFile as? KtFile ?: return false + fun shouldHighlightErrors(psiElement: PsiElement): Boolean = + (psiElement.containingFile as? KtFile)?.let { + shouldHighlightErrors(it) + } ?: false + + fun shouldHighlightErrors(ktFile: KtFile): Boolean { if (ktFile.isCompiled) { return false } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinPsiChecker.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinPsiChecker.kt deleted file mode 100644 index 18b0bd371fd..00000000000 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinPsiChecker.kt +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.idea.highlighter - -import com.intellij.codeInsight.intention.IntentionAction -import com.intellij.codeInspection.ProblemHighlightType -import com.intellij.lang.annotation.AnnotationHolder -import com.intellij.openapi.diagnostic.ControlFlowException -import com.intellij.openapi.diagnostic.Logger -import com.intellij.openapi.editor.colors.CodeInsightColors -import com.intellij.openapi.progress.ProcessCanceledException -import com.intellij.openapi.util.Key -import com.intellij.psi.MultiRangeReference -import com.intellij.psi.PsiElement -import com.intellij.util.containers.MultiMap -import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments -import org.jetbrains.kotlin.config.KotlinFacetSettings -import org.jetbrains.kotlin.config.KotlinFacetSettingsProvider -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.diagnostics.Diagnostic -import org.jetbrains.kotlin.diagnostics.DiagnosticFactory -import org.jetbrains.kotlin.diagnostics.Errors -import org.jetbrains.kotlin.diagnostics.Severity -import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithAllCompilerChecks -import org.jetbrains.kotlin.idea.quickfix.QuickFixes -import org.jetbrains.kotlin.idea.references.mainReference -import org.jetbrains.kotlin.idea.util.module -import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.psi.KtNameReferenceExpression -import org.jetbrains.kotlin.psi.KtParameter -import org.jetbrains.kotlin.psi.KtReferenceExpression -import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics -import org.jetbrains.kotlin.types.KotlinType -import java.lang.reflect.* -import java.util.* - -open class KotlinPsiChecker : AbstractKotlinPsiChecker() { - override fun shouldHighlight(file: KtFile): Boolean = KotlinHighlightingUtil.shouldHighlight(file) - - override fun annotateElement( - element: PsiElement, - containingFile: KtFile, - holder: AnnotationHolder - ) { - val analysisResult = containingFile.analyzeWithAllCompilerChecks() - if (analysisResult.isError()) { - throw ProcessCanceledException(analysisResult.error) - } - - val bindingContext = analysisResult.bindingContext - - getAfterAnalysisVisitor(holder, bindingContext).forEach { visitor -> element.accept(visitor) } - - annotateElement(element, holder, bindingContext.diagnostics) - } - - protected open fun shouldSuppressUnusedParameter(parameter: KtParameter): Boolean = false - - fun annotateElement(element: PsiElement, holder: AnnotationHolder, diagnostics: Diagnostics) { - val diagnosticsForElement = diagnostics.forElement(element).toSet() - - if (element is KtNameReferenceExpression) { - val unresolved = diagnostics.any { it.factory == Errors.UNRESOLVED_REFERENCE } - element.putUserData(UNRESOLVED_KEY, if (unresolved) Unit else null) - } - - if (diagnosticsForElement.isEmpty()) return - - if (KotlinHighlightingUtil.shouldHighlightErrors(element)) { - ElementAnnotator(element, holder) { param -> - shouldSuppressUnusedParameter(param) - }.registerDiagnosticsAnnotations(diagnosticsForElement) - } - } - - companion object { - fun getAfterAnalysisVisitor(holder: AnnotationHolder, bindingContext: BindingContext) = arrayOf( - PropertiesHighlightingVisitor(holder, bindingContext), - FunctionsHighlightingVisitor(holder, bindingContext), - VariablesHighlightingVisitor(holder, bindingContext), - TypeKindHighlightingVisitor(holder, bindingContext) - ) - - fun createQuickFixes(diagnostic: Diagnostic): Collection = - createQuickFixes(listOfNotNull(diagnostic))[diagnostic] - - private val UNRESOLVED_KEY = Key("KotlinPsiChecker.UNRESOLVED_KEY") - - fun wasUnresolved(element: KtNameReferenceExpression) = element.getUserData(UNRESOLVED_KEY) != null - } -} - -private fun createQuickFixes(similarDiagnostics: Collection): MultiMap { - val first = similarDiagnostics.minByOrNull { it.toString() } - val factory = similarDiagnostics.first().getRealDiagnosticFactory() - - val actions = MultiMap() - - val intentionActionsFactories = QuickFixes.getInstance().getActionFactories(factory) - for (intentionActionsFactory in intentionActionsFactories) { - val allProblemsActions = intentionActionsFactory.createActionsForAllProblems(similarDiagnostics) - if (allProblemsActions.isNotEmpty()) { - actions.putValues(first, allProblemsActions) - } else { - for (diagnostic in similarDiagnostics) { - actions.putValues(diagnostic, intentionActionsFactory.createActions(diagnostic)) - } - } - } - - for (diagnostic in similarDiagnostics) { - actions.putValues(diagnostic, QuickFixes.getInstance().getActions(diagnostic.factory)) - } - - actions.values().forEach { NoDeclarationDescriptorsChecker.check(it::class.java) } - - return actions -} - -private fun Diagnostic.getRealDiagnosticFactory(): DiagnosticFactory<*> = - when (factory) { - Errors.PLUGIN_ERROR -> Errors.PLUGIN_ERROR.cast(this).a.factory - Errors.PLUGIN_WARNING -> Errors.PLUGIN_WARNING.cast(this).a.factory - Errors.PLUGIN_INFO -> Errors.PLUGIN_INFO.cast(this).a.factory - else -> factory - } - -private object NoDeclarationDescriptorsChecker { - private val LOG = Logger.getInstance(NoDeclarationDescriptorsChecker::class.java) - - private val checkedQuickFixClasses = Collections.synchronizedSet(HashSet>()) - - fun check(quickFixClass: Class<*>) { - if (!checkedQuickFixClasses.add(quickFixClass)) return - - for (field in quickFixClass.declaredFields) { - checkType(field.genericType, field) - } - - quickFixClass.superclass?.let { check(it) } - } - - private fun checkType(type: Type, field: Field) { - when (type) { - is Class<*> -> { - if (DeclarationDescriptor::class.java.isAssignableFrom(type) || KotlinType::class.java.isAssignableFrom(type)) { - LOG.error( - "QuickFix class ${field.declaringClass.name} contains field ${field.name} that holds ${type.simpleName}. " - + "This leads to holding too much memory through this quick-fix instance. " - + "Possible solution can be wrapping it using KotlinIntentionActionFactoryWithDelegate." - ) - } - - if (IntentionAction::class.java.isAssignableFrom(type)) { - check(type) - } - - } - - is GenericArrayType -> checkType(type.genericComponentType, field) - - is ParameterizedType -> { - if (Collection::class.java.isAssignableFrom(type.rawType as Class<*>)) { - type.actualTypeArguments.forEach { checkType(it, field) } - } - } - - is WildcardType -> type.upperBounds.forEach { checkType(it, field) } - } - } -} - -private class ElementAnnotator( - private val element: PsiElement, - private val holder: AnnotationHolder, - private val shouldSuppressUnusedParameter: (KtParameter) -> Boolean -) { - fun registerDiagnosticsAnnotations(diagnostics: Collection) { - diagnostics.groupBy { it.factory }.forEach { group -> registerDiagnosticAnnotations(group.value) } - } - - private fun registerDiagnosticAnnotations(diagnostics: List) { - assert(diagnostics.isNotEmpty()) - - val validDiagnostics = diagnostics.filter { it.isValid } - if (validDiagnostics.isEmpty()) return - - val diagnostic = diagnostics.first() - val factory = diagnostic.factory - - // hack till the root cause #KT-21246 is fixed - if (isUnstableAbiClassDiagnosticForModulesWithEnabledUnstableAbi(diagnostic)) return - - assert(diagnostics.all { it.psiElement == element && it.factory == factory }) - - val ranges = diagnostic.textRanges - - val presentationInfo: AnnotationPresentationInfo = when (factory.severity) { - Severity.ERROR -> { - when (factory) { - in Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS -> { - val referenceExpression = element as KtReferenceExpression - val reference = referenceExpression.mainReference - if (reference is MultiRangeReference) { - AnnotationPresentationInfo( - ranges = reference.ranges.map { it.shiftRight(referenceExpression.textOffset) }, - highlightType = ProblemHighlightType.LIKE_UNKNOWN_SYMBOL - ) - } else { - AnnotationPresentationInfo(ranges, highlightType = ProblemHighlightType.LIKE_UNKNOWN_SYMBOL) - } - } - - Errors.ILLEGAL_ESCAPE -> AnnotationPresentationInfo( - ranges, textAttributes = KotlinHighlightingColors.INVALID_STRING_ESCAPE - ) - - Errors.REDECLARATION -> AnnotationPresentationInfo( - ranges = listOf(diagnostic.textRanges.first()), nonDefaultMessage = "" - ) - - else -> { - AnnotationPresentationInfo( - ranges, - highlightType = if (factory == Errors.INVISIBLE_REFERENCE) - ProblemHighlightType.LIKE_UNKNOWN_SYMBOL - else - null - ) - } - } - } - Severity.WARNING -> { - if (factory == Errors.UNUSED_PARAMETER && shouldSuppressUnusedParameter(element as KtParameter)) { - return - } - - AnnotationPresentationInfo( - ranges, - textAttributes = when (factory) { - Errors.DEPRECATION -> CodeInsightColors.DEPRECATED_ATTRIBUTES - Errors.UNUSED_ANONYMOUS_PARAMETER -> CodeInsightColors.WEAK_WARNING_ATTRIBUTES - else -> null - }, - highlightType = when (factory) { - in Errors.UNUSED_ELEMENT_DIAGNOSTICS -> ProblemHighlightType.LIKE_UNUSED_SYMBOL - Errors.UNUSED_ANONYMOUS_PARAMETER -> ProblemHighlightType.WEAK_WARNING - else -> null - } - ) - } - Severity.INFO -> AnnotationPresentationInfo(ranges, highlightType = ProblemHighlightType.INFORMATION) - } - - setUpAnnotations(diagnostics, presentationInfo) - } - - private fun setUpAnnotations(diagnostics: List, data: AnnotationPresentationInfo) { - val fixesMap = try { - createQuickFixes(diagnostics) - } catch (e: Exception) { - if (e is ControlFlowException) { - throw e - } - LOG.error(e) - MultiMap() - } - - data.processDiagnostics(holder, diagnostics, fixesMap) - } - - private fun isUnstableAbiClassDiagnosticForModulesWithEnabledUnstableAbi(diagnostic: Diagnostic): Boolean { - val factory = diagnostic.factory - if (factory != Errors.IR_WITH_UNSTABLE_ABI_COMPILED_CLASS && factory != Errors.FIR_COMPILED_CLASS) return false - - val module = element.module ?: return false - val moduleFacetSettings = KotlinFacetSettingsProvider.getInstance(element.project)?.getSettings(module) ?: return false - return when (factory) { - Errors.IR_WITH_UNSTABLE_ABI_COMPILED_CLASS -> - moduleFacetSettings.isCompilerSettingPresent(K2JVMCompilerArguments::useIR) && - !moduleFacetSettings.isCompilerSettingPresent(K2JVMCompilerArguments::useOldBackend) - Errors.FIR_COMPILED_CLASS -> - moduleFacetSettings.isCompilerSettingPresent(K2JVMCompilerArguments::useFir) - else -> error(factory) - } - } - - companion object { - val LOG = Logger.getInstance(ElementAnnotator::class.java) - } -} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/VariablesHighlightingVisitor.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/VariablesHighlightingVisitor.kt index 0bdc9234c72..5778f16260c 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/VariablesHighlightingVisitor.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/VariablesHighlightingVisitor.kt @@ -35,8 +35,8 @@ internal class VariablesHighlightingVisitor(holder: AnnotationHolder, bindingCon if (target is ValueParameterDescriptor && bindingContext.get(AUTO_CREATED_IT, target) == true) { createInfoAnnotation( expression, - FUNCTION_LITERAL_DEFAULT_PARAMETER, - KotlinIdeaAnalysisBundle.message("automatically.declared.based.on.the.expected.type") + KotlinIdeaAnalysisBundle.message("automatically.declared.based.on.the.expected.type"), + FUNCTION_LITERAL_DEFAULT_PARAMETER ) } else if (expression.parent !is KtValueArgumentName) { // highlighted separately highlightVariable(expression, target) @@ -91,14 +91,15 @@ internal class VariablesHighlightingVisitor(holder: AnnotationHolder, bindingCon "0.smart.cast.to.1", receiverName, DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(type) - ) - ).textAttributes = SMART_CAST_RECEIVER + ), + SMART_CAST_RECEIVER + ) } } val nullSmartCast = bindingContext.get(SMARTCAST_NULL, expression) == true if (nullSmartCast) { - createInfoAnnotation(expression, KotlinIdeaAnalysisBundle.message("always.null")).textAttributes = SMART_CONSTANT + createInfoAnnotation(expression, KotlinIdeaAnalysisBundle.message("always.null"), SMART_CONSTANT) } val smartCast = bindingContext.get(SMARTCAST, expression) @@ -107,8 +108,9 @@ internal class VariablesHighlightingVisitor(holder: AnnotationHolder, bindingCon if (defaultType != null) { createInfoAnnotation( getSmartCastTarget(expression), - KotlinIdeaAnalysisBundle.message("smart.cast.to.0", DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(defaultType)) - ).textAttributes = SMART_CAST_VALUE + KotlinIdeaAnalysisBundle.message("smart.cast.to.0", DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(defaultType)), + SMART_CAST_VALUE + ) } else if (smartCast is MultipleSmartCasts) { for ((call, type) in smartCast.map) { createInfoAnnotation( @@ -117,8 +119,9 @@ internal class VariablesHighlightingVisitor(holder: AnnotationHolder, bindingCon "smart.cast.to.0.for.1.call", DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(type), call.toString() - ) - ).textAttributes = SMART_CAST_VALUE + ), + SMART_CAST_VALUE + ) } } } @@ -154,7 +157,7 @@ internal class VariablesHighlightingVisitor(holder: AnnotationHolder, bindingCon val parent = elementToHighlight.parent if (!(parent is PsiNameIdentifierOwner && parent.nameIdentifier == elementToHighlight)) { - createInfoAnnotation(elementToHighlight, WRAPPED_INTO_REF, msg) + createInfoAnnotation(elementToHighlight, msg, WRAPPED_INTO_REF) return } } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/FromUnresolvedNamesCompletion.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/FromUnresolvedNamesCompletion.kt index 955430e86d4..e9e3c7d3dd6 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/FromUnresolvedNamesCompletion.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/FromUnresolvedNamesCompletion.kt @@ -9,7 +9,8 @@ import com.intellij.codeInsight.completion.PrefixMatcher import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.openapi.progress.ProgressManager import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.idea.highlighter.KotlinPsiChecker +import org.jetbrains.kotlin.idea.highlighter.AbstractKotlinHighlightingPass +import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingPass import org.jetbrains.kotlin.idea.references.resolveMainReferenceToDescriptors import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver import org.jetbrains.kotlin.psi.KtCallExpression @@ -28,7 +29,7 @@ class FromUnresolvedNamesCompletion( scope.forEachDescendantOfType { refExpr -> ProgressManager.checkCanceled() - if (KotlinPsiChecker.wasUnresolved(refExpr)) { + if (AbstractKotlinHighlightingPass.wasUnresolved(refExpr)) { val callTypeAndReceiver = CallTypeAndReceiver.detect(refExpr) if (callTypeAndReceiver.receiver != null) return@forEachDescendantOfType if (sampleDescriptor != null) { diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/visitors/ExpressionsSmartcastHighlightingVisitor.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/visitors/ExpressionsSmartcastHighlightingVisitor.kt index add37568aa3..eb8c0166d41 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/visitors/ExpressionsSmartcastHighlightingVisitor.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/visitors/ExpressionsSmartcastHighlightingVisitor.kt @@ -10,6 +10,7 @@ import com.intellij.psi.PsiElement import org.jetbrains.kotlin.idea.KotlinIdeaAnalysisBundle import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession import org.jetbrains.kotlin.idea.frontend.api.ImplicitReceiverSmartcastKind +import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingColors import org.jetbrains.kotlin.psi.* internal class ExpressionsSmartcastHighlightingVisitor( @@ -30,8 +31,9 @@ internal class ExpressionsSmartcastHighlightingVisitor( "0.smart.cast.to.1", receiverName, type.asStringForDebugging() - ) - ).textAttributes = org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingColors.SMART_CAST_RECEIVER + ), + KotlinHighlightingColors.SMART_CAST_RECEIVER + ) } } expression.getSmartCasts()?.forEach { type -> @@ -40,8 +42,9 @@ internal class ExpressionsSmartcastHighlightingVisitor( KotlinIdeaAnalysisBundle.message( "smart.cast.to.0", type.asStringForDebugging() - ) - ).textAttributes = org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingColors.SMART_CAST_VALUE + ), + KotlinHighlightingColors.SMART_CAST_VALUE + ) } //todo smartcast to null diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/visitors/FirAfterResolveHighlightingVisitor.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/visitors/FirAfterResolveHighlightingVisitor.kt index 0348a0cf832..4a378ce9e37 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/visitors/FirAfterResolveHighlightingVisitor.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/visitors/FirAfterResolveHighlightingVisitor.kt @@ -6,6 +6,8 @@ package org.jetbrains.kotlin.idea.fir.highlighter.visitors import com.intellij.lang.annotation.AnnotationHolder +import com.intellij.openapi.editor.colors.TextAttributesKey +import com.intellij.openapi.util.TextRange import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession import org.jetbrains.kotlin.idea.highlighter.HighlightingVisitor @@ -14,6 +16,12 @@ abstract class FirAfterResolveHighlightingVisitor( protected val holder: AnnotationHolder ) : HighlightingVisitor(holder) { + override fun createInfoAnnotation(textRange: TextRange, message: String?, textAttributes: TextAttributesKey?) { + // TODO: Temporary use deprecated for FIR plugin as it is supposes to be rewritten fully + holder.createInfoAnnotation(textRange, message) + .also { annotation -> textAttributes?.let { annotation.textAttributes = textAttributes } } + } + companion object { fun createListOfVisitors( analysisSession: KtAnalysisSession, diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/visitors/VariableReferenceHighlightingVisitor.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/visitors/VariableReferenceHighlightingVisitor.kt index 316079c6e2f..b22dad28b3b 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/visitors/VariableReferenceHighlightingVisitor.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/highlighter/visitors/VariableReferenceHighlightingVisitor.kt @@ -34,8 +34,8 @@ internal class VariableReferenceHighlightingVisitor( if (expression.isAutoCreatedItParameter()) { createInfoAnnotation( expression, - Colors.FUNCTION_LITERAL_DEFAULT_PARAMETER, - KotlinIdeaAnalysisBundle.message("automatically.declared.based.on.the.expected.type") + KotlinIdeaAnalysisBundle.message("automatically.declared.based.on.the.expected.type"), + Colors.FUNCTION_LITERAL_DEFAULT_PARAMETER ) return } diff --git a/idea/idea-fir/tests/org/jetbrains/kotlin/checkers/AbstractFirPsiCheckerTest.kt b/idea/idea-fir/tests/org/jetbrains/kotlin/checkers/AbstractFirKotlinHighlightingPassTest.kt similarity index 95% rename from idea/idea-fir/tests/org/jetbrains/kotlin/checkers/AbstractFirPsiCheckerTest.kt rename to idea/idea-fir/tests/org/jetbrains/kotlin/checkers/AbstractFirKotlinHighlightingPassTest.kt index 2630a8431f0..c58d50a881c 100644 --- a/idea/idea-fir/tests/org/jetbrains/kotlin/checkers/AbstractFirPsiCheckerTest.kt +++ b/idea/idea-fir/tests/org/jetbrains/kotlin/checkers/AbstractFirKotlinHighlightingPassTest.kt @@ -13,7 +13,7 @@ import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.test.uitls.IgnoreTests import java.io.File -abstract class AbstractFirPsiCheckerTest : AbstractPsiCheckerTest() { +abstract class AbstractFirKotlinHighlightingPassTest : AbstractKotlinHighlightingPassTest() { override val captureExceptions: Boolean = false override fun isFirPlugin(): Boolean = true diff --git a/idea/idea-fir/tests/org/jetbrains/kotlin/checkers/FirPsiCheckerTestGenerated.java b/idea/idea-fir/tests/org/jetbrains/kotlin/checkers/FirKotlinHighlightingPassTestGenerated.java similarity index 97% rename from idea/idea-fir/tests/org/jetbrains/kotlin/checkers/FirPsiCheckerTestGenerated.java rename to idea/idea-fir/tests/org/jetbrains/kotlin/checkers/FirKotlinHighlightingPassTestGenerated.java index dde41ce45cf..6b27c7511c8 100644 --- a/idea/idea-fir/tests/org/jetbrains/kotlin/checkers/FirPsiCheckerTestGenerated.java +++ b/idea/idea-fir/tests/org/jetbrains/kotlin/checkers/FirKotlinHighlightingPassTestGenerated.java @@ -18,11 +18,11 @@ import java.util.regex.Pattern; /** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ @SuppressWarnings("all") @RunWith(JUnit3RunnerWithInners.class) -public class FirPsiCheckerTestGenerated extends AbstractFirPsiCheckerTest { +public class FirKotlinHighlightingPassTestGenerated extends AbstractFirKotlinHighlightingPassTest { @TestMetadata("idea/testData/checker") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class Checker extends AbstractFirPsiCheckerTest { + public static class Checker extends AbstractFirKotlinHighlightingPassTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } @@ -41,6 +41,11 @@ public class FirPsiCheckerTestGenerated extends AbstractFirPsiCheckerTest { runTest("idea/testData/checker/AnnotationOnFile.kt"); } + @TestMetadata("AnnotationSupressing.kt") + public void testAnnotationSupressing() throws Exception { + runTest("idea/testData/checker/AnnotationSupressing.kt"); + } + @TestMetadata("AnonymousInitializers.kt") public void testAnonymousInitializers() throws Exception { runTest("idea/testData/checker/AnonymousInitializers.kt"); @@ -365,7 +370,7 @@ public class FirPsiCheckerTestGenerated extends AbstractFirPsiCheckerTest { @TestMetadata("idea/testData/checker/regression") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class Regression extends AbstractFirPsiCheckerTest { + public static class Regression extends AbstractFirKotlinHighlightingPassTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } @@ -608,7 +613,7 @@ public class FirPsiCheckerTestGenerated extends AbstractFirPsiCheckerTest { @TestMetadata("idea/testData/checker/recovery") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class Recovery extends AbstractFirPsiCheckerTest { + public static class Recovery extends AbstractFirKotlinHighlightingPassTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } @@ -636,7 +641,7 @@ public class FirPsiCheckerTestGenerated extends AbstractFirPsiCheckerTest { @TestMetadata("idea/testData/checker/rendering") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class Rendering extends AbstractFirPsiCheckerTest { + public static class Rendering extends AbstractFirKotlinHighlightingPassTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } @@ -654,7 +659,7 @@ public class FirPsiCheckerTestGenerated extends AbstractFirPsiCheckerTest { @TestMetadata("idea/testData/checker/infos") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class Infos extends AbstractFirPsiCheckerTest { + public static class Infos extends AbstractFirKotlinHighlightingPassTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } @@ -747,7 +752,7 @@ public class FirPsiCheckerTestGenerated extends AbstractFirPsiCheckerTest { @TestMetadata("idea/testData/checker/diagnosticsMessage") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class DiagnosticsMessage extends AbstractFirPsiCheckerTest { + public static class DiagnosticsMessage extends AbstractFirKotlinHighlightingPassTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } diff --git a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/AbstractHighlightingPassBase.kt b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/AbstractHighlightingPassBase.kt new file mode 100644 index 00000000000..07f21d2ad9b --- /dev/null +++ b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/AbstractHighlightingPassBase.kt @@ -0,0 +1,84 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.highlighter + +import com.intellij.codeHighlighting.TextEditorHighlightingPass +import com.intellij.codeInsight.daemon.impl.AnnotationHolderImpl +import com.intellij.codeInsight.daemon.impl.HighlightInfo +import com.intellij.codeInsight.daemon.impl.UpdateHighlightersUtil +import com.intellij.lang.annotation.Annotation +import com.intellij.lang.annotation.AnnotationHolder +import com.intellij.lang.annotation.AnnotationSession +import com.intellij.openapi.editor.Document +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.project.DumbAware +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiRecursiveElementVisitor +import org.jetbrains.kotlin.psi.KtFile + +/** + * Single thread model only (as any other [TextEditorHighlightingPass]) + */ +@Suppress("UnstableApiUsage") +abstract class AbstractHighlightingPassBase( + protected val file: KtFile, + document: Document +) : TextEditorHighlightingPass(file.project, document), DumbAware { + + private val highlightInfos: MutableList = mutableListOf() + protected var annotationCallback: ((Annotation) -> Unit)? = null + protected var annotationHolder: AnnotationHolderImpl? = null + + fun annotationCallback(callback: (Annotation) -> Unit) { + annotationCallback = callback + } + + fun resetAnnotationCallback() { + annotationCallback = null + } + + override fun doCollectInformation(progress: ProgressIndicator) { + highlightInfos.clear() + + // TODO: YES, IT USES `@ApiStatus.Internal` AnnotationHolderImpl intentionally: + // there is no other way to highlight: + // - HighlightInfo could not be highlighted immediately as myHighlightInfoProcessor.infoIsAvailable is not accessible + // (HighlightingSessionImpl impl is closed) and/or UpdateHighlightersUtil.addHighlighterToEditorIncrementally is closed as well. + // therefore direct usage of AnnotationHolderImpl is the smallest evil + + val annotationHolder = object : AnnotationHolderImpl(AnnotationSession(file)) { + override fun add(element: Annotation?): Boolean { + element?.let { annotationCallback?.invoke(it) } + return super.add(element) + } + } + annotationHolder.runAnnotatorWithContext(file) { element, holder -> + runAnnotatorWithContext(element, holder) + } + this.annotationHolder = annotationHolder + } + + protected open fun runAnnotatorWithContext( + element: PsiElement, + holder: AnnotationHolder + ) { + element.accept(object : PsiRecursiveElementVisitor() {}) + } + + override fun getInfos(): MutableList = highlightInfos + + override fun doApplyInformationToEditor() { + try { + val infos = annotationHolder?.map { HighlightInfo.fromAnnotation(it) } ?: return + highlightInfos.addAll(infos) + // NOTE: keep !! for 201 version + UpdateHighlightersUtil.setHighlightersToEditor(myProject, myDocument!!, 0, file.textLength, infos, colorsScheme, id) + } finally { + annotationHolder = null + } + } + +} \ No newline at end of file diff --git a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/BeforeResolveHighlightingVisitor.kt b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/BeforeResolveHighlightingVisitor.kt index b6fd735475c..e59e13c300d 100644 --- a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/BeforeResolveHighlightingVisitor.kt +++ b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/BeforeResolveHighlightingVisitor.kt @@ -38,7 +38,7 @@ internal class BeforeResolveHighlightingVisitor(holder: AnnotationHolder) : High else -> return } - createInfoAnnotation(element, null).textAttributes = attributes + createInfoAnnotation(element, textAttributes = attributes) } private fun willApplyRainbowHighlight(element: KDocLink): Boolean { @@ -53,27 +53,29 @@ internal class BeforeResolveHighlightingVisitor(holder: AnnotationHolder) : High if (ApplicationManager.getApplication().isUnitTestMode) return val functionLiteral = lambdaExpression.functionLiteral - createInfoAnnotation(functionLiteral.lBrace, null).textAttributes = KotlinHighlightingColors.FUNCTION_LITERAL_BRACES_AND_ARROW + createInfoAnnotation(functionLiteral.lBrace, textAttributes = KotlinHighlightingColors.FUNCTION_LITERAL_BRACES_AND_ARROW) val closingBrace = functionLiteral.rBrace if (closingBrace != null) { - createInfoAnnotation(closingBrace, null).textAttributes = KotlinHighlightingColors.FUNCTION_LITERAL_BRACES_AND_ARROW + createInfoAnnotation(closingBrace, textAttributes = KotlinHighlightingColors.FUNCTION_LITERAL_BRACES_AND_ARROW) } val arrow = functionLiteral.arrow if (arrow != null) { - createInfoAnnotation(arrow, null).textAttributes = KotlinHighlightingColors.FUNCTION_LITERAL_BRACES_AND_ARROW + createInfoAnnotation(arrow, textAttributes = KotlinHighlightingColors.FUNCTION_LITERAL_BRACES_AND_ARROW) } } override fun visitArgument(argument: KtValueArgument) { val argumentName = argument.getArgumentName() ?: return val eq = argument.equalsToken ?: return - createInfoAnnotation(TextRange(argumentName.startOffset, eq.endOffset), null).textAttributes = - if (argument.parent.parent is KtAnnotationEntry) + createInfoAnnotation( + TextRange(argumentName.startOffset, eq.endOffset), + textAttributes = if (argument.parent.parent is KtAnnotationEntry) KotlinHighlightingColors.ANNOTATION_ATTRIBUTE_NAME_ATTRIBUTES else KotlinHighlightingColors.NAMED_ARGUMENT + ) } override fun visitExpressionWithLabel(expression: KtExpressionWithLabel) { diff --git a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/HighlightingVisitor.kt b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/HighlightingVisitor.kt index 500140cae50..df4edf914ab 100644 --- a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/HighlightingVisitor.kt +++ b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/HighlightingVisitor.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.idea.highlighter import com.intellij.lang.annotation.Annotation import com.intellij.lang.annotation.AnnotationHolder +import com.intellij.lang.annotation.HighlightSeverity import com.intellij.openapi.editor.colors.TextAttributesKey import com.intellij.openapi.util.TextRange import com.intellij.psi.PsiElement @@ -17,29 +18,34 @@ abstract class HighlightingVisitor protected constructor( private val holder: AnnotationHolder ) : KtVisitorVoid() { - protected fun createInfoAnnotation(element: PsiElement, textAttributes: TextAttributesKey, message: String? = null) { - createInfoAnnotation(element.textRange, textAttributes, message) + protected fun createInfoAnnotation(element: PsiElement, message: String? = null, textAttributes: TextAttributesKey) { + createInfoAnnotation(element.textRange, message, textAttributes) } - protected fun createInfoAnnotation(range: TextRange, textAttributes: TextAttributesKey, message: String? = null) { - createInfoAnnotation(range, message).textAttributes = textAttributes - } - - protected fun createInfoAnnotation(element: PsiElement, message: String? = null): Annotation = + protected fun createInfoAnnotation(element: PsiElement, message: String? = null) = createInfoAnnotation(element.textRange, message) - protected fun createInfoAnnotation(textRange: TextRange, message: String? = null): Annotation = - holder.createInfoAnnotation(textRange, message) + protected open fun createInfoAnnotation(textRange: TextRange, message: String? = null, textAttributes: TextAttributesKey? = null) { + (message?.let { holder.newAnnotation(HighlightSeverity.INFORMATION, it) } + ?: holder.newSilentAnnotation(HighlightSeverity.INFORMATION)) + .range(textRange) + .also { builder -> + textAttributes?.let { + builder.textAttributes(it) + } + } + .create() + } protected fun highlightName(element: PsiElement, attributesKey: TextAttributesKey, message: String? = null) { if (NameHighlighter.namesHighlightingEnabled && !element.textRange.isEmpty) { - createInfoAnnotation(element, attributesKey, message) + createInfoAnnotation(element, message, attributesKey) } } protected fun highlightName(textRange: TextRange, attributesKey: TextAttributesKey, message: String? = null) { if (NameHighlighter.namesHighlightingEnabled) { - createInfoAnnotation(textRange, attributesKey, message) + createInfoAnnotation(textRange, message, attributesKey) } } diff --git a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/KotlinBeforeResolveHighlightingPass.kt b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/KotlinBeforeResolveHighlightingPass.kt index 597c8ea58ea..4d3e3c34af5 100644 --- a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/KotlinBeforeResolveHighlightingPass.kt +++ b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/highlighter/KotlinBeforeResolveHighlightingPass.kt @@ -6,51 +6,29 @@ package org.jetbrains.kotlin.idea.highlighter import com.intellij.codeHighlighting.* -import com.intellij.codeInsight.daemon.impl.AnnotationHolderImpl -import com.intellij.codeInsight.daemon.impl.HighlightInfo -import com.intellij.codeInsight.daemon.impl.UpdateHighlightersUtil import com.intellij.lang.annotation.AnnotationHolder -import com.intellij.lang.annotation.AnnotationSession import com.intellij.openapi.editor.Document import com.intellij.openapi.editor.Editor import com.intellij.openapi.extensions.ExtensionPointName -import com.intellij.openapi.progress.ProgressIndicator -import com.intellij.openapi.project.DumbAware import com.intellij.openapi.project.Project import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile import com.intellij.psi.PsiRecursiveElementVisitor import org.jetbrains.kotlin.psi.KtFile -class KotlinBeforeResolveHighlightingPass( - private val file: KtFile, - document: Document -) : TextEditorHighlightingPass(file.project, document), DumbAware { +class KotlinBeforeResolveHighlightingPass(file: KtFile, document: Document) : AbstractHighlightingPassBase(file, document) { - @Volatile - private var annotationHolder: AnnotationHolderImpl? = null + override fun runAnnotatorWithContext(element: PsiElement, holder: AnnotationHolder) { + val visitor = BeforeResolveHighlightingVisitor(holder) + val extensions = EP_NAME.extensionList.map { it.createVisitor(holder) } - override fun doCollectInformation(progress: ProgressIndicator) { - val annotationHolder = AnnotationHolderImpl(AnnotationSession(file)) - val visitor = BeforeResolveHighlightingVisitor(annotationHolder) - val extensions = EP_NAME.extensionList.map { it.createVisitor(annotationHolder) } - file.accept(object : PsiRecursiveElementVisitor() { + element.accept(object : PsiRecursiveElementVisitor() { override fun visitElement(element: PsiElement) { - super.visitElement(element) element.accept(visitor) extensions.forEach(element::accept) + super.visitElement(element) } }) - this.annotationHolder = annotationHolder - } - - override fun doApplyInformationToEditor() { - if (annotationHolder == null) return - - val infos = annotationHolder!!.map { HighlightInfo.fromAnnotation(it) } - - UpdateHighlightersUtil.setHighlightersToEditor(myProject, myDocument!!, 0, file.textLength, infos, colorsScheme, id) - annotationHolder = null } class Factory : TextEditorHighlightingPassFactory { @@ -64,10 +42,10 @@ class KotlinBeforeResolveHighlightingPass( override fun registerHighlightingPassFactory(registrar: TextEditorHighlightingPassRegistrar, project: Project) { registrar.registerTextEditorHighlightingPass( Factory(), - TextEditorHighlightingPassRegistrar.Anchor.BEFORE, - Pass.UPDATE_FOLDING, - false, - false + /* anchor = */ TextEditorHighlightingPassRegistrar.Anchor.BEFORE, + /* anchorPassId = */ Pass.UPDATE_FOLDING, + /* needAdditionalIntentionsPass = */ false, + /* inPostHighlightingPass = */ false ) } } diff --git a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/util/ApplicationUtils.kt b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/util/ApplicationUtils.kt index 4d23a1b3a87..7c859256a10 100644 --- a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/util/ApplicationUtils.kt +++ b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/util/ApplicationUtils.kt @@ -58,6 +58,8 @@ inline fun invokeLater(expired: Condition<*>, crossinline action: () -> Unit) = inline fun isUnitTestMode(): Boolean = ApplicationManager.getApplication().isUnitTestMode +inline fun isApplicationInternalMode(): Boolean = ApplicationManager.getApplication().isInternal + inline fun ComponentManager.getServiceSafe(): T = this.getService(T::class.java) ?: error("Unable to locate service ${T::class.java.name}") diff --git a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/PerformanceProjectsTest.kt b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/PerformanceProjectsTest.kt index e89114cbcb2..6faae1309a9 100644 --- a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/PerformanceProjectsTest.kt +++ b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/PerformanceProjectsTest.kt @@ -5,15 +5,17 @@ package org.jetbrains.kotlin.idea.perf +import com.intellij.codeHighlighting.* import com.intellij.codeInsight.daemon.impl.HighlightInfo -import com.intellij.lang.annotation.AnnotationHolder +import com.intellij.openapi.editor.Document +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.project.Project -import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile import com.intellij.testFramework.RunAll import com.intellij.util.ThrowableRunnable import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager -import org.jetbrains.kotlin.idea.highlighter.KotlinPsiChecker -import org.jetbrains.kotlin.idea.highlighter.KotlinPsiCheckerAndHighlightingUpdater +import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingPass import org.jetbrains.kotlin.idea.perf.Stats.Companion.TEST_KEY import org.jetbrains.kotlin.idea.perf.Stats.Companion.runAndMeasure import org.jetbrains.kotlin.idea.perf.util.Metric @@ -22,6 +24,7 @@ import org.jetbrains.kotlin.idea.testFramework.Fixture import org.jetbrains.kotlin.idea.testFramework.Fixture.Companion.cleanupCaches import org.jetbrains.kotlin.idea.testFramework.Fixture.Companion.isAKotlinScriptFile import org.jetbrains.kotlin.idea.testFramework.ProjectOpenAction.GRADLE_PROJECT +import org.jetbrains.kotlin.psi.KtFile import java.util.concurrent.atomic.AtomicLong import kotlin.test.assertNotEquals @@ -38,6 +41,9 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() { @JvmStatic val timer: AtomicLong = AtomicLong() + @JvmStatic + val diagnosticTimer: AtomicLong = AtomicLong() + fun resetTimestamp() { timer.set(0) } @@ -326,6 +332,7 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() { val testName = "fileAnalysis ${notePrefix(note)}${simpleFilename(fileName)}" val extraStats = Stats("${stats.name} $testName") val extraTimingsNs = mutableListOf?>() + val diagnosticTimingsNs = mutableListOf?>() val warmUpIterations = 30 val iterations = 50 @@ -337,7 +344,7 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() { iterations(iterations) setUp(perfKtsFileAnalysisSetUp(project, fileName)) test(perfKtsFileAnalysisTest()) - tearDown(perfKtsFileAnalysisTearDown(extraTimingsNs, project)) + tearDown(perfKtsFileAnalysisTearDown(extraTimingsNs, diagnosticTimingsNs, project)) profilerConfig.enabled = true } @@ -349,19 +356,31 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() { metricChildren ) + extraStats.printWarmUpTimings( + "diagnostic", + diagnosticTimingsNs.take(warmUpIterations).toTypedArray(), + metricChildren + ) + extraStats.processTimings( "annotator", extraTimingsNs.drop(warmUpIterations).toTypedArray(), metricChildren ) + + extraStats.processTimings( + "diagnostic", + diagnosticTimingsNs.drop(warmUpIterations).toTypedArray(), + metricChildren + ) } } private fun replaceWithCustomHighlighter() { org.jetbrains.kotlin.idea.testFramework.replaceWithCustomHighlighter( testRootDisposable, - KotlinPsiCheckerAndHighlightingUpdater::class.java.name, - TestKotlinPsiChecker::class.java.name + KotlinHighlightingPass.Registrar::class.java.name, + TestKotlinHighlightingPass.Registrar::class.java.name ) } @@ -385,18 +404,22 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() { fun perfKtsFileAnalysisTest(): (TestData>>) -> Unit { return { it.value = it.setUpValue?.let { fixture -> - Pair(System.nanoTime(), fixture.doHighlighting()) + val nowNs = System.nanoTime() + diagnosticTimer.set(-nowNs) + Pair(nowNs, fixture.doHighlighting()) } } } fun perfKtsFileAnalysisTearDown( extraTimingsNs: MutableList?>, + diagnosticTimingsMs: MutableList?>, project: Project ): (TestData>>) -> Unit { return { it.setUpValue?.let { fixture -> it.value?.let { v -> + diagnosticTimingsMs.add(mapOf(TEST_KEY to diagnosticTimer.getAndSet(0))) assertTrue(v.second.isNotEmpty()) assertNotEquals(0, timer.get()) @@ -411,12 +434,38 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() { } - class TestKotlinPsiChecker : KotlinPsiChecker() { - override fun annotate( - element: PsiElement, holder: AnnotationHolder - ) { - super.annotate(element, holder) - markTimestamp() + class TestKotlinHighlightingPass(file: KtFile, document: Document) : KotlinHighlightingPass(file, document) { + override fun doCollectInformation(progress: ProgressIndicator) { + annotationCallback { + val nowNs = System.nanoTime() + diagnosticTimer.addAndGet(nowNs) + resetAnnotationCallback() + } + try { + super.doCollectInformation(progress) + } finally { + resetAnnotationCallback() + markTimestamp() + } + } + + class Factory : TextEditorHighlightingPassFactory { + override fun createHighlightingPass(file: PsiFile, editor: Editor): TextEditorHighlightingPass? { + if (file !is KtFile) return null + return TestKotlinHighlightingPass(file, editor.document) + } + } + + class Registrar : TextEditorHighlightingPassFactoryRegistrar { + override fun registerHighlightingPassFactory(registrar: TextEditorHighlightingPassRegistrar, project: Project) { + registrar.registerTextEditorHighlightingPass( + Factory(), + null, + intArrayOf(Pass.UPDATE_ALL), + false, + -1 + ) + } } } } \ No newline at end of file diff --git a/idea/resources-descriptors/META-INF/plugin.xml b/idea/resources-descriptors/META-INF/plugin.xml index 981f882d453..8f7e0dbe79c 100644 --- a/idea/resources-descriptors/META-INF/plugin.xml +++ b/idea/resources-descriptors/META-INF/plugin.xml @@ -123,6 +123,9 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. + + + diff --git a/idea/resources-descriptors/META-INF/plugin.xml.201 b/idea/resources-descriptors/META-INF/plugin.xml.201 index 8f5c88df3b5..47bfa2fd0ef 100644 --- a/idea/resources-descriptors/META-INF/plugin.xml.201 +++ b/idea/resources-descriptors/META-INF/plugin.xml.201 @@ -123,6 +123,9 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. + + + diff --git a/idea/resources-descriptors/META-INF/plugin.xml.as41 b/idea/resources-descriptors/META-INF/plugin.xml.as41 index a70a1c3b054..285aa3ca3f6 100644 --- a/idea/resources-descriptors/META-INF/plugin.xml.as41 +++ b/idea/resources-descriptors/META-INF/plugin.xml.as41 @@ -122,6 +122,9 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. + + + diff --git a/idea/resources-descriptors/META-INF/plugin.xml.as42 b/idea/resources-descriptors/META-INF/plugin.xml.as42 index 1a2237b7f41..a7cce72296f 100644 --- a/idea/resources-descriptors/META-INF/plugin.xml.as42 +++ b/idea/resources-descriptors/META-INF/plugin.xml.as42 @@ -103,6 +103,9 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. + + + diff --git a/idea/resources/META-INF/plugin-common.xml b/idea/resources/META-INF/plugin-common.xml index e802ce65eb8..89ffc2af605 100644 --- a/idea/resources/META-INF/plugin-common.xml +++ b/idea/resources/META-INF/plugin-common.xml @@ -491,13 +491,8 @@ - - - - - diff --git a/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightingPass.kt b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightingPass.kt new file mode 100644 index 00000000000..30920e08a2e --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightingPass.kt @@ -0,0 +1,45 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.highlighter + +import com.intellij.codeHighlighting.* +import com.intellij.openapi.editor.Document +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiFile +import org.jetbrains.kotlin.idea.inspections.UnusedSymbolInspection +import org.jetbrains.kotlin.idea.isMainFunction +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtNamedFunction +import org.jetbrains.kotlin.psi.KtParameter + +open class KotlinHighlightingPass(file: KtFile, document: Document) : AbstractKotlinHighlightingPass(file, document) { + + override fun shouldSuppressUnusedParameter(parameter: KtParameter): Boolean { + val grandParent = parameter.parent.parent as? KtNamedFunction ?: return false + if (!UnusedSymbolInspection.isEntryPoint(grandParent)) return false + return !grandParent.isMainFunction() + } + + class Factory : TextEditorHighlightingPassFactory { + override fun createHighlightingPass(file: PsiFile, editor: Editor): TextEditorHighlightingPass? { + if (file !is KtFile) return null + return KotlinHighlightingPass(file, editor.document) + } + } + + class Registrar : TextEditorHighlightingPassFactoryRegistrar { + override fun registerHighlightingPassFactory(registrar: TextEditorHighlightingPassRegistrar, project: Project) { + registrar.registerTextEditorHighlightingPass( + Factory(), + /* runAfterCompletionOf = */ null, + /* runAfterStartingOf = */ intArrayOf(Pass.UPDATE_ALL), + /* runIntentionsPassAfter = */false, + /* forcedPassId = */-1 + ) + } + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinPsiCheckerAndHighlightingUpdater.kt b/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinPsiCheckerAndHighlightingUpdater.kt deleted file mode 100644 index 9a01b9dec6d..00000000000 --- a/idea/src/org/jetbrains/kotlin/idea/highlighter/KotlinPsiCheckerAndHighlightingUpdater.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2010-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.kotlin.idea.highlighter - -import org.jetbrains.kotlin.idea.inspections.UnusedSymbolInspection -import org.jetbrains.kotlin.idea.isMainFunction -import org.jetbrains.kotlin.psi.KtNamedFunction -import org.jetbrains.kotlin.psi.KtParameter - -class KotlinPsiCheckerAndHighlightingUpdater : KotlinPsiChecker() { - override fun shouldSuppressUnusedParameter(parameter: KtParameter): Boolean { - val grandParent = parameter.parent.parent as? KtNamedFunction ?: return false - if (!UnusedSymbolInspection.isEntryPoint(grandParent)) return false - return !grandParent.isMainFunction() - } -} diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/KotlinCleanupInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/KotlinCleanupInspection.kt index 60cb787374c..31388e0274b 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/KotlinCleanupInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/KotlinCleanupInspection.kt @@ -17,7 +17,7 @@ import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages import org.jetbrains.kotlin.idea.KotlinBundle import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithAllCompilerChecks -import org.jetbrains.kotlin.idea.highlighter.KotlinPsiChecker +import org.jetbrains.kotlin.idea.highlighter.AbstractKotlinHighlightingPass import org.jetbrains.kotlin.idea.quickfix.CleanupFix import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction import org.jetbrains.kotlin.idea.quickfix.ReplaceObsoleteLabelSyntaxFix @@ -99,7 +99,7 @@ class KotlinCleanupInspection : LocalInspectionTool(), CleanupLocalInspectionToo } private fun Diagnostic.toCleanupFixes(): Collection { - return KotlinPsiChecker.createQuickFixes(this).filterIsInstance() + return AbstractKotlinHighlightingPass.createQuickFixes(this).filterIsInstance() } private class Wrapper(val intention: IntentionAction, file: KtFile) : IntentionWrapper(intention, file) { diff --git a/idea/testData/checker/AnnotationSupressing.kt b/idea/testData/checker/AnnotationSupressing.kt new file mode 100644 index 00000000000..7fe305fc5b1 --- /dev/null +++ b/idea/testData/checker/AnnotationSupressing.kt @@ -0,0 +1,32 @@ +annotation class A(val i: Int) +annotation class Z(val i: Int) + +@Z("BAD") @Suppress("TYPE_MISMATCH") +fun some0() {} + +@Z("BAD") @Z("BAD") @Suppress("TYPE_MISMATCH") +fun some01() {} + +@Suppress("TYPE_MISMATCH") @Z("BAD") +fun some1() { +} + +@Suppress("TYPE_MISMATCH") @Z("BAD") @Z("BAD") +fun some11() { +} + +@A("BAD") @Suppress("TYPE_MISMATCH") +fun some2() { +} + +@Suppress("TYPE_MISMATCH") @A("BAD") +fun some3() { +} + +@A("BAD") @A("BAD") +fun some4() { +} + +@Z("BAD") +fun someN() { +} diff --git a/idea/tests/org/jetbrains/kotlin/checkers/AbstractPsiCheckerTest.java b/idea/tests/org/jetbrains/kotlin/checkers/AbstractKotlinHighlightingPassTest.java similarity index 97% rename from idea/tests/org/jetbrains/kotlin/checkers/AbstractPsiCheckerTest.java rename to idea/tests/org/jetbrains/kotlin/checkers/AbstractKotlinHighlightingPassTest.java index 98a416691c4..db8320d1f16 100644 --- a/idea/tests/org/jetbrains/kotlin/checkers/AbstractPsiCheckerTest.java +++ b/idea/tests/org/jetbrains/kotlin/checkers/AbstractKotlinHighlightingPassTest.java @@ -25,7 +25,7 @@ import java.io.File; import static org.jetbrains.kotlin.resolve.lazy.ResolveSession.areDescriptorsCreatedForDeclaration; -public abstract class AbstractPsiCheckerTest extends KotlinLightCodeInsightFixtureTestCase { +public abstract class AbstractKotlinHighlightingPassTest extends KotlinLightCodeInsightFixtureTestCase { public void doTest(@NotNull VirtualFile file) throws Exception { myFixture.configureFromExistingVirtualFile(file); checkHighlighting(true, false, false); diff --git a/idea/tests/org/jetbrains/kotlin/checkers/PsiCheckerCustomTest.kt b/idea/tests/org/jetbrains/kotlin/checkers/KotlinHighlightingPassCustomTest.kt similarity index 94% rename from idea/tests/org/jetbrains/kotlin/checkers/PsiCheckerCustomTest.kt rename to idea/tests/org/jetbrains/kotlin/checkers/KotlinHighlightingPassCustomTest.kt index 457a1a7e436..406d3eef8a2 100644 --- a/idea/tests/org/jetbrains/kotlin/checkers/PsiCheckerCustomTest.kt +++ b/idea/tests/org/jetbrains/kotlin/checkers/KotlinHighlightingPassCustomTest.kt @@ -13,7 +13,7 @@ import org.junit.runner.RunWith @TestMetadata("idea/testData/checker/custom") @RunWith(JUnit3WithIdeaConfigurationRunner::class) -class PsiCheckerCustomTest : AbstractPsiCheckerTest() { +class KotlinHighlightingPassCustomTest : AbstractKotlinHighlightingPassTest() { @TestMetadata("noUnusedParameterWhenCustom.kt") fun testNoUnusedParameterWhenCustom() { diff --git a/idea/tests/org/jetbrains/kotlin/checkers/PsiCheckerSealedTest.kt b/idea/tests/org/jetbrains/kotlin/checkers/KotlinHighlightingPassSealedTest.kt similarity index 92% rename from idea/tests/org/jetbrains/kotlin/checkers/PsiCheckerSealedTest.kt rename to idea/tests/org/jetbrains/kotlin/checkers/KotlinHighlightingPassSealedTest.kt index 594fda3e8a1..e4e1c1474ba 100644 --- a/idea/tests/org/jetbrains/kotlin/checkers/PsiCheckerSealedTest.kt +++ b/idea/tests/org/jetbrains/kotlin/checkers/KotlinHighlightingPassSealedTest.kt @@ -12,7 +12,7 @@ import org.junit.runner.RunWith @TestMetadata("idea/testData/checker/sealed") @RunWith(JUnit3WithIdeaConfigurationRunner::class) -class PsiCheckerSealedTest : AbstractPsiCheckerTest() { +class KotlinHighlightingPassSealedTest : AbstractKotlinHighlightingPassTest() { fun testOutsideOfPackageInheritors() { doTest( diff --git a/idea/tests/org/jetbrains/kotlin/checkers/PsiCheckerTestGenerated.java b/idea/tests/org/jetbrains/kotlin/checkers/KotlinHighlightingPassTestGenerated.java similarity index 97% rename from idea/tests/org/jetbrains/kotlin/checkers/PsiCheckerTestGenerated.java rename to idea/tests/org/jetbrains/kotlin/checkers/KotlinHighlightingPassTestGenerated.java index e8a89d8269f..94c1d65a404 100644 --- a/idea/tests/org/jetbrains/kotlin/checkers/PsiCheckerTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/checkers/KotlinHighlightingPassTestGenerated.java @@ -18,11 +18,11 @@ import java.util.regex.Pattern; /** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ @SuppressWarnings("all") @RunWith(JUnit3RunnerWithInners.class) -public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest { +public class KotlinHighlightingPassTestGenerated extends AbstractKotlinHighlightingPassTest { @TestMetadata("idea/testData/checker") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class Checker extends AbstractPsiCheckerTest { + public static class Checker extends AbstractKotlinHighlightingPassTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } @@ -41,6 +41,11 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest { runTest("idea/testData/checker/AnnotationOnFile.kt"); } + @TestMetadata("AnnotationSupressing.kt") + public void testAnnotationSupressing() throws Exception { + runTest("idea/testData/checker/AnnotationSupressing.kt"); + } + @TestMetadata("AnonymousInitializers.kt") public void testAnonymousInitializers() throws Exception { runTest("idea/testData/checker/AnonymousInitializers.kt"); @@ -365,7 +370,7 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest { @TestMetadata("idea/testData/checker/regression") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class Regression extends AbstractPsiCheckerTest { + public static class Regression extends AbstractKotlinHighlightingPassTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } @@ -608,7 +613,7 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest { @TestMetadata("idea/testData/checker/recovery") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class Recovery extends AbstractPsiCheckerTest { + public static class Recovery extends AbstractKotlinHighlightingPassTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } @@ -636,7 +641,7 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest { @TestMetadata("idea/testData/checker/rendering") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class Rendering extends AbstractPsiCheckerTest { + public static class Rendering extends AbstractKotlinHighlightingPassTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } @@ -654,7 +659,7 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest { @TestMetadata("idea/testData/checker/scripts") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class Scripts extends AbstractPsiCheckerTest { + public static class Scripts extends AbstractKotlinHighlightingPassTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } @@ -687,7 +692,7 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest { @TestMetadata("idea/testData/checker/duplicateJvmSignature") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class DuplicateJvmSignature extends AbstractPsiCheckerTest { + public static class DuplicateJvmSignature extends AbstractKotlinHighlightingPassTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } @@ -699,7 +704,7 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest { @TestMetadata("idea/testData/checker/duplicateJvmSignature/fields") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class Fields extends AbstractPsiCheckerTest { + public static class Fields extends AbstractKotlinHighlightingPassTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } @@ -717,7 +722,7 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest { @TestMetadata("idea/testData/checker/duplicateJvmSignature/functionAndProperty") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class FunctionAndProperty extends AbstractPsiCheckerTest { + public static class FunctionAndProperty extends AbstractKotlinHighlightingPassTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } @@ -780,7 +785,7 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest { @TestMetadata("idea/testData/checker/duplicateJvmSignature/traitImpl") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class TraitImpl extends AbstractPsiCheckerTest { + public static class TraitImpl extends AbstractKotlinHighlightingPassTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } @@ -799,7 +804,7 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest { @TestMetadata("idea/testData/checker/infos") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class Infos extends AbstractPsiCheckerTest { + public static class Infos extends AbstractKotlinHighlightingPassTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTestWithInfos, this, testDataFilePath); } @@ -892,7 +897,7 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest { @TestMetadata("idea/testData/checker/diagnosticsMessage") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) - public static class DiagnosticsMessage extends AbstractPsiCheckerTest { + public static class DiagnosticsMessage extends AbstractKotlinHighlightingPassTest { private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); } diff --git a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/AbstractCodeFragmentAutoImportTest.kt b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/AbstractCodeFragmentAutoImportTest.kt index 7721f7cbd9f..a45c2615e46 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/AbstractCodeFragmentAutoImportTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/AbstractCodeFragmentAutoImportTest.kt @@ -5,12 +5,12 @@ package org.jetbrains.kotlin.idea.debugger.evaluate -import org.jetbrains.kotlin.checkers.AbstractPsiCheckerTest +import org.jetbrains.kotlin.checkers.AbstractKotlinHighlightingPassTest import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor import org.jetbrains.kotlin.psi.KtCodeFragment import kotlin.test.assertNull -abstract class AbstractCodeFragmentAutoImportTest : AbstractPsiCheckerTest() { +abstract class AbstractCodeFragmentAutoImportTest : AbstractKotlinHighlightingPassTest() { override fun doTest(filePath: String) { myFixture.configureByCodeFragment(filePath) myFixture.doHighlighting() diff --git a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/AbstractCodeFragmentHighlightingTest.kt b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/AbstractCodeFragmentHighlightingTest.kt index ba2ab37af90..415632d0415 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/AbstractCodeFragmentHighlightingTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/AbstractCodeFragmentHighlightingTest.kt @@ -7,7 +7,7 @@ package org.jetbrains.kotlin.idea.debugger.evaluate import com.intellij.codeInspection.InspectionProfileEntry import com.intellij.openapi.util.io.FileUtil -import org.jetbrains.kotlin.checkers.AbstractPsiCheckerTest +import org.jetbrains.kotlin.checkers.AbstractKotlinHighlightingPassTest import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference import org.jetbrains.kotlin.idea.util.ImportInsertHelper import org.jetbrains.kotlin.idea.util.application.executeWriteCommand @@ -16,7 +16,7 @@ import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.test.InTextDirectivesUtils import java.io.File -abstract class AbstractCodeFragmentHighlightingTest : AbstractPsiCheckerTest() { +abstract class AbstractCodeFragmentHighlightingTest : AbstractKotlinHighlightingPassTest() { override fun doTest(filePath: String) { myFixture.configureByCodeFragment(filePath) checkHighlighting(filePath) diff --git a/idea/tests/org/jetbrains/kotlin/idea/highlighter/AbstractDslHighlighterTest.kt b/idea/tests/org/jetbrains/kotlin/idea/highlighter/AbstractDslHighlighterTest.kt index 1b3af009ab6..0487de53f2d 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/highlighter/AbstractDslHighlighterTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/highlighter/AbstractDslHighlighterTest.kt @@ -34,10 +34,12 @@ abstract class AbstractDslHighlighterTest : KotlinLightCodeInsightFixtureTestCas val styleIdByCall = extension.highlightCall(element, call)?.externalName if (styleIdByCall != null && styleIdByCall == styleIdByComment) { val annotationHolder = AnnotationHolderImpl(AnnotationSession(psiFile)) - val checkers = KotlinPsiChecker.getAfterAnalysisVisitor(annotationHolder, bindingContext) - checkers.forEach { call.call.callElement.accept(it) } + annotationHolder.runAnnotatorWithContext(file) { _, _ -> + val checkers = AbstractKotlinHighlightingPass.getAfterAnalysisVisitor(annotationHolder, bindingContext) + checkers.forEach { call.call.callElement.accept(it) } + } assertTrue( - "KotlinPsiChecker did not contribute an Annotation containing the correct text attribute key at line ${lineNumber + 1}", + "KotlinHighlightingPass did not contribute an Annotation containing the correct text attribute key at line ${lineNumber + 1}", annotationHolder.any { it.textAttributes.externalName == styleIdByComment } diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/AbstractLocalInspectionTest.kt b/idea/tests/org/jetbrains/kotlin/idea/inspections/AbstractLocalInspectionTest.kt index ab1d14fd2c7..72eab58ba76 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/AbstractLocalInspectionTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/AbstractLocalInspectionTest.kt @@ -8,7 +8,9 @@ package org.jetbrains.kotlin.idea.inspections import com.google.common.collect.Lists import com.intellij.codeHighlighting.HighlightDisplayLevel import com.intellij.codeHighlighting.Pass +import com.intellij.codeHighlighting.TextEditorHighlightingPass import com.intellij.codeInsight.daemon.impl.HighlightInfoType +import com.intellij.codeInsight.daemon.impl.TextEditorHighlightingPassRegistrarEx import com.intellij.codeInsight.intention.EmptyIntentionAction import com.intellij.codeInspection.ProblemHighlightType import com.intellij.openapi.util.SystemInfo @@ -19,6 +21,7 @@ import junit.framework.ComparisonFailure import junit.framework.TestCase import org.jdom.Element import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager +import org.jetbrains.kotlin.idea.highlighter.AbstractHighlightingPassBase import org.jetbrains.kotlin.idea.test.DirectiveBasedActionUtils import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase import org.jetbrains.kotlin.idea.test.withCustomCompilerOptions @@ -29,6 +32,7 @@ import org.jetbrains.kotlin.test.KotlinTestUtils import org.junit.Assert import java.io.File + abstract class AbstractLocalInspectionTest : KotlinLightCodeInsightFixtureTestCase() { private val inspectionFileName: String get() = ".inspection" @@ -145,16 +149,23 @@ abstract class AbstractLocalInspectionTest : KotlinLightCodeInsightFixtureTestCa state.tool.tool.readSettings(inspectionSettings) } + val passIdsToIgnore = mutableListOf( + Pass.LINE_MARKERS, + Pass.EXTERNAL_TOOLS, + Pass.POPUP_HINTS, + Pass.UPDATE_ALL, + Pass.UPDATE_FOLDING, + Pass.WOLF + ) + val passRegistrar = TextEditorHighlightingPassRegistrarEx.getInstanceEx(myFixture.project) + // to exclude AbstractHighlightingPassBase instances based on their ids + passRegistrar.instantiatePasses( + file, editor, passIdsToIgnore.toIntArray() + ).filterIsInstance().map(TextEditorHighlightingPass::getId).forEach(passIdsToIgnore::add) + val caretOffset = myFixture.caretOffset val highlightInfos = CodeInsightTestFixtureImpl.instantiateAndRun( - file, editor, intArrayOf( - Pass.LINE_MARKERS, - Pass.EXTERNAL_TOOLS, - Pass.POPUP_HINTS, - Pass.UPDATE_ALL, - Pass.UPDATE_FOLDING, - Pass.WOLF - ), (file as? KtFile)?.isScript() == true + file, editor, passIdsToIgnore.toIntArray(), (file as? KtFile)?.isScript() == true ).filter { it.description != null && caretOffset in it.startOffset..it.endOffset } Assert.assertTrue( diff --git a/plugins/parcelize/parcelize-ide/tests/org/jetbrains/kotlin/pacelize/ide/test/AbstractParcelizeCheckerTest.kt b/plugins/parcelize/parcelize-ide/tests/org/jetbrains/kotlin/pacelize/ide/test/AbstractParcelizeCheckerTest.kt index d88f705b2ed..cc5cca8bcf3 100644 --- a/plugins/parcelize/parcelize-ide/tests/org/jetbrains/kotlin/pacelize/ide/test/AbstractParcelizeCheckerTest.kt +++ b/plugins/parcelize/parcelize-ide/tests/org/jetbrains/kotlin/pacelize/ide/test/AbstractParcelizeCheckerTest.kt @@ -5,11 +5,9 @@ package org.jetbrains.kotlin.pacelize.ide.test -import org.jetbrains.kotlin.checkers.AbstractPsiCheckerTest -import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil -import org.jetbrains.kotlin.test.KotlinTestUtils +import org.jetbrains.kotlin.checkers.AbstractKotlinHighlightingPassTest -abstract class AbstractParcelizeCheckerTest : AbstractPsiCheckerTest() { +abstract class AbstractParcelizeCheckerTest : AbstractKotlinHighlightingPassTest() { override fun setUp() { super.setUp() addParcelizeLibraries(module) diff --git a/tests/mute-common.csv b/tests/mute-common.csv index fa22ea62e40..edb53357168 100644 --- a/tests/mute-common.csv +++ b/tests/mute-common.csv @@ -79,7 +79,7 @@ org.jetbrains.kotlin.idea.caches.resolve.IdeLightClassTestGenerated.Facades.test org.jetbrains.kotlin.idea.caches.resolve.IdeLightClassTestGenerated.CompilationErrors.testActualTypeAliasCustomJvmPackageName, Invalid behavior of old lightclasses in common tests,, org.jetbrains.kotlin.idea.caches.resolve.IdeLightClassTestGenerated.CompilationErrors.testJvmPackageName, Invalid behavior of old lightclasses in common tests,, org.jetbrains.uast.test.kotlin.SimpleKotlinRenderLogTest.testReceiverFun, Analysing of facade annotation with receiver site is broken (connected with KT-40403),, -org.jetbrains.kotlin.checkers.FirPsiCheckerTestGenerated.Regression.testJet53,,, FLAKY +org.jetbrains.kotlin.checkers.FirKotlinHighlightingPassTestGenerated.Regression.testJet53,,, FLAKY org.jetbrains.kotlin.idea.caches.resolve.MultiModuleHighlightingTest.testLanguageVersionsViaFacets,,, FLAKY org.jetbrains.kotlin.jps.build.IncrementalJvmJpsTestGenerated.Jvm.testCircular, Temporary muted due to problems with IC and JVM IR backend,, org.jetbrains.kotlin.jps.build.IncrementalJvmJpsTestGenerated.Jvm.testCircularDependencyClasses, Temporary muted due to problems with IC and JVM IR backend,, From a16aaa382404acea10352d8a23c1eff64f890f96 Mon Sep 17 00:00:00 2001 From: Ilya Gorbunov Date: Mon, 25 Jan 2021 18:40:16 +0300 Subject: [PATCH 011/260] Setup publications with MPP Gradle metadata for kotlin-test library Move publication configuration from individual platform specific kotlin-test- modules to the root module. KT-40225 --- build.gradle.kts | 6 +- buildSrc/src/main/kotlin/tasks.kt | 21 +- .../annotations-common/build.gradle | 2 - libraries/kotlin.test/build.gradle.kts | 289 ++++++++++++++++++ libraries/kotlin.test/common/build.gradle | 2 - libraries/kotlin.test/js/build.gradle | 3 - libraries/kotlin.test/junit/build.gradle | 1 - libraries/kotlin.test/junit5/build.gradle | 1 - libraries/kotlin.test/jvm/build.gradle | 3 - libraries/kotlin.test/testng/build.gradle | 1 - 10 files changed, 297 insertions(+), 32 deletions(-) create mode 100644 libraries/kotlin.test/build.gradle.kts diff --git a/build.gradle.kts b/build.gradle.kts index 97fcae0b3ad..18c97181f22 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -345,6 +345,7 @@ val coreLibProjects = listOfNotNull( ":kotlin-stdlib-js", ":kotlin-stdlib-jdk7", ":kotlin-stdlib-jdk8", + ":kotlin-test", ":kotlin-test:kotlin-test-annotations-common", ":kotlin-test:kotlin-test-common", ":kotlin-test:kotlin-test-jvm", @@ -637,7 +638,10 @@ tasks { listOf("clean", "assemble", "install").forEach { taskName -> register("coreLibs${taskName.capitalize()}") { - coreLibProjects.forEach { projectName -> dependsOn("$projectName:$taskName") } + for (projectName in coreLibProjects) { + if (projectName.startsWith(":kotlin-test:") && taskName == "install") continue + dependsOn("$projectName:$taskName") + } } } diff --git a/buildSrc/src/main/kotlin/tasks.kt b/buildSrc/src/main/kotlin/tasks.kt index efce0a21d66..58b37c62099 100644 --- a/buildSrc/src/main/kotlin/tasks.kt +++ b/buildSrc/src/main/kotlin/tasks.kt @@ -1,17 +1,6 @@ /* - * Copyright 2010-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -51,11 +40,7 @@ fun Task.dependsOnKotlinPluginInstall() { ":kotlin-gradle-plugin-model:install", ":kotlin-reflect:install", ":kotlin-annotation-processing-gradle:install", - ":kotlin-test:kotlin-test-common:install", - ":kotlin-test:kotlin-test-annotations-common:install", - ":kotlin-test:kotlin-test-jvm:install", - ":kotlin-test:kotlin-test-js:install", - ":kotlin-test:kotlin-test-junit:install", + ":kotlin-test:install", ":kotlin-gradle-subplugin-example:install", ":kotlin-stdlib-common:install", ":kotlin-stdlib:install", diff --git a/libraries/kotlin.test/annotations-common/build.gradle b/libraries/kotlin.test/annotations-common/build.gradle index 45231065ace..56e1dd87ed6 100644 --- a/libraries/kotlin.test/annotations-common/build.gradle +++ b/libraries/kotlin.test/annotations-common/build.gradle @@ -2,8 +2,6 @@ description = 'Kotlin Test Annotations Common' apply plugin: 'kotlin-platform-common' -configurePublishing(project) - jvmTarget = "1.6" dependencies { diff --git a/libraries/kotlin.test/build.gradle.kts b/libraries/kotlin.test/build.gradle.kts new file mode 100644 index 00000000000..253f916d798 --- /dev/null +++ b/libraries/kotlin.test/build.gradle.kts @@ -0,0 +1,289 @@ +import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType + +plugins { + `kotlin-multiplatform` apply false + base + `maven-publish` +} + +open class ComponentsFactoryAccess +@javax.inject.Inject +constructor(val factory: SoftwareComponentFactory) + +val componentFactory = objects.newInstance().factory + + +val jvmApi by configurations.creating { + isCanBeConsumed = true + isCanBeResolved = false + attributes { + attribute(Usage.USAGE_ATTRIBUTE, objects.named("java-api")) + attribute(KotlinPlatformType.attribute, KotlinPlatformType.jvm) + } +} + +val jvmRuntime by configurations.creating { + isCanBeConsumed = true + isCanBeResolved = false + attributes { + attribute(Usage.USAGE_ATTRIBUTE, objects.named("java-runtime")) + attribute(KotlinPlatformType.attribute, KotlinPlatformType.jvm) + } + extendsFrom(jvmApi) +} + +val jsApiVariant by configurations.creating { + isCanBeConsumed = true + isCanBeResolved = false + attributes { + attribute(Usage.USAGE_ATTRIBUTE, objects.named("kotlin-api")) + attribute(KotlinPlatformType.attribute, KotlinPlatformType.js) + } +} +val jsRuntimeVariant by configurations.creating { + isCanBeConsumed = true + isCanBeResolved = false + attributes { + attribute(Usage.USAGE_ATTRIBUTE, objects.named("kotlin-runtime")) + attribute(KotlinPlatformType.attribute, KotlinPlatformType.js) + } + extendsFrom(jsApiVariant) +} + +val nativeApiVariant by configurations.creating { + isCanBeConsumed = true + isCanBeResolved = false + attributes { + attribute(Usage.USAGE_ATTRIBUTE, objects.named("kotlin-api")) + attribute(KotlinPlatformType.attribute, KotlinPlatformType.native) + } +} + +val commonVariant by configurations.creating { + isCanBeConsumed = true + isCanBeResolved = false + attributes { + attribute(Usage.USAGE_ATTRIBUTE, objects.named("kotlin-api")) + attribute(KotlinPlatformType.attribute, KotlinPlatformType.common) + } +} + +dependencies { + jvmApi(project(":kotlin-stdlib")) + jsApiVariant("$group:kotlin-test-js:$version") + commonVariant("$group:kotlin-test-common:$version") + commonVariant("$group:kotlin-test-annotations-common:$version") +} + +artifacts { + val jvmJar = tasks.getByPath(":kotlin-test:kotlin-test-jvm:jar") + add(jvmApi.name, jvmJar) + add(jvmRuntime.name, jvmJar) +} + +val kotlinTestCommonSourcesJar = tasks.getByPath(":kotlin-test:kotlin-test-common:sourcesJar") as Jar +val kotlinTestJvmSourcesJar = tasks.getByPath(":kotlin-test:kotlin-test-jvm:sourcesJar") as Jar + +val combinedSourcesJar by tasks.registering(Jar::class) { + dependsOn(kotlinTestCommonSourcesJar, kotlinTestJvmSourcesJar) + archiveClassifier.set("sources") + into("common") { + from(zipTree(kotlinTestCommonSourcesJar.archiveFile)) { + exclude("META-INF/**") + } + } + into("jvm") { + from(zipTree(kotlinTestJvmSourcesJar.archiveFile)) { + exclude("META-INF/**") + } + } +} + + +val rootComponent = componentFactory.adhoc("root").apply { + addVariantsFromConfiguration(jvmApi) { + mapToMavenScope("compile") + } + addVariantsFromConfiguration(jvmRuntime) { + mapToMavenScope("runtime") + } + addVariantsFromConfiguration(jsApiVariant) { mapToOptional() } + addVariantsFromConfiguration(jsRuntimeVariant) { mapToOptional() } + addVariantsFromConfiguration(nativeApiVariant) { mapToOptional() } + addVariantsFromConfiguration(commonVariant) { mapToOptional() } +} + + +val baseCapability = "$group:kotlin-test-framework:$version" +val implCapability = "$group:kotlin-test-framework-impl:$version" + +val jvmTestFrameworks = listOf("junit", "junit5", "testng") + +jvmTestFrameworks.forEach { framework -> + val (apiVariant, runtimeVariant) = listOf("api", "runtime").map { usage -> + configurations.create("${framework}${usage.capitalize()}Variant") { + isCanBeConsumed = true + isCanBeResolved = false + attributes { + attribute(Usage.USAGE_ATTRIBUTE, objects.named("java-$usage")) + attribute(KotlinPlatformType.attribute, KotlinPlatformType.jvm) + } + outgoing.capability(baseCapability) // C0 + outgoing.capability("$group:kotlin-test-framework-$framework:$version") // C0 + } + } + runtimeVariant.extendsFrom(apiVariant) + dependencies { + apiVariant("$group:kotlin-test-$framework:$version") + } + rootComponent.addVariantsFromConfiguration(apiVariant) { mapToOptional() } + rootComponent.addVariantsFromConfiguration(runtimeVariant) { mapToOptional() } + + val (apiElements, runtimeElements) = listOf("api", "runtime").map { usage -> + configurations.create("${framework}${usage.capitalize()}") { + isCanBeConsumed = true + isCanBeResolved = false + attributes { + attribute(Usage.USAGE_ATTRIBUTE, objects.named("java-$usage")) + } + outgoing.capability(implCapability) // CC + outgoing.capability("$group:kotlin-test-$framework:$version") // CC + } + } + runtimeElements.extendsFrom(apiElements) + dependencies { + apiElements("$group:kotlin-test:$version") + when(framework) { + "junit" -> { + apiElements("junit:junit:4.12") + } + "junit5" -> { + apiElements("org.junit.jupiter:junit-jupiter-api:5.0.0") + } + "testng" -> { + apiElements("org.testng:testng:6.13.1") + } + } + } + + artifacts { + val jar = tasks.getByPath(":kotlin-test:kotlin-test-$framework:jar") + add(apiElements.name, jar) + add(runtimeElements.name, jar) + } + + componentFactory.adhoc(framework).apply { + addVariantsFromConfiguration(apiElements) { + mapToMavenScope("compile") + } + addVariantsFromConfiguration(runtimeElements) { + mapToMavenScope("runtime") + } + }.let { components.add(it) } +} + +val (jsApi, jsRuntime) = listOf("api", "runtime").map { usage -> + configurations.create("js${usage.capitalize()}") { + isCanBeConsumed = true + isCanBeResolved = false + attributes { + attribute(Usage.USAGE_ATTRIBUTE, objects.named("kotlin-$usage")) + attribute(KotlinPlatformType.attribute, KotlinPlatformType.js) + } + } +} +jsRuntime.extendsFrom(jsApi) + +dependencies { + jsApi(project(":kotlin-stdlib-js")) +} + +artifacts { + val jsJar = tasks.getByPath(":kotlin-test:kotlin-test-js:libraryJarWithIr") + add(jsApi.name, jsJar) + add(jsRuntime.name, jsJar) +} + +val jsComponent = componentFactory.adhoc("js").apply { + addVariantsFromConfiguration(jsApi) { + mapToMavenScope("compile") + } + addVariantsFromConfiguration(jsRuntime) { + mapToMavenScope("runtime") + } +} + +val commonMetadata by configurations.creating { + isCanBeConsumed = true + isCanBeResolved = false + attributes { + attribute(Usage.USAGE_ATTRIBUTE, objects.named("kotlin-api")) + attribute(KotlinPlatformType.attribute, KotlinPlatformType.common) + } +} +val annotationsMetadata by configurations.creating { + isCanBeConsumed = true + isCanBeResolved = false + attributes { + attribute(Usage.USAGE_ATTRIBUTE, objects.named("kotlin-api")) + attribute(KotlinPlatformType.attribute, KotlinPlatformType.common) + } +} +dependencies { + commonMetadata(project(":kotlin-stdlib-common")) + annotationsMetadata(project(":kotlin-stdlib-common")) +} +artifacts { + add(commonMetadata.name, tasks.getByPath(":kotlin-test:kotlin-test-common:jar")) + add(annotationsMetadata.name, tasks.getByPath(":kotlin-test:kotlin-test-annotations-common:jar")) +} +val commonMetadataComponent = componentFactory.adhoc("common").apply { + addVariantsFromConfiguration(commonMetadata) { + mapToMavenScope("compile") + } +} +val annotationsMetadataComponent = componentFactory.adhoc("annotations-common").apply { + addVariantsFromConfiguration(annotationsMetadata) { + mapToMavenScope("compile") + } +} + + + +publishing { + publications { + create("main", MavenPublication::class) { + from(rootComponent) + artifact(combinedSourcesJar) + // TODO: Remove all optional dependencies from root pom + } + jvmTestFrameworks.forEach { framework -> + create(framework, MavenPublication::class) { + artifactId = "kotlin-test-$framework" + from(components[framework]) + artifact(tasks.getByPath(":kotlin-test:kotlin-test-$framework:sourcesJar") as Jar) + } + } + create("js", MavenPublication::class) { + artifactId = "kotlin-test-js" + from(jsComponent) + artifact(tasks.getByPath(":kotlin-test:kotlin-test-js:sourcesJar") as Jar) + } + create("common", MavenPublication::class) { + artifactId = "kotlin-test-common" + from(commonMetadataComponent) + artifact(tasks.getByPath(":kotlin-test:kotlin-test-common:sourcesJar") as Jar) + } + create("annotationsCommon", MavenPublication::class) { + artifactId = "kotlin-test-annotations-common" + from(annotationsMetadataComponent) + artifact(tasks.getByPath(":kotlin-test:kotlin-test-annotations-common:sourcesJar") as Jar) + } + } +} + +tasks { + val install by creating { + dependsOn(publishToMavenLocal) + } +} \ No newline at end of file diff --git a/libraries/kotlin.test/common/build.gradle b/libraries/kotlin.test/common/build.gradle index 730d97d99a9..cf0b36a35f0 100644 --- a/libraries/kotlin.test/common/build.gradle +++ b/libraries/kotlin.test/common/build.gradle @@ -2,8 +2,6 @@ description = 'Kotlin Test Common' apply plugin: 'kotlin-platform-common' -configurePublishing(project) - jvmTarget = "1.6" dependencies { diff --git a/libraries/kotlin.test/js/build.gradle b/libraries/kotlin.test/js/build.gradle index 50627f8fff5..9c194bc89c1 100644 --- a/libraries/kotlin.test/js/build.gradle +++ b/libraries/kotlin.test/js/build.gradle @@ -2,8 +2,6 @@ description = 'Kotlin Test for JS' apply plugin: 'kotlin-platform-js' -configurePublishing(project) - configurations { distJs distLibrary @@ -76,7 +74,6 @@ task sourcesJar(type: Jar, dependsOn: classes) { artifacts { runtime libraryJarWithIr archives libraryJarWithIr - publishedRuntime libraryJarWithIr distLibrary libraryJarWithIr archives sourcesJar distJs(file(compileKotlin2Js.kotlinOptions.outputFile)) { diff --git a/libraries/kotlin.test/junit/build.gradle b/libraries/kotlin.test/junit/build.gradle index 30c5736ef14..809436c2aac 100644 --- a/libraries/kotlin.test/junit/build.gradle +++ b/libraries/kotlin.test/junit/build.gradle @@ -3,7 +3,6 @@ description = 'Kotlin Test JUnit' apply plugin: 'kotlin-platform-jvm' configureJvm6Project(project) -configurePublishing(project) def includeJava9 = BuildPropertiesExtKt.getIncludeJava9(project.kotlinBuildProperties) diff --git a/libraries/kotlin.test/junit5/build.gradle b/libraries/kotlin.test/junit5/build.gradle index 51526ca91e4..411b48e69fc 100644 --- a/libraries/kotlin.test/junit5/build.gradle +++ b/libraries/kotlin.test/junit5/build.gradle @@ -3,7 +3,6 @@ description = 'Kotlin Test JUnit 5' apply plugin: 'kotlin-platform-jvm' configureJvm6Project(project) -configurePublishing(project) ext.javaHome = JDK_18 ext.jvmTarget = "1.8" diff --git a/libraries/kotlin.test/jvm/build.gradle b/libraries/kotlin.test/jvm/build.gradle index 651c29bb822..5dd30c3d69e 100644 --- a/libraries/kotlin.test/jvm/build.gradle +++ b/libraries/kotlin.test/jvm/build.gradle @@ -6,9 +6,6 @@ archivesBaseName = 'kotlin-test' configureJvm6Project(project) -configurePublishing(project) { - artifactId = archivesBaseName -} def includeJava9 = BuildPropertiesExtKt.getIncludeJava9(project.kotlinBuildProperties) diff --git a/libraries/kotlin.test/testng/build.gradle b/libraries/kotlin.test/testng/build.gradle index 968b937bef9..4f54d75a130 100644 --- a/libraries/kotlin.test/testng/build.gradle +++ b/libraries/kotlin.test/testng/build.gradle @@ -3,7 +3,6 @@ description = 'Kotlin Test TestNG' apply plugin: 'kotlin-platform-jvm' configureJvm6Project(project) -configurePublishing(project) ext.javaHome = JDK_17 def includeJava9 = BuildPropertiesExtKt.getIncludeJava9(project.kotlinBuildProperties) From 573aac7252ed441a344fd8c452e3722fc3e1879a Mon Sep 17 00:00:00 2001 From: Ilya Gorbunov Date: Wed, 27 Jan 2021 02:58:46 +0300 Subject: [PATCH 012/260] Apply common configuration to custom publications in kotlin-test To do that, extract parts of publishing setup into reusable functions. This change makes signing and repository configuration applied to all project publications, not just to the Main one. Also: - Get rid of dependencies from non-default variants in the root pom - Add an empty javadoc jar KT-40225 --- .../plugins/KotlinBuildPublishingPlugin.kt | 136 ++++++++++-------- libraries/kotlin.test/build.gradle.kts | 33 ++++- 2 files changed, 104 insertions(+), 65 deletions(-) diff --git a/buildSrc/src/main/kotlin/plugins/KotlinBuildPublishingPlugin.kt b/buildSrc/src/main/kotlin/plugins/KotlinBuildPublishingPlugin.kt index 00ff6701d4f..022e49d7f12 100644 --- a/buildSrc/src/main/kotlin/plugins/KotlinBuildPublishingPlugin.kt +++ b/buildSrc/src/main/kotlin/plugins/KotlinBuildPublishingPlugin.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -71,62 +71,11 @@ class KotlinBuildPublishingPlugin @Inject constructor( create(PUBLICATION_NAME) { from(kotlinLibraryComponent) - pom { - packaging = "jar" - name.set(humanReadableName(project)) - description.set(project.description ?: humanReadableName(project)) - url.set("https://kotlinlang.org/") - licenses { - license { - name.set("The Apache License, Version 2.0") - url.set("http://www.apache.org/licenses/LICENSE-2.0.txt") - } - } - scm { - url.set("https://github.com/JetBrains/kotlin") - connection.set("scm:git:https://github.com/JetBrains/kotlin.git") - developerConnection.set("scm:git:https://github.com/JetBrains/kotlin.git") - } - developers { - developer { - name.set("Kotlin Team") - organization.set("JetBrains") - organizationUrl.set("https://www.jetbrains.com") - } - } - } - } - } - - repositories { - maven { - name = REPOSITORY_NAME - url = file("${project.rootDir}/build/repo").toURI() + configureKotlinPomAttributes(project) } } } - - val signingRequired = provider { - project.findProperty("signingRequired")?.toString()?.toBoolean() - ?: project.property("isSonatypeRelease") as Boolean - } - - configure { - setRequired(signingRequired) - sign(extensions.getByType().publications[PUBLICATION_NAME]) - useGpgCmd() - } - - tasks.withType().configureEach { - setOnlyIf { signingRequired.get() } - } - - tasks.register("install") { - dependsOn(tasks.named("publishToMavenLocal")) - } - - tasks.named("publish${PUBLICATION_NAME}PublicationTo${REPOSITORY_NAME}Repository") - .configureRepository() + configureDefaultPublishing() } companion object { @@ -137,13 +86,84 @@ class KotlinBuildPublishingPlugin @Inject constructor( const val COMPILE_CONFIGURATION = "publishedCompile" const val RUNTIME_CONFIGURATION = "publishedRuntime" - @OptIn(ExperimentalStdlibApi::class) - fun humanReadableName(project: Project) = - project.name.split("-").joinToString(separator = " ") { it.capitalize(Locale.ROOT) } } } -fun TaskProvider.configureRepository() = configure { +@OptIn(ExperimentalStdlibApi::class) +private fun humanReadableName(name: String) = + name.split("-").joinToString(separator = " ") { it.capitalize(Locale.ROOT) } + +fun MavenPublication.configureKotlinPomAttributes(project: Project, explicitDescription: String? = null) { + val publication = this + pom { + packaging = "jar" + name.set(humanReadableName(publication.artifactId)) + description.set(explicitDescription ?: project.description ?: humanReadableName(publication.artifactId)) + url.set("https://kotlinlang.org/") + licenses { + license { + name.set("The Apache License, Version 2.0") + url.set("http://www.apache.org/licenses/LICENSE-2.0.txt") + } + } + scm { + url.set("https://github.com/JetBrains/kotlin") + connection.set("scm:git:https://github.com/JetBrains/kotlin.git") + developerConnection.set("scm:git:https://github.com/JetBrains/kotlin.git") + } + developers { + developer { + name.set("Kotlin Team") + organization.set("JetBrains") + organizationUrl.set("https://www.jetbrains.com") + } + } + } +} + + +fun Project.configureDefaultPublishing() { + configure { + repositories { + maven { + name = KotlinBuildPublishingPlugin.REPOSITORY_NAME + url = file("${project.rootDir}/build/repo").toURI() + } + } + } + + configureSigning() + + tasks.register("install") { + dependsOn(tasks.named("publishToMavenLocal")) + } + + tasks.withType() + .matching { it.name.endsWith("PublicationTo${KotlinBuildPublishingPlugin.REPOSITORY_NAME}Repository") } + .all { configureRepository() } +} + +private fun Project.configureSigning() { + val signingRequired = provider { + project.findProperty("signingRequired")?.toString()?.toBoolean() + ?: project.property("isSonatypeRelease") as Boolean + } + + configure { + setRequired(signingRequired) + sign(extensions.getByType().publications) // all publications + useGpgCmd() + } + + tasks.withType().configureEach { + setOnlyIf { signingRequired.get() } + } +} + +fun TaskProvider.configureRepository() = + configure { configureRepository() } + +private fun PublishToMavenRepository.configureRepository() { dependsOn(project.rootProject.tasks.named("preparePublication")) doFirst { val preparePublication = project.rootProject.tasks.named("preparePublication").get() diff --git a/libraries/kotlin.test/build.gradle.kts b/libraries/kotlin.test/build.gradle.kts index 253f916d798..7bcc959afff 100644 --- a/libraries/kotlin.test/build.gradle.kts +++ b/libraries/kotlin.test/build.gradle.kts @@ -1,9 +1,14 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType +import plugins.configureDefaultPublishing +import plugins.configureKotlinPomAttributes +import groovy.util.Node +import groovy.util.NodeList plugins { `kotlin-multiplatform` apply false base `maven-publish` + signing } open class ComponentsFactoryAccess @@ -248,42 +253,56 @@ val annotationsMetadataComponent = componentFactory.adhoc("annotations-common"). } } +val emptyJavadocJar by tasks.creating(Jar::class) { + archiveClassifier.set("javadoc") +} +configureDefaultPublishing() publishing { publications { create("main", MavenPublication::class) { from(rootComponent) artifact(combinedSourcesJar) - // TODO: Remove all optional dependencies from root pom + // Remove all optional dependencies from the root pom + pom.withXml { + val dependenciesNode = (asNode().get("dependencies") as NodeList).filterIsInstance().single() + val optionalDependencies = (dependenciesNode.get("dependency") as NodeList).filterIsInstance().filter { + ((it.get("optional") as NodeList).singleOrNull() as Node?)?.text() == "true" + } + optionalDependencies.forEach { dependenciesNode.remove(it) } + } + configureKotlinPomAttributes(project, "Kotlin Test Multiplatform library") } jvmTestFrameworks.forEach { framework -> create(framework, MavenPublication::class) { artifactId = "kotlin-test-$framework" from(components[framework]) artifact(tasks.getByPath(":kotlin-test:kotlin-test-$framework:sourcesJar") as Jar) + configureKotlinPomAttributes(project, "Kotlin Test Support for $framework") } } create("js", MavenPublication::class) { artifactId = "kotlin-test-js" from(jsComponent) artifact(tasks.getByPath(":kotlin-test:kotlin-test-js:sourcesJar") as Jar) + configureKotlinPomAttributes(project, "Kotlin Test for JS") } create("common", MavenPublication::class) { artifactId = "kotlin-test-common" from(commonMetadataComponent) artifact(tasks.getByPath(":kotlin-test:kotlin-test-common:sourcesJar") as Jar) + configureKotlinPomAttributes(project, "Kotlin Test Common") } create("annotationsCommon", MavenPublication::class) { artifactId = "kotlin-test-annotations-common" from(annotationsMetadataComponent) artifact(tasks.getByPath(":kotlin-test:kotlin-test-annotations-common:sourcesJar") as Jar) + configureKotlinPomAttributes(project, "Kotlin Test Common") + } + withType { + suppressAllPomMetadataWarnings() + artifact(emptyJavadocJar) } } } - -tasks { - val install by creating { - dependsOn(publishToMavenLocal) - } -} \ No newline at end of file From cbeadba15d2fe458ece167d7ce7f0760db4b3432 Mon Sep 17 00:00:00 2001 From: Ilya Gorbunov Date: Wed, 27 Jan 2021 06:05:07 +0300 Subject: [PATCH 013/260] Disable metadata publishing for legacy common artifacts When they are used explicitly in common source sets, they cannot be resolved in platform ones after that since they only have common kotlin-api variants in their metadata. KT-40225 --- libraries/kotlin.test/build.gradle.kts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/kotlin.test/build.gradle.kts b/libraries/kotlin.test/build.gradle.kts index 7bcc959afff..a78fdf6588b 100644 --- a/libraries/kotlin.test/build.gradle.kts +++ b/libraries/kotlin.test/build.gradle.kts @@ -306,3 +306,7 @@ publishing { } } } + +tasks.withType { + enabled = "common" !in (publication.get() as MavenPublication).artifactId +} \ No newline at end of file From 4a172286217a1a7d4e7a7f0eb6a0bc53ebf56515 Mon Sep 17 00:00:00 2001 From: Ilya Gorbunov Date: Wed, 27 Jan 2021 03:01:32 +0300 Subject: [PATCH 014/260] Infer required kotlin-test jvm capability based on used test framework Except when: - the Gradle version is less than 6.0, it doesn't read the metadata published by a newer Gradle by default. - the requested dependency version is less than 1.5, because it doesn't have metadata published. Update integration tests to use kotlin-test common dependency. KT-40225 --- .../gradle/KotlinSpecificDependenciesIT.kt | 11 +- .../internal/KotlinDependenciesManagement.kt | 111 +++++++++++++++++- .../kotlin/gradle/plugin/KotlinProperties.kt | 5 +- .../internals/ExposedForIntegrationTests.kt | 3 +- 4 files changed, 120 insertions(+), 10 deletions(-) diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinSpecificDependenciesIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinSpecificDependenciesIT.kt index b2cfa6a6936..bf543a1c4a8 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinSpecificDependenciesIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinSpecificDependenciesIT.kt @@ -1,11 +1,10 @@ /* - * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package org.jetbrains.kotlin.gradle -import org.jetbrains.kotlin.gradle.internals.KOTLIN_TEST_MULTIPLATFORM_MODULE_NAME import org.jetbrains.kotlin.gradle.util.AGPVersion import org.jetbrains.kotlin.gradle.util.modify import org.jetbrains.kotlin.test.util.KtTestUtil @@ -111,7 +110,7 @@ class KotlinSpecificDependenciesIT : BaseGradleIT() { ) } - private val kotlinTestMultiplatformDependency = "org.jetbrains.kotlin:$KOTLIN_TEST_MULTIPLATFORM_MODULE_NAME" + private val kotlinTestMultiplatformDependency = "org.jetbrains.kotlin:kotlin-test" @Test fun testKotlinTestSingleDependency() { @@ -222,7 +221,7 @@ class KotlinSpecificDependenciesIT : BaseGradleIT() { gradleBuildScript().appendText( "\n" + """ dependencies { testImplementation("$kotlinTestMultiplatformDependency") } - configurations.getByName("testImplementation").dependencies.removeAll { it.name == "$KOTLIN_TEST_MULTIPLATFORM_MODULE_NAME" } + configurations.getByName("testImplementation").dependencies.removeAll { it.name == "kotlin-test" } """.trimIndent() ) checkTaskCompileClasspath("compileTestKotlin", checkModulesNotInClasspath = listOf("kotlin-test")) @@ -244,14 +243,14 @@ class KotlinSpecificDependenciesIT : BaseGradleIT() { kotlin.coreLibrariesVersion = "$customVersion" dependencies { testImplementation("org.jetbrains.kotlin:kotlin-reflect") - testImplementation("org.jetbrains.kotlin:kotlin-test-multiplatform") + testImplementation("org.jetbrains.kotlin:kotlin-test") } test.useJUnit() """.trimIndent() ) checkTaskCompileClasspath( "compileTestKotlin", - listOf("kotlin-stdlib-", "kotlin-reflect-", "kotlin-test-junit-").map { it + customVersion } + listOf("kotlin-stdlib-", "kotlin-reflect-", "kotlin-test-").map { it + customVersion } ) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/KotlinDependenciesManagement.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/KotlinDependenciesManagement.kt index ee514ddd019..a7c111b0b05 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/KotlinDependenciesManagement.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/KotlinDependenciesManagement.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -36,11 +36,13 @@ import org.jetbrains.kotlin.gradle.targets.jvm.JvmCompilationsTestRunSource import org.jetbrains.kotlin.gradle.tasks.KOTLIN_MODULE_GROUP import org.jetbrains.kotlin.gradle.tasks.locateTask import org.jetbrains.kotlin.gradle.testing.KotlinTaskTestRun +import org.jetbrains.kotlin.gradle.utils.isGradleVersionAtLeast import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName internal fun customizeKotlinDependencies(project: Project) { configureStdlibDefaultDependency(project) configureKotlinTestDependencies(project) + configureKotlinTestDependency(project) configureDefaultVersionsResolutionStrategy(project) } @@ -179,6 +181,113 @@ private fun stdlibModuleForJvmCompilations(compilations: Iterable 1 || c1 == 1 && c2 >= 5 + } ?: false + + KotlinDependencyScope.values().forEach { scope -> + val versionOrNullBySourceSet = mutableMapOf() + + project.kotlinExtension.sourceSets.all { kotlinSourceSet -> + val configuration = project.sourceSetDependencyConfigurationByScope(kotlinSourceSet, scope) + var finalizingDependencies = false + + configuration.dependencies.matching(::isKotlinTestRootDependency).apply { + firstOrNull()?.let { versionOrNullBySourceSet[kotlinSourceSet] = it.version } + whenObjectRemoved { + if (!finalizingDependencies && !any()) + versionOrNullBySourceSet.remove(kotlinSourceSet) + } + whenObjectAdded { item -> + versionOrNullBySourceSet[kotlinSourceSet] = item.version + } + } + + project.tryWithDependenciesIfUnresolved(configuration) { dependencies -> + val parentOrOwnVersions: List = + kotlinSourceSet.getSourceSetHierarchy().filter(versionOrNullBySourceSet::contains).map(versionOrNullBySourceSet::get) + + finalizingDependencies = true + + for (version in parentOrOwnVersions.distinct()) { // add dependencies with each version and let Gradle disambiguate them + val effectiveVersion = version ?: project.kotlinExtension.coreLibrariesVersion + if (!isAtLeast1_5(effectiveVersion)) continue + val clarifyCapability = kotlinTestCapabilityForJvmSourceSet(project, kotlinSourceSet) ?: continue + val clarifiedDependency = + (project.kotlinDependency(KOTLIN_TEST_ROOT_MODULE_NAME, version) as ExternalDependency).apply { + if (version == null) { + version { constraint -> constraint.require(project.kotlinExtension.coreLibrariesVersion) } + } + capabilities { + it.requireCapability(clarifyCapability) + } + } + dependencies.add(clarifiedDependency) + } + } + } + } +} + +private fun kotlinTestCapabilityForJvmSourceSet(project: Project, kotlinSourceSet: KotlinSourceSet): String? { + val compilations = CompilationSourceSetUtil.compilationsBySourceSets(project).getValue(kotlinSourceSet) + .filter { it.target !is KotlinMetadataTarget } + + val platformTypes = compilations.map { it.platformType } + // TODO: Extract jvmPlatformTypes to public constant? + val jvmPlatforms = setOf(KotlinPlatformType.jvm, KotlinPlatformType.androidJvm) + if (!jvmPlatforms.containsAll(platformTypes)) return null + + val testTaskLists: List?> = compilations.map { compilation -> + val target = compilation.target + when { + target is KotlinTargetWithTests<*, *> -> + target.findTestRunsByCompilation(compilation)?.filterIsInstance>()?.map { it.executionTask.get() } + target is KotlinWithJavaTarget<*> -> + if (compilation.name == KotlinCompilation.TEST_COMPILATION_NAME) + project.locateTask(target.testTaskName)?.get()?.let(::listOf) + else null + compilation is KotlinJvmAndroidCompilation -> when (compilation.androidVariant) { + is UnitTestVariant -> + project.locateTask(lowerCamelCaseName("test", compilation.androidVariant.name))?.get()?.let(::listOf) + is TestVariant -> (compilation.androidVariant as TestVariant).connectedInstrumentTest?.let(::listOf) + else -> null + } + else -> null + } + } + if (null in testTaskLists) { + return null + } + val testTasks = testTaskLists.flatMap { checkNotNull(it) } + val frameworks = testTasks.mapTo(mutableSetOf()) { testTask -> + when (testTask) { + is Test -> testFrameworkOf(testTask) + else -> // Android connected test tasks don't inherit from Test, but we use JUnit for them + KotlinTestJvmFramework.junit + } + } + return when { + frameworks.size > 1 -> null + else -> "$KOTLIN_MODULE_GROUP:$KOTLIN_TEST_ROOT_MODULE_NAME-framework-${frameworks.single()}" + } +} + +internal const val KOTLIN_TEST_ROOT_MODULE_NAME = "kotlin-test" + + internal fun configureKotlinTestDependencies(project: Project) { fun isKotlinTestMultiplatformDependency(dependency: Dependency) = dependency.group == KOTLIN_MODULE_GROUP && dependency.name == KOTLIN_TEST_MULTIPLATFORM_MODULE_NAME diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinProperties.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinProperties.kt index d0fabeb4812..4b0c5b44264 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinProperties.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinProperties.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -253,6 +253,9 @@ internal class PropertiesProvider private constructor(private val project: Proje val stdlibDefaultDependency: Boolean get() = booleanProperty("kotlin.stdlib.default.dependency") ?: true + val kotlinTestInferJvmVariant: Boolean + get() = booleanProperty("kotlin.test.infer.jvm.variant") ?: true + private fun propertyWithDeprecatedVariant(propName: String, deprecatedPropName: String): String? { val deprecatedProperty = property(deprecatedPropName) if (deprecatedProperty != null) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/internals/ExposedForIntegrationTests.kt b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/internals/ExposedForIntegrationTests.kt index 0c02d9fc57a..ac223b63d86 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/internals/ExposedForIntegrationTests.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/internals/ExposedForIntegrationTests.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -26,4 +26,3 @@ const val NO_NATIVE_STDLIB_PROPERTY_WARNING = NO_NATIVE_STDLIB_PROPERTY_WARNING val KOTLIN_12X_MPP_DEPRECATION_WARNING = KOTLIN_12X_MPP_DEPRECATION_WARNING -const val KOTLIN_TEST_MULTIPLATFORM_MODULE_NAME = org.jetbrains.kotlin.gradle.internal.KOTLIN_TEST_MULTIPLATFORM_MODULE_NAME \ No newline at end of file From 0f2ca5d84c0f3f69521c16f2418014c63ab0b043 Mon Sep 17 00:00:00 2001 From: pyos Date: Tue, 18 Feb 2020 12:48:59 +0100 Subject: [PATCH 015/260] JVM_IR: support non-local break/continue in the inliner Not in the frontend or psi2ir, though, so this not a complete implementation of KT-1436, but rather a part of it that is currently useful to make other code compile. In particular, lambdas passed to array constructors and JVM-style `assert` are inlined as IR returnable blocks, which are then converted into `do { ... } while (false)` loops, so non-local returns from them become non-local `break`s. --- .../inline/AnonymousObjectTransformer.kt | 2 +- .../kotlin/codegen/inline/InlineCodegen.kt | 10 +- .../kotlin/codegen/inline/LambdaInfo.kt | 20 ++-- .../kotlin/codegen/inline/MethodInliner.kt | 82 ++++++++--------- .../codegen/inline/ReturnLabelOwner.java | 29 ------ .../codegen/inline/SourceCompilerForInline.kt | 16 ++-- ...FirBlackBoxInlineCodegenTestGenerated.java | 40 ++++++++ .../jetbrains/kotlin/backend/jvm/JvmLower.kt | 3 +- .../backend/jvm/codegen/ExpressionCodegen.kt | 92 +++++++++++-------- .../backend/jvm/codegen/IrInlineCodegen.kt | 4 - .../jvm/codegen/IrSourceCompilerForInline.kt | 24 +++-- .../nonLocalReturns/fromArrayGenerator.kt | 5 + .../fromArrayGeneratorCatch.kt | 24 +++++ .../fromArrayGeneratorNested.kt | 5 + .../fromArrayGeneratorWithCapture.kt | 8 ++ .../fromArrayGeneratorWithCatch.kt | 22 +++++ .../fromArrayGeneratorWithFinally.kt | 19 ++++ .../fromArrayGeneratorWithFinallyX2.kt | 25 +++++ .../fromArrayGeneratorWithFinallyX2_2.kt | 25 +++++ .../BlackBoxInlineCodegenTestGenerated.java | 40 ++++++++ ...otlinAgainstInlineKotlinTestGenerated.java | 40 ++++++++ .../IrBlackBoxInlineCodegenTestGenerated.java | 40 ++++++++ ...otlinAgainstInlineKotlinTestGenerated.java | 40 ++++++++ ...JvmIrAgainstOldBoxInlineTestGenerated.java | 40 ++++++++ ...JvmOldAgainstIrBoxInlineTestGenerated.java | 40 ++++++++ .../IrJsCodegenInlineES6TestGenerated.java | 40 ++++++++ .../IrJsCodegenInlineTestGenerated.java | 40 ++++++++ .../JsCodegenInlineTestGenerated.java | 40 ++++++++ 28 files changed, 660 insertions(+), 155 deletions(-) delete mode 100644 compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReturnLabelOwner.java create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGenerator.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorCatch.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorNested.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCapture.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCatch.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinally.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2.kt create mode 100644 compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2_2.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.kt index f6beca2bce2..c4a846e2db7 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/AnonymousObjectTransformer.kt @@ -319,7 +319,7 @@ class AnonymousObjectTransformer( ), null ) - val result = inliner.doInline(deferringVisitor, LocalVarRemapper(parameters, 0), false, ReturnLabelOwner.NOT_APPLICABLE) + val result = inliner.doInline(deferringVisitor, LocalVarRemapper(parameters, 0), false, mapOf()) result.reifiedTypeParametersUsages.mergeAll(typeParametersToReify) deferringVisitor.visitMaxs(-1, -1) return result diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt index 7c45a0bfbff..ea97043b650 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt @@ -243,12 +243,10 @@ abstract class InlineCodegen( //hack to keep linenumber info, otherwise jdi will skip begin of linenumber chain adapter.visitInsn(Opcodes.NOP) - val result = inliner.doInline(adapter, remapper, true, ReturnLabelOwner.SKIP_ALL) + val result = inliner.doInline(adapter, remapper, true, mapOf()) result.reifiedTypeParametersUsages.mergeAll(reificationResult) - val labels = sourceCompiler.getContextLabels() - - val infos = MethodInliner.processReturns(adapter, ReturnLabelOwner { labels.contains(it) }, true, null) + val infos = MethodInliner.processReturns(adapter, sourceCompiler.getContextLabels(), null) generateAndInsertFinallyBlocks( adapter, infos, (remapper.remap(parameters.argsSizeOnStack + 1).value as StackValue.Local).index ) @@ -319,7 +317,9 @@ abstract class InlineCodegen( frameMap.enterTemp(Type.INT_TYPE) } - sourceCompiler.generateFinallyBlocksIfNeeded(finallyCodegen, extension.returnType, extension.finallyIntervalEnd.label) + sourceCompiler.generateFinallyBlocksIfNeeded( + finallyCodegen, extension.returnType, extension.finallyIntervalEnd.label, extension.jumpTarget + ) //Exception table for external try/catch/finally blocks will be generated in original codegen after exiting this method insertNodeBefore(finallyNode, intoNode, curInstr) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt index 2da961b68cd..e20441fa587 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt @@ -30,17 +30,14 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCallWithAssert import org.jetbrains.kotlin.resolve.jvm.AsmTypes.* import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.util.OperatorNameConventions -import org.jetbrains.org.objectweb.asm.ClassReader -import org.jetbrains.org.objectweb.asm.ClassVisitor -import org.jetbrains.org.objectweb.asm.Opcodes -import org.jetbrains.org.objectweb.asm.Type +import org.jetbrains.org.objectweb.asm.* import org.jetbrains.org.objectweb.asm.commons.Method import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode import kotlin.properties.Delegates interface FunctionalArgument -abstract class LambdaInfo(@JvmField val isCrossInline: Boolean) : FunctionalArgument, ReturnLabelOwner { +abstract class LambdaInfo(@JvmField val isCrossInline: Boolean) : FunctionalArgument { abstract val isBoundCallableReference: Boolean @@ -54,6 +51,9 @@ abstract class LambdaInfo(@JvmField val isCrossInline: Boolean) : FunctionalArgu abstract val capturedVars: List + open val returnLabels: Map + get() = mapOf() + lateinit var node: SMAPAndMethodNode abstract fun generateLambdaBody(sourceCompiler: SourceCompilerForInline, reifiedTypeInliner: ReifiedTypeInliner<*>) @@ -129,8 +129,6 @@ abstract class DefaultLambda( final override lateinit var capturedVars: List private set - override fun isReturnFromMe(labelName: String): Boolean = false - var originalBoundReceiverType: Type? = null private set @@ -247,7 +245,7 @@ class PsiExpressionLambda( val functionWithBodyOrCallableReference: KtExpression = (expression as? KtLambdaExpression)?.functionLiteral ?: expression - private val labels: Set + override val returnLabels: Map override val isSuspend: Boolean @@ -284,7 +282,7 @@ class PsiExpressionLambda( closure = it!! } - labels = InlineCodegen.getDeclarationLabels(expression, invokeMethodDescriptor) + returnLabels = InlineCodegen.getDeclarationLabels(expression, invokeMethodDescriptor).associateWith { null } invokeMethod = typeMapper.mapAsmMethod(invokeMethodDescriptor) isSuspend = invokeMethodDescriptor.isSuspend } @@ -324,10 +322,6 @@ class PsiExpressionLambda( } } - override fun isReturnFromMe(labelName: String): Boolean { - return labels.contains(labelName) - } - val isPropertyReference: Boolean get() = propertyReferenceInfo != null diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt index df48334c6e4..970c93c146e 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/MethodInliner.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful import org.jetbrains.kotlin.codegen.optimization.fixStack.peek import org.jetbrains.kotlin.codegen.optimization.fixStack.top import org.jetbrains.kotlin.codegen.optimization.nullCheck.isCheckParameterIsNotNull +import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.ParameterDescriptor @@ -72,9 +73,9 @@ class MethodInliner( adapter: MethodVisitor, remapper: LocalVarRemapper, remapReturn: Boolean, - returnLabelOwner: ReturnLabelOwner + returnLabels: Map ): InlineResult { - return doInline(adapter, remapper, remapReturn, returnLabelOwner, 0) + return doInline(adapter, remapper, remapReturn, returnLabels, 0) } private fun recordTransformation(info: TransformationInfo) { @@ -91,11 +92,11 @@ class MethodInliner( adapter: MethodVisitor, remapper: LocalVarRemapper, remapReturn: Boolean, - returnLabelOwner: ReturnLabelOwner, + returnLabels: Map, finallyDeepShift: Int ): InlineResult { //analyze body - var transformedNode = markPlacesForInlineAndRemoveInlinable(node, returnLabelOwner, finallyDeepShift) + var transformedNode = markPlacesForInlineAndRemoveInlinable(node, returnLabels, finallyDeepShift) if (inliningContext.isInliningLambda && isDefaultLambdaWithReification(inliningContext.lambdaInfo!!)) { //TODO maybe move reification in one place inliningContext.root.inlineMethodReifier.reifyInstructions(transformedNode) @@ -139,7 +140,9 @@ class MethodInliner( ) } - processReturns(resultNode, returnLabelOwner, remapReturn, end) + if (remapReturn) { + processReturns(resultNode, returnLabels, end) + } //flush transformed node to output resultNode.accept(SkipMaxAndEndVisitor(adapter)) return result @@ -297,7 +300,7 @@ class MethodInliner( val varRemapper = LocalVarRemapper(lambdaParameters, valueParamShift) //TODO add skipped this and receiver - val lambdaResult = inliner.doInline(localVariablesSorter, varRemapper, true, info, invokeCall.finallyDepthShift) + val lambdaResult = inliner.doInline(localVariablesSorter, varRemapper, true, info.returnLabels, invokeCall.finallyDepthShift) result.mergeWithNotChangeInfo(lambdaResult) result.reifiedTypeParametersUsages.mergeAll(lambdaResult.reifiedTypeParametersUsages) @@ -486,11 +489,11 @@ class MethodInliner( } private fun markPlacesForInlineAndRemoveInlinable( - node: MethodNode, returnLabelOwner: ReturnLabelOwner, finallyDeepShift: Int + node: MethodNode, returnLabels: Map, finallyDeepShift: Int ): MethodNode { val processingNode = prepareNode(node, finallyDeepShift) - preprocessNodeBeforeInline(processingNode, returnLabelOwner) + preprocessNodeBeforeInline(processingNode, returnLabels) replaceContinuationAccessesWithFakeContinuationsIfNeeded(processingNode) @@ -765,7 +768,7 @@ class MethodInliner( } } - private fun preprocessNodeBeforeInline(node: MethodNode, returnLabelOwner: ReturnLabelOwner) { + private fun preprocessNodeBeforeInline(node: MethodNode, returnLabels: Map) { try { FixStackWithLabelNormalizationMethodTransformer().transform("fake", node) } catch (e: Throwable) { @@ -787,16 +790,13 @@ class MethodInliner( if (!isReturnOpcode(insnNode.opcode)) continue - var insertBeforeInsn = insnNode - // TODO extract isLocalReturn / isNonLocalReturn, see processReturns val labelName = getMarkedReturnLabelOrNull(insnNode) - if (labelName != null) { - if (!returnLabelOwner.isReturnFromMe(labelName)) continue - insertBeforeInsn = insnNode.previous + if (labelName == null) { + localReturnsNormalizer.addLocalReturnToTransform(insnNode, insnNode, frame) + } else if (labelName in returnLabels) { + localReturnsNormalizer.addLocalReturnToTransform(insnNode, insnNode.previous, frame) } - - localReturnsNormalizer.addLocalReturnToTransform(insnNode, insertBeforeInsn, frame) } localReturnsNormalizer.transform(node) @@ -1001,7 +1001,8 @@ class MethodInliner( class PointForExternalFinallyBlocks( @JvmField val beforeIns: AbstractInsnNode, @JvmField val returnType: Type, - @JvmField val finallyIntervalEnd: LabelNode + @JvmField val finallyIntervalEnd: LabelNode, + @JvmField val jumpTarget: Label? ) companion object { @@ -1115,55 +1116,44 @@ class MethodInliner( //process local and global returns (local substituted with goto end-label global kept unchanged) @JvmStatic fun processReturns( - node: MethodNode, returnLabelOwner: ReturnLabelOwner, remapReturn: Boolean, endLabel: Label? + node: MethodNode, returnLabels: Map, endLabel: Label? ): List { - if (!remapReturn) { - return emptyList() - } val result = ArrayList() val instructions = node.instructions var insnNode: AbstractInsnNode? = instructions.first while (insnNode != null) { if (isReturnOpcode(insnNode.opcode)) { - var isLocalReturn = true val labelName = getMarkedReturnLabelOrNull(insnNode) + val returnType = getReturnType(insnNode.opcode) - if (labelName != null) { - isLocalReturn = returnLabelOwner.isReturnFromMe(labelName) - //remove global return flag - if (isLocalReturn) { - instructions.remove(insnNode.previous) - } + val isLocalReturn = labelName == null || labelName in returnLabels + val jumpTarget = returnLabels[labelName] ?: endLabel + + if (isLocalReturn && labelName != null) { + // remove non-local return flag + instructions.remove(insnNode.previous) } - if (isLocalReturn && endLabel != null) { - val nop = InsnNode(Opcodes.NOP) - instructions.insert(insnNode, nop) - - val labelNode = endLabel.info as LabelNode - val jumpInsnNode = JumpInsnNode(Opcodes.GOTO, labelNode) - instructions.insert(nop, jumpInsnNode) - + if (isLocalReturn && jumpTarget != null) { + val jumpInsnNode = JumpInsnNode(Opcodes.GOTO, jumpTarget.info as LabelNode) + instructions.insertBefore(insnNode, InsnNode(Opcodes.NOP)) + if (jumpTarget != endLabel) { + instructions.insertBefore(insnNode, PseudoInsn.FIX_STACK_BEFORE_JUMP.createInsnNode()) + } + instructions.insertBefore(insnNode, jumpInsnNode) instructions.remove(insnNode) insnNode = jumpInsnNode } - //generate finally block before nonLocalReturn flag/return/goto val label = LabelNode() instructions.insert(insnNode, label) - result.add( - PointForExternalFinallyBlocks( - getInstructionToInsertFinallyBefore(insnNode, isLocalReturn), getReturnType(insnNode.opcode), label - ) - ) + // generate finally blocks before the non-local return flag or the stack fixup pseudo instruction + val finallyInsertionPoint = if (isLocalReturn && jumpTarget == endLabel) insnNode else insnNode.previous + result.add(PointForExternalFinallyBlocks(finallyInsertionPoint, returnType, label, jumpTarget)) } insnNode = insnNode.next } return result } - - private fun getInstructionToInsertFinallyBefore(nonLocalReturnOrJump: AbstractInsnNode, isLocal: Boolean): AbstractInsnNode { - return if (isLocal) nonLocalReturnOrJump else nonLocalReturnOrJump.previous - } } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReturnLabelOwner.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReturnLabelOwner.java deleted file mode 100644 index 4b1d1e78cda..00000000000 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReturnLabelOwner.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2010-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.kotlin.codegen.inline; - -import org.jetbrains.annotations.NotNull; - -public interface ReturnLabelOwner { - boolean isReturnFromMe(@NotNull String labelName); - - ReturnLabelOwner SKIP_ALL = name -> false; - - ReturnLabelOwner NOT_APPLICABLE = name -> { - throw new RuntimeException("This operation not applicable for current context"); - }; -} diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SourceCompilerForInline.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SourceCompilerForInline.kt index e01026264ab..360760bd27b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SourceCompilerForInline.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SourceCompilerForInline.kt @@ -64,7 +64,7 @@ interface SourceCompilerForInline { curFinallyDepth: Int ): BaseExpressionCodegen - fun generateFinallyBlocksIfNeeded(finallyCodegen: BaseExpressionCodegen, returnType: Type, afterReturnLabel: Label) + fun generateFinallyBlocksIfNeeded(codegen: BaseExpressionCodegen, returnType: Type, afterReturnLabel: Label, target: Label?) fun isCallInsideSameModuleAsDeclared(functionDescriptor: FunctionDescriptor): Boolean @@ -74,7 +74,7 @@ interface SourceCompilerForInline { val compilationContextFunctionDescriptor: FunctionDescriptor - fun getContextLabels(): Set + fun getContextLabels(): Map fun reportSuspensionPointInsideMonitor(stackTraceElement: String) } @@ -311,9 +311,10 @@ class PsiSourceCompilerForInline(private val codegen: ExpressionCodegen, overrid override fun hasFinallyBlocks() = codegen.hasFinallyBlocks() - override fun generateFinallyBlocksIfNeeded(finallyCodegen: BaseExpressionCodegen, returnType: Type, afterReturnLabel: Label) { - require(finallyCodegen is ExpressionCodegen) - finallyCodegen.generateFinallyBlocksIfNeeded(returnType, null, afterReturnLabel) + override fun generateFinallyBlocksIfNeeded(codegen: BaseExpressionCodegen, returnType: Type, afterReturnLabel: Label, target: Label?) { + // TODO use the target label for non-local break/continue + require(codegen is ExpressionCodegen) + codegen.generateFinallyBlocksIfNeeded(returnType, null, afterReturnLabel) } override fun createCodegenForExternalFinallyBlockGenerationOnNonLocalReturn(finallyNode: MethodNode, curFinallyDepth: Int) = @@ -337,14 +338,15 @@ class PsiSourceCompilerForInline(private val codegen: ExpressionCodegen, overrid override val compilationContextFunctionDescriptor get() = codegen.getContext().functionDescriptor - override fun getContextLabels(): Set { + override fun getContextLabels(): Map { val context = codegen.getContext() val parentContext = context.parentContext val descriptor = if (parentContext is ClosureContext && parentContext.originalSuspendLambdaDescriptor != null) { parentContext.originalSuspendLambdaDescriptor!! } else context.contextDescriptor - return InlineCodegen.getDeclarationLabels(DescriptorToSourceUtils.descriptorToDeclaration(descriptor), descriptor) + val labels = InlineCodegen.getDeclarationLabels(DescriptorToSourceUtils.descriptorToDeclaration(descriptor), descriptor) + return labels.associateWith { null } // TODO add break/continue labels } fun initializeInlineFunctionContext(functionDescriptor: FunctionDescriptor) { diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/codegen/ir/FirBlackBoxInlineCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/codegen/ir/FirBlackBoxInlineCodegenTestGenerated.java index 83d79e91a01..25ca6b9f83f 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/codegen/ir/FirBlackBoxInlineCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/codegen/ir/FirBlackBoxInlineCodegenTestGenerated.java @@ -2420,6 +2420,46 @@ public class FirBlackBoxInlineCodegenTestGenerated extends AbstractFirBlackBoxIn runTest("compiler/testData/codegen/boxInline/nonLocalReturns/explicitLocalReturn.kt"); } + @TestMetadata("fromArrayGenerator.kt") + public void testFromArrayGenerator() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGenerator.kt"); + } + + @TestMetadata("fromArrayGeneratorCatch.kt") + public void testFromArrayGeneratorCatch() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorCatch.kt"); + } + + @TestMetadata("fromArrayGeneratorNested.kt") + public void testFromArrayGeneratorNested() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorNested.kt"); + } + + @TestMetadata("fromArrayGeneratorWithCapture.kt") + public void testFromArrayGeneratorWithCapture() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCapture.kt"); + } + + @TestMetadata("fromArrayGeneratorWithCatch.kt") + public void testFromArrayGeneratorWithCatch() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCatch.kt"); + } + + @TestMetadata("fromArrayGeneratorWithFinally.kt") + public void testFromArrayGeneratorWithFinally() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinally.kt"); + } + + @TestMetadata("fromArrayGeneratorWithFinallyX2.kt") + public void testFromArrayGeneratorWithFinallyX2() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2.kt"); + } + + @TestMetadata("fromArrayGeneratorWithFinallyX2_2.kt") + public void testFromArrayGeneratorWithFinallyX2_2() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2_2.kt"); + } + @TestMetadata("fromInterfaceDefaultGetter.kt") public void testFromInterfaceDefaultGetter() throws Exception { runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromInterfaceDefaultGetter.kt"); diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt index 47e43f02d84..8c9224fac46 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt @@ -313,8 +313,6 @@ private val jvmFilePhases = listOf( collectionStubMethodLowering, jvmInlineClassPhase, - sharedVariablesPhase, - makePatchParentsPhase(1), enumWhenPhase, @@ -323,6 +321,7 @@ private val jvmFilePhases = listOf( singleAbstractMethodPhase, assertionPhase, returnableBlocksPhase, + sharedVariablesPhase, localDeclarationsPhase, jvmLocalClassExtractionPhase, staticCallableReferencePhase, diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt index 70dafe7c487..da0cac1c4f2 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt @@ -80,7 +80,7 @@ class TryWithFinallyInfo(val onExit: IrExpression) : TryInfo() class BlockInfo(val parent: BlockInfo? = null) { val variables = mutableListOf() - private val infos: Stack = parent?.infos ?: Stack() + val infos: Stack = parent?.infos ?: Stack() fun hasFinallyBlocks(): Boolean = infos.firstIsInstanceOrNull() != null @@ -869,42 +869,39 @@ class ExpressionCodegen( return unitValue } + private fun generateGlobalReturnFlagIfPossible(expression: IrExpression, label: String) { + if (state.isInlineDisabled) { + context.psiErrorBuilder.at(expression, irFunction).report(Errors.NON_LOCAL_RETURN_IN_DISABLED_INLINE) + genThrow(mv, "java/lang/UnsupportedOperationException", "Non-local returns are not allowed with inlining disabled") + } else { + generateGlobalReturnFlag(mv, label) + } + } + override fun visitReturn(expression: IrReturn, data: BlockInfo): PromisedValue { val returnTarget = expression.returnTargetSymbol.owner - val owner = - returnTarget as? IrFunction - ?: (returnTarget as? IrReturnableBlock)?.inlineFunctionSymbol?.owner - ?: error("Unsupported IrReturnTarget: $returnTarget") - //TODO: should be owner != irFunction - val isNonLocalReturn = - methodSignatureMapper.mapFunctionName(owner) != methodSignatureMapper.mapFunctionName(irFunction) - if (isNonLocalReturn && state.isInlineDisabled) { - context.psiErrorBuilder.at(expression, owner).report(Errors.NON_LOCAL_RETURN_IN_DISABLED_INLINE) - genThrow( - mv, "java/lang/UnsupportedOperationException", - "Non-local returns are not allowed with inlining disabled" - ) - return unitValue - } + val owner = returnTarget as? IrFunction ?: error("Unsupported IrReturnTarget: $returnTarget") + // TODO: should be owner != irFunction + val isNonLocalReturn = methodSignatureMapper.mapFunctionName(owner) != methodSignatureMapper.mapFunctionName(irFunction) var returnType = if (owner == irFunction) signature.returnType else methodSignatureMapper.mapReturnType(owner) var returnIrType = owner.returnType - val unboxedInlineClass = owner.suspendFunctionOriginal().originalReturnTypeOfSuspendFunctionReturningUnboxedInlineClass() if (unboxedInlineClass != null) { returnIrType = unboxedInlineClass returnType = unboxedInlineClass.asmType } + val afterReturnLabel = Label() expression.value.accept(this, data).materializeAt(returnType, returnIrType) // In case of non-local return from suspend lambda 'materializeAt' does not box return value, box it manually. if (isNonLocalReturn && owner.isInvokeSuspendOfLambda() && expression.value.type.isKotlinResult()) { StackValue.boxInlineClass(expression.value.type.toIrBasedKotlinType(), mv) } - generateFinallyBlocksIfNeeded(returnType, afterReturnLabel, data) + generateFinallyBlocksIfNeeded(returnType, afterReturnLabel, data, null) expression.markLineNumber(startOffset = true) if (isNonLocalReturn) { - generateGlobalReturnFlag(mv, owner.name.asString()) + generateGlobalReturnFlagIfPossible(expression, owner.name.asString()) } mv.areturn(returnType) mv.mark(afterReturnLabel) @@ -1012,9 +1009,15 @@ class ExpressionCodegen( } override fun visitWhileLoop(loop: IrWhileLoop, data: BlockInfo): PromisedValue { - val continueLabel = markNewLabel() - val endLabel = Label() - // Mark stack depth for break + // Spill the stack in case the loop contains inline functions that break/continue + // out of it. (The case where a loop is entered with a non-empty stack is rare, but + // possible; basically, you need to either use `Array(n) { ... }` or put a `when` + // containing a loop as an argument to a function call.) + addInlineMarker(mv, true) + val continueLabel = markNewLinkedLabel() + val endLabel = linkedLabel() + // Mark the label as having 0 stack depth, so that `break`/`continue` inside + // expressions pop all elements off it before jumping. mv.fakeAlwaysFalseIfeq(endLabel) loop.condition.markLineNumber(true) loop.condition.accept(this, data).coerceToBoolean().jumpIfFalse(endLabel) @@ -1023,14 +1026,16 @@ class ExpressionCodegen( } mv.goTo(continueLabel) mv.mark(endLabel) + addInlineMarker(mv, false) return unitValue } override fun visitDoWhileLoop(loop: IrDoWhileLoop, data: BlockInfo): PromisedValue { + // See comments in `visitWhileLoop` + addInlineMarker(mv, true) val entry = markNewLabel() - val endLabel = Label() - val continueLabel = Label() - // Mark stack depth for break/continue + val endLabel = linkedLabel() + val continueLabel = linkedLabel() mv.fakeAlwaysFalseIfeq(continueLabel) mv.fakeAlwaysFalseIfeq(endLabel) data.withBlock(LoopInfo(loop, continueLabel, endLabel)) { @@ -1040,6 +1045,7 @@ class ExpressionCodegen( loop.condition.markLineNumber(true) loop.condition.accept(this, data).coerceToBoolean().jumpIfTrue(entry) mv.mark(endLabel) + addInlineMarker(mv, false) return unitValue } @@ -1047,26 +1053,32 @@ class ExpressionCodegen( endLabel: Label, data: BlockInfo, nestedTryWithoutFinally: MutableList = arrayListOf(), - stop: (ExpressionInfo) -> Boolean = { false } - ): ExpressionInfo? { + stop: (LoopInfo) -> Boolean + ): LoopInfo? { return data.handleBlock { - if (it is TryWithFinallyInfo) { - genFinallyBlock(it, null, endLabel, data, nestedTryWithoutFinally) - nestedTryWithoutFinally.clear() - } else if (it is TryInfo) { - nestedTryWithoutFinally.add(it) + when { + it is TryWithFinallyInfo -> { + genFinallyBlock(it, null, endLabel, data, nestedTryWithoutFinally) + nestedTryWithoutFinally.clear() + } + it is TryInfo -> nestedTryWithoutFinally.add(it) + it is LoopInfo && stop(it) -> return it } - return if (stop(it)) it else unwindBlockStack(endLabel, data, nestedTryWithoutFinally, stop) + return unwindBlockStack(endLabel, data, nestedTryWithoutFinally, stop) } } override fun visitBreakContinue(jump: IrBreakContinue, data: BlockInfo): PromisedValue { jump.markLineNumber(startOffset = true) val endLabel = Label() - val stackElement = unwindBlockStack(endLabel, data) { it is LoopInfo && it.loop == jump.loop } as LoopInfo? - ?: throw AssertionError("Target label for break/continue not found") - mv.fixStackAndJump(if (jump is IrBreak) stackElement.breakLabel else stackElement.continueLabel) - mv.mark(endLabel) + val stackElement = unwindBlockStack(endLabel, data) { it.loop == jump.loop } + if (stackElement == null) { + generateGlobalReturnFlagIfPossible(jump, jump.loop.nonLocalReturnLabel(jump is IrBreak)) + mv.areturn(Type.VOID_TYPE) + } else { + mv.fixStackAndJump(if (jump is IrBreak) stackElement.breakLabel else stackElement.continueLabel) + mv.mark(endLabel) + } return unitValue } @@ -1214,16 +1226,16 @@ class ExpressionCodegen( } } - fun generateFinallyBlocksIfNeeded(returnType: Type, afterReturnLabel: Label, data: BlockInfo) { + fun generateFinallyBlocksIfNeeded(returnType: Type, afterReturnLabel: Label, data: BlockInfo, jumpLabel: Label?) { if (data.hasFinallyBlocks()) { if (Type.VOID_TYPE != returnType) { val returnValIndex = frameMap.enterTemp(returnType) mv.store(returnValIndex, returnType) - unwindBlockStack(afterReturnLabel, data) + unwindBlockStack(afterReturnLabel, data) { it.breakLabel == jumpLabel || it.continueLabel == jumpLabel } mv.load(returnValIndex, returnType) frameMap.leaveTemp(returnType) } else { - unwindBlockStack(afterReturnLabel, data) + unwindBlockStack(afterReturnLabel, data) { it.breakLabel == jumpLabel || it.continueLabel == jumpLabel } } } } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt index 8cf6c637b0b..7d946c0eb6a 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt @@ -181,10 +181,6 @@ class IrExpressionLambdaImpl( override val isSuspend: Boolean = function.isSuspend - override fun isReturnFromMe(labelName: String): Boolean { - return false //always false - } - // This name doesn't actually matter: it is used internally to tell this lambda's captured // arguments apart from any other scope's. So long as it's unique, any value is fine. // This particular string slightly aids in debugging internal compiler errors as it at least diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrSourceCompilerForInline.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrSourceCompilerForInline.kt index d838d691ed1..14104b2fe10 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrSourceCompilerForInline.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrSourceCompilerForInline.kt @@ -24,10 +24,10 @@ import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.descriptors.IrBasedSimpleFunctionDescriptor import org.jetbrains.kotlin.ir.descriptors.toIrBasedDescriptor import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression +import org.jetbrains.kotlin.ir.expressions.IrLoop import org.jetbrains.kotlin.ir.util.isSuspend import org.jetbrains.kotlin.ir.util.module import org.jetbrains.kotlin.ir.util.parentAsClass -import org.jetbrains.kotlin.load.kotlin.* import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.doNotAnalyze import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.SUSPENSION_POINT_INSIDE_MONITOR @@ -36,7 +36,6 @@ import org.jetbrains.org.objectweb.asm.* import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter import org.jetbrains.org.objectweb.asm.commons.Method import org.jetbrains.org.objectweb.asm.tree.MethodNode -import java.io.File class IrSourceCompilerForInline( override val state: GenerationState, @@ -107,9 +106,9 @@ class IrSourceCompilerForInline( override fun hasFinallyBlocks() = data.hasFinallyBlocks() - override fun generateFinallyBlocksIfNeeded(finallyCodegen: BaseExpressionCodegen, returnType: Type, afterReturnLabel: Label) { - require(finallyCodegen is ExpressionCodegen) - finallyCodegen.generateFinallyBlocksIfNeeded(returnType, afterReturnLabel, data) + override fun generateFinallyBlocksIfNeeded(codegen: BaseExpressionCodegen, returnType: Type, afterReturnLabel: Label, target: Label?) { + require(codegen is ExpressionCodegen) + codegen.generateFinallyBlocksIfNeeded(returnType, afterReturnLabel, data, target) } override fun createCodegenForExternalFinallyBlockGenerationOnNonLocalReturn(finallyNode: MethodNode, curFinallyDepth: Int) = @@ -139,9 +138,15 @@ class IrSourceCompilerForInline( override val compilationContextFunctionDescriptor: FunctionDescriptor get() = generateSequence(codegen) { it.inlinedInto }.last().irFunction.toIrBasedDescriptor() - override fun getContextLabels(): Set { - val name = codegen.irFunction.name.asString() - return setOf(name) + override fun getContextLabels(): Map { + val result = mutableMapOf(codegen.irFunction.name.asString() to null) + for (info in data.infos) { + if (info !is LoopInfo) + continue + result[info.loop.nonLocalReturnLabel(false)] = info.continueLabel + result[info.loop.nonLocalReturnLabel(true)] = info.breakLabel + } + return result } // TODO: Find a way to avoid using PSI here @@ -161,3 +166,6 @@ private tailrec fun IrDeclaration.isInlineOrInsideInline(): Boolean { if (parent !is IrDeclaration) return false return parent.isInlineOrInsideInline() } + +// TODO generate better labels; this is unique (includes the object's address), but not very descriptive +internal fun IrLoop.nonLocalReturnLabel(forBreak: Boolean): String = "$this\$${if (forBreak) "break" else "continue"}" diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGenerator.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGenerator.kt new file mode 100644 index 00000000000..79b5d8d118d --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGenerator.kt @@ -0,0 +1,5 @@ +// FILE: 1.kt +inline fun runReturning(f: () -> Nothing): Nothing = f() + +// FILE: 2.kt +fun box() = Array(1) { runReturning { return@Array "OK" } }[0] diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorCatch.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorCatch.kt new file mode 100644 index 00000000000..68a4b1488c0 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorCatch.kt @@ -0,0 +1,24 @@ +// FILE: 1.kt +inline fun runReturning(f: () -> Nothing): Nothing = f() + +// FILE: 2.kt +fun box(): String { + var r = "" + val x = Array(1) ext@{ + try { + Array(1) { + try { + runReturning { throw RuntimeException() } + } catch (e: Throwable) { + r += "1" + return@ext "OK" + } finally { + r += "2" + } + }[0] + } finally { + r += "3" + } + }[0] + return if (r == "123") x else r +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorNested.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorNested.kt new file mode 100644 index 00000000000..a121048e30f --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorNested.kt @@ -0,0 +1,5 @@ +// FILE: 1.kt +inline fun runReturning(f: () -> Nothing): Nothing = f() + +// FILE: 2.kt +fun box() = Array(1) { run { runReturning { return@Array "OK" } } }[0] diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCapture.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCapture.kt new file mode 100644 index 00000000000..88a7fa26696 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCapture.kt @@ -0,0 +1,8 @@ +// FILE: 1.kt +inline fun runReturning(f: () -> Nothing): Nothing = f() + +// FILE: 2.kt +fun box(): String { + val result = "OK" + return Array(1) { run { runReturning { return@Array result } } }[0] +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCatch.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCatch.kt new file mode 100644 index 00000000000..8153ab263b0 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCatch.kt @@ -0,0 +1,22 @@ +// FILE: 1.kt +inline fun runReturning(f: () -> Nothing): Nothing = f() + +// FILE: 2.kt +fun box(): String { + var r = "" + val x = try { + Array(1) { + try { + runReturning { throw RuntimeException() } + } finally { + r += "1" + } + }[0] + } catch (e: Throwable) { + r += "2" + "OK" + } finally { + r += "3" + } + return if (r == "123") x else r +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinally.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinally.kt new file mode 100644 index 00000000000..7b750cace35 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinally.kt @@ -0,0 +1,19 @@ +// FILE: 1.kt +inline fun runReturning(f: () -> Nothing): Nothing = f() + +// FILE: 2.kt +fun box(): String { + var r = "" + val x = try { + Array(1) { + try { + runReturning { return@Array "OK" } + } finally { + r += "O" + } + }[0] + } finally { + r += "K" + } + return r +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2.kt new file mode 100644 index 00000000000..da8cef6c7e9 --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2.kt @@ -0,0 +1,25 @@ +// FILE: 1.kt +inline fun runReturning(f: () -> Nothing): Nothing = f() + +// FILE: 2.kt +fun box(): String { + var r = "" + val x = try { + Array(1) ext@{ + try { + Array(1) { + try { + runReturning { return@ext "OK" } + } finally { + r += "1" + } + }[0] + } finally { + r += "2" + } + }[0] + } finally { + r += "3" + } + return if (r == "123") x else r +} diff --git a/compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2_2.kt b/compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2_2.kt new file mode 100644 index 00000000000..89c0e47d0ad --- /dev/null +++ b/compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2_2.kt @@ -0,0 +1,25 @@ +// FILE: 1.kt +inline fun runReturning(f: () -> Nothing): Nothing = f() + +// FILE: 2.kt +fun box(): String { + var r = "" + val x = try { + Array(1) ext@{ + try { + Array(1) { + try { + runReturning { return@Array "OK" } + } finally { + r += "1" + } + }[0] + } finally { + r += "2" + } + }[0] + } finally { + r += "3" + } + return if (r == "123") x else r +} diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java index a1c375e4b7f..e0538e0f37e 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/BlackBoxInlineCodegenTestGenerated.java @@ -2420,6 +2420,46 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo runTest("compiler/testData/codegen/boxInline/nonLocalReturns/explicitLocalReturn.kt"); } + @TestMetadata("fromArrayGenerator.kt") + public void testFromArrayGenerator() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGenerator.kt"); + } + + @TestMetadata("fromArrayGeneratorCatch.kt") + public void testFromArrayGeneratorCatch() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorCatch.kt"); + } + + @TestMetadata("fromArrayGeneratorNested.kt") + public void testFromArrayGeneratorNested() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorNested.kt"); + } + + @TestMetadata("fromArrayGeneratorWithCapture.kt") + public void testFromArrayGeneratorWithCapture() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCapture.kt"); + } + + @TestMetadata("fromArrayGeneratorWithCatch.kt") + public void testFromArrayGeneratorWithCatch() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCatch.kt"); + } + + @TestMetadata("fromArrayGeneratorWithFinally.kt") + public void testFromArrayGeneratorWithFinally() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinally.kt"); + } + + @TestMetadata("fromArrayGeneratorWithFinallyX2.kt") + public void testFromArrayGeneratorWithFinallyX2() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2.kt"); + } + + @TestMetadata("fromArrayGeneratorWithFinallyX2_2.kt") + public void testFromArrayGeneratorWithFinallyX2_2() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2_2.kt"); + } + @TestMetadata("fromInterfaceDefaultGetter.kt") public void testFromInterfaceDefaultGetter() throws Exception { runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromInterfaceDefaultGetter.kt"); diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java index d9bc3ce43a5..d6cd24012ad 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/CompileKotlinAgainstInlineKotlinTestGenerated.java @@ -2420,6 +2420,46 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi runTest("compiler/testData/codegen/boxInline/nonLocalReturns/explicitLocalReturn.kt"); } + @TestMetadata("fromArrayGenerator.kt") + public void testFromArrayGenerator() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGenerator.kt"); + } + + @TestMetadata("fromArrayGeneratorCatch.kt") + public void testFromArrayGeneratorCatch() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorCatch.kt"); + } + + @TestMetadata("fromArrayGeneratorNested.kt") + public void testFromArrayGeneratorNested() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorNested.kt"); + } + + @TestMetadata("fromArrayGeneratorWithCapture.kt") + public void testFromArrayGeneratorWithCapture() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCapture.kt"); + } + + @TestMetadata("fromArrayGeneratorWithCatch.kt") + public void testFromArrayGeneratorWithCatch() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCatch.kt"); + } + + @TestMetadata("fromArrayGeneratorWithFinally.kt") + public void testFromArrayGeneratorWithFinally() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinally.kt"); + } + + @TestMetadata("fromArrayGeneratorWithFinallyX2.kt") + public void testFromArrayGeneratorWithFinallyX2() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2.kt"); + } + + @TestMetadata("fromArrayGeneratorWithFinallyX2_2.kt") + public void testFromArrayGeneratorWithFinallyX2_2() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2_2.kt"); + } + @TestMetadata("fromInterfaceDefaultGetter.kt") public void testFromInterfaceDefaultGetter() throws Exception { runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromInterfaceDefaultGetter.kt"); diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java index 5db3b918dbf..122840b7164 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrBlackBoxInlineCodegenTestGenerated.java @@ -2420,6 +2420,46 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli runTest("compiler/testData/codegen/boxInline/nonLocalReturns/explicitLocalReturn.kt"); } + @TestMetadata("fromArrayGenerator.kt") + public void testFromArrayGenerator() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGenerator.kt"); + } + + @TestMetadata("fromArrayGeneratorCatch.kt") + public void testFromArrayGeneratorCatch() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorCatch.kt"); + } + + @TestMetadata("fromArrayGeneratorNested.kt") + public void testFromArrayGeneratorNested() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorNested.kt"); + } + + @TestMetadata("fromArrayGeneratorWithCapture.kt") + public void testFromArrayGeneratorWithCapture() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCapture.kt"); + } + + @TestMetadata("fromArrayGeneratorWithCatch.kt") + public void testFromArrayGeneratorWithCatch() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCatch.kt"); + } + + @TestMetadata("fromArrayGeneratorWithFinally.kt") + public void testFromArrayGeneratorWithFinally() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinally.kt"); + } + + @TestMetadata("fromArrayGeneratorWithFinallyX2.kt") + public void testFromArrayGeneratorWithFinallyX2() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2.kt"); + } + + @TestMetadata("fromArrayGeneratorWithFinallyX2_2.kt") + public void testFromArrayGeneratorWithFinallyX2_2() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2_2.kt"); + } + @TestMetadata("fromInterfaceDefaultGetter.kt") public void testFromInterfaceDefaultGetter() throws Exception { runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromInterfaceDefaultGetter.kt"); diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java index 50ee263b67e..d65f800fc3c 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrCompileKotlinAgainstInlineKotlinTestGenerated.java @@ -2420,6 +2420,46 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC runTest("compiler/testData/codegen/boxInline/nonLocalReturns/explicitLocalReturn.kt"); } + @TestMetadata("fromArrayGenerator.kt") + public void testFromArrayGenerator() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGenerator.kt"); + } + + @TestMetadata("fromArrayGeneratorCatch.kt") + public void testFromArrayGeneratorCatch() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorCatch.kt"); + } + + @TestMetadata("fromArrayGeneratorNested.kt") + public void testFromArrayGeneratorNested() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorNested.kt"); + } + + @TestMetadata("fromArrayGeneratorWithCapture.kt") + public void testFromArrayGeneratorWithCapture() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCapture.kt"); + } + + @TestMetadata("fromArrayGeneratorWithCatch.kt") + public void testFromArrayGeneratorWithCatch() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCatch.kt"); + } + + @TestMetadata("fromArrayGeneratorWithFinally.kt") + public void testFromArrayGeneratorWithFinally() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinally.kt"); + } + + @TestMetadata("fromArrayGeneratorWithFinallyX2.kt") + public void testFromArrayGeneratorWithFinallyX2() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2.kt"); + } + + @TestMetadata("fromArrayGeneratorWithFinallyX2_2.kt") + public void testFromArrayGeneratorWithFinallyX2_2() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2_2.kt"); + } + @TestMetadata("fromInterfaceDefaultGetter.kt") public void testFromInterfaceDefaultGetter() throws Exception { runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromInterfaceDefaultGetter.kt"); diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/JvmIrAgainstOldBoxInlineTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/JvmIrAgainstOldBoxInlineTestGenerated.java index 7fbe2635784..05cc786a511 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/JvmIrAgainstOldBoxInlineTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/JvmIrAgainstOldBoxInlineTestGenerated.java @@ -2420,6 +2420,46 @@ public class JvmIrAgainstOldBoxInlineTestGenerated extends AbstractJvmIrAgainstO runTest("compiler/testData/codegen/boxInline/nonLocalReturns/explicitLocalReturn.kt"); } + @TestMetadata("fromArrayGenerator.kt") + public void testFromArrayGenerator() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGenerator.kt"); + } + + @TestMetadata("fromArrayGeneratorCatch.kt") + public void testFromArrayGeneratorCatch() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorCatch.kt"); + } + + @TestMetadata("fromArrayGeneratorNested.kt") + public void testFromArrayGeneratorNested() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorNested.kt"); + } + + @TestMetadata("fromArrayGeneratorWithCapture.kt") + public void testFromArrayGeneratorWithCapture() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCapture.kt"); + } + + @TestMetadata("fromArrayGeneratorWithCatch.kt") + public void testFromArrayGeneratorWithCatch() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCatch.kt"); + } + + @TestMetadata("fromArrayGeneratorWithFinally.kt") + public void testFromArrayGeneratorWithFinally() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinally.kt"); + } + + @TestMetadata("fromArrayGeneratorWithFinallyX2.kt") + public void testFromArrayGeneratorWithFinallyX2() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2.kt"); + } + + @TestMetadata("fromArrayGeneratorWithFinallyX2_2.kt") + public void testFromArrayGeneratorWithFinallyX2_2() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2_2.kt"); + } + @TestMetadata("fromInterfaceDefaultGetter.kt") public void testFromInterfaceDefaultGetter() throws Exception { runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromInterfaceDefaultGetter.kt"); diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/JvmOldAgainstIrBoxInlineTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/JvmOldAgainstIrBoxInlineTestGenerated.java index f66d8be4f83..60080a06436 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/JvmOldAgainstIrBoxInlineTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/JvmOldAgainstIrBoxInlineTestGenerated.java @@ -2420,6 +2420,46 @@ public class JvmOldAgainstIrBoxInlineTestGenerated extends AbstractJvmOldAgainst runTest("compiler/testData/codegen/boxInline/nonLocalReturns/explicitLocalReturn.kt"); } + @TestMetadata("fromArrayGenerator.kt") + public void testFromArrayGenerator() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGenerator.kt"); + } + + @TestMetadata("fromArrayGeneratorCatch.kt") + public void testFromArrayGeneratorCatch() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorCatch.kt"); + } + + @TestMetadata("fromArrayGeneratorNested.kt") + public void testFromArrayGeneratorNested() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorNested.kt"); + } + + @TestMetadata("fromArrayGeneratorWithCapture.kt") + public void testFromArrayGeneratorWithCapture() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCapture.kt"); + } + + @TestMetadata("fromArrayGeneratorWithCatch.kt") + public void testFromArrayGeneratorWithCatch() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCatch.kt"); + } + + @TestMetadata("fromArrayGeneratorWithFinally.kt") + public void testFromArrayGeneratorWithFinally() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinally.kt"); + } + + @TestMetadata("fromArrayGeneratorWithFinallyX2.kt") + public void testFromArrayGeneratorWithFinallyX2() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2.kt"); + } + + @TestMetadata("fromArrayGeneratorWithFinallyX2_2.kt") + public void testFromArrayGeneratorWithFinallyX2_2() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2_2.kt"); + } + @TestMetadata("fromInterfaceDefaultGetter.kt") public void testFromInterfaceDefaultGetter() throws Exception { runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromInterfaceDefaultGetter.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenInlineES6TestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenInlineES6TestGenerated.java index 11e204014bb..63c56be9b9d 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenInlineES6TestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenInlineES6TestGenerated.java @@ -2170,6 +2170,46 @@ public class IrJsCodegenInlineES6TestGenerated extends AbstractIrJsCodegenInline runTest("compiler/testData/codegen/boxInline/nonLocalReturns/explicitLocalReturn.kt"); } + @TestMetadata("fromArrayGenerator.kt") + public void testFromArrayGenerator() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGenerator.kt"); + } + + @TestMetadata("fromArrayGeneratorCatch.kt") + public void testFromArrayGeneratorCatch() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorCatch.kt"); + } + + @TestMetadata("fromArrayGeneratorNested.kt") + public void testFromArrayGeneratorNested() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorNested.kt"); + } + + @TestMetadata("fromArrayGeneratorWithCapture.kt") + public void testFromArrayGeneratorWithCapture() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCapture.kt"); + } + + @TestMetadata("fromArrayGeneratorWithCatch.kt") + public void testFromArrayGeneratorWithCatch() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCatch.kt"); + } + + @TestMetadata("fromArrayGeneratorWithFinally.kt") + public void testFromArrayGeneratorWithFinally() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinally.kt"); + } + + @TestMetadata("fromArrayGeneratorWithFinallyX2.kt") + public void testFromArrayGeneratorWithFinallyX2() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2.kt"); + } + + @TestMetadata("fromArrayGeneratorWithFinallyX2_2.kt") + public void testFromArrayGeneratorWithFinallyX2_2() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2_2.kt"); + } + @TestMetadata("fromInterfaceDefaultGetter.kt") public void testFromInterfaceDefaultGetter() throws Exception { runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromInterfaceDefaultGetter.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenInlineTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenInlineTestGenerated.java index 0d6fbc8db9c..0890c06420f 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenInlineTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenInlineTestGenerated.java @@ -2170,6 +2170,46 @@ public class IrJsCodegenInlineTestGenerated extends AbstractIrJsCodegenInlineTes runTest("compiler/testData/codegen/boxInline/nonLocalReturns/explicitLocalReturn.kt"); } + @TestMetadata("fromArrayGenerator.kt") + public void testFromArrayGenerator() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGenerator.kt"); + } + + @TestMetadata("fromArrayGeneratorCatch.kt") + public void testFromArrayGeneratorCatch() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorCatch.kt"); + } + + @TestMetadata("fromArrayGeneratorNested.kt") + public void testFromArrayGeneratorNested() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorNested.kt"); + } + + @TestMetadata("fromArrayGeneratorWithCapture.kt") + public void testFromArrayGeneratorWithCapture() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCapture.kt"); + } + + @TestMetadata("fromArrayGeneratorWithCatch.kt") + public void testFromArrayGeneratorWithCatch() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCatch.kt"); + } + + @TestMetadata("fromArrayGeneratorWithFinally.kt") + public void testFromArrayGeneratorWithFinally() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinally.kt"); + } + + @TestMetadata("fromArrayGeneratorWithFinallyX2.kt") + public void testFromArrayGeneratorWithFinallyX2() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2.kt"); + } + + @TestMetadata("fromArrayGeneratorWithFinallyX2_2.kt") + public void testFromArrayGeneratorWithFinallyX2_2() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2_2.kt"); + } + @TestMetadata("fromInterfaceDefaultGetter.kt") public void testFromInterfaceDefaultGetter() throws Exception { runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromInterfaceDefaultGetter.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenInlineTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenInlineTestGenerated.java index ac312ac3401..bcc0eb78cff 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenInlineTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenInlineTestGenerated.java @@ -2170,6 +2170,46 @@ public class JsCodegenInlineTestGenerated extends AbstractJsCodegenInlineTest { runTest("compiler/testData/codegen/boxInline/nonLocalReturns/explicitLocalReturn.kt"); } + @TestMetadata("fromArrayGenerator.kt") + public void testFromArrayGenerator() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGenerator.kt"); + } + + @TestMetadata("fromArrayGeneratorCatch.kt") + public void testFromArrayGeneratorCatch() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorCatch.kt"); + } + + @TestMetadata("fromArrayGeneratorNested.kt") + public void testFromArrayGeneratorNested() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorNested.kt"); + } + + @TestMetadata("fromArrayGeneratorWithCapture.kt") + public void testFromArrayGeneratorWithCapture() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCapture.kt"); + } + + @TestMetadata("fromArrayGeneratorWithCatch.kt") + public void testFromArrayGeneratorWithCatch() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithCatch.kt"); + } + + @TestMetadata("fromArrayGeneratorWithFinally.kt") + public void testFromArrayGeneratorWithFinally() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinally.kt"); + } + + @TestMetadata("fromArrayGeneratorWithFinallyX2.kt") + public void testFromArrayGeneratorWithFinallyX2() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2.kt"); + } + + @TestMetadata("fromArrayGeneratorWithFinallyX2_2.kt") + public void testFromArrayGeneratorWithFinallyX2_2() throws Exception { + runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromArrayGeneratorWithFinallyX2_2.kt"); + } + @TestMetadata("fromInterfaceDefaultGetter.kt") public void testFromInterfaceDefaultGetter() throws Exception { runTest("compiler/testData/codegen/boxInline/nonLocalReturns/fromInterfaceDefaultGetter.kt"); From ad53fc931e6ad9e1705d97bd895f0f07bd1820de Mon Sep 17 00:00:00 2001 From: pyos Date: Tue, 12 May 2020 14:53:18 +0200 Subject: [PATCH 016/260] JVM: optimize temporary `kotlin.jvm.internal.Ref`s as well i.e. remove the condition that there must be an LVT entry. Such temporary `Ref`s can be created, for example, by the JVM_IR backend if a lambda inlined at an IR level (e.g. argument to `assert`/`Array`) is the target of a non-local return from a function inlined at bytecode level (e.g. `run`): IntArray(n) { i -> intOrNull?.let { return@IntArray it } someInt } -> val `tmp$0` = IntArray(n) for (i in 0 until `tmp$0`.size) { var `tmp$1`: Int do { intOrNull?.let { `tmp$1` = it // causes `tmp$1` to become an IntRef break } `tmp$1` = someInt } while (false) `tmp$0`[i] = `tmp$1` } --- ...pturedVarsOptimizationMethodTransformer.kt | 169 ++++++------------ .../codegen/FirBytecodeTextTestGenerated.java | 6 + .../returnValueOfArrayConstructor.kt | 5 + .../codegen/BytecodeTextTestGenerated.java | 6 + .../codegen/IrBytecodeTextTestGenerated.java | 6 + 5 files changed, 78 insertions(+), 114 deletions(-) create mode 100644 compiler/testData/codegen/bytecodeText/capturedVarsOptimization/returnValueOfArrayConstructor.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/CapturedVarsOptimizationMethodTransformer.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/CapturedVarsOptimizationMethodTransformer.kt index 2bf01a52891..373cf3307f7 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/CapturedVarsOptimizationMethodTransformer.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/CapturedVarsOptimizationMethodTransformer.kt @@ -37,17 +37,9 @@ class CapturedVarsOptimizationMethodTransformer : MethodTransformer() { // Tracks proper usages of objects corresponding to captured variables. // - // The 'kotlin.jvm.internal.Ref.*' instance can be replaced with a local variable, - // if all of the following conditions are satisfied: - // * It is created inside a current method. - // * The only permitted operations on it are: - // - store to a local variable - // - ALOAD, ASTORE - // - DUP, POP - // - GETFIELD .element, PUTFIELD .element - // * There's a corresponding local variable definition, - // and all ALOAD/ASTORE instructions operate on that particular local variable. - // * Its 'element' field is initialized at start of local variable visibility range. + // The 'kotlin.jvm.internal.Ref.*' instance can be replaced with a local variable, if + // * it is created inside a current method; + // * the only operations on it are ALOAD, ASTORE, DUP, POP, GETFIELD element, PUTFIELD element. // // Note that for code that doesn't create Ref objects explicitly these conditions are true, // unless the Ref object escapes to a local class constructor (including local classes for lambdas). @@ -58,18 +50,9 @@ class CapturedVarsOptimizationMethodTransformer : MethodTransformer() { var initCallInsn: MethodInsnNode? = null var localVar: LocalVariableNode? = null var localVarIndex = -1 - val astoreInsns: MutableCollection = LinkedHashSet() - val aloadInsns: MutableCollection = LinkedHashSet() - val stackInsns: MutableCollection = LinkedHashSet() + val wrapperInsns: MutableCollection = LinkedHashSet() val getFieldInsns: MutableCollection = LinkedHashSet() val putFieldInsns: MutableCollection = LinkedHashSet() - var cleanVarInstruction: VarInsnNode? = null - - fun canRewrite(): Boolean = - !hazard && - initCallInsn != null && - localVar != null && - localVarIndex >= 0 override fun onUseAsTainted() { hazard = true @@ -79,26 +62,29 @@ class CapturedVarsOptimizationMethodTransformer : MethodTransformer() { private class Transformer(private val internalClassName: String, private val methodNode: MethodNode) { private val refValues = ArrayList() private val refValuesByNewInsn = LinkedHashMap() - private val insns = methodNode.instructions.toArray() - private lateinit var frames: Array?> - - val hasRewritableRefValues: Boolean - get() = refValues.isNotEmpty() fun run() { createRefValues() - if (!hasRewritableRefValues) return + if (refValues.isEmpty()) return - analyze() - if (!hasRewritableRefValues) return + val frames = analyze(internalClassName, methodNode, Interpreter()) + trackPops(frames) + assignLocalVars(frames) - rewrite() + for (refValue in refValues) { + if (!refValue.hazard) { + rewriteRefValue(refValue) + } + } + + methodNode.removeEmptyCatchBlocks() + methodNode.removeUnusedLocalVariables() } private fun AbstractInsnNode.getIndex() = methodNode.instructions.indexOf(this) private fun createRefValues() { - for (insn in insns) { + for (insn in methodNode.instructions) { if (insn.opcode == Opcodes.NEW && insn is TypeInsnNode) { val type = Type.getObjectType(insn.desc) if (AsmTypes.isSharedVarType(type)) { @@ -113,19 +99,15 @@ class CapturedVarsOptimizationMethodTransformer : MethodTransformer() { private inner class Interpreter : ReferenceTrackingInterpreter() { override fun newOperation(insn: AbstractInsnNode): BasicValue = - refValuesByNewInsn[insn]?.let { descriptor -> - ProperTrackedReferenceValue(descriptor.refType, descriptor) - } - ?: super.newOperation(insn) + refValuesByNewInsn[insn]?.let { ProperTrackedReferenceValue(it.refType, it) } ?: super.newOperation(insn) override fun processRefValueUsage(value: TrackedReferenceValue, insn: AbstractInsnNode, position: Int) { for (descriptor in value.descriptors) { if (descriptor !is CapturedVarDescriptor) throw AssertionError("Unexpected descriptor: $descriptor") when { - insn.opcode == Opcodes.ALOAD -> - descriptor.aloadInsns.add(insn as VarInsnNode) - insn.opcode == Opcodes.ASTORE -> - descriptor.astoreInsns.add(insn as VarInsnNode) + insn.opcode == Opcodes.DUP -> descriptor.wrapperInsns.add(insn) + insn.opcode == Opcodes.ALOAD -> descriptor.wrapperInsns.add(insn) + insn.opcode == Opcodes.ASTORE -> descriptor.wrapperInsns.add(insn) insn.opcode == Opcodes.GETFIELD && insn is FieldInsnNode && insn.name == REF_ELEMENT_FIELD && position == 0 -> descriptor.getFieldInsns.add(insn) insn.opcode == Opcodes.PUTFIELD && insn is FieldInsnNode && insn.name == REF_ELEMENT_FIELD && position == 0 -> @@ -135,32 +117,18 @@ class CapturedVarsOptimizationMethodTransformer : MethodTransformer() { descriptor.hazard = true else descriptor.initCallInsn = insn - insn.opcode == Opcodes.DUP -> - descriptor.stackInsns.add(insn) - else -> - descriptor.hazard = true + else -> descriptor.hazard = true } } } - } - private fun analyze() { - frames = MethodTransformer.analyze(internalClassName, methodNode, Interpreter()) - trackPops() - assignLocalVars() - - refValues.removeAll { !it.canRewrite() } - } - - private fun trackPops() { - for (i in insns.indices) { + private fun trackPops(frames: Array?>) { + for ((i, insn) in methodNode.instructions.withIndex()) { val frame = frames[i] ?: continue - val insn = insns[i] - when (insn.opcode) { Opcodes.POP -> { - frame.top()?.getCapturedVarOrNull()?.run { stackInsns.add(insn) } + frame.top()?.getCapturedVarOrNull()?.run { wrapperInsns.add(insn) } } Opcodes.POP2 -> { val top = frame.top() @@ -176,7 +144,7 @@ class CapturedVarsOptimizationMethodTransformer : MethodTransformer() { private fun BasicValue.getCapturedVarOrNull() = safeAs()?.descriptor?.safeAs() - private fun assignLocalVars() { + private fun assignLocalVars(frames: Array?>) { for (localVar in methodNode.localVariables) { val type = Type.getType(localVar.desc) if (!AsmTypes.isSharedVarType(type)) continue @@ -197,51 +165,20 @@ class CapturedVarsOptimizationMethodTransformer : MethodTransformer() { for (refValue in refValues) { if (refValue.hazard) continue - val localVar = refValue.localVar ?: continue - val oldVarIndex = localVar.index - - if (refValue.valueType.size != 1) { + if (refValue.localVar == null || refValue.valueType.size != 1) { refValue.localVarIndex = methodNode.maxLocals - methodNode.maxLocals += 2 - localVar.index = refValue.localVarIndex + methodNode.maxLocals += refValue.valueType.size } else { - refValue.localVarIndex = localVar.index + refValue.localVarIndex = refValue.localVar!!.index } - - val cleanInstructions = findCleanInstructions(refValue, oldVarIndex, methodNode.instructions) - if (cleanInstructions.size > 1) { - refValue.hazard = true - continue - } - refValue.cleanVarInstruction = cleanInstructions.firstOrNull() } } - private fun findCleanInstructions(refValue: CapturedVarDescriptor, oldVarIndex: Int, instructions: InsnList): List { - return InsnSequence(instructions).filterIsInstance().filter { - it.opcode == Opcodes.ASTORE && it.`var` == oldVarIndex - }.filter { - it.previous?.opcode == Opcodes.ACONST_NULL - }.filter { - val operationIndex = instructions.indexOf(it) - val localVariableNode = refValue.localVar!! - instructions.indexOf(localVariableNode.start) < operationIndex && operationIndex < instructions.indexOf( - localVariableNode.end - ) - }.toList() - } - - private fun rewrite() { - for (refValue in refValues) { - if (!refValue.canRewrite()) continue - - rewriteRefValue(refValue) + private fun LocalVariableNode.findCleanInstructions() = + InsnSequence(methodNode.instructions).dropWhile { it != start }.takeWhile { it != end }.filter { + it is VarInsnNode && it.opcode == Opcodes.ASTORE && it.`var` == index && it.previous?.opcode == Opcodes.ACONST_NULL } - methodNode.removeEmptyCatchBlocks() - methodNode.removeUnusedLocalVariables() - } - // Be careful to not remove instructions that are the only instruction for a line number. That will // break debugging. If the previous instruction is a line number and the following instruction is // a label followed by a line number, insert a nop instead of deleting the instruction. @@ -255,34 +192,38 @@ class CapturedVarsOptimizationMethodTransformer : MethodTransformer() { private fun rewriteRefValue(capturedVar: CapturedVarDescriptor) { methodNode.instructions.run { - val localVar = capturedVar.localVar!! - localVar.signature = null - localVar.desc = capturedVar.valueType.descriptor - val loadOpcode = capturedVar.valueType.getOpcode(Opcodes.ILOAD) val storeOpcode = capturedVar.valueType.getOpcode(Opcodes.ISTORE) - if (capturedVar.putFieldInsns.none { it.getIndex() < localVar.start.getIndex() }) { - // variable needs to be initialized before its live range can begin - insertBefore(capturedVar.newInsn, InsnNode(AsmUtil.defaultValueOpcode(capturedVar.valueType))) - insertBefore(capturedVar.newInsn, VarInsnNode(storeOpcode, capturedVar.localVarIndex)) + val localVar = capturedVar.localVar + if (localVar != null) { + if (capturedVar.putFieldInsns.none { it.getIndex() < localVar.start.getIndex() }) { + // variable needs to be initialized before its live range can begin + insertBefore(capturedVar.newInsn, InsnNode(AsmUtil.defaultValueOpcode(capturedVar.valueType))) + insertBefore(capturedVar.newInsn, VarInsnNode(storeOpcode, capturedVar.localVarIndex)) + } + + for (insn in localVar.findCleanInstructions()) { + // after visiting block codegen tries to delete all allocated references: + // see ExpressionCodegen.addLeaveTaskToRemoveLocalVariableFromFrameMap + if (storeOpcode == Opcodes.ASTORE) { + set(insn.previous, InsnNode(AsmUtil.defaultValueOpcode(capturedVar.valueType))) + } else { + remove(insn.previous) + remove(insn) + } + } + + localVar.index = capturedVar.localVarIndex + localVar.desc = capturedVar.valueType.descriptor + localVar.signature = null } remove(capturedVar.newInsn) remove(capturedVar.initCallInsn!!) - - capturedVar.stackInsns.forEach { removeOrReplaceByNop(it) } - capturedVar.aloadInsns.forEach { removeOrReplaceByNop(it) } - capturedVar.astoreInsns.forEach { removeOrReplaceByNop(it) } + capturedVar.wrapperInsns.forEach { removeOrReplaceByNop(it) } capturedVar.getFieldInsns.forEach { set(it, VarInsnNode(loadOpcode, capturedVar.localVarIndex)) } capturedVar.putFieldInsns.forEach { set(it, VarInsnNode(storeOpcode, capturedVar.localVarIndex)) } - - //after visiting block codegen tries to delete all allocated references: - // see ExpressionCodegen.addLeaveTaskToRemoveLocalVariableFromFrameMap - capturedVar.cleanVarInstruction?.let { - remove(it.previous) - remove(it) - } } } diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java index 5fad7f402f5..e5c06c9afb4 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBytecodeTextTestGenerated.java @@ -974,6 +974,12 @@ public class FirBytecodeTextTestGenerated extends AbstractFirBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/capturedVarsOptimization/capturedVarsOfSize2.kt"); } + @Test + @TestMetadata("returnValueOfArrayConstructor.kt") + public void testReturnValueOfArrayConstructor() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/capturedVarsOptimization/returnValueOfArrayConstructor.kt"); + } + @Test @TestMetadata("sharedSlotsWithCapturedVars.kt") public void testSharedSlotsWithCapturedVars() throws Exception { diff --git a/compiler/testData/codegen/bytecodeText/capturedVarsOptimization/returnValueOfArrayConstructor.kt b/compiler/testData/codegen/bytecodeText/capturedVarsOptimization/returnValueOfArrayConstructor.kt new file mode 100644 index 00000000000..2887fa456fc --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/capturedVarsOptimization/returnValueOfArrayConstructor.kt @@ -0,0 +1,5 @@ +fun f() = IntArray(1) { run { return@IntArray 1 } } + +// On JVM_IR, the return is an assignment to a captured var followed by +// a non-local `break` from a `do ... while (false)`. The var should be optimized. +// 0 IntRef diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeTextTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeTextTestGenerated.java index 6c133049b2c..d980d6eec80 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BytecodeTextTestGenerated.java @@ -974,6 +974,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/capturedVarsOptimization/capturedVarsOfSize2.kt"); } + @Test + @TestMetadata("returnValueOfArrayConstructor.kt") + public void testReturnValueOfArrayConstructor() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/capturedVarsOptimization/returnValueOfArrayConstructor.kt"); + } + @Test @TestMetadata("sharedSlotsWithCapturedVars.kt") public void testSharedSlotsWithCapturedVars() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java index 22ab68493f9..1ff1b1efe20 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBytecodeTextTestGenerated.java @@ -974,6 +974,12 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/capturedVarsOptimization/capturedVarsOfSize2.kt"); } + @Test + @TestMetadata("returnValueOfArrayConstructor.kt") + public void testReturnValueOfArrayConstructor() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/capturedVarsOptimization/returnValueOfArrayConstructor.kt"); + } + @Test @TestMetadata("sharedSlotsWithCapturedVars.kt") public void testSharedSlotsWithCapturedVars() throws Exception { From bd3bc13e752dd68d43baa62b7e23e285012b499e Mon Sep 17 00:00:00 2001 From: pyos Date: Tue, 5 Jan 2021 12:19:20 +0100 Subject: [PATCH 017/260] JVM_IR: give loops somewhat more debuggable labels --- .../jetbrains/kotlin/backend/jvm/JvmLower.kt | 2 +- .../jvm/codegen/IrSourceCompilerForInline.kt | 3 +- .../BytecodeInliningPreparationLowering.kt | 56 +++++++++++++++++++ ...eDeclarationsThatWouldBeInlinedLowering.kt | 55 ------------------ 4 files changed, 58 insertions(+), 58 deletions(-) create mode 100644 compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/BytecodeInliningPreparationLowering.kt delete mode 100644 compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/RemoveDeclarationsThatWouldBeInlinedLowering.kt diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt index 8c9224fac46..cafe0c14140 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt @@ -394,7 +394,7 @@ val jvmPhases = NamedCompilerPhase( generateMultifileFacadesPhase then resolveInlineCallsPhase then // should be last transformation - removeDeclarationsThatWouldBeInlined then + prepareForBytecodeInlining then validateIrAfterLowering ) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrSourceCompilerForInline.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrSourceCompilerForInline.kt index 14104b2fe10..70f4b80a811 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrSourceCompilerForInline.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrSourceCompilerForInline.kt @@ -167,5 +167,4 @@ private tailrec fun IrDeclaration.isInlineOrInsideInline(): Boolean { return parent.isInlineOrInsideInline() } -// TODO generate better labels; this is unique (includes the object's address), but not very descriptive -internal fun IrLoop.nonLocalReturnLabel(forBreak: Boolean): String = "$this\$${if (forBreak) "break" else "continue"}" +internal fun IrLoop.nonLocalReturnLabel(forBreak: Boolean): String = "${label!!}\$${if (forBreak) "break" else "continue"}" diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/BytecodeInliningPreparationLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/BytecodeInliningPreparationLowering.kt new file mode 100644 index 00000000000..5f023370765 --- /dev/null +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/BytecodeInliningPreparationLowering.kt @@ -0,0 +1,56 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.backend.jvm.lower + +import org.jetbrains.kotlin.backend.common.FileLoweringPass +import org.jetbrains.kotlin.backend.common.phaser.makeIrModulePhase +import org.jetbrains.kotlin.backend.jvm.JvmBackendContext +import org.jetbrains.kotlin.backend.jvm.codegen.isInlineIrExpression +import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.expressions.IrFunctionReference +import org.jetbrains.kotlin.ir.expressions.IrLoop +import org.jetbrains.kotlin.ir.util.parentAsClass +import org.jetbrains.kotlin.ir.visitors.IrElementVisitor + +internal val prepareForBytecodeInlining = makeIrModulePhase( + ::BytecodeInliningPreparationLowering, + name = "BytecodeInliningPreparation", + description = "Remove inline lambda declarations and label all loops" +) + +private class BytecodeInliningPreparationLowering(val context: JvmBackendContext) : FileLoweringPass { + override fun lower(irFile: IrFile) { + val loweredLambdasToDelete = mutableSetOf() + irFile.accept(object : IrElementVisitor { + // This counter is intentionally not local to every declaration because their names might clash. + private var counter = 0 + + override fun visitElement(element: IrElement, data: String) = + element.acceptChildren(this, if (element is IrDeclarationWithName) "$data${element.name}$" else data) + + override fun visitLoop(loop: IrLoop, data: String) { + // Give all loops unique labels so that we can generate unambiguous instructions for non-local + // `break`/`continue` statements. + loop.label = "$data${++counter}" + super.visitLoop(loop, data) + } + + override fun visitFunctionReference(expression: IrFunctionReference, data: String) { + // Remove inline lambdas from their declaration parents. They should not appear in the output + // bytecode in non-inlined form. + if (expression.origin.isInlineIrExpression()) { + loweredLambdasToDelete.add(expression.symbol.owner) + } + super.visitFunctionReference(expression, data) + } + }, "") + + for (irClass in loweredLambdasToDelete.mapTo(mutableSetOf()) { it.parentAsClass }) { + irClass.declarations.removeAll(loweredLambdasToDelete) + } + } +} diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/RemoveDeclarationsThatWouldBeInlinedLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/RemoveDeclarationsThatWouldBeInlinedLowering.kt deleted file mode 100644 index c3637e0a17f..00000000000 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/RemoveDeclarationsThatWouldBeInlinedLowering.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.backend.jvm.lower - -import org.jetbrains.kotlin.backend.common.FileLoweringPass -import org.jetbrains.kotlin.backend.common.phaser.makeIrModulePhase -import org.jetbrains.kotlin.backend.jvm.JvmBackendContext -import org.jetbrains.kotlin.backend.jvm.codegen.isInlineIrExpression -import org.jetbrains.kotlin.ir.IrElement -import org.jetbrains.kotlin.ir.IrStatement -import org.jetbrains.kotlin.ir.declarations.IrClass -import org.jetbrains.kotlin.ir.declarations.IrFile -import org.jetbrains.kotlin.ir.declarations.IrFunction -import org.jetbrains.kotlin.ir.expressions.IrFunctionReference -import org.jetbrains.kotlin.ir.visitors.* - -internal val removeDeclarationsThatWouldBeInlined = makeIrModulePhase( - ::RemoveDeclarationsThatWouldBeInlinedLowering, - name = "RemoveInlinedDeclarations", - description = "Rename declaration that should be inlined" -) - -// Removes all functions which are only used as arguments to inline functions. It's -// important that this phase runs right before codegen, since we need the bodies of lambdas to -// be lowered for inline codegen. Conversely, since this phase runs right before codegen we can -// assume that all remaining function references are only used as arguments to inline functions - -// otherwise they would have been lowered. -private class RemoveDeclarationsThatWouldBeInlinedLowering(val context: JvmBackendContext) : FileLoweringPass { - override fun lower(irFile: IrFile) { - val loweredLambdasToDelete = mutableSetOf() - - irFile.acceptVoid(object : IrElementVisitorVoid { - override fun visitElement(element: IrElement) = element.acceptChildrenVoid(this) - - override fun visitFunctionReference(expression: IrFunctionReference) { - if (expression.origin.isInlineIrExpression()) { - loweredLambdasToDelete.add(expression.symbol.owner) - } - - expression.acceptChildrenVoid(this) - } - }) - - irFile.transformChildrenVoid(object : IrElementTransformerVoid() { - override fun visitClass(declaration: IrClass): IrStatement { - return super.visitClass(declaration).also { - declaration.declarations.removeAll(loweredLambdasToDelete) - } - } - }) - } -} From 8172ae5d89d655a5fc12c39d1bf4ea3a576853bd Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Mon, 1 Feb 2021 15:52:14 +0100 Subject: [PATCH 018/260] Fix codegen test classLiteralWithExpectedType.kt on Android Similar to changes in d022bb0248a, this test started to fail because `AnnotationTarget.TYPE` is mapped to `ElementType.TYPE_USE` if JVM target is >= 1.8. In codegen tests on Android, we're running the emulator of version 19 which is less than 26, where `TYPE_USE` has first appeared. --- .../annotations/onTypes/classLiteralWithExpectedType.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/testData/codegen/box/reflection/annotations/onTypes/classLiteralWithExpectedType.kt b/compiler/testData/codegen/box/reflection/annotations/onTypes/classLiteralWithExpectedType.kt index 43923fce2a6..8f430ae0cd2 100644 --- a/compiler/testData/codegen/box/reflection/annotations/onTypes/classLiteralWithExpectedType.kt +++ b/compiler/testData/codegen/box/reflection/annotations/onTypes/classLiteralWithExpectedType.kt @@ -1,6 +1,8 @@ // IGNORE_BACKEND_FIR: JVM_IR // TARGET_BACKEND: JVM // WITH_REFLECT +// JVM_TARGET: 1.6 + package test import kotlin.reflect.KClass @@ -23,4 +25,4 @@ fun box(): String { ) return "OK" -} \ No newline at end of file +} From 4ec369ac5be9dba9505948aab328431929d77e1a Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Mon, 1 Feb 2021 16:03:39 +0300 Subject: [PATCH 019/260] JVM_IR fix special bridge generation for inline classes --- .../FirBlackBoxCodegenTestGenerated.java | 28 +++++++++ .../backend/jvm/lower/BridgeLowering.kt | 18 +++--- .../inlineCollectionOfInlineClass.kt | 43 ++++++++++++++ .../inlineListOfInlineClass.kt | 56 ++++++++++++++++++ .../inlineMapOfInlineClass.kt | 57 +++++++++++++++++++ .../UIntArrayWithFullJdk_ir.txt | 2 +- .../collection_ir.txt | 2 +- .../inlineCollectionOfInlineClass/list_ir.txt | 6 +- .../inlineCollectionOfInlineClass/map_ir.txt | 5 +- .../mutableCollection_ir.txt | 2 +- .../mutableList_ir.txt | 6 +- .../mutableMap_ir.txt | 5 +- .../mutableSet2_ir.txt | 2 +- .../mutableSet_ir.txt | 2 +- .../inlineCollectionOfInlineClass/set_ir.txt | 2 +- .../specialBridges/unsignedArray_ir.txt | 2 +- .../codegen/BlackBoxCodegenTestGenerated.java | 28 +++++++++ .../IrBlackBoxCodegenTestGenerated.java | 28 +++++++++ .../LightAnalysisModeTestGenerated.java | 28 +++++++++ .../IrJsCodegenBoxES6TestGenerated.java | 28 +++++++++ .../IrJsCodegenBoxTestGenerated.java | 28 +++++++++ .../semantics/JsCodegenBoxTestGenerated.java | 28 +++++++++ .../IrCodegenBoxWasmTestGenerated.java | 28 +++++++++ 23 files changed, 410 insertions(+), 24 deletions(-) create mode 100644 compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineCollectionOfInlineClass.kt create mode 100644 compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineListOfInlineClass.kt create mode 100644 compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineMapOfInlineClass.kt diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index 188314799ea..725024a531c 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -17356,6 +17356,34 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT } } + @Nested + @TestMetadata("compiler/testData/codegen/box/inlineClasses/inlineClassCollection") + @TestDataPath("$PROJECT_ROOT") + public class InlineClassCollection extends AbstractFirBlackBoxCodegenTest { + @Test + public void testAllFilesPresentInInlineClassCollection() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses/inlineClassCollection"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); + } + + @Test + @TestMetadata("inlineCollectionOfInlineClass.kt") + public void testInlineCollectionOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineCollectionOfInlineClass.kt"); + } + + @Test + @TestMetadata("inlineListOfInlineClass.kt") + public void testInlineListOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineListOfInlineClass.kt"); + } + + @Test + @TestMetadata("inlineMapOfInlineClass.kt") + public void testInlineMapOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineMapOfInlineClass.kt"); + } + } + @Nested @TestMetadata("compiler/testData/codegen/box/inlineClasses/interfaceDelegation") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt index 6017d3fbd3b..78e97767e86 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt @@ -17,10 +17,8 @@ import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface import org.jetbrains.kotlin.backend.jvm.ir.* import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.unboxInlineClass -import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.descriptors.DescriptorVisibilities -import org.jetbrains.kotlin.descriptors.DescriptorVisibility import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.builders.* @@ -593,17 +591,23 @@ internal class BridgeLowering(val context: JvmBackendContext) : FileLoweringPass fun computeJvmMethod(function: IrFunction): Method = signatureCache.getOrPut(function.symbol) { context.methodSignatureMapper.mapAsmMethod(function) } + private fun canHaveSpecialBridge(function: IrSimpleFunction): Boolean { + if (function.name in specialBridgeMethods.specialMethodNames) + return true + // Function name could be mangled by inline class rules + val functionName = function.name.asString() + if (specialBridgeMethods.specialMethodNames.any { functionName.startsWith(it.asString() + "-") }) + return true + return false + } + fun computeSpecialBridge(function: IrSimpleFunction): SpecialBridge? { // Optimization: do not try to compute special bridge for irrelevant methods. val correspondingProperty = function.correspondingPropertySymbol if (correspondingProperty != null) { if (correspondingProperty.owner.name !in specialBridgeMethods.specialPropertyNames) return null } else { - // 'remove' and 'removeAt' functions can be mangled by inline class rules - if (function.name !in specialBridgeMethods.specialMethodNames && - !function.name.asString().startsWith("removeAt-") && - !function.name.asString().startsWith("remove-") - ) { + if (!canHaveSpecialBridge(function)) { return null } } diff --git a/compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineCollectionOfInlineClass.kt b/compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineCollectionOfInlineClass.kt new file mode 100644 index 00000000000..284153155d9 --- /dev/null +++ b/compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineCollectionOfInlineClass.kt @@ -0,0 +1,43 @@ +// WITH_RUNTIME + +inline class Z(val x: Int) + +inline class ZArray(val storage: IntArray) : Collection { + override val size: Int + get() = storage.size + + override fun contains(element: Z): Boolean { + return storage.contains(element.x) + } + + override fun containsAll(elements: Collection): Boolean { + return elements.all { contains(it) } + } + + override fun isEmpty(): Boolean { + return storage.isEmpty() + } + + private class ZArrayIterator(val storage: IntArray): Iterator { + var index = 0 + + override fun hasNext(): Boolean = index < storage.size + + override fun next(): Z = Z(storage[index++]) + } + + override fun iterator(): Iterator = ZArrayIterator(storage) +} + + +fun box(): String { + val zs = ZArray(IntArray(5)) + + val testSize = zs.size + if (testSize != 5) return "Failed: testSize=$testSize" + + val testContains = zs.contains(object {} as Any) + if (testContains) return "Failed: testContains=$testContains" + + return "OK" +} diff --git a/compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineListOfInlineClass.kt b/compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineListOfInlineClass.kt new file mode 100644 index 00000000000..d97fafd4ea0 --- /dev/null +++ b/compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineListOfInlineClass.kt @@ -0,0 +1,56 @@ +// WITH_RUNTIME + +inline class Z(val x: Int) + +inline class ZArray(val storage: IntArray) : List { + override val size: Int + get() = storage.size + + override fun contains(element: Z): Boolean { + return storage.contains(element.x) + } + + override fun containsAll(elements: Collection): Boolean { + return elements.all { contains(it) } + } + + override fun isEmpty(): Boolean { + return storage.isEmpty() + } + + override fun get(index: Int): Z = Z(storage[index]) + + override fun indexOf(element: Z): Int = storage.indexOf(element.x) + + override fun lastIndexOf(element: Z): Int = storage.lastIndexOf(element.x) + + override fun listIterator(): ListIterator = ZArrayIterator(storage) + + override fun listIterator(index: Int): ListIterator = ZArrayIterator(storage, index) + + override fun subList(fromIndex: Int, toIndex: Int): List = TODO() + + private class ZArrayIterator(val storage: IntArray, var index: Int = 0): ListIterator { + override fun hasNext(): Boolean = index < storage.size + override fun next(): Z = Z(storage[index++]) + override fun nextIndex(): Int = index + 1 + + override fun hasPrevious(): Boolean = index > 0 + override fun previous(): Z = Z(storage[index--]) + override fun previousIndex(): Int = index - 1 + } + + override fun iterator(): Iterator = ZArrayIterator(storage) +} + + +fun box(): String { + val zs = ZArray(IntArray(5)) + + val testElement = object {} as Any + zs.contains(testElement) + zs.indexOf(testElement) + zs.lastIndexOf(testElement) + + return "OK" +} diff --git a/compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineMapOfInlineClass.kt b/compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineMapOfInlineClass.kt new file mode 100644 index 00000000000..81fa9a51558 --- /dev/null +++ b/compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineMapOfInlineClass.kt @@ -0,0 +1,57 @@ +// WITH_RUNTIME + +inline class Z(val x: Int) + +inline class ZArrayMap(val storage: IntArray) : Map { + override val size: Int + get() = storage.size + + private class MapEntry(val i: Int, val si: Int): Map.Entry { + override val key: Z get() = Z(i) + override val value: Z get() = Z(si) + } + + private class MapEntrySet(val storage: IntArray) : AbstractSet>() { + private inner class MyIterator : Iterator> { + var index = 0 + override fun hasNext(): Boolean = index < size + override fun next(): Map.Entry = MapEntry(index, storage[index++]) + } + + override val size: Int + get() = storage.size + + override fun iterator(): Iterator> = MyIterator() + } + + override val entries: Set> + get() = MapEntrySet(storage) + + override val keys: Set + get() = (0 until size).mapTo(HashSet()) { Z(it) } + + override val values: Collection + get() = storage.mapTo(ArrayList()) { Z(it) } + + override fun containsKey(key: Z): Boolean = key.x in (0 until size) + + override fun containsValue(value: Z): Boolean = storage.contains(value.x) + + override fun get(key: Z) = storage.getOrNull(key.x)?.let { Z(it) } + + override fun isEmpty(): Boolean = size > 0 +} + +fun box(): String { + val zm = ZArrayMap(IntArray(5)) + + zm.containsKey(Z(0)) + zm.containsValue(Z(0)) + zm[Z(0)] + + zm.containsKey(object {} as Any) + zm.containsValue(object {} as Any) + zm.get(object {} as Any) + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollection/UIntArrayWithFullJdk_ir.txt b/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollection/UIntArrayWithFullJdk_ir.txt index 44b3d3082ac..0c1b909eada 100644 --- a/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollection/UIntArrayWithFullJdk_ir.txt +++ b/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollection/UIntArrayWithFullJdk_ir.txt @@ -29,7 +29,7 @@ public final class UIntArray { public synthetic final static method box-impl(p0: int[]): UIntArray public method clear(): void public static @org.jetbrains.annotations.NotNull method constructor-impl(@org.jetbrains.annotations.NotNull p0: int[]): int[] - public synthetic bridge method contains(p0: java.lang.Object): boolean + public bridge final method contains(p0: java.lang.Object): boolean public method contains-fLmw4x8(p0: int): boolean public static method contains-fLmw4x8(p0: int[], p1: int): boolean public method containsAll(@org.jetbrains.annotations.NotNull p0: java.util.Collection): boolean diff --git a/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/collection_ir.txt b/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/collection_ir.txt index 120be8748b7..c10951b8475 100644 --- a/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/collection_ir.txt +++ b/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/collection_ir.txt @@ -25,7 +25,7 @@ public final class InlineCollection { public synthetic final static method box-impl(p0: java.util.Collection): InlineCollection public method clear(): void public static method constructor-impl(p0: java.util.Collection): java.util.Collection - public synthetic bridge method contains(p0: java.lang.Object): boolean + public bridge final method contains(p0: java.lang.Object): boolean public method contains-jHY5zpA(p0: int): boolean public static method contains-jHY5zpA(p0: java.util.Collection, p1: int): boolean public method containsAll(p0: java.util.Collection): boolean diff --git a/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/list_ir.txt b/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/list_ir.txt index 40a3cd61795..e8f71deff56 100644 --- a/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/list_ir.txt +++ b/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/list_ir.txt @@ -28,7 +28,7 @@ public final class InlineList { public synthetic final static method box-impl(p0: java.util.List): InlineList public method clear(): void public static method constructor-impl(p0: java.util.List): java.util.List - public synthetic bridge method contains(p0: java.lang.Object): boolean + public bridge final method contains(p0: java.lang.Object): boolean public method contains-jHY5zpA(p0: int): boolean public static method contains-jHY5zpA(p0: java.util.List, p1: int): boolean public method containsAll(p0: java.util.Collection): boolean @@ -43,14 +43,14 @@ public final class InlineList { public static method getSize-impl(p0: java.util.List): int public method hashCode(): int public static method hashCode-impl(p0: java.util.List): int - public synthetic bridge method indexOf(p0: java.lang.Object): int + public bridge final method indexOf(p0: java.lang.Object): int public method indexOf-jHY5zpA(p0: int): int public static method indexOf-jHY5zpA(p0: java.util.List, p1: int): int public method isEmpty(): boolean public static method isEmpty-impl(p0: java.util.List): boolean public method iterator(): java.util.Iterator public static method iterator-impl(p0: java.util.List): java.util.Iterator - public synthetic bridge method lastIndexOf(p0: java.lang.Object): int + public bridge final method lastIndexOf(p0: java.lang.Object): int public method lastIndexOf-jHY5zpA(p0: int): int public static method lastIndexOf-jHY5zpA(p0: java.util.List, p1: int): int public method listIterator(): java.util.ListIterator diff --git a/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/map_ir.txt b/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/map_ir.txt index 8e8a274d498..da9c4407692 100644 --- a/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/map_ir.txt +++ b/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/map_ir.txt @@ -39,16 +39,17 @@ public final class InlineMap { public synthetic final static method box-impl(p0: java.util.Map): InlineMap public method clear(): void public static method constructor-impl(p0: java.util.Map): java.util.Map - public synthetic bridge method containsKey(p0: java.lang.Object): boolean + public bridge final method containsKey(p0: java.lang.Object): boolean public method containsKey-FSIWiWE(p0: int): boolean public static method containsKey-FSIWiWE(p0: java.util.Map, p1: int): boolean - public synthetic bridge method containsValue(p0: java.lang.Object): boolean + public bridge final method containsValue(p0: java.lang.Object): boolean public method containsValue-jbX5DO8(p0: double): boolean public static method containsValue-jbX5DO8(p0: java.util.Map, p1: double): boolean public synthetic bridge method entrySet(): java.util.Set public method equals(p0: java.lang.Object): boolean public static method equals-impl(p0: java.util.Map, p1: java.lang.Object): boolean public final static method equals-impl0(p0: java.util.Map, p1: java.util.Map): boolean + public bridge final method get(p0: java.lang.Object): IV public synthetic bridge method get(p0: java.lang.Object): java.lang.Object public method get-qgyy0Jc(p0: int): IV public static method get-qgyy0Jc(p0: java.util.Map, p1: int): IV diff --git a/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/mutableCollection_ir.txt b/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/mutableCollection_ir.txt index 73a1c6a8a28..575f2f46d03 100644 --- a/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/mutableCollection_ir.txt +++ b/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/mutableCollection_ir.txt @@ -28,7 +28,7 @@ public final class InlineMutableCollection { public method clear(): void public static method clear-impl(p0: java.util.Collection): void public static method constructor-impl(p0: java.util.Collection): java.util.Collection - public synthetic bridge method contains(p0: java.lang.Object): boolean + public bridge final method contains(p0: java.lang.Object): boolean public method contains-jHY5zpA(p0: int): boolean public static method contains-jHY5zpA(p0: java.util.Collection, p1: int): boolean public method containsAll(p0: java.util.Collection): boolean diff --git a/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/mutableList_ir.txt b/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/mutableList_ir.txt index e95e8ff4ae3..7af209ff5cc 100644 --- a/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/mutableList_ir.txt +++ b/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/mutableList_ir.txt @@ -33,7 +33,7 @@ public final class InlineMutableList { public method clear(): void public static method clear-impl(p0: java.util.List): void public static method constructor-impl(p0: java.util.List): java.util.List - public synthetic bridge method contains(p0: java.lang.Object): boolean + public bridge final method contains(p0: java.lang.Object): boolean public static method contains-jHY5zpA(p0: java.util.List, p1: long): boolean public method contains-jHY5zpA(p0: long): boolean public method containsAll(p0: java.util.Collection): boolean @@ -48,14 +48,14 @@ public final class InlineMutableList { public static method getSize-impl(p0: java.util.List): int public method hashCode(): int public static method hashCode-impl(p0: java.util.List): int - public synthetic bridge method indexOf(p0: java.lang.Object): int + public bridge final method indexOf(p0: java.lang.Object): int public static method indexOf-jHY5zpA(p0: java.util.List, p1: long): int public method indexOf-jHY5zpA(p0: long): int public method isEmpty(): boolean public static method isEmpty-impl(p0: java.util.List): boolean public method iterator(): java.util.Iterator public static method iterator-impl(p0: java.util.List): java.util.Iterator - public synthetic bridge method lastIndexOf(p0: java.lang.Object): int + public bridge final method lastIndexOf(p0: java.lang.Object): int public static method lastIndexOf-jHY5zpA(p0: java.util.List, p1: long): int public method lastIndexOf-jHY5zpA(p0: long): int public method listIterator(): java.util.ListIterator diff --git a/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/mutableMap_ir.txt b/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/mutableMap_ir.txt index 3cd6ac061ca..c879e3ba8fe 100644 --- a/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/mutableMap_ir.txt +++ b/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/mutableMap_ir.txt @@ -40,16 +40,17 @@ public final class InlineMutableMap { public method clear(): void public static method clear-impl(p0: java.util.Map): void public static method constructor-impl(p0: java.util.Map): java.util.Map - public synthetic bridge method containsKey(p0: java.lang.Object): boolean + public bridge final method containsKey(p0: java.lang.Object): boolean public method containsKey-FSIWiWE(p0: int): boolean public static method containsKey-FSIWiWE(p0: java.util.Map, p1: int): boolean - public synthetic bridge method containsValue(p0: java.lang.Object): boolean + public bridge final method containsValue(p0: java.lang.Object): boolean public method containsValue-jbX5DO8(p0: double): boolean public static method containsValue-jbX5DO8(p0: java.util.Map, p1: double): boolean public synthetic bridge method entrySet(): java.util.Set public method equals(p0: java.lang.Object): boolean public static method equals-impl(p0: java.util.Map, p1: java.lang.Object): boolean public final static method equals-impl0(p0: java.util.Map, p1: java.util.Map): boolean + public bridge final method get(p0: java.lang.Object): IV public synthetic bridge method get(p0: java.lang.Object): java.lang.Object public method get-qgyy0Jc(p0: int): IV public static method get-qgyy0Jc(p0: java.util.Map, p1: int): IV diff --git a/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/mutableSet2_ir.txt b/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/mutableSet2_ir.txt index 2b408cd103b..c68d863467e 100644 --- a/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/mutableSet2_ir.txt +++ b/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/mutableSet2_ir.txt @@ -45,7 +45,7 @@ public final class InlineMutableSet2 { public method clear(): void public static method clear-impl(p0: java.util.Set): void public static method constructor-impl(p0: java.util.Set): java.util.Set - public synthetic bridge method contains(p0: java.lang.Object): boolean + public bridge final method contains(p0: java.lang.Object): boolean public method contains-C2ZI6mw(p0: int): boolean public static method contains-C2ZI6mw(p0: java.util.Set, p1: int): boolean public method containsAll(p0: java.util.Collection): boolean diff --git a/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/mutableSet_ir.txt b/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/mutableSet_ir.txt index 0724572ec0e..4fc590cc770 100644 --- a/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/mutableSet_ir.txt +++ b/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/mutableSet_ir.txt @@ -28,7 +28,7 @@ public final class InlineMutableSet { public method clear(): void public static method clear-impl(p0: java.util.Set): void public static method constructor-impl(p0: java.util.Set): java.util.Set - public synthetic bridge method contains(p0: java.lang.Object): boolean + public bridge final method contains(p0: java.lang.Object): boolean public method contains-jHY5zpA(p0: int): boolean public static method contains-jHY5zpA(p0: java.util.Set, p1: int): boolean public method containsAll(p0: java.util.Collection): boolean diff --git a/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/set_ir.txt b/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/set_ir.txt index 598f2a92f7c..377d4e338dc 100644 --- a/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/set_ir.txt +++ b/compiler/testData/codegen/bytecodeListing/inlineClasses/inlineCollectionOfInlineClass/set_ir.txt @@ -25,7 +25,7 @@ public final class InlineSet { public synthetic final static method box-impl(p0: java.util.Set): InlineSet public method clear(): void public static method constructor-impl(p0: java.util.Set): java.util.Set - public synthetic bridge method contains(p0: java.lang.Object): boolean + public bridge final method contains(p0: java.lang.Object): boolean public method contains-jHY5zpA(p0: int): boolean public static method contains-jHY5zpA(p0: java.util.Set, p1: int): boolean public method containsAll(p0: java.util.Collection): boolean diff --git a/compiler/testData/codegen/bytecodeListing/specialBridges/unsignedArray_ir.txt b/compiler/testData/codegen/bytecodeListing/specialBridges/unsignedArray_ir.txt index a42fe476c10..e5962c29b60 100644 --- a/compiler/testData/codegen/bytecodeListing/specialBridges/unsignedArray_ir.txt +++ b/compiler/testData/codegen/bytecodeListing/specialBridges/unsignedArray_ir.txt @@ -8,7 +8,7 @@ public final class UIntArray { public synthetic final static method box-impl(p0: int[]): UIntArray public method clear(): void public static method constructor-impl(p0: int[]): int[] - public synthetic bridge method contains(p0: java.lang.Object): boolean + public bridge final method contains(p0: java.lang.Object): boolean public method contains-WZ4Q5Ns(p0: int): boolean public static method contains-WZ4Q5Ns(p0: int[], p1: int): boolean public method containsAll(p0: java.util.Collection): boolean diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index fa8a769400f..fbd8c8d8487 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -17356,6 +17356,34 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { } } + @Nested + @TestMetadata("compiler/testData/codegen/box/inlineClasses/inlineClassCollection") + @TestDataPath("$PROJECT_ROOT") + public class InlineClassCollection extends AbstractBlackBoxCodegenTest { + @Test + public void testAllFilesPresentInInlineClassCollection() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses/inlineClassCollection"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); + } + + @Test + @TestMetadata("inlineCollectionOfInlineClass.kt") + public void testInlineCollectionOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineCollectionOfInlineClass.kt"); + } + + @Test + @TestMetadata("inlineListOfInlineClass.kt") + public void testInlineListOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineListOfInlineClass.kt"); + } + + @Test + @TestMetadata("inlineMapOfInlineClass.kt") + public void testInlineMapOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineMapOfInlineClass.kt"); + } + } + @Nested @TestMetadata("compiler/testData/codegen/box/inlineClasses/interfaceDelegation") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index baa98bc5e7a..4de1e3dfc00 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -17356,6 +17356,34 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes } } + @Nested + @TestMetadata("compiler/testData/codegen/box/inlineClasses/inlineClassCollection") + @TestDataPath("$PROJECT_ROOT") + public class InlineClassCollection extends AbstractIrBlackBoxCodegenTest { + @Test + public void testAllFilesPresentInInlineClassCollection() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses/inlineClassCollection"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true); + } + + @Test + @TestMetadata("inlineCollectionOfInlineClass.kt") + public void testInlineCollectionOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineCollectionOfInlineClass.kt"); + } + + @Test + @TestMetadata("inlineListOfInlineClass.kt") + public void testInlineListOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineListOfInlineClass.kt"); + } + + @Test + @TestMetadata("inlineMapOfInlineClass.kt") + public void testInlineMapOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineMapOfInlineClass.kt"); + } + } + @Nested @TestMetadata("compiler/testData/codegen/box/inlineClasses/interfaceDelegation") @TestDataPath("$PROJECT_ROOT") diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index bd4b3d744f3..a5448fe6e4d 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -15191,6 +15191,34 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes } } + @TestMetadata("compiler/testData/codegen/box/inlineClasses/inlineClassCollection") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class InlineClassCollection extends AbstractLightAnalysisModeTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); + } + + public void testAllFilesPresentInInlineClassCollection() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses/inlineClassCollection"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true); + } + + @TestMetadata("inlineCollectionOfInlineClass.kt") + public void testInlineCollectionOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineCollectionOfInlineClass.kt"); + } + + @TestMetadata("inlineListOfInlineClass.kt") + public void testInlineListOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineListOfInlineClass.kt"); + } + + @TestMetadata("inlineMapOfInlineClass.kt") + public void testInlineMapOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineMapOfInlineClass.kt"); + } + } + @TestMetadata("compiler/testData/codegen/box/inlineClasses/interfaceDelegation") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java index 21993b93b26..872d90e230b 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java @@ -13086,6 +13086,34 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes } } + @TestMetadata("compiler/testData/codegen/box/inlineClasses/inlineClassCollection") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class InlineClassCollection extends AbstractIrJsCodegenBoxES6Test { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR_ES6, testDataFilePath); + } + + public void testAllFilesPresentInInlineClassCollection() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses/inlineClassCollection"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true); + } + + @TestMetadata("inlineCollectionOfInlineClass.kt") + public void testInlineCollectionOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineCollectionOfInlineClass.kt"); + } + + @TestMetadata("inlineListOfInlineClass.kt") + public void testInlineListOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineListOfInlineClass.kt"); + } + + @TestMetadata("inlineMapOfInlineClass.kt") + public void testInlineMapOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineMapOfInlineClass.kt"); + } + } + @TestMetadata("compiler/testData/codegen/box/inlineClasses/interfaceDelegation") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index b947ffc7c3d..b85b2a4d70f 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -13086,6 +13086,34 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { } } + @TestMetadata("compiler/testData/codegen/box/inlineClasses/inlineClassCollection") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class InlineClassCollection extends AbstractIrJsCodegenBoxTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath); + } + + public void testAllFilesPresentInInlineClassCollection() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses/inlineClassCollection"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true); + } + + @TestMetadata("inlineCollectionOfInlineClass.kt") + public void testInlineCollectionOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineCollectionOfInlineClass.kt"); + } + + @TestMetadata("inlineListOfInlineClass.kt") + public void testInlineListOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineListOfInlineClass.kt"); + } + + @TestMetadata("inlineMapOfInlineClass.kt") + public void testInlineMapOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineMapOfInlineClass.kt"); + } + } + @TestMetadata("compiler/testData/codegen/box/inlineClasses/interfaceDelegation") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 85bb3588fd6..58a5b2bc99d 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -13151,6 +13151,34 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { } } + @TestMetadata("compiler/testData/codegen/box/inlineClasses/inlineClassCollection") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class InlineClassCollection extends AbstractJsCodegenBoxTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath); + } + + public void testAllFilesPresentInInlineClassCollection() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses/inlineClassCollection"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true); + } + + @TestMetadata("inlineCollectionOfInlineClass.kt") + public void testInlineCollectionOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineCollectionOfInlineClass.kt"); + } + + @TestMetadata("inlineListOfInlineClass.kt") + public void testInlineListOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineListOfInlineClass.kt"); + } + + @TestMetadata("inlineMapOfInlineClass.kt") + public void testInlineMapOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineMapOfInlineClass.kt"); + } + } + @TestMetadata("compiler/testData/codegen/box/inlineClasses/interfaceDelegation") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java index 94605af3d16..5de254d934a 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java @@ -7377,6 +7377,34 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest } } + @TestMetadata("compiler/testData/codegen/box/inlineClasses/inlineClassCollection") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class InlineClassCollection extends AbstractIrCodegenBoxWasmTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath); + } + + public void testAllFilesPresentInInlineClassCollection() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/inlineClasses/inlineClassCollection"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true); + } + + @TestMetadata("inlineCollectionOfInlineClass.kt") + public void testInlineCollectionOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineCollectionOfInlineClass.kt"); + } + + @TestMetadata("inlineListOfInlineClass.kt") + public void testInlineListOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineListOfInlineClass.kt"); + } + + @TestMetadata("inlineMapOfInlineClass.kt") + public void testInlineMapOfInlineClass() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/inlineClassCollection/inlineMapOfInlineClass.kt"); + } + } + @TestMetadata("compiler/testData/codegen/box/inlineClasses/interfaceDelegation") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) From 593fb8770b3fbd73f4abc925bafaa00f4b7cfa14 Mon Sep 17 00:00:00 2001 From: Mads Ager Date: Fri, 29 Jan 2021 11:51:54 +0100 Subject: [PATCH 020/260] [FIR] Fix lookup order for statics in super chains The order was reversed and the static in the top-most class in the inheritance hierarchy would be found instead of the lowest one. --- .../FirBlackBoxCodegenTestGenerated.java | 6 ++++ .../fir/resolve/BodyResolveComponents.kt | 8 +++-- .../codegen/box/statics/protectedStatic2.kt | 1 - .../statics/simpleStaticInJavaSuperChain.kt | 31 +++++++++++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 6 ++++ .../IrBlackBoxCodegenTestGenerated.java | 6 ++++ .../LightAnalysisModeTestGenerated.java | 5 +++ 7 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 compiler/testData/codegen/box/statics/simpleStaticInJavaSuperChain.kt diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index 725024a531c..cdaa879604d 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -35588,6 +35588,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/statics/protectedStaticAndInline.kt"); } + @Test + @TestMetadata("simpleStaticInJavaSuperChain.kt") + public void testSimpleStaticInJavaSuperChain() throws Exception { + runTest("compiler/testData/codegen/box/statics/simpleStaticInJavaSuperChain.kt"); + } + @Test @TestMetadata("syntheticAccessor.kt") public void testSyntheticAccessor() throws Exception { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/BodyResolveComponents.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/BodyResolveComponents.kt index 38c4a2d54a9..27af854fac4 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/BodyResolveComponents.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/BodyResolveComponents.kt @@ -180,7 +180,7 @@ fun SessionHolder.collectImplicitReceivers( throw IllegalArgumentException("Incorrect label & receiver owner: ${owner.javaClass}") } } - return ImplicitReceivers(implicitReceiverValue, implicitCompanionValues.asReversed()) + return ImplicitReceivers(implicitReceiverValue, implicitCompanionValues) } fun SessionHolder.collectTowerDataElementsForClass(owner: FirClass<*>, defaultType: ConeKotlinType): TowerElementsForClass { @@ -221,8 +221,8 @@ fun SessionHolder.collectTowerDataElementsForClass(owner: FirClass<*>, defaultTy owner.staticScope(this), companionReceiver, companionObject?.staticScope(this), - superClassesStaticsAndCompanionReceivers, - allImplicitCompanionValues + superClassesStaticsAndCompanionReceivers.asReversed(), + allImplicitCompanionValues.asReversed() ) } @@ -234,6 +234,8 @@ class TowerElementsForClass( val staticScope: FirScope?, val companionReceiver: ImplicitReceiverValue<*>?, val companionStaticScope: FirScope?, + // Ordered from inner scopes to outer scopes. val superClassesStaticsAndCompanionReceivers: List, + // Ordered from inner scopes to outer scopes. val implicitCompanionValues: List> ) diff --git a/compiler/testData/codegen/box/statics/protectedStatic2.kt b/compiler/testData/codegen/box/statics/protectedStatic2.kt index 1a8f42273bf..5b584a702a4 100644 --- a/compiler/testData/codegen/box/statics/protectedStatic2.kt +++ b/compiler/testData/codegen/box/statics/protectedStatic2.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR // TARGET_BACKEND: JVM // FILE: Base.java diff --git a/compiler/testData/codegen/box/statics/simpleStaticInJavaSuperChain.kt b/compiler/testData/codegen/box/statics/simpleStaticInJavaSuperChain.kt new file mode 100644 index 00000000000..85f6fdfa2ed --- /dev/null +++ b/compiler/testData/codegen/box/statics/simpleStaticInJavaSuperChain.kt @@ -0,0 +1,31 @@ +// TARGET_BACKEND: JVM + +// FILE: A.java + +public class A { + public static String s = "A.s: NOT OK"; + public static String f() { + return "A.f: NOT OK"; + } + + public static class B extends A { + public static String s = "OK"; + public static String f() { + return "OK"; + } + } +} + + +// FILE: Kotlin.kt + +class Kotlin: A.B() { + fun getS() = s + fun callF() = f() +} + +fun box(): String { + val kotlin = Kotlin() + if (kotlin.getS() != "OK") return "fail1" + return kotlin.callF() +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index fbd8c8d8487..739134dac50 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -35788,6 +35788,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/statics/protectedStaticAndInline.kt"); } + @Test + @TestMetadata("simpleStaticInJavaSuperChain.kt") + public void testSimpleStaticInJavaSuperChain() throws Exception { + runTest("compiler/testData/codegen/box/statics/simpleStaticInJavaSuperChain.kt"); + } + @Test @TestMetadata("syntheticAccessor.kt") public void testSyntheticAccessor() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index 4de1e3dfc00..306d9937b3d 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -35588,6 +35588,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/statics/protectedStaticAndInline.kt"); } + @Test + @TestMetadata("simpleStaticInJavaSuperChain.kt") + public void testSimpleStaticInJavaSuperChain() throws Exception { + runTest("compiler/testData/codegen/box/statics/simpleStaticInJavaSuperChain.kt"); + } + @Test @TestMetadata("syntheticAccessor.kt") public void testSyntheticAccessor() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index a5448fe6e4d..355433bff8c 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -29277,6 +29277,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/statics/protectedStaticAndInline.kt"); } + @TestMetadata("simpleStaticInJavaSuperChain.kt") + public void testSimpleStaticInJavaSuperChain() throws Exception { + runTest("compiler/testData/codegen/box/statics/simpleStaticInJavaSuperChain.kt"); + } + @TestMetadata("syntheticAccessor.kt") public void testSyntheticAccessor() throws Exception { runTest("compiler/testData/codegen/box/statics/syntheticAccessor.kt"); From 1f62fee4f94369267da7f46242eaca62a5be0d1a Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Mon, 1 Feb 2021 17:25:47 +0300 Subject: [PATCH 021/260] Fix typo --- .../test/services/impl/ModuleStructureExtractorImpl.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/impl/ModuleStructureExtractorImpl.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/impl/ModuleStructureExtractorImpl.kt index 63077ebfd23..2cd06f5fbad 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/impl/ModuleStructureExtractorImpl.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/impl/ModuleStructureExtractorImpl.kt @@ -219,7 +219,7 @@ class ModuleStructureExtractorImpl( return true } - private fun splitRawModuleStringToNameAndDependencies(moduleDirectiveString: String): ModuleNameAndDependeciens { + private fun splitRawModuleStringToNameAndDependencies(moduleDirectiveString: String): ModuleNameAndDependencies { val matchResult = moduleDirectiveRegex.matchEntire(moduleDirectiveString) ?: error("\"$moduleDirectiveString\" doesn't matches with pattern \"moduleName(dep1, dep2)\"") val (name, _, dependencies, _, friends) = matchResult.destructured @@ -234,7 +234,7 @@ class ModuleStructureExtractorImpl( dependenciesNames = dependenciesNames.filter { it != "support" } } } - return ModuleNameAndDependeciens( + return ModuleNameAndDependencies( name, dependenciesNames, friends.takeIf { it.isNotBlank() }?.split(" ") ?: emptyList(), @@ -393,7 +393,7 @@ class ModuleStructureExtractorImpl( } } - private data class ModuleNameAndDependeciens( + private data class ModuleNameAndDependencies( val name: String, val dependencies: List, val friends: List From 78c6e0733c84747ec9be50e3a623572e50f05782 Mon Sep 17 00:00:00 2001 From: Anton Yalyshev Date: Mon, 1 Feb 2021 18:50:49 +0300 Subject: [PATCH 022/260] Add change-notes for 1.4.30 --- .../resources-descriptors/META-INF/plugin.xml | 23 +++++++++++++++---- .../META-INF/plugin.xml.201 | 12 ++++++++++ .../META-INF/plugin.xml.as41 | 12 ++++++++++ .../META-INF/plugin.xml.as42 | 12 ++++++++++ 4 files changed, 55 insertions(+), 4 deletions(-) diff --git a/idea/resources-descriptors/META-INF/plugin.xml b/idea/resources-descriptors/META-INF/plugin.xml index 8f7e0dbe79c..5b2bed17c94 100644 --- a/idea/resources-descriptors/META-INF/plugin.xml +++ b/idea/resources-descriptors/META-INF/plugin.xml @@ -16,7 +16,19 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. 1.4.30 +
    +
  • Preview of new language features: JVM records support, sealed interfaces, and stable inline classes.
  • +
  • Kotlin/JVM: IR backend is now in Beta.
  • +
  • Kotlin/Native: performance improvements, new `watchosX64` simulator target, support for Xcode 12.2 libraries.
  • +
  • Kotlin/JS: prototype lazy initialization of top-level properties.
  • +
  • Support for Gradle configuration cache.
  • +
  • Standard library API improvements: locale-agnostic API for upper/lowercasing text and clear Char-to-code and Char-to-digit conversions.
  • +
+ For more details, see
What’s New in Kotlin 1.4.30 and this blog post. +

1.4.20

+ Released: November 23, 2020