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.types.KtSubstitutor
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LowLevelFirApiFacadeForResolveOnAir.getTowerContextProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirOfType
import org.jetbrains.kotlin.analysis.low.level.api.fir.resolver.ResolutionParameters
@@ -61,7 +60,7 @@ internal class KtFirCompletionCandidateChecker(
val file = originalFile.getOrBuildFirFile(firResolveState)
val explicitReceiverExpression = possibleExplicitReceiver?.getOrBuildFirOfType<FirExpression>(firResolveState)
val resolver = SingleCandidateResolver(firResolveState.rootModuleSession, file)
val implicitReceivers = getImplicitReceivers(nameExpression)
val implicitReceivers = getImplicitReceivers(originalFile, nameExpression)
for (implicitReceiverValue in implicitReceivers) {
val resolutionParameters = ResolutionParameters(
singleCandidateResolutionMode = SingleCandidateResolutionMode.CHECK_EXTENSION_FOR_COMPLETION,
@@ -84,8 +83,11 @@ internal class KtFirCompletionCandidateChecker(
return KtExtensionApplicabilityResult.NonApplicable(KtSubstitutor.Empty(token))
}
private fun getImplicitReceivers(fakeNameExpression: KtSimpleNameExpression): Sequence<ImplicitReceiverValue<*>?> {
val towerDataContext = analysisSession.firResolveState.getTowerContextProvider()
private fun getImplicitReceivers(
originalFile: KtFile,
fakeNameExpression: KtSimpleNameExpression
): Sequence<ImplicitReceiverValue<*>?> {
val towerDataContext = analysisSession.firResolveState.getTowerContextProvider(originalFile)
.getClosestAvailableParentContext(fakeNameExpression)
?: 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.withValidityAssertion
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LowLevelFirApiFacadeForResolveOnAir.getTowerContextProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.getElementTextInContext
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirClass
@@ -189,9 +188,8 @@ internal class KtFirScopeProvider(
originalFile: KtFile,
positionInFakeFile: KtElement
): KtScopeContext = withValidityAssertion {
val towerDataContext =
analysisSession.firResolveState.getTowerContextProvider().getClosestAvailableParentContext(positionInFakeFile)
analysisSession.firResolveState.getTowerContextProvider(originalFile).getClosestAvailableParentContext(positionInFakeFile)
?: error("Cannot find enclosing declaration for ${positionInFakeFile.getElementTextInContext()}")
val implicitReceivers = towerDataContext.nonLocalTowerDataElements.mapNotNull { it.implicitReceiver }.distinct()
@@ -20,7 +20,6 @@ import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.analysis.api.types.KtTypeNullability
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LowLevelFirApiFacadeForResolveOnAir.getTowerContextProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFir
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.throwUnexpectedFirElementError
import org.jetbrains.kotlin.fir.FirRenderer
@@ -28,7 +27,6 @@ import org.jetbrains.kotlin.fir.analysis.checkers.ConeTypeCompatibilityChecker
import org.jetbrains.kotlin.fir.analysis.checkers.ConeTypeCompatibilityChecker.isCompatible
import org.jetbrains.kotlin.fir.analysis.checkers.fullyExpandedClass
import org.jetbrains.kotlin.fir.analysis.checkers.typeParameterSymbols
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes
import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess
@@ -124,7 +122,7 @@ internal class KtFirTypeProvider(
}
override fun getImplicitReceiverTypesAtPosition(position: KtElement): List<KtType> {
return analysisSession.firResolveState.getTowerContextProvider()
return analysisSession.firResolveState.getTowerContextProvider(position.containingKtFile)
.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.sessions.FirIdeSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.FirIdeSessionProviderStorage
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.FirIdeSourcesSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirLibraryOrLibrarySourceResolvableModuleSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.FirSourceModuleResolveState
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirLibraryOrLibrarySourceResolvableModuleResolveState
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirResolvableModuleResolveState
import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule
import org.jetbrains.kotlin.analysis.project.structure.KtLibrarySourceModule
import org.jetbrains.kotlin.analysis.project.structure.KtModule
import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule
import org.jetbrains.kotlin.analysis.providers.createProjectWideOutOfBlockModificationTracker
@@ -27,10 +33,10 @@ internal class FirIdeResolveStateService(project: Project) {
project.createProjectWideOutOfBlockModificationTracker(),
ProjectRootModificationTracker.getInstance(project),
) {
ConcurrentHashMap<KtModule, FirSourceModuleResolveState>()
ConcurrentHashMap<KtModule, LLFirResolvableModuleResolveState>()
}
fun getResolveState(module: KtModule): FirSourceModuleResolveState =
fun getResolveState(module: KtModule): LLFirResolvableModuleResolveState =
stateCache.computeIfAbsent(module) { createResolveStateFor(module, sessionProviderStorage) }
companion object {
@@ -41,19 +47,34 @@ internal class FirIdeResolveStateService(project: Project) {
module: KtModule,
sessionProviderStorage: FirIdeSessionProviderStorage,
configureSession: (FirIdeSession.() -> Unit)? = null,
): FirSourceModuleResolveState {
if (module !is KtSourceModule) {
error("Creating FirModuleResolveState is not yet supported for $module")
}
): LLFirResolvableModuleResolveState {
val sessionProvider = sessionProviderStorage.getSessionProvider(module, configureSession)
val firFileBuilder = sessionProvider.rootModuleSession.firFileBuilder
return FirSourceModuleResolveState(
sessionProviderStorage.project,
module,
sessionProvider,
firFileBuilder,
FirLazyDeclarationResolver(firFileBuilder),
)
return when (module) {
is KtSourceModule -> {
val firFileBuilder = (sessionProvider.rootModuleSession as FirIdeSourcesSession).firFileBuilder
FirSourceModuleResolveState(
sessionProviderStorage.project,
module,
sessionProvider,
firFileBuilder,
FirLazyDeclarationResolver(firFileBuilder),
)
}
is KtLibraryModule, is KtLibrarySourceModule -> {
val firFileBuilder = (sessionProvider.rootModuleSession as LLFirLibraryOrLibrarySourceResolvableModuleSession).firFileBuilder
LLFirLibraryOrLibrarySourceResolvableModuleResolveState(
sessionProviderStorage.project,
module,
sessionProvider,
firFileBuilder,
FirLazyDeclarationResolver(firFileBuilder),
)
}
else -> {
error("Unexpected $module")
}
}
}
}
}
@@ -8,10 +8,13 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.DiagnosticCheckerFilter
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirModuleResolveState
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirElementBuilder
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirTowerContextProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.ModuleFileCache
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.KtToFirMapping
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.FirSourceModuleResolveState
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirResolvableModuleResolveState
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.TowerProviderForElementForState
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.containingKtFileIfAny
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.originalKtFile
import org.jetbrains.kotlin.analysis.project.structure.KtModule
@@ -28,35 +31,21 @@ import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtLambdaExpression
internal class FirModuleResolveStateDepended(
val originalState: FirSourceModuleResolveState,
val originalState: LLFirResolvableModuleResolveState,
val towerProviderBuiltUponElement: FirTowerContextProvider,
private val ktToFirMapping: KtToFirMapping?,
) : FirModuleResolveState() {
override val project: Project get() = originalState.project
override val module: KtModule get() = originalState.module
override val rootModuleSession get() = originalState.rootModuleSession
private val fileStructureCache get() = originalState.fileStructureCache
override fun getSessionFor(module: KtModule): FirSession =
originalState.getSessionFor(module)
override fun getOrBuildFirFor(element: KtElement): FirElement? {
val elementBuilder = originalState.elementBuilder
val psi = elementBuilder.getPsiAsFirElementSource(element) ?: return null
if (!elementBuilder.doKtElementHasCorrespondingFirElement(element)) return null
val psi = FirElementBuilder.getPsiAsFirElementSource(element) ?: return null
ktToFirMapping?.getFirOfClosestParent(psi, this)?.let { return it }
return elementBuilder.getOrBuildFirFor(
element = element,
firFileBuilder = originalState.firFileBuilder,
moduleFileCache = originalState.rootModuleSession.cache,
fileStructureCache = fileStructureCache,
firLazyDeclarationResolver = originalState.firLazyDeclarationResolver,
state = this,
)
return originalState.getOrBuildFirFor(element = element)
}
override fun getOrBuildFirFile(ktFile: KtFile): FirFile =
@@ -82,4 +71,7 @@ internal class FirModuleResolveStateDepended(
override fun resolveToFirSymbol(ktDeclaration: KtDeclaration, phase: FirResolvePhase): FirBasedSymbol<*> {
return originalState.resolveToFirSymbol(ktDeclaration, phase)
}
override fun getTowerContextProvider(ktFile: KtFile): FirTowerContextProvider =
TowerProviderForElementForState(this)
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.api
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirTowerContextProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.ModuleFileCache
import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule
import org.jetbrains.kotlin.analysis.project.structure.KtModule
@@ -56,4 +57,6 @@ abstract class FirModuleResolveState {
abstract fun resolveToFirSymbol(ktDeclaration: KtDeclaration, phase: FirResolvePhase): FirBasedSymbol<*>
internal abstract fun resolveFirToPhase(declaration: FirDeclaration, toPhase: FirResolvePhase)
abstract fun getTowerContextProvider(ktFile: KtFile): FirTowerContextProvider
}
@@ -10,7 +10,6 @@ import org.jetbrains.kotlin.analysis.api.impl.barebone.parentOfType
import org.jetbrains.kotlin.analysis.api.impl.barebone.parentsOfType
import org.jetbrains.kotlin.analysis.low.level.api.fir.DeclarationCopyBuilder.withBodyFrom
import org.jetbrains.kotlin.analysis.low.level.api.fir.FirModuleResolveStateDepended
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.FirSourceModuleResolveState
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FileTowerProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirTowerContextProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirTowerDataContextAllElementsCollector
@@ -18,8 +17,8 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.runCustomRes
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.FirElementsRecorder
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.KtToFirMapping
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.*
import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.firIdeProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.FirIdeSourcesSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirResolvableModuleSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirResolvableModuleResolveState
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.getElementTextInContext
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.originalDeclaration
import org.jetbrains.kotlin.analysis.project.structure.getKtModule
@@ -31,6 +30,7 @@ import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.transformers.FirTypeResolveTransformer
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirTowerDataContextCollector
import org.jetbrains.kotlin.fir.scopes.createImportingScopes
import org.jetbrains.kotlin.fir.scopes.kotlinScopeProvider
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
import org.jetbrains.kotlin.psi.*
@@ -67,7 +67,7 @@ object LowLevelFirApiFacadeForResolveOnAir {
place: T,
elementToResolve: T,
): FirElement {
require(state is FirSourceModuleResolveState)
require(state is LLFirResolvableModuleResolveState)
require(place.isPhysical)
val declaration = runBodyResolveOnAir(
@@ -95,7 +95,7 @@ object LowLevelFirApiFacadeForResolveOnAir {
state: FirModuleResolveState,
place: KtElement,
): FirTowerContextProvider {
require(state is FirSourceModuleResolveState)
require(state is LLFirResolvableModuleResolveState)
return if (place is KtFile) {
FileTowerProvider(place, onAirGetTowerContextForFile(state, place))
@@ -116,11 +116,11 @@ object LowLevelFirApiFacadeForResolveOnAir {
}
private fun onAirGetTowerContextForFile(
state: FirSourceModuleResolveState,
state: LLFirResolvableModuleResolveState,
file: KtFile,
): FirTowerDataContext {
require(file.isPhysical)
val session = state.getSessionFor(file.getKtModule(state.project)) as FirIdeSourcesSession
val session = state.getSessionFor(file.getKtModule(state.project)) as LLFirResolvableModuleSession
val firFile = session.firFileBuilder.buildRawFirFileWithCaching(
ktFile = file,
@@ -144,7 +144,7 @@ object LowLevelFirApiFacadeForResolveOnAir {
originalKtFile: KtFile,
elementToAnalyze: KtElement
): FirModuleResolveState {
require(originalState is FirSourceModuleResolveState)
require(originalState is LLFirResolvableModuleResolveState)
require(elementToAnalyze !is KtFile) { "KtFile for dependency element not supported" }
require(!elementToAnalyze.isPhysical) { "Depended state should be build only for non-physical elements" }
@@ -178,21 +178,21 @@ object LowLevelFirApiFacadeForResolveOnAir {
private fun tryResolveAsFileAnnotation(
annotationEntry: KtAnnotationEntry,
state: FirSourceModuleResolveState,
state: LLFirResolvableModuleResolveState,
replacement: RawFirReplacement,
firFile: FirFile,
collector: FirTowerDataContextCollector? = null,
): FirAnnotation {
val annotationCall = buildFileFirAnnotation(
session = firFile.moduleData.session,
baseScopeProvider = firFile.moduleData.session.firIdeProvider.kotlinScopeProvider,
baseScopeProvider = firFile.moduleData.session.kotlinScopeProvider,
fileAnnotation = annotationEntry,
replacement = replacement
)
state.firLazyDeclarationResolver.resolveFileAnnotations(
firFile = firFile,
annotations = listOf(annotationCall),
moduleFileCache = state.rootModuleSession.cache,
moduleFileCache = state.cache,
scopeSession = ScopeSession(),
checkPCE = true,
collector = collector
@@ -202,7 +202,7 @@ object LowLevelFirApiFacadeForResolveOnAir {
}
private fun runBodyResolveOnAir(
state: FirSourceModuleResolveState,
state: LLFirResolvableModuleResolveState,
replacement: RawFirReplacement,
onAirCreatedDeclaration: Boolean,
collector: FirTowerDataContextCollector? = null,
@@ -233,7 +233,7 @@ object LowLevelFirApiFacadeForResolveOnAir {
val newDeclarationWithReplacement = RawFirNonLocalDeclarationBuilder.buildWithReplacement(
session = originalDeclaration.moduleData.session,
scopeProvider = originalDeclaration.moduleData.session.firIdeProvider.kotlinScopeProvider,
scopeProvider = originalDeclaration.moduleData.session.kotlinScopeProvider,
designation = originalDesignation,
rootNonLocalDeclaration = nonLocalDeclaration,
replacement = replacement,
@@ -241,7 +241,7 @@ object LowLevelFirApiFacadeForResolveOnAir {
val isInBodyReplacement = isInBodyReplacement(nonLocalDeclaration, replacement)
return state.rootModuleSession.cache.firFileLockProvider.runCustomResolveUnderLock(originalFirFile, true) {
return state.cache.firFileLockProvider.runCustomResolveUnderLock(originalFirFile, true) {
val copiedFirDeclaration = if (isInBodyReplacement) {
when (originalDeclaration) {
is FirSimpleFunction ->
@@ -263,7 +263,7 @@ object LowLevelFirApiFacadeForResolveOnAir {
ResolveTreeBuilder.resolveEnsure(onAirDesignation.declaration, FirResolvePhase.BODY_RESOLVE) {
state.firLazyDeclarationResolver.runLazyDesignatedOnAirResolveToBodyWithoutLock(
designation = onAirDesignation,
moduleFileCache = state.rootModuleSession.cache,
moduleFileCache = state.cache,
checkPCE = true,
onAirCreatedDeclaration = onAirCreatedDeclaration,
towerDataContextCollector = collector,
@@ -299,16 +299,16 @@ object LowLevelFirApiFacadeForResolveOnAir {
fun onAirResolveTypeInPlace(
place: KtElement,
typeReference: KtTypeReference,
state: FirModuleResolveState
state: FirModuleResolveState,
): FirResolvedTypeRef {
val context = state.getTowerContextProvider().getClosestAvailableParentContext(place)
val context = state.getTowerContextProvider(place.containingKtFile).getClosestAvailableParentContext(place)
?: error("TowerContext not found for ${place.getElementTextInContext()}")
val session = state.rootModuleSession
val firTypeReference = buildFirUserTypeRef(
typeReference = typeReference,
session = session,
baseScopeProvider = session.firIdeProvider.kotlinScopeProvider
baseScopeProvider = session.kotlinScopeProvider
)
return FirTypeResolveTransformer(
@@ -317,18 +317,4 @@ object LowLevelFirApiFacadeForResolveOnAir {
initialScopes = context.towerDataElements.asReversed().mapNotNull { it.scope }
).transformTypeRef(firTypeReference, null)
}
private class TowerProviderForElementForState(private val state: FirModuleResolveState) : FirTowerContextProvider {
override fun getClosestAvailableParentContext(ktElement: KtElement): FirTowerDataContext? {
return if (state is FirModuleResolveStateDepended) {
state.towerProviderBuiltUponElement.getClosestAvailableParentContext(ktElement)
?: onAirGetTowerContextProvider(state.originalState, ktElement).getClosestAvailableParentContext(ktElement)
} else {
onAirGetTowerContextProvider(state, ktElement).getClosestAvailableParentContext(ktElement)
}
}
}
fun FirModuleResolveState.getTowerContextProvider(): FirTowerContextProvider =
TowerProviderForElementForState(this)
}
@@ -32,29 +32,32 @@ import org.jetbrains.kotlin.psi2ir.deparenthesize
*/
@ThreadSafe
internal class FirElementBuilder {
fun getPsiAsFirElementSource(element: KtElement): KtElement? {
val deparenthesized = if (element is KtPropertyDelegate) element.deparenthesize() else element
return when {
deparenthesized is KtParenthesizedExpression -> deparenthesized.deparenthesize()
deparenthesized is KtPropertyDelegate -> deparenthesized.expression ?: element
deparenthesized is KtQualifiedExpression && deparenthesized.selectorExpression is KtCallExpression -> {
/*
KtQualifiedExpression with KtCallExpression in selector transformed in FIR to FirFunctionCall expression
Which will have a receiver as qualifier
*/
deparenthesized.selectorExpression ?: error("Incomplete code:\n${element.getElementTextInContext()}")
companion object {
fun getPsiAsFirElementSource(element: KtElement): KtElement? {
val deparenthesized = if (element is KtPropertyDelegate) element.deparenthesize() else element
return when {
deparenthesized is KtParenthesizedExpression -> deparenthesized.deparenthesize()
deparenthesized is KtPropertyDelegate -> deparenthesized.expression ?: element
deparenthesized is KtQualifiedExpression && deparenthesized.selectorExpression is KtCallExpression -> {
/*
KtQualifiedExpression with KtCallExpression in selector transformed in FIR to FirFunctionCall expression
Which will have a receiver as qualifier
*/
deparenthesized.selectorExpression ?: error("Incomplete code:\n${element.getElementTextInContext()}")
}
deparenthesized is KtValueArgument -> {
// null will be return in case of invalid KtValueArgument
deparenthesized.getArgumentExpression()
}
deparenthesized is KtObjectLiteralExpression -> deparenthesized.objectDeclaration
deparenthesized is KtStringTemplateEntryWithExpression -> deparenthesized.expression
deparenthesized is KtUserType && deparenthesized.parent is KtNullableType -> deparenthesized.parent as KtNullableType
else -> deparenthesized
}
deparenthesized is KtValueArgument -> {
// null will be return in case of invalid KtValueArgument
deparenthesized.getArgumentExpression()
}
deparenthesized is KtObjectLiteralExpression -> deparenthesized.objectDeclaration
deparenthesized is KtStringTemplateEntryWithExpression -> deparenthesized.expression
deparenthesized is KtUserType && deparenthesized.parent is KtNullableType -> deparenthesized.parent as KtNullableType
else -> deparenthesized
}
}
fun doKtElementHasCorrespondingFirElement(ktElement: KtElement): Boolean = when (ktElement) {
is KtImportList -> false
else -> true
@@ -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.ModuleFileCache
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.FirLazyDeclarationResolver
import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.firIdeProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.FirIdeProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.findSourceNonLocalFirDeclaration
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.getElementTextInContext
import org.jetbrains.kotlin.diagnostics.KtPsiDiagnostic
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
import org.jetbrains.kotlin.psi.*
import java.util.concurrent.ConcurrentHashMap
@@ -40,7 +41,7 @@ internal class FileStructure private constructor(
}
}
private val firIdeProvider = firFile.moduleData.session.firIdeProvider
private val firProvider = firFile.moduleData.session.firProvider
private val structureElements = ConcurrentHashMap<KtAnnotated, FileStructureElement>()
@@ -59,7 +60,6 @@ internal class FileStructure private constructor(
newKtDeclaration = declaration as KtDeclaration,
cache = moduleFileCache,
firLazyDeclarationResolver = firLazyDeclarationResolver,
firIdeProvider = firIdeProvider,
)
}
else -> structureElement
@@ -112,7 +112,7 @@ internal class FileStructure private constructor(
private fun createDeclarationStructure(declaration: KtDeclaration): FileStructureElement {
val firDeclaration = declaration.findSourceNonLocalFirDeclaration(
firFileBuilder,
firIdeProvider.symbolProvider,
firProvider.symbolProvider,
moduleFileCache,
firFile
)
@@ -18,11 +18,12 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.FirLazyDecla
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.RawFirNonLocalDeclarationBuilder
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.declarationCanBeLazilyResolved
import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.FirIdeProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.firIdeProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirResolvableModuleResolveState
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.scopes.kotlinScopeProvider
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
@@ -36,12 +37,10 @@ internal sealed class FileStructureElement(val firFile: FirFile, protected val l
}
internal class KtToFirMapping(firElement: FirElement, recorder: FirElementsRecorder) {
private val mapping = FirElementsRecorder.recordElementsFrom(firElement, recorder)
private val userTypeMapping = ConcurrentHashMap<KtUserType, FirElement>()
fun getElement(ktElement: KtElement, state: FirModuleResolveState): FirElement? {
fun getElement(ktElement: KtElement, state: FirModuleResolveState): FirElement? {
mapping[ktElement]?.let { return it }
val userType = when (ktElement) {
@@ -87,7 +86,6 @@ internal sealed class ReanalyzableStructureElement<KT : KtDeclaration, S : FirBa
newKtDeclaration: KT,
cache: ModuleFileCache,
firLazyDeclarationResolver: FirLazyDeclarationResolver,
firIdeProvider: FirIdeProvider,
): ReanalyzableStructureElement<KT, S>
fun isUpToDate(): Boolean = psi.getModificationStamp() == timestamp
@@ -116,20 +114,18 @@ internal class ReanalyzableFunctionStructureElement(
newKtDeclaration: KtNamedFunction,
cache: ModuleFileCache,
firLazyDeclarationResolver: FirLazyDeclarationResolver,
firIdeProvider: FirIdeProvider,
): ReanalyzableFunctionStructureElement {
val originalFunction = firSymbol.fir as FirSimpleFunction
val designation = originalFunction.collectDesignation()
val temporaryFunction = RawFirNonLocalDeclarationBuilder.buildWithFunctionSymbolRebind(
session = originalFunction.moduleData.session,
scopeProvider = originalFunction.moduleData.session.firIdeProvider.kotlinScopeProvider,
scopeProvider = originalFunction.moduleData.session.kotlinScopeProvider,
designation = designation,
rootNonLocalDeclaration = newKtDeclaration,
) as FirSimpleFunction
return cache.firFileLockProvider.withWriteLock(firFile) {
val upgradedPhase = minOf(originalFunction.resolvePhase, FirResolvePhase.DECLARATIONS)
with(originalFunction) {
replaceBody(temporaryFunction.body)
@@ -172,14 +168,13 @@ internal class ReanalyzablePropertyStructureElement(
newKtDeclaration: KtProperty,
cache: ModuleFileCache,
firLazyDeclarationResolver: FirLazyDeclarationResolver,
firIdeProvider: FirIdeProvider,
): ReanalyzablePropertyStructureElement {
val originalProperty = firSymbol.fir
val designation = originalProperty.collectDesignation()
val temporaryProperty = RawFirNonLocalDeclarationBuilder.buildWithFunctionSymbolRebind(
session = originalProperty.moduleData.session,
scopeProvider = originalProperty.moduleData.session.firIdeProvider.kotlinScopeProvider,
scopeProvider = originalProperty.moduleData.session.kotlinScopeProvider,
designation = designation,
rootNonLocalDeclaration = newKtDeclaration,
) as FirProperty
@@ -9,7 +9,6 @@ import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toPersistentList
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDeclarationDesignation
import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.firIdeProvider
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.getExplicitBackingField
@@ -18,6 +17,7 @@ import org.jetbrains.kotlin.fir.expressions.FirWrappedDelegateExpression
import org.jetbrains.kotlin.fir.expressions.impl.FirLazyBlock
import org.jetbrains.kotlin.fir.expressions.impl.FirLazyExpression
import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.scopes.kotlinScopeProvider
import org.jetbrains.kotlin.fir.visitors.FirTransformer
import org.jetbrains.kotlin.fir.visitors.transformSingle
import org.jetbrains.kotlin.psi.KtNamedFunction
@@ -41,7 +41,7 @@ internal object FirLazyBodiesCalculator {
if (simpleFunction.body !is FirLazyBlock) return
val newFunction = RawFirNonLocalDeclarationBuilder.buildWithFunctionSymbolRebind(
session = simpleFunction.moduleData.session,
scopeProvider = simpleFunction.moduleData.session.firIdeProvider.kotlinScopeProvider,
scopeProvider = simpleFunction.moduleData.session.kotlinScopeProvider,
designation = designation,
rootNonLocalDeclaration = simpleFunction.psi as KtNamedFunction,
) as FirSimpleFunction
@@ -58,7 +58,7 @@ internal object FirLazyBodiesCalculator {
val newFunction = RawFirNonLocalDeclarationBuilder.buildWithFunctionSymbolRebind(
session = secondaryConstructor.moduleData.session,
scopeProvider = secondaryConstructor.moduleData.session.firIdeProvider.kotlinScopeProvider,
scopeProvider = secondaryConstructor.moduleData.session.kotlinScopeProvider,
designation = designation,
rootNonLocalDeclaration = secondaryConstructor.psi as KtSecondaryConstructor,
) as FirSimpleFunction
@@ -74,7 +74,7 @@ internal object FirLazyBodiesCalculator {
val newProperty = RawFirNonLocalDeclarationBuilder.buildWithFunctionSymbolRebind(
session = firProperty.moduleData.session,
scopeProvider = firProperty.moduleData.session.firIdeProvider.kotlinScopeProvider,
scopeProvider = firProperty.moduleData.session.kotlinScopeProvider,
designation = designation,
rootNonLocalDeclaration = firProperty.psi as KtProperty
) as FirProperty
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.getNonLoc
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.FirFileBuilder
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.ModuleFileCache
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.runCustomResolveUnderLock
import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.firIdeProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.FirFileAnnotationsResolveTransformer
import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.FirProviderInterceptorForIDE
import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.LazyTransformerFactory
@@ -114,6 +113,7 @@ internal class FirLazyDeclarationResolver(private val firFileBuilder: FirFileBui
moduleFileCache: ModuleFileCache,
toPhase: FirResolvePhase,
scopeSession: ScopeSession,
collector: FirTowerDataContextCollector? = null,
checkPCE: Boolean = false,
) {
if (toPhase == FirResolvePhase.RAW_FIR) return
@@ -126,6 +126,7 @@ internal class FirLazyDeclarationResolver(private val firFileBuilder: FirFileBui
firFile = firFile,
moduleFileCache = moduleFileCache,
toPhase = toPhase,
collector = collector,
scopeSession = scopeSession,
checkPCE = checkPCE,
)
@@ -185,7 +186,7 @@ internal class FirLazyDeclarationResolver(private val firFileBuilder: FirFileBui
scopeSession = scopeSession,
moduleFileCache = moduleFileCache,
lazyDeclarationResolver = this,
towerDataContextCollector = null,
towerDataContextCollector = collector,
firProviderInterceptor = null,
checkPCE = checkPCE,
)
@@ -298,14 +299,14 @@ internal class FirLazyDeclarationResolver(private val firFileBuilder: FirFileBui
declarationToResolve = enumEntry.findSourceNonLocalFirDeclaration(
firFileBuilder,
firDeclarationToResolve.moduleData.session.firIdeProvider.symbolProvider,
firDeclarationToResolve.moduleData.session.firProvider.symbolProvider,
moduleFileCache
)
neededPhase = FirResolvePhase.BODY_RESOLVE
} else {
declarationToResolve = nonLocalDeclaration.findSourceNonLocalFirDeclaration(
firFileBuilder,
firDeclarationToResolve.moduleData.session.firIdeProvider.symbolProvider,
firDeclarationToResolve.moduleData.session.firProvider.symbolProvider,
moduleFileCache
)
neededPhase = toPhase
@@ -30,3 +30,4 @@ internal class 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
import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.ProjectScope
import org.jetbrains.kotlin.analysis.low.level.api.fir.FirPhaseRunner
import org.jetbrains.kotlin.analysis.low.level.api.fir.IdeFirPhaseManager
import org.jetbrains.kotlin.analysis.low.level.api.fir.IdeSessionComponents
@@ -60,12 +62,12 @@ internal object FirIdeSessionFactory {
firPhaseRunner: FirPhaseRunner,
sessionInvalidator: FirSessionInvalidator,
builtinTypes: BuiltinTypes,
sessionsCache: MutableMap<KtSourceModule, FirIdeSourcesSession>,
sessionsCache: MutableMap<KtModule, LLFirResolvableModuleSession>,
isRootModule: Boolean,
librariesCache: LibrariesCache,
configureSession: (FirIdeSession.() -> Unit)? = null
): FirIdeSourcesSession {
sessionsCache[module]?.let { return it }
sessionsCache[module]?.let { return it as FirIdeSourcesSession }
val languageVersionSettings = module.languageVersionSettings
val scopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped)
val firBuilder = FirFileBuilder(scopeProvider, firPhaseRunner)
@@ -211,7 +213,7 @@ internal object FirIdeSessionFactory {
}
}
private fun createModuleDataProvider(sourceModule: KtSourceModule, session: FirIdeSession): ModuleDataProvider {
private fun createModuleDataProvider(sourceModule: KtModule, session: FirIdeSession): ModuleDataProvider {
val dependencyList = DependencyListForCliModule.build(
Name.special("<${sourceModule.moduleDescription}>"),
sourceModule.platform,
@@ -264,6 +266,113 @@ internal object FirIdeSessionFactory {
}
}
fun creatLibraryOrLibrarySourceResolvableSession(
project: Project,
module: KtModule,
builtinsAndCloneableSession: FirIdeBuiltinsAndCloneableSession,
firPhaseRunner: FirPhaseRunner,
sessionInvalidator: FirSessionInvalidator,
builtinTypes: BuiltinTypes,
sessionsCache: MutableMap<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) {
register(IdeSessionComponents::class, IdeSessionComponents.create(this))
register(FirCachesFactory::class, FirThreadSafeCachesFactory)
@@ -17,8 +17,8 @@ import org.jetbrains.kotlin.fir.FirSessionProvider
@Immutable
class FirIdeSessionProvider internal constructor(
val project: Project,
internal val rootModuleSession: FirIdeSourcesSession,
val sessions: Map<KtSourceModule, FirIdeSession>
internal val rootModuleSession: LLFirResolvableModuleSession,
val sessions: Map<KtModule, LLFirResolvableModuleSession>
) : FirSessionProvider() {
override fun getSession(moduleData: FirModuleData): FirSession? =
sessions[moduleData.module]
@@ -26,6 +26,6 @@ class FirIdeSessionProvider internal constructor(
fun getSession(module: KtModule): FirSession? =
sessions[module]
internal fun getModuleCache(module: KtSourceModule): ModuleFileCache =
(sessions.getValue(module) as FirIdeSourcesSession).cache
internal fun getModuleCache(module: KtModule): ModuleFileCache =
sessions.getValue(module).cache
}
@@ -6,51 +6,71 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.ModificationTracker
import kotlinx.collections.immutable.PersistentMap
import kotlinx.collections.immutable.persistentMapOf
import kotlinx.collections.immutable.toPersistentMap
import org.jetbrains.kotlin.analysis.providers.createLibrariesModificationTracker
import org.jetbrains.kotlin.analysis.providers.createModuleWithoutDependenciesOutOfBlockModificationTracker
import org.jetbrains.kotlin.fir.BuiltinTypes
import org.jetbrains.kotlin.fir.FirModuleData
import org.jetbrains.kotlin.fir.moduleData
import org.jetbrains.kotlin.analysis.low.level.api.fir.FirPhaseRunner
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.addValueFor
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.executeWithoutPCE
import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule
import org.jetbrains.kotlin.analysis.project.structure.KtLibrarySourceModule
import org.jetbrains.kotlin.analysis.project.structure.KtModule
import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule
import org.jetbrains.kotlin.analysis.utils.caches.*
import org.jetbrains.kotlin.analysis.providers.createLibrariesModificationTracker
import org.jetbrains.kotlin.analysis.providers.createModuleWithoutDependenciesOutOfBlockModificationTracker
import org.jetbrains.kotlin.analysis.utils.caches.getValue
import org.jetbrains.kotlin.analysis.utils.caches.softCachedValue
import org.jetbrains.kotlin.fir.BuiltinTypes
import org.jetbrains.kotlin.fir.FirModuleData
import org.jetbrains.kotlin.fir.moduleData
import java.util.concurrent.ConcurrentHashMap
class FirIdeSessionProviderStorage(val project: Project) {
private val sessionsCache = ConcurrentHashMap<KtSourceModule, FromModuleViewSessionCache>()
private val sessionsCache = ConcurrentHashMap<KtModule, FromModuleViewSessionCache>()
private val librariesCache by softCachedValue(project, project.createLibrariesModificationTracker()) { LibrariesCache() }
fun getSessionProvider(
rootModule: KtSourceModule,
rootModule: KtModule,
configureSession: (FirIdeSession.() -> Unit)? = null
): FirIdeSessionProvider {
val firPhaseRunner = FirPhaseRunner()
val builtinTypes = BuiltinTypes()
val builtinsAndCloneableSession = FirIdeSessionFactory.createBuiltinsAndCloneableSession(project, builtinTypes)
val cache = sessionsCache.getOrPut(rootModule) { FromModuleViewSessionCache(rootModule) }
val cache = sessionsCache.getOrPut(rootModule) { FromModuleViewSessionCache() }
val (sessions, session) = cache.withMappings(project) { mappings ->
val sessions = mutableMapOf<KtSourceModule, FirIdeSourcesSession>().apply { putAll(mappings) }
val sessions = mutableMapOf<KtModule, LLFirResolvableModuleSession>().apply { putAll(mappings) }
val session = executeWithoutPCE {
FirIdeSessionFactory.createSourcesSession(
project,
rootModule,
builtinsAndCloneableSession,
firPhaseRunner,
cache.sessionInvalidator,
builtinTypes,
sessions,
isRootModule = true,
librariesCache = librariesCache,
configureSession = configureSession,
)
when (rootModule) {
is KtSourceModule -> {
FirIdeSessionFactory.createSourcesSession(
project,
rootModule,
builtinsAndCloneableSession,
firPhaseRunner,
cache.sessionInvalidator,
builtinTypes,
sessions,
isRootModule = true,
librariesCache = librariesCache,
configureSession = configureSession,
)
}
is KtLibraryModule, is KtLibrarySourceModule -> FirIdeSessionFactory.creatLibraryOrLibrarySourceResolvableSession(
project,
rootModule,
builtinsAndCloneableSession,
firPhaseRunner,
cache.sessionInvalidator,
builtinTypes,
sessions,
configureSession = configureSession,
)
else -> error("Unexpected ${rootModule::class.simpleName}")
}
}
sessions to session
}
@@ -59,11 +79,9 @@ class FirIdeSessionProviderStorage(val project: Project) {
}
}
private class FromModuleViewSessionCache(
val root: KtSourceModule,
) {
private class FromModuleViewSessionCache {
@Volatile
private var mappings: PersistentMap<KtSourceModule, FirSessionWithModificationTracker> = persistentMapOf()
private var mappings: PersistentMap<KtModule, FirSessionWithModificationTracker> = persistentMapOf()
val sessionInvalidator: FirSessionInvalidator = FirSessionInvalidator { session ->
mappings[session.moduleData.module]?.invalidate()
@@ -72,15 +90,15 @@ private class FromModuleViewSessionCache(
inline fun <R> withMappings(
project: Project,
action: (Map<KtSourceModule, FirIdeSourcesSession>) -> Pair<Map<KtSourceModule, FirIdeSourcesSession>, R>
): Pair<Map<KtSourceModule, FirIdeSourcesSession>, R> {
action: (Map<KtModule, LLFirResolvableModuleSession>) -> Pair<Map<KtModule, LLFirResolvableModuleSession>, R>
): Pair<Map<KtModule, LLFirResolvableModuleSession>, R> {
val (newMappings, result) = action(getSessions().mapValues { it.value })
mappings = newMappings.mapValues { FirSessionWithModificationTracker(project, it.value) }.toPersistentMap()
return newMappings to result
}
@OptIn(ExperimentalStdlibApi::class)
private fun getSessions(): Map<KtSourceModule, FirIdeSourcesSession> = buildMap {
private fun getSessions(): Map<KtModule, LLFirResolvableModuleSession> = buildMap {
val sessions = mappings.values
val wasSessionInvalidated = sessions.associateWithTo(hashMapOf()) { false }
@@ -122,10 +140,13 @@ private class FromModuleViewSessionCache(
private class FirSessionWithModificationTracker(
project: Project,
val firSession: FirIdeSourcesSession,
val firSession: LLFirResolvableModuleSession,
) {
private val modificationTracker =
firSession.moduleData.module.createModuleWithoutDependenciesOutOfBlockModificationTracker(project)
when (val moduleInfo = firSession.moduleData.module) {
is KtSourceModule -> moduleInfo.createModuleWithoutDependenciesOutOfBlockModificationTracker(project)
else -> ModificationTracker.NEVER_CHANGED
}
private val timeStamp = modificationTracker.modificationCount
@@ -139,7 +160,7 @@ private class FirSessionWithModificationTracker(
val isValid: Boolean get() = !isInvalidated && modificationTracker.modificationCount == timeStamp
}
internal val FirModuleData.module: KtSourceModule get() = moduleUnsafe()
internal val FirModuleData.module: KtModule get() = moduleUnsafe()
internal inline fun <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
@@ -6,21 +6,14 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions
import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.FirFileBuilder
import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.firIdeProvider
import org.jetbrains.kotlin.analysis.project.structure.KtModule
import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule
import org.jetbrains.kotlin.fir.BuiltinTypes
import org.jetbrains.kotlin.fir.PrivateSessionConstructor
@OptIn(PrivateSessionConstructor::class)
internal class FirIdeSourcesSession @PrivateSessionConstructor constructor(
override val module: KtSourceModule,
override val project: Project,
val firFileBuilder: FirFileBuilder,
override val firFileBuilder: FirFileBuilder,
builtinTypes: BuiltinTypes,
) : FirIdeModuleSession(builtinTypes, Kind.Source) {
val cache get() = firIdeProvider.cache
}
) : LLFirResolvableModuleSession(builtinTypes)
@@ -7,9 +7,9 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions
import org.jetbrains.kotlin.fir.FirSession
internal class FirSessionInvalidator(private val invalidateSourcesSession: (FirIdeSourcesSession) -> Unit) {
internal class FirSessionInvalidator(private val invalidateSourcesSession: (LLFirResolvableModuleSession) -> Unit) {
fun invalidate(session: FirSession) {
require(session is FirIdeSourcesSession)
require(session is LLFirResolvableModuleSession)
invalidateSourcesSession(session)
}
}
@@ -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
import org.jetbrains.kotlin.analysis.project.structure.KtModule
import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule
import java.util.concurrent.ConcurrentHashMap
@JvmInline
internal value class LibrariesCache(
private val cache: ConcurrentHashMap<KtSourceModule, FirIdeLibrariesSession> = ConcurrentHashMap()
private val cache: ConcurrentHashMap<KtModule, FirIdeLibrariesSession> = ConcurrentHashMap()
) {
fun cached(
moduleSourceInfo: KtSourceModule,
create: (KtSourceModule) -> FirIdeLibrariesSession
module: KtModule,
create: (KtModule) -> 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 org.jetbrains.kotlin.analysis.low.level.api.fir.api.DiagnosticCheckerFilter
import org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics.DiagnosticsCollector
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirElementBuilder
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.getNonLocalContainingOrThisDeclaration
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.FirFileBuilder
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.ModuleFileCache
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.FileStructureCache
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.FirLazyDeclarationResolver
import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.firIdeProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.FirIdeSessionProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.FirIdeSourcesSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.FirDeclarationForCompiledElementSearcher
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.findSourceNonLocalFirDeclaration
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.getElementTextInContext
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.originalDeclaration
import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule
import org.jetbrains.kotlin.analysis.project.structure.KtModule
import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule
import org.jetbrains.kotlin.analysis.project.structure.getKtModule
import org.jetbrains.kotlin.analysis.utils.errors.unexpectedElementError
import org.jetbrains.kotlin.diagnostics.KtPsiDiagnostic
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.expressions.FirAnonymousFunctionExpression
import org.jetbrains.kotlin.fir.expressions.FirAnonymousObjectExpression
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
internal class FirSourceModuleResolveState(
override val project: Project,
override val module: KtSourceModule,
private val sessionProvider: FirIdeSessionProvider,
val firFileBuilder: FirFileBuilder,
val firLazyDeclarationResolver: FirLazyDeclarationResolver,
) : FirPhysicalModuleResolveState() {
override val rootModuleSession: FirIdeSourcesSession get() = sessionProvider.rootModuleSession
/**
* WARNING! This object contains scopes for all statements and declarations that were ever resolved.
* It can grow unbounded if you never edit the files in the opened project.
*
* It is a temporary solution until we can retrieve scopes for any fir element without re-resolving it.
*/
val fileStructureCache = FileStructureCache(firFileBuilder, firLazyDeclarationResolver)
val elementBuilder = FirElementBuilder()
private val diagnosticsCollector = DiagnosticsCollector(fileStructureCache, rootModuleSession.cache)
override fun getSessionFor(module: KtModule): FirSession =
sessionProvider.getSession(module)!!
override fun getOrBuildFirFor(element: KtElement): FirElement? =
elementBuilder.getOrBuildFirFor(
element = element,
firFileBuilder = firFileBuilder,
moduleFileCache = rootModuleSession.cache,
fileStructureCache = fileStructureCache,
firLazyDeclarationResolver = firLazyDeclarationResolver,
state = this
)
override fun getOrBuildFirFile(ktFile: KtFile): FirFile =
firFileBuilder.buildRawFirFileWithCaching(ktFile, rootModuleSession.cache)
override fun tryGetCachedFirFile(declaration: FirDeclaration, cache: ModuleFileCache): FirFile? =
cache.getContainerFirFile(declaration)
override val module: KtModule,
sessionProvider: FirIdeSessionProvider,
firFileBuilder: FirFileBuilder,
firLazyDeclarationResolver: FirLazyDeclarationResolver,
) : LLFirResolvableModuleResolveState(sessionProvider, firFileBuilder, firLazyDeclarationResolver) {
private val diagnosticsCollector = DiagnosticsCollector(fileStructureCache, cache)
override fun getDiagnostics(element: KtElement, filter: DiagnosticCheckerFilter): List<KtPsiDiagnostic> =
diagnosticsCollector.getDiagnosticsFor(element, filter)
@@ -82,70 +34,12 @@ internal class FirSourceModuleResolveState(
override fun collectDiagnosticsForFile(ktFile: KtFile, filter: DiagnosticCheckerFilter): Collection<KtPsiDiagnostic> =
diagnosticsCollector.collectDiagnosticsForFile(ktFile, filter)
override fun resolveToFirSymbol(
ktDeclaration: KtDeclaration,
phase: FirResolvePhase
): FirBasedSymbol<*> {
return when (val module = ktDeclaration.getKtModule()) {
is KtSourceModule -> findSourceFirSymbol(ktDeclaration).also { resolveFirToPhase(it.fir, phase) }
is KtLibraryModule -> findFirCompiledSymbol(ktDeclaration)
else -> error("unsupported module $module")
override fun getModuleKind(module: KtModule): ModuleKind {
return when (module) {
is KtSourceModule -> ModuleKind.RESOLVABLE_MODULE
is KtLibraryModule -> ModuleKind.BINARY_MODULE
else -> unexpectedElementError("module", module)
}
}
private fun findSourceFirSymbol(ktDeclaration: KtDeclaration): FirBasedSymbol<*> {
return findSourceFirDeclarationByExpression(ktDeclaration.originalDeclaration ?: ktDeclaration).symbol
}
private fun findFirCompiledSymbol(ktDeclaration: KtDeclaration): FirBasedSymbol<*> {
require(ktDeclaration.containingKtFile.isCompiled) {
"This method will only work on compiled declarations, but this declaration is not compiled: ${ktDeclaration.getElementTextInContext()}"
}
val searcher = FirDeclarationForCompiledElementSearcher(rootModuleSession.symbolProvider)
val firDeclaration = searcher.findNonLocalDeclaration(ktDeclaration)
return firDeclaration.symbol
}
/**
* [ktDeclaration] should be either [KtDeclaration] or [KtLambdaExpression]
*/
private fun findSourceFirDeclarationByExpression(ktDeclaration: KtExpression): FirDeclaration {
val module = ktDeclaration.getKtModule(project)
require(module is KtSourceModule) {
"Declaration should have ModuleSourceInfo, instead it had ${module::class}"
}
val nonLocalNamedDeclaration = ktDeclaration.getNonLocalContainingOrThisDeclaration()
?: error("Declaration should have non-local container${ktDeclaration.getElementTextInContext()}")
if (ktDeclaration == nonLocalNamedDeclaration) {
return nonLocalNamedDeclaration.findSourceNonLocalFirDeclaration(
firFileBuilder = firFileBuilder,
firSymbolProvider = rootModuleSession.firIdeProvider.symbolProvider,
moduleFileCache = sessionProvider.getModuleCache(module)
)
}
return when (val localFirElement = getOrBuildFirFor(ktDeclaration)) {
is FirDeclaration -> localFirElement
is FirAnonymousFunctionExpression -> localFirElement.anonymousFunction
is FirAnonymousObjectExpression -> localFirElement.anonymousObject
else -> error("FirDeclaration was not found for\n${ktDeclaration.getElementTextInContext()}")
}
}
override fun resolveFirToPhase(declaration: FirDeclaration, toPhase: FirResolvePhase) {
if (toPhase == FirResolvePhase.RAW_FIR) return
val fileCache = when (val session = declaration.moduleData.session) {
is FirIdeSourcesSession -> session.cache
else -> return
}
firLazyDeclarationResolver.lazyResolveDeclaration(
firDeclarationToResolve = declaration,
moduleFileCache = fileCache,
scopeSession = ScopeSession(),
toPhase = toPhase,
checkPCE = true,
)
}
}
@@ -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.visitors.FirVisitorVoid
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.FirLazyBodiesCalculator
import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.firIdeProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.AbstractLowLevelApiSingleFileTest
import org.jetbrains.kotlin.fir.scopes.kotlinScopeProvider
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.services.TestModuleStructure
import org.jetbrains.kotlin.test.services.TestServices
abstract class AbstractFirLazyBodiesCalculatorTest : AbstractLowLevelApiSingleFileTest() {
private val lazyChecker = object : FirVisitorVoid() {
override fun visitElement(element: FirElement) {
TestCase.assertFalse("${FirLazyBlock::class.qualifiedName} should not present in the tree", element is FirLazyBlock)
@@ -34,7 +33,7 @@ abstract class AbstractFirLazyBodiesCalculatorTest : AbstractLowLevelApiSingleFi
override fun doTestByFileStructure(ktFile: KtFile, moduleStructure: TestModuleStructure, testServices: TestServices) {
resolveWithClearCaches(ktFile) { resolveState ->
val session = resolveState.rootModuleSession
val provider = session.firIdeProvider.kotlinScopeProvider
val provider = session.kotlinScopeProvider
val laziedFirFile = RawFirBuilder(
session,
@@ -59,5 +58,4 @@ abstract class AbstractFirLazyBodiesCalculatorTest : AbstractLowLevelApiSingleFi
TestCase.assertEquals(laziedFirFileDump, fullFirFileDump)
}
}
}
@@ -43,7 +43,7 @@ abstract class AbstractFirContextCollectionTest : AbstractLowLevelApiSingleFileT
) { resolveState ->
check(resolveState is FirSourceModuleResolveState)
val fileStructure = resolveState.fileStructureCache.getFileStructure(ktFile, resolveState.rootModuleSession.cache)
val fileStructure = resolveState.fileStructureCache.getFileStructure(ktFile, resolveState.cache)
val allStructureElements = fileStructure.getAllStructureElements()
handler.elementsToCheckContext = allStructureElements.map { it.getFirDeclaration() }
@@ -88,7 +88,7 @@ abstract class AbstractFileStructureTest : AbstractLowLevelApiSingleFileTest() {
val moduleResolveState = getResolveState() as FirSourceModuleResolveState
return moduleResolveState.fileStructureCache.getFileStructure(
ktFile = this,
moduleFileCache = moduleResolveState.rootModuleSession.cache
moduleFileCache = moduleResolveState.cache
)
}