[FIR] Properly handle nested annotations on compiler-required annotation phase
There was a case when we visited the same declaration multiple times because of forward-referencing and visiting with designation So because of this there were two changes required: - remove assertion about visiting the same declaration twice (it's fine since we don't actually resolve annotations twice) - not skipping resolution of class children if annotations on this class are already resolved ^KT-61388 Fixed KT-62854
This commit is contained in:
committed by
Space Team
parent
80257dc58f
commit
0325ffaa01
+6
@@ -767,6 +767,12 @@ public class DiagnosticCompilerTestFirTestdataTestGenerated extends AbstractDiag
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/annotations"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kindaCompilerRequiredNestedAnnotation.kt")
|
||||
public void testKindaCompilerRequiredNestedAnnotation() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/annotations/kindaCompilerRequiredNestedAnnotation.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt43936.kt")
|
||||
public void testKt43936() throws Exception {
|
||||
|
||||
+6
@@ -767,6 +767,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFirTestDataTestGenerated
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/annotations"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kindaCompilerRequiredNestedAnnotation.kt")
|
||||
public void testKindaCompilerRequiredNestedAnnotation() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/annotations/kindaCompilerRequiredNestedAnnotation.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt43936.kt")
|
||||
public void testKt43936() throws Exception {
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
FILE: a.kt
|
||||
@R|SinceKotlin|() public final class Some : R|kotlin/Any| {
|
||||
public constructor(): R|Some| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
FILE: b.kt
|
||||
@R|SinceKotlin.SinceKotlin|() public final class Other : R|kotlin/Any| {
|
||||
public constructor(): R|Other| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
FILE: SinceKotlin.kt
|
||||
public final annotation class SinceKotlin : R|kotlin/Annotation| {
|
||||
public constructor(): R|SinceKotlin| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final annotation class SinceKotlin : R|kotlin/Annotation| {
|
||||
public constructor(): R|SinceKotlin.SinceKotlin| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
// ISSUE: KT-61388
|
||||
// FILE: a.kt
|
||||
@SinceKotlin
|
||||
class Some
|
||||
|
||||
// FILE: b.kt
|
||||
@SinceKotlin.SinceKotlin
|
||||
class Other
|
||||
|
||||
// FILE: SinceKotlin.kt
|
||||
annotation class SinceKotlin {
|
||||
annotation class SinceKotlin
|
||||
}
|
||||
+6
@@ -767,6 +767,12 @@ public class FirLightTreeDiagnosticsTestGenerated extends AbstractFirLightTreeDi
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/annotations"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kindaCompilerRequiredNestedAnnotation.kt")
|
||||
public void testKindaCompilerRequiredNestedAnnotation() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/annotations/kindaCompilerRequiredNestedAnnotation.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt43936.kt")
|
||||
public void testKt43936() throws Exception {
|
||||
|
||||
+6
@@ -767,6 +767,12 @@ public class FirPsiDiagnosticTestGenerated extends AbstractFirPsiDiagnosticTest
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/annotations"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kindaCompilerRequiredNestedAnnotation.kt")
|
||||
public void testKindaCompilerRequiredNestedAnnotation() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/annotations/kindaCompilerRequiredNestedAnnotation.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt43936.kt")
|
||||
public void testKt43936() throws Exception {
|
||||
|
||||
+53
-4
@@ -31,10 +31,56 @@ import org.jetbrains.kotlin.fir.visitors.transformSingle
|
||||
import org.jetbrains.kotlin.fir.withFileAnalysisExceptionWrapping
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
|
||||
/**
|
||||
* Little explanation the logic of this phase
|
||||
*
|
||||
* - this transformer visits all declarations and tries to resolve each annotation that looks like compiler-required by short name
|
||||
* - if there are any meta-annotations registered by plugins, then each annotation is considered as "potentially compiler-required"
|
||||
* - transformer resolves:
|
||||
* - annotation types
|
||||
* - annotation call arguments, if annotation classId mentioned in FirAnnotationsPlatformSpecificSupportComponent.requiredAnnotationsWithArguments
|
||||
* - if annotation is considered as compiler-required after the resolution, the resolved type is saved in the annotation with
|
||||
* FirAnnotationResolvePhase.CompilerRequiredAnnotations phase
|
||||
* - if annotation potentially can be annotated with meta-annotation, the phase performs a designated jump to corresponding annotation class
|
||||
* to resolve annotations on it. This jump resolves annotations only on last declaration from designation path
|
||||
*
|
||||
* Example:
|
||||
* ```
|
||||
* // FILE: plugin.kt
|
||||
* annotation class MetaAnnotation
|
||||
*
|
||||
* // FILE: a.kt
|
||||
* @A // (1)
|
||||
* class Some
|
||||
*
|
||||
* // FILE: b.kt
|
||||
* @A.B // (2)
|
||||
* class Other
|
||||
*
|
||||
* // FILE: SinceKotlin.kt
|
||||
* @MetaAnnotation // (3)
|
||||
* annotation class A {
|
||||
* @MetaAnnotation // (4)
|
||||
* annotation class B
|
||||
*
|
||||
* @MetaAnnotation // (5)
|
||||
* annotation class C
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* 1. visit class `Some`, resolve (1)
|
||||
* 2. there are meta-annotations -> jump to class `A` and resolve (3)
|
||||
* 3. visit class `Other`, resolved (2)
|
||||
* 4. there are meta-annotations -> jump to class `A.B` and resolve (4)
|
||||
* 5. visit class `A`, skip annotations on `A` since they are already resolved
|
||||
* 6. visit class `A.B`, skip annotations on `A.B` since they are already resolved
|
||||
* 7. visit class `A.C`, resolve (5)
|
||||
*/
|
||||
class FirCompilerRequiredAnnotationsResolveProcessor(
|
||||
session: FirSession,
|
||||
scopeSession: ScopeSession
|
||||
) : FirGlobalResolveProcessor(session, scopeSession, FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS) {
|
||||
) : FirGlobalResolveProcessor(session, scopeSession, COMPILER_REQUIRED_ANNOTATIONS) {
|
||||
|
||||
override fun process(files: Collection<FirFile>) {
|
||||
val computationSession = CompilerRequiredAnnotationsComputationSession()
|
||||
@@ -150,9 +196,7 @@ open class CompilerRequiredAnnotationsComputationSession {
|
||||
}
|
||||
|
||||
fun recordThatAnnotationsAreResolved(declaration: FirAnnotationContainer) {
|
||||
if (!declarationsWithResolvedAnnotations.add(declaration)) {
|
||||
error("Annotations are resolved twice")
|
||||
}
|
||||
declarationsWithResolvedAnnotations.add(declaration)
|
||||
}
|
||||
|
||||
fun resolveAnnotationsOnAnnotationIfNeeded(symbol: FirRegularClassSymbol, scopeSession: ScopeSession) {
|
||||
@@ -198,6 +242,11 @@ class FirSpecificAnnotationResolveTransformer(
|
||||
computationSession: CompilerRequiredAnnotationsComputationSession
|
||||
) : AbstractFirSpecificAnnotationResolveTransformer(session, scopeSession, computationSession) {
|
||||
override fun shouldTransformDeclaration(declaration: FirDeclaration): Boolean {
|
||||
/*
|
||||
* Even if annotations on class are resolved, annotations on nested declarations might be not resolved yet
|
||||
* It may happen if we visited a top-level class with designated transformer with this class as target of designation
|
||||
*/
|
||||
if (declaration is FirRegularClass) return true
|
||||
@OptIn(PrivateForInline::class)
|
||||
return !computationSession.annotationsAreResolved(declaration, treatNonSourceDeclarationsAsResolved = true)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user