diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirExtensionPointService.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirExtensionPointService.kt index 53ae5603ad5..8418b7b0f88 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirExtensionPointService.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirExtensionPointService.kt @@ -138,19 +138,18 @@ class FirExtensionPointService( } } - private val FirAnnotationCall.fqName: FqName? - get() { - val symbol = session.firSymbolProvider.getSymbolByTypeRef(annotationTypeRef) ?: return null - return symbol.classId.asSingleFqName() - } - private fun collectExtensions(result: MutableSet

, declaration: FirAnnotationContainer, extensions: Multimap) { 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() \ No newline at end of file +val FirSession.extensionPointService: FirExtensionPointService by FirSession.sessionComponentAccessor() + +fun FirAnnotationCall.fqName(session: FirSession): FqName? { + val symbol = session.firSymbolProvider.getSymbolByTypeRef(annotationTypeRef) ?: return null + return symbol.classId.asSingleFqName() +} \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirImportResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirImportResolveTransformer.kt index 4b4ad5d7ac4..5b4dd9f026a 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirImportResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirImportResolveTransformer.kt @@ -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(phase = FirResolvePhase.IMPORTS) { +open class FirImportResolveTransformer protected constructor(phase: FirResolvePhase) : FirAbstractTreeTransformer(phase) { + constructor() : this(FirResolvePhase.IMPORTS) + override fun transformElement(element: E, data: Nothing?): CompositeTransformResult { 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(phase override fun transformImport(import: FirImport, data: Nothing?): CompositeTransformResult { 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(phase return transformImportForFqName(parentFqName, import) } + protected open val FqName.isAcceptable: Boolean + get() = true + private fun transformImportForFqName(fqName: FqName, delegate: FirImport): CompositeTransformResult { val (packageFqName, relativeClassFqName) = resolveToPackageOrClass(symbolProvider, fqName) ?: return delegate.compose() return buildResolvedImport { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/ResolvePhaseUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/ResolvePhaseUtils.kt index 8c3d7c207de..b9f7764a92e 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/ResolvePhaseUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/ResolvePhaseUtils.kt @@ -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 { 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() diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/FirAbstractAnnotationResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/FirAbstractAnnotationResolveTransformer.kt new file mode 100644 index 00000000000..2b69a4861df --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/FirAbstractAnnotationResolveTransformer.kt @@ -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( + protected val session: FirSession, + protected val scopeSession: ScopeSession +) : FirDefaultTransformer() { + abstract override fun transformAnnotationCall(annotationCall: FirAnnotationCall, data: D): CompositeTransformResult + + protected val towerScope = FirCompositeScope(mutableListOf()) + + override fun transformFile(file: FirFile, data: D): CompositeTransformResult { + 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 { + return property.transformAnnotations(this, data).compose() + } + + override fun transformRegularClass( + regularClass: FirRegularClass, + data: D + ): CompositeTransformResult { + 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 { + simpleFunction.transformValueParameters(this, data) + return simpleFunction.transformAnnotations(this, data).compose() + } + + override fun transformConstructor( + constructor: FirConstructor, + data: D + ): CompositeTransformResult { + constructor.transformValueParameters(this, data) + return constructor.transformAnnotations(this, data).compose() + } + + override fun transformValueParameter( + valueParameter: FirValueParameter, + data: D + ): CompositeTransformResult { + return valueParameter.transformAnnotations(this, data).compose() + } + + override fun transformTypeAlias(typeAlias: FirTypeAlias, data: D): CompositeTransformResult { + return typeAlias.transformAnnotations(this, data).compose() + } + + override fun transformTypeRef(typeRef: FirTypeRef, data: D): CompositeTransformResult { + return typeRef.transformAnnotations(this, data).compose() + } + + override fun transformElement(element: E, data: D): CompositeTransformResult { + return element.compose() + } +} \ No newline at end of file diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/FirPluginAnnotationsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/FirPluginAnnotationsResolveTransformer.kt new file mode 100644 index 00000000000..db9c10f2f82 --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/FirPluginAnnotationsResolveTransformer.kt @@ -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() { + override fun transformElement(element: E, data: Nothing?): CompositeTransformResult { + throw IllegalStateException("Should not be here") + } + + override fun transformFile(file: FirFile, data: Nothing?): CompositeTransformResult { + 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, + metaAnnotations: Set + ): Set { + val importTransformer = FirPartialImportResolveTransformer(annotations) + this.transform(importTransformer, null) + + val annotationTransformer = FirAnnotationResolveTransformer(metaAnnotations, session, scopeSession) + val newAnnotations = mutableSetOf() + this.transform>(annotationTransformer, newAnnotations) + return newAnnotations + } +} + +private class FirPartialImportResolveTransformer( + private val acceptableFqNames: Set +) : FirImportResolveTransformer(FirResolvePhase.ANNOTATIONS_FOR_PLUGINS) { + override val FqName.isAcceptable: Boolean + get() = this in acceptableFqNames +} + +private class FirAnnotationResolveTransformer( + private val metaAnnotations: Set, + session: FirSession, + scopeSession: ScopeSession +) : FirAbstractAnnotationResolveTransformer>(session, scopeSession) { + private val typeResolverTransformer: FirSpecificTypeResolverTransformer = FirSpecificTypeResolverTransformer(towerScope, session) + + override fun transformAnnotationCall( + annotationCall: FirAnnotationCall, + data: MutableSet + ): CompositeTransformResult { + return annotationCall.transformAnnotationTypeRef(typeResolverTransformer, null).compose() + } + + override fun transformRegularClass( + regularClass: FirRegularClass, + data: MutableSet + ): CompositeTransformResult { + 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 + } + } + } + } +} \ No newline at end of file diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirResolvePhase.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirResolvePhase.kt index 3c24819924e..092bfdf81f5 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirResolvePhase.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirResolvePhase.kt @@ -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] }