From d926dda27fe470412fb834d1ea4ed3866a12e94a Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Mon, 24 Jan 2022 11:35:20 +0100 Subject: [PATCH] Analysis API FIR: introduce declarations from library resolve ^KT-50252 fixed --- .../KtFirCompletionCandidateChecker.kt | 10 +- .../api/fir/components/KtFirScopeProvider.kt | 4 +- .../api/fir/components/KtFirTypeProvider.kt | 4 +- .../kotlin/analysis/utils/errors/errors.kt | 10 ++ .../api/fir/FirIdeResolveStateService.kt | 49 ++++-- .../api/fir/FirModuleResolveStateDepended.kt | 26 ++- .../api/fir/api/FirModuleResolveState.kt | 3 + .../LowLevelFirApiFacadeForResolveOnAir.kt | 50 +++--- .../fir/element/builder/FirElementBuilder.kt | 41 ++--- .../LLFirLibraryResolveModuleFileCache.kt | 86 ++++++++++ .../api/fir/file/structure/FileStructure.kt | 8 +- .../file/structure/FileStructureElement.kt | 15 +- .../lazy/resolve/FirLazyBodiesCalculator.kt | 8 +- .../resolve/FirLazyDeclarationResolver.kt | 9 +- .../FirIdeLibrariesSessionProvider.kt | 1 + .../level/api/fir/providers/FirIdeProvider.kt | 2 - .../LLFirLibraryResolvableProvider.kt | 36 +++++ .../api/fir/sessions/FirIdeSessionFactory.kt | 115 +++++++++++++- .../api/fir/sessions/FirIdeSessionProvider.kt | 8 +- .../sessions/FirIdeSessionProviderStorage.kt | 85 ++++++---- .../api/fir/sessions/FirIdeSourcesSession.kt | 11 +- .../api/fir/sessions/FirSessionInvalidator.kt | 4 +- ...yOrLibrarySourceResolvableModuleSession.kt | 34 ++++ .../sessions/LLFirResolvableModuleSession.kt | 19 +++ .../level/api/fir/sessions/LibrariesCache.kt | 9 +- .../state/FirPhysicalModuleResolveState.kt | 10 -- .../fir/state/FirSourceModuleResolveState.kt | 136 ++-------------- ...brarySourceResolvableModuleResolveState.kt | 41 +++++ .../LLFirResolvableModuleResolveState.kt | 150 ++++++++++++++++++ .../state/TowerProviderForElementForState.kt | 25 +++ .../api/fir/util/LLFirResolvePhaseChecker.kt | 17 ++ .../AbstractFirLazyBodiesCalculatorTest.kt | 6 +- .../AbstractFirContextCollectionTest.kt | 2 +- .../structure/AbstractFileStructureTest.kt | 2 +- 34 files changed, 729 insertions(+), 307 deletions(-) create mode 100644 analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/errors/errors.kt create mode 100644 analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/builder/LLFirLibraryResolveModuleFileCache.kt create mode 100644 analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirLibraryResolvableProvider.kt create mode 100644 analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirLibraryOrLibrarySourceResolvableModuleSession.kt create mode 100644 analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirResolvableModuleSession.kt delete mode 100644 analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/FirPhysicalModuleResolveState.kt create mode 100644 analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirLibraryOrLibrarySourceResolvableModuleResolveState.kt create mode 100644 analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirResolvableModuleResolveState.kt create mode 100644 analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/TowerProviderForElementForState.kt create mode 100644 analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/LLFirResolvePhaseChecker.kt diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCompletionCandidateChecker.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCompletionCandidateChecker.kt index d09ff0399d3..e8504dfb4ff 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCompletionCandidateChecker.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCompletionCandidateChecker.kt @@ -14,7 +14,6 @@ import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken import org.jetbrains.kotlin.analysis.api.types.KtSubstitutor import org.jetbrains.kotlin.analysis.api.withValidityAssertion -import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LowLevelFirApiFacadeForResolveOnAir.getTowerContextProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirFile import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirOfType import org.jetbrains.kotlin.analysis.low.level.api.fir.resolver.ResolutionParameters @@ -61,7 +60,7 @@ internal class KtFirCompletionCandidateChecker( val file = originalFile.getOrBuildFirFile(firResolveState) val explicitReceiverExpression = possibleExplicitReceiver?.getOrBuildFirOfType(firResolveState) val resolver = SingleCandidateResolver(firResolveState.rootModuleSession, file) - val implicitReceivers = getImplicitReceivers(nameExpression) + val implicitReceivers = getImplicitReceivers(originalFile, nameExpression) for (implicitReceiverValue in implicitReceivers) { val resolutionParameters = ResolutionParameters( singleCandidateResolutionMode = SingleCandidateResolutionMode.CHECK_EXTENSION_FOR_COMPLETION, @@ -84,8 +83,11 @@ internal class KtFirCompletionCandidateChecker( return KtExtensionApplicabilityResult.NonApplicable(KtSubstitutor.Empty(token)) } - private fun getImplicitReceivers(fakeNameExpression: KtSimpleNameExpression): Sequence?> { - val towerDataContext = analysisSession.firResolveState.getTowerContextProvider() + private fun getImplicitReceivers( + originalFile: KtFile, + fakeNameExpression: KtSimpleNameExpression + ): Sequence?> { + val towerDataContext = analysisSession.firResolveState.getTowerContextProvider(originalFile) .getClosestAvailableParentContext(fakeNameExpression) ?: error("Cannot find enclosing declaration for ${fakeNameExpression.getElementTextInContext()}") diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirScopeProvider.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirScopeProvider.kt index 5ad47a586b2..ca5be97e633 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirScopeProvider.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirScopeProvider.kt @@ -30,7 +30,6 @@ import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken import org.jetbrains.kotlin.analysis.api.types.KtType import org.jetbrains.kotlin.analysis.api.withValidityAssertion import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState -import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LowLevelFirApiFacadeForResolveOnAir.getTowerContextProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.util.getElementTextInContext import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirClass @@ -189,9 +188,8 @@ internal class KtFirScopeProvider( originalFile: KtFile, positionInFakeFile: KtElement ): KtScopeContext = withValidityAssertion { - val towerDataContext = - analysisSession.firResolveState.getTowerContextProvider().getClosestAvailableParentContext(positionInFakeFile) + analysisSession.firResolveState.getTowerContextProvider(originalFile).getClosestAvailableParentContext(positionInFakeFile) ?: error("Cannot find enclosing declaration for ${positionInFakeFile.getElementTextInContext()}") val implicitReceivers = towerDataContext.nonLocalTowerDataElements.mapNotNull { it.implicitReceiver }.distinct() diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirTypeProvider.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirTypeProvider.kt index eadf98c0704..b86625f2fba 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirTypeProvider.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirTypeProvider.kt @@ -20,7 +20,6 @@ import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken import org.jetbrains.kotlin.analysis.api.types.KtType import org.jetbrains.kotlin.analysis.api.types.KtTypeNullability import org.jetbrains.kotlin.analysis.api.withValidityAssertion -import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LowLevelFirApiFacadeForResolveOnAir.getTowerContextProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFir import org.jetbrains.kotlin.analysis.low.level.api.fir.api.throwUnexpectedFirElementError import org.jetbrains.kotlin.fir.FirRenderer @@ -28,7 +27,6 @@ import org.jetbrains.kotlin.fir.analysis.checkers.ConeTypeCompatibilityChecker import org.jetbrains.kotlin.fir.analysis.checkers.ConeTypeCompatibilityChecker.isCompatible import org.jetbrains.kotlin.fir.analysis.checkers.fullyExpandedClass import org.jetbrains.kotlin.fir.analysis.checkers.typeParameterSymbols -import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess @@ -124,7 +122,7 @@ internal class KtFirTypeProvider( } override fun getImplicitReceiverTypesAtPosition(position: KtElement): List { - return analysisSession.firResolveState.getTowerContextProvider() + return analysisSession.firResolveState.getTowerContextProvider(position.containingKtFile) .getClosestAvailableParentContext(position)?.implicitReceiverStack?.map { it.type.asKtType() } ?: emptyList() } diff --git a/analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/errors/errors.kt b/analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/errors/errors.kt new file mode 100644 index 00000000000..7d608b5f54e --- /dev/null +++ b/analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/errors/errors.kt @@ -0,0 +1,10 @@ +/* + * Copyright 2010-2022 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.analysis.utils.errors + +public fun unexpectedElementError(elementName: String, element: Any?): Nothing { + error("Unexpected $elementName ${element?.let { it::class.simpleName }}") +} \ No newline at end of file diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/FirIdeResolveStateService.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/FirIdeResolveStateService.kt index c933cb583e8..2c172e4e721 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/FirIdeResolveStateService.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/FirIdeResolveStateService.kt @@ -13,7 +13,13 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.FirLazyDeclarationResolver import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.FirIdeSession import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.FirIdeSessionProviderStorage +import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.FirIdeSourcesSession +import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirLibraryOrLibrarySourceResolvableModuleSession import org.jetbrains.kotlin.analysis.low.level.api.fir.state.FirSourceModuleResolveState +import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirLibraryOrLibrarySourceResolvableModuleResolveState +import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirResolvableModuleResolveState +import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule +import org.jetbrains.kotlin.analysis.project.structure.KtLibrarySourceModule import org.jetbrains.kotlin.analysis.project.structure.KtModule import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule import org.jetbrains.kotlin.analysis.providers.createProjectWideOutOfBlockModificationTracker @@ -27,10 +33,10 @@ internal class FirIdeResolveStateService(project: Project) { project.createProjectWideOutOfBlockModificationTracker(), ProjectRootModificationTracker.getInstance(project), ) { - ConcurrentHashMap() + ConcurrentHashMap() } - fun getResolveState(module: KtModule): FirSourceModuleResolveState = + fun getResolveState(module: KtModule): LLFirResolvableModuleResolveState = stateCache.computeIfAbsent(module) { createResolveStateFor(module, sessionProviderStorage) } companion object { @@ -41,19 +47,34 @@ internal class FirIdeResolveStateService(project: Project) { module: KtModule, sessionProviderStorage: FirIdeSessionProviderStorage, configureSession: (FirIdeSession.() -> Unit)? = null, - ): FirSourceModuleResolveState { - if (module !is KtSourceModule) { - error("Creating FirModuleResolveState is not yet supported for $module") - } + ): LLFirResolvableModuleResolveState { val sessionProvider = sessionProviderStorage.getSessionProvider(module, configureSession) - val firFileBuilder = sessionProvider.rootModuleSession.firFileBuilder - return FirSourceModuleResolveState( - sessionProviderStorage.project, - module, - sessionProvider, - firFileBuilder, - FirLazyDeclarationResolver(firFileBuilder), - ) + return when (module) { + is KtSourceModule -> { + val firFileBuilder = (sessionProvider.rootModuleSession as FirIdeSourcesSession).firFileBuilder + FirSourceModuleResolveState( + sessionProviderStorage.project, + module, + sessionProvider, + firFileBuilder, + FirLazyDeclarationResolver(firFileBuilder), + ) + } + is KtLibraryModule, is KtLibrarySourceModule -> { + val firFileBuilder = (sessionProvider.rootModuleSession as LLFirLibraryOrLibrarySourceResolvableModuleSession).firFileBuilder + LLFirLibraryOrLibrarySourceResolvableModuleResolveState( + sessionProviderStorage.project, + module, + sessionProvider, + firFileBuilder, + FirLazyDeclarationResolver(firFileBuilder), + ) + } + else -> { + error("Unexpected $module") + } + } + } } } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/FirModuleResolveStateDepended.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/FirModuleResolveStateDepended.kt index 2532aea7627..db344295e84 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/FirModuleResolveStateDepended.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/FirModuleResolveStateDepended.kt @@ -8,10 +8,13 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir import com.intellij.openapi.project.Project import org.jetbrains.kotlin.analysis.low.level.api.fir.api.DiagnosticCheckerFilter import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState +import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirElementBuilder import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirTowerContextProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.ModuleFileCache import org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.KtToFirMapping import org.jetbrains.kotlin.analysis.low.level.api.fir.state.FirSourceModuleResolveState +import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirResolvableModuleResolveState +import org.jetbrains.kotlin.analysis.low.level.api.fir.state.TowerProviderForElementForState import org.jetbrains.kotlin.analysis.low.level.api.fir.util.containingKtFileIfAny import org.jetbrains.kotlin.analysis.low.level.api.fir.util.originalKtFile import org.jetbrains.kotlin.analysis.project.structure.KtModule @@ -28,35 +31,21 @@ import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtLambdaExpression internal class FirModuleResolveStateDepended( - val originalState: FirSourceModuleResolveState, + val originalState: LLFirResolvableModuleResolveState, val towerProviderBuiltUponElement: FirTowerContextProvider, private val ktToFirMapping: KtToFirMapping?, ) : FirModuleResolveState() { - override val project: Project get() = originalState.project override val module: KtModule get() = originalState.module override val rootModuleSession get() = originalState.rootModuleSession - private val fileStructureCache get() = originalState.fileStructureCache override fun getSessionFor(module: KtModule): FirSession = originalState.getSessionFor(module) override fun getOrBuildFirFor(element: KtElement): FirElement? { - val elementBuilder = originalState.elementBuilder - - val psi = elementBuilder.getPsiAsFirElementSource(element) ?: return null - if (!elementBuilder.doKtElementHasCorrespondingFirElement(element)) return null - + val psi = FirElementBuilder.getPsiAsFirElementSource(element) ?: return null ktToFirMapping?.getFirOfClosestParent(psi, this)?.let { return it } - - return elementBuilder.getOrBuildFirFor( - element = element, - firFileBuilder = originalState.firFileBuilder, - moduleFileCache = originalState.rootModuleSession.cache, - fileStructureCache = fileStructureCache, - firLazyDeclarationResolver = originalState.firLazyDeclarationResolver, - state = this, - ) + return originalState.getOrBuildFirFor(element = element) } override fun getOrBuildFirFile(ktFile: KtFile): FirFile = @@ -82,4 +71,7 @@ internal class FirModuleResolveStateDepended( override fun resolveToFirSymbol(ktDeclaration: KtDeclaration, phase: FirResolvePhase): FirBasedSymbol<*> { return originalState.resolveToFirSymbol(ktDeclaration, phase) } + + override fun getTowerContextProvider(ktFile: KtFile): FirTowerContextProvider = + TowerProviderForElementForState(this) } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/FirModuleResolveState.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/FirModuleResolveState.kt index 25e495b5344..38c5b40eb89 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/FirModuleResolveState.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/FirModuleResolveState.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.api import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirTowerContextProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.ModuleFileCache import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule import org.jetbrains.kotlin.analysis.project.structure.KtModule @@ -56,4 +57,6 @@ abstract class FirModuleResolveState { abstract fun resolveToFirSymbol(ktDeclaration: KtDeclaration, phase: FirResolvePhase): FirBasedSymbol<*> internal abstract fun resolveFirToPhase(declaration: FirDeclaration, toPhase: FirResolvePhase) + + abstract fun getTowerContextProvider(ktFile: KtFile): FirTowerContextProvider } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/LowLevelFirApiFacadeForResolveOnAir.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/LowLevelFirApiFacadeForResolveOnAir.kt index d1f5ea7b6c4..16360f3cb14 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/LowLevelFirApiFacadeForResolveOnAir.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/LowLevelFirApiFacadeForResolveOnAir.kt @@ -10,7 +10,6 @@ import org.jetbrains.kotlin.analysis.api.impl.barebone.parentOfType import org.jetbrains.kotlin.analysis.api.impl.barebone.parentsOfType import org.jetbrains.kotlin.analysis.low.level.api.fir.DeclarationCopyBuilder.withBodyFrom import org.jetbrains.kotlin.analysis.low.level.api.fir.FirModuleResolveStateDepended -import org.jetbrains.kotlin.analysis.low.level.api.fir.state.FirSourceModuleResolveState import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FileTowerProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirTowerContextProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirTowerDataContextAllElementsCollector @@ -18,8 +17,8 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.runCustomRes import org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.FirElementsRecorder import org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.KtToFirMapping import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.* -import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.firIdeProvider -import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.FirIdeSourcesSession +import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirResolvableModuleSession +import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirResolvableModuleResolveState import org.jetbrains.kotlin.analysis.low.level.api.fir.util.getElementTextInContext import org.jetbrains.kotlin.analysis.low.level.api.fir.util.originalDeclaration import org.jetbrains.kotlin.analysis.project.structure.getKtModule @@ -31,6 +30,7 @@ import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.transformers.FirTypeResolveTransformer import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirTowerDataContextCollector import org.jetbrains.kotlin.fir.scopes.createImportingScopes +import org.jetbrains.kotlin.fir.scopes.kotlinScopeProvider import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid import org.jetbrains.kotlin.psi.* @@ -67,7 +67,7 @@ object LowLevelFirApiFacadeForResolveOnAir { place: T, elementToResolve: T, ): FirElement { - require(state is FirSourceModuleResolveState) + require(state is LLFirResolvableModuleResolveState) require(place.isPhysical) val declaration = runBodyResolveOnAir( @@ -95,7 +95,7 @@ object LowLevelFirApiFacadeForResolveOnAir { state: FirModuleResolveState, place: KtElement, ): FirTowerContextProvider { - require(state is FirSourceModuleResolveState) + require(state is LLFirResolvableModuleResolveState) return if (place is KtFile) { FileTowerProvider(place, onAirGetTowerContextForFile(state, place)) @@ -116,11 +116,11 @@ object LowLevelFirApiFacadeForResolveOnAir { } private fun onAirGetTowerContextForFile( - state: FirSourceModuleResolveState, + state: LLFirResolvableModuleResolveState, file: KtFile, ): FirTowerDataContext { require(file.isPhysical) - val session = state.getSessionFor(file.getKtModule(state.project)) as FirIdeSourcesSession + val session = state.getSessionFor(file.getKtModule(state.project)) as LLFirResolvableModuleSession val firFile = session.firFileBuilder.buildRawFirFileWithCaching( ktFile = file, @@ -144,7 +144,7 @@ object LowLevelFirApiFacadeForResolveOnAir { originalKtFile: KtFile, elementToAnalyze: KtElement ): FirModuleResolveState { - require(originalState is FirSourceModuleResolveState) + require(originalState is LLFirResolvableModuleResolveState) require(elementToAnalyze !is KtFile) { "KtFile for dependency element not supported" } require(!elementToAnalyze.isPhysical) { "Depended state should be build only for non-physical elements" } @@ -178,21 +178,21 @@ object LowLevelFirApiFacadeForResolveOnAir { private fun tryResolveAsFileAnnotation( annotationEntry: KtAnnotationEntry, - state: FirSourceModuleResolveState, + state: LLFirResolvableModuleResolveState, replacement: RawFirReplacement, firFile: FirFile, collector: FirTowerDataContextCollector? = null, ): FirAnnotation { val annotationCall = buildFileFirAnnotation( session = firFile.moduleData.session, - baseScopeProvider = firFile.moduleData.session.firIdeProvider.kotlinScopeProvider, + baseScopeProvider = firFile.moduleData.session.kotlinScopeProvider, fileAnnotation = annotationEntry, replacement = replacement ) state.firLazyDeclarationResolver.resolveFileAnnotations( firFile = firFile, annotations = listOf(annotationCall), - moduleFileCache = state.rootModuleSession.cache, + moduleFileCache = state.cache, scopeSession = ScopeSession(), checkPCE = true, collector = collector @@ -202,7 +202,7 @@ object LowLevelFirApiFacadeForResolveOnAir { } private fun runBodyResolveOnAir( - state: FirSourceModuleResolveState, + state: LLFirResolvableModuleResolveState, replacement: RawFirReplacement, onAirCreatedDeclaration: Boolean, collector: FirTowerDataContextCollector? = null, @@ -233,7 +233,7 @@ object LowLevelFirApiFacadeForResolveOnAir { val newDeclarationWithReplacement = RawFirNonLocalDeclarationBuilder.buildWithReplacement( session = originalDeclaration.moduleData.session, - scopeProvider = originalDeclaration.moduleData.session.firIdeProvider.kotlinScopeProvider, + scopeProvider = originalDeclaration.moduleData.session.kotlinScopeProvider, designation = originalDesignation, rootNonLocalDeclaration = nonLocalDeclaration, replacement = replacement, @@ -241,7 +241,7 @@ object LowLevelFirApiFacadeForResolveOnAir { val isInBodyReplacement = isInBodyReplacement(nonLocalDeclaration, replacement) - return state.rootModuleSession.cache.firFileLockProvider.runCustomResolveUnderLock(originalFirFile, true) { + return state.cache.firFileLockProvider.runCustomResolveUnderLock(originalFirFile, true) { val copiedFirDeclaration = if (isInBodyReplacement) { when (originalDeclaration) { is FirSimpleFunction -> @@ -263,7 +263,7 @@ object LowLevelFirApiFacadeForResolveOnAir { ResolveTreeBuilder.resolveEnsure(onAirDesignation.declaration, FirResolvePhase.BODY_RESOLVE) { state.firLazyDeclarationResolver.runLazyDesignatedOnAirResolveToBodyWithoutLock( designation = onAirDesignation, - moduleFileCache = state.rootModuleSession.cache, + moduleFileCache = state.cache, checkPCE = true, onAirCreatedDeclaration = onAirCreatedDeclaration, towerDataContextCollector = collector, @@ -299,16 +299,16 @@ object LowLevelFirApiFacadeForResolveOnAir { fun onAirResolveTypeInPlace( place: KtElement, typeReference: KtTypeReference, - state: FirModuleResolveState + state: FirModuleResolveState, ): FirResolvedTypeRef { - val context = state.getTowerContextProvider().getClosestAvailableParentContext(place) + val context = state.getTowerContextProvider(place.containingKtFile).getClosestAvailableParentContext(place) ?: error("TowerContext not found for ${place.getElementTextInContext()}") val session = state.rootModuleSession val firTypeReference = buildFirUserTypeRef( typeReference = typeReference, session = session, - baseScopeProvider = session.firIdeProvider.kotlinScopeProvider + baseScopeProvider = session.kotlinScopeProvider ) return FirTypeResolveTransformer( @@ -317,18 +317,4 @@ object LowLevelFirApiFacadeForResolveOnAir { initialScopes = context.towerDataElements.asReversed().mapNotNull { it.scope } ).transformTypeRef(firTypeReference, null) } - - private class TowerProviderForElementForState(private val state: FirModuleResolveState) : FirTowerContextProvider { - override fun getClosestAvailableParentContext(ktElement: KtElement): FirTowerDataContext? { - return if (state is FirModuleResolveStateDepended) { - state.towerProviderBuiltUponElement.getClosestAvailableParentContext(ktElement) - ?: onAirGetTowerContextProvider(state.originalState, ktElement).getClosestAvailableParentContext(ktElement) - } else { - onAirGetTowerContextProvider(state, ktElement).getClosestAvailableParentContext(ktElement) - } - } - } - - fun FirModuleResolveState.getTowerContextProvider(): FirTowerContextProvider = - TowerProviderForElementForState(this) } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/element/builder/FirElementBuilder.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/element/builder/FirElementBuilder.kt index 6ad95fcebce..890566c5e40 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/element/builder/FirElementBuilder.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/element/builder/FirElementBuilder.kt @@ -32,29 +32,32 @@ import org.jetbrains.kotlin.psi2ir.deparenthesize */ @ThreadSafe internal class FirElementBuilder { - fun getPsiAsFirElementSource(element: KtElement): KtElement? { - val deparenthesized = if (element is KtPropertyDelegate) element.deparenthesize() else element - return when { - deparenthesized is KtParenthesizedExpression -> deparenthesized.deparenthesize() - deparenthesized is KtPropertyDelegate -> deparenthesized.expression ?: element - deparenthesized is KtQualifiedExpression && deparenthesized.selectorExpression is KtCallExpression -> { - /* - KtQualifiedExpression with KtCallExpression in selector transformed in FIR to FirFunctionCall expression - Which will have a receiver as qualifier - */ - deparenthesized.selectorExpression ?: error("Incomplete code:\n${element.getElementTextInContext()}") + companion object { + fun getPsiAsFirElementSource(element: KtElement): KtElement? { + val deparenthesized = if (element is KtPropertyDelegate) element.deparenthesize() else element + return when { + deparenthesized is KtParenthesizedExpression -> deparenthesized.deparenthesize() + deparenthesized is KtPropertyDelegate -> deparenthesized.expression ?: element + deparenthesized is KtQualifiedExpression && deparenthesized.selectorExpression is KtCallExpression -> { + /* + KtQualifiedExpression with KtCallExpression in selector transformed in FIR to FirFunctionCall expression + Which will have a receiver as qualifier + */ + deparenthesized.selectorExpression ?: error("Incomplete code:\n${element.getElementTextInContext()}") + } + deparenthesized is KtValueArgument -> { + // null will be return in case of invalid KtValueArgument + deparenthesized.getArgumentExpression() + } + deparenthesized is KtObjectLiteralExpression -> deparenthesized.objectDeclaration + deparenthesized is KtStringTemplateEntryWithExpression -> deparenthesized.expression + deparenthesized is KtUserType && deparenthesized.parent is KtNullableType -> deparenthesized.parent as KtNullableType + else -> deparenthesized } - deparenthesized is KtValueArgument -> { - // null will be return in case of invalid KtValueArgument - deparenthesized.getArgumentExpression() - } - deparenthesized is KtObjectLiteralExpression -> deparenthesized.objectDeclaration - deparenthesized is KtStringTemplateEntryWithExpression -> deparenthesized.expression - deparenthesized is KtUserType && deparenthesized.parent is KtNullableType -> deparenthesized.parent as KtNullableType - else -> deparenthesized } } + fun doKtElementHasCorrespondingFirElement(ktElement: KtElement): Boolean = when (ktElement) { is KtImportList -> false else -> true diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/builder/LLFirLibraryResolveModuleFileCache.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/builder/LLFirLibraryResolveModuleFileCache.kt new file mode 100644 index 00000000000..d5e66eea499 --- /dev/null +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/builder/LLFirLibraryResolveModuleFileCache.kt @@ -0,0 +1,86 @@ +/* + * Copyright 2010-2022 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.analysis.low.level.api.fir.file.builder + +import org.jetbrains.kotlin.analysis.low.level.api.fir.FirPhaseRunner +import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirTowerDataContextAllElementsCollector +import org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.FirElementsRecorder +import org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.KtToFirMapping +import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.FirLazyDeclarationResolver +import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirLibraryOrLibrarySourceResolvableModuleSession +import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration +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.psi +import org.jetbrains.kotlin.fir.resolve.ScopeSession +import org.jetbrains.kotlin.fir.scopes.FirScopeProvider +import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol +import org.jetbrains.kotlin.name.CallableId +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.psi.KtFile +import java.util.* +import java.util.concurrent.ConcurrentHashMap + +internal class LLFirLibraryResolveModuleFileCache( + val kotlinScopeProvider: FirScopeProvider, + override val session: LLFirLibraryOrLibrarySourceResolvableModuleSession +) : ModuleFileCache() { + private val firFileBuilder = FirFileBuilder(kotlinScopeProvider, FirPhaseRunner()) + + private val firLazyDeclarationResolver = FirLazyDeclarationResolver(firFileBuilder) + + private val kfFileToFirCache = ConcurrentHashMap() + + override val classifierByClassId: ConcurrentHashMap> get() = error("Should not be called") + override val callableByCallableId: ConcurrentHashMap>> get() = error("Should not be called") + + override fun fileCached(file: KtFile, createValue: () -> FirFile): FirFile { + return getResolvedFile(file) { createValue() }.firFile + } + + override fun getContainerFirFile(declaration: FirDeclaration): FirFile? { + val ktFile = declaration.psi?.containingFile as? KtFile ?: return null + return getCachedFirFile(ktFile) + } + + override fun getCachedFirFile(ktFile: KtFile): FirFile? { + return kfFileToFirCache[ktFile]?.firFile + } + + override val firFileLockProvider: LockProvider = LockProvider() + + fun getResolvedFile( + ktFile: KtFile, + createKtFile: (KtFile) -> FirFile + ): ResolvedFile = kfFileToFirCache.computeIfAbsent(ktFile) { + val collector = FirTowerDataContextAllElementsCollector() + val scopeSession = ScopeSession() + + val firFile = createKtFile(ktFile) + + firLazyDeclarationResolver.lazyResolveFileDeclaration( + firFile, + this, + FirResolvePhase.BODY_RESOLVE, + scopeSession, + collector = collector, + checkPCE = true + ) + + ResolvedFile( + firFile, + KtToFirMapping(firFile, FirElementsRecorder()), + collector + ) + } + + class ResolvedFile( + val firFile: FirFile, + val mapping: KtToFirMapping, + val collector: FirTowerDataContextAllElementsCollector, + ) +} \ No newline at end of file diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileStructure.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileStructure.kt index a93dfc8a86a..367ef2c0e99 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileStructure.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileStructure.kt @@ -11,13 +11,14 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.getNonLoc import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.FirFileBuilder import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.ModuleFileCache import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.FirLazyDeclarationResolver -import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.firIdeProvider +import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.FirIdeProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.util.findSourceNonLocalFirDeclaration import org.jetbrains.kotlin.analysis.low.level.api.fir.util.getElementTextInContext import org.jetbrains.kotlin.diagnostics.KtPsiDiagnostic import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.resolve.ScopeSession +import org.jetbrains.kotlin.fir.resolve.providers.firProvider import org.jetbrains.kotlin.psi.* import java.util.concurrent.ConcurrentHashMap @@ -40,7 +41,7 @@ internal class FileStructure private constructor( } } - private val firIdeProvider = firFile.moduleData.session.firIdeProvider + private val firProvider = firFile.moduleData.session.firProvider private val structureElements = ConcurrentHashMap() @@ -59,7 +60,6 @@ internal class FileStructure private constructor( newKtDeclaration = declaration as KtDeclaration, cache = moduleFileCache, firLazyDeclarationResolver = firLazyDeclarationResolver, - firIdeProvider = firIdeProvider, ) } else -> structureElement @@ -112,7 +112,7 @@ internal class FileStructure private constructor( private fun createDeclarationStructure(declaration: KtDeclaration): FileStructureElement { val firDeclaration = declaration.findSourceNonLocalFirDeclaration( firFileBuilder, - firIdeProvider.symbolProvider, + firProvider.symbolProvider, moduleFileCache, firFile ) diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileStructureElement.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileStructureElement.kt index b4ff178bd88..8541629d262 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileStructureElement.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileStructureElement.kt @@ -18,11 +18,12 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.FirLazyDecla import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.RawFirNonLocalDeclarationBuilder import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.declarationCanBeLazilyResolved import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.FirIdeProvider -import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.firIdeProvider +import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirResolvableModuleResolveState import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.psi import org.jetbrains.kotlin.fir.resolve.ScopeSession +import org.jetbrains.kotlin.fir.scopes.kotlinScopeProvider import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol @@ -36,12 +37,10 @@ internal sealed class FileStructureElement(val firFile: FirFile, protected val l } internal class KtToFirMapping(firElement: FirElement, recorder: FirElementsRecorder) { - private val mapping = FirElementsRecorder.recordElementsFrom(firElement, recorder) - private val userTypeMapping = ConcurrentHashMap() - fun getElement(ktElement: KtElement, state: FirModuleResolveState): FirElement? { + fun getElement(ktElement: KtElement, state: FirModuleResolveState): FirElement? { mapping[ktElement]?.let { return it } val userType = when (ktElement) { @@ -87,7 +86,6 @@ internal sealed class ReanalyzableStructureElement fun isUpToDate(): Boolean = psi.getModificationStamp() == timestamp @@ -116,20 +114,18 @@ internal class ReanalyzableFunctionStructureElement( newKtDeclaration: KtNamedFunction, cache: ModuleFileCache, firLazyDeclarationResolver: FirLazyDeclarationResolver, - firIdeProvider: FirIdeProvider, ): ReanalyzableFunctionStructureElement { val originalFunction = firSymbol.fir as FirSimpleFunction val designation = originalFunction.collectDesignation() val temporaryFunction = RawFirNonLocalDeclarationBuilder.buildWithFunctionSymbolRebind( session = originalFunction.moduleData.session, - scopeProvider = originalFunction.moduleData.session.firIdeProvider.kotlinScopeProvider, + scopeProvider = originalFunction.moduleData.session.kotlinScopeProvider, designation = designation, rootNonLocalDeclaration = newKtDeclaration, ) as FirSimpleFunction return cache.firFileLockProvider.withWriteLock(firFile) { - val upgradedPhase = minOf(originalFunction.resolvePhase, FirResolvePhase.DECLARATIONS) with(originalFunction) { replaceBody(temporaryFunction.body) @@ -172,14 +168,13 @@ internal class ReanalyzablePropertyStructureElement( newKtDeclaration: KtProperty, cache: ModuleFileCache, firLazyDeclarationResolver: FirLazyDeclarationResolver, - firIdeProvider: FirIdeProvider, ): ReanalyzablePropertyStructureElement { val originalProperty = firSymbol.fir val designation = originalProperty.collectDesignation() val temporaryProperty = RawFirNonLocalDeclarationBuilder.buildWithFunctionSymbolRebind( session = originalProperty.moduleData.session, - scopeProvider = originalProperty.moduleData.session.firIdeProvider.kotlinScopeProvider, + scopeProvider = originalProperty.moduleData.session.kotlinScopeProvider, designation = designation, rootNonLocalDeclaration = newKtDeclaration, ) as FirProperty diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/FirLazyBodiesCalculator.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/FirLazyBodiesCalculator.kt index bdac8778c68..a8c700efa32 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/FirLazyBodiesCalculator.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/FirLazyBodiesCalculator.kt @@ -9,7 +9,6 @@ import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toPersistentList import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDeclarationDesignation -import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.firIdeProvider import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.utils.getExplicitBackingField @@ -18,6 +17,7 @@ import org.jetbrains.kotlin.fir.expressions.FirWrappedDelegateExpression import org.jetbrains.kotlin.fir.expressions.impl.FirLazyBlock import org.jetbrains.kotlin.fir.expressions.impl.FirLazyExpression import org.jetbrains.kotlin.fir.psi +import org.jetbrains.kotlin.fir.scopes.kotlinScopeProvider import org.jetbrains.kotlin.fir.visitors.FirTransformer import org.jetbrains.kotlin.fir.visitors.transformSingle import org.jetbrains.kotlin.psi.KtNamedFunction @@ -41,7 +41,7 @@ internal object FirLazyBodiesCalculator { if (simpleFunction.body !is FirLazyBlock) return val newFunction = RawFirNonLocalDeclarationBuilder.buildWithFunctionSymbolRebind( session = simpleFunction.moduleData.session, - scopeProvider = simpleFunction.moduleData.session.firIdeProvider.kotlinScopeProvider, + scopeProvider = simpleFunction.moduleData.session.kotlinScopeProvider, designation = designation, rootNonLocalDeclaration = simpleFunction.psi as KtNamedFunction, ) as FirSimpleFunction @@ -58,7 +58,7 @@ internal object FirLazyBodiesCalculator { val newFunction = RawFirNonLocalDeclarationBuilder.buildWithFunctionSymbolRebind( session = secondaryConstructor.moduleData.session, - scopeProvider = secondaryConstructor.moduleData.session.firIdeProvider.kotlinScopeProvider, + scopeProvider = secondaryConstructor.moduleData.session.kotlinScopeProvider, designation = designation, rootNonLocalDeclaration = secondaryConstructor.psi as KtSecondaryConstructor, ) as FirSimpleFunction @@ -74,7 +74,7 @@ internal object FirLazyBodiesCalculator { val newProperty = RawFirNonLocalDeclarationBuilder.buildWithFunctionSymbolRebind( session = firProperty.moduleData.session, - scopeProvider = firProperty.moduleData.session.firIdeProvider.kotlinScopeProvider, + scopeProvider = firProperty.moduleData.session.kotlinScopeProvider, designation = designation, rootNonLocalDeclaration = firProperty.psi as KtProperty ) as FirProperty diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/FirLazyDeclarationResolver.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/FirLazyDeclarationResolver.kt index 159cb3df907..c122ede55f1 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/FirLazyDeclarationResolver.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/lazy/resolve/FirLazyDeclarationResolver.kt @@ -12,7 +12,6 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.getNonLoc import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.FirFileBuilder import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.ModuleFileCache import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.runCustomResolveUnderLock -import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.firIdeProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.FirFileAnnotationsResolveTransformer import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.FirProviderInterceptorForIDE import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.LazyTransformerFactory @@ -114,6 +113,7 @@ internal class FirLazyDeclarationResolver(private val firFileBuilder: FirFileBui moduleFileCache: ModuleFileCache, toPhase: FirResolvePhase, scopeSession: ScopeSession, + collector: FirTowerDataContextCollector? = null, checkPCE: Boolean = false, ) { if (toPhase == FirResolvePhase.RAW_FIR) return @@ -126,6 +126,7 @@ internal class FirLazyDeclarationResolver(private val firFileBuilder: FirFileBui firFile = firFile, moduleFileCache = moduleFileCache, toPhase = toPhase, + collector = collector, scopeSession = scopeSession, checkPCE = checkPCE, ) @@ -185,7 +186,7 @@ internal class FirLazyDeclarationResolver(private val firFileBuilder: FirFileBui scopeSession = scopeSession, moduleFileCache = moduleFileCache, lazyDeclarationResolver = this, - towerDataContextCollector = null, + towerDataContextCollector = collector, firProviderInterceptor = null, checkPCE = checkPCE, ) @@ -298,14 +299,14 @@ internal class FirLazyDeclarationResolver(private val firFileBuilder: FirFileBui declarationToResolve = enumEntry.findSourceNonLocalFirDeclaration( firFileBuilder, - firDeclarationToResolve.moduleData.session.firIdeProvider.symbolProvider, + firDeclarationToResolve.moduleData.session.firProvider.symbolProvider, moduleFileCache ) neededPhase = FirResolvePhase.BODY_RESOLVE } else { declarationToResolve = nonLocalDeclaration.findSourceNonLocalFirDeclaration( firFileBuilder, - firDeclarationToResolve.moduleData.session.firIdeProvider.symbolProvider, + firDeclarationToResolve.moduleData.session.firProvider.symbolProvider, moduleFileCache ) neededPhase = toPhase diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/FirIdeLibrariesSessionProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/FirIdeLibrariesSessionProvider.kt index 7528bfe78c2..ca7bbdec7e9 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/FirIdeLibrariesSessionProvider.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/FirIdeLibrariesSessionProvider.kt @@ -30,3 +30,4 @@ internal class FirIdeLibrariesSessionProvider( private fun shouldNotBeCalled(): Nothing = error("Should not be called for FirIdeLibrariesSessionProvider") } + diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/FirIdeProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/FirIdeProvider.kt index 295c5fd103e..b16b66ee4fb 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/FirIdeProvider.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/FirIdeProvider.kt @@ -124,5 +124,3 @@ internal class FirIdeProvider( } } } - -internal val FirSession.firIdeProvider: FirIdeProvider by FirSession.sessionComponentAccessor() diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirLibraryResolvableProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirLibraryResolvableProvider.kt new file mode 100644 index 00000000000..3a63e6853f8 --- /dev/null +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirLibraryResolvableProvider.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2010-2022 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.analysis.low.level.api.fir.providers + +import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLibraryResolveModuleFileCache +import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration +import org.jetbrains.kotlin.fir.declarations.FirFile +import org.jetbrains.kotlin.fir.java.deserialization.JvmClassFileBasedSymbolProvider +import org.jetbrains.kotlin.fir.resolve.providers.FirProvider +import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name + +internal class LLFirLibraryResolvableProvider( + override val symbolProvider: JvmClassFileBasedSymbolProvider, + private val cache: LLFirLibraryResolveModuleFileCache, +) : FirProvider() { + + override fun getFirClassifierByFqName(classId: ClassId): FirClassLikeDeclaration? = + symbolProvider.getClassLikeSymbolByClassId(classId)?.fir + + override fun getFirClassifierContainerFile(fqName: ClassId): FirFile = + getFirClassifierContainerFileIfAny(fqName)!! + + override fun getFirClassifierContainerFileIfAny(fqName: ClassId): FirFile? = null + override fun getFirCallableContainerFile(symbol: FirCallableSymbol<*>): FirFile? = null + override fun getFirFilesByPackage(fqName: FqName): List = emptyList() + + override fun getClassNamesInPackage(fqName: FqName): Set = shouldNotBeCalled() + + private fun shouldNotBeCalled(): Nothing = error("Should not be called for FirIdeLibrariesSessionProvider") +} diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSessionFactory.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSessionFactory.kt index 1cd39910a12..931cdb96478 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSessionFactory.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSessionFactory.kt @@ -6,6 +6,8 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions import com.intellij.openapi.project.Project +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.psi.search.ProjectScope import org.jetbrains.kotlin.analysis.low.level.api.fir.FirPhaseRunner import org.jetbrains.kotlin.analysis.low.level.api.fir.IdeFirPhaseManager import org.jetbrains.kotlin.analysis.low.level.api.fir.IdeSessionComponents @@ -60,12 +62,12 @@ internal object FirIdeSessionFactory { firPhaseRunner: FirPhaseRunner, sessionInvalidator: FirSessionInvalidator, builtinTypes: BuiltinTypes, - sessionsCache: MutableMap, + sessionsCache: MutableMap, isRootModule: Boolean, librariesCache: LibrariesCache, configureSession: (FirIdeSession.() -> Unit)? = null ): FirIdeSourcesSession { - sessionsCache[module]?.let { return it } + sessionsCache[module]?.let { return it as FirIdeSourcesSession } val languageVersionSettings = module.languageVersionSettings val scopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped) val firBuilder = FirFileBuilder(scopeProvider, firPhaseRunner) @@ -211,7 +213,7 @@ internal object FirIdeSessionFactory { } } - private fun createModuleDataProvider(sourceModule: KtSourceModule, session: FirIdeSession): ModuleDataProvider { + private fun createModuleDataProvider(sourceModule: KtModule, session: FirIdeSession): ModuleDataProvider { val dependencyList = DependencyListForCliModule.build( Name.special("<${sourceModule.moduleDescription}>"), sourceModule.platform, @@ -264,6 +266,113 @@ internal object FirIdeSessionFactory { } } + fun creatLibraryOrLibrarySourceResolvableSession( + project: Project, + module: KtModule, + builtinsAndCloneableSession: FirIdeBuiltinsAndCloneableSession, + firPhaseRunner: FirPhaseRunner, + sessionInvalidator: FirSessionInvalidator, + builtinTypes: BuiltinTypes, + sessionsCache: MutableMap, + languageVersionSettings: LanguageVersionSettings = LanguageVersionSettingsImpl.DEFAULT, + configureSession: (FirIdeSession.() -> Unit)? = null + ): LLFirLibraryOrLibrarySourceResolvableModuleSession { + LLFirLibraryOrLibrarySourceResolvableModuleSession.checkIsValidKtModule(module) + sessionsCache[module]?.let { return it as LLFirLibraryOrLibrarySourceResolvableModuleSession } + checkCanceled() + + val libraryModule = when (module) { + is KtLibraryModule -> module + is KtLibrarySourceModule -> module.binaryLibrary + else -> error("Unexpected module ${module::class.simpleName}") + } + + + val scopeProvider = FirKotlinScopeProvider() + val firFileBuilder = FirFileBuilder(scopeProvider, firPhaseRunner) + val contentScope = module.contentScope + val session = LLFirLibraryOrLibrarySourceResolvableModuleSession(module, project, firFileBuilder, builtinTypes) + sessionsCache[module] = session + + return session.apply session@{ + val moduleData = KtModuleBasedModuleData(module).apply { bindSession(this@session) } + registerModuleData(moduleData) + register(FirKotlinScopeProvider::class, scopeProvider) + + val cache = ModuleFileCacheImpl(this) + val firPhaseManager = IdeFirPhaseManager(FirLazyDeclarationResolver(firFileBuilder), cache, sessionInvalidator) + + registerIdeComponents(project) + registerCommonComponents(languageVersionSettings) + registerCommonJavaComponents(JavaModuleResolver.getInstance(project)) + registerResolveComponents() + + val provider = FirIdeProvider( + project, + this, + module, + scopeProvider, + firFileBuilder, + cache, + project.createDeclarationProvider(contentScope), + project.createPackageProvider(contentScope), + ) + + register(FirProvider::class, provider) + register(FirIdeProvider::class, provider) + + register(FirPhaseManager::class, firPhaseManager) + val dependentProviders = buildList { + val librariesSearchScope = ProjectScope.getLibrariesScope(project) + .intersectWith(GlobalSearchScope.notScope(libraryModule.contentScope)) // - + add(builtinsAndCloneableSession.symbolProvider) + add( + JvmClassFileBasedSymbolProvider( + this@session, + moduleDataProvider = createModuleDataProvider(module, this@session), + kotlinScopeProvider = scopeProvider, + packagePartProvider = project.createPackagePartProviderForLibrary(librariesSearchScope), + kotlinClassFinder = VirtualFileFinderFactory.getInstance(project).create(librariesSearchScope), + javaFacade = FirJavaFacade( + this@session, moduleData, project.createJavaClassFinder(librariesSearchScope) + ) + ) + ) + } + + val dependencyProvider = DependentModuleProviders(this, dependentProviders) + + register( + FirSymbolProvider::class, + FirModuleWithDependenciesSymbolProvider( + this, + providers = listOf( + provider.symbolProvider, + JavaSymbolProvider( + this, + FirJavaFacade( + this, moduleData, project.createJavaClassFinder(contentScope) + ) + ), + ), + dependencyProvider + ) + ) + + register(FirDependenciesSymbolProvider::class, dependencyProvider) + register(FirJvmTypeMapper::class, FirJvmTypeMapper(this)) + + registerJavaSpecificResolveComponents() + FirSessionFactory.FirSessionConfigurator(this).apply { + for (extensionRegistrar in FirExtensionRegistrar.getInstances(project)) { + registerExtensions(extensionRegistrar.configure()) + } + }.configure() + configureSession?.invoke(this) + } + + } + private fun FirIdeSession.registerIdeComponents(project: Project) { register(IdeSessionComponents::class, IdeSessionComponents.create(this)) register(FirCachesFactory::class, FirThreadSafeCachesFactory) diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSessionProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSessionProvider.kt index 048a9f69f61..bc6ada12ea3 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSessionProvider.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSessionProvider.kt @@ -17,8 +17,8 @@ import org.jetbrains.kotlin.fir.FirSessionProvider @Immutable class FirIdeSessionProvider internal constructor( val project: Project, - internal val rootModuleSession: FirIdeSourcesSession, - val sessions: Map + internal val rootModuleSession: LLFirResolvableModuleSession, + val sessions: Map ) : FirSessionProvider() { override fun getSession(moduleData: FirModuleData): FirSession? = sessions[moduleData.module] @@ -26,6 +26,6 @@ class FirIdeSessionProvider internal constructor( fun getSession(module: KtModule): FirSession? = sessions[module] - internal fun getModuleCache(module: KtSourceModule): ModuleFileCache = - (sessions.getValue(module) as FirIdeSourcesSession).cache + internal fun getModuleCache(module: KtModule): ModuleFileCache = + sessions.getValue(module).cache } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSessionProviderStorage.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSessionProviderStorage.kt index 80ba26ea11f..1127c7bb2d4 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSessionProviderStorage.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSessionProviderStorage.kt @@ -6,51 +6,71 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions import com.intellij.openapi.project.Project +import com.intellij.openapi.util.ModificationTracker import kotlinx.collections.immutable.PersistentMap import kotlinx.collections.immutable.persistentMapOf import kotlinx.collections.immutable.toPersistentMap -import org.jetbrains.kotlin.analysis.providers.createLibrariesModificationTracker -import org.jetbrains.kotlin.analysis.providers.createModuleWithoutDependenciesOutOfBlockModificationTracker -import org.jetbrains.kotlin.fir.BuiltinTypes -import org.jetbrains.kotlin.fir.FirModuleData -import org.jetbrains.kotlin.fir.moduleData import org.jetbrains.kotlin.analysis.low.level.api.fir.FirPhaseRunner import org.jetbrains.kotlin.analysis.low.level.api.fir.util.addValueFor import org.jetbrains.kotlin.analysis.low.level.api.fir.util.executeWithoutPCE +import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule +import org.jetbrains.kotlin.analysis.project.structure.KtLibrarySourceModule import org.jetbrains.kotlin.analysis.project.structure.KtModule import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule -import org.jetbrains.kotlin.analysis.utils.caches.* +import org.jetbrains.kotlin.analysis.providers.createLibrariesModificationTracker +import org.jetbrains.kotlin.analysis.providers.createModuleWithoutDependenciesOutOfBlockModificationTracker +import org.jetbrains.kotlin.analysis.utils.caches.getValue +import org.jetbrains.kotlin.analysis.utils.caches.softCachedValue +import org.jetbrains.kotlin.fir.BuiltinTypes +import org.jetbrains.kotlin.fir.FirModuleData +import org.jetbrains.kotlin.fir.moduleData import java.util.concurrent.ConcurrentHashMap class FirIdeSessionProviderStorage(val project: Project) { - private val sessionsCache = ConcurrentHashMap() + private val sessionsCache = ConcurrentHashMap() private val librariesCache by softCachedValue(project, project.createLibrariesModificationTracker()) { LibrariesCache() } fun getSessionProvider( - rootModule: KtSourceModule, + rootModule: KtModule, configureSession: (FirIdeSession.() -> Unit)? = null ): FirIdeSessionProvider { val firPhaseRunner = FirPhaseRunner() val builtinTypes = BuiltinTypes() val builtinsAndCloneableSession = FirIdeSessionFactory.createBuiltinsAndCloneableSession(project, builtinTypes) - val cache = sessionsCache.getOrPut(rootModule) { FromModuleViewSessionCache(rootModule) } + val cache = sessionsCache.getOrPut(rootModule) { FromModuleViewSessionCache() } val (sessions, session) = cache.withMappings(project) { mappings -> - val sessions = mutableMapOf().apply { putAll(mappings) } + val sessions = mutableMapOf().apply { putAll(mappings) } val session = executeWithoutPCE { - FirIdeSessionFactory.createSourcesSession( - project, - rootModule, - builtinsAndCloneableSession, - firPhaseRunner, - cache.sessionInvalidator, - builtinTypes, - sessions, - isRootModule = true, - librariesCache = librariesCache, - configureSession = configureSession, - ) + when (rootModule) { + is KtSourceModule -> { + FirIdeSessionFactory.createSourcesSession( + project, + rootModule, + builtinsAndCloneableSession, + firPhaseRunner, + cache.sessionInvalidator, + builtinTypes, + sessions, + isRootModule = true, + librariesCache = librariesCache, + configureSession = configureSession, + ) + } + is KtLibraryModule, is KtLibrarySourceModule -> FirIdeSessionFactory.creatLibraryOrLibrarySourceResolvableSession( + project, + rootModule, + builtinsAndCloneableSession, + firPhaseRunner, + cache.sessionInvalidator, + builtinTypes, + sessions, + configureSession = configureSession, + ) + else -> error("Unexpected ${rootModule::class.simpleName}") + } + } sessions to session } @@ -59,11 +79,9 @@ class FirIdeSessionProviderStorage(val project: Project) { } } -private class FromModuleViewSessionCache( - val root: KtSourceModule, -) { +private class FromModuleViewSessionCache { @Volatile - private var mappings: PersistentMap = persistentMapOf() + private var mappings: PersistentMap = persistentMapOf() val sessionInvalidator: FirSessionInvalidator = FirSessionInvalidator { session -> mappings[session.moduleData.module]?.invalidate() @@ -72,15 +90,15 @@ private class FromModuleViewSessionCache( inline fun withMappings( project: Project, - action: (Map) -> Pair, R> - ): Pair, R> { + action: (Map) -> Pair, R> + ): Pair, R> { val (newMappings, result) = action(getSessions().mapValues { it.value }) mappings = newMappings.mapValues { FirSessionWithModificationTracker(project, it.value) }.toPersistentMap() return newMappings to result } @OptIn(ExperimentalStdlibApi::class) - private fun getSessions(): Map = buildMap { + private fun getSessions(): Map = buildMap { val sessions = mappings.values val wasSessionInvalidated = sessions.associateWithTo(hashMapOf()) { false } @@ -122,10 +140,13 @@ private class FromModuleViewSessionCache( private class FirSessionWithModificationTracker( project: Project, - val firSession: FirIdeSourcesSession, + val firSession: LLFirResolvableModuleSession, ) { private val modificationTracker = - firSession.moduleData.module.createModuleWithoutDependenciesOutOfBlockModificationTracker(project) + when (val moduleInfo = firSession.moduleData.module) { + is KtSourceModule -> moduleInfo.createModuleWithoutDependenciesOutOfBlockModificationTracker(project) + else -> ModificationTracker.NEVER_CHANGED + } private val timeStamp = modificationTracker.modificationCount @@ -139,7 +160,7 @@ private class FirSessionWithModificationTracker( val isValid: Boolean get() = !isInvalidated && modificationTracker.modificationCount == timeStamp } -internal val FirModuleData.module: KtSourceModule get() = moduleUnsafe() +internal val FirModuleData.module: KtModule get() = moduleUnsafe() internal inline fun FirModuleData.moduleUnsafe(): T = (this as KtModuleBasedModuleData).module as T internal inline fun FirModuleData.moduleInfoSafe(): T? = (this as KtModuleBasedModuleData).module as? T diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSourcesSession.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSourcesSession.kt index 3ff8d2b2440..7be7868b8bd 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSourcesSession.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSourcesSession.kt @@ -6,21 +6,14 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions import com.intellij.openapi.project.Project -import com.intellij.psi.search.GlobalSearchScope import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.FirFileBuilder -import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.firIdeProvider -import org.jetbrains.kotlin.analysis.project.structure.KtModule import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule import org.jetbrains.kotlin.fir.BuiltinTypes import org.jetbrains.kotlin.fir.PrivateSessionConstructor -@OptIn(PrivateSessionConstructor::class) internal class FirIdeSourcesSession @PrivateSessionConstructor constructor( override val module: KtSourceModule, override val project: Project, - val firFileBuilder: FirFileBuilder, + override val firFileBuilder: FirFileBuilder, builtinTypes: BuiltinTypes, -) : FirIdeModuleSession(builtinTypes, Kind.Source) { - val cache get() = firIdeProvider.cache -} - +) : LLFirResolvableModuleSession(builtinTypes) diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirSessionInvalidator.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirSessionInvalidator.kt index 38dfcdf069a..c1fa3ab02a8 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirSessionInvalidator.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirSessionInvalidator.kt @@ -7,9 +7,9 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions import org.jetbrains.kotlin.fir.FirSession -internal class FirSessionInvalidator(private val invalidateSourcesSession: (FirIdeSourcesSession) -> Unit) { +internal class FirSessionInvalidator(private val invalidateSourcesSession: (LLFirResolvableModuleSession) -> Unit) { fun invalidate(session: FirSession) { - require(session is FirIdeSourcesSession) + require(session is LLFirResolvableModuleSession) invalidateSourcesSession(session) } } \ No newline at end of file diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirLibraryOrLibrarySourceResolvableModuleSession.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirLibraryOrLibrarySourceResolvableModuleSession.kt new file mode 100644 index 00000000000..4b815bb6ba7 --- /dev/null +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirLibraryOrLibrarySourceResolvableModuleSession.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2010-2022 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.analysis.low.level.api.fir.sessions + +import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.FirFileBuilder +import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLibraryResolveModuleFileCache +import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule +import org.jetbrains.kotlin.analysis.project.structure.KtLibrarySourceModule +import org.jetbrains.kotlin.analysis.project.structure.KtModule +import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule +import org.jetbrains.kotlin.fir.BuiltinTypes + +internal class LLFirLibraryOrLibrarySourceResolvableModuleSession( + override val module: KtModule, + override val project: Project, + override val firFileBuilder: FirFileBuilder, + builtinTypes: BuiltinTypes, +) : LLFirResolvableModuleSession(builtinTypes) { + init { + checkIsValidKtModule(module) + } + + companion object { + fun checkIsValidKtModule(module: KtModule) { + require(module is KtLibraryModule || module is KtLibrarySourceModule) { + "Expected ${KtLibraryModule::class.simpleName} or ${KtLibrarySourceModule::class.simpleName}, but ${module::class.simpleName} found" + } + } + } +} \ No newline at end of file diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirResolvableModuleSession.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirResolvableModuleSession.kt new file mode 100644 index 00000000000..3df0f7fcd0e --- /dev/null +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirResolvableModuleSession.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2010-2022 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.analysis.low.level.api.fir.sessions + +import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.FirFileBuilder +import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.ModuleFileCache +import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.FirIdeProvider +import org.jetbrains.kotlin.fir.BuiltinTypes +import org.jetbrains.kotlin.fir.resolve.providers.firProvider + +internal abstract class LLFirResolvableModuleSession( + builtinTypes: BuiltinTypes, +) : FirIdeModuleSession(builtinTypes, Kind.Source) { + internal val cache: ModuleFileCache get() = (firProvider as FirIdeProvider).cache + abstract val firFileBuilder: FirFileBuilder +} \ No newline at end of file diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LibrariesCache.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LibrariesCache.kt index a1f397c71c6..9a08b95bf6d 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LibrariesCache.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LibrariesCache.kt @@ -5,16 +5,17 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions +import org.jetbrains.kotlin.analysis.project.structure.KtModule import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule import java.util.concurrent.ConcurrentHashMap @JvmInline internal value class LibrariesCache( - private val cache: ConcurrentHashMap = ConcurrentHashMap() + private val cache: ConcurrentHashMap = ConcurrentHashMap() ) { fun cached( - moduleSourceInfo: KtSourceModule, - create: (KtSourceModule) -> FirIdeLibrariesSession + module: KtModule, + create: (KtModule) -> FirIdeLibrariesSession ): FirIdeLibrariesSession = - cache.computeIfAbsent(moduleSourceInfo, create) + cache.computeIfAbsent(module, create) } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/FirPhysicalModuleResolveState.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/FirPhysicalModuleResolveState.kt deleted file mode 100644 index 1aad192c415..00000000000 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/FirPhysicalModuleResolveState.kt +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright 2010-2022 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.analysis.low.level.api.fir.state - -import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState - -abstract class FirPhysicalModuleResolveState : FirModuleResolveState() \ No newline at end of file diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/FirSourceModuleResolveState.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/FirSourceModuleResolveState.kt index ad5d8f3ae5a..f4503e6dc25 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/FirSourceModuleResolveState.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/FirSourceModuleResolveState.kt @@ -8,73 +8,25 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.state import com.intellij.openapi.project.Project import org.jetbrains.kotlin.analysis.low.level.api.fir.api.DiagnosticCheckerFilter import org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics.DiagnosticsCollector -import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirElementBuilder -import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.getNonLocalContainingOrThisDeclaration import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.FirFileBuilder -import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.ModuleFileCache -import org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.FileStructureCache import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.FirLazyDeclarationResolver -import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.firIdeProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.FirIdeSessionProvider -import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.FirIdeSourcesSession -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.FirDeclarationForCompiledElementSearcher -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.findSourceNonLocalFirDeclaration -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.getElementTextInContext -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.originalDeclaration import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule import org.jetbrains.kotlin.analysis.project.structure.KtModule import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule -import org.jetbrains.kotlin.analysis.project.structure.getKtModule +import org.jetbrains.kotlin.analysis.utils.errors.unexpectedElementError import org.jetbrains.kotlin.diagnostics.KtPsiDiagnostic -import org.jetbrains.kotlin.fir.FirElement -import org.jetbrains.kotlin.fir.FirSession -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.expressions.FirAnonymousFunctionExpression -import org.jetbrains.kotlin.fir.expressions.FirAnonymousObjectExpression -import org.jetbrains.kotlin.fir.resolve.ScopeSession -import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider -import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol -import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.psi.KtFile internal class FirSourceModuleResolveState( override val project: Project, - override val module: KtSourceModule, - private val sessionProvider: FirIdeSessionProvider, - val firFileBuilder: FirFileBuilder, - val firLazyDeclarationResolver: FirLazyDeclarationResolver, -) : FirPhysicalModuleResolveState() { - override val rootModuleSession: FirIdeSourcesSession get() = sessionProvider.rootModuleSession - - /** - * WARNING! This object contains scopes for all statements and declarations that were ever resolved. - * 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. - */ - val fileStructureCache = FileStructureCache(firFileBuilder, firLazyDeclarationResolver) - val elementBuilder = FirElementBuilder() - private val diagnosticsCollector = DiagnosticsCollector(fileStructureCache, rootModuleSession.cache) - - override fun getSessionFor(module: KtModule): FirSession = - sessionProvider.getSession(module)!! - - override fun getOrBuildFirFor(element: KtElement): FirElement? = - elementBuilder.getOrBuildFirFor( - element = element, - firFileBuilder = firFileBuilder, - moduleFileCache = rootModuleSession.cache, - fileStructureCache = fileStructureCache, - firLazyDeclarationResolver = firLazyDeclarationResolver, - state = this - ) - - override fun getOrBuildFirFile(ktFile: KtFile): FirFile = - firFileBuilder.buildRawFirFileWithCaching(ktFile, rootModuleSession.cache) - - override fun tryGetCachedFirFile(declaration: FirDeclaration, cache: ModuleFileCache): FirFile? = - cache.getContainerFirFile(declaration) + override val module: KtModule, + sessionProvider: FirIdeSessionProvider, + firFileBuilder: FirFileBuilder, + firLazyDeclarationResolver: FirLazyDeclarationResolver, +) : LLFirResolvableModuleResolveState(sessionProvider, firFileBuilder, firLazyDeclarationResolver) { + private val diagnosticsCollector = DiagnosticsCollector(fileStructureCache, cache) override fun getDiagnostics(element: KtElement, filter: DiagnosticCheckerFilter): List = diagnosticsCollector.getDiagnosticsFor(element, filter) @@ -82,70 +34,12 @@ internal class FirSourceModuleResolveState( override fun collectDiagnosticsForFile(ktFile: KtFile, filter: DiagnosticCheckerFilter): Collection = diagnosticsCollector.collectDiagnosticsForFile(ktFile, filter) - override fun resolveToFirSymbol( - ktDeclaration: KtDeclaration, - phase: FirResolvePhase - ): FirBasedSymbol<*> { - return when (val module = ktDeclaration.getKtModule()) { - is KtSourceModule -> findSourceFirSymbol(ktDeclaration).also { resolveFirToPhase(it.fir, phase) } - is KtLibraryModule -> findFirCompiledSymbol(ktDeclaration) - else -> error("unsupported module $module") + override fun getModuleKind(module: KtModule): ModuleKind { + return when (module) { + is KtSourceModule -> ModuleKind.RESOLVABLE_MODULE + is KtLibraryModule -> ModuleKind.BINARY_MODULE + else -> unexpectedElementError("module", module) } } - - private fun findSourceFirSymbol(ktDeclaration: KtDeclaration): FirBasedSymbol<*> { - return findSourceFirDeclarationByExpression(ktDeclaration.originalDeclaration ?: ktDeclaration).symbol - } - - private fun findFirCompiledSymbol(ktDeclaration: KtDeclaration): FirBasedSymbol<*> { - require(ktDeclaration.containingKtFile.isCompiled) { - "This method will only work on compiled declarations, but this declaration is not compiled: ${ktDeclaration.getElementTextInContext()}" - } - - val searcher = FirDeclarationForCompiledElementSearcher(rootModuleSession.symbolProvider) - val firDeclaration = searcher.findNonLocalDeclaration(ktDeclaration) - return firDeclaration.symbol - } - - /** - * [ktDeclaration] should be either [KtDeclaration] or [KtLambdaExpression] - */ - private fun findSourceFirDeclarationByExpression(ktDeclaration: KtExpression): FirDeclaration { - val module = ktDeclaration.getKtModule(project) - require(module is KtSourceModule) { - "Declaration should have ModuleSourceInfo, instead it had ${module::class}" - } - val nonLocalNamedDeclaration = ktDeclaration.getNonLocalContainingOrThisDeclaration() - ?: error("Declaration should have non-local container${ktDeclaration.getElementTextInContext()}") - - if (ktDeclaration == nonLocalNamedDeclaration) { - return nonLocalNamedDeclaration.findSourceNonLocalFirDeclaration( - firFileBuilder = firFileBuilder, - firSymbolProvider = rootModuleSession.firIdeProvider.symbolProvider, - moduleFileCache = sessionProvider.getModuleCache(module) - ) - } - - return when (val localFirElement = getOrBuildFirFor(ktDeclaration)) { - is FirDeclaration -> localFirElement - is FirAnonymousFunctionExpression -> localFirElement.anonymousFunction - is FirAnonymousObjectExpression -> localFirElement.anonymousObject - else -> error("FirDeclaration was not found for\n${ktDeclaration.getElementTextInContext()}") - } - } - - override fun resolveFirToPhase(declaration: FirDeclaration, toPhase: FirResolvePhase) { - if (toPhase == FirResolvePhase.RAW_FIR) return - val fileCache = when (val session = declaration.moduleData.session) { - is FirIdeSourcesSession -> session.cache - else -> return - } - firLazyDeclarationResolver.lazyResolveDeclaration( - firDeclarationToResolve = declaration, - moduleFileCache = fileCache, - scopeSession = ScopeSession(), - toPhase = toPhase, - checkPCE = true, - ) - } } + diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirLibraryOrLibrarySourceResolvableModuleResolveState.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirLibraryOrLibrarySourceResolvableModuleResolveState.kt new file mode 100644 index 00000000000..ac9858638a2 --- /dev/null +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirLibraryOrLibrarySourceResolvableModuleResolveState.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2010-2022 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.analysis.low.level.api.fir.state + +import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.analysis.low.level.api.fir.api.DiagnosticCheckerFilter +import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.FirFileBuilder +import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.FirLazyDeclarationResolver +import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.FirIdeSessionProvider +import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirLibraryOrLibrarySourceResolvableModuleSession +import org.jetbrains.kotlin.analysis.project.structure.KtModule +import org.jetbrains.kotlin.diagnostics.KtPsiDiagnostic +import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.psi.KtFile + + +internal class LLFirLibraryOrLibrarySourceResolvableModuleResolveState( + override val project: Project, + override val module: KtModule, + sessionProvider: FirIdeSessionProvider, + firFileBuilder: FirFileBuilder, + firLazyDeclarationResolver: FirLazyDeclarationResolver, +) : LLFirResolvableModuleResolveState(sessionProvider, firFileBuilder, firLazyDeclarationResolver) { + override fun getDiagnostics(element: KtElement, filter: DiagnosticCheckerFilter): List = + emptyList() + + override fun collectDiagnosticsForFile(ktFile: KtFile, filter: DiagnosticCheckerFilter): Collection = + emptyList() + + override fun getModuleKind(module: KtModule): ModuleKind { + LLFirLibraryOrLibrarySourceResolvableModuleSession.checkIsValidKtModule(module) + return when { + module == this.module -> ModuleKind.RESOLVABLE_MODULE + else -> ModuleKind.BINARY_MODULE + } + } +} + diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirResolvableModuleResolveState.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirResolvableModuleResolveState.kt new file mode 100644 index 00000000000..b352ff8f620 --- /dev/null +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirResolvableModuleResolveState.kt @@ -0,0 +1,150 @@ +/* + * Copyright 2010-2022 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.analysis.low.level.api.fir.state + +import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState +import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirElementBuilder +import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirTowerContextProvider +import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.getNonLocalContainingOrThisDeclaration +import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.FirFileBuilder +import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.ModuleFileCache +import org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.FileStructureCache +import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.FirLazyDeclarationResolver +import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.FirIdeProvider +import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.FirIdeSessionProvider +import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.FirIdeSourcesSession +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.FirDeclarationForCompiledElementSearcher +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.findSourceNonLocalFirDeclaration +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.getElementTextInContext +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.originalDeclaration +import org.jetbrains.kotlin.analysis.project.structure.KtModule +import org.jetbrains.kotlin.analysis.project.structure.getKtModule +import org.jetbrains.kotlin.fir.FirElement +import org.jetbrains.kotlin.fir.FirSession +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.expressions.FirAnonymousFunctionExpression +import org.jetbrains.kotlin.fir.expressions.FirAnonymousObjectExpression +import org.jetbrains.kotlin.fir.resolve.ScopeSession +import org.jetbrains.kotlin.fir.resolve.providers.firProvider +import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider +import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol +import org.jetbrains.kotlin.psi.* + +internal abstract class LLFirResolvableModuleResolveState( + protected val sessionProvider: FirIdeSessionProvider, + val firFileBuilder: FirFileBuilder, + val firLazyDeclarationResolver: FirLazyDeclarationResolver, +) : FirModuleResolveState() { + final override val rootModuleSession = sessionProvider.rootModuleSession + val cache = (rootModuleSession.firProvider as FirIdeProvider).cache + + val fileStructureCache = FileStructureCache(firFileBuilder, firLazyDeclarationResolver) + val elementBuilder = FirElementBuilder() + + override fun getSessionFor(module: KtModule): FirSession = + sessionProvider.getSession(module)!! + + override fun getOrBuildFirFor(element: KtElement): FirElement? = + elementBuilder.getOrBuildFirFor( + element = element, + firFileBuilder = firFileBuilder, + moduleFileCache = cache, + fileStructureCache = fileStructureCache, + firLazyDeclarationResolver = firLazyDeclarationResolver, + state = this + ) + + + override fun getOrBuildFirFile(ktFile: KtFile): FirFile = + firFileBuilder.buildRawFirFileWithCaching(ktFile, cache) + + override fun tryGetCachedFirFile(declaration: FirDeclaration, cache: ModuleFileCache): FirFile? = + cache.getContainerFirFile(declaration) + + override fun resolveToFirSymbol( + ktDeclaration: KtDeclaration, + phase: FirResolvePhase + ): FirBasedSymbol<*> { + val module = ktDeclaration.getKtModule() + return when (getModuleKind(module)) { + ModuleKind.RESOLVABLE_MODULE -> findSourceFirSymbol(ktDeclaration, module).also { resolveFirToPhase(it.fir, phase) } + ModuleKind.BINARY_MODULE -> findFirCompiledSymbol(ktDeclaration) + } + } + + private fun findFirCompiledSymbol(ktDeclaration: KtDeclaration): FirBasedSymbol<*> { + require(ktDeclaration.containingKtFile.isCompiled) { + "This method will only work on compiled declarations, but this declaration is not compiled: ${ktDeclaration.getElementTextInContext()}" + } + + val searcher = FirDeclarationForCompiledElementSearcher(rootModuleSession.symbolProvider) + val firDeclaration = searcher.findNonLocalDeclaration(ktDeclaration) + return firDeclaration.symbol + } + + private fun findSourceFirSymbol(ktDeclaration: KtDeclaration, module: KtModule): FirBasedSymbol<*> { + return findSourceFirDeclarationByExpression(ktDeclaration.originalDeclaration ?: ktDeclaration, module) + } + + /** + * [ktDeclaration] should be either [KtDeclaration] or [KtLambdaExpression] + */ + private fun findSourceFirDeclarationByExpression(ktDeclaration: KtExpression, module: KtModule): FirBasedSymbol<*> { + require(getModuleKind(module) == ModuleKind.RESOLVABLE_MODULE) { + "Declaration should be resolvable module, instead it had ${module::class}" + } + val nonLocalNamedDeclaration = ktDeclaration.getNonLocalContainingOrThisDeclaration() + ?: error("Declaration should have non-local container${ktDeclaration.getElementTextInContext()}") + + if (ktDeclaration == nonLocalNamedDeclaration) { + return nonLocalNamedDeclaration.findSourceNonLocalFirDeclaration( + firFileBuilder = firFileBuilder, + firSymbolProvider = rootModuleSession.firProvider.symbolProvider, + moduleFileCache = sessionProvider.getModuleCache(module) + ).symbol + } + + return findDeclarationInSourceViaResolve(ktDeclaration) + } + + protected abstract fun getModuleKind(module: KtModule): ModuleKind + + private fun findDeclarationInSourceViaResolve(ktDeclaration: KtExpression): FirBasedSymbol<*> { + val firDeclaration = when (val fir = getOrBuildFirFor(ktDeclaration)) { + is FirDeclaration -> fir + is FirAnonymousFunctionExpression -> fir.anonymousFunction + is FirAnonymousObjectExpression -> fir.anonymousObject + else -> error("FirDeclaration was not found for\n${ktDeclaration.getElementTextInContext()}") + } + return firDeclaration.symbol + } + + override fun resolveFirToPhase(declaration: FirDeclaration, toPhase: FirResolvePhase) { + if (toPhase == FirResolvePhase.RAW_FIR) return + val fileCache = when (val session = declaration.moduleData.session) { + is FirIdeSourcesSession -> session.cache + else -> return + } + firLazyDeclarationResolver.lazyResolveDeclaration( + firDeclarationToResolve = declaration, + moduleFileCache = fileCache, + scopeSession = ScopeSession(), + toPhase = toPhase, + checkPCE = true, + ) + } + + override fun getTowerContextProvider(ktFile: KtFile): FirTowerContextProvider { + return TowerProviderForElementForState(this) + } + + protected enum class ModuleKind { + RESOLVABLE_MODULE, + BINARY_MODULE + } +} \ No newline at end of file diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/TowerProviderForElementForState.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/TowerProviderForElementForState.kt new file mode 100644 index 00000000000..5ce52ab4b7b --- /dev/null +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/TowerProviderForElementForState.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2010-2022 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.analysis.low.level.api.fir.state + +import org.jetbrains.kotlin.analysis.low.level.api.fir.FirModuleResolveStateDepended +import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState +import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LowLevelFirApiFacadeForResolveOnAir +import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirTowerContextProvider +import org.jetbrains.kotlin.fir.declarations.FirTowerDataContext +import org.jetbrains.kotlin.psi.KtElement + +internal class TowerProviderForElementForState(private val state: FirModuleResolveState) : FirTowerContextProvider { + override fun getClosestAvailableParentContext(ktElement: KtElement): FirTowerDataContext? { + return if (state is FirModuleResolveStateDepended) { + state.towerProviderBuiltUponElement.getClosestAvailableParentContext(ktElement) + ?: LowLevelFirApiFacadeForResolveOnAir.onAirGetTowerContextProvider(state.originalState, ktElement) + .getClosestAvailableParentContext(ktElement) + } else { + LowLevelFirApiFacadeForResolveOnAir.onAirGetTowerContextProvider(state, ktElement).getClosestAvailableParentContext(ktElement) + } + } +} \ No newline at end of file diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/LLFirResolvePhaseChecker.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/LLFirResolvePhaseChecker.kt new file mode 100644 index 00000000000..bda80403319 --- /dev/null +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/LLFirResolvePhaseChecker.kt @@ -0,0 +1,17 @@ +/* + * Copyright 2010-2022 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.analysis.low.level.api.fir.util + +import org.jetbrains.kotlin.fir.declarations.FirDeclaration +import org.jetbrains.kotlin.fir.declarations.FirResolvePhase + +internal object LLFirResolvePhaseChecker { + fun requireResolvePhase(firDeclaration: FirDeclaration, requiredPhase: FirResolvePhase) { + require(firDeclaration.resolvePhase == FirResolvePhase.BODY_RESOLVE) { + "Required $requiredPhase for $firDeclaration but ${firDeclaration.resolvePhase} found" + } + } +} \ No newline at end of file diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/AbstractFirLazyBodiesCalculatorTest.kt b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/AbstractFirLazyBodiesCalculatorTest.kt index 2d66d003b35..8edcdb3eefa 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/AbstractFirLazyBodiesCalculatorTest.kt +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/AbstractFirLazyBodiesCalculatorTest.kt @@ -15,14 +15,13 @@ import org.jetbrains.kotlin.fir.expressions.impl.FirLazyBlock import org.jetbrains.kotlin.fir.expressions.impl.FirLazyExpression import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.FirLazyBodiesCalculator -import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.firIdeProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.AbstractLowLevelApiSingleFileTest +import org.jetbrains.kotlin.fir.scopes.kotlinScopeProvider import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.test.services.TestModuleStructure import org.jetbrains.kotlin.test.services.TestServices abstract class AbstractFirLazyBodiesCalculatorTest : AbstractLowLevelApiSingleFileTest() { - private val lazyChecker = object : FirVisitorVoid() { override fun visitElement(element: FirElement) { TestCase.assertFalse("${FirLazyBlock::class.qualifiedName} should not present in the tree", element is FirLazyBlock) @@ -34,7 +33,7 @@ abstract class AbstractFirLazyBodiesCalculatorTest : AbstractLowLevelApiSingleFi override fun doTestByFileStructure(ktFile: KtFile, moduleStructure: TestModuleStructure, testServices: TestServices) { resolveWithClearCaches(ktFile) { resolveState -> val session = resolveState.rootModuleSession - val provider = session.firIdeProvider.kotlinScopeProvider + val provider = session.kotlinScopeProvider val laziedFirFile = RawFirBuilder( session, @@ -59,5 +58,4 @@ abstract class AbstractFirLazyBodiesCalculatorTest : AbstractLowLevelApiSingleFi TestCase.assertEquals(laziedFirFileDump, fullFirFileDump) } } - } \ No newline at end of file diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/AbstractFirContextCollectionTest.kt b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/AbstractFirContextCollectionTest.kt index 32c3fad7f6e..373d16701ee 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/AbstractFirContextCollectionTest.kt +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/AbstractFirContextCollectionTest.kt @@ -43,7 +43,7 @@ abstract class AbstractFirContextCollectionTest : AbstractLowLevelApiSingleFileT ) { resolveState -> check(resolveState is FirSourceModuleResolveState) - val fileStructure = resolveState.fileStructureCache.getFileStructure(ktFile, resolveState.rootModuleSession.cache) + val fileStructure = resolveState.fileStructureCache.getFileStructure(ktFile, resolveState.cache) val allStructureElements = fileStructure.getAllStructureElements() handler.elementsToCheckContext = allStructureElements.map { it.getFirDeclaration() } diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/AbstractFileStructureTest.kt b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/AbstractFileStructureTest.kt index f1f9971bf8a..6451de08ec1 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/AbstractFileStructureTest.kt +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/AbstractFileStructureTest.kt @@ -88,7 +88,7 @@ abstract class AbstractFileStructureTest : AbstractLowLevelApiSingleFileTest() { val moduleResolveState = getResolveState() as FirSourceModuleResolveState return moduleResolveState.fileStructureCache.getFileStructure( ktFile = this, - moduleFileCache = moduleResolveState.rootModuleSession.cache + moduleFileCache = moduleResolveState.cache ) }