[FIR] avoid jumping from super type transformer for local classes to unresolved non-local classes

In the worst case, we will visit the entire hierarchy of a local class,
where non-local classes are not yet resolved

^KT-56550
This commit is contained in:
Dmitrii Gridin
2023-05-07 15:48:10 +02:00
committed by Space Team
parent 6f584bcbe7
commit ee74e10f28
5 changed files with 495 additions and 9 deletions
@@ -0,0 +1,24 @@
open class TopLevelClass {
open fun foo(i: Int) {
}
open fun boo(b: String) {
}
}
open class AnotherTopLevelClass : TopLevelClass() {
override fun foo(i: Int) {
}
}
fun reso<caret>lveMe() {
class LocalClass : AnotherTopLevelClass() {
override fun foo(i: Int) {
}
class NestedLocalClass
}
}
@@ -0,0 +1,414 @@
RAW_FIR:
FILE: [ResolvedTo(RAW_FIR)] localNestedClass.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<R|kotlin/Any|>
}
public? open [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK }
public? open [ResolvedTo(RAW_FIR)] fun boo([ResolvedTo(RAW_FIR)] b: String): R|kotlin/Unit| { LAZY_BLOCK }
}
public? open [ResolvedTo(RAW_FIR)] class AnotherTopLevelClass : TopLevelClass {
public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| {
LAZY_super<TopLevelClass>
}
public? open? override [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK }
}
public? final? [ResolvedTo(RAW_FIR)] fun resolveMe(): R|kotlin/Unit| { LAZY_BLOCK }
IMPORTS:
FILE: [ResolvedTo(IMPORTS)] localNestedClass.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<R|kotlin/Any|>
}
public? open [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK }
public? open [ResolvedTo(RAW_FIR)] fun boo([ResolvedTo(RAW_FIR)] b: String): R|kotlin/Unit| { LAZY_BLOCK }
}
public? open [ResolvedTo(RAW_FIR)] class AnotherTopLevelClass : TopLevelClass {
public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| {
LAZY_super<TopLevelClass>
}
public? open? override [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK }
}
public? final? [ResolvedTo(RAW_FIR)] fun resolveMe(): R|kotlin/Unit| { LAZY_BLOCK }
COMPILER_REQUIRED_ANNOTATIONS:
FILE: [ResolvedTo(IMPORTS)] localNestedClass.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<R|kotlin/Any|>
}
public? open [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK }
public? open [ResolvedTo(RAW_FIR)] fun boo([ResolvedTo(RAW_FIR)] b: String): R|kotlin/Unit| { LAZY_BLOCK }
}
public? open [ResolvedTo(RAW_FIR)] class AnotherTopLevelClass : TopLevelClass {
public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| {
LAZY_super<TopLevelClass>
}
public? open? override [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK }
}
public? final? [ResolvedTo(COMPILER_REQUIRED_ANNOTATIONS)] fun resolveMe(): R|kotlin/Unit| { LAZY_BLOCK }
COMPANION_GENERATION:
FILE: [ResolvedTo(IMPORTS)] localNestedClass.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<R|kotlin/Any|>
}
public? open [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK }
public? open [ResolvedTo(RAW_FIR)] fun boo([ResolvedTo(RAW_FIR)] b: String): R|kotlin/Unit| { LAZY_BLOCK }
}
public? open [ResolvedTo(RAW_FIR)] class AnotherTopLevelClass : TopLevelClass {
public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| {
LAZY_super<TopLevelClass>
}
public? open? override [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK }
}
public? final? [ResolvedTo(COMPANION_GENERATION)] fun resolveMe(): R|kotlin/Unit| { LAZY_BLOCK }
SUPER_TYPES:
FILE: [ResolvedTo(IMPORTS)] localNestedClass.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<R|kotlin/Any|>
}
public? open [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK }
public? open [ResolvedTo(RAW_FIR)] fun boo([ResolvedTo(RAW_FIR)] b: String): R|kotlin/Unit| { LAZY_BLOCK }
}
public? open [ResolvedTo(RAW_FIR)] class AnotherTopLevelClass : TopLevelClass {
public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| {
LAZY_super<TopLevelClass>
}
public? open? override [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK }
}
public? final? [ResolvedTo(SUPER_TYPES)] fun resolveMe(): R|kotlin/Unit| { LAZY_BLOCK }
TYPES:
FILE: [ResolvedTo(IMPORTS)] localNestedClass.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<R|kotlin/Any|>
}
public? open [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK }
public? open [ResolvedTo(RAW_FIR)] fun boo([ResolvedTo(RAW_FIR)] b: String): R|kotlin/Unit| { LAZY_BLOCK }
}
public? open [ResolvedTo(RAW_FIR)] class AnotherTopLevelClass : TopLevelClass {
public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| {
LAZY_super<TopLevelClass>
}
public? open? override [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK }
}
public? final? [ResolvedTo(TYPES)] fun resolveMe(): R|kotlin/Unit| { LAZY_BLOCK }
STATUS:
FILE: [ResolvedTo(IMPORTS)] localNestedClass.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<R|kotlin/Any|>
}
public? open [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK }
public? open [ResolvedTo(RAW_FIR)] fun boo([ResolvedTo(RAW_FIR)] b: String): R|kotlin/Unit| { LAZY_BLOCK }
}
public? open [ResolvedTo(RAW_FIR)] class AnotherTopLevelClass : TopLevelClass {
public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| {
LAZY_super<TopLevelClass>
}
public? open? override [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK }
}
public final [ResolvedTo(STATUS)] fun resolveMe(): R|kotlin/Unit| { LAZY_BLOCK }
EXPECT_ACTUAL_MATCHING:
FILE: [ResolvedTo(IMPORTS)] localNestedClass.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<R|kotlin/Any|>
}
public? open [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK }
public? open [ResolvedTo(RAW_FIR)] fun boo([ResolvedTo(RAW_FIR)] b: String): R|kotlin/Unit| { LAZY_BLOCK }
}
public? open [ResolvedTo(RAW_FIR)] class AnotherTopLevelClass : TopLevelClass {
public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| {
LAZY_super<TopLevelClass>
}
public? open? override [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK }
}
public final [ResolvedTo(EXPECT_ACTUAL_MATCHING)] fun resolveMe(): R|kotlin/Unit| { LAZY_BLOCK }
ARGUMENTS_OF_ANNOTATIONS:
FILE: [ResolvedTo(IMPORTS)] localNestedClass.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<R|kotlin/Any|>
}
public? open [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK }
public? open [ResolvedTo(RAW_FIR)] fun boo([ResolvedTo(RAW_FIR)] b: String): R|kotlin/Unit| { LAZY_BLOCK }
}
public? open [ResolvedTo(RAW_FIR)] class AnotherTopLevelClass : TopLevelClass {
public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| {
LAZY_super<TopLevelClass>
}
public? open? override [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK }
}
public final [ResolvedTo(ARGUMENTS_OF_ANNOTATIONS)] fun resolveMe(): R|kotlin/Unit| { LAZY_BLOCK }
CONTRACTS:
FILE: [ResolvedTo(IMPORTS)] localNestedClass.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<R|kotlin/Any|>
}
public? open [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK }
public? open [ResolvedTo(RAW_FIR)] fun boo([ResolvedTo(RAW_FIR)] b: String): R|kotlin/Unit| { LAZY_BLOCK }
}
public? open [ResolvedTo(RAW_FIR)] class AnotherTopLevelClass : TopLevelClass {
public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| {
LAZY_super<TopLevelClass>
}
public? open? override [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK }
}
public final [ResolvedTo(CONTRACTS)] fun resolveMe(): R|kotlin/Unit| {
local final? [ResolvedTo(RAW_FIR)] class LocalClass : AnotherTopLevelClass {
public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=LocalClass] constructor(): R|LocalClass| {
super<AnotherTopLevelClass>()
}
public? open? override [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| {
}
local final? [ResolvedTo(RAW_FIR)] [ContainingClassKey=LocalClass] class NestedLocalClass : R|kotlin/Any| {
public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=NestedLocalClass] constructor(): R|LocalClass.NestedLocalClass| {
super<R|kotlin/Any|>()
}
}
}
}
IMPLICIT_TYPES_BODY_RESOLVE:
FILE: [ResolvedTo(IMPORTS)] localNestedClass.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<R|kotlin/Any|>
}
public? open [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK }
public? open [ResolvedTo(RAW_FIR)] fun boo([ResolvedTo(RAW_FIR)] b: String): R|kotlin/Unit| { LAZY_BLOCK }
}
public? open [ResolvedTo(RAW_FIR)] class AnotherTopLevelClass : TopLevelClass {
public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| {
LAZY_super<TopLevelClass>
}
public? open? override [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK }
}
public final [ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] fun resolveMe(): R|kotlin/Unit| {
local final? [ResolvedTo(RAW_FIR)] class LocalClass : AnotherTopLevelClass {
public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=LocalClass] constructor(): R|LocalClass| {
super<AnotherTopLevelClass>()
}
public? open? override [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| {
}
local final? [ResolvedTo(RAW_FIR)] [ContainingClassKey=LocalClass] class NestedLocalClass : R|kotlin/Any| {
public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=NestedLocalClass] constructor(): R|LocalClass.NestedLocalClass| {
super<R|kotlin/Any|>()
}
}
}
}
ANNOTATIONS_ARGUMENTS_MAPPING:
FILE: [ResolvedTo(IMPORTS)] localNestedClass.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<R|kotlin/Any|>
}
public? open [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK }
public? open [ResolvedTo(RAW_FIR)] fun boo([ResolvedTo(RAW_FIR)] b: String): R|kotlin/Unit| { LAZY_BLOCK }
}
public? open [ResolvedTo(RAW_FIR)] class AnotherTopLevelClass : TopLevelClass {
public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| {
LAZY_super<TopLevelClass>
}
public? open? override [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| { LAZY_BLOCK }
}
public final [ResolvedTo(ANNOTATIONS_ARGUMENTS_MAPPING)] fun resolveMe(): R|kotlin/Unit| {
local final? [ResolvedTo(RAW_FIR)] class LocalClass : AnotherTopLevelClass {
public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=LocalClass] constructor(): R|LocalClass| {
super<AnotherTopLevelClass>()
}
public? open? override [ResolvedTo(RAW_FIR)] fun foo([ResolvedTo(RAW_FIR)] i: Int): R|kotlin/Unit| {
}
local final? [ResolvedTo(RAW_FIR)] [ContainingClassKey=LocalClass] class NestedLocalClass : R|kotlin/Any| {
public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=NestedLocalClass] constructor(): R|LocalClass.NestedLocalClass| {
super<R|kotlin/Any|>()
}
}
}
}
BODY_RESOLVE:
FILE: [ResolvedTo(IMPORTS)] localNestedClass.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<R|kotlin/Any|>
}
public open [ResolvedTo(STATUS)] fun foo([ResolvedTo(STATUS)] i: R|kotlin/Int|): R|kotlin/Unit| { LAZY_BLOCK }
public open [ResolvedTo(STATUS)] fun boo([ResolvedTo(STATUS)] b: R|kotlin/String|): R|kotlin/Unit| { LAZY_BLOCK }
}
public open [ResolvedTo(STATUS)] class AnotherTopLevelClass : R|TopLevelClass| {
public [ResolvedTo(STATUS)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| {
LAZY_super<R|TopLevelClass|>
}
public open override [ResolvedTo(STATUS)] fun foo([ResolvedTo(STATUS)] i: R|kotlin/Int|): R|kotlin/Unit| { LAZY_BLOCK }
}
public final [ResolvedTo(BODY_RESOLVE)] fun resolveMe(): R|kotlin/Unit| {
local final [ResolvedTo(BODY_RESOLVE)] class LocalClass : R|AnotherTopLevelClass| {
public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=LocalClass] constructor(): R|LocalClass| {
super<R|AnotherTopLevelClass|>()
}
public open override [ResolvedTo(BODY_RESOLVE)] fun foo([ResolvedTo(BODY_RESOLVE)] i: R|kotlin/Int|): R|kotlin/Unit| {
}
local final [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=LocalClass] class NestedLocalClass : R|kotlin/Any| {
public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=NestedLocalClass] constructor(): R|LocalClass.NestedLocalClass| {
super<R|kotlin/Any|>()
}
}
}
}
FILE RAW TO BODY:
FILE: [ResolvedTo(IMPORTS)] localNestedClass.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<R|kotlin/Any|>()
}
public open [ResolvedTo(BODY_RESOLVE)] fun foo([ResolvedTo(BODY_RESOLVE)] i: R|kotlin/Int|): R|kotlin/Unit| {
}
public open [ResolvedTo(BODY_RESOLVE)] fun boo([ResolvedTo(BODY_RESOLVE)] b: R|kotlin/String|): R|kotlin/Unit| {
}
}
public open [ResolvedTo(BODY_RESOLVE)] class AnotherTopLevelClass : R|TopLevelClass| {
public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=AnotherTopLevelClass] constructor(): R|AnotherTopLevelClass| {
super<R|TopLevelClass|>()
}
public open override [ResolvedTo(BODY_RESOLVE)] fun foo([ResolvedTo(BODY_RESOLVE)] i: R|kotlin/Int|): R|kotlin/Unit| {
}
}
public final [ResolvedTo(BODY_RESOLVE)] fun resolveMe(): R|kotlin/Unit| {
local final [ResolvedTo(BODY_RESOLVE)] class LocalClass : R|AnotherTopLevelClass| {
public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=LocalClass] constructor(): R|LocalClass| {
super<R|AnotherTopLevelClass|>()
}
public open override [ResolvedTo(BODY_RESOLVE)] fun foo([ResolvedTo(BODY_RESOLVE)] i: R|kotlin/Int|): R|kotlin/Unit| {
}
local final [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=LocalClass] class NestedLocalClass : R|kotlin/Any| {
public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=NestedLocalClass] constructor(): R|LocalClass.NestedLocalClass| {
super<R|kotlin/Any|>()
}
}
}
}
@@ -198,6 +198,12 @@ public class FirOutOfContentRootLazyDeclarationResolveTestGenerated extends Abst
runTest("analysis/low-level-api-fir/testdata/lazyResolve/lazyProperty.kt");
}
@Test
@TestMetadata("localNestedClass.kt")
public void testLocalNestedClass() throws Exception {
runTest("analysis/low-level-api-fir/testdata/lazyResolve/localNestedClass.kt");
}
@Test
@TestMetadata("parameterOfNonLocalSetter.kt")
public void testParameterOfNonLocalSetter() throws Exception {
@@ -198,6 +198,12 @@ public class FirSourceLazyDeclarationResolveTestGenerated extends AbstractFirSou
runTest("analysis/low-level-api-fir/testdata/lazyResolve/lazyProperty.kt");
}
@Test
@TestMetadata("localNestedClass.kt")
public void testLocalNestedClass() throws Exception {
runTest("analysis/low-level-api-fir/testdata/lazyResolve/localNestedClass.kt");
}
@Test
@TestMetadata("parameterOfNonLocalSetter.kt")
public void testParameterOfNonLocalSetter() throws Exception {
@@ -43,6 +43,8 @@ import org.jetbrains.kotlin.fir.visitors.FirTransformer
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.types.model.TypeArgumentMarker
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
class FirSupertypeResolverProcessor(session: FirSession, scopeSession: ScopeSession) : FirTransformerBasedResolveProcessor(
session, scopeSession, FirResolvePhase.SUPER_TYPES
@@ -81,7 +83,7 @@ fun <F : FirClassLikeDeclaration> F.runSupertypeResolvePhaseForLocalClass(
useSiteFile: FirFile,
containingDeclarations: List<FirDeclaration>,
): F {
val supertypeComputationSession = SupertypeComputationSession()
val supertypeComputationSession = SupertypeComputationSessionForLocalClasses()
val supertypeResolverVisitor = FirSupertypeResolverVisitor(
session, supertypeComputationSession, scopeSession,
currentScopeList.toPersistentList(),
@@ -97,6 +99,41 @@ fun <F : FirClassLikeDeclaration> F.runSupertypeResolvePhaseForLocalClass(
return this.transform<F, Nothing?>(applySupertypesTransformer, null)
}
/**
* We should resolve non-local classes to [FirResolvePhase.SUPER_TYPES] explicitly
* to avoid unsafe access to unresolved super type references
*
* Example:
* ```
* open class TopLevelClass
* open class AnotherTopLevelClass : TopLevelClass()
*
* fun resolveMe() {
* class LocalClass : AnotherTopLevelClass() {
* class NestedLocalClass
* }
* }
* ```
*
* During the resolution of local classes, in the best case, we will only try
* to access the unresolved super type reference of "AnotherTopLevelClass" that is unsafe in the context of parallel resolution.
* In the worst case, from NestedLocalClass we will visit the entire hierarchy of "LocalClass"
*/
private class SupertypeComputationSessionForLocalClasses : SupertypeComputationSession() {
override fun getResolvedSuperTypeRefsForOutOfSessionDeclaration(classLikeDeclaration: FirClassLikeDeclaration): List<FirResolvedTypeRef>? {
classLikeDeclaration.lazyResolveToPhase(FirResolvePhase.SUPER_TYPES)
return super.getResolvedSuperTypeRefsForOutOfSessionDeclaration(classLikeDeclaration)
}
override fun supertypeRefs(declaration: FirClassLikeDeclaration): List<FirTypeRef> {
if (!declaration.isLocal) {
declaration.lazyResolveToPhase(FirResolvePhase.SUPER_TYPES)
}
return super.supertypeRefs(declaration)
}
}
private class FirApplySupertypesTransformer(
private val supertypeComputationSession: SupertypeComputationSession,
private val session: FirSession,
@@ -285,16 +322,10 @@ class FirSupertypeResolverVisitor(
if (supertype !is ConeClassLikeType) continue
val supertypeModuleSession = supertype.toSymbol(session)?.moduleData?.session ?: continue
val fir = supertype.lookupTag.toSymbol(supertypeModuleSession)?.fir ?: continue
resolveAllSupertypes(fir, fir.supertypeRefs(), visited)
resolveAllSupertypes(fir, supertypeComputationSession.supertypeRefs(fir), visited)
}
}
private fun FirClassLikeDeclaration.supertypeRefs() = when (this) {
is FirRegularClass -> superTypeRefs
is FirTypeAlias -> listOf(expandedTypeRef)
else -> emptyList()
}
private fun prepareScopes(classLikeDeclaration: FirClassLikeDeclaration): PersistentList<FirScope> {
val classId = classLikeDeclaration.symbol.classId
val classModuleSession = classLikeDeclaration.moduleData.session
@@ -580,6 +611,12 @@ open class SupertypeComputationSession {
else -> null
}
internal open fun supertypeRefs(declaration: FirClassLikeDeclaration): List<FirTypeRef> = when (declaration) {
is FirRegularClass -> declaration.superTypeRefs
is FirTypeAlias -> listOf(declaration.expandedTypeRef)
else -> emptyList()
}
/**
* @param declaration declaration to be checked for loops
* @param visited visited declarations during the current loop search
@@ -725,7 +762,6 @@ open class SupertypeComputationSession {
}
}
sealed class SupertypeComputationStatus {
object NotComputed : SupertypeComputationStatus()
object Computing : SupertypeComputationStatus()