[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:
committed by
Space Team
parent
6a9b525ca0
commit
6864433581
+8
@@ -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,
|
||||
|
||||
+6
@@ -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
|
||||
|
||||
+7
@@ -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,
|
||||
|
||||
+2
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-21
@@ -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)
|
||||
|
||||
+18
-2
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -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()) {
|
||||
|
||||
Reference in New Issue
Block a user