[LL FIR] designation refactoring
Collect `FirDesignation` by default with `FirFile` instead of just a separate path and additional repeated logic around ^KT-65344
This commit is contained in:
committed by
Space Team
parent
47e8d987b9
commit
8f987644ab
+46
-47
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.llFirMo
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.nullableJavaSymbolProvider
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirLibraryOrLibrarySourceResolvableModuleSession
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.FirElementFinder
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.containingClassIdOrNull
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.getContainingFile
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.isLocalForLazyResolutionPurposes
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.unwrapCopy
|
||||
@@ -25,13 +26,13 @@ import org.jetbrains.kotlin.fir.declarations.utils.isLocal
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirScriptSymbol
|
||||
import org.jetbrains.kotlin.fir.utils.exceptions.withFirEntry
|
||||
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtScript
|
||||
import org.jetbrains.kotlin.utils.exceptions.ExceptionAttachmentBuilder
|
||||
import org.jetbrains.kotlin.utils.exceptions.checkWithAttachment
|
||||
@@ -118,7 +119,7 @@ fun FirDesignation.toSequence(includeTarget: Boolean): Sequence<FirElementWithRe
|
||||
if (includeTarget) yield(target)
|
||||
}
|
||||
|
||||
private fun collectDesignationPath(target: FirElementWithResolveState): List<FirDeclaration>? {
|
||||
private fun tryCollectDesignation(providedFile: FirFile?, target: FirElementWithResolveState): FirDesignation? {
|
||||
when (target) {
|
||||
is FirSimpleFunction,
|
||||
is FirProperty,
|
||||
@@ -132,14 +133,14 @@ private fun collectDesignationPath(target: FirElementWithResolveState): List<Fir
|
||||
|
||||
// We shouldn't try to build a designation path for such fake declarations as they
|
||||
// do not depend on outer classes during resolution
|
||||
if (target.isCopyCreatedInScope) return emptyList()
|
||||
if (target.isCopyCreatedInScope) return FirDesignation(target)
|
||||
|
||||
if (target.symbol.isLocalForLazyResolutionPurposes) {
|
||||
return null
|
||||
}
|
||||
|
||||
val containingClassId = target.containingClassLookupTag()?.classId
|
||||
return collectDesignationPathWithContainingClass(target, containingClassId)
|
||||
return collectDesignationPathWithContainingClass(providedFile, target, containingClassId)
|
||||
}
|
||||
|
||||
is FirClassLikeDeclaration -> {
|
||||
@@ -148,55 +149,58 @@ private fun collectDesignationPath(target: FirElementWithResolveState): List<Fir
|
||||
}
|
||||
|
||||
val containingClassId = target.symbol.classId.outerClassId
|
||||
return collectDesignationPathWithContainingClass(target, containingClassId)
|
||||
return collectDesignationPathWithContainingClass(providedFile, target, containingClassId)
|
||||
}
|
||||
|
||||
is FirDanglingModifierList -> {
|
||||
val containingClassId = target.containingClass()?.classId
|
||||
return collectDesignationPathWithContainingClass(target, containingClassId)
|
||||
return collectDesignationPathWithContainingClass(providedFile, target, containingClassId)
|
||||
}
|
||||
|
||||
is FirAnonymousInitializer -> {
|
||||
val containingDeclarationSymbol = target.containingDeclarationSymbol
|
||||
return when (containingDeclarationSymbol) {
|
||||
is FirScriptSymbol -> listOf(containingDeclarationSymbol.fir)
|
||||
is FirClassSymbol<*> -> collectDesignationPathWithContainingClass(target, containingDeclarationSymbol.classId)
|
||||
else -> null
|
||||
}
|
||||
val containingClassId = target.containingClassIdOrNull()
|
||||
return collectDesignationPathWithContainingClass(providedFile, target, containingClassId)
|
||||
}
|
||||
|
||||
is FirFileAnnotationsContainer -> return FirDesignation(path = listOf(target.containingFileSymbol.fir), target = target)
|
||||
is FirScript, is FirCodeFragment -> {
|
||||
requireIsInstance<FirDeclaration>(target)
|
||||
|
||||
return collectDesignationPathWithContainingClass(providedFile, target, containingClassId = null)
|
||||
}
|
||||
|
||||
is FirScript, is FirCodeFragment, is FirFileAnnotationsContainer -> return emptyList()
|
||||
else -> return null
|
||||
}
|
||||
}
|
||||
|
||||
private fun collectDesignationPathWithContainingClassByFirFile(
|
||||
firFile: FirFile,
|
||||
containingClassId: ClassId?,
|
||||
private fun collectDesignationPathWithContainingClass(
|
||||
providedFile: FirFile?,
|
||||
target: FirDeclaration,
|
||||
): List<FirDeclaration>? = FirElementFinder.findClassPathToDeclaration(
|
||||
firFile = firFile,
|
||||
declarationContainerClassId = containingClassId,
|
||||
targetMemberDeclaration = target,
|
||||
)
|
||||
|
||||
private fun collectDesignationPathWithContainingClass(target: FirDeclaration, containingClassId: ClassId?): List<FirDeclaration>? {
|
||||
containingClassId: ClassId?,
|
||||
): FirDesignation? {
|
||||
if (containingClassId?.isLocal == true) {
|
||||
return null
|
||||
}
|
||||
|
||||
val firFile = target.getContainingFile()
|
||||
if (firFile != null && (containingClassId == null || firFile.packageFqName == containingClassId.packageFqName)) {
|
||||
val designationPath = collectDesignationPathWithContainingClassByFirFile(firFile, containingClassId, target)
|
||||
val file = providedFile ?: target.getContainingFile()
|
||||
if (file != null && (containingClassId == null || file.packageFqName == containingClassId.packageFqName)) {
|
||||
val designationPath = FirElementFinder.collectDesignationPath(
|
||||
firFile = file,
|
||||
declarationContainerClassId = containingClassId,
|
||||
targetMemberDeclaration = target,
|
||||
)
|
||||
|
||||
if (designationPath != null) {
|
||||
return designationPath
|
||||
}
|
||||
}
|
||||
|
||||
val fallbackClassPath = collectDesignationPathWithContainingClassFallback(target, containingClassId)
|
||||
val firScript = firFile?.declarations?.singleOrNull() as? FirScript
|
||||
val fallbackPath = listOfNotNull(firScript) + fallbackClassPath.orEmpty()
|
||||
return patchDesignationPathIfNeeded(target, fallbackPath)
|
||||
val fallbackFile = providedFile ?: fallbackClassPath?.lastOrNull()?.getContainingFile() ?: file
|
||||
val fallbackScript = fallbackFile?.declarations?.singleOrNull() as? FirScript
|
||||
val fallbackPath = listOfNotNull(fallbackFile, fallbackScript) + fallbackClassPath.orEmpty()
|
||||
val patchedPath = patchDesignationPathIfNeeded(target, fallbackPath)
|
||||
return FirDesignation(patchedPath, target)
|
||||
}
|
||||
|
||||
private fun collectDesignationPathWithContainingClassFallback(
|
||||
@@ -321,26 +325,18 @@ fun FirElementWithResolveState.collectDesignationWithFile(): FirDesignation =
|
||||
}
|
||||
|
||||
fun FirElementWithResolveState.tryCollectDesignation(firFile: FirFile): FirDesignation? =
|
||||
collectDesignationPath(this)?.let {
|
||||
FirDesignation(path = listOf(firFile) + it, target = this)
|
||||
}
|
||||
tryCollectDesignation(providedFile = firFile, target = this)
|
||||
|
||||
fun FirElementWithResolveState.tryCollectDesignation(): FirDesignation? =
|
||||
collectDesignationPath(this)?.let {
|
||||
FirDesignation(path = it, target = this)
|
||||
}
|
||||
tryCollectDesignation(providedFile = null, target = this)
|
||||
|
||||
fun FirElementWithResolveState.tryCollectDesignationWithFile(): FirDesignation? {
|
||||
return when (this) {
|
||||
is FirSyntheticProperty, is FirSyntheticPropertyAccessor -> unexpectedElementError<FirElementWithResolveState>(this)
|
||||
is FirFileAnnotationsContainer, is FirDeclaration -> {
|
||||
val path = collectDesignationPath(this) ?: return null
|
||||
val firFile = path.lastOrNull()?.getContainingFile() ?: getContainingFile() ?: return null
|
||||
FirDesignation(path = listOf(firFile) + path, target = this)
|
||||
}
|
||||
|
||||
else -> unexpectedElementError<FirElementWithResolveState>(this)
|
||||
fun FirElementWithResolveState.tryCollectDesignationWithFile(): FirDesignation? = when (this) {
|
||||
is FirSyntheticProperty, is FirSyntheticPropertyAccessor -> unexpectedElementError<FirElementWithResolveState>(this)
|
||||
is FirFileAnnotationsContainer, is FirDeclaration -> {
|
||||
val designation = tryCollectDesignation(providedFile = null, target = this)
|
||||
designation?.takeIf { it.fileOrNull != null }
|
||||
}
|
||||
else -> unexpectedElementError<FirElementWithResolveState>(this)
|
||||
}
|
||||
|
||||
internal fun patchDesignationPathIfNeeded(target: FirElementWithResolveState, targetPath: List<FirDeclaration>): List<FirDeclaration> {
|
||||
@@ -358,11 +354,14 @@ private fun patchDesignationPathForCopy(target: FirElementWithResolveState, targ
|
||||
|
||||
return buildList {
|
||||
for (targetPathDeclaration in targetPath) {
|
||||
val targetPathPsi = targetPathDeclaration.psi as? KtDeclaration ?: return null
|
||||
val targetPathPsi = targetPathDeclaration.psi ?: return null
|
||||
if (targetPathPsi !is KtClassOrObject && targetPathPsi !is KtScript && targetPathPsi !is KtFile) return null
|
||||
|
||||
val originalPathPsi = targetPathPsi.unwrapCopy(targetPsiFile) ?: return null
|
||||
val originalPathDeclaration = when (originalPathPsi) {
|
||||
is KtClassOrObject -> originalPathPsi.getOrBuildFirSafe<FirRegularClass>(contextResolveSession)
|
||||
is KtScript -> originalPathPsi.getOrBuildFirSafe<FirScript>(contextResolveSession)
|
||||
is KtFile -> originalPathPsi.getOrBuildFirFile(contextResolveSession)
|
||||
else -> null
|
||||
} ?: return null
|
||||
|
||||
|
||||
+30
-15
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.util
|
||||
import com.intellij.openapi.progress.ProgressManager
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDesignation
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.withFirDesignationEntry
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.getNonLocalContainingOrThisDeclaration
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.isAutonomousDeclaration
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.ContextCollector.Context
|
||||
@@ -34,6 +35,7 @@ import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.BodyResolveCon
|
||||
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.fir.types.typeContext
|
||||
import org.jetbrains.kotlin.fir.utils.exceptions.withFirEntry
|
||||
import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitorVoid
|
||||
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
@@ -41,6 +43,7 @@ import org.jetbrains.kotlin.psi.KtParameter
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isPropertyParameter
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||
import org.jetbrains.kotlin.util.PrivateForInline
|
||||
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
|
||||
import java.util.ArrayList
|
||||
|
||||
object ContextCollector {
|
||||
@@ -160,35 +163,47 @@ object ContextCollector {
|
||||
shouldCollectBodyContext: Boolean,
|
||||
filter: (PsiElement) -> FilterResponse,
|
||||
): ContextProvider {
|
||||
val interceptor = designation?.let(::DesignationInterceptor) ?: { null }
|
||||
val interceptor = designation?.let(::DesignationInterceptor)
|
||||
val visitor = ContextCollectorVisitor(holder, shouldCollectBodyContext, filter, interceptor)
|
||||
file.accept(visitor)
|
||||
visitor.collect(file)
|
||||
|
||||
return ContextProvider { element, kind -> visitor[element, kind] }
|
||||
}
|
||||
|
||||
private class DesignationInterceptor(private val designation: FirDesignation) : () -> FirElement? {
|
||||
private val targetIterator = iterator {
|
||||
yieldAll(designation.path)
|
||||
yield(designation.target)
|
||||
}
|
||||
|
||||
override fun invoke(): FirElement? {
|
||||
return if (targetIterator.hasNext()) targetIterator.next() else null
|
||||
}
|
||||
}
|
||||
|
||||
fun interface ContextProvider {
|
||||
operator fun get(element: PsiElement, kind: ContextKind): Context?
|
||||
}
|
||||
}
|
||||
|
||||
private class DesignationInterceptor(val designation: FirDesignation) : () -> FirElement? {
|
||||
private val targetIterator = iterator {
|
||||
yieldAll(designation.path)
|
||||
yield(designation.target)
|
||||
}
|
||||
|
||||
override fun invoke(): FirElement? = if (targetIterator.hasNext()) targetIterator.next() else null
|
||||
}
|
||||
|
||||
private class ContextCollectorVisitor(
|
||||
private val holder: SessionHolder,
|
||||
private val shouldCollectBodyContext: Boolean,
|
||||
private val filter: (PsiElement) -> FilterResponse,
|
||||
private val designationPathInterceptor: () -> FirElement?,
|
||||
private val designationPathInterceptor: DesignationInterceptor?,
|
||||
) : FirDefaultVisitorVoid() {
|
||||
fun collect(file: FirFile) {
|
||||
if (designationPathInterceptor != null) {
|
||||
withInterceptor {
|
||||
// This code is unreachable in the case of a not empty path
|
||||
errorWithAttachment("Designation path is empty") {
|
||||
withFirEntry("file", file)
|
||||
withFirDesignationEntry("designation", designationPathInterceptor.designation)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
file.accept(this)
|
||||
}
|
||||
}
|
||||
|
||||
private data class ContextKey(val element: PsiElement, val kind: ContextKind)
|
||||
|
||||
operator fun get(element: PsiElement, kind: ContextKind): Context? {
|
||||
@@ -754,7 +769,7 @@ private class ContextCollectorVisitor(
|
||||
* If the designation is over, then allows the [block] code to take control.
|
||||
*/
|
||||
private fun withInterceptor(block: () -> Unit) {
|
||||
val target = designationPathInterceptor()
|
||||
val target = designationPathInterceptor?.invoke()
|
||||
if (target != null) {
|
||||
target.accept(this)
|
||||
} else {
|
||||
|
||||
+5
-4
@@ -28,15 +28,15 @@ internal object FirElementFinder {
|
||||
expectedDeclarationAcceptor = { it is FirClassLikeDeclaration && it.symbol.name == classId.shortClassName },
|
||||
)?.target?.let { it as FirClassLikeDeclaration }
|
||||
|
||||
fun findClassPathToDeclaration(
|
||||
fun collectDesignationPath(
|
||||
firFile: FirFile,
|
||||
declarationContainerClassId: ClassId?,
|
||||
targetMemberDeclaration: FirDeclaration,
|
||||
): List<FirDeclaration>? = collectDesignationPath(
|
||||
): FirDesignation? = collectDesignationPath(
|
||||
firFile = firFile,
|
||||
containerClassId = declarationContainerClassId,
|
||||
expectedDeclarationAcceptor = { it == targetMemberDeclaration },
|
||||
)?.path
|
||||
)
|
||||
|
||||
fun findDeclaration(firFile: FirFile, nonLocalDeclaration: KtDeclaration): FirDeclaration? = collectDesignationPath(
|
||||
firFile = firFile,
|
||||
@@ -90,7 +90,7 @@ internal object FirElementFinder {
|
||||
}
|
||||
|
||||
val classIdPathSegment = containerClassId?.relativeClassName?.pathSegments().orEmpty()
|
||||
val path = ArrayList<FirDeclaration>(classIdPathSegment.size + 1)
|
||||
val path = ArrayList<FirDeclaration>(classIdPathSegment.size + 2)
|
||||
var result: FirDeclaration? = null
|
||||
|
||||
fun find(declarations: Iterable<FirDeclaration>, classIdPathIndex: Int): Boolean {
|
||||
@@ -136,6 +136,7 @@ internal object FirElementFinder {
|
||||
return false
|
||||
}
|
||||
|
||||
path += firFile
|
||||
find(firFile.declarations, classIdPathIndex = 0)
|
||||
|
||||
if (result == null) {
|
||||
|
||||
+3
-5
@@ -47,8 +47,8 @@ Tower Data Context:
|
||||
Scope: FirLocalScope
|
||||
|
||||
FILE: [ResolvedTo(IMPORTS)] statement.kts
|
||||
context(<script>@R|kotlin/script/templates/standard/ScriptTemplateWithArgs|)
|
||||
SCRIPT: [ResolvedTo(TYPES)] <script-statement.kts>
|
||||
context(<script>@kotlin.script.templates.standard.ScriptTemplateWithArgs)
|
||||
SCRIPT: [ResolvedTo(RAW_FIR)] <script-statement.kts>
|
||||
[ResolvedTo(RAW_FIR)] lval args: R|kotlin/Array<kotlin/String>|
|
||||
|
||||
public final? [ResolvedTo(RAW_FIR)] class ScriptClass : R|kotlin/Any| {
|
||||
@@ -61,9 +61,7 @@ FILE: [ResolvedTo(IMPORTS)] statement.kts
|
||||
|
||||
}
|
||||
|
||||
public final [ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] fun scriptFunction(): R|kotlin/Int| {
|
||||
^scriptFunction Int(42)
|
||||
}
|
||||
public? final? [ResolvedTo(RAW_FIR)] fun scriptFunction(): <implicit> { LAZY_BLOCK }
|
||||
|
||||
public? final? [ResolvedTo(RAW_FIR)] fun unusedScriptFunction([ResolvedTo(RAW_FIR)] p: String): <implicit> { LAZY_BLOCK }
|
||||
|
||||
|
||||
+2
-2
@@ -53,8 +53,8 @@ Tower Data Context:
|
||||
Scope: FirLocalScope
|
||||
|
||||
FILE: [ResolvedTo(IMPORTS)] topLevel.kts
|
||||
context(<script>@R|kotlin/script/templates/standard/ScriptTemplateWithArgs|)
|
||||
SCRIPT: [ResolvedTo(TYPES)] <script-topLevel.kts>
|
||||
context(<script>@kotlin.script.templates.standard.ScriptTemplateWithArgs)
|
||||
SCRIPT: [ResolvedTo(RAW_FIR)] <script-topLevel.kts>
|
||||
[ResolvedTo(RAW_FIR)] lval args: R|kotlin/Array<kotlin/String>|
|
||||
|
||||
public? final? [ResolvedTo(RAW_FIR)] fun before_Fun(): R|kotlin/Unit| { LAZY_BLOCK }
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
Tower Data Context:
|
||||
Element 0
|
||||
Scope: FirDefaultStarImportingScope
|
||||
Element 1
|
||||
Scope: FirExplicitStarImportingScope
|
||||
Element 2
|
||||
Scope: FirDefaultSimpleImportingScope
|
||||
Element 3
|
||||
Scope: FirDefaultSimpleImportingScope
|
||||
Element 4
|
||||
Scope: FirPackageMemberScope
|
||||
Element 5
|
||||
Scope: FirExplicitSimpleImportingScope
|
||||
|
||||
FILE: [ResolvedTo(RAW_FIR)] typeAlias.kt
|
||||
public final [ResolvedTo(RAW_FIR)] typealias Foo = String
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
Tower Data Context:
|
||||
Element 0
|
||||
Scope: FirDefaultStarImportingScope
|
||||
Element 1
|
||||
Scope: FirExplicitStarImportingScope
|
||||
Element 2
|
||||
Scope: FirDefaultSimpleImportingScope
|
||||
Element 3
|
||||
Scope: FirDefaultSimpleImportingScope
|
||||
Element 4
|
||||
Scope: FirPackageMemberScope
|
||||
Element 5
|
||||
Scope: FirExplicitSimpleImportingScope
|
||||
|
||||
FILE: [ResolvedTo(RAW_FIR)] typeAliasInitializer.kt
|
||||
public final [ResolvedTo(RAW_FIR)] typealias Foo = String
|
||||
Reference in New Issue
Block a user