[FIR] Fix matching annotated predicate for java and binary declarations

^KT-57400 Fixed
This commit is contained in:
Dmitriy Novozhilov
2023-03-21 13:22:49 +02:00
committed by Space Team
parent 1ac7d13c96
commit 62ad784b73
9 changed files with 252 additions and 7 deletions
@@ -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<AnnotationFqn>): 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<AnnotationFqn>): Boolean {
return declaration.annotations.any { it.fqName(session) in annotations }
}
private fun matchUnder(declaration: FirDeclaration, annotations: Set<AnnotationFqn>): Boolean {
@@ -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
@@ -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()
@@ -18,6 +18,8 @@ import org.jetbrains.kotlin.ir.plugin.GeneratedDeclarationsIrBodyFiller
class FirPluginPrototypeExtensionRegistrar : FirExtensionRegistrar() {
override fun ExtensionRegistrarContext.configurePlugin() {
+::AllOpenStatusTransformer
+::AllOpenMatcherBasedStatusTransformer
+::AllOpenPredicateMatcher
+::AllPublicVisibilityTransformer
+::SomeAdditionalSupertypeGenerator
+::SupertypeWithArgumentGenerator
@@ -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<R|Base_ShouldBeOpen|>()
}
public open fun baseImplMethod_ShouldBeOpen(): R|kotlin/Unit| {
}
}
public open class BaseImpl2_ShouldBeOpen : R|BaseImpl| {
public constructor(): R|BaseImpl2_ShouldBeOpen| {
super<R|BaseImpl|>()
}
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<R|kotlin/Any|>()
}
public open fun intfImplMethod_ShouldBeOpen(): R|kotlin/Unit| {
}
}
public open class IntfImpl2_ShouldBeOpen : R|IntfImpl| {
public constructor(): R|IntfImpl2_ShouldBeOpen| {
super<R|IntfImpl|>()
}
public open fun intfImpl2Method_ShouldBeOpen(): R|kotlin/Unit| {
}
}
public final fun box(): R|kotlin/String| {
^box String(OK)
}
@@ -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"
@@ -0,0 +1,46 @@
FILE: main.kt
public open class BaseImpl : R|Base_ShouldBeOpen| {
public constructor(): R|BaseImpl| {
super<R|Base_ShouldBeOpen|>()
}
public open fun baseImplMethod_ShouldBeOpen(): R|kotlin/Unit| {
}
}
public open class BaseImpl2_ShouldBeOpen : R|BaseImpl| {
public constructor(): R|BaseImpl2_ShouldBeOpen| {
super<R|BaseImpl|>()
}
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<R|kotlin/Any|>()
}
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<R|IntfImpl|>()
}
public open fun intfImpl2Method_ShouldBeOpen(): R|kotlin/Unit| {
}
}
public final fun box(): R|kotlin/String| {
^box String(OK)
}
@@ -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"
@@ -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 {