[FIR] Add ability to specify if meta annotation itself should match metaAnnotated predicate

^KT-55843 Fixed
This commit is contained in:
Dmitriy Novozhilov
2023-01-11 11:32:44 +02:00
committed by Space Team
parent e88a6af7a0
commit 4363b0815c
12 changed files with 33 additions and 20 deletions
@@ -134,7 +134,7 @@ internal class LLFirIdePredicateBasedProvider(
override fun visitMetaAnnotatedWith(predicate: AbstractPredicate.MetaAnnotatedWith<P>, data: FirDeclaration): Boolean { override fun visitMetaAnnotatedWith(predicate: AbstractPredicate.MetaAnnotatedWith<P>, data: FirDeclaration): Boolean {
return data.annotations.any { annotation -> return data.annotations.any { annotation ->
annotation.markedWithMetaAnnotation(session, data, predicate.metaAnnotations) annotation.markedWithMetaAnnotation(session, data, predicate.metaAnnotations, predicate.includeItself)
} }
} }
@@ -140,7 +140,7 @@ class FirPredicateBasedProviderImpl(private val session: FirSession) : FirPredic
override fun visitMetaAnnotatedWith(predicate: AbstractPredicate.MetaAnnotatedWith<P>, data: FirDeclaration): Boolean { override fun visitMetaAnnotatedWith(predicate: AbstractPredicate.MetaAnnotatedWith<P>, data: FirDeclaration): Boolean {
return data.annotations.any { annotation -> return data.annotations.any { annotation ->
annotation.markedWithMetaAnnotation(session, data, predicate.metaAnnotations) annotation.markedWithMetaAnnotation(session, data, predicate.metaAnnotations, predicate.includeItself)
} }
} }
@@ -190,23 +190,25 @@ class FirPredicateBasedProviderImpl(private val session: FirSession) : FirPredic
fun FirAnnotation.markedWithMetaAnnotation( fun FirAnnotation.markedWithMetaAnnotation(
session: FirSession, session: FirSession,
containingDeclaration: FirDeclaration, containingDeclaration: FirDeclaration,
metaAnnotations: Set<AnnotationFqn> metaAnnotations: Set<AnnotationFqn>,
includeItself: Boolean
): Boolean { ): Boolean {
containingDeclaration.symbol.lazyResolveToPhase(FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS) containingDeclaration.symbol.lazyResolveToPhase(FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS)
return annotationTypeRef.coneTypeSafe<ConeKotlinType>() return annotationTypeRef.coneTypeSafe<ConeKotlinType>()
?.toRegularClassSymbol(session) ?.toRegularClassSymbol(session)
.markedWithMetaAnnotationImpl(session, metaAnnotations, mutableSetOf()) .markedWithMetaAnnotationImpl(session, metaAnnotations, includeItself, mutableSetOf())
} }
fun FirRegularClassSymbol?.markedWithMetaAnnotationImpl( fun FirRegularClassSymbol?.markedWithMetaAnnotationImpl(
session: FirSession, session: FirSession,
metaAnnotations: Set<AnnotationFqn>, metaAnnotations: Set<AnnotationFqn>,
includeItself: Boolean,
visited: MutableSet<FirRegularClassSymbol> visited: MutableSet<FirRegularClassSymbol>
): Boolean { ): Boolean {
if (this == null) return false if (this == null) return false
if (!visited.add(this)) return false if (!visited.add(this)) return false
if (this.classId.asSingleFqName() in metaAnnotations) return true if (this.classId.asSingleFqName() in metaAnnotations) return includeItself
return this.resolvedCompilerAnnotationsWithClassIds return this.resolvedCompilerAnnotationsWithClassIds
.mapNotNull { it.annotationTypeRef.coneTypeSafe<ConeKotlinType>()?.toRegularClassSymbol(session) } .mapNotNull { it.annotationTypeRef.coneTypeSafe<ConeKotlinType>()?.toRegularClassSymbol(session) }
.any { it.markedWithMetaAnnotationImpl(session, metaAnnotations, visited) } .any { it.markedWithMetaAnnotationImpl(session, metaAnnotations, includeItself = true, visited) }
} }
@@ -144,7 +144,7 @@ internal abstract class AbstractFirSpecificAnnotationResolveTransformer(
} }
private fun ConeKotlinType.markedWithMetaAnnotation(session: FirSession, metaAnnotations: Set<AnnotationFqn>): Boolean { private fun ConeKotlinType.markedWithMetaAnnotation(session: FirSession, metaAnnotations: Set<AnnotationFqn>): Boolean {
return toRegularClassSymbol(session).markedWithMetaAnnotationImpl(session, metaAnnotations, mutableSetOf()) return toRegularClassSymbol(session).markedWithMetaAnnotationImpl(session, metaAnnotations, includeItself = true, mutableSetOf())
} }
@@ -169,8 +169,13 @@ sealed interface AbstractPredicate<P : AbstractPredicate<P>> {
/** /**
* Matches declarations, which are annotated with annotations which are annotated with [metaAnnotations] * Matches declarations, which are annotated with annotations which are annotated with [metaAnnotations]
*
* [includeItself] flag determines if declaration, annotated with meta-annotation itself will
* be considered as matching to predicate
*
* Relation "annotation with meta annotation" is transitive. E.g. in snippet below some declaration will * Relation "annotation with meta annotation" is transitive. E.g. in snippet below some declaration will
* be matched with predicate MetaAnnotatedWith("Ann") if it is annotated with `@Ann`, `@Some` or `@Other` * be matched with predicate MetaAnnotatedWith("Ann") if it is annotated with `@Ann` (if [includeItself] set to true),
* `@Some` or `@Other`
* *
* @Ann * @Ann
* annotation class Some * annotation class Some
@@ -200,6 +205,8 @@ sealed interface AbstractPredicate<P : AbstractPredicate<P>> {
* and can not be used for global lookup * and can not be used for global lookup
*/ */
sealed interface MetaAnnotatedWith<P : AbstractPredicate<P>> : AbstractPredicate<P> { sealed interface MetaAnnotatedWith<P : AbstractPredicate<P>> : AbstractPredicate<P> {
val includeItself: Boolean
override fun <R, D> accept(visitor: PredicateVisitor<P, R, D>, data: D): R { override fun <R, D> accept(visitor: PredicateVisitor<P, R, D>, data: D): R {
return visitor.visitMetaAnnotatedWith(this, data) return visitor.visitMetaAnnotatedWith(this, data)
} }
@@ -91,7 +91,8 @@ sealed class DeclarationPredicate : AbstractPredicate<DeclarationPredicate> {
// ------------------------------------ MetaAnnotated ------------------------------------ // ------------------------------------ MetaAnnotated ------------------------------------
class MetaAnnotatedWith( class MetaAnnotatedWith(
override val metaAnnotations: Set<AnnotationFqn> override val metaAnnotations: Set<AnnotationFqn>,
override val includeItself: Boolean
) : DeclarationPredicate(), AbstractPredicate.MetaAnnotatedWith<DeclarationPredicate> { ) : DeclarationPredicate(), AbstractPredicate.MetaAnnotatedWith<DeclarationPredicate> {
init { init {
require(metaAnnotations.isNotEmpty()) { require(metaAnnotations.isNotEmpty()) {
@@ -122,7 +123,8 @@ sealed class DeclarationPredicate : AbstractPredicate<DeclarationPredicate> {
override fun annotatedOrUnder(vararg annotations: AnnotationFqn): DeclarationPredicate = override fun annotatedOrUnder(vararg annotations: AnnotationFqn): DeclarationPredicate =
annotated(*annotations) or ancestorAnnotated(*annotations) annotated(*annotations) or ancestorAnnotated(*annotations)
fun metaAnnotated(vararg metaAnnotations: AnnotationFqn): DeclarationPredicate = MetaAnnotatedWith(metaAnnotations.toSet()) fun metaAnnotated(vararg metaAnnotations: AnnotationFqn, includeItself: Boolean): DeclarationPredicate =
MetaAnnotatedWith(metaAnnotations.toSet(), includeItself)
// ------------------- collections ------------------- // ------------------- collections -------------------
override fun annotated(annotations: Collection<AnnotationFqn>): DeclarationPredicate = AnnotatedWith(annotations.toSet()) override fun annotated(annotations: Collection<AnnotationFqn>): DeclarationPredicate = AnnotatedWith(annotations.toSet())
@@ -137,7 +139,8 @@ sealed class DeclarationPredicate : AbstractPredicate<DeclarationPredicate> {
override fun annotatedOrUnder(annotations: Collection<AnnotationFqn>): DeclarationPredicate = override fun annotatedOrUnder(annotations: Collection<AnnotationFqn>): DeclarationPredicate =
annotated(annotations) or ancestorAnnotated(annotations) annotated(annotations) or ancestorAnnotated(annotations)
fun metaAnnotated(metaAnnotations: Collection<AnnotationFqn>): DeclarationPredicate = MetaAnnotatedWith(metaAnnotations.toSet()) fun metaAnnotated(metaAnnotations: Collection<AnnotationFqn>, includeItself: Boolean): DeclarationPredicate =
MetaAnnotatedWith(metaAnnotations.toSet(), includeItself)
} }
companion object { companion object {
@@ -57,7 +57,7 @@ class FirAllOpenPredicateMatcher(
override val predicate = DeclarationPredicate.create { override val predicate = DeclarationPredicate.create {
val annotationFqNames = allOpenAnnotationFqNames.map { FqName(it) } val annotationFqNames = allOpenAnnotationFqNames.map { FqName(it) }
annotated(annotationFqNames) or metaAnnotated(annotationFqNames) annotated(annotationFqNames) or metaAnnotated(annotationFqNames, includeItself = true)
} }
} }
@@ -20,7 +20,7 @@ class AllOpenStatusTransformer(session: FirSession) : FirStatusTransformerExtens
companion object { companion object {
private val ALL_OPEN = FqName("org.jetbrains.kotlin.fir.plugin.AllOpen") private val ALL_OPEN = FqName("org.jetbrains.kotlin.fir.plugin.AllOpen")
private val PREDICATE = DeclarationPredicate.create { private val PREDICATE = DeclarationPredicate.create {
annotatedOrUnder(ALL_OPEN) or metaAnnotated(ALL_OPEN) annotatedOrUnder(ALL_OPEN) or metaAnnotated(ALL_OPEN, includeItself = true)
} }
} }
@@ -31,7 +31,7 @@ class SomeAdditionalSupertypeGenerator(session: FirSession) : FirSupertypeGenera
companion object { companion object {
private val myInterfaceClassId = ClassId(FqName("foo"), Name.identifier("MyInterface")) private val myInterfaceClassId = ClassId(FqName("foo"), Name.identifier("MyInterface"))
private val PREDICATE = DeclarationPredicate.create { private val PREDICATE = DeclarationPredicate.create {
annotated("MyInterfaceSupertype".fqn()) or metaAnnotated("MetaSupertype".fqn()) annotated("MyInterfaceSupertype".fqn()) or metaAnnotated("MetaSupertype".fqn(), includeItself = false)
} }
} }
@@ -24,14 +24,14 @@ FILE: main.kt
} }
} }
@R|org/jetbrains/kotlin/fir/plugin/MetaSupertype|() public final class Zero : R|kotlin/Any|, R|foo/MyInterface| { @R|org/jetbrains/kotlin/fir/plugin/MetaSupertype|() public final class Zero : R|kotlin/Any| {
public constructor(): R|foo/Zero| { public constructor(): R|foo/Zero| {
super<R|kotlin/Any|>() super<R|kotlin/Any|>()
} }
} }
public final fun test(a: R|foo/Zero|, b: R|foo/First|, c: R|foo/Second|, d: R|foo/Third|): R|kotlin/Unit| { public final fun test(a: R|foo/Zero|, b: R|foo/First|, c: R|foo/Second|, d: R|foo/Third|): R|kotlin/Unit| {
R|<local>/a|.R|foo/MyInterface.foo|() R|<local>/a|.<Unresolved name: foo>#()
R|<local>/b|.R|foo/MyInterface.foo|() R|<local>/b|.R|foo/MyInterface.foo|()
R|<local>/c|.R|foo/MyInterface.foo|() R|<local>/c|.R|foo/MyInterface.foo|()
R|<local>/d|.R|foo/MyInterface.foo|() R|<local>/d|.R|foo/MyInterface.foo|()
@@ -21,7 +21,7 @@ class First
class Zero class Zero
fun test(a: Zero, b: First, c: Second, d: Third) { fun test(a: Zero, b: First, c: Second, d: Third) {
a.foo() a.<!UNRESOLVED_REFERENCE!>foo<!>() // should be an error, because meta predicate has inludeItself = false
b.foo() b.foo()
c.foo() c.foo()
d.foo() d.foo()
@@ -13,9 +13,10 @@ object FirSerializationPredicates {
annotated(setOf(SerializationAnnotations.serializerAnnotationFqName)) // @Serializer(for=...) annotated(setOf(SerializationAnnotations.serializerAnnotationFqName)) // @Serializer(for=...)
} }
internal val hasMetaAnnotation = DeclarationPredicate.create { internal val hasMetaAnnotation = DeclarationPredicate.create {
metaAnnotated(SerializationAnnotations.metaSerializableAnnotationFqName) metaAnnotated(SerializationAnnotations.metaSerializableAnnotationFqName, includeItself = false)
} }
internal val annotatedWithSerializableOrMeta = DeclarationPredicate.create { internal val annotatedWithSerializableOrMeta = DeclarationPredicate.create {
annotated(setOf(SerializationAnnotations.serializableAnnotationFqName)) or metaAnnotated(SerializationAnnotations.metaSerializableAnnotationFqName) annotated(setOf(SerializationAnnotations.serializableAnnotationFqName)) or
metaAnnotated(SerializationAnnotations.metaSerializableAnnotationFqName, includeItself = false)
} }
} }
@@ -22,7 +22,7 @@ class FirNoArgPredicateMatcher(
override val predicate = DeclarationPredicate.create { override val predicate = DeclarationPredicate.create {
val annotationFqNames = noArgAnnotationFqNames.map { FqName(it) } val annotationFqNames = noArgAnnotationFqNames.map { FqName(it) }
annotated(annotationFqNames) or metaAnnotated(annotationFqNames) annotated(annotationFqNames) or metaAnnotated(annotationFqNames, includeItself = true)
} }
} }