diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt index 51f36fe7f62..75aee78eec0 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -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, diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt index 21cc7f95668..197c8a36ec0 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt @@ -697,6 +697,12 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = AnnotationInWhereClauseError::class } + abstract class PluginAnnotationAmbiguity : KtFirDiagnostic() { + override val diagnosticClass get() = PluginAnnotationAmbiguity::class + abstract val typeFromCompilerPhase: KtType + abstract val typeFromTypesPhase: KtType + } + abstract class OptInUsage : KtFirDiagnostic() { override val diagnosticClass get() = OptInUsage::class abstract val optInMarkerFqName: FqName diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index 4ac58ca865b..15fa267542b 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -837,6 +837,13 @@ internal class AnnotationInWhereClauseErrorImpl( override val token: KtLifetimeToken, ) : KtFirDiagnostic.AnnotationInWhereClauseError(), KtAbstractFirDiagnostic +internal class PluginAnnotationAmbiguityImpl( + override val typeFromCompilerPhase: KtType, + override val typeFromTypesPhase: KtType, + override val firDiagnostic: KtPsiDiagnostic, + override val token: KtLifetimeToken, +) : KtFirDiagnostic.PluginAnnotationAmbiguity(), KtAbstractFirDiagnostic + internal class OptInUsageImpl( override val optInMarkerFqName: FqName, override val message: String, diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/LLFirNonUnderContentRootSessionFactory.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/LLFirNonUnderContentRootSessionFactory.kt index f6267fc4138..6af8a222e6c 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/LLFirNonUnderContentRootSessionFactory.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/LLFirNonUnderContentRootSessionFactory.kt @@ -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) } } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirIdePredicateBasedProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirIdePredicateBasedProvider.kt index ef2a5adfeb1..e48a0ffbc2e 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirIdePredicateBasedProvider.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirIdePredicateBasedProvider.kt @@ -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

, data: FirDeclaration): Boolean { - val visited = mutableSetOf() return data.annotations.any { annotation -> - annotation.markedWithMetaAnnotation(predicate.metaAnnotations, visited) + annotation.markedWithMetaAnnotation(session, data, predicate.metaAnnotations) } } - private fun FirAnnotation.markedWithMetaAnnotation( - metaAnnotations: Set, - visited: MutableSet - ): 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

