From aaefe94763d6ddd40f3ce2bf90110df37072ac67 Mon Sep 17 00:00:00 2001 From: Igor Yakovlev Date: Wed, 21 Apr 2021 18:26:36 +0200 Subject: [PATCH] [FIR IDE] Refactor low level resolve state for completion Rename refactorings Remove redundant methods and implementations Increase code-logic locality Removed redundant entities --- .../KotlinFirCompletionContributor.kt | 2 - .../context/FirPositionCompletionContext.kt | 7 +- .../idea/frontend/api/KtAnalysisSession.kt | 2 +- .../frontend/api/KtAnalysisSessionProvider.kt | 20 +++-- ...on.kt => FirModuleResolveStateDepended.kt} | 87 ++++++++----------- .../level/api/FirModuleResolveStateImpl.kt | 58 +++---------- .../level/api/api/DeclarationCopyBuilder.kt | 26 +++--- .../level/api/api/FirModuleResolveState.kt | 20 ----- .../api/LowLevelFirApiFacadeForCompletion.kt | 33 ------- .../LowLevelFirApiFacadeForDependentCopy.kt | 78 +++++++++++++++++ .../AbstractFirLazyDeclarationResolveTest.kt | 1 + .../frontend/api/fir/KtFirAnalysisSession.kt | 54 ++++-------- .../fir/utils/EnclosingDeclarationContext.kt | 79 ----------------- 13 files changed, 179 insertions(+), 288 deletions(-) rename idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/{FirModuleResolveStateForCompletion.kt => FirModuleResolveStateDepended.kt} (63%) delete mode 100644 idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/LowLevelFirApiFacadeForCompletion.kt create mode 100644 idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/LowLevelFirApiFacadeForDependentCopy.kt delete mode 100644 idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/utils/EnclosingDeclarationContext.kt diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/KotlinFirCompletionContributor.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/KotlinFirCompletionContributor.kt index ab012833515..ec18104d154 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/KotlinFirCompletionContributor.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/KotlinFirCompletionContributor.kt @@ -6,7 +6,6 @@ package org.jetbrains.kotlin.idea.completion import com.intellij.codeInsight.completion.* -import com.intellij.codeInsight.lookup.LookupElement import com.intellij.patterns.PlatformPatterns import com.intellij.patterns.PsiJavaPatterns import com.intellij.util.ProcessingContext @@ -26,7 +25,6 @@ import org.jetbrains.kotlin.idea.frontend.api.scopes.KtCompositeScope import org.jetbrains.kotlin.idea.frontend.api.scopes.KtScope import org.jetbrains.kotlin.idea.frontend.api.scopes.KtScopeNameFilter 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.KtSymbolWithVisibility import org.jetbrains.kotlin.idea.frontend.api.types.KtClassType import org.jetbrains.kotlin.idea.frontend.api.types.KtType diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/context/FirPositionCompletionContext.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/context/FirPositionCompletionContext.kt index cd6df1b3267..887061971b3 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/context/FirPositionCompletionContext.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/context/FirPositionCompletionContext.kt @@ -8,16 +8,13 @@ package org.jetbrains.kotlin.idea.completion.context import com.intellij.psi.PsiElement import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession import org.jetbrains.kotlin.idea.frontend.api.analyse -import org.jetbrains.kotlin.idea.frontend.api.analyseInFakeAnalysisSession +import org.jetbrains.kotlin.idea.frontend.api.analyseInDependedAnalysisSession import org.jetbrains.kotlin.idea.references.KtSimpleNameReference import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtLabelReferenceExpression import org.jetbrains.kotlin.psi.KtSimpleNameExpression import org.jetbrains.kotlin.psi.psiUtil.getReceiverExpression -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract internal sealed class FirPositionCompletionContext { abstract val position: PsiElement @@ -51,7 +48,7 @@ internal object FirPositionCompletionContextDetector { action: KtAnalysisSession.() -> Unit ) { return when (positionContext) { - is FirNameReferencePositionContext -> analyseInFakeAnalysisSession( + is FirNameReferencePositionContext -> analyseInDependedAnalysisSession( basicContext.originalKtFile, positionContext.nameExpression, action diff --git a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/KtAnalysisSession.kt b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/KtAnalysisSession.kt index 88ab822f5b1..6542dda006f 100644 --- a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/KtAnalysisSession.kt +++ b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/KtAnalysisSession.kt @@ -47,7 +47,7 @@ abstract class KtAnalysisSession(final override val token: ValidityToken) : Vali override val analysisSession: KtAnalysisSession get() = this - abstract fun createContextDependentCopy(originalKtFile: KtFile, fakeKtElement: KtElement): KtAnalysisSession + abstract fun createContextDependentCopy(originalKtFile: KtFile, dependencyKtElement: KtElement): KtAnalysisSession internal val smartCastProvider: KtSmartCastProvider get() = smartCastProviderImpl protected abstract val smartCastProviderImpl: KtSmartCastProvider diff --git a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/KtAnalysisSessionProvider.kt b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/KtAnalysisSessionProvider.kt index 94258843f2f..97847cb52f2 100644 --- a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/KtAnalysisSessionProvider.kt +++ b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/KtAnalysisSessionProvider.kt @@ -36,10 +36,14 @@ abstract class KtAnalysisSessionProvider : Disposable { abstract fun getAnalysisSession(contextElement: KtElement, factory: ValidityTokenFactory): KtAnalysisSession @InvalidWayOfUsingAnalysisSession - inline fun analyseInFakeAnalysisSession(originalFile: KtFile, fakeExpresion: KtElement, action: KtAnalysisSession.() -> R): R { - val fakeAnalysisSession = getAnalysisSession(originalFile, ReadActionConfinementValidityTokenFactory) - .createContextDependentCopy(originalFile, fakeExpresion) - return analyse(fakeAnalysisSession, ReadActionConfinementValidityTokenFactory, action) + inline fun analyseInDependedAnalysisSession( + originalFile: KtFile, + dependencyExpression: KtElement, + action: KtAnalysisSession.() -> R + ): R { + val dependedAnalysisSession = getAnalysisSession(originalFile, ReadActionConfinementValidityTokenFactory) + .createContextDependentCopy(originalFile, dependencyExpression) + return analyse(dependedAnalysisSession, ReadActionConfinementValidityTokenFactory, action) } @InvalidWayOfUsingAnalysisSession @@ -89,8 +93,12 @@ inline fun analyseWithCustomToken( contextElement.project.service().analyse(contextElement, tokenFactory, action) @OptIn(InvalidWayOfUsingAnalysisSession::class) -inline fun analyseInFakeAnalysisSession(originalFile: KtFile, fakeExpresion: KtElement, action: KtAnalysisSession.() -> R): R = - originalFile.project.service().analyseInFakeAnalysisSession(originalFile, fakeExpresion, action) +inline fun analyseInDependedAnalysisSession( + originalFile: KtFile, + dependencyExpression: KtElement, + action: KtAnalysisSession.() -> R +): R = + originalFile.project.service().analyseInDependedAnalysisSession(originalFile, dependencyExpression, action) /** * Execute given [action] in [KtAnalysisSession] context like [analyse] does but execute it in read action diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateForCompletion.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateDepended.kt similarity index 63% rename from idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateForCompletion.kt rename to idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateDepended.kt index af8eb2221aa..55706368873 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateForCompletion.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateDepended.kt @@ -6,7 +6,6 @@ package org.jetbrains.kotlin.idea.fir.low.level.api import com.intellij.openapi.project.Project -import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic @@ -14,31 +13,34 @@ import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.resolve.FirTowerDataContext -import org.jetbrains.kotlin.fir.resolve.providers.FirProvider 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.api.DiagnosticCheckerFilter 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.getClosestAvailableParentContext 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.originalKtFile -import org.jetbrains.kotlin.idea.frontend.api.components.KtDiagnosticCheckerFilter import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtLambdaExpression -internal class FirModuleResolveStateForCompletion( - override val project: Project, - private val originalState: FirModuleResolveStateImpl +internal class FirModuleResolveStateDepended( + dependencyFirDeclaration: FirDeclaration, + originalFirFile: FirFile, + private val originalState: FirModuleResolveStateImpl, ) : FirModuleResolveState() { - override val moduleInfo: IdeaModuleInfo get() = originalState.moduleInfo + override val project: Project get() = originalState.project + override val moduleInfo: IdeaModuleInfo get() = originalState.moduleInfo override val rootModuleSession get() = originalState.rootModuleSession private val fileStructureCache = originalState.fileStructureCache - private val completionMapping = mutableMapOf() + private val collector = FirTowerDataContextCollector() override fun getSessionFor(moduleInfo: IdeaModuleInfo): FirSession = originalState.getSessionFor(moduleInfo) @@ -57,24 +59,8 @@ internal class FirModuleResolveStateForCompletion( override fun getFirFile(ktFile: KtFile): FirFile = originalState.getFirFile(ktFile) - override fun isFirFileBuilt(ktFile: KtFile): Boolean { - error("Should not be called in in completion") - } - - override fun recordPsiToFirMappingsForCompletionFrom(fir: FirDeclaration, firFile: FirFile, ktFile: KtFile) { - synchronized(completionMapping) { fir.accept(FirElementsRecorder(), completionMapping) } - } - - override fun resolvedFirToPhase(declaration: D, toPhase: FirResolvePhase): D { - return originalState.resolvedFirToPhase(declaration, toPhase) - } - - override fun lazyResolveDeclarationForCompletion( - firDeclaration: FirDeclaration, - containerFirFile: FirFile, - ) { - originalState.lazyResolveDeclarationForCompletion(firDeclaration, containerFirFile) - } + override fun resolvedFirToPhase(declaration: D, toPhase: FirResolvePhase): D = + originalState.resolvedFirToPhase(declaration, toPhase) override fun getFirFile(declaration: FirDeclaration, cache: ModuleFileCache): FirFile? { val ktFile = declaration.containingKtFileIfAny ?: return null @@ -83,34 +69,37 @@ internal class FirModuleResolveStateForCompletion( return null } + override fun getDiagnostics(element: KtElement, filter: DiagnosticCheckerFilter): List> = + TODO("Diagnostics are not implemented for depended state") - override fun getDiagnostics(element: KtElement, filter: DiagnosticCheckerFilter): List> { - error("Diagnostics should not be retrieved in completion") - } - - override fun collectDiagnosticsForFile(ktFile: KtFile, filter: DiagnosticCheckerFilter): Collection> { - error("Diagnostics should not be retrieved in completion") - } + override fun collectDiagnosticsForFile(ktFile: KtFile, filter: DiagnosticCheckerFilter): Collection> = + TODO("Diagnostics are not implemented for depended state") @OptIn(InternalForInline::class) - override fun findNonLocalSourceFirDeclaration(ktDeclaration: KtDeclaration): FirDeclaration { - error("Should not be used in completion") - } + override fun findSourceFirDeclaration(ktDeclaration: KtLambdaExpression): FirDeclaration = + originalState.findSourceFirDeclaration(ktDeclaration) @OptIn(InternalForInline::class) - override fun findSourceFirDeclaration(ktDeclaration: KtDeclaration): FirDeclaration { - return originalState.findSourceFirDeclaration(ktDeclaration) - } - - @OptIn(InternalForInline::class) - override fun findSourceFirDeclaration(ktDeclaration: KtLambdaExpression): FirDeclaration { - error("Should not be used in completion") - } - - override fun getBuiltFirFileOrNull(ktFile: KtFile): FirFile? { - error("Should not be used in completion") - } + override fun findSourceFirDeclaration(ktDeclaration: KtDeclaration): FirDeclaration = + originalState.findSourceFirDeclaration(ktDeclaration) override fun getTowerDataContextForElement(element: KtElement): FirTowerDataContext? = - originalState.getTowerDataContextForElement(element) + 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) } + } } \ No newline at end of file diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateImpl.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateImpl.kt index 084a06614be..47e9d006466 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateImpl.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveStateImpl.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.idea.fir.low.level.api import com.intellij.openapi.project.Project +import org.jetbrains.annotations.TestOnly import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic @@ -74,24 +75,12 @@ internal class FirModuleResolveStateImpl( override fun collectDiagnosticsForFile(ktFile: KtFile, filter: DiagnosticCheckerFilter): Collection> = diagnosticsCollector.collectDiagnosticsForFile(ktFile, filter) - override fun getBuiltFirFileOrNull(ktFile: KtFile): FirFile? { + @TestOnly + internal fun getBuiltFirFileOrNull(ktFile: KtFile): FirFile? { val cache = sessionProvider.getModuleCache(ktFile.getModuleInfo() as ModuleSourceInfo) return firFileBuilder.getBuiltFirFileOrNull(ktFile, cache) } - override fun recordPsiToFirMappingsForCompletionFrom(fir: FirDeclaration, firFile: FirFile, ktFile: KtFile) { - error("Should be called only from FirModuleResolveStateForCompletion") - } - - @OptIn(InternalForInline::class) - override fun findNonLocalSourceFirDeclaration( - ktDeclaration: KtDeclaration, - ): FirDeclaration = ktDeclaration.findSourceNonLocalFirDeclaration( - firFileBuilder, - rootModuleSession.firIdeProvider.symbolProvider, - sessionProvider.getModuleCache(ktDeclaration.getModuleInfo() as ModuleSourceInfo) - ) - @OptIn(InternalForInline::class) override fun findSourceFirDeclaration(ktDeclaration: KtDeclaration): FirDeclaration = findSourceFirDeclarationByExpression(ktDeclaration) @@ -104,25 +93,28 @@ internal class FirModuleResolveStateImpl( * [ktDeclaration] should be either [KtDeclaration] or [KtLambdaExpression] */ private fun findSourceFirDeclarationByExpression(ktDeclaration: KtExpression): FirDeclaration { - val nonLocalFirDeclaration = ktDeclaration.getNonLocalContainingOrThisDeclaration() + val nonLocalNamedDeclaration = ktDeclaration.getNonLocalContainingOrThisDeclaration() ?: error("Declaration should have non-local container${ktDeclaration.getElementTextInContext()}") - if (ktDeclaration == nonLocalFirDeclaration) return findNonLocalSourceFirDeclaration(ktDeclaration as KtDeclaration) - val container = nonLocalFirDeclaration.findSourceNonLocalFirDeclaration( + + val nonLocalFirForNamedDeclaration = nonLocalNamedDeclaration.findSourceNonLocalFirDeclaration( firFileBuilder, rootModuleSession.firIdeProvider.symbolProvider, sessionProvider.getModuleCache(ktDeclaration.getModuleInfo() as ModuleSourceInfo) ) - if (container.resolvePhase < FirResolvePhase.BODY_RESOLVE) { - val cache = (container.moduleData.session as FirIdeSourcesSession).cache + + if (ktDeclaration == nonLocalNamedDeclaration) return nonLocalFirForNamedDeclaration + + if (nonLocalFirForNamedDeclaration.resolvePhase < FirResolvePhase.BODY_RESOLVE) { + val cache = (nonLocalFirForNamedDeclaration.moduleData.session as FirIdeSourcesSession).cache firLazyDeclarationResolver.lazyResolveDeclaration( - container, + nonLocalFirForNamedDeclaration, cache, FirResolvePhase.BODY_RESOLVE, checkPCE = false, /*TODO*/ towerDataContextCollector = collector, ) } - val firDeclaration = FirElementFinder.findElementIn(container) { firDeclaration -> + val firDeclaration = FirElementFinder.findElementIn(nonLocalFirForNamedDeclaration) { firDeclaration -> when (val realPsi = firDeclaration.realPsi) { is KtObjectLiteralExpression -> realPsi.objectDeclaration == ktDeclaration is KtFunctionLiteral -> realPsi.parent == ktDeclaration @@ -133,12 +125,6 @@ internal class FirModuleResolveStateImpl( ?: error("FirDeclaration was not found for\n${ktDeclaration.getElementTextInContext()}") } - override fun isFirFileBuilt(ktFile: KtFile): Boolean { - val moduleSourceInfo = ktFile.getModuleInfo() as? ModuleSourceInfo ?: return true - val cache = sessionProvider.getModuleCache(moduleSourceInfo) - return firFileBuilder.isFirFileBuilt(ktFile, cache) - } - override fun resolvedFirToPhase(declaration: D, toPhase: FirResolvePhase): D { val fileCache = when (val session = declaration.moduleData.session) { is FirIdeSourcesSession -> session.cache @@ -154,24 +140,6 @@ internal class FirModuleResolveStateImpl( return declaration } - override fun lazyResolveDeclarationForCompletion( - firDeclaration: FirDeclaration, - containerFirFile: FirFile, - ) { - firFileBuilder.runCustomResolveWithPCECheck(containerFirFile, rootModuleSession.cache) { - firLazyDeclarationResolver.runLazyResolveWithoutLock( - firDeclaration, - rootModuleSession.cache, - containerFirFile, - containerFirFile.moduleData.session.firIdeProvider, - fromPhase = firDeclaration.resolvePhase, - toPhase = FirResolvePhase.BODY_RESOLVE, - towerDataContextCollector = collector, - checkPCE = true - ) - } - } - override fun getFirFile(declaration: FirDeclaration, cache: ModuleFileCache): FirFile? = cache.getContainerFirFile(declaration) diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/DeclarationCopyBuilder.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/DeclarationCopyBuilder.kt index b4e4bdd8322..e047b68b75b 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/DeclarationCopyBuilder.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/DeclarationCopyBuilder.kt @@ -18,31 +18,31 @@ import org.jetbrains.kotlin.psi.* object DeclarationCopyBuilder { fun createDeclarationCopy( originalFirDeclaration: FirDeclaration, - fakeKtDeclaration: KtDeclaration, + copiedKtDeclaration: KtDeclaration, state: FirModuleResolveState, ): FirDeclaration { - return when (fakeKtDeclaration) { + return when (copiedKtDeclaration) { is KtNamedFunction -> createFunctionCopy( - fakeKtDeclaration, + copiedKtDeclaration, originalFirDeclaration as FirSimpleFunction, state ) is KtProperty -> createPropertyCopy( - fakeKtDeclaration, + copiedKtDeclaration, originalFirDeclaration as FirProperty, state ) is KtClassOrObject -> createClassCopy( - fakeKtDeclaration, + copiedKtDeclaration, originalFirDeclaration as FirRegularClass, state ) is KtTypeAlias -> createTypeAliasCopy( - fakeKtDeclaration, + copiedKtDeclaration, originalFirDeclaration as FirTypeAlias, state ) - else -> error("Unsupported declaration ${fakeKtDeclaration::class.simpleName}") + else -> error("Unsupported declaration ${copiedKtDeclaration::class.simpleName}") } } @@ -64,11 +64,11 @@ object DeclarationCopyBuilder { } private fun createClassCopy( - fakeKtClassOrObject: KtClassOrObject, + copiedKtClassOrObject: KtClassOrObject, originalFirClass: FirRegularClass, state: FirModuleResolveState, ): FirRegularClass { - val builtClass = createCopy(fakeKtClassOrObject, originalFirClass) + val builtClass = createCopy(copiedKtClassOrObject, originalFirClass) return buildRegularClassCopy(originalFirClass) { declarations.clear() @@ -79,11 +79,11 @@ object DeclarationCopyBuilder { } private fun createTypeAliasCopy( - fakeKtTypeAlias: KtTypeAlias, + copiedKtTypeAlias: KtTypeAlias, originalFirTypeAlias: FirTypeAlias, state: FirModuleResolveState, ): FirTypeAlias { - val builtTypeAlias = createCopy(fakeKtTypeAlias, originalFirTypeAlias) + val builtTypeAlias = createCopy(copiedKtTypeAlias, originalFirTypeAlias) return buildTypeAliasCopy(originalFirTypeAlias) { expandedTypeRef = builtTypeAlias.expandedTypeRef @@ -135,14 +135,14 @@ object DeclarationCopyBuilder { } internal inline fun createCopy( - fakeKtDeclaration: KtDeclaration, + copiedKtDeclaration: KtDeclaration, originalFirDeclaration: T, ): T { return RawFirFragmentForLazyBodiesBuilder.build( session = originalFirDeclaration.moduleData.session, baseScopeProvider = originalFirDeclaration.moduleData.session.firIdeProvider.kotlinScopeProvider, designation = originalFirDeclaration.collectDesignation().fullDesignation, - declaration = fakeKtDeclaration + declaration = copiedKtDeclaration ) as T } diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/FirModuleResolveState.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/FirModuleResolveState.kt index 9666cbd0a36..5571ddb1e45 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/FirModuleResolveState.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/FirModuleResolveState.kt @@ -34,8 +34,6 @@ abstract class FirModuleResolveState { internal abstract fun getFirFile(ktFile: KtFile): FirFile - internal abstract fun isFirFileBuilt(ktFile: KtFile): Boolean - internal abstract fun getDiagnostics(element: KtElement, filter: DiagnosticCheckerFilter): List> internal abstract fun collectDiagnosticsForFile(ktFile: KtFile, filter: DiagnosticCheckerFilter): Collection> @@ -56,14 +54,6 @@ abstract class FirModuleResolveState { } } - @TestOnly - internal abstract fun getBuiltFirFileOrNull(ktFile: KtFile): FirFile? - - @InternalForInline - abstract fun findNonLocalSourceFirDeclaration( - ktDeclaration: KtDeclaration, - ): FirDeclaration - @InternalForInline abstract fun findSourceFirDeclaration( ktDeclaration: KtDeclaration, @@ -74,18 +64,8 @@ abstract class FirModuleResolveState { ktDeclaration: KtLambdaExpression, ): FirDeclaration - - // todo temporary, used only in completion - internal abstract fun recordPsiToFirMappingsForCompletionFrom(fir: FirDeclaration, firFile: FirFile, ktFile: KtFile) - internal abstract fun resolvedFirToPhase(declaration: D, toPhase: FirResolvePhase): D - // todo temporary, used only in completion - internal abstract fun lazyResolveDeclarationForCompletion( - firDeclaration: FirDeclaration, - containerFirFile: FirFile, - ) - internal abstract fun getFirFile(declaration: FirDeclaration, cache: ModuleFileCache): FirFile? abstract fun getTowerDataContextForElement(element: KtElement): FirTowerDataContext? diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/LowLevelFirApiFacadeForCompletion.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/LowLevelFirApiFacadeForCompletion.kt deleted file mode 100644 index a033c83df3f..00000000000 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/LowLevelFirApiFacadeForCompletion.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.idea.fir.low.level.api.api - -import org.jetbrains.kotlin.fir.declarations.* -import org.jetbrains.kotlin.idea.fir.low.level.api.FirModuleResolveStateForCompletion -import org.jetbrains.kotlin.idea.fir.low.level.api.FirModuleResolveStateImpl -import org.jetbrains.kotlin.psi.KtDeclaration -import org.jetbrains.kotlin.psi.KtFile - -object LowLevelFirApiFacadeForCompletion { - fun getResolveStateForCompletion(originalState: FirModuleResolveState): FirModuleResolveState { - check(originalState is FirModuleResolveStateImpl) - return FirModuleResolveStateForCompletion(originalState.project, originalState) - } - - fun recordCompletionContextForDeclaration( - firFile: FirFile, - fakeKtDeclaration: KtDeclaration, - originalKtDeclaration: KtDeclaration, - fakeContainingFile: KtFile, - state: FirModuleResolveState, - ) { - val originalFirDeclaration = originalKtDeclaration.getOrBuildFirOfType(state) - val fakeFirDeclaration = DeclarationCopyBuilder.createDeclarationCopy(originalFirDeclaration, fakeKtDeclaration, state) - - state.lazyResolveDeclarationForCompletion(fakeFirDeclaration, firFile) - state.recordPsiToFirMappingsForCompletionFrom(fakeFirDeclaration, firFile, fakeContainingFile) - } -} diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/LowLevelFirApiFacadeForDependentCopy.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/LowLevelFirApiFacadeForDependentCopy.kt new file mode 100644 index 00000000000..de2926d788a --- /dev/null +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/api/LowLevelFirApiFacadeForDependentCopy.kt @@ -0,0 +1,78 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.fir.low.level.api.api + +import com.intellij.psi.util.PsiTreeUtil +import com.intellij.psi.util.parentsOfType +import org.jetbrains.kotlin.fir.declarations.* +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.util.originalDeclaration +import org.jetbrains.kotlin.idea.util.getElementTextInContext +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject + +object LowLevelFirApiFacadeForDependentCopy { + + private fun KtDeclaration.canBeEnclosingDeclaration(): Boolean = when (this) { + is KtNamedFunction -> isTopLevel || containingClassOrObject?.isLocal == false + is KtProperty -> isTopLevel || containingClassOrObject?.isLocal == false + is KtClassOrObject -> !isLocal + is KtTypeAlias -> isTopLevel() || containingClassOrObject?.isLocal == false + else -> false + } + + private fun findEnclosingNonLocalDeclaration(position: KtElement): KtNamedDeclaration? = + position.parentsOfType().firstOrNull { ktDeclaration -> + ktDeclaration.canBeEnclosingDeclaration() + } + + private fun locateDeclarationInFileByOffset(offsetElement: T, file: KtFile): T? { + val elementOffset = offsetElement.textOffset + val elementAtOffset = file.findElementAt(elementOffset) ?: return null + return PsiTreeUtil.getParentOfType(elementAtOffset, offsetElement::class.java, false)?.takeIf { it.textOffset == elementOffset } + } + + private fun recordOriginalDeclaration(targetDeclaration: KtNamedDeclaration, originalDeclaration: KtNamedDeclaration) { + require(!targetDeclaration.isPhysical) + require(originalDeclaration.containingKtFile !== targetDeclaration.containingKtFile) + val originalDeclrationParents = originalDeclaration.parentsOfType().toList() + val fakeDeclarationParents = targetDeclaration.parentsOfType().toList() + originalDeclrationParents.zip(fakeDeclarationParents) { original, fake -> + fake.originalDeclaration = original + } + } + + fun getResolveStateForDependedCopy( + originalState: FirModuleResolveState, + originalKtFile: KtFile, + dependencyKtElement: KtElement + ): FirModuleResolveState { + require(originalState is FirModuleResolveStateImpl) + + val dependencyNonLocalDeclaration = findEnclosingNonLocalDeclaration(dependencyKtElement) + ?: error("Cannot find enclosing declaration for ${dependencyKtElement.getElementTextInContext()}") + + val originalNonLocalDeclaration = locateDeclarationInFileByOffset(dependencyNonLocalDeclaration, originalKtFile) + ?: error("Cannot find original function matching to ${dependencyNonLocalDeclaration.getElementTextInContext()} in $originalKtFile") + + recordOriginalDeclaration( + targetDeclaration = dependencyNonLocalDeclaration, + originalDeclaration = originalNonLocalDeclaration + ) + + val originalFirDeclaration = originalNonLocalDeclaration.getOrBuildFirOfType(originalState) + val copiedFirDeclaration = DeclarationCopyBuilder.createDeclarationCopy( + originalFirDeclaration = originalFirDeclaration, + copiedKtDeclaration = dependencyNonLocalDeclaration, + state = originalState + ) + + val originalFirFile = originalState.getFirFile(originalKtFile) + + return FirModuleResolveStateDepended(copiedFirDeclaration, originalFirFile, originalState) + } +} diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/AbstractFirLazyDeclarationResolveTest.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/AbstractFirLazyDeclarationResolveTest.kt index a1601d3e63f..afe4e072af4 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/AbstractFirLazyDeclarationResolveTest.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/AbstractFirLazyDeclarationResolveTest.kt @@ -36,6 +36,7 @@ abstract class AbstractFirLazyDeclarationResolveTest : KotlinLightCodeInsightFix val declarationToResolve = lazyDeclarations.firstOrNull { it.name?.lowercase() == "resolveme" } ?: error("declaration with name `resolveMe` was not found") resolveWithClearCaches(ktFile) { firModuleResolveState -> + check(firModuleResolveState is FirModuleResolveStateImpl) val rendered = declarationToResolve.withFirDeclaration( firModuleResolveState, FirResolvePhase.BODY_RESOLVE diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/KtFirAnalysisSession.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/KtFirAnalysisSession.kt index fff31753c22..ed11f16d8ba 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/KtFirAnalysisSession.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/KtFirAnalysisSession.kt @@ -7,12 +7,9 @@ package org.jetbrains.kotlin.idea.frontend.api.fir import com.intellij.openapi.project.Project import org.jetbrains.kotlin.fir.FirSession -import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.symbolProvider -import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState -import org.jetbrains.kotlin.idea.fir.low.level.api.api.LowLevelFirApiFacadeForCompletion -import org.jetbrains.kotlin.idea.fir.low.level.api.api.getFirFile +import org.jetbrains.kotlin.idea.fir.low.level.api.api.* import org.jetbrains.kotlin.idea.frontend.api.InvalidWayOfUsingAnalysisSession import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession import org.jetbrains.kotlin.idea.frontend.api.components.KtVisibilityChecker @@ -20,8 +17,6 @@ import org.jetbrains.kotlin.idea.frontend.api.components.KtSymbolDeclarationRend import org.jetbrains.kotlin.idea.frontend.api.fir.components.* import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirOverrideInfoProvider import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirSymbolProvider -import org.jetbrains.kotlin.idea.frontend.api.fir.utils.EnclosingDeclarationContext -import org.jetbrains.kotlin.idea.frontend.api.fir.utils.recordCompletionContext import org.jetbrains.kotlin.idea.frontend.api.fir.utils.threadLocal import org.jetbrains.kotlin.idea.frontend.api.tokens.ValidityToken import org.jetbrains.kotlin.psi.KtElement @@ -33,9 +28,14 @@ private constructor( val firResolveState: FirModuleResolveState, internal val firSymbolBuilder: KtSymbolByFirBuilder, token: ValidityToken, - val context: KtFirAnalysisSessionContext, + private val mode: AnalysisSessionMode, ) : KtAnalysisSession(token) { + private enum class AnalysisSessionMode { + REGULAR, + DEPENDENT_COPY + } + override val smartCastProviderImpl = KtFirSmartcastProvider(this, token) override val expressionTypeProviderImpl = KtFirExpressionTypeProvider(this, token) @@ -73,19 +73,23 @@ private constructor( override val subtypingComponentImpl = KtFirSubtypingComponent(this, token) - override fun createContextDependentCopy(originalKtFile: KtFile, fakeKtElement: KtElement): KtAnalysisSession { - check(context == KtFirAnalysisSessionContext.DefaultContext) { + override fun createContextDependentCopy(originalKtFile: KtFile, dependencyKtElement: KtElement): KtAnalysisSession { + check(mode == AnalysisSessionMode.REGULAR) { "Cannot create context-dependent copy of KtAnalysis session from a context dependent one" } - val contextResolveState = LowLevelFirApiFacadeForCompletion.getResolveStateForCompletion(firResolveState) - val originalFirFile = originalKtFile.getFirFile(firResolveState) - val context = KtFirAnalysisSessionContext.FakeFileContext(originalKtFile, originalFirFile, fakeKtElement, contextResolveState) + + val contextResolveState = LowLevelFirApiFacadeForDependentCopy.getResolveStateForDependedCopy( + originalState = firResolveState, + originalKtFile = originalKtFile, + dependencyKtElement = dependencyKtElement + ) + return KtFirAnalysisSession( project, contextResolveState, firSymbolBuilder.createReadOnlyCopy(contextResolveState), token, - context + AnalysisSessionMode.DEPENDENT_COPY ) } @@ -110,28 +114,8 @@ private constructor( firResolveState, firSymbolBuilder, token, - KtFirAnalysisSessionContext.DefaultContext + AnalysisSessionMode.REGULAR ) } } -} - -internal sealed class KtFirAnalysisSessionContext { - object DefaultContext : KtFirAnalysisSessionContext() - - class FakeFileContext( - originalFile: KtFile, - firFile: FirFile, - fakeContextElement: KtElement, - fakeModuleResolveState: FirModuleResolveState - ) : KtFirAnalysisSessionContext() { - init { - require(!fakeContextElement.isPhysical) - - val enclosingContext = EnclosingDeclarationContext.detect(originalFile, fakeContextElement) - enclosingContext.recordCompletionContext(firFile, fakeModuleResolveState) - } - - val fakeKtFile = fakeContextElement.containingKtFile - } -} +} \ No newline at end of file diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/utils/EnclosingDeclarationContext.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/utils/EnclosingDeclarationContext.kt deleted file mode 100644 index b1782ebf8f8..00000000000 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/utils/EnclosingDeclarationContext.kt +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.idea.frontend.api.fir.utils - -import com.intellij.psi.util.PsiTreeUtil -import com.intellij.psi.util.parentsOfType -import org.jetbrains.kotlin.fir.declarations.FirFile -import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState -import org.jetbrains.kotlin.idea.fir.low.level.api.api.LowLevelFirApiFacadeForCompletion -import org.jetbrains.kotlin.idea.fir.low.level.api.util.originalDeclaration -import org.jetbrains.kotlin.idea.util.getElementTextInContext -import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject -import kotlin.reflect.KClass - -internal sealed class EnclosingDeclarationContext { - abstract val fakeKtEnclosingDeclaration: KtDeclaration - abstract val originalKtEnclosingDeclaration: KtDeclaration - - companion object { - private fun KtDeclaration.canBeEnclosingDeclaration(): Boolean = when (this) { - is KtNamedFunction -> isTopLevel || containingClassOrObject?.isLocal == false - is KtProperty -> isTopLevel || containingClassOrObject?.isLocal == false - is KtClassOrObject -> !isLocal - is KtTypeAlias -> isTopLevel() || containingClassOrObject?.isLocal == false - else -> false - } - - fun detect(originalFile: KtFile, positionInFakeFile: KtElement): EnclosingDeclarationContext { - val fakeKtDeclaration = positionInFakeFile.parentsOfType().firstOrNull { ktDeclaration -> - ktDeclaration.canBeEnclosingDeclaration() - } - if (fakeKtDeclaration != null) { - val originalDeclaration = findMatchingElementInCopy(fakeKtDeclaration, originalFile) - ?: error("Cannot find original declaration matching to ${fakeKtDeclaration.getElementTextInContext()} in $originalFile") - recordOriginalDeclaration(originalDeclaration, fakeKtDeclaration) - return EnclosingDeclarationContextImpl(fakeKtDeclaration, originalDeclaration) - } - - error("Cannot find enclosing declaration for ${positionInFakeFile.getElementTextInContext()}") - } - - private fun recordOriginalDeclaration(originalDeclaration: KtNamedDeclaration, fakeDeclaration: KtNamedDeclaration) { - require(!fakeDeclaration.isPhysical) - require(originalDeclaration.containingKtFile !== fakeDeclaration.containingKtFile) - val originalDeclrationParents = originalDeclaration.parentsOfType().toList() - val fakeDeclarationParents = fakeDeclaration.parentsOfType().toList() - - originalDeclrationParents.zip(fakeDeclarationParents) { original, fake -> - fake.originalDeclaration = original - } - } - } -} - -internal class EnclosingDeclarationContextImpl( - override val fakeKtEnclosingDeclaration: KtDeclaration, - override val originalKtEnclosingDeclaration: KtDeclaration -) : EnclosingDeclarationContext() - - -internal fun EnclosingDeclarationContext.recordCompletionContext(originalFirFile: FirFile, firResolveState: FirModuleResolveState) { - LowLevelFirApiFacadeForCompletion.recordCompletionContextForDeclaration( - originalFirFile, - fakeKtEnclosingDeclaration, - originalKtEnclosingDeclaration, - state = firResolveState, - fakeContainingFile = fakeKtEnclosingDeclaration.containingKtFile - ) -} - -fun findMatchingElementInCopy(element: T, copy: KtFile): T? { - val elementOffset = element.textOffset - val elementAtOffset = copy.findElementAt(elementOffset) ?: return null - return PsiTreeUtil.getParentOfType(elementAtOffset, element::class.java, false)?.takeIf { it.textOffset == elementOffset } -} \ No newline at end of file