diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirSupertypeLazyResolver.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirSupertypeLazyResolver.kt index 2bd113820ca..a3e606c1254 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirSupertypeLazyResolver.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/transformers/LLFirSupertypeLazyResolver.kt @@ -73,11 +73,23 @@ private class LLFirSuperTypeTargetResolver( private val supertypeComputationSession: LLFirSupertypeComputationSession = LLFirSupertypeComputationSession(session), private val visitedElements: MutableSet = hashSetOf(), ) : LLFirTargetResolver(target, lockProvider, FirResolvePhase.SUPER_TYPES, isJumpingPhase = true) { - private val supertypeResolver = FirSupertypeResolverVisitor( + private val supertypeResolver = object : FirSupertypeResolverVisitor( session = session, supertypeComputationSession = supertypeComputationSession, scopeSession = scopeSession, - ) + ) { + /** + * We can do nothing here because at a call moment we've already resolved [outerClass] + * because we resolve classes from top to down + */ + override fun resolveAllSupertypesForOuterClass(outerClass: FirClass) { + // We can get into this function during a loop calculation, so it is possible that the result for [outerClass] + // is not yet published, so we expect that this class was already visited or resolved + if (outerClass !in visitedElements) { + LLFirSupertypeLazyResolver.checkIsResolved(outerClass) + } + } + } override fun withFile(firFile: FirFile, action: () -> Unit) { action() diff --git a/analysis/low-level-api-fir/testdata/lazyResolve/classes/nestedClass.kt b/analysis/low-level-api-fir/testdata/lazyResolve/classes/nestedClass.kt new file mode 100644 index 00000000000..c8d5a284d0c --- /dev/null +++ b/analysis/low-level-api-fir/testdata/lazyResolve/classes/nestedClass.kt @@ -0,0 +1,5 @@ +open class TopLevelClass +open class AnotherTopLevelClass : TopLevelClass() +class OuterClass : AnotherTopLevelClass() { + class NestedClass +} diff --git a/analysis/low-level-api-fir/testdata/lazyResolve/classes/nestedClass.txt b/analysis/low-level-api-fir/testdata/lazyResolve/classes/nestedClass.txt new file mode 100644 index 00000000000..ea5affda834 --- /dev/null +++ b/analysis/low-level-api-fir/testdata/lazyResolve/classes/nestedClass.txt @@ -0,0 +1,405 @@ +RAW_FIR: +FILE: [ResolvedTo(RAW_FIR)] nestedClass.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(RAW_FIR)] class TopLevelClass : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=TopLevelClass] constructor(): R|TopLevelClass| { + LAZY_super + } + + } + public? open [ResolvedTo(RAW_FIR)] class AnotherTopLevelClass : TopLevelClass { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| { + LAZY_super + } + + } + public? final? [ResolvedTo(RAW_FIR)] class OuterClass : AnotherTopLevelClass { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=OuterClass] constructor(): R|OuterClass| { + LAZY_super + } + + public? final? [ResolvedTo(RAW_FIR)] class NestedClass : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=NestedClass] constructor(): R|OuterClass.NestedClass| { + LAZY_super + } + + } + + } + +IMPORTS: +FILE: [ResolvedTo(IMPORTS)] nestedClass.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(RAW_FIR)] class TopLevelClass : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=TopLevelClass] constructor(): R|TopLevelClass| { + LAZY_super + } + + } + public? open [ResolvedTo(RAW_FIR)] class AnotherTopLevelClass : TopLevelClass { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| { + LAZY_super + } + + } + public? final? [ResolvedTo(RAW_FIR)] class OuterClass : AnotherTopLevelClass { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=OuterClass] constructor(): R|OuterClass| { + LAZY_super + } + + public? final? [ResolvedTo(RAW_FIR)] class NestedClass : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=NestedClass] constructor(): R|OuterClass.NestedClass| { + LAZY_super + } + + } + + } + +COMPILER_REQUIRED_ANNOTATIONS: +FILE: [ResolvedTo(IMPORTS)] nestedClass.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(RAW_FIR)] class TopLevelClass : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=TopLevelClass] constructor(): R|TopLevelClass| { + LAZY_super + } + + } + public? open [ResolvedTo(RAW_FIR)] class AnotherTopLevelClass : TopLevelClass { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| { + LAZY_super + } + + } + public? final? [ResolvedTo(RAW_FIR)] class OuterClass : AnotherTopLevelClass { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=OuterClass] constructor(): R|OuterClass| { + LAZY_super + } + + public? final? [ResolvedTo(COMPILER_REQUIRED_ANNOTATIONS)] class NestedClass : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=NestedClass] constructor(): R|OuterClass.NestedClass| { + LAZY_super + } + + } + + } + +COMPANION_GENERATION: +FILE: [ResolvedTo(IMPORTS)] nestedClass.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(RAW_FIR)] class TopLevelClass : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=TopLevelClass] constructor(): R|TopLevelClass| { + LAZY_super + } + + } + public? open [ResolvedTo(RAW_FIR)] class AnotherTopLevelClass : TopLevelClass { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| { + LAZY_super + } + + } + public? final? [ResolvedTo(RAW_FIR)] class OuterClass : AnotherTopLevelClass { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=OuterClass] constructor(): R|OuterClass| { + LAZY_super + } + + public? final? [ResolvedTo(COMPANION_GENERATION)] class NestedClass : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=NestedClass] constructor(): R|OuterClass.NestedClass| { + LAZY_super + } + + } + + } + +SUPER_TYPES: +FILE: [ResolvedTo(IMPORTS)] nestedClass.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(SUPER_TYPES)] class TopLevelClass : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=TopLevelClass] constructor(): R|TopLevelClass| { + LAZY_super + } + + } + public? open [ResolvedTo(SUPER_TYPES)] class AnotherTopLevelClass : R|TopLevelClass| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| { + LAZY_super + } + + } + public? final? [ResolvedTo(SUPER_TYPES)] class OuterClass : R|AnotherTopLevelClass| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=OuterClass] constructor(): R|OuterClass| { + LAZY_super + } + + public? final? [ResolvedTo(SUPER_TYPES)] class NestedClass : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=NestedClass] constructor(): R|OuterClass.NestedClass| { + LAZY_super + } + + } + + } + +TYPES: +FILE: [ResolvedTo(IMPORTS)] nestedClass.kt + [ResolvedTo(RAW_FIR)] annotations container + public? open [ResolvedTo(SUPER_TYPES)] class TopLevelClass : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=TopLevelClass] constructor(): R|TopLevelClass| { + LAZY_super + } + + } + public? open [ResolvedTo(SUPER_TYPES)] class AnotherTopLevelClass : R|TopLevelClass| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| { + LAZY_super + } + + } + public? final? [ResolvedTo(TYPES)] class OuterClass : R|AnotherTopLevelClass| { + public? [ResolvedTo(TYPES)] [ContainingClassKey=OuterClass] constructor(): R|OuterClass| { + LAZY_super + } + + public? final? [ResolvedTo(TYPES)] class NestedClass : R|kotlin/Any| { + public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=NestedClass] constructor(): R|OuterClass.NestedClass| { + LAZY_super + } + + } + + } + +STATUS: +FILE: [ResolvedTo(IMPORTS)] nestedClass.kt + [ResolvedTo(RAW_FIR)] annotations container + public open [ResolvedTo(STATUS)] class TopLevelClass : R|kotlin/Any| { + public [ResolvedTo(STATUS)] [ContainingClassKey=TopLevelClass] constructor(): R|TopLevelClass| { + LAZY_super + } + + } + public open [ResolvedTo(STATUS)] class AnotherTopLevelClass : R|TopLevelClass| { + public [ResolvedTo(STATUS)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| { + LAZY_super + } + + } + public final [ResolvedTo(STATUS)] class OuterClass : R|AnotherTopLevelClass| { + public [ResolvedTo(STATUS)] [ContainingClassKey=OuterClass] constructor(): R|OuterClass| { + LAZY_super + } + + public final [ResolvedTo(STATUS)] class NestedClass : R|kotlin/Any| { + public [ResolvedTo(STATUS)] [ContainingClassKey=NestedClass] constructor(): R|OuterClass.NestedClass| { + LAZY_super + } + + } + + } + +EXPECT_ACTUAL_MATCHING: +FILE: [ResolvedTo(IMPORTS)] nestedClass.kt + [ResolvedTo(RAW_FIR)] annotations container + public open [ResolvedTo(STATUS)] class TopLevelClass : R|kotlin/Any| { + public [ResolvedTo(STATUS)] [ContainingClassKey=TopLevelClass] constructor(): R|TopLevelClass| { + LAZY_super + } + + } + public open [ResolvedTo(STATUS)] class AnotherTopLevelClass : R|TopLevelClass| { + public [ResolvedTo(STATUS)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| { + LAZY_super + } + + } + public final [ResolvedTo(STATUS)] class OuterClass : R|AnotherTopLevelClass| { + public [ResolvedTo(STATUS)] [ContainingClassKey=OuterClass] constructor(): R|OuterClass| { + LAZY_super + } + + public final [ResolvedTo(EXPECT_ACTUAL_MATCHING)] class NestedClass : R|kotlin/Any| { + public [ResolvedTo(STATUS)] [ContainingClassKey=NestedClass] constructor(): R|OuterClass.NestedClass| { + LAZY_super + } + + } + + } + +ARGUMENTS_OF_ANNOTATIONS: +FILE: [ResolvedTo(IMPORTS)] nestedClass.kt + [ResolvedTo(RAW_FIR)] annotations container + public open [ResolvedTo(STATUS)] class TopLevelClass : R|kotlin/Any| { + public [ResolvedTo(STATUS)] [ContainingClassKey=TopLevelClass] constructor(): R|TopLevelClass| { + LAZY_super + } + + } + public open [ResolvedTo(STATUS)] class AnotherTopLevelClass : R|TopLevelClass| { + public [ResolvedTo(STATUS)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| { + LAZY_super + } + + } + public final [ResolvedTo(STATUS)] class OuterClass : R|AnotherTopLevelClass| { + public [ResolvedTo(STATUS)] [ContainingClassKey=OuterClass] constructor(): R|OuterClass| { + LAZY_super + } + + public final [ResolvedTo(ARGUMENTS_OF_ANNOTATIONS)] class NestedClass : R|kotlin/Any| { + public [ResolvedTo(STATUS)] [ContainingClassKey=NestedClass] constructor(): R|OuterClass.NestedClass| { + LAZY_super + } + + } + + } + +CONTRACTS: +FILE: [ResolvedTo(IMPORTS)] nestedClass.kt + [ResolvedTo(RAW_FIR)] annotations container + public open [ResolvedTo(STATUS)] class TopLevelClass : R|kotlin/Any| { + public [ResolvedTo(STATUS)] [ContainingClassKey=TopLevelClass] constructor(): R|TopLevelClass| { + LAZY_super + } + + } + public open [ResolvedTo(STATUS)] class AnotherTopLevelClass : R|TopLevelClass| { + public [ResolvedTo(STATUS)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| { + LAZY_super + } + + } + public final [ResolvedTo(STATUS)] class OuterClass : R|AnotherTopLevelClass| { + public [ResolvedTo(STATUS)] [ContainingClassKey=OuterClass] constructor(): R|OuterClass| { + LAZY_super + } + + public final [ResolvedTo(CONTRACTS)] class NestedClass : R|kotlin/Any| { + public [ResolvedTo(STATUS)] [ContainingClassKey=NestedClass] constructor(): R|OuterClass.NestedClass| { + LAZY_super + } + + } + + } + +IMPLICIT_TYPES_BODY_RESOLVE: +FILE: [ResolvedTo(IMPORTS)] nestedClass.kt + [ResolvedTo(RAW_FIR)] annotations container + public open [ResolvedTo(STATUS)] class TopLevelClass : R|kotlin/Any| { + public [ResolvedTo(STATUS)] [ContainingClassKey=TopLevelClass] constructor(): R|TopLevelClass| { + LAZY_super + } + + } + public open [ResolvedTo(STATUS)] class AnotherTopLevelClass : R|TopLevelClass| { + public [ResolvedTo(STATUS)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| { + LAZY_super + } + + } + public final [ResolvedTo(STATUS)] class OuterClass : R|AnotherTopLevelClass| { + public [ResolvedTo(STATUS)] [ContainingClassKey=OuterClass] constructor(): R|OuterClass| { + LAZY_super + } + + public final [ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] class NestedClass : R|kotlin/Any| { + public [ResolvedTo(STATUS)] [ContainingClassKey=NestedClass] constructor(): R|OuterClass.NestedClass| { + LAZY_super + } + + } + + } + +ANNOTATIONS_ARGUMENTS_MAPPING: +FILE: [ResolvedTo(IMPORTS)] nestedClass.kt + [ResolvedTo(RAW_FIR)] annotations container + public open [ResolvedTo(STATUS)] class TopLevelClass : R|kotlin/Any| { + public [ResolvedTo(STATUS)] [ContainingClassKey=TopLevelClass] constructor(): R|TopLevelClass| { + LAZY_super + } + + } + public open [ResolvedTo(STATUS)] class AnotherTopLevelClass : R|TopLevelClass| { + public [ResolvedTo(STATUS)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| { + LAZY_super + } + + } + public final [ResolvedTo(STATUS)] class OuterClass : R|AnotherTopLevelClass| { + public [ResolvedTo(STATUS)] [ContainingClassKey=OuterClass] constructor(): R|OuterClass| { + LAZY_super + } + + public final [ResolvedTo(ANNOTATIONS_ARGUMENTS_MAPPING)] class NestedClass : R|kotlin/Any| { + public [ResolvedTo(STATUS)] [ContainingClassKey=NestedClass] constructor(): R|OuterClass.NestedClass| { + LAZY_super + } + + } + + } + +BODY_RESOLVE: +FILE: [ResolvedTo(IMPORTS)] nestedClass.kt + [ResolvedTo(RAW_FIR)] annotations container + public open [ResolvedTo(STATUS)] class TopLevelClass : R|kotlin/Any| { + public [ResolvedTo(STATUS)] [ContainingClassKey=TopLevelClass] constructor(): R|TopLevelClass| { + LAZY_super + } + + } + public open [ResolvedTo(STATUS)] class AnotherTopLevelClass : R|TopLevelClass| { + public [ResolvedTo(STATUS)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| { + LAZY_super + } + + } + public final [ResolvedTo(STATUS)] class OuterClass : R|AnotherTopLevelClass| { + public [ResolvedTo(STATUS)] [ContainingClassKey=OuterClass] constructor(): R|OuterClass| { + LAZY_super + } + + public final [ResolvedTo(BODY_RESOLVE)] class NestedClass : R|kotlin/Any| { + public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=NestedClass] constructor(): R|OuterClass.NestedClass| { + super() + } + + } + + } + +FILE RAW TO BODY: +FILE: [ResolvedTo(IMPORTS)] nestedClass.kt + [ResolvedTo(BODY_RESOLVE)] annotations container + public open [ResolvedTo(BODY_RESOLVE)] class TopLevelClass : R|kotlin/Any| { + public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=TopLevelClass] constructor(): R|TopLevelClass| { + super() + } + + } + public open [ResolvedTo(BODY_RESOLVE)] class AnotherTopLevelClass : R|TopLevelClass| { + public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| { + super() + } + + } + public final [ResolvedTo(BODY_RESOLVE)] class OuterClass : R|AnotherTopLevelClass| { + public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=OuterClass] constructor(): R|OuterClass| { + super() + } + + public final [ResolvedTo(BODY_RESOLVE)] class NestedClass : R|kotlin/Any| { + public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=NestedClass] constructor(): R|OuterClass.NestedClass| { + super() + } + + } + + } diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirOutOfContentRootLazyDeclarationResolveTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirOutOfContentRootLazyDeclarationResolveTestGenerated.java index be2e1627e59..28fbe7c710a 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirOutOfContentRootLazyDeclarationResolveTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirOutOfContentRootLazyDeclarationResolveTestGenerated.java @@ -375,6 +375,12 @@ public class FirOutOfContentRootLazyDeclarationResolveTestGenerated extends Abst runTest("analysis/low-level-api-fir/testdata/lazyResolve/classes/functionInValueClass.kt"); } + @Test + @TestMetadata("nestedClass.kt") + public void testNestedClass() throws Exception { + runTest("analysis/low-level-api-fir/testdata/lazyResolve/classes/nestedClass.kt"); + } + @Test @TestMetadata("nestedClassWithPropertiesOverrides.kt") public void testNestedClassWithPropertiesOverrides() throws Exception { diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirSourceLazyDeclarationResolveTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirSourceLazyDeclarationResolveTestGenerated.java index ca5e3d7a3e0..6d57904bc74 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirSourceLazyDeclarationResolveTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/FirSourceLazyDeclarationResolveTestGenerated.java @@ -375,6 +375,12 @@ public class FirSourceLazyDeclarationResolveTestGenerated extends AbstractFirSou runTest("analysis/low-level-api-fir/testdata/lazyResolve/classes/functionInValueClass.kt"); } + @Test + @TestMetadata("nestedClass.kt") + public void testNestedClass() throws Exception { + runTest("analysis/low-level-api-fir/testdata/lazyResolve/classes/nestedClass.kt"); + } + @Test @TestMetadata("nestedClassWithPropertiesOverrides.kt") public void testNestedClassWithPropertiesOverrides() throws Exception { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt index 101ee123038..752756b051b 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSupertypesResolution.kt @@ -237,7 +237,7 @@ private fun createOtherScopesForNestedClassesOrCompanion( // See: prepareScopes() } -class FirSupertypeResolverVisitor( +open class FirSupertypeResolverVisitor( private val session: FirSession, private val supertypeComputationSession: SupertypeComputationSession, private val scopeSession: ScopeSession, @@ -300,15 +300,28 @@ class FirSupertypeResolverVisitor( } private fun calculateScopes( - klass: FirClass, + outerClass: FirClass, withCompanionScopes: Boolean, ): PersistentList { - resolveAllSupertypes(klass, klass.superTypeRefs) - return prepareScopes(klass).pushAll( - createOtherScopesForNestedClassesOrCompanion(klass, session, scopeSession, supertypeComputationSession, withCompanionScopes) + resolveAllSupertypesForOuterClass(outerClass) + return prepareScopes(outerClass).pushAll( + createOtherScopesForNestedClassesOrCompanion( + klass = outerClass, + session = session, + scopeSession = scopeSession, + supertypeComputationSession = supertypeComputationSession, + withCompanionScopes = withCompanionScopes, + ) ) } + /** + * Resolve all super types. [outerClass] is used as an outer scope for nested class or companion + */ + protected open fun resolveAllSupertypesForOuterClass(outerClass: FirClass) { + resolveAllSupertypes(outerClass, outerClass.superTypeRefs) + } + private fun resolveAllSupertypes( classLikeDeclaration: FirClassLikeDeclaration, supertypeRefs: List,