[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()) {
|
||||
|
||||
+5
@@ -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)
|
||||
|
||||
+7
@@ -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(
|
||||
|
||||
+3
@@ -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}")
|
||||
}
|
||||
|
||||
|
||||
+30
-14
@@ -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) }
|
||||
}
|
||||
|
||||
+82
-6
@@ -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()
|
||||
|
||||
+70
@@ -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
|
||||
}
|
||||
}
|
||||
+9
-47
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
+39
-3
@@ -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 {
|
||||
|
||||
+1
@@ -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)
|
||||
|
||||
+286
@@ -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
|
||||
}
|
||||
}
|
||||
-134
@@ -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?) {}
|
||||
}
|
||||
+83
-126
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
+13
-1
@@ -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
|
||||
|
||||
+4
@@ -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()
|
||||
}
|
||||
|
||||
+1
@@ -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
|
||||
|
||||
+10
@@ -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
|
||||
}
|
||||
|
||||
+10
@@ -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
|
||||
}
|
||||
|
||||
+4
-4
@@ -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
|
||||
}
|
||||
+1
-2
@@ -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)
|
||||
|
||||
+1
@@ -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()
|
||||
}
|
||||
|
||||
+3
@@ -101,6 +101,9 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
||||
default("argumentMapping") {
|
||||
needAcceptAndTransform = false
|
||||
}
|
||||
default("annotationResolvePhase") {
|
||||
value = "FirAnnotationResolvePhase.Types"
|
||||
}
|
||||
}
|
||||
|
||||
impl(arrayOfCall)
|
||||
|
||||
+2
-1
@@ -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 {
|
||||
|
||||
+1
-1
@@ -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")
|
||||
|
||||
+2
@@ -31,3 +31,5 @@ enum class Visibility {
|
||||
}
|
||||
|
||||
annotation class SupertypeWithTypeArgument(val kClass: KClass<*>)
|
||||
|
||||
annotation class MetaSupertype
|
||||
|
||||
+19
-3
@@ -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"
|
||||
}
|
||||
Vendored
+56
@@ -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|>()
|
||||
}
|
||||
|
||||
}
|
||||
Vendored
+19
@@ -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()
|
||||
+59
@@ -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|>()
|
||||
}
|
||||
|
||||
}
|
||||
+41
@@ -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
|
||||
+6
@@ -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 {
|
||||
|
||||
+12
@@ -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 {
|
||||
|
||||
-21
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user