[LL FIR] calculate designation path by FirFile where it is possible
This will fix problems with declaration clash. Otherwise, a designation path to the constructor of the second class from the snippet ``` class A class A ``` Will contain the first class instead of the second Also, this is more performed than trying to find a segment of a path by providers ^KT-58546 Fixed
This commit is contained in:
committed by
Space Team
parent
ae88726fae
commit
b3aa2dd60f
+19
@@ -116,11 +116,30 @@ private fun collectDesignationPath(target: FirElementWithResolveState): List<Fir
|
||||
}
|
||||
}
|
||||
|
||||
private fun collectDesignationPathWithContainingClassByFirFile(
|
||||
firFile: FirFile,
|
||||
containingClassId: ClassId,
|
||||
target: FirDeclaration,
|
||||
): List<FirRegularClass>? = FirElementFinder.findClassPathToDeclaration(
|
||||
firFile = firFile,
|
||||
declarationContainerClassId = containingClassId,
|
||||
targetMemberDeclaration = target,
|
||||
)
|
||||
|
||||
private fun collectDesignationPathWithContainingClass(target: FirDeclaration, containingClassId: ClassId): List<FirRegularClass>? {
|
||||
if (containingClassId.isLocal) {
|
||||
return null
|
||||
}
|
||||
|
||||
val firFile = target.getContainingFile()
|
||||
if (firFile != null && firFile.packageFqName == containingClassId.packageFqName) {
|
||||
// We should do fallback to the heavy implementation if something goes wrong.
|
||||
// For example, we can't be able to find an on-air declaration by this way
|
||||
collectDesignationPathWithContainingClassByFirFile(firFile, containingClassId, target)?.let {
|
||||
return it
|
||||
}
|
||||
}
|
||||
|
||||
val useSiteSession = getTargetSession(target)
|
||||
|
||||
fun resolveChunk(classId: ClassId): FirRegularClass {
|
||||
|
||||
+28
-15
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.analysis.low.level.api.fir.transformers
|
||||
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirResolveTarget
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirSingleResolveTarget
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.asResolveTarget
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.tryCollectDesignationWithFile
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLockProvider
|
||||
@@ -26,7 +27,6 @@ import org.jetbrains.kotlin.fir.resolve.transformers.SupertypeComputationSession
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.SupertypeComputationStatus
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirTowerDataContextCollector
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.platformSupertypeUpdater
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
@@ -86,6 +86,12 @@ private class LLFirSuperTypeTargetResolver(
|
||||
// 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) {
|
||||
outerClass.asResolveTarget()?.let { resolveTarget ->
|
||||
// It is possible in case of declaration collision,
|
||||
// so we need this logic only to be sure that [outerClass] is resolved
|
||||
resolveToSupertypePhase(resolveTarget)
|
||||
}
|
||||
|
||||
LLFirSupertypeLazyResolver.checkIsResolved(outerClass)
|
||||
}
|
||||
}
|
||||
@@ -181,6 +187,25 @@ private class LLFirSuperTypeTargetResolver(
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirClassLikeDeclaration.asResolveTarget(): LLFirSingleResolveTarget? {
|
||||
return takeIf { it.canHaveLoopInSupertypesHierarchy(session, forceSkipResolvedClasses = true) }
|
||||
?.tryCollectDesignationWithFile()
|
||||
?.asResolveTarget()
|
||||
}
|
||||
|
||||
private fun resolveToSupertypePhase(target: LLFirSingleResolveTarget) {
|
||||
LLFirSuperTypeTargetResolver(
|
||||
target = target,
|
||||
lockProvider = lockProvider,
|
||||
session = session,
|
||||
scopeSession = scopeSession,
|
||||
supertypeComputationSession = supertypeComputationSession,
|
||||
visitedElements = visitedElements,
|
||||
).resolveDesignation()
|
||||
|
||||
LLFirLazyPhaseResolverByPhase.getByPhase(resolverPhase).checkIsResolved(target)
|
||||
}
|
||||
|
||||
/**
|
||||
* We want to apply resolved supertypes to as many designations as possible.
|
||||
* So we crawl the resolved supertypes of visited designations to find more designations to collect.
|
||||
@@ -205,21 +230,9 @@ private class LLFirSuperTypeTargetResolver(
|
||||
return
|
||||
}
|
||||
|
||||
val resolveTarget = classLikeDeclaration.takeIf { it.canHaveLoopInSupertypesHierarchy(session, forceSkipResolvedClasses = true) }
|
||||
?.tryCollectDesignationWithFile()
|
||||
?.asResolveTarget()
|
||||
|
||||
val resolveTarget = classLikeDeclaration.asResolveTarget()
|
||||
if (resolveTarget != null) {
|
||||
LLFirSuperTypeTargetResolver(
|
||||
target = resolveTarget,
|
||||
lockProvider = lockProvider,
|
||||
session = session,
|
||||
scopeSession = scopeSession,
|
||||
supertypeComputationSession = supertypeComputationSession,
|
||||
visitedElements = visitedElements,
|
||||
).resolveDesignation()
|
||||
|
||||
LLFirLazyPhaseResolverByPhase.getByPhase(resolverPhase).checkIsResolved(resolveTarget)
|
||||
resolveToSupertypePhase(resolveTarget)
|
||||
} else if (type is ConeClassLikeType) {
|
||||
// The `classLikeDeclaration` is not associated with a file, and thus there is no need to resolve it, but it may still point
|
||||
// to declarations via its type arguments which need to be collected and have a containing file.
|
||||
|
||||
+1
-3
@@ -126,13 +126,11 @@ private class LLFirTypeTargetResolver(
|
||||
override fun doLazyResolveUnderLock(target: FirElementWithResolveState) {
|
||||
when (target) {
|
||||
is FirConstructor -> {
|
||||
// TODO: should be uncommented after KT-58546
|
||||
// error("Shoul be resolved during ${::resolveConstructors.name}")
|
||||
error("Should be resolved during ${::resolveConstructors.name}")
|
||||
}
|
||||
is FirDanglingModifierList, is FirFileAnnotationsContainer, is FirCallableDeclaration, is FirTypeAlias, is FirScript -> {
|
||||
target.accept(transformer, null)
|
||||
}
|
||||
|
||||
is FirRegularClass -> {
|
||||
resolveClassTypes(target)
|
||||
}
|
||||
|
||||
+54
-8
@@ -15,7 +15,30 @@ import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
|
||||
object FirElementFinder {
|
||||
fun findClassifierWithClassId(firFile: FirFile, classId: ClassId): FirClassLikeDeclaration? {
|
||||
fun findClassifierWithClassId(
|
||||
firFile: FirFile,
|
||||
classId: ClassId,
|
||||
): FirClassLikeDeclaration? = findPathToClassifierWithClassId(
|
||||
firFile = firFile,
|
||||
classId = classId,
|
||||
expectedMemberDeclaration = null
|
||||
)?.second
|
||||
|
||||
fun findClassPathToDeclaration(
|
||||
firFile: FirFile,
|
||||
declarationContainerClassId: ClassId,
|
||||
targetMemberDeclaration: FirDeclaration,
|
||||
): List<FirRegularClass>? = findPathToClassifierWithClassId(
|
||||
firFile = firFile,
|
||||
classId = declarationContainerClassId,
|
||||
expectedMemberDeclaration = targetMemberDeclaration
|
||||
)?.first
|
||||
|
||||
private fun findPathToClassifierWithClassId(
|
||||
firFile: FirFile,
|
||||
classId: ClassId,
|
||||
expectedMemberDeclaration: FirDeclaration?,
|
||||
): Pair<List<FirRegularClass>, FirClassLikeDeclaration>? {
|
||||
requireWithAttachmentBuilder(!classId.isLocal, { "ClassId should not be local" }) {
|
||||
withEntry("classId", classId) { it.asString() }
|
||||
}
|
||||
@@ -28,33 +51,56 @@ object FirElementFinder {
|
||||
}
|
||||
|
||||
val classIdPathSegment = classId.relativeClassName.pathSegments()
|
||||
val path = ArrayList<FirRegularClass>(classIdPathSegment.size)
|
||||
var result: FirClassLikeDeclaration? = null
|
||||
|
||||
fun find(declarations: Iterable<FirDeclaration>, classIdPathIndex: Int) {
|
||||
if (result != null) return
|
||||
fun find(declarations: Iterable<FirDeclaration>, classIdPathIndex: Int): Boolean {
|
||||
val currentClassSegment = classIdPathSegment[classIdPathIndex]
|
||||
|
||||
for (subDeclaration in declarations) {
|
||||
if (subDeclaration is FirScript) {
|
||||
val scriptDeclarations = subDeclaration.statements.asSequence().filterIsInstance<FirDeclaration>()
|
||||
find(scriptDeclarations.asIterable(), classIdPathIndex)
|
||||
if (find(scriptDeclarations.asIterable(), classIdPathIndex)) {
|
||||
return true
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if (subDeclaration is FirClassLikeDeclaration && currentClassSegment == subDeclaration.symbol.name) {
|
||||
if (classIdPathIndex == classIdPathSegment.lastIndex) {
|
||||
result = subDeclaration
|
||||
return
|
||||
if (expectedMemberDeclaration == null ||
|
||||
subDeclaration is FirRegularClass && expectedMemberDeclaration in subDeclaration.declarations
|
||||
) {
|
||||
if (subDeclaration is FirRegularClass) {
|
||||
path += subDeclaration
|
||||
}
|
||||
|
||||
result = subDeclaration
|
||||
return true
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if (subDeclaration is FirRegularClass) {
|
||||
find(subDeclaration.declarations, classIdPathIndex + 1)
|
||||
path += subDeclaration
|
||||
if (find(subDeclaration.declarations, classIdPathIndex + 1)) {
|
||||
return true
|
||||
}
|
||||
|
||||
path.removeLast()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
find(firFile.declarations, classIdPathIndex = 0)
|
||||
return result
|
||||
return result?.let {
|
||||
(path as List<FirRegularClass>) to it
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified E : FirElement> findElementIn(
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
// MEMBER_CLASS_FILTER: org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
|
||||
sealed class A
|
||||
|
||||
class B : A()
|
||||
|
||||
interface C : A
|
||||
|
||||
interface D : C, A
|
||||
|
||||
class E : B, A()
|
||||
|
||||
sealed class P {
|
||||
object H: P()
|
||||
class J : P()
|
||||
|
||||
object T {
|
||||
object V : P()
|
||||
class M : P()
|
||||
}
|
||||
|
||||
val p: P = object : P() {
|
||||
|
||||
}
|
||||
|
||||
val r = object : P() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class K : P()
|
||||
|
||||
object B {
|
||||
class <caret>I : P()
|
||||
}
|
||||
|
||||
fun test() {
|
||||
class L : P()
|
||||
val a = object : P() {
|
||||
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -65,13 +65,13 @@ FILE: [ResolvedTo(IMPORTS)] redeclaration.kt
|
||||
SUPER_TYPES:
|
||||
FILE: [ResolvedTo(IMPORTS)] redeclaration.kt
|
||||
[ResolvedTo(RAW_FIR)] annotations container
|
||||
public? final? [ResolvedTo(SUPER_TYPES)] class A : R|kotlin/Any| {
|
||||
public? final? [ResolvedTo(RAW_FIR)] class A : R|kotlin/Any| {
|
||||
public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=A] constructor(): R|A| {
|
||||
LAZY_super<R|kotlin/Any|>
|
||||
}
|
||||
|
||||
}
|
||||
public? final? [ResolvedTo(RAW_FIR)] class A : R|kotlin/Any| {
|
||||
public? final? [ResolvedTo(SUPER_TYPES)] class A : R|kotlin/Any| {
|
||||
public? [ResolvedTo(SUPER_TYPES)] [ContainingClassKey=A] constructor(): R|A| {
|
||||
LAZY_super<R|kotlin/Any|>
|
||||
}
|
||||
@@ -81,13 +81,13 @@ FILE: [ResolvedTo(IMPORTS)] redeclaration.kt
|
||||
TYPES:
|
||||
FILE: [ResolvedTo(IMPORTS)] redeclaration.kt
|
||||
[ResolvedTo(RAW_FIR)] annotations container
|
||||
public? final? [ResolvedTo(TYPES)] class A : R|kotlin/Any| {
|
||||
public? [ResolvedTo(TYPES)] [ContainingClassKey=A] constructor(): R|A| {
|
||||
public? final? [ResolvedTo(RAW_FIR)] class A : R|kotlin/Any| {
|
||||
public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=A] constructor(): R|A| {
|
||||
LAZY_super<R|kotlin/Any|>
|
||||
}
|
||||
|
||||
}
|
||||
public? final? [ResolvedTo(RAW_FIR)] class A : R|kotlin/Any| {
|
||||
public? final? [ResolvedTo(TYPES)] class A : R|kotlin/Any| {
|
||||
public? [ResolvedTo(TYPES)] [ContainingClassKey=A] constructor(): R|A| {
|
||||
LAZY_super<R|kotlin/Any|>
|
||||
}
|
||||
@@ -97,13 +97,13 @@ FILE: [ResolvedTo(IMPORTS)] redeclaration.kt
|
||||
STATUS:
|
||||
FILE: [ResolvedTo(IMPORTS)] redeclaration.kt
|
||||
[ResolvedTo(RAW_FIR)] annotations container
|
||||
public final [ResolvedTo(STATUS)] class A : R|kotlin/Any| {
|
||||
public [ResolvedTo(STATUS)] [ContainingClassKey=A] constructor(): R|A| {
|
||||
public? final? [ResolvedTo(RAW_FIR)] class A : R|kotlin/Any| {
|
||||
public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=A] constructor(): R|A| {
|
||||
LAZY_super<R|kotlin/Any|>
|
||||
}
|
||||
|
||||
}
|
||||
public? final? [ResolvedTo(RAW_FIR)] class A : R|kotlin/Any| {
|
||||
public final [ResolvedTo(STATUS)] class A : R|kotlin/Any| {
|
||||
public [ResolvedTo(STATUS)] [ContainingClassKey=A] constructor(): R|A| {
|
||||
LAZY_super<R|kotlin/Any|>
|
||||
}
|
||||
@@ -113,13 +113,13 @@ FILE: [ResolvedTo(IMPORTS)] redeclaration.kt
|
||||
EXPECT_ACTUAL_MATCHING:
|
||||
FILE: [ResolvedTo(IMPORTS)] redeclaration.kt
|
||||
[ResolvedTo(RAW_FIR)] annotations container
|
||||
public final [ResolvedTo(STATUS)] class A : R|kotlin/Any| {
|
||||
public [ResolvedTo(STATUS)] [ContainingClassKey=A] constructor(): R|A| {
|
||||
public? final? [ResolvedTo(RAW_FIR)] class A : R|kotlin/Any| {
|
||||
public? [ResolvedTo(RAW_FIR)] [ContainingClassKey=A] constructor(): R|A| {
|
||||
LAZY_super<R|kotlin/Any|>
|
||||
}
|
||||
|
||||
}
|
||||
public? final? [ResolvedTo(RAW_FIR)] class A : R|kotlin/Any| {
|
||||
public final [ResolvedTo(STATUS)] class A : R|kotlin/Any| {
|
||||
public [ResolvedTo(EXPECT_ACTUAL_MATCHING)] [ContainingClassKey=A] constructor(): R|A| {
|
||||
LAZY_super<R|kotlin/Any|>
|
||||
}
|
||||
@@ -135,7 +135,7 @@ FILE: [ResolvedTo(IMPORTS)] redeclaration.kt
|
||||
}
|
||||
|
||||
}
|
||||
public? final? [ResolvedTo(RAW_FIR)] class A : R|kotlin/Any| {
|
||||
public final [ResolvedTo(STATUS)] class A : R|kotlin/Any| {
|
||||
public [ResolvedTo(ARGUMENTS_OF_ANNOTATIONS)] [ContainingClassKey=A] constructor(): R|A| {
|
||||
LAZY_super<R|kotlin/Any|>
|
||||
}
|
||||
@@ -151,7 +151,7 @@ FILE: [ResolvedTo(IMPORTS)] redeclaration.kt
|
||||
}
|
||||
|
||||
}
|
||||
public? final? [ResolvedTo(RAW_FIR)] class A : R|kotlin/Any| {
|
||||
public final [ResolvedTo(STATUS)] class A : R|kotlin/Any| {
|
||||
public [ResolvedTo(CONTRACTS)] [ContainingClassKey=A] constructor(): R|A| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
@@ -167,7 +167,7 @@ FILE: [ResolvedTo(IMPORTS)] redeclaration.kt
|
||||
}
|
||||
|
||||
}
|
||||
public? final? [ResolvedTo(RAW_FIR)] class A : R|kotlin/Any| {
|
||||
public final [ResolvedTo(STATUS)] class A : R|kotlin/Any| {
|
||||
public [ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] [ContainingClassKey=A] constructor(): R|A| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
@@ -183,7 +183,7 @@ FILE: [ResolvedTo(IMPORTS)] redeclaration.kt
|
||||
}
|
||||
|
||||
}
|
||||
public? final? [ResolvedTo(RAW_FIR)] class A : R|kotlin/Any| {
|
||||
public final [ResolvedTo(STATUS)] class A : R|kotlin/Any| {
|
||||
public [ResolvedTo(ANNOTATIONS_ARGUMENTS_MAPPING)] [ContainingClassKey=A] constructor(): R|A| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
@@ -199,7 +199,7 @@ FILE: [ResolvedTo(IMPORTS)] redeclaration.kt
|
||||
}
|
||||
|
||||
}
|
||||
public? final? [ResolvedTo(RAW_FIR)] class A : R|kotlin/Any| {
|
||||
public final [ResolvedTo(STATUS)] class A : R|kotlin/Any| {
|
||||
public [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=A] constructor(): R|A| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
+6
@@ -84,6 +84,12 @@ public class FirOutOfContentRootLazyDeclarationResolveTestGenerated extends Abst
|
||||
runTest("analysis/low-level-api-fir/testdata/lazyResolve/complexLocalHierarchy.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("complexRedeclaration.kt")
|
||||
public void testComplexRedeclaration() throws Exception {
|
||||
runTest("analysis/low-level-api-fir/testdata/lazyResolve/complexRedeclaration.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("cyclicHierarchy.kt")
|
||||
public void testCyclicHierarchy() throws Exception {
|
||||
|
||||
+6
@@ -84,6 +84,12 @@ public class FirSourceLazyDeclarationResolveTestGenerated extends AbstractFirSou
|
||||
runTest("analysis/low-level-api-fir/testdata/lazyResolve/complexLocalHierarchy.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("complexRedeclaration.kt")
|
||||
public void testComplexRedeclaration() throws Exception {
|
||||
runTest("analysis/low-level-api-fir/testdata/lazyResolve/complexRedeclaration.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("cyclicHierarchy.kt")
|
||||
public void testCyclicHierarchy() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user