[FIR] Add stage for resolving annotations from plugins

This commit is contained in:
Dmitriy Novozhilov
2020-04-28 16:03:07 +03:00
parent f9c37cfa6c
commit 4ed6d7fddb
6 changed files with 198 additions and 10 deletions
@@ -138,19 +138,18 @@ class FirExtensionPointService(
}
}
private val FirAnnotationCall.fqName: FqName?
get() {
val symbol = session.firSymbolProvider.getSymbolByTypeRef<FirRegularClassSymbol>(annotationTypeRef) ?: return null
return symbol.classId.asSingleFqName()
}
private fun collectExtensions(result: MutableSet<P>, declaration: FirAnnotationContainer, extensions: Multimap<AnnotationFqn, P>) {
for (annotation in declaration.annotations) {
val fqName = annotation.fqName ?: continue
val fqName = annotation.fqName(session) ?: continue
result += extensions[fqName]
}
}
}
}
val FirSession.extensionPointService: FirExtensionPointService by FirSession.sessionComponentAccessor()
val FirSession.extensionPointService: FirExtensionPointService by FirSession.sessionComponentAccessor()
fun FirAnnotationCall.fqName(session: FirSession): FqName? {
val symbol = session.firSymbolProvider.getSymbolByTypeRef<FirRegularClassSymbol>(annotationTypeRef) ?: return null
return symbol.classId.asSingleFqName()
}
@@ -18,14 +18,16 @@ import org.jetbrains.kotlin.fir.visitors.compose
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
class FirImportResolveTransformer() : FirAbstractTreeTransformer<Nothing?>(phase = FirResolvePhase.IMPORTS) {
open class FirImportResolveTransformer protected constructor(phase: FirResolvePhase) : FirAbstractTreeTransformer<Nothing?>(phase) {
constructor() : this(FirResolvePhase.IMPORTS)
override fun <E : FirElement> transformElement(element: E, data: Nothing?): CompositeTransformResult<E> {
return element.compose()
}
private lateinit var symbolProvider: FirSymbolProvider
override lateinit var session: FirSession
final override lateinit var session: FirSession
constructor(session: FirSession) : this() {
this.session = session
@@ -43,6 +45,8 @@ class FirImportResolveTransformer() : FirAbstractTreeTransformer<Nothing?>(phase
override fun transformImport(import: FirImport, data: Nothing?): CompositeTransformResult<FirImport> {
val fqName = import.importedFqName?.takeUnless { it.isRoot } ?: return import.compose()
if (!fqName.isAcceptable) return import.compose()
if (import.isAllUnder) {
return transformImportForFqName(fqName, import)
}
@@ -51,6 +55,9 @@ class FirImportResolveTransformer() : FirAbstractTreeTransformer<Nothing?>(phase
return transformImportForFqName(parentFqName, import)
}
protected open val FqName.isAcceptable: Boolean
get() = true
private fun transformImportForFqName(fqName: FqName, delegate: FirImport): CompositeTransformResult<FirImport> {
val (packageFqName, relativeClassFqName) = resolveToPackageOrClass(symbolProvider, fqName) ?: return delegate.compose()
return buildResolvedImport {
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirBodyResolveTransformerAdapter
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirImplicitTypeBodyResolveTransformerAdapter
import org.jetbrains.kotlin.fir.resolve.transformers.contracts.FirContractResolveTransformerAdapter
import org.jetbrains.kotlin.fir.resolve.transformers.plugin.FirPluginAnnotationsResolveTransformer
import org.jetbrains.kotlin.fir.visitors.FirTransformer
// TODO: add FirSession parameter
@@ -18,6 +19,7 @@ import org.jetbrains.kotlin.fir.visitors.FirTransformer
fun FirResolvePhase.createTransformerByPhase(scopeSession: ScopeSession): FirTransformer<Nothing?> {
return when (this) {
RAW_FIR -> throw AssertionError("Raw FIR building phase does not have a transformer")
ANNOTATIONS_FOR_PLUGINS -> FirPluginAnnotationsResolveTransformer(scopeSession)
IMPORTS -> FirImportResolveTransformer()
SUPER_TYPES -> FirSupertypeResolverTransformer(scopeSession)
SEALED_CLASS_INHERITORS -> FirSealedClassInheritorsTransformer()
@@ -0,0 +1,86 @@
/*
* 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.resolve.transformers.plugin
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.withScopeCleanup
import org.jetbrains.kotlin.fir.scopes.createImportingScopes
import org.jetbrains.kotlin.fir.scopes.impl.FirCompositeScope
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult
import org.jetbrains.kotlin.fir.visitors.FirDefaultTransformer
import org.jetbrains.kotlin.fir.visitors.compose
internal abstract class FirAbstractAnnotationResolveTransformer<D>(
protected val session: FirSession,
protected val scopeSession: ScopeSession
) : FirDefaultTransformer<D>() {
abstract override fun transformAnnotationCall(annotationCall: FirAnnotationCall, data: D): CompositeTransformResult<FirStatement>
protected val towerScope = FirCompositeScope(mutableListOf())
override fun transformFile(file: FirFile, data: D): CompositeTransformResult<FirDeclaration> {
return withScopeCleanup(towerScope.scopes) {
towerScope.addScopes(createImportingScopes(file, session, scopeSession))
file.transformDeclarations(this, data)
file.transformAnnotations(this, data).compose()
}
}
override fun transformProperty(property: FirProperty, data: D): CompositeTransformResult<FirDeclaration> {
return property.transformAnnotations(this, data).compose()
}
override fun transformRegularClass(
regularClass: FirRegularClass,
data: D
): CompositeTransformResult<FirStatement> {
regularClass.transformDeclarations(this, data)
regularClass.transformCompanionObject(this, data)
regularClass.transformSuperTypeRefs(this, data)
return regularClass.transformAnnotations(this, data).compose()
}
override fun transformSimpleFunction(
simpleFunction: FirSimpleFunction,
data: D
): CompositeTransformResult<FirDeclaration> {
simpleFunction.transformValueParameters(this, data)
return simpleFunction.transformAnnotations(this, data).compose()
}
override fun transformConstructor(
constructor: FirConstructor,
data: D
): CompositeTransformResult<FirDeclaration> {
constructor.transformValueParameters(this, data)
return constructor.transformAnnotations(this, data).compose()
}
override fun transformValueParameter(
valueParameter: FirValueParameter,
data: D
): CompositeTransformResult<FirStatement> {
return valueParameter.transformAnnotations(this, data).compose()
}
override fun transformTypeAlias(typeAlias: FirTypeAlias, data: D): CompositeTransformResult<FirDeclaration> {
return typeAlias.transformAnnotations(this, data).compose()
}
override fun transformTypeRef(typeRef: FirTypeRef, data: D): CompositeTransformResult<FirTypeRef> {
return typeRef.transformAnnotations(this, data).compose()
}
override fun <E : FirElement> transformElement(element: E, data: D): CompositeTransformResult<E> {
return element.compose()
}
}
@@ -0,0 +1,92 @@
/*
* 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.resolve.transformers.plugin
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.extensions.AnnotationFqn
import org.jetbrains.kotlin.fir.extensions.extensionPointService
import org.jetbrains.kotlin.fir.extensions.fqName
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.FirImportResolveTransformer
import org.jetbrains.kotlin.fir.resolve.transformers.FirSpecificTypeResolverTransformer
import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult
import org.jetbrains.kotlin.fir.visitors.FirTransformer
import org.jetbrains.kotlin.fir.visitors.compose
import org.jetbrains.kotlin.name.FqName
class FirPluginAnnotationsResolveTransformer(private val scopeSession: ScopeSession) : FirTransformer<Nothing?>() {
override fun <E : FirElement> transformElement(element: E, data: Nothing?): CompositeTransformResult<E> {
throw IllegalStateException("Should not be here")
}
override fun transformFile(file: FirFile, data: Nothing?): CompositeTransformResult<FirDeclaration> {
file.replaceResolvePhase(FirResolvePhase.ANNOTATIONS_FOR_PLUGINS)
val extensionPointService = file.session.extensionPointService
val newAnnotations = file.resolveAnnotations(extensionPointService.annotations, extensionPointService.metaAnnotations)
if (newAnnotations.isNotEmpty()) {
for (annotationClass in newAnnotations) {
extensionPointService.registerUserDefinedAnnotation(annotationClass)
}
val newAnnotationsFqns = newAnnotations.mapTo(mutableSetOf()) { it.symbol.classId.asSingleFqName() }
file.resolveAnnotations(newAnnotationsFqns, emptySet())
}
return file.compose()
}
private fun FirFile.resolveAnnotations(
annotations: Set<AnnotationFqn>,
metaAnnotations: Set<AnnotationFqn>
): Set<FirRegularClass> {
val importTransformer = FirPartialImportResolveTransformer(annotations)
this.transform<FirFile, Nothing?>(importTransformer, null)
val annotationTransformer = FirAnnotationResolveTransformer(metaAnnotations, session, scopeSession)
val newAnnotations = mutableSetOf<FirRegularClass>()
this.transform<FirFile, MutableSet<FirRegularClass>>(annotationTransformer, newAnnotations)
return newAnnotations
}
}
private class FirPartialImportResolveTransformer(
private val acceptableFqNames: Set<FqName>
) : FirImportResolveTransformer(FirResolvePhase.ANNOTATIONS_FOR_PLUGINS) {
override val FqName.isAcceptable: Boolean
get() = this in acceptableFqNames
}
private class FirAnnotationResolveTransformer(
private val metaAnnotations: Set<AnnotationFqn>,
session: FirSession,
scopeSession: ScopeSession
) : FirAbstractAnnotationResolveTransformer<MutableSet<FirRegularClass>>(session, scopeSession) {
private val typeResolverTransformer: FirSpecificTypeResolverTransformer = FirSpecificTypeResolverTransformer(towerScope, session)
override fun transformAnnotationCall(
annotationCall: FirAnnotationCall,
data: MutableSet<FirRegularClass>
): CompositeTransformResult<FirStatement> {
return annotationCall.transformAnnotationTypeRef(typeResolverTransformer, null).compose()
}
override fun transformRegularClass(
regularClass: FirRegularClass,
data: MutableSet<FirRegularClass>
): CompositeTransformResult<FirStatement> {
return super.transformRegularClass(regularClass, data).also {
if (regularClass.classKind == ClassKind.ANNOTATION_CLASS && metaAnnotations.isNotEmpty()) {
val annotations = regularClass.annotations.mapNotNull { it.fqName(session) }
if (annotations.any { it in metaAnnotations }) {
data += regularClass
}
}
}
}
}
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.declarations
enum class FirResolvePhase {
RAW_FIR,
ANNOTATIONS_FOR_PLUGINS, // run only if some extensions are registered
IMPORTS,
SUPER_TYPES,
SEALED_CLASS_INHERITORS,
@@ -19,6 +20,7 @@ enum class FirResolvePhase {
val requiredToLaunch: FirResolvePhase
get() = when (this) {
RAW_FIR -> RAW_FIR
IMPORTS -> RAW_FIR
IMPLICIT_TYPES_BODY_RESOLVE, BODY_RESOLVE -> STATUS
else -> values()[ordinal - 1]
}