From 62ad784b73a22874f281f7960731412d111576b6 Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Tue, 21 Mar 2023 13:22:49 +0200 Subject: [PATCH] [FIR] Fix matching `annotated` predicate for java and binary declarations ^KT-57400 Fixed --- .../FirPredicateBasedProviderImpl.kt | 18 +++--- .../kotlin/fir/plugin/annotations.kt | 1 + .../AllOpenMatcherBasedStatusTransformer.kt | 57 +++++++++++++++++++ .../FirPluginPrototypeExtensionRegistrar.kt | 2 + .../box/superCompiledClassAnnotation.fir.txt | 51 +++++++++++++++++ .../box/superCompiledClassAnnotation.kt | 36 ++++++++++++ .../box/superJavaClassAnnotation.fir.txt | 46 +++++++++++++++ .../testData/box/superJavaClassAnnotation.kt | 36 ++++++++++++ ...reePluginBlackBoxCodegenTestGenerated.java | 12 ++++ 9 files changed, 252 insertions(+), 7 deletions(-) create mode 100644 plugins/fir-plugin-prototype/src/org/jetbrains/kotlin/fir/plugin/AllOpenMatcherBasedStatusTransformer.kt create mode 100644 plugins/fir-plugin-prototype/testData/box/superCompiledClassAnnotation.fir.txt create mode 100644 plugins/fir-plugin-prototype/testData/box/superCompiledClassAnnotation.kt create mode 100644 plugins/fir-plugin-prototype/testData/box/superJavaClassAnnotation.fir.txt create mode 100644 plugins/fir-plugin-prototype/testData/box/superJavaClassAnnotation.kt diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirPredicateBasedProviderImpl.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirPredicateBasedProviderImpl.kt index ed171e4506c..2f7a5a82963 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirPredicateBasedProviderImpl.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirPredicateBasedProviderImpl.kt @@ -10,10 +10,7 @@ import com.google.common.collect.Multimap import kotlinx.collections.immutable.PersistentList import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.NoMutableState -import org.jetbrains.kotlin.fir.declarations.FirClass -import org.jetbrains.kotlin.fir.declarations.FirDeclaration -import org.jetbrains.kotlin.fir.declarations.FirFile -import org.jetbrains.kotlin.fir.declarations.FirResolvePhase +import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.utils.isLocal import org.jetbrains.kotlin.fir.expressions.FirAnnotation import org.jetbrains.kotlin.fir.extensions.predicate.AbstractPredicate @@ -155,10 +152,17 @@ class FirPredicateBasedProviderImpl(private val session: FirSession) : FirPredic // ------------------------------------ Utilities ------------------------------------ private fun matchWith(declaration: FirDeclaration, annotations: Set): Boolean { - if (declaration is FirClass && declaration.isLocal) { - return declaration.annotations.any { it.fqName(session) in annotations } + return when (declaration.origin) { + FirDeclarationOrigin.Library, is FirDeclarationOrigin.Java -> matchNonIndexedDeclaration(declaration, annotations) + else -> when (declaration is FirClass && declaration.isLocal) { + true -> matchNonIndexedDeclaration(declaration, annotations) + false -> cache.annotationsOfDeclaration[declaration].any { it in annotations } + } } - return cache.annotationsOfDeclaration[declaration].any { it in annotations } + } + + private fun matchNonIndexedDeclaration(declaration: FirDeclaration, annotations: Set): Boolean { + return declaration.annotations.any { it.fqName(session) in annotations } } private fun matchUnder(declaration: FirDeclaration, annotations: Set): Boolean { diff --git a/plugins/fir-plugin-prototype/plugin-annotations/src/org/jetbrains/kotlin/fir/plugin/annotations.kt b/plugins/fir-plugin-prototype/plugin-annotations/src/org/jetbrains/kotlin/fir/plugin/annotations.kt index bfa233804e5..7688463494a 100644 --- a/plugins/fir-plugin-prototype/plugin-annotations/src/org/jetbrains/kotlin/fir/plugin/annotations.kt +++ b/plugins/fir-plugin-prototype/plugin-annotations/src/org/jetbrains/kotlin/fir/plugin/annotations.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.plugin import kotlin.reflect.KClass annotation class AllOpen +annotation class AllOpen2 annotation class DummyFunction annotation class ExternalClassWithNested diff --git a/plugins/fir-plugin-prototype/src/org/jetbrains/kotlin/fir/plugin/AllOpenMatcherBasedStatusTransformer.kt b/plugins/fir-plugin-prototype/src/org/jetbrains/kotlin/fir/plugin/AllOpenMatcherBasedStatusTransformer.kt new file mode 100644 index 00000000000..7290b9238f0 --- /dev/null +++ b/plugins/fir-plugin-prototype/src/org/jetbrains/kotlin/fir/plugin/AllOpenMatcherBasedStatusTransformer.kt @@ -0,0 +1,57 @@ +/* + * 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.fir.plugin + +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.copy +import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration +import org.jetbrains.kotlin.fir.declarations.FirDeclaration +import org.jetbrains.kotlin.fir.declarations.FirDeclarationStatus +import org.jetbrains.kotlin.fir.declarations.FirRegularClass +import org.jetbrains.kotlin.fir.extensions.FirStatusTransformerExtension +import org.jetbrains.kotlin.fir.extensions.predicate.DeclarationPredicate +import org.jetbrains.kotlin.fir.extensions.utils.AbstractSimpleClassPredicateMatchingService +import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider +import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol +import org.jetbrains.kotlin.name.FqName + +class AllOpenMatcherBasedStatusTransformer(session: FirSession) : FirStatusTransformerExtension(session) { + override fun needTransformStatus(declaration: FirDeclaration): Boolean { + return when (declaration) { + is FirRegularClass -> declaration.classKind == ClassKind.CLASS && session.allOpenPredicateMatcher.isAnnotated(declaration.symbol) + is FirCallableDeclaration -> { + val parentClassId = declaration.symbol.callableId.classId ?: return false + if (parentClassId.isLocal) return false + val parentClassSymbol = session.symbolProvider.getClassLikeSymbolByClassId(parentClassId) as? FirRegularClassSymbol + ?: return false + session.allOpenPredicateMatcher.isAnnotated(parentClassSymbol) + } + else -> false + } + } + + override fun transformStatus(status: FirDeclarationStatus, declaration: FirDeclaration): FirDeclarationStatus { + return if (status.modality == null) { + status.copy(modality = Modality.OPEN) + } else { + status + } + } +} + +class AllOpenPredicateMatcher(session: FirSession) : AbstractSimpleClassPredicateMatchingService(session) { + companion object { + private val ALL_OPEN2 = FqName("org.jetbrains.kotlin.fir.plugin.AllOpen2") + } + + override val predicate = DeclarationPredicate.create { + annotated(ALL_OPEN2) + } +} + +private val FirSession.allOpenPredicateMatcher: AllOpenPredicateMatcher by FirSession.sessionComponentAccessor() diff --git a/plugins/fir-plugin-prototype/src/org/jetbrains/kotlin/fir/plugin/FirPluginPrototypeExtensionRegistrar.kt b/plugins/fir-plugin-prototype/src/org/jetbrains/kotlin/fir/plugin/FirPluginPrototypeExtensionRegistrar.kt index 9f1f008184d..67e9d4a6a40 100644 --- a/plugins/fir-plugin-prototype/src/org/jetbrains/kotlin/fir/plugin/FirPluginPrototypeExtensionRegistrar.kt +++ b/plugins/fir-plugin-prototype/src/org/jetbrains/kotlin/fir/plugin/FirPluginPrototypeExtensionRegistrar.kt @@ -18,6 +18,8 @@ import org.jetbrains.kotlin.ir.plugin.GeneratedDeclarationsIrBodyFiller class FirPluginPrototypeExtensionRegistrar : FirExtensionRegistrar() { override fun ExtensionRegistrarContext.configurePlugin() { +::AllOpenStatusTransformer + +::AllOpenMatcherBasedStatusTransformer + +::AllOpenPredicateMatcher +::AllPublicVisibilityTransformer +::SomeAdditionalSupertypeGenerator +::SupertypeWithArgumentGenerator diff --git a/plugins/fir-plugin-prototype/testData/box/superCompiledClassAnnotation.fir.txt b/plugins/fir-plugin-prototype/testData/box/superCompiledClassAnnotation.fir.txt new file mode 100644 index 00000000000..b64789f18f9 --- /dev/null +++ b/plugins/fir-plugin-prototype/testData/box/superCompiledClassAnnotation.fir.txt @@ -0,0 +1,51 @@ +Module: lib +FILE: lib.kt + @R|org/jetbrains/kotlin/fir/plugin/AllOpen2|() public abstract interface Intf : R|kotlin/Any| { + public open fun intfMethod(): R|kotlin/Unit| { + } + + } +Module: main +FILE: module_main_superCompiledClassAnnotation.kt + public open class BaseImpl : R|Base_ShouldBeOpen| { + public constructor(): R|BaseImpl| { + super() + } + + public open fun baseImplMethod_ShouldBeOpen(): R|kotlin/Unit| { + } + + } + public open class BaseImpl2_ShouldBeOpen : R|BaseImpl| { + public constructor(): R|BaseImpl2_ShouldBeOpen| { + super() + } + + public open fun baseImpl2Method_ShouldBeOpen(): R|kotlin/Unit| { + } + + public open val baseImpl2Property_ShouldBeOpen: R|kotlin/String| = String() + public get(): R|kotlin/String| + + } + public open class IntfImpl : R|Intf| { + public constructor(): R|IntfImpl| { + super() + } + + public open fun intfImplMethod_ShouldBeOpen(): R|kotlin/Unit| { + } + + } + public open class IntfImpl2_ShouldBeOpen : R|IntfImpl| { + public constructor(): R|IntfImpl2_ShouldBeOpen| { + super() + } + + public open fun intfImpl2Method_ShouldBeOpen(): R|kotlin/Unit| { + } + + } + public final fun box(): R|kotlin/String| { + ^box String(OK) + } diff --git a/plugins/fir-plugin-prototype/testData/box/superCompiledClassAnnotation.kt b/plugins/fir-plugin-prototype/testData/box/superCompiledClassAnnotation.kt new file mode 100644 index 00000000000..c524b5b8aef --- /dev/null +++ b/plugins/fir-plugin-prototype/testData/box/superCompiledClassAnnotation.kt @@ -0,0 +1,36 @@ +// MODULE: lib +// FILE: lib.kt +import org.jetbrains.kotlin.fir.plugin.AllOpen2 + +@AllOpen2 +interface Intf { + fun intfMethod() {} +} + +// FILE: Base_ShouldBeOpen.java +import org.jetbrains.kotlin.fir.plugin.AllOpen2; + +@AllOpen2 +public abstract class Base_ShouldBeOpen { + public void baseMethod() {} +} + +// MODULE: main(lib) +open class BaseImpl : Base_ShouldBeOpen() { + fun baseImplMethod_ShouldBeOpen() {} +} + +class BaseImpl2_ShouldBeOpen : BaseImpl() { + fun baseImpl2Method_ShouldBeOpen() {} + val baseImpl2Property_ShouldBeOpen = "" +} + +open class IntfImpl : Intf { + fun intfImplMethod_ShouldBeOpen() {} +} + +class IntfImpl2_ShouldBeOpen : IntfImpl() { + fun intfImpl2Method_ShouldBeOpen() {} +} + +fun box() = "OK" diff --git a/plugins/fir-plugin-prototype/testData/box/superJavaClassAnnotation.fir.txt b/plugins/fir-plugin-prototype/testData/box/superJavaClassAnnotation.fir.txt new file mode 100644 index 00000000000..d0929f418bb --- /dev/null +++ b/plugins/fir-plugin-prototype/testData/box/superJavaClassAnnotation.fir.txt @@ -0,0 +1,46 @@ +FILE: main.kt + public open class BaseImpl : R|Base_ShouldBeOpen| { + public constructor(): R|BaseImpl| { + super() + } + + public open fun baseImplMethod_ShouldBeOpen(): R|kotlin/Unit| { + } + + } + public open class BaseImpl2_ShouldBeOpen : R|BaseImpl| { + public constructor(): R|BaseImpl2_ShouldBeOpen| { + super() + } + + public open fun baseImpl2Method_ShouldBeOpen(): R|kotlin/Unit| { + } + + public open val baseImpl2Property_ShouldBeOpen: R|kotlin/String| = String() + public get(): R|kotlin/String| + + } + public open class IntfImpl : R|Intf| { + public constructor(): R|IntfImpl| { + super() + } + + public open override fun intfMethod(): R|kotlin/Unit| { + } + + public open fun intfImplMethod_ShouldBeOpen(): R|kotlin/Unit| { + } + + } + public open class IntfImpl2_ShouldBeOpen : R|IntfImpl| { + public constructor(): R|IntfImpl2_ShouldBeOpen| { + super() + } + + public open fun intfImpl2Method_ShouldBeOpen(): R|kotlin/Unit| { + } + + } + public final fun box(): R|kotlin/String| { + ^box String(OK) + } diff --git a/plugins/fir-plugin-prototype/testData/box/superJavaClassAnnotation.kt b/plugins/fir-plugin-prototype/testData/box/superJavaClassAnnotation.kt new file mode 100644 index 00000000000..c11d11f8379 --- /dev/null +++ b/plugins/fir-plugin-prototype/testData/box/superJavaClassAnnotation.kt @@ -0,0 +1,36 @@ +// FILE: Base_ShouldBeOpen.java +import org.jetbrains.kotlin.fir.plugin.AllOpen2; + +@AllOpen2 +public abstract class Base_ShouldBeOpen { + public void baseMethod() {} +} + +// FILE: Intf.java +import org.jetbrains.kotlin.fir.plugin.AllOpen2; + +@AllOpen2 +public interface Intf { + void intfMethod(); +} + +// FILE: main.kt +open class BaseImpl : Base_ShouldBeOpen() { + fun baseImplMethod_ShouldBeOpen() {} +} + +class BaseImpl2_ShouldBeOpen : BaseImpl() { + fun baseImpl2Method_ShouldBeOpen() {} + val baseImpl2Property_ShouldBeOpen = "" +} + +open class IntfImpl : Intf { + override fun intfMethod() {} + fun intfImplMethod_ShouldBeOpen() {} +} + +class IntfImpl2_ShouldBeOpen : IntfImpl() { + fun intfImpl2Method_ShouldBeOpen() {} +} + +fun box() = "OK" diff --git a/plugins/fir-plugin-prototype/tests-gen/org/jetbrains/kotlin/fir/plugin/runners/FirLightTreePluginBlackBoxCodegenTestGenerated.java b/plugins/fir-plugin-prototype/tests-gen/org/jetbrains/kotlin/fir/plugin/runners/FirLightTreePluginBlackBoxCodegenTestGenerated.java index bae7fb53c4d..c05c61d0935 100644 --- a/plugins/fir-plugin-prototype/tests-gen/org/jetbrains/kotlin/fir/plugin/runners/FirLightTreePluginBlackBoxCodegenTestGenerated.java +++ b/plugins/fir-plugin-prototype/tests-gen/org/jetbrains/kotlin/fir/plugin/runners/FirLightTreePluginBlackBoxCodegenTestGenerated.java @@ -73,6 +73,18 @@ public class FirLightTreePluginBlackBoxCodegenTestGenerated extends AbstractFirL runTest("plugins/fir-plugin-prototype/testData/box/serializer.kt"); } + @Test + @TestMetadata("superCompiledClassAnnotation.kt") + public void testSuperCompiledClassAnnotation() throws Exception { + runTest("plugins/fir-plugin-prototype/testData/box/superCompiledClassAnnotation.kt"); + } + + @Test + @TestMetadata("superJavaClassAnnotation.kt") + public void testSuperJavaClassAnnotation() throws Exception { + runTest("plugins/fir-plugin-prototype/testData/box/superJavaClassAnnotation.kt"); + } + @Test @TestMetadata("topLevelCallables.kt") public void testTopLevelCallables() throws Exception {