[FIR] Support resolution of meta-annotations before supertypes

Now annotations are resolved with following algorithm:
1. On COMPILER_REQUIRED_ANNOTATIONS we resolve all annotations
     and store results if this is compiler annotation, plugin annotation,
     or annotation with meta-annotation (meta annotations are checked
     recursively with designated resolution if needed)
2. On TYPES stage we resolve all those annotations once again and if
     some annotation changes resolution then we keep type from p.1 and
     report error on this annotation, so user should disambiguate it

Ambiguity may occur because of nested annotations with same name as
  plugin annotations:

```
annotation class SomeAnnotation // (1) plugin annotation

open class Base {
    annotation class SomeAnnotation // (2)
}

class Derived : Base() {
    @SomeAnnotation // <-----------------
    class Inner
}
```
At COMPILER_REQUIRED_ANNOTATIONS annotation call will be resolved to (1)
  because at this stage supertypes are not resolved yet, and we consider
  only importing scopes. At the TYPES stage we will find correct
  annotation from supertype
This commit is contained in:
Dmitriy Novozhilov
2022-11-25 12:08:43 +02:00
committed by Space Team
parent 6a9b525ca0
commit 6864433581
48 changed files with 1065 additions and 387 deletions
@@ -967,6 +967,14 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.PLUGIN_ANNOTATION_AMBIGUITY) { firDiagnostic ->
PluginAnnotationAmbiguityImpl(
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.b),
firDiagnostic as KtPsiDiagnostic,
token,
)
}
add(FirErrors.OPT_IN_USAGE) { firDiagnostic ->
OptInUsageImpl(
firDiagnostic.a,
@@ -697,6 +697,12 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = AnnotationInWhereClauseError::class
}
abstract class PluginAnnotationAmbiguity : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = PluginAnnotationAmbiguity::class
abstract val typeFromCompilerPhase: KtType
abstract val typeFromTypesPhase: KtType
}
abstract class OptInUsage : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = OptInUsage::class
abstract val optInMarkerFqName: FqName
@@ -837,6 +837,13 @@ internal class AnnotationInWhereClauseErrorImpl(
override val token: KtLifetimeToken,
) : KtFirDiagnostic.AnnotationInWhereClauseError(), KtAbstractFirDiagnostic<KtAnnotationEntry>
internal class PluginAnnotationAmbiguityImpl(
override val typeFromCompilerPhase: KtType,
override val typeFromTypesPhase: KtType,
override val firDiagnostic: KtPsiDiagnostic,
override val token: KtLifetimeToken,
) : KtFirDiagnostic.PluginAnnotationAmbiguity(), KtAbstractFirDiagnostic<PsiElement>
internal class OptInUsageImpl(
override val optInMarkerFqName: FqName,
override val message: String,
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.fir.SessionConfiguration
import org.jetbrains.kotlin.fir.backend.jvm.FirJvmTypeMapper
import org.jetbrains.kotlin.fir.extensions.FirEmptyPredicateBasedProvider
import org.jetbrains.kotlin.fir.extensions.FirPredicateBasedProvider
import org.jetbrains.kotlin.fir.extensions.FirRegisteredPluginAnnotations
import org.jetbrains.kotlin.fir.resolve.providers.FirDependenciesSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
@@ -99,6 +100,7 @@ internal class LLFirNonUnderContentRootSessionFactory(private val project: Proje
register(FirDependenciesSymbolProvider::class, dependencyProvider)
register(FirDependenciesSymbolProvider::class, dependencyProvider)
register(FirJvmTypeMapper::class, FirJvmTypeMapper(this))
register(FirRegisteredPluginAnnotations::class, FirRegisteredPluginAnnotations.Empty)
}
}
@@ -22,20 +22,15 @@ import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.extensions.AnnotationFqn
import org.jetbrains.kotlin.fir.extensions.FirPredicateBasedProvider
import org.jetbrains.kotlin.fir.extensions.FirRegisteredPluginAnnotations
import org.jetbrains.kotlin.fir.extensions.*
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.extensions.predicate.PredicateVisitor
import org.jetbrains.kotlin.fir.extensions.registeredPluginAnnotations
import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.resolve.getCorrespondingClassSymbolOrNull
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.classId
import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitorVoid
import org.jetbrains.kotlin.fir.visitors.FirVisitor
import org.jetbrains.kotlin.name.ClassId
@@ -138,23 +133,11 @@ internal class LLFirIdePredicateBasedProvider(
}
override fun visitMetaAnnotatedWith(predicate: AbstractPredicate.MetaAnnotatedWith<P>, data: FirDeclaration): Boolean {
val visited = mutableSetOf<FirRegularClassSymbol>()
return data.annotations.any { annotation ->
annotation.markedWithMetaAnnotation(predicate.metaAnnotations, visited)
annotation.markedWithMetaAnnotation(session, data, predicate.metaAnnotations)
}
}
private fun FirAnnotation.markedWithMetaAnnotation(
metaAnnotations: Set<AnnotationFqn>,
visited: MutableSet<FirRegularClassSymbol>
): Boolean {
val symbol = this.getCorrespondingClassSymbolOrNull(session) ?: return false
if (!visited.add(symbol)) return false
if (symbol.classId.asSingleFqName() in metaAnnotations) return true
if (symbol.resolvedAnnotationsWithClassIds.any { it.markedWithMetaAnnotation(metaAnnotations, visited) }) return true
return false
}
override fun visitParentAnnotatedWith(predicate: AbstractPredicate.ParentAnnotatedWith<P>, data: FirDeclaration): Boolean {
val parent = data.directParentDeclaration ?: return false
val parentPredicate = DeclarationPredicate.AnnotatedWith(predicate.annotations)
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.providers
import org.jetbrains.kotlin.analysis.providers.KotlinAnnotationsResolver
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.caches.*
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.extensions.AbstractFirRegisteredPluginAnnotations
import org.jetbrains.kotlin.fir.extensions.AnnotationFqn
import org.jetbrains.kotlin.name.ClassId
@@ -25,14 +26,25 @@ internal class LLFirIdeRegisteredPluginAnnotations(
get() = allAnnotationsCache.getValue()
private val allAnnotationsCache: FirLazyValue<Set<AnnotationFqn>, Nothing?> = session.firCachesFactory.createLazyValue {
// at this point, annotationsFromPlugins should be collected
annotationsFromPlugins
// at this point, both metaAnnotations and annotationsFromPlugins should be collected
val result = metaAnnotations.flatMapTo(mutableSetOf()) { getAnnotationsWithMetaAnnotation(it) }
if (result.isEmpty()) {
annotationsFromPlugins
} else {
result += annotationsFromPlugins
result
}
}
// MetaAnnotation -> Annotations
private val annotationsWithMetaAnnotationCache: FirCache<AnnotationFqn, Set<AnnotationFqn>, Nothing?> =
session.firCachesFactory.createCache { metaAnnotation -> collectAnnotationsWithMetaAnnotation(metaAnnotation) }
override fun getAnnotationsWithMetaAnnotation(metaAnnotation: AnnotationFqn): Collection<AnnotationFqn> {
return annotationsWithMetaAnnotationCache.getValue(metaAnnotation)
}
private fun collectAnnotationsWithMetaAnnotation(metaAnnotation: AnnotationFqn): Set<FqName> {
val annotatedDeclarations = annotationsResolver.declarationsByAnnotation(ClassId.topLevel(metaAnnotation))
@@ -47,4 +59,8 @@ internal class LLFirIdeRegisteredPluginAnnotations(
override fun saveAnnotationsFromPlugin(annotations: Collection<AnnotationFqn>) {
annotationsFromPlugins += annotations
}
override fun registerUserDefinedAnnotation(metaAnnotation: AnnotationFqn, annotationClasses: Collection<FirRegularClass>) {
error("This method should never be called in IDE mode")
}
}
@@ -12,13 +12,14 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkPhase
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.plugin.CompilerRequiredAnnotationsComputationSession
import org.jetbrains.kotlin.fir.resolve.transformers.plugin.FirCompilerRequiredAnnotationsResolveTransformer
internal class LLFirDesignatedAnnotationsResolveTransformed(
private val designation: FirDeclarationDesignationWithFile,
session: FirSession,
scopeSession: ScopeSession,
) : LLFirLazyTransformer, FirCompilerRequiredAnnotationsResolveTransformer(session, scopeSession) {
) : LLFirLazyTransformer, FirCompilerRequiredAnnotationsResolveTransformer(session, scopeSession, CompilerRequiredAnnotationsComputationSession()) {
private fun moveNextDeclaration(designationIterator: Iterator<FirDeclaration>) {
if (!designationIterator.hasNext()) {
@@ -293,6 +293,11 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val WRONG_EXTENSION_FUNCTION_TYPE by error<KtAnnotationEntry>()
val WRONG_EXTENSION_FUNCTION_TYPE_WARNING by warning<KtAnnotationEntry>()
val ANNOTATION_IN_WHERE_CLAUSE_ERROR by error<KtAnnotationEntry>()
val PLUGIN_ANNOTATION_AMBIGUITY by error<PsiElement>() {
parameter<ConeKotlinType>("typeFromCompilerPhase")
parameter<ConeKotlinType>("typeFromTypesPhase")
}
}
val OPT_IN by object : DiagnosticGroup("OptIn") {
@@ -258,6 +258,7 @@ object FirErrors {
val WRONG_EXTENSION_FUNCTION_TYPE by error0<KtAnnotationEntry>()
val WRONG_EXTENSION_FUNCTION_TYPE_WARNING by warning0<KtAnnotationEntry>()
val ANNOTATION_IN_WHERE_CLAUSE_ERROR by error0<KtAnnotationEntry>()
val PLUGIN_ANNOTATION_AMBIGUITY by error2<PsiElement, ConeKotlinType, ConeKotlinType>()
// OptIn
val OPT_IN_USAGE by warning2<PsiElement, FqName, String>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
@@ -400,6 +400,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OVERRIDING_FINAL_
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PACKAGE_CANNOT_BE_IMPORTED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PACKAGE_OR_CLASSIFIER_REDECLARATION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PLATFORM_CLASS_MAPPED_TO_KOTLIN
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PLUGIN_ANNOTATION_AMBIGUITY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PRIMARY_CONSTRUCTOR_REQUIRED_FOR_DATA_CLASS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PRIVATE_CLASS_MEMBER_FROM_INLINE
@@ -905,6 +906,12 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
ANNOTATION_IN_WHERE_CLAUSE_ERROR,
"Type parameter annotations are not allowed inside where clauses. You should probably move annotations to the type parameter declaration",
)
map.put(
PLUGIN_ANNOTATION_AMBIGUITY,
"Resolution of annotation type is ambigous between {1} and plugin annotation {0}. Please specify fully qualified name of annotation",
RENDER_TYPE,
RENDER_TYPE
)
// Exposed visibility group // #
map.put(
@@ -134,6 +134,9 @@ private fun ConeDiagnostic.toKtDiagnostic(
is ConeAmbiguousSuper -> FirErrors.AMBIGUOUS_SUPER.createOn(source, this.candidateTypes)
is ConeUnresolvedParentInImport -> null // reported in FirUnresolvedImportChecker
is ConeAmbiguousAlteredAssign -> FirErrors.AMBIGUOUS_ALTERED_ASSIGN.createOn(source, this.altererNames)
is ConeAmbiguouslyResolvedAnnotationFromPlugin -> {
FirErrors.PLUGIN_ANNOTATION_AMBIGUITY.createOn(source, typeFromCompilerPhase, typeFromTypesPhase)
}
else -> throw IllegalArgumentException("Unsupported diagnostic type: ${this.javaClass}")
}
@@ -12,15 +12,19 @@ import org.jetbrains.kotlin.fir.FirSession
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.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
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.extensions.predicate.PredicateVisitor
import org.jetbrains.kotlin.fir.resolve.fqName
import org.jetbrains.kotlin.fir.resolve.getCorrespondingClassSymbolOrNull
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.coneTypeSafe
import org.jetbrains.kotlin.fir.types.toRegularClassSymbol
@NoMutableState
class FirPredicateBasedProviderImpl(private val session: FirSession) : FirPredicateBasedProvider() {
@@ -132,23 +136,11 @@ class FirPredicateBasedProviderImpl(private val session: FirSession) : FirPredic
// ------------------------------------ Meta-annotated ------------------------------------
override fun visitMetaAnnotatedWith(predicate: AbstractPredicate.MetaAnnotatedWith<P>, data: FirDeclaration): Boolean {
val visited = mutableSetOf<FirRegularClassSymbol>()
return data.annotations.any { annotation ->
annotation.markedWithMetaAnnotation(predicate.metaAnnotations, visited)
annotation.markedWithMetaAnnotation(session, data, predicate.metaAnnotations)
}
}
private fun FirAnnotation.markedWithMetaAnnotation(
metaAnnotations: Set<AnnotationFqn>,
visited: MutableSet<FirRegularClassSymbol>
): Boolean {
val symbol = this.getCorrespondingClassSymbolOrNull(session) ?: return false
if (!visited.add(symbol)) return false
if (symbol.classId.asSingleFqName() in metaAnnotations) return true
if (symbol.resolvedAnnotationsWithClassIds.any { it.markedWithMetaAnnotation(metaAnnotations, visited) }) return true
return false
}
// ------------------------------------ Utilities ------------------------------------
private fun matchWith(declaration: FirDeclaration, annotations: Set<AnnotationFqn>): Boolean {
@@ -188,3 +180,27 @@ class FirPredicateBasedProviderImpl(private val session: FirSession) : FirPredic
val filesWithPluginAnnotations: MutableSet<FirFile> = mutableSetOf()
}
}
fun FirAnnotation.markedWithMetaAnnotation(
session: FirSession,
containingDeclaration: FirDeclaration,
metaAnnotations: Set<AnnotationFqn>
): Boolean {
containingDeclaration.symbol.lazyResolveToPhase(FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS)
return annotationTypeRef.coneTypeSafe<ConeKotlinType>()
?.toRegularClassSymbol(session)
.markedWithMetaAnnotationImpl(session, metaAnnotations, mutableSetOf())
}
fun FirRegularClassSymbol?.markedWithMetaAnnotationImpl(
session: FirSession,
metaAnnotations: Set<AnnotationFqn>,
visited: MutableSet<FirRegularClassSymbol>
): Boolean {
if (this == null) return false
if (!visited.add(this)) return false
if (this.classId.asSingleFqName() in metaAnnotations) return true
return this.resolvedCompilerAnnotationsWithClassIds
.mapNotNull { it.annotationTypeRef.coneTypeSafe<ConeKotlinType>()?.toRegularClassSymbol(session) }
.any { it.markedWithMetaAnnotationImpl(session, metaAnnotations, visited) }
}
@@ -5,24 +5,68 @@
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.NoMutableState
import org.jetbrains.kotlin.fir.caches.FirCache
import org.jetbrains.kotlin.fir.caches.createCache
import org.jetbrains.kotlin.fir.caches.firCachesFactory
import org.jetbrains.kotlin.fir.caches.getValue
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
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.utils.addToStdlib.shouldNotBeCalled
abstract class FirRegisteredPluginAnnotations(protected val session: FirSession) : FirSessionComponent {
abstract class FirRegisteredPluginAnnotations : FirSessionComponent {
/**
* Contains all annotations that can be targeted by lookup predicates from plugins
* Contains all annotations that can be targeted by the plugins. It includes the annotations directly mentioned by the plugin,
* and all the user-defined annotations which are meta-annotated by the annotations from the [metaAnnotations] list.
*/
abstract val annotations: Set<AnnotationFqn>
/**
* Contains meta-annotations that can be targeted by the plugins.
*/
abstract val metaAnnotations: Set<AnnotationFqn>
val hasRegisteredAnnotations: Boolean
get() = annotations.isNotEmpty()
get() = annotations.isNotEmpty() || metaAnnotations.isNotEmpty()
abstract fun getAnnotationsWithMetaAnnotation(metaAnnotation: AnnotationFqn): Collection<AnnotationFqn>
abstract fun registerUserDefinedAnnotation(metaAnnotation: AnnotationFqn, annotationClasses: Collection<FirRegularClass>)
abstract fun getAnnotationsForPredicate(predicate: DeclarationPredicate): Set<AnnotationFqn>
@PluginServicesInitialization
abstract fun initialize()
object Empty : FirRegisteredPluginAnnotations() {
override val annotations: Set<AnnotationFqn>
get() = emptySet()
override val metaAnnotations: Set<AnnotationFqn>
get() = emptySet()
override fun getAnnotationsWithMetaAnnotation(metaAnnotation: AnnotationFqn): Collection<AnnotationFqn> {
return emptyList()
}
override fun registerUserDefinedAnnotation(metaAnnotation: AnnotationFqn, annotationClasses: Collection<FirRegularClass>) {
shouldNotBeCalled()
}
override fun getAnnotationsForPredicate(predicate: DeclarationPredicate): Set<AnnotationFqn> {
return emptySet()
}
@PluginServicesInitialization
override fun initialize() {
shouldNotBeCalled()
}
}
}
/**
@@ -31,12 +75,29 @@ abstract class FirRegisteredPluginAnnotations(protected val session: FirSession)
*
* It also has some common code in it.
*/
abstract class AbstractFirRegisteredPluginAnnotations(session: FirSession) : FirRegisteredPluginAnnotations(session) {
abstract class AbstractFirRegisteredPluginAnnotations(protected val session: FirSession) : FirRegisteredPluginAnnotations() {
final override val metaAnnotations: MutableSet<AnnotationFqn> = mutableSetOf()
private val annotationsForPredicateCache: FirCache<DeclarationPredicate, Set<AnnotationFqn>, Nothing?> =
session.firCachesFactory.createCache { predicate ->
collectAnnotations(predicate)
}
final override fun getAnnotationsForPredicate(predicate: DeclarationPredicate): Set<AnnotationFqn> {
return annotationsForPredicateCache.getValue(predicate)
}
private fun collectAnnotations(predicate: DeclarationPredicate): Set<AnnotationFqn> {
val result = predicate.metaAnnotations.flatMapTo(mutableSetOf()) { getAnnotationsWithMetaAnnotation(it) }
if (result.isEmpty()) return predicate.annotations
result += predicate.annotations
return result
}
@PluginServicesInitialization
final override fun initialize() {
val registrar = object : FirDeclarationPredicateRegistrar() {
val predicates = mutableListOf<AbstractPredicate<*>>()
override fun register(vararg predicates: AbstractPredicate<*>) {
this.predicates += predicates
}
@@ -54,6 +115,7 @@ abstract class AbstractFirRegisteredPluginAnnotations(session: FirSession) : Fir
for (predicate in registrar.predicates) {
saveAnnotationsFromPlugin(predicate.annotations)
metaAnnotations += predicate.metaAnnotations
}
}
@@ -64,9 +126,23 @@ abstract class AbstractFirRegisteredPluginAnnotations(session: FirSession) : Fir
class FirRegisteredPluginAnnotationsImpl(session: FirSession) : AbstractFirRegisteredPluginAnnotations(session) {
override val annotations: MutableSet<AnnotationFqn> = mutableSetOf()
// MetaAnnotation -> Annotations
private val userDefinedAnnotations: Multimap<AnnotationFqn, AnnotationFqn> = LinkedHashMultimap.create()
override fun getAnnotationsWithMetaAnnotation(metaAnnotation: AnnotationFqn): Collection<AnnotationFqn> {
return userDefinedAnnotations[metaAnnotation]
}
override fun saveAnnotationsFromPlugin(annotations: Collection<AnnotationFqn>) {
this.annotations += annotations
}
override fun registerUserDefinedAnnotation(metaAnnotation: AnnotationFqn, annotationClasses: Collection<FirRegularClass>) {
require(annotationClasses.all { it.classKind == ClassKind.ANNOTATION_CLASS })
val annotations = annotationClasses.map { it.symbol.classId.asSingleFqName() }
this.annotations += annotations
userDefinedAnnotations.putAll(metaAnnotation, annotations)
}
}
val FirSession.registeredPluginAnnotations: FirRegisteredPluginAnnotations by FirSession.sessionComponentAccessor()
@@ -0,0 +1,70 @@
/*
* 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.resolve.transformers
import org.jetbrains.kotlin.fir.declarations.FirAnonymousObject
import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
class DesignationState private constructor(
val firstDeclaration: FirDeclaration,
private val designation: Iterator<FirDeclaration>,
val targetClass: FirClassLikeDeclaration
) {
companion object {
fun create(
symbol: FirRegularClassSymbol,
designationMapForLocalClasses: Map<FirClassLikeDeclaration, FirClassLikeDeclaration?>,
includeFile: Boolean
): DesignationState? {
val regularClass = symbol.fir
val designation = if (regularClass.isLocal) buildList {
var klass: FirClassLikeDeclaration = regularClass
while (true) {
this.add(klass)
klass = designationMapForLocalClasses[klass]?.takeIf { it !is FirAnonymousObject } ?: break
}
reverse()
} else buildList<FirDeclaration> {
val firProvider = regularClass.moduleData.session.firProvider
val outerClasses = generateSequence(symbol.classId) { classId ->
classId.outerClassId
}.mapTo(mutableListOf()) { firProvider.getFirClassifierByFqName(it) }
val file = firProvider.getFirClassifierContainerFileIfAny(regularClass.symbol)
requireNotNull(file) { "Containing file was not found for\n${regularClass.render()}" }
if (includeFile) {
this += file
}
this += outerClasses.filterNotNull().asReversed()
}
if (designation.isEmpty()) return null
return DesignationState(designation.first(), designation.iterator(), regularClass)
}
}
private var currentElement: FirDeclaration? = null
var classLocated = false
private set
fun shouldSkipClass(declaration: FirDeclaration): Boolean {
if (classLocated) return declaration != targetClass
if (currentElement == null && designation.hasNext()) {
currentElement = designation.next()
}
val result = currentElement == declaration
if (result) {
if (currentElement == targetClass) {
classLocated = true
}
currentElement = null
}
return !result
}
}
@@ -126,8 +126,7 @@ open class FirStatusResolveTransformer(
open class FirDesignatedStatusResolveTransformer(
session: FirSession,
scopeSession: ScopeSession,
private val designation: Iterator<FirDeclaration>,
private val targetClass: FirClassLikeDeclaration,
private val designation: DesignationState,
statusComputationSession: StatusComputationSession,
designationMapForLocalClasses: Map<FirClassLikeDeclaration, FirClassLikeDeclaration?>,
scopeForLocalClass: FirScope?,
@@ -138,44 +137,26 @@ open class FirDesignatedStatusResolveTransformer(
designationMapForLocalClasses,
scopeForLocalClass
) {
private var currentElement: FirDeclaration? = null
private var classLocated = false
private fun shouldSkipClass(declaration: FirDeclaration): Boolean {
if (classLocated) return declaration != targetClass
if (currentElement == null && designation.hasNext()) {
currentElement = designation.next()
}
val result = currentElement == declaration
if (result) {
if (currentElement == targetClass) {
classLocated = true
}
currentElement = null
}
return !result
}
override fun FirDeclaration.needResolveMembers(): Boolean {
return classLocated
return designation.classLocated
}
override fun FirDeclaration.needResolveNestedClassifiers(): Boolean {
return !classLocated
return !designation.classLocated
}
override fun transformRegularClass(
regularClass: FirRegularClass,
data: FirResolvedDeclarationStatus?
): FirStatement = whileAnalysing(regularClass) {
if (shouldSkipClass(regularClass)) return regularClass
if (designation.shouldSkipClass(regularClass)) return regularClass
regularClass.symbol.lazyResolveToPhase(FirResolvePhase.TYPES)
val classLocated = this.classLocated
val classLocated = designation.classLocated
/*
* In designated status resolve we should resolve status only of target class and it's members
*/
if (classLocated) {
assert(regularClass == targetClass)
assert(regularClass == designation.targetClass)
val computationStatus = statusComputationSession.startComputing(regularClass)
forceResolveStatusesOfSupertypes(regularClass)
if (computationStatus != StatusComputationSession.StatusComputationStatus.Computed) {
@@ -411,36 +392,17 @@ abstract class AbstractFirStatusResolveTransformer(
statusComputationSession.endComputing(regularClass)
return
}
val symbol = regularClass.symbol
val designation = if (regularClass.isLocal) buildList {
var klass: FirClassLikeDeclaration = regularClass
while (true) {
this.add(klass)
klass = designationMapForLocalClasses[klass]?.takeIf { it !is FirAnonymousObject } ?: break
}
reverse()
} else buildList<FirDeclaration> {
val firProvider = regularClass.moduleData.session.firProvider
val outerClasses = generateSequence(symbol.classId) { classId ->
classId.outerClassId
}.mapTo(mutableListOf()) { firProvider.getFirClassifierByFqName(it) }
val file = firProvider.getFirClassifierContainerFileIfAny(regularClass.symbol)
requireNotNull(file) { "Containing file was not found for\n${regularClass.render()}" }
this += outerClasses.filterNotNull().asReversed()
}
if (designation.isEmpty()) return
val designation = DesignationState.create(regularClass.symbol, designationMapForLocalClasses, includeFile = false) ?: return
val transformer = FirDesignatedStatusResolveTransformer(
session,
scopeSession,
designation.iterator(),
regularClass,
designation,
statusComputationSession,
designationMapForLocalClasses,
scopeForLocalClass
)
designation.first().transformSingle(transformer, null)
designation.firstDeclaration.transformSingle(transformer, null)
statusComputationSession.endComputing(regularClass)
}
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.isFromVararg
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeAmbiguouslyResolvedAnnotationFromPlugin
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeCyclicTypeBound
import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
import org.jetbrains.kotlin.fir.scopes.FirScope
@@ -21,7 +22,9 @@ import org.jetbrains.kotlin.fir.scopes.impl.nestedClassifierScope
import org.jetbrains.kotlin.fir.scopes.impl.wrapNestedClassifierScopeWithSubstitutionForSuperType
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef
import org.jetbrains.kotlin.fir.visitors.transformSingle
import org.jetbrains.kotlin.fir.whileAnalysing
import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled
class FirTypeResolveProcessor(
session: FirSession,
@@ -226,12 +229,45 @@ open class FirTypeResolveTransformer(
}
override fun transformAnnotation(annotation: FirAnnotation, data: Any?): FirStatement {
annotation.transformAnnotationTypeRef(this, data)
return annotation
shouldNotBeCalled()
}
override fun transformAnnotationCall(annotationCall: FirAnnotationCall, data: Any?): FirStatement = whileAnalysing(annotationCall) {
return transformAnnotation(annotationCall, data)
when (val originalTypeRef = annotationCall.annotationTypeRef) {
is FirResolvedTypeRef -> {
when (annotationCall.annotationResolvePhase) {
FirAnnotationResolvePhase.Unresolved -> when (originalTypeRef){
is FirErrorTypeRef -> return annotationCall.also { it.replaceAnnotationResolvePhase(FirAnnotationResolvePhase.Types) }
else -> shouldNotBeCalled()
}
FirAnnotationResolvePhase.CompilerRequiredAnnotations -> {
annotationCall.replaceAnnotationResolvePhase(FirAnnotationResolvePhase.Types)
val alternativeResolvedTypeRef = originalTypeRef.delegatedTypeRef?.transformSingle(this, data) ?: return annotationCall
val coneTypeFromCompilerRequiredPhase = originalTypeRef.coneType
val coneTypeFromTypesPhase = alternativeResolvedTypeRef.coneType
if (coneTypeFromTypesPhase != coneTypeFromCompilerRequiredPhase) {
val errorTypeRef = buildErrorTypeRef {
source = originalTypeRef.source
type = coneTypeFromCompilerRequiredPhase
delegatedTypeRef = originalTypeRef.delegatedTypeRef
diagnostic = ConeAmbiguouslyResolvedAnnotationFromPlugin(
coneTypeFromCompilerRequiredPhase,
coneTypeFromTypesPhase
)
}
annotationCall.replaceAnnotationTypeRef(errorTypeRef)
}
}
FirAnnotationResolvePhase.Types -> {}
}
}
else -> {
val transformedTypeRef = originalTypeRef.transformSingle(this, data)
annotationCall.replaceAnnotationResolvePhase(FirAnnotationResolvePhase.Types)
annotationCall.replaceAnnotationTypeRef(transformedTypeRef)
}
}
return annotationCall
}
private inline fun <T> withScopeCleanup(crossinline l: () -> T): T {
@@ -1075,6 +1075,7 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT
): FirStatement = whileAnalysing(annotationCall) {
if (annotationCall.resolved) return annotationCall
annotationCall.transformAnnotationTypeRef(transformer, ResolutionMode.ContextIndependent)
annotationCall.replaceAnnotationResolvePhase(FirAnnotationResolvePhase.Types)
return context.forAnnotation {
withFirArrayOfCallTransformer {
dataFlowAnalyzer.enterAnnotation(annotationCall)
@@ -0,0 +1,286 @@
/*
* 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 kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.persistentListOf
import org.jetbrains.kotlin.fir.FirAnnotationContainer
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.PrivateForInline
import org.jetbrains.kotlin.fir.caches.firCachesFactory
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.FirAnnotationResolvePhase
import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.extensions.AnnotationFqn
import org.jetbrains.kotlin.fir.extensions.markedWithMetaAnnotationImpl
import org.jetbrains.kotlin.fir.extensions.predicateBasedProvider
import org.jetbrains.kotlin.fir.extensions.registeredPluginAnnotations
import org.jetbrains.kotlin.fir.resolve.ResolutionMode
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.DesignationState
import org.jetbrains.kotlin.fir.resolve.transformers.FirSpecificTypeResolverTransformer
import org.jetbrains.kotlin.fir.resolve.transformers.ScopeClassDeclaration
import org.jetbrains.kotlin.fir.resolve.transformers.withClassDeclarationCleanup
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.createImportingScopes
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.visitors.FirDefaultTransformer
import org.jetbrains.kotlin.fir.visitors.transformSingle
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.StandardClassIds.Annotations.Deprecated
import org.jetbrains.kotlin.name.StandardClassIds.Annotations.DeprecatedSinceKotlin
import org.jetbrains.kotlin.name.StandardClassIds.Annotations.JvmRecord
import org.jetbrains.kotlin.name.StandardClassIds.Annotations.WasExperimental
internal abstract class AbstractFirSpecificAnnotationResolveTransformer(
protected val session: FirSession,
protected val scopeSession: ScopeSession,
protected val computationSession: CompilerRequiredAnnotationsComputationSession
) : FirDefaultTransformer<Nothing?>() {
companion object {
private val REQUIRED_ANNOTATIONS: Set<ClassId> = setOf(Deprecated, DeprecatedSinceKotlin, WasExperimental, JvmRecord)
private val REQUIRED_ANNOTATION_NAMES: Set<Name> = REQUIRED_ANNOTATIONS.mapTo(mutableSetOf()) { it.shortClassName }
}
private val predicateBasedProvider = session.predicateBasedProvider
private val annotationsFromPlugins: Set<AnnotationFqn> = session.registeredPluginAnnotations.annotations
private val metaAnnotationsFromPlugins: Set<AnnotationFqn> = session.registeredPluginAnnotations.metaAnnotations
@PrivateForInline
val typeResolverTransformer: FirSpecificTypeResolverTransformer = FirSpecificTypeResolverTransformer(
session,
errorTypeAsResolved = false
)
@PrivateForInline
val argumentsTransformer = FirAnnotationArgumentsResolveTransformer(
session,
scopeSession,
FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS
)
private var owners: PersistentList<FirDeclaration> = persistentListOf()
private val classDeclarationsStack = ArrayDeque<FirClass>()
@OptIn(PrivateForInline::class)
override fun transformAnnotationCall(annotationCall: FirAnnotationCall, data: Nothing?): FirStatement {
val annotationTypeRef = annotationCall.annotationTypeRef
if (annotationTypeRef !is FirUserTypeRef) return annotationCall
val name = annotationTypeRef.qualifier.last().name
if (!shouldRunAnnotationResolve(name)) return annotationCall
val transformedAnnotationType = annotationCall.typeRef.transformSingle(
typeResolverTransformer,
ScopeClassDeclaration(scopes.asReversed(), classDeclarationsStack)
) as? FirResolvedTypeRef ?: return annotationCall
resolveAnnotationsOnAnnotationIfNeeded(transformedAnnotationType)
if (!transformedAnnotationType.requiredToSave()) return annotationCall
annotationCall.replaceAnnotationTypeRef(transformedAnnotationType)
annotationCall.replaceAnnotationResolvePhase(FirAnnotationResolvePhase.CompilerRequiredAnnotations)
// TODO: what if we have type alias here?
if (transformedAnnotationType.coneTypeSafe<ConeClassLikeType>()?.lookupTag?.classId == Deprecated) {
argumentsTransformer.transformAnnotation(annotationCall, ResolutionMode.ContextDependent)
}
return annotationCall
}
private fun resolveAnnotationsOnAnnotationIfNeeded(annotationTypeRef: FirResolvedTypeRef) {
val symbol = annotationTypeRef.coneType.toRegularClassSymbol(session) ?: return
val regularClass = symbol.fir
if (computationSession.annotationsAreResolved(regularClass)) return
val designation = DesignationState.create(symbol, emptyMap(), includeFile = true) ?: return
val transformer = FirDesignatedCompilerRequiredAnnotationsResolveTransformer(
designation.firstDeclaration.moduleData.session,
scopeSession,
computationSession,
designation
)
designation.firstDeclaration.transformSingle(transformer, null)
}
override fun transformAnnotation(annotation: FirAnnotation, data: Nothing?): FirStatement {
error("Should not be there")
}
private fun shouldRunAnnotationResolve(name: Name): Boolean {
if (annotationsFromPlugins.isNotEmpty()) return true
return name in REQUIRED_ANNOTATION_NAMES
}
private fun FirResolvedTypeRef.requiredToSave(): Boolean {
val classId = type.classId ?: return false
return when {
classId in REQUIRED_ANNOTATIONS -> true
classId.asSingleFqName() in annotationsFromPlugins -> true
metaAnnotationsFromPlugins.isEmpty() -> false
else -> type.markedWithMetaAnnotation(session, metaAnnotationsFromPlugins)
}
}
private fun ConeKotlinType.markedWithMetaAnnotation(session: FirSession, metaAnnotations: Set<AnnotationFqn>): Boolean {
return toRegularClassSymbol(session).markedWithMetaAnnotationImpl(session, metaAnnotations, mutableSetOf())
}
override fun transformRegularClass(regularClass: FirRegularClass, data: Nothing?): FirStatement {
withClassDeclarationCleanup(classDeclarationsStack, regularClass) {
if (!shouldTransformDeclaration(regularClass)) return regularClass
computationSession.recordThatAnnotationsAreResolved(regularClass)
return transformDeclaration(regularClass, data).also {
val state = beforeTransformingChildren(regularClass)
regularClass.transformDeclarations(this, data)
regularClass.transformSuperTypeRefs(this, data)
afterTransformingChildren(state)
calculateDeprecations(regularClass)
} as FirStatement
}
}
override fun transformTypeAlias(typeAlias: FirTypeAlias, data: Nothing?): FirTypeAlias {
if (!shouldTransformDeclaration(typeAlias)) return typeAlias
computationSession.recordThatAnnotationsAreResolved(typeAlias)
return transformDeclaration(typeAlias, data).also {
calculateDeprecations(typeAlias)
} as FirTypeAlias
}
override fun transformDeclaration(declaration: FirDeclaration, data: Nothing?): FirDeclaration {
return (transformAnnotationContainer(declaration, data) as FirDeclaration).also {
predicateBasedProvider.registerAnnotatedDeclaration(declaration, owners)
}
}
override fun transformFile(file: FirFile, data: Nothing?): FirFile {
if (!shouldTransformDeclaration(file)) return file
return withFile(file) {
withFileScopes(file) {
scopes = createImportingScopes(file, session, scopeSession, useCaching = false)
val state = beforeTransformingChildren(file)
try {
file.transformDeclarations(this, data)
} finally {
afterTransformingChildren(state)
}
}
}
}
@OptIn(PrivateForInline::class)
inline fun <T> withFile(file: FirFile, f: () -> T): T {
typeResolverTransformer.withFile(file) {
argumentsTransformer.context.withFile(file, argumentsTransformer.components) {
return f()
}
}
}
private fun calculateDeprecations(classLikeDeclaration: FirClassLikeDeclaration) {
if (classLikeDeclaration.deprecationsProvider == UnresolvedDeprecationProvider) {
classLikeDeclaration.replaceDeprecationsProvider(classLikeDeclaration.getDeprecationsProvider(session.firCachesFactory))
}
}
protected lateinit var scopes: List<FirScope>
inline fun <T> withFileScopes(file: FirFile, f: () -> T): T {
scopes = createImportingScopes(file, session, scopeSession, useCaching = false)
return f()
}
protected abstract fun shouldTransformDeclaration(declaration: FirDeclaration): Boolean
override fun transformProperty(property: FirProperty, data: Nothing?): FirProperty {
if (!shouldTransformDeclaration(property)) return property
computationSession.recordThatAnnotationsAreResolved(property)
return transformDeclaration(property, data) as FirProperty
}
override fun transformSimpleFunction(
simpleFunction: FirSimpleFunction,
data: Nothing?
): FirSimpleFunction {
if (!shouldTransformDeclaration(simpleFunction)) return simpleFunction
computationSession.recordThatAnnotationsAreResolved(simpleFunction)
return transformDeclaration(simpleFunction, data).also {
val state = beforeTransformingChildren(simpleFunction)
simpleFunction.transformValueParameters(this, data)
afterTransformingChildren(state)
} as FirSimpleFunction
}
override fun transformConstructor(
constructor: FirConstructor,
data: Nothing?
): FirConstructor {
if (!shouldTransformDeclaration(constructor)) return constructor
computationSession.recordThatAnnotationsAreResolved(constructor)
return transformDeclaration(constructor, data).also {
val state = beforeTransformingChildren(constructor)
constructor.transformValueParameters(this, data)
afterTransformingChildren(state)
} as FirConstructor
}
override fun transformValueParameter(
valueParameter: FirValueParameter,
data: Nothing?
): FirStatement {
if (!shouldTransformDeclaration(valueParameter)) return valueParameter
computationSession.recordThatAnnotationsAreResolved(valueParameter)
return transformDeclaration(valueParameter, data) as FirStatement
}
override fun transformTypeRef(typeRef: FirTypeRef, data: Nothing?): FirTypeRef {
return transformAnnotationContainer(typeRef, data) as FirTypeRef
}
override fun transformAnnotationContainer(
annotationContainer: FirAnnotationContainer,
data: Nothing?
): FirAnnotationContainer {
return annotationContainer.transformAnnotations(this, data)
}
override fun <E : FirElement> transformElement(element: E, data: Nothing?): E {
return element
}
/**
* Gets called before transforming [parentDeclaration]'s nested declarations (like in a class of a file).
*
* @param parentDeclaration A declaration whose nested declarations are about to be transformed.
* @return Some state of the transformer; when the nested declarations are transformed, this state will be
* passed to the [afterTransformingChildren].
*/
private fun beforeTransformingChildren(parentDeclaration: FirDeclaration): PersistentList<FirDeclaration> {
val current = owners
owners = owners.add(parentDeclaration)
return current
}
/**
* Gets called after performing transformation of some declaration's nested declarations; can be used to restore the internal
* state of the transformer.
*
* @param parentDeclaration A declaration whose nested declarations were transformed.
* @param state A state produced by the [beforeTransformingChildren] call before the transformation.
*/
private fun afterTransformingChildren(state: PersistentList<FirDeclaration>?) {
requireNotNull(state)
owners = state
}
}
@@ -1,134 +0,0 @@
/*
* 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.FirAnnotationContainer
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.createImportingScopes
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.visitors.FirDefaultTransformer
internal abstract class FirAbstractAnnotationResolveTransformer<D, S>(
protected val session: FirSession,
protected val scopeSession: ScopeSession
) : FirDefaultTransformer<D>() {
abstract override fun transformAnnotation(annotation: FirAnnotation, data: D): FirStatement
protected lateinit var scopes: List<FirScope>
inline fun <T> withFileScopes(file: FirFile, f: () -> T): T {
scopes = createImportingScopes(file, session, scopeSession, useCaching = false)
val state = beforeTransformingChildren(file)
try {
return f()
} finally {
afterTransformingChildren(state)
}
}
override fun transformFile(file: FirFile, data: D): FirFile {
withFileScopes(file) {
scopes = createImportingScopes(file, session, scopeSession, useCaching = false)
val state = beforeTransformingChildren(file)
file.transformDeclarations(this, data)
afterTransformingChildren(state)
}
return transformDeclaration(file, data) as FirFile
}
override fun transformProperty(property: FirProperty, data: D): FirProperty {
return transformDeclaration(property, data) as FirProperty
}
override fun transformRegularClass(
regularClass: FirRegularClass,
data: D
): FirStatement {
return transformDeclaration(regularClass, data).also {
val state = beforeTransformingChildren(regularClass)
regularClass.transformDeclarations(this, data)
regularClass.transformSuperTypeRefs(this, data)
afterTransformingChildren(state)
} as FirStatement
}
override fun transformSimpleFunction(
simpleFunction: FirSimpleFunction,
data: D
): FirSimpleFunction {
return transformDeclaration(simpleFunction, data).also {
val state = beforeTransformingChildren(simpleFunction)
simpleFunction.transformValueParameters(this, data)
afterTransformingChildren(state)
} as FirSimpleFunction
}
override fun transformConstructor(
constructor: FirConstructor,
data: D
): FirConstructor {
return transformDeclaration(constructor, data).also {
val state = beforeTransformingChildren(constructor)
constructor.transformValueParameters(this, data)
afterTransformingChildren(state)
} as FirConstructor
}
override fun transformValueParameter(
valueParameter: FirValueParameter,
data: D
): FirStatement {
return transformDeclaration(valueParameter, data) as FirStatement
}
override fun transformTypeAlias(typeAlias: FirTypeAlias, data: D): FirTypeAlias {
return transformDeclaration(typeAlias, data) as FirTypeAlias
}
override fun transformTypeRef(typeRef: FirTypeRef, data: D): FirTypeRef {
return transformAnnotationContainer(typeRef, data) as FirTypeRef
}
override fun transformDeclaration(declaration: FirDeclaration, data: D): FirDeclaration {
return transformAnnotationContainer(declaration, data) as FirDeclaration
}
override fun transformAnnotationContainer(
annotationContainer: FirAnnotationContainer,
data: D
): FirAnnotationContainer {
return annotationContainer.transformAnnotations(this, data)
}
override fun <E : FirElement> transformElement(element: E, data: D): E {
return element
}
/**
* Gets called before transforming [parentDeclaration]'s nested declarations (like in a class of a file).
*
* @param parentDeclaration A declaration whose nested declarations are about to be transformed.
* @return Some state of the transformer; when the nested declarations are transformed, this state will be
* passed to the [afterTransformingChildren].
*/
protected open fun beforeTransformingChildren(parentDeclaration: FirDeclaration): S? {
return null
}
/**
* Gets called after performing transformation of some declaration's nested declarations; can be used to restore the internal
* state of the transformer.
*
* @param state A state produced by the [beforeTransformingChildren] call before the transformation.
*/
protected open fun afterTransformingChildren(state: S?) {}
}
@@ -5,33 +5,19 @@
package org.jetbrains.kotlin.fir.resolve.transformers.plugin
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.persistentListOf
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.caches.firCachesFactory
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.extensions.*
import org.jetbrains.kotlin.fir.resolve.ResolutionMode
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals
import org.jetbrains.kotlin.fir.resolve.transformers.*
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.FirUserTypeRef
import org.jetbrains.kotlin.fir.types.coneTypeSafe
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.visitors.transformSingle
import org.jetbrains.kotlin.fir.withFileAnalysisExceptionWrapping
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.StandardClassIds.Annotations.Deprecated
import org.jetbrains.kotlin.name.StandardClassIds.Annotations.DeprecatedSinceKotlin
import org.jetbrains.kotlin.name.StandardClassIds.Annotations.JvmRecord
import org.jetbrains.kotlin.name.StandardClassIds.Annotations.WasExperimental
class FirCompilerRequiredAnnotationsResolveProcessor(
session: FirSession,
@@ -39,7 +25,8 @@ class FirCompilerRequiredAnnotationsResolveProcessor(
) : FirGlobalResolveProcessor(session, scopeSession) {
override fun process(files: Collection<FirFile>) {
val transformer = FirCompilerRequiredAnnotationsResolveTransformer(session, scopeSession)
val computationSession = CompilerRequiredAnnotationsComputationSession()
val transformer = FirCompilerRequiredAnnotationsResolveTransformer(session, scopeSession, computationSession)
files.forEach {
withFileAnalysisExceptionWrapping(it) {
it.transformSingle(transformer, null)
@@ -58,12 +45,12 @@ class FirCompilerRequiredAnnotationsResolveProcessor(
}
}
open class FirCompilerRequiredAnnotationsResolveTransformer(
abstract class AbstractFirCompilerRequiredAnnotationsResolveTransformer(
final override val session: FirSession,
scopeSession: ScopeSession
computationSession: CompilerRequiredAnnotationsComputationSession
) : FirAbstractPhaseTransformer<Nothing?>(COMPILER_REQUIRED_ANNOTATIONS) {
private val annotationTransformer = FirAnnotationResolveTransformer(session, scopeSession)
private val importTransformer = FirPartialImportResolveTransformer(session)
internal abstract val annotationTransformer: AbstractFirSpecificAnnotationResolveTransformer
private val importTransformer = FirPartialImportResolveTransformer(session, computationSession)
val extensionService = session.extensionService
override fun <E : FirElement> transformElement(element: E, data: Nothing?): E {
@@ -72,10 +59,7 @@ open class FirCompilerRequiredAnnotationsResolveTransformer(
override fun transformFile(file: FirFile, data: Nothing?): FirFile {
checkSessionConsistency(file)
val registeredPluginAnnotations = session.registeredPluginAnnotations
val regularAnnotations = registeredPluginAnnotations.annotations
file.resolveAnnotations(regularAnnotations)
file.resolveAnnotations()
return file
}
@@ -93,120 +77,93 @@ open class FirCompilerRequiredAnnotationsResolveTransformer(
return annotationTransformer.transformTypeAlias(typeAlias, null)
}
private fun FirFile.resolveAnnotations(annotations: Set<AnnotationFqn>) {
val acceptableNames = annotations
importTransformer.acceptableFqNames = acceptableNames
private fun FirFile.resolveAnnotations() {
this.transformImports(importTransformer, null)
annotationTransformer.acceptableFqNames = acceptableNames
this.transform<FirFile, Nothing?>(annotationTransformer, null)
}
}
open class FirCompilerRequiredAnnotationsResolveTransformer(
session: FirSession,
scopeSession: ScopeSession,
computationSession: CompilerRequiredAnnotationsComputationSession
) : AbstractFirCompilerRequiredAnnotationsResolveTransformer(session, computationSession) {
override val annotationTransformer: AbstractFirSpecificAnnotationResolveTransformer =
FirSpecificAnnotationResolveTransformer(session, scopeSession, computationSession)
}
class FirDesignatedCompilerRequiredAnnotationsResolveTransformer(
session: FirSession,
scopeSession: ScopeSession,
computationSession: CompilerRequiredAnnotationsComputationSession,
designation: DesignationState
) : AbstractFirCompilerRequiredAnnotationsResolveTransformer(session, computationSession) {
override val annotationTransformer: AbstractFirSpecificAnnotationResolveTransformer =
FirDesignatedSpecificAnnotationResolveTransformer(session, scopeSession, computationSession, designation)
}
class CompilerRequiredAnnotationsComputationSession {
private val filesWithResolvedImports = mutableSetOf<FirFile>()
fun importsAreResolved(file: FirFile): Boolean {
return file in filesWithResolvedImports
}
fun recordThatImportsAreResolved(file: FirFile) {
if (!filesWithResolvedImports.add(file)) {
error("Imports are resolved twice")
}
}
private val declarationsWithResolvedAnnotations = mutableSetOf<FirDeclaration>()
fun annotationsAreResolved(declaration: FirDeclaration): Boolean {
if (declaration is FirFile) return false
if (declaration.origin != FirDeclarationOrigin.Source) return true
return declaration in declarationsWithResolvedAnnotations
}
fun recordThatAnnotationsAreResolved(declaration: FirDeclaration) {
if (!declarationsWithResolvedAnnotations.add(declaration)) {
error("Annotations are resolved twice")
}
}
}
private class FirPartialImportResolveTransformer(
session: FirSession
session: FirSession,
private val computationSession: CompilerRequiredAnnotationsComputationSession
) : FirImportResolveTransformer(session, COMPILER_REQUIRED_ANNOTATIONS) {
var acceptableFqNames: Set<FqName> = emptySet()
private val acceptableFqNames: Set<FqName> = session.registeredPluginAnnotations.annotations
override val FqName.isAcceptable: Boolean
get() = this in acceptableFqNames
override fun transformFile(file: FirFile, data: Any?): FirFile {
if (computationSession.importsAreResolved(file)) return file
return super.transformFile(file, data).also {
computationSession.recordThatImportsAreResolved(file)
}
}
}
private class FirAnnotationResolveTransformer(
private class FirSpecificAnnotationResolveTransformer(
session: FirSession,
scopeSession: ScopeSession
) : FirAbstractAnnotationResolveTransformer<Nothing?, PersistentList<FirDeclaration>>(session, scopeSession) {
companion object {
private val REQUIRED_ANNOTATIONS: Set<ClassId> = setOf(
Deprecated, DeprecatedSinceKotlin, WasExperimental, JvmRecord
)
private val REQUIRED_ANNOTATION_NAMES: Set<Name> = REQUIRED_ANNOTATIONS.mapTo(mutableSetOf()) { it.shortClassName }
}
private val predicateBasedProvider = session.predicateBasedProvider
var acceptableFqNames: Set<AnnotationFqn> = emptySet()
private val typeResolverTransformer: FirSpecificTypeResolverTransformer = FirSpecificTypeResolverTransformer(
session,
errorTypeAsResolved = false
)
private val argumentsTransformer = FirAnnotationArgumentsResolveTransformer(session, scopeSession, COMPILER_REQUIRED_ANNOTATIONS)
private var owners: PersistentList<FirDeclaration> = persistentListOf()
private val classDeclarationsStack = ArrayDeque<FirClass>()
override fun beforeTransformingChildren(parentDeclaration: FirDeclaration): PersistentList<FirDeclaration> {
val current = owners
owners = owners.add(parentDeclaration)
return current
}
override fun afterTransformingChildren(state: PersistentList<FirDeclaration>?) {
requireNotNull(state)
owners = state
}
override fun transformAnnotationCall(annotationCall: FirAnnotationCall, data: Nothing?): FirStatement {
return transformAnnotation(annotationCall, data)
}
override fun transformAnnotation(annotation: FirAnnotation, data: Nothing?): FirStatement {
val annotationTypeRef = annotation.annotationTypeRef
if (annotationTypeRef !is FirUserTypeRef) return annotation
val name = annotationTypeRef.qualifier.last().name
if (name !in REQUIRED_ANNOTATION_NAMES && acceptableFqNames.none { it.shortName() == name }) return annotation
val transformedAnnotation = annotation.transformAnnotationTypeRef(
typeResolverTransformer,
ScopeClassDeclaration(scopes.asReversed(), classDeclarationsStack)
)
// TODO: what if we have type alias here?
if (transformedAnnotation.annotationTypeRef.coneTypeSafe<ConeClassLikeType>()?.lookupTag?.classId == Deprecated) {
argumentsTransformer.transformAnnotation(transformedAnnotation, ResolutionMode.ContextDependent)
}
return transformedAnnotation
}
override fun transformRegularClass(regularClass: FirRegularClass, data: Nothing?): FirStatement {
withClassDeclarationCleanup(classDeclarationsStack, regularClass) {
return super.transformRegularClass(regularClass, data).also {
calculateDeprecations(regularClass)
}
}
}
override fun transformTypeAlias(typeAlias: FirTypeAlias, data: Nothing?): FirTypeAlias {
return super.transformTypeAlias(typeAlias, data).also {
calculateDeprecations(typeAlias)
}
}
override fun transformDeclaration(declaration: FirDeclaration, data: Nothing?): FirDeclaration {
return super.transformDeclaration(declaration, data).also {
predicateBasedProvider.registerAnnotatedDeclaration(declaration, owners)
}
}
override fun transformFile(file: FirFile, data: Nothing?): FirFile {
withFile(file) {
return super.transformFile(file, data)
}
}
inline fun <T> withFile(file: FirFile, f: () -> T): T {
typeResolverTransformer.withFile(file) {
argumentsTransformer.context.withFile(file, argumentsTransformer.components) {
return f()
}
}
}
private fun calculateDeprecations(classLikeDeclaration: FirClassLikeDeclaration) {
if (classLikeDeclaration.deprecationsProvider == UnresolvedDeprecationProvider) {
classLikeDeclaration.replaceDeprecationsProvider(classLikeDeclaration.getDeprecationsProvider(session.firCachesFactory))
}
scopeSession: ScopeSession,
computationSession: CompilerRequiredAnnotationsComputationSession
) : AbstractFirSpecificAnnotationResolveTransformer(session, scopeSession, computationSession) {
override fun shouldTransformDeclaration(declaration: FirDeclaration): Boolean {
return !computationSession.annotationsAreResolved(declaration)
}
}
private class FirDesignatedSpecificAnnotationResolveTransformer(
session: FirSession,
scopeSession: ScopeSession,
computationSession: CompilerRequiredAnnotationsComputationSession,
private val designation: DesignationState
) : AbstractFirSpecificAnnotationResolveTransformer(session, scopeSession, computationSession) {
override fun shouldTransformDeclaration(declaration: FirDeclaration): Boolean {
return !designation.shouldSkipClass(declaration)
}
}
@@ -242,4 +242,16 @@ class ConeAmbiguousAlteredAssign(val altererNames: List<String?>) : ConeDiagnost
object ConeForbiddenIntersection : ConeDiagnostic {
override val reason: String get() = "Such an intersection type is not allowed"
}
}
class ConeAmbiguouslyResolvedAnnotationFromPlugin(
val typeFromCompilerPhase: ConeKotlinType,
val typeFromTypesPhase: ConeKotlinType
) : ConeDiagnostic {
override val reason: String
get() = """
Annotation type resolved differently on compiler annotation and types stages:
- compiler annotations: $typeFromCompilerPhase
- types stage: $typeFromTypesPhase
"""
}
@@ -34,6 +34,8 @@ abstract class FirAnnotation : FirExpression() {
abstract override fun replaceTypeRef(newTypeRef: FirTypeRef)
abstract fun replaceAnnotationTypeRef(newAnnotationTypeRef: FirTypeRef)
abstract fun replaceArgumentMapping(newArgumentMapping: FirAnnotationArgumentMapping)
abstract fun replaceTypeArguments(newTypeArguments: List<FirTypeProjection>)
@@ -28,6 +28,7 @@ abstract class FirAnnotationCall : FirAnnotation(), FirCall, FirResolvable {
abstract override val argumentList: FirArgumentList
abstract override val calleeReference: FirReference
abstract override val argumentMapping: FirAnnotationArgumentMapping
abstract val annotationResolvePhase: FirAnnotationResolvePhase
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R = visitor.visitAnnotationCall(this, data)
@@ -37,6 +38,8 @@ abstract class FirAnnotationCall : FirAnnotation(), FirCall, FirResolvable {
abstract override fun replaceTypeRef(newTypeRef: FirTypeRef)
abstract override fun replaceAnnotationTypeRef(newAnnotationTypeRef: FirTypeRef)
abstract override fun replaceTypeArguments(newTypeArguments: List<FirTypeProjection>)
abstract override fun replaceArgumentList(newArgumentList: FirArgumentList)
@@ -45,6 +48,8 @@ abstract class FirAnnotationCall : FirAnnotation(), FirCall, FirResolvable {
abstract override fun replaceArgumentMapping(newArgumentMapping: FirAnnotationArgumentMapping)
abstract fun replaceAnnotationResolvePhase(newAnnotationResolvePhase: FirAnnotationResolvePhase)
abstract override fun <D> transformAnnotations(transformer: FirTransformer<D>, data: D): FirAnnotationCall
abstract override fun <D> transformAnnotationTypeRef(transformer: FirTransformer<D>, data: D): FirAnnotationCall
@@ -29,6 +29,7 @@ abstract class FirErrorAnnotationCall : FirAnnotationCall(), FirDiagnosticHolder
abstract override val typeArguments: List<FirTypeProjection>
abstract override val argumentList: FirArgumentList
abstract override val calleeReference: FirReference
abstract override val annotationResolvePhase: FirAnnotationResolvePhase
abstract override val diagnostic: ConeDiagnostic
abstract override val argumentMapping: FirAnnotationArgumentMapping
@@ -40,12 +41,16 @@ abstract class FirErrorAnnotationCall : FirAnnotationCall(), FirDiagnosticHolder
abstract override fun replaceTypeRef(newTypeRef: FirTypeRef)
abstract override fun replaceAnnotationTypeRef(newAnnotationTypeRef: FirTypeRef)
abstract override fun replaceTypeArguments(newTypeArguments: List<FirTypeProjection>)
abstract override fun replaceArgumentList(newArgumentList: FirArgumentList)
abstract override fun replaceCalleeReference(newCalleeReference: FirReference)
abstract override fun replaceAnnotationResolvePhase(newAnnotationResolvePhase: FirAnnotationResolvePhase)
abstract override fun replaceArgumentMapping(newArgumentMapping: FirAnnotationArgumentMapping)
abstract override fun <D> transformAnnotations(transformer: FirTransformer<D>, data: D): FirErrorAnnotationCall
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.fir.builder.FirBuilderDsl
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.FirAnnotationArgumentMapping
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.FirAnnotationResolvePhase
import org.jetbrains.kotlin.fir.expressions.FirArgumentList
import org.jetbrains.kotlin.fir.expressions.FirEmptyArgumentList
import org.jetbrains.kotlin.fir.expressions.builder.FirCallBuilder
@@ -41,6 +42,7 @@ class FirAnnotationCallBuilder : FirCallBuilder, FirAnnotationContainerBuilder,
override var argumentList: FirArgumentList = FirEmptyArgumentList
lateinit var calleeReference: FirReference
var argumentMapping: FirAnnotationArgumentMapping = FirEmptyAnnotationArgumentMapping
var annotationResolvePhase: FirAnnotationResolvePhase = FirAnnotationResolvePhase.Unresolved
override fun build(): FirAnnotationCall {
return FirAnnotationCallImpl(
@@ -51,6 +53,7 @@ class FirAnnotationCallBuilder : FirCallBuilder, FirAnnotationContainerBuilder,
argumentList,
calleeReference,
argumentMapping,
annotationResolvePhase,
)
}
@@ -87,5 +90,6 @@ inline fun buildAnnotationCallCopy(original: FirAnnotationCall, init: FirAnnotat
copyBuilder.argumentList = original.argumentList
copyBuilder.calleeReference = original.calleeReference
copyBuilder.argumentMapping = original.argumentMapping
copyBuilder.annotationResolvePhase = original.annotationResolvePhase
return copyBuilder.apply(init).build()
}
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.fir.builder.FirBuilderDsl
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.FirAnnotationArgumentMapping
import org.jetbrains.kotlin.fir.expressions.FirAnnotationResolvePhase
import org.jetbrains.kotlin.fir.expressions.FirArgumentList
import org.jetbrains.kotlin.fir.expressions.FirEmptyArgumentList
import org.jetbrains.kotlin.fir.expressions.FirErrorAnnotationCall
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.FirAnnotationArgumentMapping
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.FirAnnotationResolvePhase
import org.jetbrains.kotlin.fir.expressions.FirArgumentList
import org.jetbrains.kotlin.fir.references.FirReference
import org.jetbrains.kotlin.fir.types.FirTypeProjection
@@ -31,6 +32,7 @@ internal class FirAnnotationCallImpl(
override var argumentList: FirArgumentList,
override var calleeReference: FirReference,
override var argumentMapping: FirAnnotationArgumentMapping,
override var annotationResolvePhase: FirAnnotationResolvePhase,
) : FirAnnotationCall() {
override val typeRef: FirTypeRef get() = annotationTypeRef
override val annotations: List<FirAnnotation> get() = emptyList()
@@ -71,6 +73,10 @@ internal class FirAnnotationCallImpl(
override fun replaceTypeRef(newTypeRef: FirTypeRef) {}
override fun replaceAnnotationTypeRef(newAnnotationTypeRef: FirTypeRef) {
annotationTypeRef = newAnnotationTypeRef
}
override fun replaceTypeArguments(newTypeArguments: List<FirTypeProjection>) {
typeArguments.clear()
typeArguments.addAll(newTypeArguments)
@@ -87,4 +93,8 @@ internal class FirAnnotationCallImpl(
override fun replaceArgumentMapping(newArgumentMapping: FirAnnotationArgumentMapping) {
argumentMapping = newArgumentMapping
}
override fun replaceAnnotationResolvePhase(newAnnotationResolvePhase: FirAnnotationResolvePhase) {
annotationResolvePhase = newAnnotationResolvePhase
}
}
@@ -59,6 +59,10 @@ internal class FirAnnotationImpl(
override fun replaceTypeRef(newTypeRef: FirTypeRef) {}
override fun replaceAnnotationTypeRef(newAnnotationTypeRef: FirTypeRef) {
annotationTypeRef = newAnnotationTypeRef
}
override fun replaceArgumentMapping(newArgumentMapping: FirAnnotationArgumentMapping) {
argumentMapping = newArgumentMapping
}
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.FirAnnotationArgumentMapping
import org.jetbrains.kotlin.fir.expressions.FirAnnotationResolvePhase
import org.jetbrains.kotlin.fir.expressions.FirArgumentList
import org.jetbrains.kotlin.fir.expressions.FirErrorAnnotationCall
import org.jetbrains.kotlin.fir.references.FirReference
@@ -36,6 +37,7 @@ internal class FirErrorAnnotationCallImpl(
) : FirErrorAnnotationCall() {
override val typeRef: FirTypeRef get() = annotationTypeRef
override val annotations: List<FirAnnotation> get() = emptyList()
override var annotationResolvePhase: FirAnnotationResolvePhase = FirAnnotationResolvePhase.Types
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
annotationTypeRef.accept(visitor, data)
@@ -73,6 +75,10 @@ internal class FirErrorAnnotationCallImpl(
override fun replaceTypeRef(newTypeRef: FirTypeRef) {}
override fun replaceAnnotationTypeRef(newAnnotationTypeRef: FirTypeRef) {
annotationTypeRef = newAnnotationTypeRef
}
override fun replaceTypeArguments(newTypeArguments: List<FirTypeProjection>) {
typeArguments.clear()
typeArguments.addAll(newTypeArguments)
@@ -86,6 +92,10 @@ internal class FirErrorAnnotationCallImpl(
calleeReference = newCalleeReference
}
override fun replaceAnnotationResolvePhase(newAnnotationResolvePhase: FirAnnotationResolvePhase) {
annotationResolvePhase = newAnnotationResolvePhase
}
override fun replaceArgumentMapping(newArgumentMapping: FirAnnotationArgumentMapping) {
argumentMapping = newArgumentMapping
}
@@ -5,8 +5,8 @@
package org.jetbrains.kotlin.fir.expressions
enum class FirAnnotationResolveStatus {
enum class FirAnnotationResolvePhase {
Unresolved,
PartiallyResolved, // only literals, annotations, class literals and enums
Resolved
}
CompilerRequiredAnnotations,
Types
}
@@ -6,12 +6,11 @@
package org.jetbrains.kotlin.fir.extensions.predicate
import org.jetbrains.kotlin.fir.extensions.AnnotationFqn
import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled
sealed class LookupPredicate : AbstractPredicate<LookupPredicate> {
abstract override val annotations: Set<AnnotationFqn>
final override val metaAnnotations: Set<AnnotationFqn>
get() = shouldNotBeCalled()
get() = emptySet()
abstract override fun <R, D> accept(visitor: PredicateVisitor<LookupPredicate, R, D>, data: D): R
@@ -48,10 +48,19 @@ abstract class FirBasedSymbol<E : FirDeclaration> {
val resolvedAnnotationsWithClassIds: List<FirAnnotation>
get() = fir.resolvedAnnotationsWithClassIds(this)
val resolvedCompilerAnnotationsWithClassIds: List<FirAnnotation>
get() = fir.resolvedCompilerRequiredAnnotations(this)
val resolvedAnnotationClassIds: List<ClassId>
get() = fir.resolvedAnnotationClassIds(this)
}
@SymbolInternals
fun FirAnnotationContainer.resolvedCompilerRequiredAnnotations(anchorElement: FirBasedSymbol<*>): List<FirAnnotation> {
anchorElement.lazyResolveToPhase(FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS)
return annotations
}
@SymbolInternals
fun FirAnnotationContainer.resolvedAnnotationsWithArguments(anchorElement: FirBasedSymbol<*>): List<FirAnnotation> {
anchorElement.lazyResolveToPhase(FirResolvePhase.ANNOTATIONS_ARGUMENTS_MAPPING)
@@ -129,6 +129,7 @@ object BuilderConfigurator : AbstractBuilderConfigurator<FirTreeBuilder>(FirTree
}
default("argumentMapping", "FirEmptyAnnotationArgumentMapping")
default("annotationTypeRef", "FirImplicitTypeRefImpl(null)")
default("annotationResolvePhase", "FirAnnotationResolvePhase.Unresolved")
useTypes(emptyArgumentListType, emptyAnnotationArgumentMappingType, implicitTypeRefType)
withCopy()
}
@@ -101,6 +101,9 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
default("argumentMapping") {
needAcceptAndTransform = false
}
default("annotationResolvePhase") {
value = "FirAnnotationResolvePhase.Types"
}
}
impl(arrayOfCall)
@@ -487,13 +487,14 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
annotation.configure {
+field("useSiteTarget", annotationUseSiteTargetType, nullable = true)
+field("annotationTypeRef", typeRef).withTransform()
+field("annotationTypeRef", typeRef, withReplace = true).withTransform()
+field("argumentMapping", annotationArgumentMapping, withReplace = true)
+typeArguments.withTransform()
}
annotationCall.configure {
+field("argumentMapping", annotationArgumentMapping, withReplace = true)
+field("annotationResolvePhase", annotationResolvePhaseType, withReplace = true)
}
errorAnnotationCall.configure {
@@ -15,7 +15,6 @@ import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.fir.tree.generator.context.generatedType
import org.jetbrains.kotlin.fir.tree.generator.context.type
import org.jetbrains.kotlin.fir.types.ConeErrorType
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.ConeSimpleKotlinType
import org.jetbrains.kotlin.name.ClassId
@@ -102,3 +101,4 @@ val emptyAnnotationArgumentMappingType = type("fir.expressions.impl", "FirEmptyA
val firPropertySymbolType = type("fir.symbols.impl", "FirPropertySymbol")
val errorTypeRefImplType = type("fir.types.impl", "FirErrorTypeRefImpl", firType = true)
val annotationResolvePhaseType = generatedType("expressions", "FirAnnotationResolvePhase")
@@ -31,3 +31,5 @@ enum class Visibility {
}
annotation class SupertypeWithTypeArgument(val kClass: KClass<*>)
annotation class MetaSupertype
@@ -5,8 +5,13 @@
package org.jetbrains.kotlin.fir.plugin
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.utils.classId
import org.jetbrains.kotlin.fir.declarations.utils.isEnumClass
import org.jetbrains.kotlin.fir.extensions.FirDeclarationPredicateRegistrar
import org.jetbrains.kotlin.fir.extensions.FirSupertypeGenerationExtension
import org.jetbrains.kotlin.fir.extensions.predicate.DeclarationPredicate
@@ -20,13 +25,14 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
/*
* Adds MyInterface supertype for all classes annotated with @MyInterfaceSupertype
* Adds MyInterface supertype for all classes annotated with @MyInterfaceSupertype or meta-annotated with MetaSupertype
*/
class SomeAdditionalSupertypeGenerator(session: FirSession) : FirSupertypeGenerationExtension(session) {
companion object {
private val myInterfaceClassId = ClassId(FqName("foo"), Name.identifier("MyInterface"))
private val PREDICATE = DeclarationPredicate.create { annotated("MyInterfaceSupertype".fqn()) }
private val PREDICATE = DeclarationPredicate.create {
annotated("MyInterfaceSupertype".fqn()) or metaAnnotated("MetaSupertype".fqn())
}
}
context(TypeResolveServiceContainer)
@@ -35,6 +41,16 @@ class SomeAdditionalSupertypeGenerator(session: FirSession) : FirSupertypeGenera
classLikeDeclaration: FirClassLikeDeclaration,
resolvedSupertypes: List<FirResolvedTypeRef>
): List<FirResolvedTypeRef> {
if (classLikeDeclaration !is FirRegularClass) return emptyList()
when (classLikeDeclaration.classKind) {
ClassKind.CLASS,
ClassKind.INTERFACE,
ClassKind.OBJECT-> {}
ClassKind.ENUM_CLASS,
ClassKind.ENUM_ENTRY,
ClassKind.ANNOTATION_CLASS -> return emptyList()
}
if (resolvedSupertypes.any { it.type.classId == myInterfaceClassId }) return emptyList()
return listOf(
buildResolvedTypeRef {
@@ -0,0 +1,77 @@
Module: lib
FILE: module_lib_metaAnnotationFromLibrary.kt
@R|org/jetbrains/kotlin/fir/plugin/AllOpen|() public open annotation class Open1 : R|kotlin/Annotation| {
public constructor(): R|Open1| {
super<R|kotlin/Any|>()
}
}
@R|Open1|() public open annotation class Open2 : R|kotlin/Annotation| {
public constructor(): R|Open2| {
super<R|kotlin/Any|>()
}
}
@R|Open2|() public open annotation class Open3 : R|kotlin/Annotation| {
public constructor(): R|Open3| {
super<R|kotlin/Any|>()
}
}
Module: main
FILE: module_main_metaAnnotationFromLibrary.kt
@R|org/jetbrains/kotlin/fir/plugin/AllOpen|() public open class Zero : R|kotlin/Any| {
public constructor(): R|Zero| {
super<R|kotlin/Any|>()
}
}
@R|Open1|() public open class First : R|kotlin/Any| {
public constructor(): R|First| {
super<R|kotlin/Any|>()
}
}
@R|Open2|() public open class Second : R|kotlin/Any| {
public constructor(): R|Second| {
super<R|kotlin/Any|>()
}
}
@R|Open3|() public open class Third : R|kotlin/Any| {
public constructor(): R|Third| {
super<R|kotlin/Any|>()
}
}
public final fun box(): R|kotlin/String| {
lval a: R|<anonymous>| = object : R|Zero| {
private constructor(): R|<anonymous>| {
super<R|Zero|>()
}
}
lval b: R|<anonymous>| = object : R|First| {
private constructor(): R|<anonymous>| {
super<R|First|>()
}
}
lval c: R|<anonymous>| = object : R|Second| {
private constructor(): R|<anonymous>| {
super<R|Second|>()
}
}
lval d: R|<anonymous>| = object : R|Third| {
private constructor(): R|<anonymous>| {
super<R|Third|>()
}
}
^box String(OK)
}
@@ -0,0 +1,35 @@
// MODULE: lib
import org.jetbrains.kotlin.fir.plugin.AllOpen
@AllOpen
annotation class Open1
@Open1
annotation class Open2
@Open2
annotation class Open3
// MODULE: main(lib)
import org.jetbrains.kotlin.fir.plugin.AllOpen
@AllOpen
class Zero
@Open1
class First
@Open2
class Second
@Open3
class Third
fun box(): String {
val a = object : Zero() {}
val b = object : First() {}
val c = object : Second() {}
val d = object : Third() {}
return "OK"
}
@@ -0,0 +1,56 @@
FILE: metaAnnotationClashesWithSupertype.kt
@R|org/jetbrains/kotlin/fir/plugin/AllOpen|() public open annotation class Open : R|kotlin/Annotation| {
public constructor(): R|Open| {
super<R|kotlin/Any|>()
}
}
public final annotation class Ann : R|kotlin/Annotation| {
public constructor(): R|Ann| {
super<R|kotlin/Any|>()
}
}
public open class Base : R|kotlin/Any| {
public constructor(): R|Base| {
super<R|kotlin/Any|>()
}
public final annotation class Open : R|kotlin/Annotation| {
public constructor(): R|Base.Open| {
super<R|kotlin/Any|>()
}
}
public final annotation class Ann : R|kotlin/Annotation| {
public constructor(): R|Base.Ann| {
super<R|kotlin/Any|>()
}
}
}
public final class Derived : R|Base| {
public constructor(): R|Derived| {
super<R|Base|>()
}
@<ERROR TYPE REF:
Annotation type resolved differently on compiler annotation and types stages:
- compiler annotations: Open
- types stage: Base.Open
>() @R|Base.Ann|() public open class ShouldBeFinal : R|kotlin/Any| {
public constructor(): R|Derived.ShouldBeFinal| {
super<R|kotlin/Any|>()
}
}
}
public final class ShouldBeAnError : R|Derived.ShouldBeFinal| {
public constructor(): R|ShouldBeAnError| {
super<R|Derived.ShouldBeFinal|>()
}
}
@@ -0,0 +1,19 @@
import org.jetbrains.kotlin.fir.plugin.AllOpen
@AllOpen
annotation class Open
annotation class Ann
open class Base {
annotation class Open
annotation class Ann
}
class Derived : Base() {
@<!PLUGIN_ANNOTATION_AMBIGUITY!>Open<!> // should be an error
@Ann // should be ok
class ShouldBeFinal
}
class ShouldBeAnError : Derived.ShouldBeFinal()
@@ -0,0 +1,59 @@
FILE: main.kt
package foo
public abstract interface MyInterface : R|kotlin/Any| {
public open fun foo(): R|kotlin/Unit| {
}
}
@R|AddSupertype2|() public final class Second : R|kotlin/Any|, R|foo/MyInterface| {
public constructor(): R|foo/Second| {
super<R|kotlin/Any|>()
}
}
@R|AddSupertype3|() public final class Third : R|kotlin/Any|, R|foo/MyInterface| {
public constructor(): R|foo/Third| {
super<R|kotlin/Any|>()
}
}
@R|AddSupertype1|() public final class First : R|kotlin/Any|, R|foo/MyInterface| {
public constructor(): R|foo/First| {
super<R|kotlin/Any|>()
}
}
@R|org/jetbrains/kotlin/fir/plugin/MetaSupertype|() public final class Zero : R|kotlin/Any|, R|foo/MyInterface| {
public constructor(): R|foo/Zero| {
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| {
R|<local>/a|.R|foo/MyInterface.foo|()
R|<local>/b|.R|foo/MyInterface.foo|()
R|<local>/c|.R|foo/MyInterface.foo|()
R|<local>/d|.R|foo/MyInterface.foo|()
}
FILE: ann3.kt
@R|AddSupertype2|() public final annotation class AddSupertype3 : R|kotlin/Annotation| {
public constructor(): R|AddSupertype3| {
super<R|kotlin/Any|>()
}
}
FILE: ann2.kt
@R|AddSupertype1|() public final annotation class AddSupertype2 : R|kotlin/Annotation| {
public constructor(): R|AddSupertype2| {
super<R|kotlin/Any|>()
}
}
FILE: ann1.kt
@R|org/jetbrains/kotlin/fir/plugin/MetaSupertype|() public final annotation class AddSupertype1 : R|kotlin/Annotation| {
public constructor(): R|AddSupertype1| {
super<R|kotlin/Any|>()
}
}
@@ -0,0 +1,41 @@
// FILE: main.kt
package foo
import org.jetbrains.kotlin.fir.plugin.MetaSupertype
interface MyInterface {
fun foo() {}
}
@AddSupertype2
class Second
@AddSupertype3
class Third
@AddSupertype1
class First
@MetaSupertype
class Zero
fun test(a: Zero, b: First, c: Second, d: Third) {
a.foo()
b.foo()
c.foo()
d.foo()
}
// FILE: ann3.kt
@AddSupertype2
annotation class AddSupertype3
// FILE: ann2.kt
@AddSupertype1
annotation class AddSupertype2
// FILE: ann1.kt
import org.jetbrains.kotlin.fir.plugin.MetaSupertype
@MetaSupertype
annotation class AddSupertype1
@@ -43,6 +43,12 @@ public class FirPluginBlackBoxCodegenTestGenerated extends AbstractFirPluginBlac
runTest("plugins/fir-plugin-prototype/testData/box/generatedClassWithMembersAndNestedClasses.kt");
}
@Test
@TestMetadata("metaAnnotationFromLibrary.kt")
public void testMetaAnnotationFromLibrary() throws Exception {
runTest("plugins/fir-plugin-prototype/testData/box/metaAnnotationFromLibrary.kt");
}
@Test
@TestMetadata("newSupertype.kt")
public void testNewSupertype() throws Exception {
@@ -111,6 +111,12 @@ public class FirPluginDiagnosticTestGenerated extends AbstractFirPluginDiagnosti
runTest("plugins/fir-plugin-prototype/testData/diagnostics/status/metaAnnotation.kt");
}
@Test
@TestMetadata("metaAnnotationClashesWithSupertype.kt")
public void testMetaAnnotationClashesWithSupertype() throws Exception {
runTest("plugins/fir-plugin-prototype/testData/diagnostics/status/metaAnnotationClashesWithSupertype.kt");
}
@Test
@TestMetadata("simpleAnnotation.kt")
public void testSimpleAnnotation() throws Exception {
@@ -133,6 +139,12 @@ public class FirPluginDiagnosticTestGenerated extends AbstractFirPluginDiagnosti
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/fir-plugin-prototype/testData/diagnostics/supertypes"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@Test
@TestMetadata("metaAnnotationOrder.kt")
public void testMetaAnnotationOrder() throws Exception {
runTest("plugins/fir-plugin-prototype/testData/diagnostics/supertypes/metaAnnotationOrder.kt");
}
@Test
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
@@ -1,21 +0,0 @@
// WITH_STDLIB
// SKIP_TXT
import kotlinx.serialization.*
@MetaSerializable
annotation class TopLevel
class MetaSerializableNestedTest {
<!META_SERIALIZABLE_NOT_APPLICABLE!>@MetaSerializable<!>
@Target(AnnotationTarget.PROPERTY, AnnotationTarget.CLASS)
annotation class JsonComment(val comment: String)
object Nested2 {
<!META_SERIALIZABLE_NOT_APPLICABLE!>@MetaSerializable<!>
annotation class Nested3
}
@<!UNRESOLVED_REFERENCE!>JsonComment<!>("class_comment")
data class IntDataCommented(val i: Int)
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// WITH_STDLIB
// SKIP_TXT