[FIR] Introduce FirPredicateBasedProvider

This commit is contained in:
Dmitriy Novozhilov
2020-05-20 13:08:13 +03:00
parent 0b00015424
commit 5c12b3df95
6 changed files with 236 additions and 20 deletions
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.fir.FirSessionBase
import org.jetbrains.kotlin.fir.FirSessionProvider import org.jetbrains.kotlin.fir.FirSessionProvider
import org.jetbrains.kotlin.fir.analysis.CheckersComponent import org.jetbrains.kotlin.fir.analysis.CheckersComponent
import org.jetbrains.kotlin.fir.extensions.FirOldExtensionsService import org.jetbrains.kotlin.fir.extensions.FirOldExtensionsService
import org.jetbrains.kotlin.fir.extensions.FirPredicateBasedProvider
import org.jetbrains.kotlin.fir.java.deserialization.KotlinDeserializedJvmSymbolsProvider import org.jetbrains.kotlin.fir.java.deserialization.KotlinDeserializedJvmSymbolsProvider
import org.jetbrains.kotlin.fir.resolve.FirProvider import org.jetbrains.kotlin.fir.resolve.FirProvider
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
@@ -126,6 +127,11 @@ class FirLibrarySession private constructor(
FirOldExtensionsService(this) FirOldExtensionsService(this)
) )
registerComponent(
FirPredicateBasedProvider::class,
FirPredicateBasedProvider.create(this)
)
sessionProvider.sessionCache[moduleInfo] = this sessionProvider.sessionCache[moduleInfo] = this
} }
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir
import org.jetbrains.kotlin.analyzer.ModuleInfo import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.fir.extensions.FirOldExtensionsService import org.jetbrains.kotlin.fir.extensions.FirOldExtensionsService
import org.jetbrains.kotlin.fir.extensions.FirPredicateBasedProvider
import org.jetbrains.kotlin.fir.resolve.* import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.impl.* import org.jetbrains.kotlin.fir.resolve.impl.*
import org.jetbrains.kotlin.fir.scopes.impl.FirDeclaredMemberScopeProvider import org.jetbrains.kotlin.fir.scopes.impl.FirDeclaredMemberScopeProvider
@@ -18,6 +19,7 @@ abstract class FirModuleBasedSession(override val moduleInfo: ModuleInfo, sessio
registerComponent(FirTypeResolver::class, FirTypeResolverImpl(this)) registerComponent(FirTypeResolver::class, FirTypeResolverImpl(this))
registerComponent(FirDeclaredMemberScopeProvider::class, FirDeclaredMemberScopeProvider()) registerComponent(FirDeclaredMemberScopeProvider::class, FirDeclaredMemberScopeProvider())
registerComponent(FirOldExtensionsService::class, FirOldExtensionsService(this)) registerComponent(FirOldExtensionsService::class, FirOldExtensionsService(this))
registerComponent(FirPredicateBasedProvider::class, FirPredicateBasedProvider.create(this))
} }
} }
@@ -0,0 +1,75 @@
/*
* 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.extensions
import com.google.common.collect.ArrayListMultimap
import com.google.common.collect.Multimap
import kotlinx.collections.immutable.PersistentList
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.FirSessionComponent
import org.jetbrains.kotlin.fir.declarations.FirAnnotatedDeclaration
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.extensions.predicate.DeclarationPredicate
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
abstract class FirPredicateBasedProvider : FirSessionComponent {
companion object {
fun create(session: FirSession): FirPredicateBasedProvider {
return FirPredicateBasedProviderImpl(session)
}
}
abstract fun getSymbolsByPredicate(predicate: DeclarationPredicate): List<FirAnnotatedDeclaration>
abstract fun registerAnnotatedDeclaration(declaration: FirAnnotatedDeclaration, owners: PersistentList<FirAnnotatedDeclaration>)
}
private class FirPredicateBasedProviderImpl(private val session: FirSession) : FirPredicateBasedProvider() {
private val registeredPluginAnnotations = session.registeredPluginAnnotations
private val cache = Cache()
override fun getSymbolsByPredicate(predicate: DeclarationPredicate): List<FirAnnotatedDeclaration> {
val annotations = registeredPluginAnnotations.getAnnotationsForPredicate(predicate)
if (annotations.isEmpty()) return emptyList()
return annotations.flatMap { cache.declarationByAnnotation[it] + cache.declarationsUnderAnnotated[it] }.filter {
predicate.match(it, cache.ownersForDeclaration.getValue(it))
}
}
override fun registerAnnotatedDeclaration(declaration: FirAnnotatedDeclaration, owners: PersistentList<FirAnnotatedDeclaration>) {
cache.ownersForDeclaration[declaration] = owners
registerOwnersDeclarations(declaration, owners)
if (declaration.annotations.isEmpty()) return
val matchingAnnotations = declaration.annotations.mapNotNull { it.fqName(session) }
.filter { it in registeredPluginAnnotations.annotations }
if (matchingAnnotations.isEmpty()) return
matchingAnnotations.forEach { cache.declarationByAnnotation.put(it, declaration) }
cache.annotationsOfDeclaration.putAll(declaration, matchingAnnotations)
}
private fun registerOwnersDeclarations(declaration: FirAnnotatedDeclaration, owners: PersistentList<FirAnnotatedDeclaration>) {
val lastOwner = owners.lastOrNull() ?: return
val annotationsFromLastOwner = cache.annotationsOfDeclaration[lastOwner]
val annotationsFromPreviousOwners = cache.parentAnnotationsOfDeclaration[lastOwner]
val allParentDeclarations = annotationsFromLastOwner + annotationsFromPreviousOwners
allParentDeclarations.forEach { cache.declarationsUnderAnnotated.put(it, declaration) }
cache.parentAnnotationsOfDeclaration.putAll(declaration, allParentDeclarations)
}
private class Cache {
val declarationByAnnotation: Multimap<AnnotationFqn, FirAnnotatedDeclaration> = ArrayListMultimap.create()
val annotationsOfDeclaration: Multimap<FirAnnotatedDeclaration, AnnotationFqn> = ArrayListMultimap.create()
val declarationsUnderAnnotated: Multimap<AnnotationFqn, FirAnnotatedDeclaration> = ArrayListMultimap.create()
val parentAnnotationsOfDeclaration: Multimap<FirAnnotatedDeclaration, AnnotationFqn> = ArrayListMultimap.create()
val ownersForDeclaration: MutableMap<FirAnnotatedDeclaration, PersistentList<FirAnnotatedDeclaration>> = mutableMapOf()
}
}
val FirSession.predicateBasedProvider: FirPredicateBasedProvider by FirSession.sessionComponentAccessor()
@@ -0,0 +1,75 @@
/*
* 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.extensions
import com.google.common.collect.LinkedHashMultimap
import com.google.common.collect.Multimap
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.FirSessionComponent
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.extensions.predicate.DeclarationPredicate
abstract class FirRegisteredPluginAnnotations : FirSessionComponent {
companion object {
fun create(): FirRegisteredPluginAnnotations {
return FirRegisteredPluginAnnotationsImpl()
}
}
abstract val annotations: Set<AnnotationFqn>
abstract val metaAnnotations: Set<AnnotationFqn>
abstract fun getAnnotationsWithMetaAnnotation(metaAnnotation: AnnotationFqn): Collection<AnnotationFqn>
abstract fun registerAnnotations(annotations: Collection<AnnotationFqn>)
abstract fun registerMetaAnnotations(metaAnnotations: Collection<AnnotationFqn>)
abstract fun registerUserDefinedAnnotation(metaAnnotation: AnnotationFqn, annotationClasses: Collection<FirRegularClass>)
abstract fun getAnnotationsForPredicate(predicate: DeclarationPredicate): Set<AnnotationFqn>
}
private class FirRegisteredPluginAnnotationsImpl : FirRegisteredPluginAnnotations() {
override val annotations: MutableSet<AnnotationFqn> = mutableSetOf()
override val metaAnnotations: MutableSet<AnnotationFqn> = mutableSetOf()
// MetaAnnotation -> Annotations
private val userDefinedAnnotations: Multimap<AnnotationFqn, AnnotationFqn> = LinkedHashMultimap.create()
private val annotationsForPredicateCache: MutableMap<DeclarationPredicate, Set<AnnotationFqn>> = mutableMapOf()
override fun getAnnotationsWithMetaAnnotation(metaAnnotation: AnnotationFqn): Collection<AnnotationFqn> {
return userDefinedAnnotations[metaAnnotation]
}
override fun registerAnnotations(annotations: Collection<AnnotationFqn>) {
this.annotations += annotations
}
override fun registerMetaAnnotations(metaAnnotations: Collection<AnnotationFqn>) {
this.metaAnnotations += metaAnnotations
}
override fun registerUserDefinedAnnotation(metaAnnotation: AnnotationFqn, annotationClasses: Collection<FirRegularClass>) {
require(annotationClasses.all { it.classKind == ClassKind.ANNOTATION_CLASS })
val annotations = annotationClasses.map { it.symbol.classId.asSingleFqName() }
registerAnnotations(annotations)
userDefinedAnnotations.putAll(metaAnnotation, annotations)
}
override fun getAnnotationsForPredicate(predicate: DeclarationPredicate): Set<AnnotationFqn> {
return annotationsForPredicateCache.computeIfAbsent(predicate, ::collectAnnotations)
}
private fun collectAnnotations(predicate: DeclarationPredicate): Set<AnnotationFqn> {
if (predicate.metaAnnotations.isEmpty()) return predicate.annotations
val result = predicate.metaAnnotations.flatMapTo(mutableSetOf()) { getAnnotationsWithMetaAnnotation(it) }
if (result.isEmpty()) return predicate.annotations
result += predicate.annotations
return result
}
}
val FirSession.registeredPluginAnnotations: FirRegisteredPluginAnnotations by FirSession.sessionComponentAccessor()
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.fir.resolve.transformers.plugin package org.jetbrains.kotlin.fir.resolve.transformers.plugin
import org.jetbrains.kotlin.fir.FirAnnotationContainer
import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
@@ -19,7 +20,7 @@ import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult
import org.jetbrains.kotlin.fir.visitors.FirDefaultTransformer import org.jetbrains.kotlin.fir.visitors.FirDefaultTransformer
import org.jetbrains.kotlin.fir.visitors.compose import org.jetbrains.kotlin.fir.visitors.compose
internal abstract class FirAbstractAnnotationResolveTransformer<D>( internal abstract class FirAbstractAnnotationResolveTransformer<D, S>(
protected val session: FirSession, protected val session: FirSession,
protected val scopeSession: ScopeSession protected val scopeSession: ScopeSession
) : FirDefaultTransformer<D>() { ) : FirDefaultTransformer<D>() {
@@ -30,57 +31,92 @@ internal abstract class FirAbstractAnnotationResolveTransformer<D>(
override fun transformFile(file: FirFile, data: D): CompositeTransformResult<FirDeclaration> { override fun transformFile(file: FirFile, data: D): CompositeTransformResult<FirDeclaration> {
return withScopeCleanup(towerScope.scopes) { return withScopeCleanup(towerScope.scopes) {
towerScope.addScopes(createImportingScopes(file, session, scopeSession)) towerScope.addScopes(createImportingScopes(file, session, scopeSession))
val state = beforeChildren(file)
file.transformDeclarations(this, data) file.transformDeclarations(this, data)
file.transformAnnotations(this, data).compose() afterChildren(state)
transformAnnotatedDeclaration(file, data)
} }
} }
override fun transformProperty(property: FirProperty, data: D): CompositeTransformResult<FirDeclaration> { override fun transformProperty(property: FirProperty, data: D): CompositeTransformResult<FirDeclaration> {
return property.transformAnnotations(this, data).compose() return transformAnnotatedDeclaration(property, data)
} }
override fun transformRegularClass( override fun transformRegularClass(
regularClass: FirRegularClass, regularClass: FirRegularClass,
data: D data: D
): CompositeTransformResult<FirStatement> { ): CompositeTransformResult<FirStatement> {
regularClass.transformDeclarations(this, data) @Suppress("UNCHECKED_CAST")
regularClass.transformCompanionObject(this, data) return transformAnnotatedDeclaration(regularClass, data).also {
regularClass.transformSuperTypeRefs(this, data) val state = beforeChildren(regularClass)
return regularClass.transformAnnotations(this, data).compose() regularClass.transformDeclarations(this, data)
regularClass.transformCompanionObject(this, data)
regularClass.transformSuperTypeRefs(this, data)
afterChildren(state)
} as CompositeTransformResult<FirStatement>
} }
override fun transformSimpleFunction( override fun transformSimpleFunction(
simpleFunction: FirSimpleFunction, simpleFunction: FirSimpleFunction,
data: D data: D
): CompositeTransformResult<FirDeclaration> { ): CompositeTransformResult<FirDeclaration> {
simpleFunction.transformValueParameters(this, data) return transformAnnotatedDeclaration(simpleFunction, data).also {
return simpleFunction.transformAnnotations(this, data).compose() val state = beforeChildren(simpleFunction)
simpleFunction.transformValueParameters(this, data)
afterChildren(state)
}
} }
override fun transformConstructor( override fun transformConstructor(
constructor: FirConstructor, constructor: FirConstructor,
data: D data: D
): CompositeTransformResult<FirDeclaration> { ): CompositeTransformResult<FirDeclaration> {
constructor.transformValueParameters(this, data) return transformAnnotatedDeclaration(constructor, data).also {
return constructor.transformAnnotations(this, data).compose() val state = beforeChildren(constructor)
constructor.transformValueParameters(this, data)
afterChildren(state)
}
} }
override fun transformValueParameter( override fun transformValueParameter(
valueParameter: FirValueParameter, valueParameter: FirValueParameter,
data: D data: D
): CompositeTransformResult<FirStatement> { ): CompositeTransformResult<FirStatement> {
return valueParameter.transformAnnotations(this, data).compose() @Suppress("UNCHECKED_CAST")
return transformAnnotatedDeclaration(valueParameter, data) as CompositeTransformResult<FirStatement>
} }
override fun transformTypeAlias(typeAlias: FirTypeAlias, data: D): CompositeTransformResult<FirDeclaration> { override fun transformTypeAlias(typeAlias: FirTypeAlias, data: D): CompositeTransformResult<FirDeclaration> {
return typeAlias.transformAnnotations(this, data).compose() return transformAnnotatedDeclaration(typeAlias, data)
} }
override fun transformTypeRef(typeRef: FirTypeRef, data: D): CompositeTransformResult<FirTypeRef> { override fun transformTypeRef(typeRef: FirTypeRef, data: D): CompositeTransformResult<FirTypeRef> {
return typeRef.transformAnnotations(this, data).compose() @Suppress("UNCHECKED_CAST")
return transformAnnotationContainer(typeRef, data) as CompositeTransformResult<FirTypeRef>
}
override fun transformAnnotatedDeclaration(
annotatedDeclaration: FirAnnotatedDeclaration,
data: D
): CompositeTransformResult<FirDeclaration> {
@Suppress("UNCHECKED_CAST")
return transformAnnotationContainer(annotatedDeclaration, data) as CompositeTransformResult<FirDeclaration>
}
override fun transformAnnotationContainer(
annotationContainer: FirAnnotationContainer,
data: D
): CompositeTransformResult<FirAnnotationContainer> {
return annotationContainer.transformAnnotations(this, data).compose()
} }
override fun <E : FirElement> transformElement(element: E, data: D): CompositeTransformResult<E> { override fun <E : FirElement> transformElement(element: E, data: D): CompositeTransformResult<E> {
return element.compose() return element.compose()
} }
protected open fun beforeChildren(declaration: FirAnnotatedDeclaration): S? {
return null
}
protected open fun afterChildren(state: S?) {}
} }
@@ -7,16 +7,15 @@ package org.jetbrains.kotlin.fir.resolve.transformers.plugin
import com.google.common.collect.LinkedHashMultimap import com.google.common.collect.LinkedHashMultimap
import com.google.common.collect.Multimap import com.google.common.collect.Multimap
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.persistentListOf
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.FirStatement import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.extensions.AnnotationFqn import org.jetbrains.kotlin.fir.extensions.*
import org.jetbrains.kotlin.fir.extensions.extensionsService
import org.jetbrains.kotlin.fir.extensions.fqName
import org.jetbrains.kotlin.fir.extensions.hasExtensions
import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.FirAbstractPhaseTransformer import org.jetbrains.kotlin.fir.resolve.transformers.FirAbstractPhaseTransformer
import org.jetbrains.kotlin.fir.resolve.transformers.FirImportResolveTransformer import org.jetbrains.kotlin.fir.resolve.transformers.FirImportResolveTransformer
@@ -42,11 +41,13 @@ class FirPluginAnnotationsResolveTransformer(
override fun transformFile(file: FirFile, data: Nothing?): CompositeTransformResult<FirFile> { override fun transformFile(file: FirFile, data: Nothing?): CompositeTransformResult<FirFile> {
checkSessionConsistency(file) checkSessionConsistency(file)
if (!extensionPointService.hasExtensions) return file.compose() if (!extensionPointService.hasExtensions) return file.compose()
val registeredPluginAnnotations = file.session.registeredPluginAnnotations
file.replaceResolvePhase(FirResolvePhase.ANNOTATIONS_FOR_PLUGINS) file.replaceResolvePhase(FirResolvePhase.ANNOTATIONS_FOR_PLUGINS)
val newAnnotations = file.resolveAnnotations(extensionPointService.annotations, extensionPointService.metaAnnotations) val newAnnotations = file.resolveAnnotations(extensionPointService.annotations, extensionPointService.metaAnnotations)
if (!newAnnotations.isEmpty) { if (!newAnnotations.isEmpty) {
for (metaAnnotation in newAnnotations.keySet()) { for (metaAnnotation in newAnnotations.keySet()) {
extensionPointService.registerUserDefinedAnnotation(metaAnnotation, newAnnotations[metaAnnotation]) extensionPointService.registerUserDefinedAnnotation(metaAnnotation, newAnnotations[metaAnnotation])
registeredPluginAnnotations.registerUserDefinedAnnotation(metaAnnotation, newAnnotations[metaAnnotation])
} }
val newAnnotationsFqns = newAnnotations.values().mapTo(mutableSetOf()) { it.symbol.classId.asSingleFqName() } val newAnnotationsFqns = newAnnotations.values().mapTo(mutableSetOf()) { it.symbol.classId.asSingleFqName() }
file.resolveAnnotations(newAnnotationsFqns, emptySet()) file.resolveAnnotations(newAnnotationsFqns, emptySet())
@@ -80,15 +81,27 @@ private class FirPartialImportResolveTransformer(
private class FirAnnotationResolveTransformer( private class FirAnnotationResolveTransformer(
session: FirSession, session: FirSession,
scopeSession: ScopeSession scopeSession: ScopeSession
) : FirAbstractAnnotationResolveTransformer<Multimap<AnnotationFqn, FirRegularClass>>(session, scopeSession) { ) : FirAbstractAnnotationResolveTransformer<Multimap<AnnotationFqn, FirRegularClass>, PersistentList<FirAnnotatedDeclaration>>(session, scopeSession) {
var metaAnnotations: Set<AnnotationFqn> = emptySet() var metaAnnotations: Set<AnnotationFqn> = emptySet()
private val typeResolverTransformer: FirSpecificTypeResolverTransformer = FirSpecificTypeResolverTransformer( private val typeResolverTransformer: FirSpecificTypeResolverTransformer = FirSpecificTypeResolverTransformer(
towerScope, towerScope,
session, session,
errorTypeAsResolved = false errorTypeAsResolved = false
) )
private var owners: PersistentList<FirAnnotatedDeclaration> = persistentListOf()
override fun beforeChildren(declaration: FirAnnotatedDeclaration): PersistentList<FirAnnotatedDeclaration>? {
val current = owners
owners = owners.add(declaration)
return current
}
override fun afterChildren(state: PersistentList<FirAnnotatedDeclaration>?) {
requireNotNull(state)
owners = state
}
override fun transformAnnotationCall( override fun transformAnnotationCall(
annotationCall: FirAnnotationCall, annotationCall: FirAnnotationCall,
data: Multimap<AnnotationFqn, FirRegularClass> data: Multimap<AnnotationFqn, FirRegularClass>
@@ -109,4 +122,13 @@ private class FirAnnotationResolveTransformer(
} }
} }
} }
override fun transformAnnotatedDeclaration(
annotatedDeclaration: FirAnnotatedDeclaration,
data: Multimap<AnnotationFqn, FirRegularClass>
): CompositeTransformResult<FirDeclaration> {
return super.transformAnnotatedDeclaration(annotatedDeclaration, data).also {
session.predicateBasedProvider.registerAnnotatedDeclaration(annotatedDeclaration, owners)
}
}
} }