From 485fad19516146e4d153e2842bb3e44807b7d102 Mon Sep 17 00:00:00 2001 From: Dmitrii Gridin Date: Thu, 5 Jan 2023 18:13:04 +0100 Subject: [PATCH] [FIR] FirJavaClass: make annotations and deprecationsProvider lazily enhanced ^KT-55387 --- ...lassesByFqNameForLibraryTestGenerated.java | 6 +++ ...assesParentingForLibraryTestGenerated.java | 6 +++ ...ClassesByFqNameForSourceTestGenerated.java | 6 +++ ...lassesParentingForSourceTestGenerated.java | 6 +++ .../kotlin/fir/java/FirJavaFacade.kt | 8 ++-- .../fir/java/declarations/FirJavaClass.kt | 28 +++++++++----- .../JavaClassWithAnnotation.fir.java | 4 ++ .../JavaClassWithAnnotation.java | 4 ++ .../JavaClassWithAnnotation.kt | 37 +++++++++++++++++++ .../CompilerLightClassTestGenerated.java | 5 +++ 10 files changed, 97 insertions(+), 13 deletions(-) create mode 100644 compiler/testData/asJava/lightClasses/lightClassByFqName/JavaClassWithAnnotation.fir.java create mode 100644 compiler/testData/asJava/lightClasses/lightClassByFqName/JavaClassWithAnnotation.java create mode 100644 compiler/testData/asJava/lightClasses/lightClassByFqName/JavaClassWithAnnotation.kt diff --git a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/decompiled/SymbolLightClassesByFqNameForLibraryTestGenerated.java b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/decompiled/SymbolLightClassesByFqNameForLibraryTestGenerated.java index db74a793680..7391c0b5df1 100644 --- a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/decompiled/SymbolLightClassesByFqNameForLibraryTestGenerated.java +++ b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/decompiled/SymbolLightClassesByFqNameForLibraryTestGenerated.java @@ -192,6 +192,12 @@ public class SymbolLightClassesByFqNameForLibraryTestGenerated extends AbstractS runTest("compiler/testData/asJava/lightClasses/lightClassByFqName/JavaBetween.kt"); } + @Test + @TestMetadata("JavaClassWithAnnotation.kt") + public void testJavaClassWithAnnotation() throws Exception { + runTest("compiler/testData/asJava/lightClasses/lightClassByFqName/JavaClassWithAnnotation.kt"); + } + @Test @TestMetadata("JvmNameOnMember.kt") public void testJvmNameOnMember() throws Exception { diff --git a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/decompiled/SymbolLightClassesParentingForLibraryTestGenerated.java b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/decompiled/SymbolLightClassesParentingForLibraryTestGenerated.java index 2826388c442..2d1afe90906 100644 --- a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/decompiled/SymbolLightClassesParentingForLibraryTestGenerated.java +++ b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/decompiled/SymbolLightClassesParentingForLibraryTestGenerated.java @@ -192,6 +192,12 @@ public class SymbolLightClassesParentingForLibraryTestGenerated extends Abstract runTest("compiler/testData/asJava/lightClasses/lightClassByFqName/JavaBetween.kt"); } + @Test + @TestMetadata("JavaClassWithAnnotation.kt") + public void testJavaClassWithAnnotation() throws Exception { + runTest("compiler/testData/asJava/lightClasses/lightClassByFqName/JavaClassWithAnnotation.kt"); + } + @Test @TestMetadata("JvmNameOnMember.kt") public void testJvmNameOnMember() throws Exception { diff --git a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/source/SymbolLightClassesByFqNameForSourceTestGenerated.java b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/source/SymbolLightClassesByFqNameForSourceTestGenerated.java index 2ab6c1bf842..69dec8dffa4 100644 --- a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/source/SymbolLightClassesByFqNameForSourceTestGenerated.java +++ b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/source/SymbolLightClassesByFqNameForSourceTestGenerated.java @@ -192,6 +192,12 @@ public class SymbolLightClassesByFqNameForSourceTestGenerated extends AbstractSy runTest("compiler/testData/asJava/lightClasses/lightClassByFqName/JavaBetween.kt"); } + @Test + @TestMetadata("JavaClassWithAnnotation.kt") + public void testJavaClassWithAnnotation() throws Exception { + runTest("compiler/testData/asJava/lightClasses/lightClassByFqName/JavaClassWithAnnotation.kt"); + } + @Test @TestMetadata("JvmNameOnMember.kt") public void testJvmNameOnMember() throws Exception { diff --git a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/source/SymbolLightClassesParentingForSourceTestGenerated.java b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/source/SymbolLightClassesParentingForSourceTestGenerated.java index 15c34afe439..3f4b9ccf0d3 100644 --- a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/source/SymbolLightClassesParentingForSourceTestGenerated.java +++ b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/source/SymbolLightClassesParentingForSourceTestGenerated.java @@ -192,6 +192,12 @@ public class SymbolLightClassesParentingForSourceTestGenerated extends AbstractS runTest("compiler/testData/asJava/lightClasses/lightClassByFqName/JavaBetween.kt"); } + @Test + @TestMetadata("JavaClassWithAnnotation.kt") + public void testJavaClassWithAnnotation() throws Exception { + runTest("compiler/testData/asJava/lightClasses/lightClassByFqName/JavaClassWithAnnotation.kt"); + } + @Test @TestMetadata("JvmNameOnMember.kt") public void testJvmNameOnMember() throws Exception { diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaFacade.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaFacade.kt index df687be6905..5e41ab9c318 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaFacade.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaFacade.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2023 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. */ @@ -172,13 +172,12 @@ abstract class FirJavaFacade( val enhancement = FirSignatureEnhancement(firJavaClass, session) { emptyList() } val initialBounds = enhancement.performFirstRoundOfBoundsResolution(firJavaClass.typeParameters) - // 1. Resolve annotations + // 1. (will happen lazily in FirJavaClass.annotations) Resolve annotations // 2. Enhance type parameter bounds - may refer to each other, take default nullability from annotations // 3. (will happen lazily in FirJavaClass.superTypeRefs) Enhance super types - may refer to type parameter bounds, take default nullability from annotations - firJavaClass.setAnnotationsFromJava(session, javaClass, javaTypeParameterStack) enhancement.enhanceTypeParameterBoundsAfterFirstRound(firJavaClass.typeParameters, initialBounds) - firJavaClass.replaceDeprecationsProvider(firJavaClass.getDeprecationsProvider(session)) + return firJavaClass } @@ -194,6 +193,7 @@ abstract class FirJavaFacade( val moduleData = getModuleDataForClass(javaClass) return buildJavaClass { resolvePhase = FirResolvePhase.BODY_RESOLVE + javaAnnotations += javaClass.annotations source = javaClass.toSourceElement() this.moduleData = moduleData symbol = classSymbol diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/declarations/FirJavaClass.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/declarations/FirJavaClass.kt index baa08cad75e..72304a0b60b 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/declarations/FirJavaClass.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/declarations/FirJavaClass.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2023 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. */ @@ -15,10 +15,12 @@ import org.jetbrains.kotlin.fir.MutableOrEmptyList import org.jetbrains.kotlin.fir.builder.FirAnnotationContainerBuilder import org.jetbrains.kotlin.fir.builder.FirBuilderDsl import org.jetbrains.kotlin.fir.builder.toMutableOrEmpty +import org.jetbrains.kotlin.fir.caches.firCachesFactory import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.builder.FirRegularClassBuilder import org.jetbrains.kotlin.fir.expressions.FirAnnotation import org.jetbrains.kotlin.fir.java.JavaTypeParameterStack +import org.jetbrains.kotlin.fir.java.convertAnnotationsToFir import org.jetbrains.kotlin.fir.java.enhancement.FirSignatureEnhancement import org.jetbrains.kotlin.fir.references.FirControlFlowGraphReference import org.jetbrains.kotlin.fir.scopes.FirScopeProvider @@ -28,6 +30,7 @@ import org.jetbrains.kotlin.fir.visitors.FirTransformer import org.jetbrains.kotlin.fir.visitors.FirVisitor import org.jetbrains.kotlin.fir.visitors.transformInplace import org.jetbrains.kotlin.fir.visitors.transformSingle +import org.jetbrains.kotlin.load.java.structure.JavaAnnotation import org.jetbrains.kotlin.load.java.structure.JavaPackage import org.jetbrains.kotlin.name.Name import kotlin.properties.Delegates @@ -39,7 +42,7 @@ class FirJavaClass @FirImplementationDetail internal constructor( override var resolvePhase: FirResolvePhase, override val name: Name, override val origin: FirDeclarationOrigin.Java, - override var annotations: MutableOrEmptyList, + private val unEnhancedAnnotations: MutableOrEmptyList, override var status: FirDeclarationStatus, override val classKind: ClassKind, override val declarations: MutableList, @@ -53,7 +56,6 @@ class FirJavaClass @FirImplementationDetail internal constructor( ) : FirRegularClass() { override val hasLazyNestedClassifiers: Boolean get() = true override val controlFlowGraphReference: FirControlFlowGraphReference? get() = null - override var deprecationsProvider: DeprecationsProvider = UnresolvedDeprecationProvider override val contextReceivers: List get() = emptyList() @@ -70,6 +72,16 @@ class FirJavaClass @FirImplementationDetail internal constructor( enhancement.enhanceSuperTypes(unenhnancedSuperTypes) } + // TODO: the lazy annotations is a workaround for KT-55387, some non-lazy solution should probably be used instead + override val annotations: List by lazy { + unEnhancedAnnotations.convertAnnotationsToFir(moduleData.session, javaTypeParameterStack) + } + + // TODO: the lazy deprecationsProvider is a workaround for KT-55387, some non-lazy solution should probably be used instead + override val deprecationsProvider: DeprecationsProvider by lazy { + getDeprecationsProvider(moduleData.session) + } + override fun replaceSuperTypeRefs(newSuperTypeRefs: List) { error("${::replaceSuperTypeRefs.name} should not be called for ${this::class.simpleName}, ${superTypeRefs::class.simpleName} is lazily calulated") } @@ -79,7 +91,7 @@ class FirJavaClass @FirImplementationDetail internal constructor( } override fun replaceDeprecationsProvider(newDeprecationsProvider: DeprecationsProvider) { - deprecationsProvider = newDeprecationsProvider + error("${::replaceDeprecationsProvider.name} should not be called for ${this::class.simpleName}, ${deprecationsProvider::class.simpleName} is lazily calculated") } override fun replaceControlFlowGraphReference(newControlFlowGraphReference: FirControlFlowGraphReference?) {} @@ -116,11 +128,10 @@ class FirJavaClass @FirImplementationDetail internal constructor( } override fun replaceAnnotations(newAnnotations: List) { - annotations = newAnnotations.toMutableOrEmpty() + error("${::replaceAnnotations.name} should not be called for ${this::class.simpleName}, ${annotations::class.simpleName} is lazily calculated") } override fun transformAnnotations(transformer: FirTransformer, data: D): FirJavaClass { - annotations.transformInplace(transformer, data) return this } @@ -149,7 +160,7 @@ class FirJavaClassBuilder : FirRegularClassBuilder(), FirAnnotationContainerBuil override var source: KtSourceElement? = null override var resolvePhase: FirResolvePhase = FirResolvePhase.RAW_FIR - override val annotations: MutableList = mutableListOf() + var javaAnnotations: MutableList = mutableListOf() override val typeParameters: MutableList = mutableListOf() override val declarations: MutableList = mutableListOf() @@ -157,14 +168,13 @@ class FirJavaClassBuilder : FirRegularClassBuilder(), FirAnnotationContainerBuil @OptIn(FirImplementationDetail::class) override fun build(): FirJavaClass { - @Suppress("UNCHECKED_CAST") return FirJavaClass( source, moduleData, resolvePhase = FirResolvePhase.ANALYZED_DEPENDENCIES, name, origin = javaOrigin(isFromSource), - annotations.toMutableOrEmpty(), + javaAnnotations.toMutableOrEmpty(), status, classKind, declarations, diff --git a/compiler/testData/asJava/lightClasses/lightClassByFqName/JavaClassWithAnnotation.fir.java b/compiler/testData/asJava/lightClasses/lightClassByFqName/JavaClassWithAnnotation.fir.java new file mode 100644 index 00000000000..6e5584edd3f --- /dev/null +++ b/compiler/testData/asJava/lightClasses/lightClassByFqName/JavaClassWithAnnotation.fir.java @@ -0,0 +1,4 @@ +public final class KotlinFacadeKt /* one.KotlinFacadeKt*/ { + @org.jetbrains.annotations.NotNull() + private static final java.lang.String MY_FIELD = "abcd" /* initializer type: java.lang.String */; +} diff --git a/compiler/testData/asJava/lightClasses/lightClassByFqName/JavaClassWithAnnotation.java b/compiler/testData/asJava/lightClasses/lightClassByFqName/JavaClassWithAnnotation.java new file mode 100644 index 00000000000..ff39ad9741e --- /dev/null +++ b/compiler/testData/asJava/lightClasses/lightClassByFqName/JavaClassWithAnnotation.java @@ -0,0 +1,4 @@ +public final class KotlinFacadeKt /* one.KotlinFacadeKt*/ { + @org.jetbrains.annotations.NotNull() + private static final java.lang.String MY_FIELD; +} \ No newline at end of file diff --git a/compiler/testData/asJava/lightClasses/lightClassByFqName/JavaClassWithAnnotation.kt b/compiler/testData/asJava/lightClasses/lightClassByFqName/JavaClassWithAnnotation.kt new file mode 100644 index 00000000000..7ef6d6af269 --- /dev/null +++ b/compiler/testData/asJava/lightClasses/lightClassByFqName/JavaClassWithAnnotation.kt @@ -0,0 +1,37 @@ +// one.KotlinFacadeKt + +// FILE: KotlinFacade.kt +package one + +import one.JavaClass.staticJavaMethod + +private val MY_FIELD = "abcd" + +// FILE: one/JavaClass.java +package one; + +import two.Service; + +import static one.KotlinFacadeKt.*; + +@Service(Service.Level.PROJECT) +public final class JavaClass { + static void staticJavaMethod() { + + } +} + +// FILE: two/Service.java +package two; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface Service { + Level[] value() default {}; + + enum Level { + PROJECT + } +} diff --git a/compiler/tests-gen/org/jetbrains/kotlin/asJava/CompilerLightClassTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/asJava/CompilerLightClassTestGenerated.java index 3e4618dafc4..9a0166194b4 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/asJava/CompilerLightClassTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/asJava/CompilerLightClassTestGenerated.java @@ -169,6 +169,11 @@ public class CompilerLightClassTestGenerated extends AbstractCompilerLightClassT runTest("compiler/testData/asJava/lightClasses/lightClassByFqName/JavaBetween.kt"); } + @TestMetadata("JavaClassWithAnnotation.kt") + public void testJavaClassWithAnnotation() throws Exception { + runTest("compiler/testData/asJava/lightClasses/lightClassByFqName/JavaClassWithAnnotation.kt"); + } + @TestMetadata("JvmNameOnMember.kt") public void testJvmNameOnMember() throws Exception { runTest("compiler/testData/asJava/lightClasses/lightClassByFqName/JvmNameOnMember.kt");