[FIR] Rework predicates system

Now predicates are split into LookupPredicate and DeclarationPredicate
  hierarchies. First one allows to perform global search for declarations
  and second one allows to check if some declaration matches the predicate.
Predicates with meta annotations are excluded from LookupPredicates,
  because it's impossible to create index of annotations with meta-annotations,
  because they can be located inside binary dependencies (so to achieve
  this we need to scan the whole classpath).
Also only one predicate with meta-annotations is left in DeclarationPredicate
  hierarchy (AnnotatedWithMeta)

^KT-53874 Fixed
^KT-53590 Fixed
This commit is contained in:
Dmitriy Novozhilov
2022-11-23 15:16:44 +02:00
committed by Space Team
parent 7a9a71a089
commit 246dc985a6
41 changed files with 934 additions and 605 deletions
@@ -6,7 +6,9 @@
package org.jetbrains.kotlin.fir.extensions
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.extensions.predicate.AbstractPredicate
import org.jetbrains.kotlin.fir.extensions.predicate.DeclarationPredicate
import org.jetbrains.kotlin.fir.extensions.predicate.LookupPredicate
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import kotlin.reflect.KClass
@@ -38,8 +40,8 @@ data class FirExtensionPointName(val name: Name) {
// todo: KDOC
abstract class FirDeclarationPredicateRegistrar {
abstract fun register(vararg predicates: DeclarationPredicate)
abstract fun register(predicates: Collection<DeclarationPredicate>)
abstract fun register(vararg predicates: AbstractPredicate<*>)
abstract fun register(predicates: Collection<AbstractPredicate<*>>)
}
@RequiresOptIn
@@ -11,11 +11,13 @@ import org.jetbrains.kotlin.fir.FirSessionComponent
import org.jetbrains.kotlin.fir.NoMutableState
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.extensions.predicate.AbstractPredicate
import org.jetbrains.kotlin.fir.extensions.predicate.DeclarationPredicate
import org.jetbrains.kotlin.fir.extensions.predicate.LookupPredicate
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
abstract class FirPredicateBasedProvider : FirSessionComponent {
abstract fun getSymbolsByPredicate(predicate: DeclarationPredicate): List<FirBasedSymbol<*>>
abstract fun getSymbolsByPredicate(predicate: LookupPredicate): List<FirBasedSymbol<*>>
abstract fun getOwnersOfDeclaration(declaration: FirDeclaration): List<FirBasedSymbol<*>>?
/**
@@ -23,17 +25,17 @@ abstract class FirPredicateBasedProvider : FirSessionComponent {
* @see FirRegisteredPluginAnnotations.annotations
*/
abstract fun fileHasPluginAnnotations(file: FirFile): Boolean
abstract fun matches(predicate: DeclarationPredicate, declaration: FirDeclaration): Boolean
abstract fun matches(predicate: AbstractPredicate<*>, declaration: FirDeclaration): Boolean
fun matches(predicate: DeclarationPredicate, declaration: FirBasedSymbol<*>): Boolean {
fun matches(predicate: AbstractPredicate<*>, declaration: FirBasedSymbol<*>): Boolean {
return matches(predicate, declaration.fir)
}
fun matches(predicates: List<DeclarationPredicate>, declaration: FirDeclaration): Boolean {
fun matches(predicates: List<AbstractPredicate<*>>, declaration: FirDeclaration): Boolean {
return predicates.any { matches(it, declaration) }
}
fun matches(predicates: List<DeclarationPredicate>, declaration: FirBasedSymbol<*>): Boolean {
fun matches(predicates: List<AbstractPredicate<*>>, declaration: FirBasedSymbol<*>): Boolean {
return matches(predicates, declaration.fir)
}
@@ -41,14 +43,14 @@ abstract class FirPredicateBasedProvider : FirSessionComponent {
}
@NoMutableState
class FirEmptyPredicateBasedProvider(): FirPredicateBasedProvider() {
override fun getSymbolsByPredicate(predicate: DeclarationPredicate): List<FirBasedSymbol<*>> = emptyList()
object FirEmptyPredicateBasedProvider : FirPredicateBasedProvider() {
override fun getSymbolsByPredicate(predicate: LookupPredicate): List<FirBasedSymbol<*>> = emptyList()
override fun getOwnersOfDeclaration(declaration: FirDeclaration): List<FirBasedSymbol<*>>? = null
override fun fileHasPluginAnnotations(file: FirFile): Boolean = false
override fun matches(predicate: DeclarationPredicate, declaration: FirDeclaration): Boolean = false
override fun matches(predicate: AbstractPredicate<*>, declaration: FirDeclaration): Boolean = false
}
val FirSession.predicateBasedProvider: FirPredicateBasedProvider by FirSession.sessionComponentAccessor()
@@ -0,0 +1,97 @@
/*
* Copyright 2010-2022 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.extensions.predicate
import org.jetbrains.kotlin.fir.extensions.AnnotationFqn
sealed interface AbstractPredicate<P : AbstractPredicate<P>> {
val annotations: Set<AnnotationFqn>
val metaAnnotations: Set<AnnotationFqn>
fun <R, D> accept(visitor: PredicateVisitor<P, R, D>, data: D): R
sealed interface Or<P : AbstractPredicate<P>> : AbstractPredicate<P> {
val a: P
val b: P
override fun <R, D> accept(visitor: PredicateVisitor<P, R, D>, data: D): R {
return visitor.visitOr(this, data)
}
}
sealed interface And<P : AbstractPredicate<P>> : AbstractPredicate<P> {
val a: P
val b: P
override fun <R, D> accept(visitor: PredicateVisitor<P, R, D>, data: D): R {
return visitor.visitAnd(this, data)
}
}
// ------------------------------------ Annotated ------------------------------------
sealed interface Annotated<P : AbstractPredicate<P>> : AbstractPredicate<P> {
override fun <R, D> accept(visitor: PredicateVisitor<P, R, D>, data: D): R {
return visitor.visitAnnotated(this, data)
}
}
sealed interface AnnotatedWith<P : AbstractPredicate<P>> : Annotated<P> {
override fun <R, D> accept(visitor: PredicateVisitor<P, R, D>, data: D): R {
return visitor.visitAnnotatedWith(this, data)
}
}
sealed interface AncestorAnnotatedWith<P : AbstractPredicate<P>> : Annotated<P> {
override fun <R, D> accept(visitor: PredicateVisitor<P, R, D>, data: D): R {
return visitor.visitAncestorAnnotatedWith(this, data)
}
}
sealed interface ParentAnnotatedWith<P : AbstractPredicate<P>> : Annotated<P> {
override fun <R, D> accept(visitor: PredicateVisitor<P, R, D>, data: D): R {
return visitor.visitParentAnnotatedWith(this, data)
}
}
sealed interface HasAnnotatedWith<P : AbstractPredicate<P>> : Annotated<P> {
override fun <R, D> accept(visitor: PredicateVisitor<P, R, D>, data: D): R {
return visitor.visitHasAnnotatedWith(this, data)
}
}
// ------------------------------------ MetaAnnotated ------------------------------------
sealed interface MetaAnnotatedWith<P : AbstractPredicate<P>> : AbstractPredicate<P> {
override fun <R, D> accept(visitor: PredicateVisitor<P, R, D>, data: D): R {
return visitor.visitMetaAnnotatedWith(this, data)
}
}
// -------------------------------------------- DSL --------------------------------------------
abstract class BuilderContext<P : AbstractPredicate<P>> {
abstract infix fun P.or(other: P): P
abstract infix fun P.and(other: P): P
// ------------------- varargs -------------------
abstract fun annotated(vararg annotations: AnnotationFqn): P
abstract fun ancestorAnnotated(vararg annotations: AnnotationFqn): P
abstract fun parentAnnotated(vararg annotations: AnnotationFqn): P
abstract fun hasAnnotated(vararg annotations: AnnotationFqn): P
abstract fun annotatedOrUnder(vararg annotations: AnnotationFqn): P
// ------------------- collections -------------------
abstract fun annotated(annotations: Collection<AnnotationFqn>): P
abstract fun ancestorAnnotated(annotations: Collection<AnnotationFqn>): P
abstract fun parentAnnotated(annotations: Collection<AnnotationFqn>): P
abstract fun hasAnnotated(annotations: Collection<AnnotationFqn>): P
abstract fun annotatedOrUnder(annotations: Collection<AnnotationFqn>): P
}
}
@@ -10,226 +10,215 @@ import org.jetbrains.kotlin.fir.extensions.AnnotationFqn
// -------------------------------------------- Predicates --------------------------------------------
// todo: Missing KDOC
sealed class DeclarationPredicate {
abstract val annotations: Set<AnnotationFqn>
abstract val metaAnnotations: Set<AnnotationFqn>
sealed class DeclarationPredicate : AbstractPredicate<DeclarationPredicate> {
abstract override val annotations: Set<AnnotationFqn>
abstract override val metaAnnotations: Set<AnnotationFqn>
abstract fun <R, D> accept(visitor: DeclarationPredicateVisitor<R, D>, data: D): R
abstract override fun <R, D> accept(visitor: PredicateVisitor<DeclarationPredicate, R, D>, data: D): R
class Or(val a: DeclarationPredicate, val b: DeclarationPredicate) : DeclarationPredicate() {
class Or(
override val a: DeclarationPredicate,
override val b: DeclarationPredicate
) : DeclarationPredicate(), AbstractPredicate.Or<DeclarationPredicate> {
override val annotations: Set<AnnotationFqn> = a.annotations + b.annotations
override val metaAnnotations: Set<AnnotationFqn> = a.metaAnnotations + b.metaAnnotations
override fun <R, D> accept(visitor: DeclarationPredicateVisitor<R, D>, data: D): R {
override fun <R, D> accept(visitor: PredicateVisitor<DeclarationPredicate, R, D>, data: D): R {
return visitor.visitOr(this, data)
}
}
class And(val a: DeclarationPredicate, val b: DeclarationPredicate) : DeclarationPredicate() {
class And(
override val a: DeclarationPredicate,
override val b: DeclarationPredicate
) : DeclarationPredicate(), AbstractPredicate.And<DeclarationPredicate> {
override val annotations: Set<AnnotationFqn> = a.annotations + b.annotations
override val metaAnnotations: Set<AnnotationFqn> = a.metaAnnotations + b.metaAnnotations
override fun <R, D> accept(visitor: DeclarationPredicateVisitor<R, D>, data: D): R {
override fun <R, D> accept(visitor: PredicateVisitor<DeclarationPredicate, R, D>, data: D): R {
return visitor.visitAnd(this, data)
}
}
}
// ------------------------------------ Annotated ------------------------------------
// ------------------------------------ Annotated ------------------------------------
/**
* Base class for all predicates with specific annotations
* Declaration will be matched if at least one of [annotations] is found
*/
sealed class Annotated(final override val annotations: Set<AnnotationFqn>) : DeclarationPredicate() {
init {
require(annotations.isNotEmpty()) {
"Annotations should be not empty"
/**
* Base class for all predicates with specific annotations
* Declaration will be matched if at least one of [annotations] is found
*/
sealed class Annotated(final override val annotations: Set<AnnotationFqn>) : DeclarationPredicate(),
AbstractPredicate.Annotated<DeclarationPredicate> {
init {
require(annotations.isNotEmpty()) {
"Annotations should be not empty"
}
}
final override val metaAnnotations: Set<AnnotationFqn>
get() = emptySet()
override fun <R, D> accept(visitor: PredicateVisitor<DeclarationPredicate, R, D>, data: D): R {
return visitor.visitAnnotated(this, data)
}
}
final override val metaAnnotations: Set<AnnotationFqn>
get() = emptySet()
override fun <R, D> accept(visitor: DeclarationPredicateVisitor<R, D>, data: D): R {
return visitor.visitAnnotated(this, data)
}
}
/**
* Matches declarations, which are annotated with [annotations]
*
* @Ann
* fun foo() {}
*
* fun bar(@Ann param: Int) {}
*
* @Ann
* class A {
* fun baz() {}
*
* class Nested {
* fun foobar() {}
* }
* }
*
* Matched symbols: [fun foo, parameter `param` from fun bar, class A]
*/
class AnnotatedWith(annotations: Set<AnnotationFqn>) : Annotated(annotations) {
override fun <R, D> accept(visitor: DeclarationPredicateVisitor<R, D>, data: D): R {
return visitor.visitAnnotatedWith(this, data)
}
}
/**
* Matches declaration, if one of its containers annotated with [annotations]
*
* @Ann
* fun foo() {}
*
* fun bar(@Ann param: Int) {}
*
* @Ann
* class A {
* fun baz() {}
*
* class Nested {
* fun foobar() {}
* }
* }
*
* Matched symbols: [fun A.baz, class Nested, fun Nested.foobar]
*/
class AncestorAnnotatedWith(annotations: Set<AnnotationFqn>) : Annotated(annotations) {
override fun <R, D> accept(visitor: DeclarationPredicateVisitor<R, D>, data: D): R {
return visitor.visitAncestorAnnotatedWith(this, data)
}
}
/**
* Matches declaration, if its direct container annotated with [annotations]
*
* @Ann
* fun foo() {}
*
* fun bar(@Ann param: Int) {}
*
* @Ann
* class A {
* fun baz() {}
*
* class Nested {
* fun foobar() {}
* }
* }
*
* Matched symbols: [fun A.baz, class Nested]
*/
class ParentAnnotatedWith(annotations: Set<AnnotationFqn>) : Annotated(annotations) {
override fun <R, D> accept(visitor: DeclarationPredicateVisitor<R, D>, data: D): R {
return visitor.visitParentAnnotatedWith(this, data)
}
}
/**
* Matches declaration, if one of its direct child declarations annotated with [annotations]
*
* @Ann
* fun foo() {}
*
* fun bar(@Ann param: Int) {}
*
* class A {
* @Ann
* fun baz() {}
*
* class Nested {
* fun foobar() {}
* }
* }
*
* Matched symbols: [fun bar, class A]
*/
class HasAnnotatedWith(annotations: Set<AnnotationFqn>) : Annotated(annotations) {
override fun <R, D> accept(visitor: DeclarationPredicateVisitor<R, D>, data: D): R {
return visitor.visitHasAnnotatedWith(this, data)
}
}
// ------------------------------------ MetaAnnotated ------------------------------------
sealed class MetaAnnotated(final override val metaAnnotations: Set<AnnotationFqn>) : DeclarationPredicate() {
init {
require(metaAnnotations.isNotEmpty()) {
"Annotations should be not empty"
/**
* Matches declarations, which are annotated with [annotations]
*
* @Ann
* fun foo() {}
*
* fun bar(@Ann param: Int) {}
*
* @Ann
* class A {
* fun baz() {}
*
* class Nested {
* fun foobar() {}
* }
* }
*
* Matched symbols: [fun foo, parameter `param` from fun bar, class A]
*/
class AnnotatedWith(annotations: Set<AnnotationFqn>) : Annotated(annotations), AbstractPredicate.AnnotatedWith<DeclarationPredicate> {
override fun <R, D> accept(visitor: PredicateVisitor<DeclarationPredicate, R, D>, data: D): R {
return visitor.visitAnnotatedWith(this, data)
}
}
final override val annotations: Set<AnnotationFqn>
get() = emptySet()
/**
* Matches declaration, if one of its containers annotated with [annotations]
*
* @Ann
* fun foo() {}
*
* fun bar(@Ann param: Int) {}
*
* @Ann
* class A {
* fun baz() {}
*
* class Nested {
* fun foobar() {}
* }
* }
*
* Matched symbols: [fun A.baz, class Nested, fun Nested.foobar]
*/
class AncestorAnnotatedWith(annotations: Set<AnnotationFqn>) : Annotated(annotations),
AbstractPredicate.AncestorAnnotatedWith<DeclarationPredicate> {
override fun <R, D> accept(visitor: PredicateVisitor<DeclarationPredicate, R, D>, data: D): R {
return visitor.visitAncestorAnnotatedWith(this, data)
}
}
override fun <R, D> accept(visitor: DeclarationPredicateVisitor<R, D>, data: D): R {
return visitor.visitMetaAnnotated(this, data)
/**
* Matches declaration, if its direct container annotated with [annotations]
*
* @Ann
* fun foo() {}
*
* fun bar(@Ann param: Int) {}
*
* @Ann
* class A {
* fun baz() {}
*
* class Nested {
* fun foobar() {}
* }
* }
*
* Matched symbols: [fun A.baz, class Nested]
*/
class ParentAnnotatedWith(annotations: Set<AnnotationFqn>) : Annotated(annotations),
AbstractPredicate.ParentAnnotatedWith<DeclarationPredicate> {
override fun <R, D> accept(visitor: PredicateVisitor<DeclarationPredicate, R, D>, data: D): R {
return visitor.visitParentAnnotatedWith(this, data)
}
}
/**
* Matches declaration, if one of its direct child declarations annotated with [annotations]
*
* @Ann
* fun foo() {}
*
* fun bar(@Ann param: Int) {}
*
* class A {
* @Ann
* fun baz() {}
*
* class Nested {
* fun foobar() {}
* }
* }
*
* Matched symbols: [fun bar, class A]
*/
class HasAnnotatedWith(annotations: Set<AnnotationFqn>) : Annotated(annotations),
AbstractPredicate.HasAnnotatedWith<DeclarationPredicate> {
override fun <R, D> accept(visitor: PredicateVisitor<DeclarationPredicate, R, D>, data: D): R {
return visitor.visitHasAnnotatedWith(this, data)
}
}
// ------------------------------------ MetaAnnotated ------------------------------------
class MetaAnnotatedWith(
override val metaAnnotations: Set<AnnotationFqn>
) : DeclarationPredicate(), AbstractPredicate.MetaAnnotatedWith<DeclarationPredicate> {
init {
require(metaAnnotations.isNotEmpty()) {
"Annotations should be not empty"
}
}
override val annotations: Set<AnnotationFqn>
get() = emptySet()
override fun <R, D> accept(visitor: PredicateVisitor<DeclarationPredicate, R, D>, data: D): R {
return visitor.visitMetaAnnotatedWith(this, data)
}
}
// -------------------------------------------- DSL --------------------------------------------
object BuilderContext : AbstractPredicate.BuilderContext<DeclarationPredicate>() {
override infix fun DeclarationPredicate.or(other: DeclarationPredicate): DeclarationPredicate = Or(this, other)
override infix fun DeclarationPredicate.and(other: DeclarationPredicate): DeclarationPredicate = And(this, other)
// ------------------- varargs -------------------
override fun annotated(vararg annotations: AnnotationFqn): DeclarationPredicate = annotated(annotations.toList())
override fun ancestorAnnotated(vararg annotations: AnnotationFqn): DeclarationPredicate = ancestorAnnotated(annotations.toList())
override fun parentAnnotated(vararg annotations: AnnotationFqn): DeclarationPredicate = parentAnnotated(annotations.toList())
override fun hasAnnotated(vararg annotations: AnnotationFqn): DeclarationPredicate = hasAnnotated(annotations.toList())
override fun annotatedOrUnder(vararg annotations: AnnotationFqn): DeclarationPredicate =
annotated(*annotations) or ancestorAnnotated(*annotations)
fun metaAnnotated(vararg metaAnnotations: AnnotationFqn): DeclarationPredicate = MetaAnnotatedWith(metaAnnotations.toSet())
// ------------------- collections -------------------
override fun annotated(annotations: Collection<AnnotationFqn>): DeclarationPredicate = AnnotatedWith(annotations.toSet())
override fun ancestorAnnotated(annotations: Collection<AnnotationFqn>): DeclarationPredicate =
AncestorAnnotatedWith(annotations.toSet())
override fun parentAnnotated(annotations: Collection<AnnotationFqn>): DeclarationPredicate =
ParentAnnotatedWith(annotations.toSet())
override fun hasAnnotated(annotations: Collection<AnnotationFqn>): DeclarationPredicate = HasAnnotatedWith(annotations.toSet())
override fun annotatedOrUnder(annotations: Collection<AnnotationFqn>): DeclarationPredicate =
annotated(annotations) or ancestorAnnotated(annotations)
fun metaAnnotated(metaAnnotations: Collection<AnnotationFqn>): DeclarationPredicate = MetaAnnotatedWith(metaAnnotations.toSet())
}
companion object {
inline fun create(init: BuilderContext.() -> DeclarationPredicate): DeclarationPredicate = BuilderContext.init()
}
}
class MetaAnnotatedWith(metaAnnotations: Set<AnnotationFqn>) : MetaAnnotated(metaAnnotations) {
override fun <R, D> accept(visitor: DeclarationPredicateVisitor<R, D>, data: D): R {
return visitor.visitMetaAnnotatedWith(this, data)
}
}
class AncestorMetaAnnotatedWith(metaAnnotations: Set<AnnotationFqn>) : MetaAnnotated(metaAnnotations) {
override fun <R, D> accept(visitor: DeclarationPredicateVisitor<R, D>, data: D): R {
return visitor.visitAncestorMetaAnnotatedWith(this, data)
}
}
class ParentMetaAnnotatedWith(metaAnnotations: Set<AnnotationFqn>) : MetaAnnotated(metaAnnotations) {
override fun <R, D> accept(visitor: DeclarationPredicateVisitor<R, D>, data: D): R {
return visitor.visitParentMetaAnnotatedWith(this, data)
}
}
class HasMetaAnnotatedWith(metaAnnotations: Set<AnnotationFqn>) : MetaAnnotated(metaAnnotations) {
override fun <R, D> accept(visitor: DeclarationPredicateVisitor<R, D>, data: D): R {
return visitor.visitHasMetaAnnotatedWith(this, data)
}
}
// -------------------------------------------- DSL --------------------------------------------
infix fun DeclarationPredicate.or(other: DeclarationPredicate): DeclarationPredicate = DeclarationPredicate.Or(this, other)
infix fun DeclarationPredicate.and(other: DeclarationPredicate): DeclarationPredicate = DeclarationPredicate.And(this, other)
// ------------------- varargs -------------------
fun annotated(vararg annotations: AnnotationFqn): DeclarationPredicate = AnnotatedWith(annotations.toSet())
fun ancestorAnnotated(vararg annotations: AnnotationFqn): DeclarationPredicate = AncestorAnnotatedWith(annotations.toSet())
fun parentAnnotated(vararg annotations: AnnotationFqn): DeclarationPredicate = ParentAnnotatedWith(annotations.toSet())
fun hasAnnotated(vararg annotations: AnnotationFqn): DeclarationPredicate = HasAnnotatedWith(annotations.toSet())
fun metaAnnotated(vararg metaAnnotations: AnnotationFqn): DeclarationPredicate = MetaAnnotatedWith(metaAnnotations.toSet())
fun metaAncestorAnnotated(vararg metaAnnotations: AnnotationFqn): DeclarationPredicate = AncestorMetaAnnotatedWith(metaAnnotations.toSet())
fun parentMetaAnnotated(vararg metaAnnotations: AnnotationFqn): DeclarationPredicate = ParentMetaAnnotatedWith(metaAnnotations.toSet())
fun hasMetaAnnotated(vararg metaAnnotations: AnnotationFqn): DeclarationPredicate = HasMetaAnnotatedWith(metaAnnotations.toSet())
fun annotatedOrUnder(vararg annotations: AnnotationFqn): DeclarationPredicate = annotated(*annotations) or ancestorAnnotated(*annotations)
fun metaAnnotatedOrUnder(vararg metaAnnotations: AnnotationFqn): DeclarationPredicate =
metaAnnotated(*metaAnnotations) or metaAncestorAnnotated(*metaAnnotations)
// ------------------- collections -------------------
fun annotated(annotations: Collection<AnnotationFqn>): DeclarationPredicate = AnnotatedWith(annotations.toSet())
fun ancestorAnnotated(annotations: Collection<AnnotationFqn>): DeclarationPredicate = AncestorAnnotatedWith(annotations.toSet())
fun parentAnnotated(annotations: Collection<AnnotationFqn>): DeclarationPredicate = ParentAnnotatedWith(annotations.toSet())
fun hasAnnotated(annotations: Collection<AnnotationFqn>): DeclarationPredicate = HasAnnotatedWith(annotations.toSet())
fun metaAnnotated(metaAnnotations: Collection<AnnotationFqn>): DeclarationPredicate = MetaAnnotatedWith(metaAnnotations.toSet())
fun metaAncestorAnnotated(metaAnnotations: Collection<AnnotationFqn>): DeclarationPredicate = AncestorMetaAnnotatedWith(metaAnnotations.toSet())
fun parentMetaAnnotated(metaAnnotations: Collection<AnnotationFqn>): DeclarationPredicate = ParentMetaAnnotatedWith(metaAnnotations.toSet())
fun hasMetaAnnotated(metaAnnotations: Collection<AnnotationFqn>): DeclarationPredicate = HasMetaAnnotatedWith(metaAnnotations.toSet())
fun annotatedOrUnder(annotations: Collection<AnnotationFqn>): DeclarationPredicate = annotated(annotations) or ancestorAnnotated(annotations)
fun metaAnnotatedOrUnder(metaAnnotations: Collection<AnnotationFqn>): DeclarationPredicate =
metaAnnotated(metaAnnotations) or metaAncestorAnnotated(metaAnnotations)
@@ -1,58 +0,0 @@
/*
* 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.extensions.predicate
abstract class DeclarationPredicateVisitor<R, D> {
abstract fun visitPredicate(predicate: DeclarationPredicate, data: D): R
open fun visitAnd(predicate: DeclarationPredicate.And, data: D): R {
return visitPredicate(predicate, data)
}
open fun visitOr(predicate: DeclarationPredicate.Or, data: D): R {
return visitPredicate(predicate, data)
}
open fun visitAnnotated(predicate: Annotated, data: D): R {
return visitPredicate(predicate, data)
}
open fun visitAnnotatedWith(predicate: AnnotatedWith, data: D): R {
return visitAnnotated(predicate, data)
}
open fun visitAncestorAnnotatedWith(predicate: AncestorAnnotatedWith, data: D): R {
return visitAnnotated(predicate, data)
}
open fun visitParentAnnotatedWith(predicate: ParentAnnotatedWith, data: D): R {
return visitAnnotated(predicate, data)
}
open fun visitHasAnnotatedWith(predicate: HasAnnotatedWith, data: D): R {
return visitAnnotated(predicate, data)
}
open fun visitMetaAnnotated(predicate: MetaAnnotated, data: D): R {
return visitPredicate(predicate, data)
}
open fun visitMetaAnnotatedWith(predicate: MetaAnnotatedWith, data: D): R {
return visitMetaAnnotated(predicate, data)
}
open fun visitAncestorMetaAnnotatedWith(predicate: AncestorMetaAnnotatedWith, data: D): R {
return visitMetaAnnotated(predicate, data)
}
open fun visitParentMetaAnnotatedWith(predicate: ParentMetaAnnotatedWith, data: D): R {
return visitMetaAnnotated(predicate, data)
}
open fun visitHasMetaAnnotatedWith(predicate: HasMetaAnnotatedWith, data: D): R {
return visitMetaAnnotated(predicate, data)
}
}
@@ -0,0 +1,183 @@
/*
* Copyright 2010-2022 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.extensions.predicate
import org.jetbrains.kotlin.fir.extensions.AnnotationFqn
sealed class LookupPredicate : AbstractPredicate<LookupPredicate> {
abstract override val annotations: Set<AnnotationFqn>
final override val metaAnnotations: Set<AnnotationFqn>
get() = error("Should not be called")
abstract override fun <R, D> accept(visitor: PredicateVisitor<LookupPredicate, R, D>, data: D): R
class Or(
override val a: LookupPredicate,
override val b: LookupPredicate
) : LookupPredicate(), AbstractPredicate.Or<LookupPredicate> {
override val annotations: Set<AnnotationFqn> = a.annotations + b.annotations
override fun <R, D> accept(visitor: PredicateVisitor<LookupPredicate, R, D>, data: D): R {
return visitor.visitOr(this, data)
}
}
class And(
override val a: LookupPredicate,
override val b: LookupPredicate
) : LookupPredicate(), AbstractPredicate.And<LookupPredicate> {
override val annotations: Set<AnnotationFqn> = a.annotations + b.annotations
override fun <R, D> accept(visitor: PredicateVisitor<LookupPredicate, R, D>, data: D): R {
return visitor.visitAnd(this, data)
}
}
/**
* Base class for all predicates with specific annotations
* Declaration will be matched if at least one of [annotations] is found
*/
sealed class Annotated(final override val annotations: Set<AnnotationFqn>) : LookupPredicate(), AbstractPredicate.Annotated<LookupPredicate> {
init {
require(annotations.isNotEmpty()) {
"Annotations should be not empty"
}
}
override fun <R, D> accept(visitor: PredicateVisitor<LookupPredicate, R, D>, data: D): R {
return visitor.visitAnnotated(this, data)
}
}
/**
* Matches declarations, which are annotated with [annotations]
*
* @Ann
* fun foo() {}
*
* fun bar(@Ann param: Int) {}
*
* @Ann
* class A {
* fun baz() {}
*
* class Nested {
* fun foobar() {}
* }
* }
*
* Matched symbols: [fun foo, parameter `param` from fun bar, class A]
*/
class AnnotatedWith(annotations: Set<AnnotationFqn>) : Annotated(annotations), AbstractPredicate.AnnotatedWith<LookupPredicate> {
override fun <R, D> accept(visitor: PredicateVisitor<LookupPredicate, R, D>, data: D): R {
return visitor.visitAnnotatedWith(this, data)
}
}
/**
* Matches declaration, if one of its containers annotated with [annotations]
*
* @Ann
* fun foo() {}
*
* fun bar(@Ann param: Int) {}
*
* @Ann
* class A {
* fun baz() {}
*
* class Nested {
* fun foobar() {}
* }
* }
*
* Matched symbols: [fun A.baz, class Nested, fun Nested.foobar]
*/
class AncestorAnnotatedWith(annotations: Set<AnnotationFqn>) : Annotated(annotations), AbstractPredicate.AncestorAnnotatedWith<LookupPredicate> {
override fun <R, D> accept(visitor: PredicateVisitor<LookupPredicate, R, D>, data: D): R {
return visitor.visitAncestorAnnotatedWith(this, data)
}
}
/**
* Matches declaration, if its direct container annotated with [annotations]
*
* @Ann
* fun foo() {}
*
* fun bar(@Ann param: Int) {}
*
* @Ann
* class A {
* fun baz() {}
*
* class Nested {
* fun foobar() {}
* }
* }
*
* Matched symbols: [fun A.baz, class Nested]
*/
class ParentAnnotatedWith(annotations: Set<AnnotationFqn>) : Annotated(annotations), AbstractPredicate.ParentAnnotatedWith<LookupPredicate> {
override fun <R, D> accept(visitor: PredicateVisitor<LookupPredicate, R, D>, data: D): R {
return visitor.visitParentAnnotatedWith(this, data)
}
}
/**
* Matches declaration, if one of its direct child declarations annotated with [annotations]
*
* @Ann
* fun foo() {}
*
* fun bar(@Ann param: Int) {}
*
* class A {
* @Ann
* fun baz() {}
*
* class Nested {
* fun foobar() {}
* }
* }
*
* Matched symbols: [fun bar, class A]
*/
class HasAnnotatedWith(annotations: Set<AnnotationFqn>) : Annotated(annotations), AbstractPredicate.HasAnnotatedWith<LookupPredicate> {
override fun <R, D> accept(visitor: PredicateVisitor<LookupPredicate, R, D>, data: D): R {
return visitor.visitHasAnnotatedWith(this, data)
}
}
// -------------------------------------------- DSL --------------------------------------------
object BuilderContext : AbstractPredicate.BuilderContext<LookupPredicate>() {
override infix fun LookupPredicate.or(other: LookupPredicate): LookupPredicate = Or(this, other)
override infix fun LookupPredicate.and(other: LookupPredicate): LookupPredicate = And(this, other)
// ------------------- varargs -------------------
override fun annotated(vararg annotations: AnnotationFqn): LookupPredicate = annotated(annotations.toList())
override fun ancestorAnnotated(vararg annotations: AnnotationFqn): LookupPredicate = ancestorAnnotated(annotations.toList())
override fun parentAnnotated(vararg annotations: AnnotationFqn): LookupPredicate = parentAnnotated(annotations.toList())
override fun hasAnnotated(vararg annotations: AnnotationFqn): LookupPredicate = hasAnnotated(annotations.toList())
override fun annotatedOrUnder(vararg annotations: AnnotationFqn): LookupPredicate =
annotated(*annotations) or ancestorAnnotated(*annotations)
// ------------------- collections -------------------
override fun annotated(annotations: Collection<AnnotationFqn>): LookupPredicate = AnnotatedWith(annotations.toSet())
override fun ancestorAnnotated(annotations: Collection<AnnotationFqn>): LookupPredicate = AncestorAnnotatedWith(annotations.toSet())
override fun parentAnnotated(annotations: Collection<AnnotationFqn>): LookupPredicate = ParentAnnotatedWith(annotations.toSet())
override fun hasAnnotated(annotations: Collection<AnnotationFqn>): LookupPredicate = HasAnnotatedWith(annotations.toSet())
override fun annotatedOrUnder(annotations: Collection<AnnotationFqn>): LookupPredicate =
annotated(annotations) or ancestorAnnotated(annotations)
}
companion object {
inline fun create(init: BuilderContext.() -> LookupPredicate): LookupPredicate = BuilderContext.init()
}
}
@@ -0,0 +1,45 @@
/*
* 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.extensions.predicate
abstract class PredicateVisitor<P : AbstractPredicate<P>, R, D> {
abstract fun visitPredicate(predicate: AbstractPredicate<P>, data: D): R
open fun visitAnd(predicate: AbstractPredicate.And<P>, data: D): R {
return visitPredicate(predicate, data)
}
open fun visitOr(predicate: AbstractPredicate.Or<P>, data: D): R {
return visitPredicate(predicate, data)
}
open fun visitAnnotated(predicate: AbstractPredicate.Annotated<P>, data: D): R {
return visitPredicate(predicate, data)
}
open fun visitAnnotatedWith(predicate: AbstractPredicate.AnnotatedWith<P>, data: D): R {
return visitAnnotated(predicate, data)
}
open fun visitAncestorAnnotatedWith(predicate: AbstractPredicate.AncestorAnnotatedWith<P>, data: D): R {
return visitAnnotated(predicate, data)
}
open fun visitParentAnnotatedWith(predicate: AbstractPredicate.ParentAnnotatedWith<P>, data: D): R {
return visitAnnotated(predicate, data)
}
open fun visitHasAnnotatedWith(predicate: AbstractPredicate.HasAnnotatedWith<P>, data: D): R {
return visitAnnotated(predicate, data)
}
open fun visitMetaAnnotatedWith(predicate: AbstractPredicate.MetaAnnotatedWith<P>, data: D): R {
return visitPredicate(predicate, data)
}
}
typealias DeclarationPredicateVisitor<R, D> = PredicateVisitor<DeclarationPredicate, R, D>
typealias LookupPredicateVisitor<R, D> = PredicateVisitor<LookupPredicate, R, D>