Analysis API FIR: introduce declarations from library resolve

^KT-50252 fixed
This commit is contained in:
Ilya Kirillov
2022-01-24 11:35:20 +01:00
parent d9200affe4
commit d926dda27f
34 changed files with 729 additions and 307 deletions
@@ -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.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.types.KtSubstitutor import org.jetbrains.kotlin.analysis.api.types.KtSubstitutor
import org.jetbrains.kotlin.analysis.api.withValidityAssertion 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.getOrBuildFirFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirOfType import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirOfType
import org.jetbrains.kotlin.analysis.low.level.api.fir.resolver.ResolutionParameters import org.jetbrains.kotlin.analysis.low.level.api.fir.resolver.ResolutionParameters
@@ -61,7 +60,7 @@ internal class KtFirCompletionCandidateChecker(
val file = originalFile.getOrBuildFirFile(firResolveState) val file = originalFile.getOrBuildFirFile(firResolveState)
val explicitReceiverExpression = possibleExplicitReceiver?.getOrBuildFirOfType<FirExpression>(firResolveState) val explicitReceiverExpression = possibleExplicitReceiver?.getOrBuildFirOfType<FirExpression>(firResolveState)
val resolver = SingleCandidateResolver(firResolveState.rootModuleSession, file) val resolver = SingleCandidateResolver(firResolveState.rootModuleSession, file)
val implicitReceivers = getImplicitReceivers(nameExpression) val implicitReceivers = getImplicitReceivers(originalFile, nameExpression)
for (implicitReceiverValue in implicitReceivers) { for (implicitReceiverValue in implicitReceivers) {
val resolutionParameters = ResolutionParameters( val resolutionParameters = ResolutionParameters(
singleCandidateResolutionMode = SingleCandidateResolutionMode.CHECK_EXTENSION_FOR_COMPLETION, singleCandidateResolutionMode = SingleCandidateResolutionMode.CHECK_EXTENSION_FOR_COMPLETION,
@@ -84,8 +83,11 @@ internal class KtFirCompletionCandidateChecker(
return KtExtensionApplicabilityResult.NonApplicable(KtSubstitutor.Empty(token)) return KtExtensionApplicabilityResult.NonApplicable(KtSubstitutor.Empty(token))
} }
private fun getImplicitReceivers(fakeNameExpression: KtSimpleNameExpression): Sequence<ImplicitReceiverValue<*>?> { private fun getImplicitReceivers(
val towerDataContext = analysisSession.firResolveState.getTowerContextProvider() originalFile: KtFile,
fakeNameExpression: KtSimpleNameExpression
): Sequence<ImplicitReceiverValue<*>?> {
val towerDataContext = analysisSession.firResolveState.getTowerContextProvider(originalFile)
.getClosestAvailableParentContext(fakeNameExpression) .getClosestAvailableParentContext(fakeNameExpression)
?: error("Cannot find enclosing declaration for ${fakeNameExpression.getElementTextInContext()}") ?: error("Cannot find enclosing declaration for ${fakeNameExpression.getElementTextInContext()}")
@@ -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.types.KtType
import org.jetbrains.kotlin.analysis.api.withValidityAssertion 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.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.analysis.low.level.api.fir.util.getElementTextInContext
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirClass
@@ -189,9 +188,8 @@ internal class KtFirScopeProvider(
originalFile: KtFile, originalFile: KtFile,
positionInFakeFile: KtElement positionInFakeFile: KtElement
): KtScopeContext = withValidityAssertion { ): KtScopeContext = withValidityAssertion {
val towerDataContext = val towerDataContext =
analysisSession.firResolveState.getTowerContextProvider().getClosestAvailableParentContext(positionInFakeFile) analysisSession.firResolveState.getTowerContextProvider(originalFile).getClosestAvailableParentContext(positionInFakeFile)
?: error("Cannot find enclosing declaration for ${positionInFakeFile.getElementTextInContext()}") ?: error("Cannot find enclosing declaration for ${positionInFakeFile.getElementTextInContext()}")
val implicitReceivers = towerDataContext.nonLocalTowerDataElements.mapNotNull { it.implicitReceiver }.distinct() val implicitReceivers = towerDataContext.nonLocalTowerDataElements.mapNotNull { it.implicitReceiver }.distinct()
@@ -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.KtType
import org.jetbrains.kotlin.analysis.api.types.KtTypeNullability import org.jetbrains.kotlin.analysis.api.types.KtTypeNullability
import org.jetbrains.kotlin.analysis.api.withValidityAssertion 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.getOrBuildFir
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.throwUnexpectedFirElementError import org.jetbrains.kotlin.analysis.low.level.api.fir.api.throwUnexpectedFirElementError
import org.jetbrains.kotlin.fir.FirRenderer 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.ConeTypeCompatibilityChecker.isCompatible
import org.jetbrains.kotlin.fir.analysis.checkers.fullyExpandedClass import org.jetbrains.kotlin.fir.analysis.checkers.fullyExpandedClass
import org.jetbrains.kotlin.fir.analysis.checkers.typeParameterSymbols 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.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes
import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess
@@ -124,7 +122,7 @@ internal class KtFirTypeProvider(
} }
override fun getImplicitReceiverTypesAtPosition(position: KtElement): List<KtType> { override fun getImplicitReceiverTypesAtPosition(position: KtElement): List<KtType> {
return analysisSession.firResolveState.getTowerContextProvider() return analysisSession.firResolveState.getTowerContextProvider(position.containingKtFile)
.getClosestAvailableParentContext(position)?.implicitReceiverStack?.map { it.type.asKtType() } ?: emptyList() .getClosestAvailableParentContext(position)?.implicitReceiverStack?.map { it.type.asKtType() } ?: emptyList()
} }
@@ -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 }}")
}
@@ -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.lazy.resolve.FirLazyDeclarationResolver
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.FirIdeSession 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.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.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.KtModule
import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule
import org.jetbrains.kotlin.analysis.providers.createProjectWideOutOfBlockModificationTracker import org.jetbrains.kotlin.analysis.providers.createProjectWideOutOfBlockModificationTracker
@@ -27,10 +33,10 @@ internal class FirIdeResolveStateService(project: Project) {
project.createProjectWideOutOfBlockModificationTracker(), project.createProjectWideOutOfBlockModificationTracker(),
ProjectRootModificationTracker.getInstance(project), ProjectRootModificationTracker.getInstance(project),
) { ) {
ConcurrentHashMap<KtModule, FirSourceModuleResolveState>() ConcurrentHashMap<KtModule, LLFirResolvableModuleResolveState>()
} }
fun getResolveState(module: KtModule): FirSourceModuleResolveState = fun getResolveState(module: KtModule): LLFirResolvableModuleResolveState =
stateCache.computeIfAbsent(module) { createResolveStateFor(module, sessionProviderStorage) } stateCache.computeIfAbsent(module) { createResolveStateFor(module, sessionProviderStorage) }
companion object { companion object {
@@ -41,19 +47,34 @@ internal class FirIdeResolveStateService(project: Project) {
module: KtModule, module: KtModule,
sessionProviderStorage: FirIdeSessionProviderStorage, sessionProviderStorage: FirIdeSessionProviderStorage,
configureSession: (FirIdeSession.() -> Unit)? = null, configureSession: (FirIdeSession.() -> Unit)? = null,
): FirSourceModuleResolveState { ): LLFirResolvableModuleResolveState {
if (module !is KtSourceModule) {
error("Creating FirModuleResolveState is not yet supported for $module")
}
val sessionProvider = sessionProviderStorage.getSessionProvider(module, configureSession) val sessionProvider = sessionProviderStorage.getSessionProvider(module, configureSession)
val firFileBuilder = sessionProvider.rootModuleSession.firFileBuilder return when (module) {
return FirSourceModuleResolveState( is KtSourceModule -> {
sessionProviderStorage.project, val firFileBuilder = (sessionProvider.rootModuleSession as FirIdeSourcesSession).firFileBuilder
module, FirSourceModuleResolveState(
sessionProvider, sessionProviderStorage.project,
firFileBuilder, module,
FirLazyDeclarationResolver(firFileBuilder), 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")
}
}
} }
} }
} }
@@ -8,10 +8,13 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir
import com.intellij.openapi.project.Project 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.DiagnosticCheckerFilter
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState 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.FirTowerContextProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.ModuleFileCache 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.file.structure.KtToFirMapping
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.FirSourceModuleResolveState 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.containingKtFileIfAny
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.originalKtFile import org.jetbrains.kotlin.analysis.low.level.api.fir.util.originalKtFile
import org.jetbrains.kotlin.analysis.project.structure.KtModule import org.jetbrains.kotlin.analysis.project.structure.KtModule
@@ -28,35 +31,21 @@ import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtLambdaExpression import org.jetbrains.kotlin.psi.KtLambdaExpression
internal class FirModuleResolveStateDepended( internal class FirModuleResolveStateDepended(
val originalState: FirSourceModuleResolveState, val originalState: LLFirResolvableModuleResolveState,
val towerProviderBuiltUponElement: FirTowerContextProvider, val towerProviderBuiltUponElement: FirTowerContextProvider,
private val ktToFirMapping: KtToFirMapping?, private val ktToFirMapping: KtToFirMapping?,
) : FirModuleResolveState() { ) : FirModuleResolveState() {
override val project: Project get() = originalState.project override val project: Project get() = originalState.project
override val module: KtModule get() = originalState.module override val module: KtModule get() = originalState.module
override val rootModuleSession get() = originalState.rootModuleSession override val rootModuleSession get() = originalState.rootModuleSession
private val fileStructureCache get() = originalState.fileStructureCache
override fun getSessionFor(module: KtModule): FirSession = override fun getSessionFor(module: KtModule): FirSession =
originalState.getSessionFor(module) originalState.getSessionFor(module)
override fun getOrBuildFirFor(element: KtElement): FirElement? { override fun getOrBuildFirFor(element: KtElement): FirElement? {
val elementBuilder = originalState.elementBuilder val psi = FirElementBuilder.getPsiAsFirElementSource(element) ?: return null
val psi = elementBuilder.getPsiAsFirElementSource(element) ?: return null
if (!elementBuilder.doKtElementHasCorrespondingFirElement(element)) return null
ktToFirMapping?.getFirOfClosestParent(psi, this)?.let { return it } ktToFirMapping?.getFirOfClosestParent(psi, this)?.let { return it }
return originalState.getOrBuildFirFor(element = element)
return elementBuilder.getOrBuildFirFor(
element = element,
firFileBuilder = originalState.firFileBuilder,
moduleFileCache = originalState.rootModuleSession.cache,
fileStructureCache = fileStructureCache,
firLazyDeclarationResolver = originalState.firLazyDeclarationResolver,
state = this,
)
} }
override fun getOrBuildFirFile(ktFile: KtFile): FirFile = override fun getOrBuildFirFile(ktFile: KtFile): FirFile =
@@ -82,4 +71,7 @@ internal class FirModuleResolveStateDepended(
override fun resolveToFirSymbol(ktDeclaration: KtDeclaration, phase: FirResolvePhase): FirBasedSymbol<*> { override fun resolveToFirSymbol(ktDeclaration: KtDeclaration, phase: FirResolvePhase): FirBasedSymbol<*> {
return originalState.resolveToFirSymbol(ktDeclaration, phase) return originalState.resolveToFirSymbol(ktDeclaration, phase)
} }
override fun getTowerContextProvider(ktFile: KtFile): FirTowerContextProvider =
TowerProviderForElementForState(this)
} }
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.api package org.jetbrains.kotlin.analysis.low.level.api.fir.api
import com.intellij.openapi.project.Project 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.low.level.api.fir.file.builder.ModuleFileCache
import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule
import org.jetbrains.kotlin.analysis.project.structure.KtModule import org.jetbrains.kotlin.analysis.project.structure.KtModule
@@ -56,4 +57,6 @@ abstract class FirModuleResolveState {
abstract fun resolveToFirSymbol(ktDeclaration: KtDeclaration, phase: FirResolvePhase): FirBasedSymbol<*> abstract fun resolveToFirSymbol(ktDeclaration: KtDeclaration, phase: FirResolvePhase): FirBasedSymbol<*>
internal abstract fun resolveFirToPhase(declaration: FirDeclaration, toPhase: FirResolvePhase) internal abstract fun resolveFirToPhase(declaration: FirDeclaration, toPhase: FirResolvePhase)
abstract fun getTowerContextProvider(ktFile: KtFile): FirTowerContextProvider
} }
@@ -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.api.impl.barebone.parentsOfType
import org.jetbrains.kotlin.analysis.low.level.api.fir.DeclarationCopyBuilder.withBodyFrom 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.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.FileTowerProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirTowerContextProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirTowerContextProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirTowerDataContextAllElementsCollector 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.FirElementsRecorder
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.KtToFirMapping 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.lazy.resolve.*
import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.firIdeProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirResolvableModuleSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.FirIdeSourcesSession 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.getElementTextInContext
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.originalDeclaration import org.jetbrains.kotlin.analysis.low.level.api.fir.util.originalDeclaration
import org.jetbrains.kotlin.analysis.project.structure.getKtModule 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.FirTypeResolveTransformer
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirTowerDataContextCollector import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirTowerDataContextCollector
import org.jetbrains.kotlin.fir.scopes.createImportingScopes 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.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
@@ -67,7 +67,7 @@ object LowLevelFirApiFacadeForResolveOnAir {
place: T, place: T,
elementToResolve: T, elementToResolve: T,
): FirElement { ): FirElement {
require(state is FirSourceModuleResolveState) require(state is LLFirResolvableModuleResolveState)
require(place.isPhysical) require(place.isPhysical)
val declaration = runBodyResolveOnAir( val declaration = runBodyResolveOnAir(
@@ -95,7 +95,7 @@ object LowLevelFirApiFacadeForResolveOnAir {
state: FirModuleResolveState, state: FirModuleResolveState,
place: KtElement, place: KtElement,
): FirTowerContextProvider { ): FirTowerContextProvider {
require(state is FirSourceModuleResolveState) require(state is LLFirResolvableModuleResolveState)
return if (place is KtFile) { return if (place is KtFile) {
FileTowerProvider(place, onAirGetTowerContextForFile(state, place)) FileTowerProvider(place, onAirGetTowerContextForFile(state, place))
@@ -116,11 +116,11 @@ object LowLevelFirApiFacadeForResolveOnAir {
} }
private fun onAirGetTowerContextForFile( private fun onAirGetTowerContextForFile(
state: FirSourceModuleResolveState, state: LLFirResolvableModuleResolveState,
file: KtFile, file: KtFile,
): FirTowerDataContext { ): FirTowerDataContext {
require(file.isPhysical) 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( val firFile = session.firFileBuilder.buildRawFirFileWithCaching(
ktFile = file, ktFile = file,
@@ -144,7 +144,7 @@ object LowLevelFirApiFacadeForResolveOnAir {
originalKtFile: KtFile, originalKtFile: KtFile,
elementToAnalyze: KtElement elementToAnalyze: KtElement
): FirModuleResolveState { ): FirModuleResolveState {
require(originalState is FirSourceModuleResolveState) require(originalState is LLFirResolvableModuleResolveState)
require(elementToAnalyze !is KtFile) { "KtFile for dependency element not supported" } require(elementToAnalyze !is KtFile) { "KtFile for dependency element not supported" }
require(!elementToAnalyze.isPhysical) { "Depended state should be build only for non-physical elements" } require(!elementToAnalyze.isPhysical) { "Depended state should be build only for non-physical elements" }
@@ -178,21 +178,21 @@ object LowLevelFirApiFacadeForResolveOnAir {
private fun tryResolveAsFileAnnotation( private fun tryResolveAsFileAnnotation(
annotationEntry: KtAnnotationEntry, annotationEntry: KtAnnotationEntry,
state: FirSourceModuleResolveState, state: LLFirResolvableModuleResolveState,
replacement: RawFirReplacement, replacement: RawFirReplacement,
firFile: FirFile, firFile: FirFile,
collector: FirTowerDataContextCollector? = null, collector: FirTowerDataContextCollector? = null,
): FirAnnotation { ): FirAnnotation {
val annotationCall = buildFileFirAnnotation( val annotationCall = buildFileFirAnnotation(
session = firFile.moduleData.session, session = firFile.moduleData.session,
baseScopeProvider = firFile.moduleData.session.firIdeProvider.kotlinScopeProvider, baseScopeProvider = firFile.moduleData.session.kotlinScopeProvider,
fileAnnotation = annotationEntry, fileAnnotation = annotationEntry,
replacement = replacement replacement = replacement
) )
state.firLazyDeclarationResolver.resolveFileAnnotations( state.firLazyDeclarationResolver.resolveFileAnnotations(
firFile = firFile, firFile = firFile,
annotations = listOf(annotationCall), annotations = listOf(annotationCall),
moduleFileCache = state.rootModuleSession.cache, moduleFileCache = state.cache,
scopeSession = ScopeSession(), scopeSession = ScopeSession(),
checkPCE = true, checkPCE = true,
collector = collector collector = collector
@@ -202,7 +202,7 @@ object LowLevelFirApiFacadeForResolveOnAir {
} }
private fun runBodyResolveOnAir( private fun runBodyResolveOnAir(
state: FirSourceModuleResolveState, state: LLFirResolvableModuleResolveState,
replacement: RawFirReplacement, replacement: RawFirReplacement,
onAirCreatedDeclaration: Boolean, onAirCreatedDeclaration: Boolean,
collector: FirTowerDataContextCollector? = null, collector: FirTowerDataContextCollector? = null,
@@ -233,7 +233,7 @@ object LowLevelFirApiFacadeForResolveOnAir {
val newDeclarationWithReplacement = RawFirNonLocalDeclarationBuilder.buildWithReplacement( val newDeclarationWithReplacement = RawFirNonLocalDeclarationBuilder.buildWithReplacement(
session = originalDeclaration.moduleData.session, session = originalDeclaration.moduleData.session,
scopeProvider = originalDeclaration.moduleData.session.firIdeProvider.kotlinScopeProvider, scopeProvider = originalDeclaration.moduleData.session.kotlinScopeProvider,
designation = originalDesignation, designation = originalDesignation,
rootNonLocalDeclaration = nonLocalDeclaration, rootNonLocalDeclaration = nonLocalDeclaration,
replacement = replacement, replacement = replacement,
@@ -241,7 +241,7 @@ object LowLevelFirApiFacadeForResolveOnAir {
val isInBodyReplacement = isInBodyReplacement(nonLocalDeclaration, replacement) val isInBodyReplacement = isInBodyReplacement(nonLocalDeclaration, replacement)
return state.rootModuleSession.cache.firFileLockProvider.runCustomResolveUnderLock(originalFirFile, true) { return state.cache.firFileLockProvider.runCustomResolveUnderLock(originalFirFile, true) {
val copiedFirDeclaration = if (isInBodyReplacement) { val copiedFirDeclaration = if (isInBodyReplacement) {
when (originalDeclaration) { when (originalDeclaration) {
is FirSimpleFunction -> is FirSimpleFunction ->
@@ -263,7 +263,7 @@ object LowLevelFirApiFacadeForResolveOnAir {
ResolveTreeBuilder.resolveEnsure(onAirDesignation.declaration, FirResolvePhase.BODY_RESOLVE) { ResolveTreeBuilder.resolveEnsure(onAirDesignation.declaration, FirResolvePhase.BODY_RESOLVE) {
state.firLazyDeclarationResolver.runLazyDesignatedOnAirResolveToBodyWithoutLock( state.firLazyDeclarationResolver.runLazyDesignatedOnAirResolveToBodyWithoutLock(
designation = onAirDesignation, designation = onAirDesignation,
moduleFileCache = state.rootModuleSession.cache, moduleFileCache = state.cache,
checkPCE = true, checkPCE = true,
onAirCreatedDeclaration = onAirCreatedDeclaration, onAirCreatedDeclaration = onAirCreatedDeclaration,
towerDataContextCollector = collector, towerDataContextCollector = collector,
@@ -299,16 +299,16 @@ object LowLevelFirApiFacadeForResolveOnAir {
fun onAirResolveTypeInPlace( fun onAirResolveTypeInPlace(
place: KtElement, place: KtElement,
typeReference: KtTypeReference, typeReference: KtTypeReference,
state: FirModuleResolveState state: FirModuleResolveState,
): FirResolvedTypeRef { ): FirResolvedTypeRef {
val context = state.getTowerContextProvider().getClosestAvailableParentContext(place) val context = state.getTowerContextProvider(place.containingKtFile).getClosestAvailableParentContext(place)
?: error("TowerContext not found for ${place.getElementTextInContext()}") ?: error("TowerContext not found for ${place.getElementTextInContext()}")
val session = state.rootModuleSession val session = state.rootModuleSession
val firTypeReference = buildFirUserTypeRef( val firTypeReference = buildFirUserTypeRef(
typeReference = typeReference, typeReference = typeReference,
session = session, session = session,
baseScopeProvider = session.firIdeProvider.kotlinScopeProvider baseScopeProvider = session.kotlinScopeProvider
) )
return FirTypeResolveTransformer( return FirTypeResolveTransformer(
@@ -317,18 +317,4 @@ object LowLevelFirApiFacadeForResolveOnAir {
initialScopes = context.towerDataElements.asReversed().mapNotNull { it.scope } initialScopes = context.towerDataElements.asReversed().mapNotNull { it.scope }
).transformTypeRef(firTypeReference, null) ).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)
} }
@@ -32,29 +32,32 @@ import org.jetbrains.kotlin.psi2ir.deparenthesize
*/ */
@ThreadSafe @ThreadSafe
internal class FirElementBuilder { internal class FirElementBuilder {
fun getPsiAsFirElementSource(element: KtElement): KtElement? { companion object {
val deparenthesized = if (element is KtPropertyDelegate) element.deparenthesize() else element fun getPsiAsFirElementSource(element: KtElement): KtElement? {
return when { val deparenthesized = if (element is KtPropertyDelegate) element.deparenthesize() else element
deparenthesized is KtParenthesizedExpression -> deparenthesized.deparenthesize() return when {
deparenthesized is KtPropertyDelegate -> deparenthesized.expression ?: element deparenthesized is KtParenthesizedExpression -> deparenthesized.deparenthesize()
deparenthesized is KtQualifiedExpression && deparenthesized.selectorExpression is KtCallExpression -> { 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 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.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) { fun doKtElementHasCorrespondingFirElement(ktElement: KtElement): Boolean = when (ktElement) {
is KtImportList -> false is KtImportList -> false
else -> true else -> true
@@ -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<KtFile, ResolvedFile>()
override val classifierByClassId: ConcurrentHashMap<ClassId, Optional<FirClassLikeDeclaration>> get() = error("Should not be called")
override val callableByCallableId: ConcurrentHashMap<CallableId, List<FirCallableSymbol<*>>> 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<FirFile> = 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,
)
}
@@ -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.FirFileBuilder
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.ModuleFileCache 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.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.findSourceNonLocalFirDeclaration
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.getElementTextInContext import org.jetbrains.kotlin.analysis.low.level.api.fir.util.getElementTextInContext
import org.jetbrains.kotlin.diagnostics.KtPsiDiagnostic import org.jetbrains.kotlin.diagnostics.KtPsiDiagnostic
import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import java.util.concurrent.ConcurrentHashMap 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<KtAnnotated, FileStructureElement>() private val structureElements = ConcurrentHashMap<KtAnnotated, FileStructureElement>()
@@ -59,7 +60,6 @@ internal class FileStructure private constructor(
newKtDeclaration = declaration as KtDeclaration, newKtDeclaration = declaration as KtDeclaration,
cache = moduleFileCache, cache = moduleFileCache,
firLazyDeclarationResolver = firLazyDeclarationResolver, firLazyDeclarationResolver = firLazyDeclarationResolver,
firIdeProvider = firIdeProvider,
) )
} }
else -> structureElement else -> structureElement
@@ -112,7 +112,7 @@ internal class FileStructure private constructor(
private fun createDeclarationStructure(declaration: KtDeclaration): FileStructureElement { private fun createDeclarationStructure(declaration: KtDeclaration): FileStructureElement {
val firDeclaration = declaration.findSourceNonLocalFirDeclaration( val firDeclaration = declaration.findSourceNonLocalFirDeclaration(
firFileBuilder, firFileBuilder,
firIdeProvider.symbolProvider, firProvider.symbolProvider,
moduleFileCache, moduleFileCache,
firFile firFile
) )
@@ -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.RawFirNonLocalDeclarationBuilder
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.declarationCanBeLazilyResolved 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.providers.firIdeProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirResolvableModuleResolveState
import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.psi import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.resolve.ScopeSession 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.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol 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) { internal class KtToFirMapping(firElement: FirElement, recorder: FirElementsRecorder) {
private val mapping = FirElementsRecorder.recordElementsFrom(firElement, recorder) private val mapping = FirElementsRecorder.recordElementsFrom(firElement, recorder)
private val userTypeMapping = ConcurrentHashMap<KtUserType, FirElement>() private val userTypeMapping = ConcurrentHashMap<KtUserType, FirElement>()
fun getElement(ktElement: KtElement, state: FirModuleResolveState): FirElement? {
fun getElement(ktElement: KtElement, state: FirModuleResolveState): FirElement? {
mapping[ktElement]?.let { return it } mapping[ktElement]?.let { return it }
val userType = when (ktElement) { val userType = when (ktElement) {
@@ -87,7 +86,6 @@ internal sealed class ReanalyzableStructureElement<KT : KtDeclaration, S : FirBa
newKtDeclaration: KT, newKtDeclaration: KT,
cache: ModuleFileCache, cache: ModuleFileCache,
firLazyDeclarationResolver: FirLazyDeclarationResolver, firLazyDeclarationResolver: FirLazyDeclarationResolver,
firIdeProvider: FirIdeProvider,
): ReanalyzableStructureElement<KT, S> ): ReanalyzableStructureElement<KT, S>
fun isUpToDate(): Boolean = psi.getModificationStamp() == timestamp fun isUpToDate(): Boolean = psi.getModificationStamp() == timestamp
@@ -116,20 +114,18 @@ internal class ReanalyzableFunctionStructureElement(
newKtDeclaration: KtNamedFunction, newKtDeclaration: KtNamedFunction,
cache: ModuleFileCache, cache: ModuleFileCache,
firLazyDeclarationResolver: FirLazyDeclarationResolver, firLazyDeclarationResolver: FirLazyDeclarationResolver,
firIdeProvider: FirIdeProvider,
): ReanalyzableFunctionStructureElement { ): ReanalyzableFunctionStructureElement {
val originalFunction = firSymbol.fir as FirSimpleFunction val originalFunction = firSymbol.fir as FirSimpleFunction
val designation = originalFunction.collectDesignation() val designation = originalFunction.collectDesignation()
val temporaryFunction = RawFirNonLocalDeclarationBuilder.buildWithFunctionSymbolRebind( val temporaryFunction = RawFirNonLocalDeclarationBuilder.buildWithFunctionSymbolRebind(
session = originalFunction.moduleData.session, session = originalFunction.moduleData.session,
scopeProvider = originalFunction.moduleData.session.firIdeProvider.kotlinScopeProvider, scopeProvider = originalFunction.moduleData.session.kotlinScopeProvider,
designation = designation, designation = designation,
rootNonLocalDeclaration = newKtDeclaration, rootNonLocalDeclaration = newKtDeclaration,
) as FirSimpleFunction ) as FirSimpleFunction
return cache.firFileLockProvider.withWriteLock(firFile) { return cache.firFileLockProvider.withWriteLock(firFile) {
val upgradedPhase = minOf(originalFunction.resolvePhase, FirResolvePhase.DECLARATIONS) val upgradedPhase = minOf(originalFunction.resolvePhase, FirResolvePhase.DECLARATIONS)
with(originalFunction) { with(originalFunction) {
replaceBody(temporaryFunction.body) replaceBody(temporaryFunction.body)
@@ -172,14 +168,13 @@ internal class ReanalyzablePropertyStructureElement(
newKtDeclaration: KtProperty, newKtDeclaration: KtProperty,
cache: ModuleFileCache, cache: ModuleFileCache,
firLazyDeclarationResolver: FirLazyDeclarationResolver, firLazyDeclarationResolver: FirLazyDeclarationResolver,
firIdeProvider: FirIdeProvider,
): ReanalyzablePropertyStructureElement { ): ReanalyzablePropertyStructureElement {
val originalProperty = firSymbol.fir val originalProperty = firSymbol.fir
val designation = originalProperty.collectDesignation() val designation = originalProperty.collectDesignation()
val temporaryProperty = RawFirNonLocalDeclarationBuilder.buildWithFunctionSymbolRebind( val temporaryProperty = RawFirNonLocalDeclarationBuilder.buildWithFunctionSymbolRebind(
session = originalProperty.moduleData.session, session = originalProperty.moduleData.session,
scopeProvider = originalProperty.moduleData.session.firIdeProvider.kotlinScopeProvider, scopeProvider = originalProperty.moduleData.session.kotlinScopeProvider,
designation = designation, designation = designation,
rootNonLocalDeclaration = newKtDeclaration, rootNonLocalDeclaration = newKtDeclaration,
) as FirProperty ) as FirProperty
@@ -9,7 +9,6 @@ import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toPersistentList 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.api.FirDeclarationDesignation
import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.firIdeProvider
import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.getExplicitBackingField 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.FirLazyBlock
import org.jetbrains.kotlin.fir.expressions.impl.FirLazyExpression import org.jetbrains.kotlin.fir.expressions.impl.FirLazyExpression
import org.jetbrains.kotlin.fir.psi import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.scopes.kotlinScopeProvider
import org.jetbrains.kotlin.fir.visitors.FirTransformer import org.jetbrains.kotlin.fir.visitors.FirTransformer
import org.jetbrains.kotlin.fir.visitors.transformSingle import org.jetbrains.kotlin.fir.visitors.transformSingle
import org.jetbrains.kotlin.psi.KtNamedFunction import org.jetbrains.kotlin.psi.KtNamedFunction
@@ -41,7 +41,7 @@ internal object FirLazyBodiesCalculator {
if (simpleFunction.body !is FirLazyBlock) return if (simpleFunction.body !is FirLazyBlock) return
val newFunction = RawFirNonLocalDeclarationBuilder.buildWithFunctionSymbolRebind( val newFunction = RawFirNonLocalDeclarationBuilder.buildWithFunctionSymbolRebind(
session = simpleFunction.moduleData.session, session = simpleFunction.moduleData.session,
scopeProvider = simpleFunction.moduleData.session.firIdeProvider.kotlinScopeProvider, scopeProvider = simpleFunction.moduleData.session.kotlinScopeProvider,
designation = designation, designation = designation,
rootNonLocalDeclaration = simpleFunction.psi as KtNamedFunction, rootNonLocalDeclaration = simpleFunction.psi as KtNamedFunction,
) as FirSimpleFunction ) as FirSimpleFunction
@@ -58,7 +58,7 @@ internal object FirLazyBodiesCalculator {
val newFunction = RawFirNonLocalDeclarationBuilder.buildWithFunctionSymbolRebind( val newFunction = RawFirNonLocalDeclarationBuilder.buildWithFunctionSymbolRebind(
session = secondaryConstructor.moduleData.session, session = secondaryConstructor.moduleData.session,
scopeProvider = secondaryConstructor.moduleData.session.firIdeProvider.kotlinScopeProvider, scopeProvider = secondaryConstructor.moduleData.session.kotlinScopeProvider,
designation = designation, designation = designation,
rootNonLocalDeclaration = secondaryConstructor.psi as KtSecondaryConstructor, rootNonLocalDeclaration = secondaryConstructor.psi as KtSecondaryConstructor,
) as FirSimpleFunction ) as FirSimpleFunction
@@ -74,7 +74,7 @@ internal object FirLazyBodiesCalculator {
val newProperty = RawFirNonLocalDeclarationBuilder.buildWithFunctionSymbolRebind( val newProperty = RawFirNonLocalDeclarationBuilder.buildWithFunctionSymbolRebind(
session = firProperty.moduleData.session, session = firProperty.moduleData.session,
scopeProvider = firProperty.moduleData.session.firIdeProvider.kotlinScopeProvider, scopeProvider = firProperty.moduleData.session.kotlinScopeProvider,
designation = designation, designation = designation,
rootNonLocalDeclaration = firProperty.psi as KtProperty rootNonLocalDeclaration = firProperty.psi as KtProperty
) as FirProperty ) as FirProperty
@@ -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.FirFileBuilder
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.ModuleFileCache 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.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.FirFileAnnotationsResolveTransformer
import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.FirProviderInterceptorForIDE import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.FirProviderInterceptorForIDE
import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.LazyTransformerFactory import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.LazyTransformerFactory
@@ -114,6 +113,7 @@ internal class FirLazyDeclarationResolver(private val firFileBuilder: FirFileBui
moduleFileCache: ModuleFileCache, moduleFileCache: ModuleFileCache,
toPhase: FirResolvePhase, toPhase: FirResolvePhase,
scopeSession: ScopeSession, scopeSession: ScopeSession,
collector: FirTowerDataContextCollector? = null,
checkPCE: Boolean = false, checkPCE: Boolean = false,
) { ) {
if (toPhase == FirResolvePhase.RAW_FIR) return if (toPhase == FirResolvePhase.RAW_FIR) return
@@ -126,6 +126,7 @@ internal class FirLazyDeclarationResolver(private val firFileBuilder: FirFileBui
firFile = firFile, firFile = firFile,
moduleFileCache = moduleFileCache, moduleFileCache = moduleFileCache,
toPhase = toPhase, toPhase = toPhase,
collector = collector,
scopeSession = scopeSession, scopeSession = scopeSession,
checkPCE = checkPCE, checkPCE = checkPCE,
) )
@@ -185,7 +186,7 @@ internal class FirLazyDeclarationResolver(private val firFileBuilder: FirFileBui
scopeSession = scopeSession, scopeSession = scopeSession,
moduleFileCache = moduleFileCache, moduleFileCache = moduleFileCache,
lazyDeclarationResolver = this, lazyDeclarationResolver = this,
towerDataContextCollector = null, towerDataContextCollector = collector,
firProviderInterceptor = null, firProviderInterceptor = null,
checkPCE = checkPCE, checkPCE = checkPCE,
) )
@@ -298,14 +299,14 @@ internal class FirLazyDeclarationResolver(private val firFileBuilder: FirFileBui
declarationToResolve = enumEntry.findSourceNonLocalFirDeclaration( declarationToResolve = enumEntry.findSourceNonLocalFirDeclaration(
firFileBuilder, firFileBuilder,
firDeclarationToResolve.moduleData.session.firIdeProvider.symbolProvider, firDeclarationToResolve.moduleData.session.firProvider.symbolProvider,
moduleFileCache moduleFileCache
) )
neededPhase = FirResolvePhase.BODY_RESOLVE neededPhase = FirResolvePhase.BODY_RESOLVE
} else { } else {
declarationToResolve = nonLocalDeclaration.findSourceNonLocalFirDeclaration( declarationToResolve = nonLocalDeclaration.findSourceNonLocalFirDeclaration(
firFileBuilder, firFileBuilder,
firDeclarationToResolve.moduleData.session.firIdeProvider.symbolProvider, firDeclarationToResolve.moduleData.session.firProvider.symbolProvider,
moduleFileCache moduleFileCache
) )
neededPhase = toPhase neededPhase = toPhase
@@ -30,3 +30,4 @@ internal class FirIdeLibrariesSessionProvider(
private fun shouldNotBeCalled(): Nothing = error("Should not be called for FirIdeLibrariesSessionProvider") private fun shouldNotBeCalled(): Nothing = error("Should not be called for FirIdeLibrariesSessionProvider")
} }
@@ -124,5 +124,3 @@ internal class FirIdeProvider(
} }
} }
} }
internal val FirSession.firIdeProvider: FirIdeProvider by FirSession.sessionComponentAccessor()
@@ -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<FirFile> = emptyList()
override fun getClassNamesInPackage(fqName: FqName): Set<Name> = shouldNotBeCalled()
private fun shouldNotBeCalled(): Nothing = error("Should not be called for FirIdeLibrariesSessionProvider")
}
@@ -6,6 +6,8 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions
import com.intellij.openapi.project.Project 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.FirPhaseRunner
import org.jetbrains.kotlin.analysis.low.level.api.fir.IdeFirPhaseManager import org.jetbrains.kotlin.analysis.low.level.api.fir.IdeFirPhaseManager
import org.jetbrains.kotlin.analysis.low.level.api.fir.IdeSessionComponents import org.jetbrains.kotlin.analysis.low.level.api.fir.IdeSessionComponents
@@ -60,12 +62,12 @@ internal object FirIdeSessionFactory {
firPhaseRunner: FirPhaseRunner, firPhaseRunner: FirPhaseRunner,
sessionInvalidator: FirSessionInvalidator, sessionInvalidator: FirSessionInvalidator,
builtinTypes: BuiltinTypes, builtinTypes: BuiltinTypes,
sessionsCache: MutableMap<KtSourceModule, FirIdeSourcesSession>, sessionsCache: MutableMap<KtModule, LLFirResolvableModuleSession>,
isRootModule: Boolean, isRootModule: Boolean,
librariesCache: LibrariesCache, librariesCache: LibrariesCache,
configureSession: (FirIdeSession.() -> Unit)? = null configureSession: (FirIdeSession.() -> Unit)? = null
): FirIdeSourcesSession { ): FirIdeSourcesSession {
sessionsCache[module]?.let { return it } sessionsCache[module]?.let { return it as FirIdeSourcesSession }
val languageVersionSettings = module.languageVersionSettings val languageVersionSettings = module.languageVersionSettings
val scopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped) val scopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped)
val firBuilder = FirFileBuilder(scopeProvider, firPhaseRunner) 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( val dependencyList = DependencyListForCliModule.build(
Name.special("<${sourceModule.moduleDescription}>"), Name.special("<${sourceModule.moduleDescription}>"),
sourceModule.platform, 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<KtModule, LLFirResolvableModuleSession>,
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)) // <all libraries scope> - <current library scope>
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) { private fun FirIdeSession.registerIdeComponents(project: Project) {
register(IdeSessionComponents::class, IdeSessionComponents.create(this)) register(IdeSessionComponents::class, IdeSessionComponents.create(this))
register(FirCachesFactory::class, FirThreadSafeCachesFactory) register(FirCachesFactory::class, FirThreadSafeCachesFactory)
@@ -17,8 +17,8 @@ import org.jetbrains.kotlin.fir.FirSessionProvider
@Immutable @Immutable
class FirIdeSessionProvider internal constructor( class FirIdeSessionProvider internal constructor(
val project: Project, val project: Project,
internal val rootModuleSession: FirIdeSourcesSession, internal val rootModuleSession: LLFirResolvableModuleSession,
val sessions: Map<KtSourceModule, FirIdeSession> val sessions: Map<KtModule, LLFirResolvableModuleSession>
) : FirSessionProvider() { ) : FirSessionProvider() {
override fun getSession(moduleData: FirModuleData): FirSession? = override fun getSession(moduleData: FirModuleData): FirSession? =
sessions[moduleData.module] sessions[moduleData.module]
@@ -26,6 +26,6 @@ class FirIdeSessionProvider internal constructor(
fun getSession(module: KtModule): FirSession? = fun getSession(module: KtModule): FirSession? =
sessions[module] sessions[module]
internal fun getModuleCache(module: KtSourceModule): ModuleFileCache = internal fun getModuleCache(module: KtModule): ModuleFileCache =
(sessions.getValue(module) as FirIdeSourcesSession).cache sessions.getValue(module).cache
} }
@@ -6,51 +6,71 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.util.ModificationTracker
import kotlinx.collections.immutable.PersistentMap import kotlinx.collections.immutable.PersistentMap
import kotlinx.collections.immutable.persistentMapOf import kotlinx.collections.immutable.persistentMapOf
import kotlinx.collections.immutable.toPersistentMap 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.FirPhaseRunner
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.addValueFor 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.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.KtModule
import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule 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 import java.util.concurrent.ConcurrentHashMap
class FirIdeSessionProviderStorage(val project: Project) { class FirIdeSessionProviderStorage(val project: Project) {
private val sessionsCache = ConcurrentHashMap<KtSourceModule, FromModuleViewSessionCache>() private val sessionsCache = ConcurrentHashMap<KtModule, FromModuleViewSessionCache>()
private val librariesCache by softCachedValue(project, project.createLibrariesModificationTracker()) { LibrariesCache() } private val librariesCache by softCachedValue(project, project.createLibrariesModificationTracker()) { LibrariesCache() }
fun getSessionProvider( fun getSessionProvider(
rootModule: KtSourceModule, rootModule: KtModule,
configureSession: (FirIdeSession.() -> Unit)? = null configureSession: (FirIdeSession.() -> Unit)? = null
): FirIdeSessionProvider { ): FirIdeSessionProvider {
val firPhaseRunner = FirPhaseRunner() val firPhaseRunner = FirPhaseRunner()
val builtinTypes = BuiltinTypes() val builtinTypes = BuiltinTypes()
val builtinsAndCloneableSession = FirIdeSessionFactory.createBuiltinsAndCloneableSession(project, 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, session) = cache.withMappings(project) { mappings ->
val sessions = mutableMapOf<KtSourceModule, FirIdeSourcesSession>().apply { putAll(mappings) } val sessions = mutableMapOf<KtModule, LLFirResolvableModuleSession>().apply { putAll(mappings) }
val session = executeWithoutPCE { val session = executeWithoutPCE {
FirIdeSessionFactory.createSourcesSession( when (rootModule) {
project, is KtSourceModule -> {
rootModule, FirIdeSessionFactory.createSourcesSession(
builtinsAndCloneableSession, project,
firPhaseRunner, rootModule,
cache.sessionInvalidator, builtinsAndCloneableSession,
builtinTypes, firPhaseRunner,
sessions, cache.sessionInvalidator,
isRootModule = true, builtinTypes,
librariesCache = librariesCache, sessions,
configureSession = configureSession, 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 sessions to session
} }
@@ -59,11 +79,9 @@ class FirIdeSessionProviderStorage(val project: Project) {
} }
} }
private class FromModuleViewSessionCache( private class FromModuleViewSessionCache {
val root: KtSourceModule,
) {
@Volatile @Volatile
private var mappings: PersistentMap<KtSourceModule, FirSessionWithModificationTracker> = persistentMapOf() private var mappings: PersistentMap<KtModule, FirSessionWithModificationTracker> = persistentMapOf()
val sessionInvalidator: FirSessionInvalidator = FirSessionInvalidator { session -> val sessionInvalidator: FirSessionInvalidator = FirSessionInvalidator { session ->
mappings[session.moduleData.module]?.invalidate() mappings[session.moduleData.module]?.invalidate()
@@ -72,15 +90,15 @@ private class FromModuleViewSessionCache(
inline fun <R> withMappings( inline fun <R> withMappings(
project: Project, project: Project,
action: (Map<KtSourceModule, FirIdeSourcesSession>) -> Pair<Map<KtSourceModule, FirIdeSourcesSession>, R> action: (Map<KtModule, LLFirResolvableModuleSession>) -> Pair<Map<KtModule, LLFirResolvableModuleSession>, R>
): Pair<Map<KtSourceModule, FirIdeSourcesSession>, R> { ): Pair<Map<KtModule, LLFirResolvableModuleSession>, R> {
val (newMappings, result) = action(getSessions().mapValues { it.value }) val (newMappings, result) = action(getSessions().mapValues { it.value })
mappings = newMappings.mapValues { FirSessionWithModificationTracker(project, it.value) }.toPersistentMap() mappings = newMappings.mapValues { FirSessionWithModificationTracker(project, it.value) }.toPersistentMap()
return newMappings to result return newMappings to result
} }
@OptIn(ExperimentalStdlibApi::class) @OptIn(ExperimentalStdlibApi::class)
private fun getSessions(): Map<KtSourceModule, FirIdeSourcesSession> = buildMap { private fun getSessions(): Map<KtModule, LLFirResolvableModuleSession> = buildMap {
val sessions = mappings.values val sessions = mappings.values
val wasSessionInvalidated = sessions.associateWithTo(hashMapOf()) { false } val wasSessionInvalidated = sessions.associateWithTo(hashMapOf()) { false }
@@ -122,10 +140,13 @@ private class FromModuleViewSessionCache(
private class FirSessionWithModificationTracker( private class FirSessionWithModificationTracker(
project: Project, project: Project,
val firSession: FirIdeSourcesSession, val firSession: LLFirResolvableModuleSession,
) { ) {
private val modificationTracker = 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 private val timeStamp = modificationTracker.modificationCount
@@ -139,7 +160,7 @@ private class FirSessionWithModificationTracker(
val isValid: Boolean get() = !isInvalidated && modificationTracker.modificationCount == timeStamp 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 <reified T : KtModule> FirModuleData.moduleUnsafe(): T = (this as KtModuleBasedModuleData).module as T internal inline fun <reified T : KtModule> FirModuleData.moduleUnsafe(): T = (this as KtModuleBasedModuleData).module as T
internal inline fun <reified T : KtModule> FirModuleData.moduleInfoSafe(): T? = (this as KtModuleBasedModuleData).module as? T internal inline fun <reified T : KtModule> FirModuleData.moduleInfoSafe(): T? = (this as KtModuleBasedModuleData).module as? T
@@ -6,21 +6,14 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions
import com.intellij.openapi.project.Project 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.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.analysis.project.structure.KtSourceModule
import org.jetbrains.kotlin.fir.BuiltinTypes import org.jetbrains.kotlin.fir.BuiltinTypes
import org.jetbrains.kotlin.fir.PrivateSessionConstructor import org.jetbrains.kotlin.fir.PrivateSessionConstructor
@OptIn(PrivateSessionConstructor::class)
internal class FirIdeSourcesSession @PrivateSessionConstructor constructor( internal class FirIdeSourcesSession @PrivateSessionConstructor constructor(
override val module: KtSourceModule, override val module: KtSourceModule,
override val project: Project, override val project: Project,
val firFileBuilder: FirFileBuilder, override val firFileBuilder: FirFileBuilder,
builtinTypes: BuiltinTypes, builtinTypes: BuiltinTypes,
) : FirIdeModuleSession(builtinTypes, Kind.Source) { ) : LLFirResolvableModuleSession(builtinTypes)
val cache get() = firIdeProvider.cache
}
@@ -7,9 +7,9 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions
import org.jetbrains.kotlin.fir.FirSession 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) { fun invalidate(session: FirSession) {
require(session is FirIdeSourcesSession) require(session is LLFirResolvableModuleSession)
invalidateSourcesSession(session) invalidateSourcesSession(session)
} }
} }
@@ -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"
}
}
}
}
@@ -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
}
@@ -5,16 +5,17 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions 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 org.jetbrains.kotlin.analysis.project.structure.KtSourceModule
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
@JvmInline @JvmInline
internal value class LibrariesCache( internal value class LibrariesCache(
private val cache: ConcurrentHashMap<KtSourceModule, FirIdeLibrariesSession> = ConcurrentHashMap() private val cache: ConcurrentHashMap<KtModule, FirIdeLibrariesSession> = ConcurrentHashMap()
) { ) {
fun cached( fun cached(
moduleSourceInfo: KtSourceModule, module: KtModule,
create: (KtSourceModule) -> FirIdeLibrariesSession create: (KtModule) -> FirIdeLibrariesSession
): FirIdeLibrariesSession = ): FirIdeLibrariesSession =
cache.computeIfAbsent(moduleSourceInfo, create) cache.computeIfAbsent(module, create)
} }
@@ -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()
@@ -8,73 +8,25 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.state
import com.intellij.openapi.project.Project 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.DiagnosticCheckerFilter
import org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics.DiagnosticsCollector 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.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.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.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.KtLibraryModule
import org.jetbrains.kotlin.analysis.project.structure.KtModule import org.jetbrains.kotlin.analysis.project.structure.KtModule
import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule 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.diagnostics.KtPsiDiagnostic
import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.psi.KtFile
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.*
internal class FirSourceModuleResolveState( internal class FirSourceModuleResolveState(
override val project: Project, override val project: Project,
override val module: KtSourceModule, override val module: KtModule,
private val sessionProvider: FirIdeSessionProvider, sessionProvider: FirIdeSessionProvider,
val firFileBuilder: FirFileBuilder, firFileBuilder: FirFileBuilder,
val firLazyDeclarationResolver: FirLazyDeclarationResolver, firLazyDeclarationResolver: FirLazyDeclarationResolver,
) : FirPhysicalModuleResolveState() { ) : LLFirResolvableModuleResolveState(sessionProvider, firFileBuilder, firLazyDeclarationResolver) {
override val rootModuleSession: FirIdeSourcesSession get() = sessionProvider.rootModuleSession private val diagnosticsCollector = DiagnosticsCollector(fileStructureCache, cache)
/**
* 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 fun getDiagnostics(element: KtElement, filter: DiagnosticCheckerFilter): List<KtPsiDiagnostic> = override fun getDiagnostics(element: KtElement, filter: DiagnosticCheckerFilter): List<KtPsiDiagnostic> =
diagnosticsCollector.getDiagnosticsFor(element, filter) diagnosticsCollector.getDiagnosticsFor(element, filter)
@@ -82,70 +34,12 @@ internal class FirSourceModuleResolveState(
override fun collectDiagnosticsForFile(ktFile: KtFile, filter: DiagnosticCheckerFilter): Collection<KtPsiDiagnostic> = override fun collectDiagnosticsForFile(ktFile: KtFile, filter: DiagnosticCheckerFilter): Collection<KtPsiDiagnostic> =
diagnosticsCollector.collectDiagnosticsForFile(ktFile, filter) diagnosticsCollector.collectDiagnosticsForFile(ktFile, filter)
override fun resolveToFirSymbol( override fun getModuleKind(module: KtModule): ModuleKind {
ktDeclaration: KtDeclaration, return when (module) {
phase: FirResolvePhase is KtSourceModule -> ModuleKind.RESOLVABLE_MODULE
): FirBasedSymbol<*> { is KtLibraryModule -> ModuleKind.BINARY_MODULE
return when (val module = ktDeclaration.getKtModule()) { else -> unexpectedElementError("module", module)
is KtSourceModule -> findSourceFirSymbol(ktDeclaration).also { resolveFirToPhase(it.fir, phase) }
is KtLibraryModule -> findFirCompiledSymbol(ktDeclaration)
else -> error("unsupported 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,
)
}
} }
@@ -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<KtPsiDiagnostic> =
emptyList()
override fun collectDiagnosticsForFile(ktFile: KtFile, filter: DiagnosticCheckerFilter): Collection<KtPsiDiagnostic> =
emptyList()
override fun getModuleKind(module: KtModule): ModuleKind {
LLFirLibraryOrLibrarySourceResolvableModuleSession.checkIsValidKtModule(module)
return when {
module == this.module -> ModuleKind.RESOLVABLE_MODULE
else -> ModuleKind.BINARY_MODULE
}
}
}
@@ -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
}
}
@@ -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)
}
}
}
@@ -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"
}
}
}
@@ -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.expressions.impl.FirLazyExpression
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid 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.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.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.psi.KtFile
import org.jetbrains.kotlin.test.services.TestModuleStructure import org.jetbrains.kotlin.test.services.TestModuleStructure
import org.jetbrains.kotlin.test.services.TestServices import org.jetbrains.kotlin.test.services.TestServices
abstract class AbstractFirLazyBodiesCalculatorTest : AbstractLowLevelApiSingleFileTest() { abstract class AbstractFirLazyBodiesCalculatorTest : AbstractLowLevelApiSingleFileTest() {
private val lazyChecker = object : FirVisitorVoid() { private val lazyChecker = object : FirVisitorVoid() {
override fun visitElement(element: FirElement) { override fun visitElement(element: FirElement) {
TestCase.assertFalse("${FirLazyBlock::class.qualifiedName} should not present in the tree", element is FirLazyBlock) 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) { override fun doTestByFileStructure(ktFile: KtFile, moduleStructure: TestModuleStructure, testServices: TestServices) {
resolveWithClearCaches(ktFile) { resolveState -> resolveWithClearCaches(ktFile) { resolveState ->
val session = resolveState.rootModuleSession val session = resolveState.rootModuleSession
val provider = session.firIdeProvider.kotlinScopeProvider val provider = session.kotlinScopeProvider
val laziedFirFile = RawFirBuilder( val laziedFirFile = RawFirBuilder(
session, session,
@@ -59,5 +58,4 @@ abstract class AbstractFirLazyBodiesCalculatorTest : AbstractLowLevelApiSingleFi
TestCase.assertEquals(laziedFirFileDump, fullFirFileDump) TestCase.assertEquals(laziedFirFileDump, fullFirFileDump)
} }
} }
} }
@@ -43,7 +43,7 @@ abstract class AbstractFirContextCollectionTest : AbstractLowLevelApiSingleFileT
) { resolveState -> ) { resolveState ->
check(resolveState is FirSourceModuleResolveState) 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() val allStructureElements = fileStructure.getAllStructureElements()
handler.elementsToCheckContext = allStructureElements.map { it.getFirDeclaration() } handler.elementsToCheckContext = allStructureElements.map { it.getFirDeclaration() }
@@ -88,7 +88,7 @@ abstract class AbstractFileStructureTest : AbstractLowLevelApiSingleFileTest() {
val moduleResolveState = getResolveState() as FirSourceModuleResolveState val moduleResolveState = getResolveState() as FirSourceModuleResolveState
return moduleResolveState.fileStructureCache.getFileStructure( return moduleResolveState.fileStructureCache.getFileStructure(
ktFile = this, ktFile = this,
moduleFileCache = moduleResolveState.rootModuleSession.cache moduleFileCache = moduleResolveState.cache
) )
} }