[FIR IDE] Implement on-air resolve of non-local declarations

This commit is contained in:
Igor Yakovlev
2021-05-04 17:03:46 +02:00
committed by TeamCityServer
parent 779a06e86f
commit 261098a122
17 changed files with 348 additions and 209 deletions
@@ -17,9 +17,11 @@ import com.intellij.openapi.editor.Document
import com.intellij.openapi.util.TextRange import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.completion.handlers.isTextAt import org.jetbrains.kotlin.idea.completion.handlers.isTextAt
import com.intellij.psi.util.PsiUtil
import org.jetbrains.kotlin.idea.core.asFqNameWithRootPrefixIfNeeded import org.jetbrains.kotlin.idea.core.asFqNameWithRootPrefixIfNeeded
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
import org.jetbrains.kotlin.idea.frontend.api.analyse import org.jetbrains.kotlin.idea.frontend.api.analyse
import org.jetbrains.kotlin.idea.frontend.api.analyseInDependedAnalysisSession
import org.jetbrains.kotlin.idea.frontend.api.fir.utils.addImportToFile import org.jetbrains.kotlin.idea.frontend.api.fir.utils.addImportToFile
import org.jetbrains.kotlin.idea.frontend.api.symbols.* import org.jetbrains.kotlin.idea.frontend.api.symbols.*
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtNamedSymbol import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtNamedSymbol
@@ -415,7 +417,6 @@ private fun shortenReferences(targetFile: KtFile, textRange: TextRange) {
collectPossibleReferenceShortenings(targetFile, textRange) collectPossibleReferenceShortenings(targetFile, textRange)
} }
} }
shortenings.invokeShortening() shortenings.invokeShortening()
} }
@@ -6,22 +6,19 @@
package org.jetbrains.kotlin.idea.fir.low.level.api package org.jetbrains.kotlin.idea.fir.low.level.api
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic
import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.resolve.FirTowerDataContext
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
import org.jetbrains.kotlin.idea.fir.low.level.api.annotations.InternalForInline import org.jetbrains.kotlin.idea.fir.low.level.api.annotations.InternalForInline
import org.jetbrains.kotlin.idea.fir.low.level.api.api.DiagnosticCheckerFilter import org.jetbrains.kotlin.idea.fir.low.level.api.api.DiagnosticCheckerFilter
import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState
import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirTowerDataContextCollector import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirTowerContextProvider
import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.getClosestAvailableParentContext
import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCache import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCache
import org.jetbrains.kotlin.idea.fir.low.level.api.file.structure.FirElementsRecorder
import org.jetbrains.kotlin.idea.fir.low.level.api.providers.firIdeProvider
import org.jetbrains.kotlin.idea.fir.low.level.api.util.containingKtFileIfAny import org.jetbrains.kotlin.idea.fir.low.level.api.util.containingKtFileIfAny
import org.jetbrains.kotlin.idea.fir.low.level.api.util.originalKtFile import org.jetbrains.kotlin.idea.fir.low.level.api.util.originalKtFile
import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtDeclaration
@@ -30,24 +27,29 @@ import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtLambdaExpression import org.jetbrains.kotlin.psi.KtLambdaExpression
internal class FirModuleResolveStateDepended( internal class FirModuleResolveStateDepended(
dependencyFirDeclaration: FirDeclaration,
originalFirFile: FirFile,
private val originalState: FirModuleResolveStateImpl, private val originalState: FirModuleResolveStateImpl,
val towerProviderBuiltUponElement: FirTowerContextProvider,
private val ktToFirMapping: Map<KtElement, FirElement>,
) : FirModuleResolveState() { ) : FirModuleResolveState() {
override val project: Project get() = originalState.project override val project: Project get() = originalState.project
override val moduleInfo: IdeaModuleInfo get() = originalState.moduleInfo override val moduleInfo: IdeaModuleInfo get() = originalState.moduleInfo
override val rootModuleSession get() = originalState.rootModuleSession override val rootModuleSession get() = originalState.rootModuleSession
private val fileStructureCache = originalState.fileStructureCache private val fileStructureCache get() = originalState.fileStructureCache
private val completionMapping = mutableMapOf<KtElement, FirElement>()
private val collector = FirTowerDataContextCollector()
override fun getSessionFor(moduleInfo: IdeaModuleInfo): FirSession = override fun getSessionFor(moduleInfo: IdeaModuleInfo): FirSession =
originalState.getSessionFor(moduleInfo) originalState.getSessionFor(moduleInfo)
override fun getOrBuildFirFor(element: KtElement): FirElement { override fun getOrBuildFirFor(element: KtElement): FirElement {
val psi = originalState.elementBuilder.getPsiAsFirElementSource(element) val psi = originalState.elementBuilder.getPsiAsFirElementSource(element)
synchronized(completionMapping) { completionMapping[psi] }?.let { return it }
//TODO It return invalid elements for elements with invalid code, but try to return the most closest ones
var currentElement: PsiElement = psi
while (currentElement !is KtFile) {
ktToFirMapping[currentElement]?.let { return it }
currentElement = currentElement.parent
}
return originalState.elementBuilder.getOrBuildFirFor( return originalState.elementBuilder.getOrBuildFirFor(
element, element,
originalState.firFileBuilder, originalState.firFileBuilder,
@@ -82,24 +84,4 @@ internal class FirModuleResolveStateDepended(
@OptIn(InternalForInline::class) @OptIn(InternalForInline::class)
override fun findSourceFirDeclaration(ktDeclaration: KtDeclaration): FirDeclaration = override fun findSourceFirDeclaration(ktDeclaration: KtDeclaration): FirDeclaration =
originalState.findSourceFirDeclaration(ktDeclaration) originalState.findSourceFirDeclaration(ktDeclaration)
override fun getTowerDataContextForElement(element: KtElement): FirTowerDataContext? =
collector.getClosestAvailableParentContext(element) ?: originalState.getTowerDataContextForElement(element)
init {
originalState.firFileBuilder.runCustomResolveWithPCECheck(originalFirFile, rootModuleSession.cache) {
originalState.firLazyDeclarationResolver.runLazyResolveWithoutLock(
dependencyFirDeclaration,
rootModuleSession.cache,
originalFirFile,
originalFirFile.session.firIdeProvider,
fromPhase = dependencyFirDeclaration.resolvePhase,
toPhase = FirResolvePhase.BODY_RESOLVE,
towerDataContextCollector = collector,
checkPCE = true
)
}
synchronized(completionMapping) { dependencyFirDeclaration.accept(FirElementsRecorder(), completionMapping) }
}
} }
@@ -14,7 +14,6 @@ import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.realPsi import org.jetbrains.kotlin.fir.realPsi
import org.jetbrains.kotlin.fir.resolve.FirTowerDataContext
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo
import org.jetbrains.kotlin.idea.caches.project.getModuleInfo import org.jetbrains.kotlin.idea.caches.project.getModuleInfo
@@ -23,8 +22,6 @@ import org.jetbrains.kotlin.idea.fir.low.level.api.api.DiagnosticCheckerFilter
import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState
import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.DiagnosticsCollector import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.DiagnosticsCollector
import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirElementBuilder import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirElementBuilder
import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirTowerDataContextCollector
import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.getClosestAvailableParentContext
import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.getNonLocalContainingOrThisDeclaration import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.getNonLocalContainingOrThisDeclaration
import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.FirFileBuilder import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.FirFileBuilder
import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCache import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCache
@@ -52,11 +49,8 @@ internal class FirModuleResolveStateImpl(
* It can grow unbounded if you never edit the files in the opened project. * It can grow unbounded if you never edit the files in the opened project.
* *
* It is a temporary solution until we can retrieve scopes for any fir element without re-resolving it. * It is a temporary solution until we can retrieve scopes for any fir element without re-resolving it.
*
* TODO Fix this when refactoring that separates resolving and scopes creation is done
*/ */
private val collector = FirTowerDataContextCollector() val fileStructureCache = FileStructureCache(firFileBuilder, firLazyDeclarationResolver)
val fileStructureCache = FileStructureCache(firFileBuilder, firLazyDeclarationResolver, collector)
val elementBuilder = FirElementBuilder() val elementBuilder = FirElementBuilder()
private val diagnosticsCollector = DiagnosticsCollector(fileStructureCache, rootModuleSession.cache) private val diagnosticsCollector = DiagnosticsCollector(fileStructureCache, rootModuleSession.cache)
@@ -111,7 +105,6 @@ internal class FirModuleResolveStateImpl(
cache, cache,
FirResolvePhase.BODY_RESOLVE, FirResolvePhase.BODY_RESOLVE,
checkPCE = false, /*TODO*/ checkPCE = false, /*TODO*/
towerDataContextCollector = collector,
) )
} }
val firDeclaration = FirElementFinder.findElementIn<FirDeclaration>(nonLocalFirForNamedDeclaration) { firDeclaration -> val firDeclaration = FirElementFinder.findElementIn<FirDeclaration>(nonLocalFirForNamedDeclaration) { firDeclaration ->
@@ -135,15 +128,11 @@ internal class FirModuleResolveStateImpl(
fileCache, fileCache,
toPhase, toPhase,
checkPCE = true, checkPCE = true,
towerDataContextCollector = collector, towerDataContextCollector = null,
) )
return declaration return declaration
} }
override fun getFirFile(declaration: FirDeclaration, cache: ModuleFileCache): FirFile? = override fun getFirFile(declaration: FirDeclaration, cache: ModuleFileCache): FirFile? =
cache.getContainerFirFile(declaration) cache.getContainerFirFile(declaration)
}
override fun getTowerDataContextForElement(element: KtElement): FirTowerDataContext? {
return collector.getClosestAvailableParentContext(element)
}
}
@@ -36,6 +36,7 @@ internal class FirPhaseRunner {
FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE -> implicitTypesResolveLock.withLock { FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE -> implicitTypesResolveLock.withLock {
runPhaseWithoutLock(firFile, phase, scopeSession) runPhaseWithoutLock(firFile, phase, scopeSession)
} }
//TODO: Make correct sync for TYPES
else -> { else -> {
runPhaseWithoutLock(firFile, phase, scopeSession) runPhaseWithoutLock(firFile, phase, scopeSession)
} }
@@ -51,6 +52,7 @@ internal class FirPhaseRunner {
FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE -> implicitTypesResolveLock.withLock { FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE -> implicitTypesResolveLock.withLock {
runPhaseWithCustomResolveWithoutLock(resolve) runPhaseWithCustomResolveWithoutLock(resolve)
} }
//TODO: Make correct sync for TYPES
else -> { else -> {
runPhaseWithCustomResolveWithoutLock(resolve) runPhaseWithCustomResolveWithoutLock(resolve)
} }
@@ -7,51 +7,58 @@ package org.jetbrains.kotlin.idea.fir.low.level.api.api
import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.builder.RawFirFragmentForLazyBodiesBuilder import org.jetbrains.kotlin.fir.builder.RawFirFragmentForLazyBodiesBuilder
import org.jetbrains.kotlin.fir.builder.RawFirReplacement
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.* import org.jetbrains.kotlin.fir.declarations.builder.*
import org.jetbrains.kotlin.fir.expressions.FirReturnExpression import org.jetbrains.kotlin.fir.expressions.FirReturnExpression
import org.jetbrains.kotlin.fir.moduleData import org.jetbrains.kotlin.fir.moduleData
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
import org.jetbrains.kotlin.idea.fir.low.level.api.providers.firIdeProvider import org.jetbrains.kotlin.idea.fir.low.level.api.providers.firIdeProvider
import org.jetbrains.kotlin.idea.util.getElementTextInContext
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
object DeclarationCopyBuilder { object DeclarationCopyBuilder {
fun createDeclarationCopy( fun <T : KtElement> createDeclarationCopy(
originalFirDeclaration: FirDeclaration,
copiedKtDeclaration: KtDeclaration,
state: FirModuleResolveState, state: FirModuleResolveState,
replacement: RawFirReplacement<T>
): FirDeclaration { ): FirDeclaration {
return when (copiedKtDeclaration) {
val nonLocalDeclaration = LowLevelFirApiFacadeForDependentCopy.findEnclosingNonLocalDeclaration(replacement.from)
?: error("Cannot find enclosing declaration for ${replacement.from.getElementTextInContext()}")
return when (nonLocalDeclaration) {
is KtNamedFunction -> createFunctionCopy( is KtNamedFunction -> createFunctionCopy(
copiedKtDeclaration, nonLocalDeclaration,
originalFirDeclaration as FirSimpleFunction, state,
state replacement
) )
is KtProperty -> createPropertyCopy( is KtProperty -> createPropertyCopy(
copiedKtDeclaration, nonLocalDeclaration,
originalFirDeclaration as FirProperty, state,
state replacement
) )
is KtClassOrObject -> createClassCopy( is KtClassOrObject -> createClassCopy(
copiedKtDeclaration, nonLocalDeclaration,
originalFirDeclaration as FirRegularClass, state,
state replacement
) )
is KtTypeAlias -> createTypeAliasCopy( is KtTypeAlias -> createTypeAliasCopy(
copiedKtDeclaration, nonLocalDeclaration,
originalFirDeclaration as FirTypeAlias, state,
state replacement
) )
else -> error("Unsupported declaration ${copiedKtDeclaration::class.simpleName}") else -> error("Unsupported declaration ${nonLocalDeclaration::class.simpleName}")
} }
} }
private fun createFunctionCopy( private fun <T : KtElement> createFunctionCopy(
element: KtNamedFunction, rootNonLocalDeclaration: KtNamedFunction,
originalFunction: FirSimpleFunction,
state: FirModuleResolveState, state: FirModuleResolveState,
replacement: RawFirReplacement<T>,
): FirSimpleFunction { ): FirSimpleFunction {
val builtFunction = createCopy(element, originalFunction)
val originalFunction = rootNonLocalDeclaration.getOrBuildFirOfType<FirSimpleFunction>(state)
val builtFunction = createCopy(rootNonLocalDeclaration, originalFunction, replacement)
// right now we can't resolve builtFunction header properly, as it built right in air, // right now we can't resolve builtFunction header properly, as it built right in air,
// without file, which is now required for running stages other then body resolve, so we // without file, which is now required for running stages other then body resolve, so we
@@ -63,27 +70,31 @@ object DeclarationCopyBuilder {
}.apply { reassignAllReturnTargets(builtFunction) } }.apply { reassignAllReturnTargets(builtFunction) }
} }
private fun createClassCopy( private fun <T : KtElement> createClassCopy(
copiedKtClassOrObject: KtClassOrObject, rootNonLocalDeclaration: KtClassOrObject,
originalFirClass: FirRegularClass,
state: FirModuleResolveState, state: FirModuleResolveState,
replacement: RawFirReplacement<T>,
): FirRegularClass { ): FirRegularClass {
val builtClass = createCopy(copiedKtClassOrObject, originalFirClass) val originalFirClass = rootNonLocalDeclaration.getOrBuildFirOfType<FirRegularClass>(state)
val builtClass = createCopy(rootNonLocalDeclaration, originalFirClass, replacement)
return buildRegularClassCopy(originalFirClass) { return buildRegularClassCopy(originalFirClass) {
declarations.clear() declarations.clear()
declarations.addAll(builtClass.declarations) declarations.addAll(builtClass.declarations)
symbol = builtClass.symbol symbol = builtClass.symbol
initDeclaration(originalFirClass, builtClass, state) initDeclaration(originalFirClass, builtClass, state)
resolvePhase = minOf(originalFirClass.resolvePhase, FirResolvePhase.IMPORTS) //TODO move into initDeclaration?
} }
} }
private fun createTypeAliasCopy( private fun <T : KtElement> createTypeAliasCopy(
copiedKtTypeAlias: KtTypeAlias, rootNonLocalDeclaration: KtTypeAlias,
originalFirTypeAlias: FirTypeAlias,
state: FirModuleResolveState, state: FirModuleResolveState,
replacement: RawFirReplacement<T>,
): FirTypeAlias { ): FirTypeAlias {
val builtTypeAlias = createCopy(copiedKtTypeAlias, originalFirTypeAlias)
val originalFirTypeAlias = rootNonLocalDeclaration.getOrBuildFirOfType<FirTypeAlias>(state)
val builtTypeAlias = createCopy(rootNonLocalDeclaration, originalFirTypeAlias, replacement)
return buildTypeAliasCopy(originalFirTypeAlias) { return buildTypeAliasCopy(originalFirTypeAlias) {
expandedTypeRef = builtTypeAlias.expandedTypeRef expandedTypeRef = builtTypeAlias.expandedTypeRef
@@ -92,12 +103,13 @@ object DeclarationCopyBuilder {
} }
} }
private fun createPropertyCopy( private fun <T : KtElement> createPropertyCopy(
element: KtProperty, rootNonLocalDeclaration: KtProperty,
originalProperty: FirProperty, state: FirModuleResolveState,
state: FirModuleResolveState replacement: RawFirReplacement<T>,
): FirProperty { ): FirProperty {
val builtProperty = createCopy(element, originalProperty) val originalProperty = rootNonLocalDeclaration.getOrBuildFirOfType<FirProperty>(state)
val builtProperty = createCopy(rootNonLocalDeclaration, originalProperty, replacement)
val originalSetter = originalProperty.setter val originalSetter = originalProperty.setter
val builtSetter = builtProperty.setter val builtSetter = builtProperty.setter
@@ -134,16 +146,18 @@ object DeclarationCopyBuilder {
moduleData = state.rootModuleSession.moduleData moduleData = state.rootModuleSession.moduleData
} }
internal inline fun <reified T : FirDeclaration> createCopy( internal inline fun <reified D : FirDeclaration, T : KtElement> createCopy(
copiedKtDeclaration: KtDeclaration, rootNonLocalDeclaration: KtDeclaration,
originalFirDeclaration: T, originalFirDeclaration: D,
): T { replacement: RawFirReplacement<T>? = null,
return RawFirFragmentForLazyBodiesBuilder.build( ): D {
return RawFirFragmentForLazyBodiesBuilder.buildWithReplacement(
session = originalFirDeclaration.moduleData.session, session = originalFirDeclaration.moduleData.session,
baseScopeProvider = originalFirDeclaration.moduleData.session.firIdeProvider.kotlinScopeProvider, baseScopeProvider = originalFirDeclaration.moduleData.session.firIdeProvider.kotlinScopeProvider,
designation = originalFirDeclaration.collectDesignation().fullDesignation, designation = originalFirDeclaration.collectDesignation().path,
declaration = copiedKtDeclaration declarationToBuild = rootNonLocalDeclaration,
) as T replacement = replacement,
) as D
} }
private fun FirFunction<*>.reassignAllReturnTargets(from: FirFunction<*>) { private fun FirFunction<*>.reassignAllReturnTargets(from: FirFunction<*>) {
@@ -10,7 +10,6 @@ import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.FirTowerDataContext
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
import org.jetbrains.kotlin.idea.fir.low.level.api.annotations.InternalForInline import org.jetbrains.kotlin.idea.fir.low.level.api.annotations.InternalForInline
import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCache import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCache
@@ -67,9 +66,4 @@ abstract class FirModuleResolveState {
internal abstract fun <D : FirDeclaration> resolvedFirToPhase(declaration: D, toPhase: FirResolvePhase): D internal abstract fun <D : FirDeclaration> resolvedFirToPhase(declaration: D, toPhase: FirResolvePhase): D
internal abstract fun getFirFile(declaration: FirDeclaration, cache: ModuleFileCache): FirFile? internal abstract fun getFirFile(declaration: FirDeclaration, cache: ModuleFileCache): FirFile?
}
abstract fun getTowerDataContextForElement(element: KtElement): FirTowerDataContext?
}
fun FirModuleResolveState.getTowerDataContextUnsafe(element: KtElement): FirTowerDataContext =
getTowerDataContextForElement(element) ?: error("No context for ${element.getElementTextInContext()}")
@@ -7,9 +7,23 @@ package org.jetbrains.kotlin.idea.fir.low.level.api.api
import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.PsiTreeUtil
import com.intellij.psi.util.parentsOfType import com.intellij.psi.util.parentsOfType
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.builder.RawFirReplacement
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.realPsi
import org.jetbrains.kotlin.fir.resolve.FirTowerDataContext
import org.jetbrains.kotlin.fir.resolve.ResolutionMode
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirBodyResolveTransformer
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
import org.jetbrains.kotlin.idea.fir.low.level.api.FirModuleResolveStateDepended import org.jetbrains.kotlin.idea.fir.low.level.api.FirModuleResolveStateDepended
import org.jetbrains.kotlin.idea.fir.low.level.api.FirModuleResolveStateImpl import org.jetbrains.kotlin.idea.fir.low.level.api.FirModuleResolveStateImpl
import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirTowerContextProvider
import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirTowerDataContextCollector
import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirTowerDataContextAllElementsCollector
import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.SingleElementTowerProvider
import org.jetbrains.kotlin.idea.fir.low.level.api.file.structure.FirElementsRecorder
import org.jetbrains.kotlin.idea.fir.low.level.api.providers.firIdeProvider
import org.jetbrains.kotlin.idea.fir.low.level.api.util.originalDeclaration import org.jetbrains.kotlin.idea.fir.low.level.api.util.originalDeclaration
import org.jetbrains.kotlin.idea.util.getElementTextInContext import org.jetbrains.kotlin.idea.util.getElementTextInContext
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
@@ -25,7 +39,7 @@ object LowLevelFirApiFacadeForDependentCopy {
else -> false else -> false
} }
private fun findEnclosingNonLocalDeclaration(position: KtElement): KtNamedDeclaration? = fun findEnclosingNonLocalDeclaration(position: KtElement): KtNamedDeclaration? =
position.parentsOfType<KtNamedDeclaration>().firstOrNull { ktDeclaration -> position.parentsOfType<KtNamedDeclaration>().firstOrNull { ktDeclaration ->
ktDeclaration.canBeEnclosingDeclaration() ktDeclaration.canBeEnclosingDeclaration()
} }
@@ -46,33 +60,153 @@ object LowLevelFirApiFacadeForDependentCopy {
} }
} }
private fun <T : KtElement> onAirResolveElement(
state: FirModuleResolveState,
place: T,
elementToResolve: T,
): FirModuleResolveState {
require(state is FirModuleResolveStateImpl)
require(place.isPhysical)
require(!elementToResolve.isPhysical)
val collector = FirTowerDataContextAllElementsCollector()
val declaration = runBodyResolve(state, replacement = RawFirReplacement(place, elementToResolve))
val expressionLocator = object : FirVisitorVoid() {
var result: FirElement? = null
private set
override fun visitElement(element: FirElement) {
if (element.realPsi == elementToResolve) result = element
if (result != null) return
element.acceptChildren(this)
}
}
declaration.accept(expressionLocator)
val recordedMap = FirElementsRecorder.recordElementsFrom(declaration, FirElementsRecorder())
return FirModuleResolveStateDepended(state, collector, recordedMap)
}
fun onAirGetTowerContextProvider(
state: FirModuleResolveState,
place: KtElement,
): FirTowerContextProvider {
require(state is FirModuleResolveStateImpl)
require(place.isPhysical)
return if (place is KtFile) {
onAirGetTowerContextForFile(state, place)
} else {
FirTowerDataContextAllElementsCollector().also {
runBodyResolve(state, collector = it, replacement = RawFirReplacement(place, place))
}
}
}
private fun onAirGetTowerContextForFile(
state: FirModuleResolveState,
file: KtFile,
): FirTowerContextProvider {
val firFile = state.getOrBuildFirFor(file) as FirFile
val fileTransformer = object : FirBodyResolveTransformer(
session = firFile.declarationSiteSession,
phase = FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE,
implicitTypeOnly = true,
scopeSession = ScopeSession()
) {
var result: FirTowerDataContext? = null
private set
override fun transformDeclarationContent(declaration: FirDeclaration, data: ResolutionMode): FirDeclaration {
check(declaration is FirFile)
result = context.towerDataContext
return declaration
}
}
firFile.transform<FirFile, ResolutionMode>(fileTransformer, ResolutionMode.ContextDependent)
val fileContext = fileTransformer.result
check(fileContext != null) { "File context not found for physical file" }
return SingleElementTowerProvider(file, fileContext)
}
fun getResolveStateForDependedCopy( fun getResolveStateForDependedCopy(
originalState: FirModuleResolveState, originalState: FirModuleResolveState,
originalKtFile: KtFile, originalKtFile: KtFile,
dependencyKtElement: KtElement dependencyKtElement: KtElement
): FirModuleResolveState { ): FirModuleResolveState {
require(originalState is FirModuleResolveStateImpl) require(originalState is FirModuleResolveStateImpl)
require(dependencyKtElement !is KtFile) { "KtFile for dependency element not supported" }
require(!dependencyKtElement.isPhysical) { "Depended state should be build only for non-physical elements" }
val dependencyNonLocalDeclaration = findEnclosingNonLocalDeclaration(dependencyKtElement) val dependencyNonLocalDeclaration = findEnclosingNonLocalDeclaration(dependencyKtElement)
?: error("Cannot find enclosing declaration for ${dependencyKtElement.getElementTextInContext()}") ?: error("Cannot find enclosing declaration for ${dependencyKtElement.getElementTextInContext()}")
val originalNonLocalDeclaration = locateDeclarationInFileByOffset(dependencyNonLocalDeclaration, originalKtFile) val sameDeclarationInOriginalFile = locateDeclarationInFileByOffset(dependencyNonLocalDeclaration, originalKtFile)
?: error("Cannot find original function matching to ${dependencyNonLocalDeclaration.getElementTextInContext()} in $originalKtFile") ?: error("Cannot find original function matching to ${dependencyNonLocalDeclaration.getElementTextInContext()} in $originalKtFile")
recordOriginalDeclaration( recordOriginalDeclaration(
targetDeclaration = dependencyNonLocalDeclaration, targetDeclaration = dependencyNonLocalDeclaration,
originalDeclaration = originalNonLocalDeclaration originalDeclaration = sameDeclarationInOriginalFile
) )
val originalFirDeclaration = originalNonLocalDeclaration.getOrBuildFirOfType<FirDeclaration>(originalState) val collector = FirTowerDataContextAllElementsCollector()
val copiedFirDeclaration = DeclarationCopyBuilder.createDeclarationCopy( val copiedFirDeclaration = runBodyResolve(
originalFirDeclaration = originalFirDeclaration, originalState,
copiedKtDeclaration = dependencyNonLocalDeclaration, collector = collector,
state = originalState replacement = RawFirReplacement(sameDeclarationInOriginalFile, dependencyNonLocalDeclaration)
) )
val originalFirFile = originalState.getFirFile(originalKtFile) val recordedMap = FirElementsRecorder.recordElementsFrom(copiedFirDeclaration, FirElementsRecorder())
return FirModuleResolveStateDepended(originalState, collector, recordedMap)
return FirModuleResolveStateDepended(copiedFirDeclaration, originalFirFile, originalState)
} }
private fun <T : KtElement> runBodyResolve(
state: FirModuleResolveStateImpl,
replacement: RawFirReplacement<T>,
collector: FirTowerDataContextCollector? = null,
): FirDeclaration {
val copiedFirDeclaration = DeclarationCopyBuilder.createDeclarationCopy(
state = state,
replacement = replacement,
)
val originalFirFile = state.getOrBuildFirFor(replacement.from.containingKtFile) as FirFile
state.firFileBuilder.runCustomResolveWithPCECheck(originalFirFile, state.rootModuleSession.cache) {
state.firLazyDeclarationResolver.runLazyResolveWithoutLock(
copiedFirDeclaration,
state.rootModuleSession.cache,
originalFirFile,
originalFirFile.declarationSiteSession.firIdeProvider,
fromPhase = copiedFirDeclaration.resolvePhase,
toPhase = FirResolvePhase.BODY_RESOLVE,
towerDataContextCollector = collector,
checkPCE = true,
lastNonLazyPhase = FirResolvePhase.IMPORTS
)
}
return copiedFirDeclaration
}
private class TowerProviderForElementForState(private val state: FirModuleResolveState) : FirTowerContextProvider {
override fun getClosestAvailableParentContext(ktElement: KtElement): FirTowerDataContext? {
return if (ktElement.isPhysical) {
onAirGetTowerContextProvider(state, ktElement).getClosestAvailableParentContext(ktElement)
} else {
require(state is FirModuleResolveStateDepended) {
"Invalid resolve state ${this::class.simpleName} but have to be ${FirModuleResolveStateDepended::class.simpleName}"
}
state.towerProviderBuiltUponElement.getClosestAvailableParentContext(ktElement)
}
}
}
fun FirModuleResolveState.getTowerContextProvider(): FirTowerContextProvider =
TowerProviderForElementForState(this)
} }
@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.idea.fir.low.level.api.element.builder package org.jetbrains.kotlin.idea.fir.low.level.api.element.builder
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.fir.ThreadSafeMutableState
import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.expressions.FirStatement import org.jetbrains.kotlin.fir.expressions.FirStatement
@@ -15,43 +14,59 @@ import org.jetbrains.kotlin.fir.resolve.FirTowerDataContext
import org.jetbrains.kotlin.idea.fir.low.level.api.util.originalDeclaration import org.jetbrains.kotlin.idea.fir.low.level.api.util.originalDeclaration
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
@ThreadSafeMutableState interface FirTowerContextProvider {
class FirTowerDataContextCollector { fun getClosestAvailableParentContext(ktElement: KtElement): FirTowerDataContext?
private val state: MutableMap<KtElement, FirTowerDataContext> = hashMapOf()
fun addFileContext(file: FirFile, context: FirTowerDataContext) {
val ktFile = file.psi as? KtFile ?: return
state[ktFile] = context
}
fun addStatementContext(statement: FirStatement, context: FirTowerDataContext) {
val closestStatementInBlock = statement.psi?.closestBlockLevelOrInitializerExpression() ?: return
state[closestStatementInBlock] = context
}
fun addDeclarationContext(declaration: FirDeclaration, context: FirTowerDataContext) {
(declaration.psi as? KtElement)?.let { state[it] = context }
}
fun getContext(psi: KtElement): FirTowerDataContext? = state[psi]
} }
fun FirTowerDataContextCollector.getClosestAvailableParentContext(element: KtElement): FirTowerDataContext? { interface FirTowerDataContextCollector {
var current: PsiElement? = element fun addFileContext(file: FirFile, context: FirTowerDataContext)
while (current != null) { fun addStatementContext(statement: FirStatement, context: FirTowerDataContext)
if (current is KtElement) { fun addDeclarationContext(declaration: FirDeclaration, context: FirTowerDataContext)
getContext(current)?.let { return it } }
}
if (current is KtDeclaration) { internal class SingleElementTowerProvider(
val originalDeclaration = current.originalDeclaration private val element: KtElement,
originalDeclaration?.let { getContext(it) }?.let { return it } private val context: FirTowerDataContext
} ) : FirTowerContextProvider {
if (current is KtFile) { override fun getClosestAvailableParentContext(ktElement: KtElement): FirTowerDataContext? =
break if (element == ktElement) context else null
} }
current = current.parent
internal class FirTowerDataContextAllElementsCollector : FirTowerDataContextCollector, FirTowerContextProvider {
private val elementsToContext: MutableMap<KtElement, FirTowerDataContext> = hashMapOf()
override fun addFileContext(file: FirFile, context: FirTowerDataContext) {
val ktFile = file.psi as? KtFile ?: return
elementsToContext[ktFile] = context
}
override fun addStatementContext(statement: FirStatement, context: FirTowerDataContext) {
val closestStatementInBlock = statement.psi?.closestBlockLevelOrInitializerExpression() ?: return
elementsToContext[closestStatementInBlock] = context
}
override fun addDeclarationContext(declaration: FirDeclaration, context: FirTowerDataContext) {
val psi = declaration.psi as? KtElement ?: return
elementsToContext[psi] = context
}
override fun getClosestAvailableParentContext(ktElement: KtElement): FirTowerDataContext? {
var current: PsiElement? = ktElement
while (current != null) {
if (current is KtElement) {
elementsToContext[current]?.let { return it }
}
if (current is KtDeclaration) {
val originalDeclaration = current.originalDeclaration
originalDeclaration?.let { elementsToContext[it] }?.let { return it }
}
if (current is KtFile) {
break
}
current = current.parent
}
return null
} }
return null
} }
private tailrec fun PsiElement.closestBlockLevelOrInitializerExpression(): KtExpression? = private tailrec fun PsiElement.closestBlockLevelOrInitializerExpression(): KtExpression? =
@@ -11,7 +11,6 @@ import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.idea.fir.low.level.api.api.DiagnosticCheckerFilter import org.jetbrains.kotlin.idea.fir.low.level.api.api.DiagnosticCheckerFilter
import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirTowerDataContextCollector
import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.getNonLocalContainingOrThisDeclaration import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.getNonLocalContainingOrThisDeclaration
import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.FirFileBuilder import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.FirFileBuilder
import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCache import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCache
@@ -28,7 +27,6 @@ internal class FileStructure(
private val firLazyDeclarationResolver: FirLazyDeclarationResolver, private val firLazyDeclarationResolver: FirLazyDeclarationResolver,
private val firFileBuilder: FirFileBuilder, private val firFileBuilder: FirFileBuilder,
private val moduleFileCache: ModuleFileCache, private val moduleFileCache: ModuleFileCache,
private val collector: FirTowerDataContextCollector
) { ) {
private val firIdeProvider = firFile.moduleData.session.firIdeProvider private val firIdeProvider = firFile.moduleData.session.firIdeProvider
@@ -50,7 +48,6 @@ internal class FileStructure(
cache = moduleFileCache, cache = moduleFileCache,
firLazyDeclarationResolver = firLazyDeclarationResolver, firLazyDeclarationResolver = firLazyDeclarationResolver,
firIdeProvider = firIdeProvider, firIdeProvider = firIdeProvider,
towerDataContextCollector = collector
) )
} }
else -> structureElement else -> structureElement
@@ -112,7 +109,6 @@ internal class FileStructure(
moduleFileCache, moduleFileCache,
FirResolvePhase.BODY_RESOLVE, FirResolvePhase.BODY_RESOLVE,
checkPCE = true, checkPCE = true,
towerDataContextCollector = collector
) )
return moduleFileCache.firFileLockProvider.withReadLock(firFile) { return moduleFileCache.firFileLockProvider.withReadLock(firFile) {
FileElementFactory.createFileStructureElement(firDeclaration, declaration, firFile, moduleFileCache.firFileLockProvider) FileElementFactory.createFileStructureElement(firDeclaration, declaration, firFile, moduleFileCache.firFileLockProvider)
@@ -18,12 +18,11 @@ import java.util.concurrent.ConcurrentHashMap
internal class FileStructureCache( internal class FileStructureCache(
private val fileBuilder: FirFileBuilder, private val fileBuilder: FirFileBuilder,
private val firLazyDeclarationResolver: FirLazyDeclarationResolver, private val firLazyDeclarationResolver: FirLazyDeclarationResolver,
private val collector: FirTowerDataContextCollector,
) { ) {
private val cache = ConcurrentHashMap<KtFile, FileStructure>() private val cache = ConcurrentHashMap<KtFile, FileStructure>()
fun getFileStructure(ktFile: KtFile, moduleFileCache: ModuleFileCache): FileStructure = cache.computeIfAbsent(ktFile) { fun getFileStructure(ktFile: KtFile, moduleFileCache: ModuleFileCache): FileStructure = cache.computeIfAbsent(ktFile) {
val firFile = fileBuilder.buildRawFirFileWithCaching(ktFile, moduleFileCache, lazyBodiesMode = false) val firFile = fileBuilder.buildRawFirFileWithCaching(ktFile, moduleFileCache, lazyBodiesMode = false)
FileStructure(ktFile, firFile, firLazyDeclarationResolver, fileBuilder, moduleFileCache, collector) FileStructure(ktFile, firFile, firLazyDeclarationResolver, fileBuilder, moduleFileCache)
} }
} }
@@ -15,7 +15,6 @@ import org.jetbrains.kotlin.idea.fir.low.level.api.api.DeclarationCopyBuilder
import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.FileDiagnosticRetriever import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.FileDiagnosticRetriever
import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.FileStructureElementDiagnostics import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.FileStructureElementDiagnostics
import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.SingleNonLocalDeclarationDiagnosticRetriever import org.jetbrains.kotlin.idea.fir.low.level.api.diagnostics.SingleNonLocalDeclarationDiagnosticRetriever
import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirTowerDataContextCollector
import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.LockProvider import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.LockProvider
import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCache import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.ModuleFileCache
import org.jetbrains.kotlin.idea.fir.low.level.api.lazy.resolve.FirLazyDeclarationResolver import org.jetbrains.kotlin.idea.fir.low.level.api.lazy.resolve.FirLazyDeclarationResolver
@@ -45,7 +44,6 @@ internal sealed class ReanalyzableStructureElement<KT : KtDeclaration, S : Abstr
cache: ModuleFileCache, cache: ModuleFileCache,
firLazyDeclarationResolver: FirLazyDeclarationResolver, firLazyDeclarationResolver: FirLazyDeclarationResolver,
firIdeProvider: FirIdeProvider, firIdeProvider: FirIdeProvider,
towerDataContextCollector: FirTowerDataContextCollector,
): ReanalyzableStructureElement<KT, S> ): ReanalyzableStructureElement<KT, S>
fun isUpToDate(): Boolean = psi.getModificationStamp() == timestamp fun isUpToDate(): Boolean = psi.getModificationStamp() == timestamp
@@ -76,17 +74,15 @@ internal class ReanalyzableFunctionStructureElement(
cache: ModuleFileCache, cache: ModuleFileCache,
firLazyDeclarationResolver: FirLazyDeclarationResolver, firLazyDeclarationResolver: FirLazyDeclarationResolver,
firIdeProvider: FirIdeProvider, firIdeProvider: FirIdeProvider,
towerDataContextCollector: FirTowerDataContextCollector,
): ReanalyzableFunctionStructureElement { ): ReanalyzableFunctionStructureElement {
val originalFunction = firSymbol.fir as FirSimpleFunction val originalFunction = firSymbol.fir as FirSimpleFunction
val newFunction = DeclarationCopyBuilder.createCopy(newKtDeclaration, originalFunction) val newFunction = DeclarationCopyBuilder.createCopy<FirSimpleFunction, KtElement>(newKtDeclaration, originalFunction)
return FileStructureUtil.withDeclarationReplaced(firFile, cache, originalFunction, newFunction) { return FileStructureUtil.withDeclarationReplaced(firFile, cache, originalFunction, newFunction) {
firLazyDeclarationResolver.lazyResolveDeclaration( firLazyDeclarationResolver.lazyResolveDeclaration(
newFunction, newFunction,
cache, cache,
FirResolvePhase.BODY_RESOLVE, FirResolvePhase.BODY_RESOLVE,
towerDataContextCollector,
checkPCE = true, checkPCE = true,
reresolveFile = true, reresolveFile = true,
) )
@@ -118,17 +114,15 @@ internal class ReanalyzablePropertyStructureElement(
cache: ModuleFileCache, cache: ModuleFileCache,
firLazyDeclarationResolver: FirLazyDeclarationResolver, firLazyDeclarationResolver: FirLazyDeclarationResolver,
firIdeProvider: FirIdeProvider, firIdeProvider: FirIdeProvider,
towerDataContextCollector: FirTowerDataContextCollector,
): ReanalyzablePropertyStructureElement { ): ReanalyzablePropertyStructureElement {
val originalProperty = firSymbol.fir val originalProperty = firSymbol.fir
val newProperty = DeclarationCopyBuilder.createCopy(newKtDeclaration, originalProperty) val newProperty = DeclarationCopyBuilder.createCopy<FirProperty, KtElement>(newKtDeclaration, originalProperty)
return FileStructureUtil.withDeclarationReplaced(firFile, cache, originalProperty, newProperty) { return FileStructureUtil.withDeclarationReplaced(firFile, cache, originalProperty, newProperty) {
firLazyDeclarationResolver.lazyResolveDeclaration( firLazyDeclarationResolver.lazyResolveDeclaration(
newProperty, newProperty,
cache, cache,
FirResolvePhase.BODY_RESOLVE, FirResolvePhase.BODY_RESOLVE,
towerDataContextCollector,
checkPCE = true, checkPCE = true,
reresolveFile = true, reresolveFile = true,
) )
@@ -14,14 +14,18 @@ import org.jetbrains.kotlin.fir.expressions.impl.FirLazyExpression
import org.jetbrains.kotlin.fir.psi import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.visitors.FirTransformer import org.jetbrains.kotlin.fir.visitors.FirTransformer
import org.jetbrains.kotlin.fir.visitors.transformSingle import org.jetbrains.kotlin.fir.visitors.transformSingle
import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirDeclarationDesignation
import org.jetbrains.kotlin.idea.fir.low.level.api.providers.firIdeProvider import org.jetbrains.kotlin.idea.fir.low.level.api.providers.firIdeProvider
import org.jetbrains.kotlin.psi.KtNamedFunction import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtProperty import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.KtSecondaryConstructor import org.jetbrains.kotlin.psi.KtSecondaryConstructor
internal object FirLazyBodiesCalculator { internal object FirLazyBodiesCalculator {
fun calculateLazyBodiesInside(element: FirElement, designation: List<FirDeclaration>) { fun calculateLazyBodiesInside(element: FirElement, designation: FirDeclarationDesignation) {
element.transform<FirElement, MutableList<FirDeclaration>>(FirLazyBodiesCalculatorTransformer, designation.toMutableList()) element.transform<FirElement, MutableList<FirDeclaration>>(
FirLazyBodiesCalculatorTransformer,
designation.fullDesignation.toMutableList()
)
} }
fun calculateLazyBodiesIfPhaseRequires(firFile: FirFile, phase: FirResolvePhase) { fun calculateLazyBodiesIfPhaseRequires(firFile: FirFile, phase: FirResolvePhase) {
@@ -36,7 +40,7 @@ internal object FirLazyBodiesCalculator {
session = simpleFunction.moduleData.session, session = simpleFunction.moduleData.session,
baseScopeProvider = simpleFunction.moduleData.session.firIdeProvider.kotlinScopeProvider, baseScopeProvider = simpleFunction.moduleData.session.firIdeProvider.kotlinScopeProvider,
designation = designation, designation = designation,
declaration = simpleFunction.psi as KtNamedFunction rootNonLocalDeclaration = simpleFunction.psi as KtNamedFunction
) as FirSimpleFunction ) as FirSimpleFunction
simpleFunction.apply { simpleFunction.apply {
replaceBody(newFunction.body) replaceBody(newFunction.body)
@@ -52,7 +56,7 @@ internal object FirLazyBodiesCalculator {
session = secondaryConstructor.moduleData.session, session = secondaryConstructor.moduleData.session,
baseScopeProvider = secondaryConstructor.moduleData.session.firIdeProvider.kotlinScopeProvider, baseScopeProvider = secondaryConstructor.moduleData.session.firIdeProvider.kotlinScopeProvider,
designation = designation, designation = designation,
declaration = secondaryConstructor.psi as KtSecondaryConstructor rootNonLocalDeclaration = secondaryConstructor.psi as KtSecondaryConstructor
) as FirSimpleFunction ) as FirSimpleFunction
secondaryConstructor.apply { secondaryConstructor.apply {
@@ -67,7 +71,7 @@ internal object FirLazyBodiesCalculator {
session = firProperty.moduleData.session, session = firProperty.moduleData.session,
baseScopeProvider = firProperty.moduleData.session.firIdeProvider.kotlinScopeProvider, baseScopeProvider = firProperty.moduleData.session.firIdeProvider.kotlinScopeProvider,
designation = designation, designation = designation,
declaration = firProperty.psi as KtProperty rootNonLocalDeclaration = firProperty.psi as KtProperty
) as FirProperty ) as FirProperty
firProperty.getter?.takeIf { it.body is FirLazyBlock }?.let { getter -> firProperty.getter?.takeIf { it.body is FirLazyBlock }?.let { getter ->
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.idea.fir.low.level.api.lazy.resolve package org.jetbrains.kotlin.idea.fir.low.level.api.lazy.resolve
import com.intellij.psi.util.parentsOfType
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.psi import org.jetbrains.kotlin.fir.psi
@@ -14,6 +13,8 @@ import org.jetbrains.kotlin.fir.resolve.ResolutionMode
import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.providers.FirProvider import org.jetbrains.kotlin.fir.resolve.providers.FirProvider
import org.jetbrains.kotlin.fir.resolve.symbolProvider import org.jetbrains.kotlin.fir.resolve.symbolProvider
import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirDeclarationDesignation
import org.jetbrains.kotlin.idea.fir.low.level.api.api.collectDesignation
import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirTowerDataContextCollector import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirTowerDataContextCollector
import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.getNonLocalContainingOrThisDeclaration import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.getNonLocalContainingOrThisDeclaration
import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.FirFileBuilder import org.jetbrains.kotlin.idea.fir.low.level.api.file.builder.FirFileBuilder
@@ -107,7 +108,7 @@ internal class FirLazyDeclarationResolver(
} }
} }
private fun calculateLazyBodies(firDeclaration: FirDeclaration, designation: List<FirDeclaration>) { private fun calculateLazyBodies(firDeclaration: FirDeclaration, designation: FirDeclarationDesignation) {
FirLazyBodiesCalculator.calculateLazyBodiesInside(firDeclaration, designation) FirLazyBodiesCalculator.calculateLazyBodiesInside(firDeclaration, designation)
} }
@@ -120,9 +121,10 @@ internal class FirLazyDeclarationResolver(
toPhase: FirResolvePhase, toPhase: FirResolvePhase,
towerDataContextCollector: FirTowerDataContextCollector? = null, towerDataContextCollector: FirTowerDataContextCollector? = null,
checkPCE: Boolean, checkPCE: Boolean,
lastNonLazyPhase: FirResolvePhase = LAST_NON_LAZY_PHASE
) { ) {
if (fromPhase >= toPhase) return if (fromPhase >= toPhase) return
val nonLazyPhase = minOf(toPhase, LAST_NON_LAZY_PHASE) val nonLazyPhase = minOf(toPhase, lastNonLazyPhase)
val scopeSession = ScopeSession() val scopeSession = ScopeSession()
if (fromPhase < nonLazyPhase) { if (fromPhase < nonLazyPhase) {
@@ -138,7 +140,7 @@ internal class FirLazyDeclarationResolver(
resolveFileAnnotations(containerFirFile, moduleFileCache, scopeSession) resolveFileAnnotations(containerFirFile, moduleFileCache, scopeSession)
val nonLocalDeclarationToResolve = firDeclarationToResolve.getNonLocalDeclarationToResolve(provider, moduleFileCache) val nonLocalDeclarationToResolve = firDeclarationToResolve.getNonLocalDeclarationToResolve(provider, moduleFileCache)
val designation = nonLocalDeclarationToResolve.getDesignation(containerFirFile, provider, moduleFileCache) val designation = nonLocalDeclarationToResolve.collectDesignation()
executeWithoutPCE { executeWithoutPCE {
calculateLazyBodies(firDeclarationToResolve, designation) calculateLazyBodies(firDeclarationToResolve, designation)
@@ -165,9 +167,9 @@ internal class FirLazyDeclarationResolver(
phase: FirResolvePhase, phase: FirResolvePhase,
scopeSession: ScopeSession, scopeSession: ScopeSession,
towerDataContextCollector: FirTowerDataContextCollector?, towerDataContextCollector: FirTowerDataContextCollector?,
designation: List<FirDeclaration> designation: FirDeclarationDesignation
) { ) {
if (designation.all { it.resolvePhase >= phase }) { if (designation.fullDesignation.all { it.resolvePhase >= phase }) {
return return
} }
@@ -179,29 +181,49 @@ internal class FirLazyDeclarationResolver(
) )
firFileBuilder.firPhaseRunner.runPhaseWithCustomResolve(phase) { firFileBuilder.firPhaseRunner.runPhaseWithCustomResolve(phase) {
containerFirFile.transform<FirFile, ResolutionMode>(transformer, ResolutionMode.ContextIndependent) transformer.transformDeclaration()
} }
} }
private fun FirResolvePhase.createLazyTransformer( private fun FirResolvePhase.createLazyTransformer(
designation: List<FirDeclaration>, designation: FirDeclarationDesignation,
containerFirFile: FirFile, containerFirFile: FirFile,
scopeSession: ScopeSession, scopeSession: ScopeSession,
towerDataContextCollector: FirTowerDataContextCollector? towerDataContextCollector: FirTowerDataContextCollector?
) = when (this) { ): FirLazyTransformerForIDE = when (this) {
FirResolvePhase.SUPER_TYPES -> FirDesignatedSupertypeResolverTransformerForIDE(
designation,
containerFirFile,
containerFirFile.moduleData.session,
scopeSession
)
FirResolvePhase.SEALED_CLASS_INHERITORS -> FirLazyTransformerForIDE.EMPTY
FirResolvePhase.TYPES -> FirDesignatedTypeResolverTransformerForIDE(
containerFirFile,
designation,
containerFirFile.moduleData.session,
scopeSession,
)
FirResolvePhase.STATUS -> FirDesignatedStatusResolveTransformerForIDE(
designation,
containerFirFile.moduleData.session,
scopeSession
)
FirResolvePhase.CONTRACTS -> FirDesignatedContractsResolveTransformerForIDE( FirResolvePhase.CONTRACTS -> FirDesignatedContractsResolveTransformerForIDE(
FirDesignation(designation), containerFirFile,
designation,
containerFirFile.moduleData.session, containerFirFile.moduleData.session,
scopeSession, scopeSession,
) )
FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE -> FirDesignatedImplicitTypesTransformerForIDE( FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE -> FirDesignatedImplicitTypesTransformerForIDE(
FirDesignation(designation), containerFirFile,
designation,
containerFirFile.moduleData.session, containerFirFile.moduleData.session,
scopeSession, scopeSession
towerDataContextCollector,
) )
FirResolvePhase.BODY_RESOLVE -> FirDesignatedBodyResolveTransformerForIDE( FirResolvePhase.BODY_RESOLVE -> FirDesignatedBodyResolveTransformerForIDE(
FirDesignation(designation), containerFirFile,
designation,
containerFirFile.moduleData.session, containerFirFile.moduleData.session,
scopeSession, scopeSession,
towerDataContextCollector towerDataContextCollector
@@ -209,27 +231,6 @@ internal class FirLazyDeclarationResolver(
else -> error("Non-lazy phase $this") else -> error("Non-lazy phase $this")
} }
@OptIn(ExperimentalStdlibApi::class)
private fun FirDeclaration.getDesignation(
containerFirFile: FirFile,
provider: FirProvider,
moduleFileCache: ModuleFileCache
): List<FirDeclaration> = buildList {
if (this !is FirFile) {
val ktDeclaration = ktDeclaration
ktDeclaration.parentsOfType<KtClassOrObject>(withSelf = true)
.filter { it !is KtEnumEntry }
.map { it.findSourceNonLocalFirDeclaration(firFileBuilder, provider.symbolProvider, moduleFileCache, containerFirFile) }
.toList()
.asReversed()
.let(::addAll)
if (this@getDesignation is FirCallableDeclaration<*> || this@getDesignation is FirTypeAlias) {
add(this@getDesignation)
}
}
}
private fun FirDeclaration.getNonLocalDeclarationToResolve(provider: FirProvider, moduleFileCache: ModuleFileCache): FirDeclaration { private fun FirDeclaration.getNonLocalDeclarationToResolve(provider: FirProvider, moduleFileCache: ModuleFileCache): FirDeclaration {
if (this is FirFile) return this if (this is FirFile) return this
val ktDeclaration = psi as? KtDeclaration ?: error("FirDeclaration should have a PSI of type KtDeclaration") val ktDeclaration = psi as? KtDeclaration ?: error("FirDeclaration should have a PSI of type KtDeclaration")
@@ -77,6 +77,7 @@ private constructor(
check(mode == AnalysisSessionMode.REGULAR) { check(mode == AnalysisSessionMode.REGULAR) {
"Cannot create context-dependent copy of KtAnalysis session from a context dependent one" "Cannot create context-dependent copy of KtAnalysis session from a context dependent one"
} }
require(!dependencyKtElement.isPhysical) { "Depended context should be build only for non-physical elements" }
val contextResolveState = LowLevelFirApiFacadeForDependentCopy.getResolveStateForDependedCopy( val contextResolveState = LowLevelFirApiFacadeForDependentCopy.getResolveStateForDependedCopy(
originalState = firResolveState, originalState = firResolveState,
@@ -8,9 +8,9 @@ package org.jetbrains.kotlin.idea.frontend.api.fir.components
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.resolve.calls.ImplicitReceiverValue import org.jetbrains.kotlin.fir.resolve.calls.ImplicitReceiverValue
import org.jetbrains.kotlin.idea.fir.low.level.api.api.LowLevelFirApiFacadeForDependentCopy.getTowerContextProvider
import org.jetbrains.kotlin.idea.fir.low.level.api.api.getFirFile import org.jetbrains.kotlin.idea.fir.low.level.api.api.getFirFile
import org.jetbrains.kotlin.idea.fir.low.level.api.api.getOrBuildFirOfType import org.jetbrains.kotlin.idea.fir.low.level.api.api.getOrBuildFirOfType
import org.jetbrains.kotlin.idea.fir.low.level.api.api.getTowerDataContextUnsafe
import org.jetbrains.kotlin.idea.fir.low.level.api.resolver.ResolutionParameters import org.jetbrains.kotlin.idea.fir.low.level.api.resolver.ResolutionParameters
import org.jetbrains.kotlin.idea.fir.low.level.api.resolver.SingleCandidateResolutionMode import org.jetbrains.kotlin.idea.fir.low.level.api.resolver.SingleCandidateResolutionMode
import org.jetbrains.kotlin.idea.fir.low.level.api.resolver.SingleCandidateResolver import org.jetbrains.kotlin.idea.fir.low.level.api.resolver.SingleCandidateResolver
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirSymbol
import org.jetbrains.kotlin.idea.frontend.api.fir.utils.weakRef import org.jetbrains.kotlin.idea.frontend.api.fir.utils.weakRef
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtCallableSymbol import org.jetbrains.kotlin.idea.frontend.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.idea.frontend.api.withValidityAssertion import org.jetbrains.kotlin.idea.frontend.api.withValidityAssertion
import org.jetbrains.kotlin.idea.util.getElementTextInContext
import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtSimpleNameExpression import org.jetbrains.kotlin.psi.KtSimpleNameExpression
@@ -84,7 +85,9 @@ internal class KtFirCompletionCandidateChecker(
firFile: FirFile, firFile: FirFile,
fakeNameExpression: KtSimpleNameExpression fakeNameExpression: KtSimpleNameExpression
): Sequence<ImplicitReceiverValue<*>?> { ): Sequence<ImplicitReceiverValue<*>?> {
val towerDataContext = analysisSession.firResolveState.getTowerDataContextUnsafe(fakeNameExpression) val towerDataContext = analysisSession.firResolveState.getTowerContextProvider()
.getClosestAvailableParentContext(fakeNameExpression)
?: error("Cannot find enclosing declaration for ${fakeNameExpression.getElementTextInContext()}")
return sequence { return sequence {
yield(null) // otherwise explicit receiver won't be checked when there are no implicit receivers in completion position yield(null) // otherwise explicit receiver won't be checked when there are no implicit receivers in completion position
@@ -45,7 +45,10 @@ import org.jetbrains.kotlin.fir.types.classId
import org.jetbrains.kotlin.fir.types.lowerBoundIfFlexible import org.jetbrains.kotlin.fir.types.lowerBoundIfFlexible
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState
import org.jetbrains.kotlin.idea.fir.low.level.api.api.LowLevelFirApiFacadeForDependentCopy
import org.jetbrains.kotlin.idea.fir.low.level.api.api.LowLevelFirApiFacadeForDependentCopy.getTowerContextProvider
import org.jetbrains.kotlin.idea.fir.low.level.api.api.getOrBuildFir import org.jetbrains.kotlin.idea.fir.low.level.api.api.getOrBuildFir
import org.jetbrains.kotlin.idea.fir.low.level.api.element.builder.FirTowerContextProvider
import org.jetbrains.kotlin.idea.frontend.api.tokens.ValidityToken import org.jetbrains.kotlin.idea.frontend.api.tokens.ValidityToken
import org.jetbrains.kotlin.idea.frontend.api.components.KtReferenceShortener import org.jetbrains.kotlin.idea.frontend.api.components.KtReferenceShortener
import org.jetbrains.kotlin.idea.frontend.api.components.ShortenCommand import org.jetbrains.kotlin.idea.frontend.api.components.ShortenCommand
@@ -72,7 +75,10 @@ internal class KtFirReferenceShortener(
val firDeclaration = declarationToVisit.getOrBuildFir(firResolveState) val firDeclaration = declarationToVisit.getOrBuildFir(firResolveState)
val collector = ElementsToShortenCollector(context) val towerContext =
LowLevelFirApiFacadeForDependentCopy.onAirGetTowerContextProvider(firResolveState, declarationToVisit)
val collector = ElementsToShortenCollector(context, towerContext)
firDeclaration.accept(collector) firDeclaration.accept(collector)
return ShortenCommandImpl( return ShortenCommandImpl(
@@ -139,9 +145,8 @@ private class FirShorteningContext(val firResolveState: FirModuleResolveState) {
} }
@OptIn(ExperimentalStdlibApi::class) @OptIn(ExperimentalStdlibApi::class)
fun findScopesAtPosition(position: KtElement, newImports: List<FqName>): List<FirScope>? { fun findScopesAtPosition(position: KtElement, newImports: List<FqName>, towerContextProvider: FirTowerContextProvider): List<FirScope>? {
val towerDataContext = firResolveState.getTowerDataContextForElement(position) ?: return null val towerDataContext = towerContextProvider.getClosestAvailableParentContext(position) ?: return null
val result = buildList<FirScope> { val result = buildList<FirScope> {
addAll(towerDataContext.nonLocalTowerDataElements.mapNotNull { it.scope }) addAll(towerDataContext.nonLocalTowerDataElements.mapNotNull { it.scope })
addIfNotNull(createFakeImportingScope(newImports)) addIfNotNull(createFakeImportingScope(newImports))
@@ -181,7 +186,8 @@ private sealed class ElementToShorten
private class ShortenType(val element: KtUserType, val nameToImport: FqName? = null) : ElementToShorten() private class ShortenType(val element: KtUserType, val nameToImport: FqName? = null) : ElementToShorten()
private class ShortenQualifier(val element: KtDotQualifiedExpression, val nameToImport: FqName? = null) : ElementToShorten() private class ShortenQualifier(val element: KtDotQualifiedExpression, val nameToImport: FqName? = null) : ElementToShorten()
private class ElementsToShortenCollector(private val shorteningContext: FirShorteningContext) : FirVisitorVoid() { private class ElementsToShortenCollector(private val shorteningContext: FirShorteningContext, private val towerContextProvider: FirTowerContextProvider) :
FirVisitorVoid() {
val namesToImport: MutableList<FqName> = mutableListOf() val namesToImport: MutableList<FqName> = mutableListOf()
val typesToShorten: MutableList<KtUserType> = mutableListOf() val typesToShorten: MutableList<KtUserType> = mutableListOf()
val qualifiersToShorten: MutableList<KtDotQualifiedExpression> = mutableListOf() val qualifiersToShorten: MutableList<KtDotQualifiedExpression> = mutableListOf()
@@ -230,7 +236,7 @@ private class ElementsToShortenCollector(private val shorteningContext: FirShort
val allClassIds = wholeClassifierId.outerClassesWithSelf val allClassIds = wholeClassifierId.outerClassesWithSelf
val allTypeElements = wholeTypeElement.qualifiersWithSelf val allTypeElements = wholeTypeElement.qualifiersWithSelf
val positionScopes = shorteningContext.findScopesAtPosition(wholeTypeElement, namesToImport) ?: return null val positionScopes = shorteningContext.findScopesAtPosition(wholeTypeElement, namesToImport, towerContextProvider) ?: return null
for ((classId, typeElement) in allClassIds.zip(allTypeElements)) { for ((classId, typeElement) in allClassIds.zip(allTypeElements)) {
// if qualifier is null, then this type have no package and thus cannot be shortened // if qualifier is null, then this type have no package and thus cannot be shortened
@@ -280,7 +286,7 @@ private class ElementsToShortenCollector(private val shorteningContext: FirShort
wholeClassQualifier: ClassId, wholeClassQualifier: ClassId,
wholeQualifierElement: KtDotQualifiedExpression wholeQualifierElement: KtDotQualifiedExpression
): ShortenQualifier? { ): ShortenQualifier? {
val positionScopes = shorteningContext.findScopesAtPosition(wholeQualifierElement, namesToImport) ?: return null val positionScopes = shorteningContext.findScopesAtPosition(wholeQualifierElement, namesToImport, towerContextProvider) ?: return null
val allClassIds = wholeClassQualifier.outerClassesWithSelf val allClassIds = wholeClassQualifier.outerClassesWithSelf
val allQualifiers = wholeQualifierElement.qualifiersWithSelf val allQualifiers = wholeQualifierElement.qualifiersWithSelf
@@ -313,7 +319,7 @@ private class ElementsToShortenCollector(private val shorteningContext: FirShort
val propertyId = (resolvedNamedReference.resolvedSymbol as? FirCallableSymbol<*>)?.callableId ?: return val propertyId = (resolvedNamedReference.resolvedSymbol as? FirCallableSymbol<*>)?.callableId ?: return
val scopes = shorteningContext.findScopesAtPosition(qualifiedProperty, namesToImport) ?: return val scopes = shorteningContext.findScopesAtPosition(qualifiedProperty, namesToImport, towerContextProvider) ?: return
val singleAvailableProperty = shorteningContext.findPropertiesInScopes(scopes, propertyId.callableName) val singleAvailableProperty = shorteningContext.findPropertiesInScopes(scopes, propertyId.callableName)
val propertyToShorten = when { val propertyToShorten = when {
@@ -334,7 +340,7 @@ private class ElementsToShortenCollector(private val shorteningContext: FirShort
val calleeReference = functionCall.calleeReference val calleeReference = functionCall.calleeReference
val callableId = findUnambiguousReferencedCallableId(calleeReference) ?: return val callableId = findUnambiguousReferencedCallableId(calleeReference) ?: return
val scopes = shorteningContext.findScopesAtPosition(callExpression, namesToImport) ?: return val scopes = shorteningContext.findScopesAtPosition(callExpression, namesToImport, towerContextProvider) ?: return
val availableCallables = shorteningContext.findFunctionsInScopes(scopes, callableId.callableName) val availableCallables = shorteningContext.findFunctionsInScopes(scopes, callableId.callableName)
val callToShorten = when { val callToShorten = when {
@@ -17,7 +17,8 @@ import org.jetbrains.kotlin.fir.resolve.scope
import org.jetbrains.kotlin.fir.scopes.* import org.jetbrains.kotlin.fir.scopes.*
import org.jetbrains.kotlin.fir.scopes.impl.* import org.jetbrains.kotlin.fir.scopes.impl.*
import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState
import org.jetbrains.kotlin.idea.fir.low.level.api.api.getTowerDataContextUnsafe import org.jetbrains.kotlin.idea.fir.low.level.api.api.LowLevelFirApiFacadeForDependentCopy.getTowerContextProvider
import org.jetbrains.kotlin.idea.frontend.api.tokens.ValidityToken
import org.jetbrains.kotlin.idea.frontend.api.ValidityTokenOwner import org.jetbrains.kotlin.idea.frontend.api.ValidityTokenOwner
import org.jetbrains.kotlin.idea.frontend.api.components.KtImplicitReceiver import org.jetbrains.kotlin.idea.frontend.api.components.KtImplicitReceiver
import org.jetbrains.kotlin.idea.frontend.api.components.KtScopeContext import org.jetbrains.kotlin.idea.frontend.api.components.KtScopeContext
@@ -33,9 +34,9 @@ import org.jetbrains.kotlin.idea.frontend.api.symbols.KtFileSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtPackageSymbol import org.jetbrains.kotlin.idea.frontend.api.symbols.KtPackageSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolWithDeclarations import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolWithDeclarations
import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolWithMembers import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolWithMembers
import org.jetbrains.kotlin.idea.frontend.api.tokens.ValidityToken
import org.jetbrains.kotlin.idea.frontend.api.types.KtType import org.jetbrains.kotlin.idea.frontend.api.types.KtType
import org.jetbrains.kotlin.idea.frontend.api.withValidityAssertion import org.jetbrains.kotlin.idea.frontend.api.withValidityAssertion
import org.jetbrains.kotlin.idea.util.getElementTextInContext
import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import java.util.* import java.util.*
@@ -142,7 +143,10 @@ internal class KtFirScopeProvider(
originalFile: KtFile, originalFile: KtFile,
positionInFakeFile: KtElement positionInFakeFile: KtElement
): KtScopeContext = withValidityAssertion { ): KtScopeContext = withValidityAssertion {
val towerDataContext = analysisSession.firResolveState.getTowerDataContextUnsafe(positionInFakeFile)
val towerDataContext =
analysisSession.firResolveState.getTowerContextProvider().getClosestAvailableParentContext(positionInFakeFile)
?: error("Cannot find enclosing declaration for ${positionInFakeFile.getElementTextInContext()}")
val implicitReceivers = towerDataContext.nonLocalTowerDataElements.mapNotNull { it.implicitReceiver }.distinct() val implicitReceivers = towerDataContext.nonLocalTowerDataElements.mapNotNull { it.implicitReceiver }.distinct()
val implicitKtReceivers = implicitReceivers.map { receiver -> val implicitKtReceivers = implicitReceivers.map { receiver ->