, data: FirDeclaration): Boolean { val parent = data.directParentDeclaration ?: return false val parentPredicate = DeclarationPredicate.AnnotatedWith(predicate.annotations) diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirIdeRegisteredPluginAnnotations.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirIdeRegisteredPluginAnnotations.kt index c8cfee4d644..5b19cf4d4cd 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirIdeRegisteredPluginAnnotations.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirIdeRegisteredPluginAnnotations.kt @@ -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, 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, Nothing?> = session.firCachesFactory.createCache { metaAnnotation -> collectAnnotationsWithMetaAnnotation(metaAnnotation) } + override fun getAnnotationsWithMetaAnnotation(metaAnnotation: AnnotationFqn): Collection { + return annotationsWithMetaAnnotationCache.getValue(metaAnnotation) + } + private fun collectAnnotationsWithMetaAnnotation(metaAnnotation: AnnotationFqn): Set { val annotatedDeclarations = annotationsResolver.declarationsByAnnotation(ClassId.topLevel(metaAnnotation)) @@ -47,4 +59,8 @@ internal class LLFirIdeRegisteredPluginAnnotations( override fun saveAnnotationsFromPlugin(annotations: Collection) { annotationsFromPlugins += annotations } + + override fun registerUserDefinedAnnotation(metaAnnotation: AnnotationFqn, annotationClasses: Collection) { + error("This method should never be called in IDE mode") + } } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedAnnotationsResolveTransformed.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedAnnotationsResolveTransformed.kt index d8042905bfc..63fb15ea4f8 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedAnnotationsResolveTransformed.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirDesignatedAnnotationsResolveTransformed.kt @@ -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) { if (!designationIterator.hasNext()) { diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index 88a79151836..82e1da9212a 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -293,6 +293,11 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { val WRONG_EXTENSION_FUNCTION_TYPE by error() val WRONG_EXTENSION_FUNCTION_TYPE_WARNING by warning() val ANNOTATION_IN_WHERE_CLAUSE_ERROR by error() + + val PLUGIN_ANNOTATION_AMBIGUITY by error() { + parameter("typeFromCompilerPhase") + parameter("typeFromTypesPhase") + } } val OPT_IN by object : DiagnosticGroup("OptIn") { diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index 57dde324ba9..1c33c40c00f 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -258,6 +258,7 @@ object FirErrors { val WRONG_EXTENSION_FUNCTION_TYPE by error0() val WRONG_EXTENSION_FUNCTION_TYPE_WARNING by warning0() val ANNOTATION_IN_WHERE_CLAUSE_ERROR by error0() + val PLUGIN_ANNOTATION_AMBIGUITY by error2() // OptIn val OPT_IN_USAGE by warning2(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt index ef41f20f623..5218940ac28 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt @@ -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( diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt index dec024f3d13..a665b8f0fa2 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt @@ -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}") } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirPredicateBasedProviderImpl.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirPredicateBasedProviderImpl.kt index 268bfc6f3b0..5c080182d9d 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirPredicateBasedProviderImpl.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirPredicateBasedProviderImpl.kt @@ -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

, data: FirDeclaration): Boolean { - val visited = mutableSetOf() return data.annotations.any { annotation -> - annotation.markedWithMetaAnnotation(predicate.metaAnnotations, visited) + annotation.markedWithMetaAnnotation(session, data, predicate.metaAnnotations) } } - private fun FirAnnotation.markedWithMetaAnnotation( - metaAnnotations: Set, - visited: MutableSet - ): 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): Boolean { @@ -188,3 +180,27 @@ class FirPredicateBasedProviderImpl(private val session: FirSession) : FirPredic val filesWithPluginAnnotations: MutableSet = mutableSetOf() } } + +fun FirAnnotation.markedWithMetaAnnotation( + session: FirSession, + containingDeclaration: FirDeclaration, + metaAnnotations: Set +): Boolean { + containingDeclaration.symbol.lazyResolveToPhase(FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS) + return annotationTypeRef.coneTypeSafe() + ?.toRegularClassSymbol(session) + .markedWithMetaAnnotationImpl(session, metaAnnotations, mutableSetOf()) +} + +fun FirRegularClassSymbol?.markedWithMetaAnnotationImpl( + session: FirSession, + metaAnnotations: Set, + visited: MutableSet +): 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()?.toRegularClassSymbol(session) } + .any { it.markedWithMetaAnnotationImpl(session, metaAnnotations, visited) } +} diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirRegisteredPluginAnnotations.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirRegisteredPluginAnnotations.kt index 4719bdb9d8b..49c82ff1063 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirRegisteredPluginAnnotations.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/extensions/FirRegisteredPluginAnnotations.kt @@ -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 + /** + * Contains meta-annotations that can be targeted by the plugins. + */ + abstract val metaAnnotations: Set + val hasRegisteredAnnotations: Boolean - get() = annotations.isNotEmpty() + get() = annotations.isNotEmpty() || metaAnnotations.isNotEmpty() + + abstract fun getAnnotationsWithMetaAnnotation(metaAnnotation: AnnotationFqn): Collection + + abstract fun registerUserDefinedAnnotation(metaAnnotation: AnnotationFqn, annotationClasses: Collection) + + abstract fun getAnnotationsForPredicate(predicate: DeclarationPredicate): Set @PluginServicesInitialization abstract fun initialize() + + object Empty : FirRegisteredPluginAnnotations() { + override val annotations: Set + get() = emptySet() + override val metaAnnotations: Set + get() = emptySet() + + override fun getAnnotationsWithMetaAnnotation(metaAnnotation: AnnotationFqn): Collection { + return emptyList() + } + + override fun registerUserDefinedAnnotation(metaAnnotation: AnnotationFqn, annotationClasses: Collection) { + shouldNotBeCalled() + } + + override fun getAnnotationsForPredicate(predicate: DeclarationPredicate): Set { + 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 = mutableSetOf() + + private val annotationsForPredicateCache: FirCache, Nothing?> = + session.firCachesFactory.createCache { predicate -> + collectAnnotations(predicate) + } + + final override fun getAnnotationsForPredicate(predicate: DeclarationPredicate): Set { + return annotationsForPredicateCache.getValue(predicate) + } + + private fun collectAnnotations(predicate: DeclarationPredicate): Set { + 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>() - 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 = mutableSetOf() + // MetaAnnotation -> Annotations + private val userDefinedAnnotations: Multimap = LinkedHashMultimap.create() + + override fun getAnnotationsWithMetaAnnotation(metaAnnotation: AnnotationFqn): Collection { + return userDefinedAnnotations[metaAnnotation] + } + override fun saveAnnotationsFromPlugin(annotations: Collection) { this.annotations += annotations } + + override fun registerUserDefinedAnnotation(metaAnnotation: AnnotationFqn, annotationClasses: Collection) { + 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() diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/DesignationState.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/DesignationState.kt new file mode 100644 index 00000000000..cbf84bbc73b --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/DesignationState.kt @@ -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, + val targetClass: FirClassLikeDeclaration +) { + companion object { + fun create( + symbol: FirRegularClassSymbol, + designationMapForLocalClasses: Map, + 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 { + 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 + } +} diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolveTransformer.kt index 1170308b284..70843af454f 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolveTransformer.kt @@ -126,8 +126,7 @@ open class FirStatusResolveTransformer( open class FirDesignatedStatusResolveTransformer( session: FirSession, scopeSession: ScopeSession, - private val designation: Iterator, - private val targetClass: FirClassLikeDeclaration, + private val designation: DesignationState, statusComputationSession: StatusComputationSession, designationMapForLocalClasses: Map, 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 { - 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) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt index 3e3b0b2af18..a55ac7d9eba 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt @@ -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 withScopeCleanup(crossinline l: () -> T): T { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt index c76440c86aa..16d7ad0c0b7 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt @@ -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) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/AbstractFirSpecificAnnotationResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/AbstractFirSpecificAnnotationResolveTransformer.kt new file mode 100644 index 00000000000..09a77db7f7c --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/AbstractFirSpecificAnnotationResolveTransformer.kt @@ -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() { + companion object { + private val REQUIRED_ANNOTATIONS: Set = setOf(Deprecated, DeprecatedSinceKotlin, WasExperimental, JvmRecord) + + private val REQUIRED_ANNOTATION_NAMES: Set = REQUIRED_ANNOTATIONS.mapTo(mutableSetOf()) { it.shortClassName } + } + + private val predicateBasedProvider = session.predicateBasedProvider + + private val annotationsFromPlugins: Set = session.registeredPluginAnnotations.annotations + private val metaAnnotationsFromPlugins: Set = 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 = persistentListOf() + private val classDeclarationsStack = ArrayDeque() + + @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()?.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): 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 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 + + inline fun 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 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 { + 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?) { + requireNotNull(state) + owners = state + } +} diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/FirAbstractAnnotationResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/FirAbstractAnnotationResolveTransformer.kt deleted file mode 100644 index 725e3ff345b..00000000000 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/FirAbstractAnnotationResolveTransformer.kt +++ /dev/null @@ -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( - protected val session: FirSession, - protected val scopeSession: ScopeSession -) : FirDefaultTransformer() { - abstract override fun transformAnnotation(annotation: FirAnnotation, data: D): FirStatement - - protected lateinit var scopes: List - - inline fun 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 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?) {} -} diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/FirCompilerRequiredAnnotationsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/FirCompilerRequiredAnnotationsResolveTransformer.kt index 035290561e2..f789c6f31e9 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/FirCompilerRequiredAnnotationsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/FirCompilerRequiredAnnotationsResolveTransformer.kt @@ -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) { - 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(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 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) { - val acceptableNames = annotations - importTransformer.acceptableFqNames = acceptableNames + private fun FirFile.resolveAnnotations() { this.transformImports(importTransformer, null) - - annotationTransformer.acceptableFqNames = acceptableNames this.transform(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() + + 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() + + 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 = emptySet() + private val acceptableFqNames: Set = 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>(session, scopeSession) { - companion object { - private val REQUIRED_ANNOTATIONS: Set = setOf( - Deprecated, DeprecatedSinceKotlin, WasExperimental, JvmRecord - ) - - private val REQUIRED_ANNOTATION_NAMES: Set = REQUIRED_ANNOTATIONS.mapTo(mutableSetOf()) { it.shortClassName } - } - - private val predicateBasedProvider = session.predicateBasedProvider - - var acceptableFqNames: Set = emptySet() - - private val typeResolverTransformer: FirSpecificTypeResolverTransformer = FirSpecificTypeResolverTransformer( - session, - errorTypeAsResolved = false - ) - - private val argumentsTransformer = FirAnnotationArgumentsResolveTransformer(session, scopeSession, COMPILER_REQUIRED_ANNOTATIONS) - - private var owners: PersistentList = persistentListOf() - private val classDeclarationsStack = ArrayDeque() - - override fun beforeTransformingChildren(parentDeclaration: FirDeclaration): PersistentList { - val current = owners - owners = owners.add(parentDeclaration) - return current - } - - override fun afterTransformingChildren(state: PersistentList?) { - 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()?.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 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) } } diff --git a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/diagnostics/ConeDiagnostics.kt b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/diagnostics/ConeDiagnostics.kt index 008559028d6..c5eda0609a9 100644 --- a/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/diagnostics/ConeDiagnostics.kt +++ b/compiler/fir/semantics/src/org/jetbrains/kotlin/fir/resolve/diagnostics/ConeDiagnostics.kt @@ -242,4 +242,16 @@ class ConeAmbiguousAlteredAssign(val altererNames: List) : ConeDiagnost object ConeForbiddenIntersection : ConeDiagnostic { override val reason: String get() = "Such an intersection type is not allowed" -} \ No newline at end of file +} + +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 + """ +} diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/FirAnnotation.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/FirAnnotation.kt index 7a8dec0bd8e..cc279789d95 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/FirAnnotation.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/FirAnnotation.kt @@ -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) diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/FirAnnotationCall.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/FirAnnotationCall.kt index 744019f2cf0..75773e1ad56 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/FirAnnotationCall.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/FirAnnotationCall.kt @@ -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 accept(visitor: FirVisitor, 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) 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 transformAnnotations(transformer: FirTransformer, data: D): FirAnnotationCall abstract override fun transformAnnotationTypeRef(transformer: FirTransformer, data: D): FirAnnotationCall diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/FirErrorAnnotationCall.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/FirErrorAnnotationCall.kt index 6692e22ef97..7c798be350e 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/FirErrorAnnotationCall.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/FirErrorAnnotationCall.kt @@ -29,6 +29,7 @@ abstract class FirErrorAnnotationCall : FirAnnotationCall(), FirDiagnosticHolder abstract override val typeArguments: List 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) 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 transformAnnotations(transformer: FirTransformer, data: D): FirErrorAnnotationCall diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/builder/FirAnnotationCallBuilder.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/builder/FirAnnotationCallBuilder.kt index 6f71cc1767c..9e7ec0bc2b4 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/builder/FirAnnotationCallBuilder.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/builder/FirAnnotationCallBuilder.kt @@ -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() } diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/builder/FirErrorAnnotationCallBuilder.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/builder/FirErrorAnnotationCallBuilder.kt index b631c57f887..b1a9abf5b98 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/builder/FirErrorAnnotationCallBuilder.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/builder/FirErrorAnnotationCallBuilder.kt @@ -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 diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/impl/FirAnnotationCallImpl.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/impl/FirAnnotationCallImpl.kt index 49ccf51ffd5..558757e4fb3 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/impl/FirAnnotationCallImpl.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/impl/FirAnnotationCallImpl.kt @@ -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 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) { 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 + } } diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/impl/FirAnnotationImpl.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/impl/FirAnnotationImpl.kt index f4412cca79b..49128cdf2dc 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/impl/FirAnnotationImpl.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/impl/FirAnnotationImpl.kt @@ -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 } diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/impl/FirErrorAnnotationCallImpl.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/impl/FirErrorAnnotationCallImpl.kt index f7294a31781..7fe553b5561 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/impl/FirErrorAnnotationCallImpl.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/impl/FirErrorAnnotationCallImpl.kt @@ -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 get() = emptyList() + override var annotationResolvePhase: FirAnnotationResolvePhase = FirAnnotationResolvePhase.Types override fun acceptChildren(visitor: FirVisitor, 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) { 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 } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/FirAnnotationResolveStatus.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/FirAnnotationResolvePhase.kt similarity index 67% rename from compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/FirAnnotationResolveStatus.kt rename to compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/FirAnnotationResolvePhase.kt index f5aa757d9f6..b7019dd1a6d 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/FirAnnotationResolveStatus.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/FirAnnotationResolvePhase.kt @@ -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 -} \ No newline at end of file + CompilerRequiredAnnotations, + Types +} diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/extensions/predicate/LookupPredicate.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/extensions/predicate/LookupPredicate.kt index 3bd6fed7256..4d9747f4283 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/extensions/predicate/LookupPredicate.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/extensions/predicate/LookupPredicate.kt @@ -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 { abstract override val annotations: Set final override val metaAnnotations: Set - get() = shouldNotBeCalled() + get() = emptySet() abstract override fun accept(visitor: PredicateVisitor, data: D): R diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/FirBasedSymbol.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/FirBasedSymbol.kt index 5e3c7a54f44..4d79a57f69a 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/FirBasedSymbol.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/FirBasedSymbol.kt @@ -48,10 +48,19 @@ abstract class FirBasedSymbol { val resolvedAnnotationsWithClassIds: List get() = fir.resolvedAnnotationsWithClassIds(this) + val resolvedCompilerAnnotationsWithClassIds: List + get() = fir.resolvedCompilerRequiredAnnotations(this) + val resolvedAnnotationClassIds: List get() = fir.resolvedAnnotationClassIds(this) } +@SymbolInternals +fun FirAnnotationContainer.resolvedCompilerRequiredAnnotations(anchorElement: FirBasedSymbol<*>): List { + anchorElement.lazyResolveToPhase(FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS) + return annotations +} + @SymbolInternals fun FirAnnotationContainer.resolvedAnnotationsWithArguments(anchorElement: FirBasedSymbol<*>): List { anchorElement.lazyResolveToPhase(FirResolvePhase.ANNOTATIONS_ARGUMENTS_MAPPING) diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/BuilderConfigurator.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/BuilderConfigurator.kt index 133d1c50cac..9b921ee7ede 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/BuilderConfigurator.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/BuilderConfigurator.kt @@ -129,6 +129,7 @@ object BuilderConfigurator : AbstractBuilderConfigurator(FirTree } default("argumentMapping", "FirEmptyAnnotationArgumentMapping") default("annotationTypeRef", "FirImplicitTypeRefImpl(null)") + default("annotationResolvePhase", "FirAnnotationResolvePhase.Unresolved") useTypes(emptyArgumentListType, emptyAnnotationArgumentMappingType, implicitTypeRefType) withCopy() } diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/ImplementationConfigurator.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/ImplementationConfigurator.kt index 5daad1c6ce5..57a282b4045 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/ImplementationConfigurator.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/ImplementationConfigurator.kt @@ -101,6 +101,9 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator() default("argumentMapping") { needAcceptAndTransform = false } + default("annotationResolvePhase") { + value = "FirAnnotationResolvePhase.Types" + } } impl(arrayOfCall) diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt index 93ab5165493..fe8ef26c65a 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt @@ -487,13 +487,14 @@ object NodeConfigurator : AbstractFieldConfigurator(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 { diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/Types.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/Types.kt index 1621c7ac4a4..dfd205c3076 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/Types.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/Types.kt @@ -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") diff --git a/plugins/fir-plugin-prototype/plugin-annotations/src/org/jetbrains/kotlin/fir/plugin/annotations.kt b/plugins/fir-plugin-prototype/plugin-annotations/src/org/jetbrains/kotlin/fir/plugin/annotations.kt index bcc4696b93d..f1c117494b5 100644 --- a/plugins/fir-plugin-prototype/plugin-annotations/src/org/jetbrains/kotlin/fir/plugin/annotations.kt +++ b/plugins/fir-plugin-prototype/plugin-annotations/src/org/jetbrains/kotlin/fir/plugin/annotations.kt @@ -31,3 +31,5 @@ enum class Visibility { } annotation class SupertypeWithTypeArgument(val kClass: KClass<*>) + +annotation class MetaSupertype diff --git a/plugins/fir-plugin-prototype/src/org/jetbrains/kotlin/fir/plugin/SomeAdditionalSupertypeGenerator.kt b/plugins/fir-plugin-prototype/src/org/jetbrains/kotlin/fir/plugin/SomeAdditionalSupertypeGenerator.kt index d7111d1443f..a65130bcb27 100644 --- a/plugins/fir-plugin-prototype/src/org/jetbrains/kotlin/fir/plugin/SomeAdditionalSupertypeGenerator.kt +++ b/plugins/fir-plugin-prototype/src/org/jetbrains/kotlin/fir/plugin/SomeAdditionalSupertypeGenerator.kt @@ -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 ): List { + 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 { diff --git a/plugins/fir-plugin-prototype/testData/box/metaAnnotationFromLibrary.fir.txt b/plugins/fir-plugin-prototype/testData/box/metaAnnotationFromLibrary.fir.txt new file mode 100644 index 00000000000..e2693734242 --- /dev/null +++ b/plugins/fir-plugin-prototype/testData/box/metaAnnotationFromLibrary.fir.txt @@ -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|Open1|() public open annotation class Open2 : R|kotlin/Annotation| { + public constructor(): R|Open2| { + super() + } + + } + @R|Open2|() public open annotation class Open3 : R|kotlin/Annotation| { + public constructor(): R|Open3| { + super() + } + + } +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|Open1|() public open class First : R|kotlin/Any| { + public constructor(): R|First| { + super() + } + + } + @R|Open2|() public open class Second : R|kotlin/Any| { + public constructor(): R|Second| { + super() + } + + } + @R|Open3|() public open class Third : R|kotlin/Any| { + public constructor(): R|Third| { + super() + } + + } + public final fun box(): R|kotlin/String| { + lval a: R|| = object : R|Zero| { + private constructor(): R|| { + super() + } + + } + + lval b: R|| = object : R|First| { + private constructor(): R|| { + super() + } + + } + + lval c: R|| = object : R|Second| { + private constructor(): R|| { + super() + } + + } + + lval d: R|| = object : R|Third| { + private constructor(): R|| { + super() + } + + } + + ^box String(OK) + } diff --git a/plugins/fir-plugin-prototype/testData/box/metaAnnotationFromLibrary.kt b/plugins/fir-plugin-prototype/testData/box/metaAnnotationFromLibrary.kt new file mode 100644 index 00000000000..2df4b8312cc --- /dev/null +++ b/plugins/fir-plugin-prototype/testData/box/metaAnnotationFromLibrary.kt @@ -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" +} diff --git a/plugins/fir-plugin-prototype/testData/diagnostics/status/metaAnnotationClashesWithSupertype.fir.txt b/plugins/fir-plugin-prototype/testData/diagnostics/status/metaAnnotationClashesWithSupertype.fir.txt new file mode 100644 index 00000000000..b690bb544d7 --- /dev/null +++ b/plugins/fir-plugin-prototype/testData/diagnostics/status/metaAnnotationClashesWithSupertype.fir.txt @@ -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() + } + + } + public final annotation class Ann : R|kotlin/Annotation| { + public constructor(): R|Ann| { + super() + } + + } + public open class Base : R|kotlin/Any| { + public constructor(): R|Base| { + super() + } + + public final annotation class Open : R|kotlin/Annotation| { + public constructor(): R|Base.Open| { + super() + } + + } + + public final annotation class Ann : R|kotlin/Annotation| { + public constructor(): R|Base.Ann| { + super() + } + + } + + } + public final class Derived : R|Base| { + public constructor(): R|Derived| { + super() + } + + @() @R|Base.Ann|() public open class ShouldBeFinal : R|kotlin/Any| { + public constructor(): R|Derived.ShouldBeFinal| { + super() + } + + } + + } + public final class ShouldBeAnError : R|Derived.ShouldBeFinal| { + public constructor(): R|ShouldBeAnError| { + super() + } + + } diff --git a/plugins/fir-plugin-prototype/testData/diagnostics/status/metaAnnotationClashesWithSupertype.kt b/plugins/fir-plugin-prototype/testData/diagnostics/status/metaAnnotationClashesWithSupertype.kt new file mode 100644 index 00000000000..529f9db9fd4 --- /dev/null +++ b/plugins/fir-plugin-prototype/testData/diagnostics/status/metaAnnotationClashesWithSupertype.kt @@ -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() { + @Open // should be an error + @Ann // should be ok + class ShouldBeFinal +} + +class ShouldBeAnError : Derived.ShouldBeFinal() diff --git a/plugins/fir-plugin-prototype/testData/diagnostics/supertypes/metaAnnotationOrder.fir.txt b/plugins/fir-plugin-prototype/testData/diagnostics/supertypes/metaAnnotationOrder.fir.txt new file mode 100644 index 00000000000..83946e67168 --- /dev/null +++ b/plugins/fir-plugin-prototype/testData/diagnostics/supertypes/metaAnnotationOrder.fir.txt @@ -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|AddSupertype3|() public final class Third : R|kotlin/Any|, R|foo/MyInterface| { + public constructor(): R|foo/Third| { + super() + } + + } + @R|AddSupertype1|() public final class First : R|kotlin/Any|, R|foo/MyInterface| { + public constructor(): R|foo/First| { + super() + } + + } + @R|org/jetbrains/kotlin/fir/plugin/MetaSupertype|() public final class Zero : R|kotlin/Any|, R|foo/MyInterface| { + public constructor(): R|foo/Zero| { + super() + } + + } + public final fun test(a: R|foo/Zero|, b: R|foo/First|, c: R|foo/Second|, d: R|foo/Third|): R|kotlin/Unit| { + R|/a|.R|foo/MyInterface.foo|() + R|/b|.R|foo/MyInterface.foo|() + R|/c|.R|foo/MyInterface.foo|() + R|/d|.R|foo/MyInterface.foo|() + } +FILE: ann3.kt + @R|AddSupertype2|() public final annotation class AddSupertype3 : R|kotlin/Annotation| { + public constructor(): R|AddSupertype3| { + super() + } + + } +FILE: ann2.kt + @R|AddSupertype1|() public final annotation class AddSupertype2 : R|kotlin/Annotation| { + public constructor(): R|AddSupertype2| { + super() + } + + } +FILE: ann1.kt + @R|org/jetbrains/kotlin/fir/plugin/MetaSupertype|() public final annotation class AddSupertype1 : R|kotlin/Annotation| { + public constructor(): R|AddSupertype1| { + super() + } + + } diff --git a/plugins/fir-plugin-prototype/testData/diagnostics/supertypes/metaAnnotationOrder.kt b/plugins/fir-plugin-prototype/testData/diagnostics/supertypes/metaAnnotationOrder.kt new file mode 100644 index 00000000000..9354ea132a8 --- /dev/null +++ b/plugins/fir-plugin-prototype/testData/diagnostics/supertypes/metaAnnotationOrder.kt @@ -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 diff --git a/plugins/fir-plugin-prototype/tests-gen/org/jetbrains/kotlin/fir/plugin/runners/FirPluginBlackBoxCodegenTestGenerated.java b/plugins/fir-plugin-prototype/tests-gen/org/jetbrains/kotlin/fir/plugin/runners/FirPluginBlackBoxCodegenTestGenerated.java index a4262e926e5..9ba2d6137e5 100644 --- a/plugins/fir-plugin-prototype/tests-gen/org/jetbrains/kotlin/fir/plugin/runners/FirPluginBlackBoxCodegenTestGenerated.java +++ b/plugins/fir-plugin-prototype/tests-gen/org/jetbrains/kotlin/fir/plugin/runners/FirPluginBlackBoxCodegenTestGenerated.java @@ -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 { diff --git a/plugins/fir-plugin-prototype/tests-gen/org/jetbrains/kotlin/fir/plugin/runners/FirPluginDiagnosticTestGenerated.java b/plugins/fir-plugin-prototype/tests-gen/org/jetbrains/kotlin/fir/plugin/runners/FirPluginDiagnosticTestGenerated.java index 4c43219100a..6df25b34094 100644 --- a/plugins/fir-plugin-prototype/tests-gen/org/jetbrains/kotlin/fir/plugin/runners/FirPluginDiagnosticTestGenerated.java +++ b/plugins/fir-plugin-prototype/tests-gen/org/jetbrains/kotlin/fir/plugin/runners/FirPluginDiagnosticTestGenerated.java @@ -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 { diff --git a/plugins/kotlinx-serialization/testData/diagnostics/metaSerializableNested.fir.kt b/plugins/kotlinx-serialization/testData/diagnostics/metaSerializableNested.fir.kt deleted file mode 100644 index f8b2959bbf7..00000000000 --- a/plugins/kotlinx-serialization/testData/diagnostics/metaSerializableNested.fir.kt +++ /dev/null @@ -1,21 +0,0 @@ -// WITH_STDLIB -// SKIP_TXT - -import kotlinx.serialization.* - -@MetaSerializable -annotation class TopLevel - -class MetaSerializableNestedTest { - @MetaSerializable - @Target(AnnotationTarget.PROPERTY, AnnotationTarget.CLASS) - annotation class JsonComment(val comment: String) - - object Nested2 { - @MetaSerializable - annotation class Nested3 - } - - @JsonComment("class_comment") - data class IntDataCommented(val i: Int) -} diff --git a/plugins/kotlinx-serialization/testData/diagnostics/metaSerializableNested.kt b/plugins/kotlinx-serialization/testData/diagnostics/metaSerializableNested.kt index 0595798824f..a1707a898c2 100644 --- a/plugins/kotlinx-serialization/testData/diagnostics/metaSerializableNested.kt +++ b/plugins/kotlinx-serialization/testData/diagnostics/metaSerializableNested.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // WITH_STDLIB // SKIP_TXT