From 686443358110cb5dfd4dd191bd9fbf43006bb51c Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Fri, 25 Nov 2022 12:08:43 +0200 Subject: [PATCH] [FIR] Support resolution of meta-annotations before supertypes Now annotations are resolved with following algorithm: 1. On COMPILER_REQUIRED_ANNOTATIONS we resolve all annotations and store results if this is compiler annotation, plugin annotation, or annotation with meta-annotation (meta annotations are checked recursively with designated resolution if needed) 2. On TYPES stage we resolve all those annotations once again and if some annotation changes resolution then we keep type from p.1 and report error on this annotation, so user should disambiguate it Ambiguity may occur because of nested annotations with same name as plugin annotations: ``` annotation class SomeAnnotation // (1) plugin annotation open class Base { annotation class SomeAnnotation // (2) } class Derived : Base() { @SomeAnnotation // <----------------- class Inner } ``` At COMPILER_REQUIRED_ANNOTATIONS annotation call will be resolved to (1) because at this stage supertypes are not resolved yet, and we consider only importing scopes. At the TYPES stage we will find correct annotation from supertype --- .../diagnostics/KtFirDataClassConverters.kt | 8 + .../api/fir/diagnostics/KtFirDiagnostics.kt | 6 + .../fir/diagnostics/KtFirDiagnosticsImpl.kt | 7 + .../LLFirNonUnderContentRootSessionFactory.kt | 2 + .../LLFirIdePredicateBasedProvider.kt | 25 +- .../LLFirIdeRegisteredPluginAnnotations.kt | 20 +- ...DesignatedAnnotationsResolveTransformed.kt | 3 +- .../diagnostics/FirDiagnosticsList.kt | 5 + .../fir/analysis/diagnostics/FirErrors.kt | 1 + .../diagnostics/FirErrorsDefaultMessages.kt | 7 + .../coneDiagnosticToFirDiagnostic.kt | 3 + .../FirPredicateBasedProviderImpl.kt | 44 ++- .../FirRegisteredPluginAnnotations.kt | 88 +++++- .../resolve/transformers/DesignationState.kt | 70 +++++ .../FirStatusResolveTransformer.kt | 56 +--- .../transformers/FirTypeResolveTransformer.kt | 42 ++- .../FirExpressionsResolveTransformer.kt | 1 + ...FirSpecificAnnotationResolveTransformer.kt | 286 ++++++++++++++++++ ...FirAbstractAnnotationResolveTransformer.kt | 134 -------- ...erRequiredAnnotationsResolveTransformer.kt | 209 +++++-------- .../resolve/diagnostics/ConeDiagnostics.kt | 14 +- .../kotlin/fir/expressions/FirAnnotation.kt | 2 + .../fir/expressions/FirAnnotationCall.kt | 5 + .../fir/expressions/FirErrorAnnotationCall.kt | 5 + .../builder/FirAnnotationCallBuilder.kt | 4 + .../builder/FirErrorAnnotationCallBuilder.kt | 1 + .../expressions/impl/FirAnnotationCallImpl.kt | 10 + .../fir/expressions/impl/FirAnnotationImpl.kt | 4 + .../impl/FirErrorAnnotationCallImpl.kt | 10 + ...Status.kt => FirAnnotationResolvePhase.kt} | 8 +- .../extensions/predicate/LookupPredicate.kt | 3 +- .../kotlin/fir/symbols/FirBasedSymbol.kt | 9 + .../fir/tree/generator/BuilderConfigurator.kt | 1 + .../generator/ImplementationConfigurator.kt | 3 + .../fir/tree/generator/NodeConfigurator.kt | 3 +- .../kotlin/fir/tree/generator/Types.kt | 2 +- .../kotlin/fir/plugin/annotations.kt | 2 + .../SomeAdditionalSupertypeGenerator.kt | 22 +- .../box/metaAnnotationFromLibrary.fir.txt | 77 +++++ .../testData/box/metaAnnotationFromLibrary.kt | 35 +++ ...metaAnnotationClashesWithSupertype.fir.txt | 56 ++++ .../metaAnnotationClashesWithSupertype.kt | 19 ++ .../supertypes/metaAnnotationOrder.fir.txt | 59 ++++ .../supertypes/metaAnnotationOrder.kt | 41 +++ ...FirPluginBlackBoxCodegenTestGenerated.java | 6 + .../FirPluginDiagnosticTestGenerated.java | 12 + .../diagnostics/metaSerializableNested.fir.kt | 21 -- .../diagnostics/metaSerializableNested.kt | 1 + 48 files changed, 1065 insertions(+), 387 deletions(-) create mode 100644 compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/DesignationState.kt create mode 100644 compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/AbstractFirSpecificAnnotationResolveTransformer.kt delete mode 100644 compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/plugin/FirAbstractAnnotationResolveTransformer.kt rename compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/{FirAnnotationResolveStatus.kt => FirAnnotationResolvePhase.kt} (67%) create mode 100644 plugins/fir-plugin-prototype/testData/box/metaAnnotationFromLibrary.fir.txt create mode 100644 plugins/fir-plugin-prototype/testData/box/metaAnnotationFromLibrary.kt create mode 100644 plugins/fir-plugin-prototype/testData/diagnostics/status/metaAnnotationClashesWithSupertype.fir.txt create mode 100644 plugins/fir-plugin-prototype/testData/diagnostics/status/metaAnnotationClashesWithSupertype.kt create mode 100644 plugins/fir-plugin-prototype/testData/diagnostics/supertypes/metaAnnotationOrder.fir.txt create mode 100644 plugins/fir-plugin-prototype/testData/diagnostics/supertypes/metaAnnotationOrder.kt delete mode 100644 plugins/kotlinx-serialization/testData/diagnostics/metaSerializableNested.fir.kt 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