From 5c9a9913db7b0d0a5af4d89304fee9587fd10579 Mon Sep 17 00:00:00 2001 From: Yan Zhulanow Date: Fri, 10 Mar 2023 16:18:32 +0900 Subject: [PATCH] [LL API] Refactor session caches Use 'CachedValue' and dependency handling with 'ModificationTracker' for dependent session invalidation. --- .../standalone/RegisterComponentService.java | 20 +- .../StandaloneAnalysisAPISessionBuilder.kt | 3 +- .../trackers/CompositeModificationTracker.kt | 32 ++- .../api/fir/LLFirGlobalResolveComponents.kt | 11 +- .../api/fir/LLFirResolveSessionDepended.kt | 1 - .../level/api/fir/LLFirResolveStateService.kt | 106 ++----- .../LowLevelFirApiFacadeForResolveOnAir.kt | 5 +- .../structure/LLFirBuiltinsSessionFactory.kt | 21 +- .../structure/LLFirLibrarySessionFactory.kt | 81 ------ .../LLFirBuiltinsAndCloneableSession.kt | 4 +- .../api/fir/sessions/LLFirLibrariesSession.kt | 4 +- .../fir/sessions/LLFirLibraryLikeSession.kt | 4 +- ...yOrLibrarySourceResolvableModuleSession.kt | 4 +- ...UnderContentRootResolvableModuleSession.kt | 4 +- .../sessions/LLFirResolvableModuleSession.kt | 4 +- .../api/fir/sessions/LLFirScriptSession.kt | 4 +- .../level/api/fir/sessions/LLFirSession.kt | 55 +++- ...SessionFactory.kt => LLFirSessionCache.kt} | 269 +++++++++++------- .../api/fir/sessions/LLFirSessionProvider.kt | 70 ----- .../sessions/LLFirSessionProviderStorage.kt | 144 ---------- .../api/fir/sessions/LLFirSourcesSession.kt | 4 +- ...OrLibrarySourceResolvableResolveSession.kt | 17 +- .../LLFirNotUnderContentRootResolveSession.kt | 11 +- .../state/LLFirResolvableResolveSession.kt | 33 ++- .../fir/state/LLFirScriptResolveSession.kt | 42 +-- .../fir/state/LLFirSourceResolveSession.kt | 11 +- .../analysis/low/level/api/fir/util/utils.kt | 8 +- .../based/AbstractCompilerBasedTestForFir.kt | 7 +- ...sInheritorsCaclulatorPreAnalysisHandler.kt | 4 +- .../low/level/api/fir/firTestUtils.kt | 5 +- .../AnalysisApiFirTestServiceRegistrar.kt | 6 +- 31 files changed, 372 insertions(+), 622 deletions(-) delete mode 100644 analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/LLFirLibrarySessionFactory.kt rename analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/{LLFirSessionFactory.kt => LLFirSessionCache.kt} (66%) delete mode 100644 analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirSessionProvider.kt delete mode 100644 analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirSessionProviderStorage.kt diff --git a/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/api/standalone/RegisterComponentService.java b/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/api/standalone/RegisterComponentService.java index cd808b52cf4..61bbe399a33 100644 --- a/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/api/standalone/RegisterComponentService.java +++ b/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/api/standalone/RegisterComponentService.java @@ -6,21 +6,21 @@ package org.jetbrains.kotlin.analysis.api.standalone; import com.intellij.mock.MockProject; +import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirGlobalResolveComponents; import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirResolveSessionService; -import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirLibrarySessionFactory; +import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSessionCache; +@SuppressWarnings("KotlinInternalInJava") class RegisterComponentService { - static void registerLLFirLibrarySessionFactory(MockProject project) { - project.registerService( - LLFirLibrarySessionFactory.class, - new LLFirLibrarySessionFactory(project) - ); + static void registerLLFirSessionCache(MockProject project) { + project.registerService(LLFirSessionCache.class, new LLFirSessionCache(project)); + } + + static void registerLLFirGlobalResolveComponents(MockProject project) { + project.registerService(LLFirGlobalResolveComponents.class, new LLFirGlobalResolveComponents(project)); } static void registerLLFirResolveSessionService(MockProject project) { - project.registerService( - LLFirResolveSessionService.class, - new LLFirResolveSessionService(project) - ); + project.registerService(LLFirResolveSessionService.class, new LLFirResolveSessionService(project)); } } diff --git a/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/api/standalone/StandaloneAnalysisAPISessionBuilder.kt b/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/api/standalone/StandaloneAnalysisAPISessionBuilder.kt index f761190e88b..20170f2c21e 100644 --- a/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/api/standalone/StandaloneAnalysisAPISessionBuilder.kt +++ b/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/api/standalone/StandaloneAnalysisAPISessionBuilder.kt @@ -142,7 +142,8 @@ public class StandaloneAnalysisAPISessionBuilder( } ) registerService(LLFirBuiltinsSessionFactory::class.java, LLFirBuiltinsSessionFactory(this)) - RegisterComponentService.registerLLFirLibrarySessionFactory(this) + RegisterComponentService.registerLLFirSessionCache(this) + RegisterComponentService.registerLLFirGlobalResolveComponents(this) registerService(KotlinReferenceProvidersService::class.java, HLApiReferenceProviderService::class.java) registerService(KotlinReferenceProviderContributor::class.java, KotlinFirReferenceContributor::class.java) diff --git a/analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/trackers/CompositeModificationTracker.kt b/analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/trackers/CompositeModificationTracker.kt index 0665ceebc76..ca081275300 100644 --- a/analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/trackers/CompositeModificationTracker.kt +++ b/analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/trackers/CompositeModificationTracker.kt @@ -6,15 +6,39 @@ package org.jetbrains.kotlin.analysis.utils.trackers import com.intellij.openapi.util.ModificationTracker +import java.util.* +import kotlin.collections.ArrayList public class CompositeModificationTracker private constructor(private val trackers: List) : ModificationTracker { override fun getModificationCount(): Long = trackers.sumOf { it.modificationCount } public companion object { - public fun create(trackers: List): ModificationTracker = when (trackers.size) { - 0 -> ModificationTracker.NEVER_CHANGED - 1 -> trackers.single() - else -> CompositeModificationTracker(trackers) + public fun create(trackers: List): ModificationTracker { + return when (trackers.size) { + 0 -> ModificationTracker.NEVER_CHANGED + 1 -> trackers.single() + else -> CompositeModificationTracker(trackers) + } + } + + public fun createFlattened(trackers: List): ModificationTracker { + val map = IdentityHashMap() + val flattened = ArrayList() + + fun flatten(tracker: ModificationTracker) { + when (tracker) { + is CompositeModificationTracker -> tracker.trackers.forEach(::flatten) + ModificationTracker.NEVER_CHANGED -> {} + else -> { + if (map.put(tracker, true) == null) { + flattened += tracker + } + } + } + } + + trackers.forEach(::flatten) + return create(flattened) } } } \ No newline at end of file diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirGlobalResolveComponents.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirGlobalResolveComponents.kt index 811a5baf149..41a9f32b19e 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirGlobalResolveComponents.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirGlobalResolveComponents.kt @@ -7,11 +7,14 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir import com.intellij.openapi.project.Project import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLockProvider -import org.jetbrains.kotlin.analysis.project.structure.KtModule -internal class LLFirGlobalResolveComponents( - val project: Project, -) { +internal class LLFirGlobalResolveComponents(val project: Project) { + companion object { + fun getInstance(project: Project): LLFirGlobalResolveComponents { + return project.getService(LLFirGlobalResolveComponents::class.java) + } + } + val phaseRunner: LLFirPhaseRunner = LLFirPhaseRunner() val lockProvider: LLFirLockProvider = LLFirLockProvider() } \ No newline at end of file diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirResolveSessionDepended.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirResolveSessionDepended.kt index b108aa91898..6de2f5d9e8b 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirResolveSessionDepended.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirResolveSessionDepended.kt @@ -30,7 +30,6 @@ import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtFile -import java.util.concurrent.ConcurrentHashMap internal class LLFirResolveSessionDepended( val originalFirResolveSession: LLFirResolvableResolveSession, diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirResolveStateService.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirResolveStateService.kt index 38b25844208..057aa894122 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirResolveStateService.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirResolveStateService.kt @@ -7,10 +7,9 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.project.Project -import com.intellij.openapi.roots.ProjectRootModificationTracker -import org.jetbrains.annotations.TestOnly import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession -import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSessionProviderStorage +import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSession +import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSessionCache import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirLibraryOrLibrarySourceResolvableResolveSession import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirNotUnderContentRootResolveSession import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirResolvableResolveSession @@ -18,91 +17,36 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirScriptResolveS import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirSourceResolveSession import org.jetbrains.kotlin.analysis.low.level.api.fir.util.errorWithFirSpecificEntries import org.jetbrains.kotlin.analysis.project.structure.* -import org.jetbrains.kotlin.analysis.providers.createProjectWideOutOfBlockModificationTracker -import org.jetbrains.kotlin.analysis.utils.caches.SoftCachedMap -internal class LLFirResolveSessionService(project: Project) { - private val sessionProviderStorage = LLFirSessionProviderStorage(project) +class LLFirResolveSessionService(project: Project) { + private val cache = LLFirSessionCache.getInstance(project) - private val cache = SoftCachedMap.create( - project, - SoftCachedMap.Kind.STRONG_KEYS_SOFT_VALUES, - listOf( - ProjectRootModificationTracker.getInstance(project), - project.createProjectWideOutOfBlockModificationTracker(), - ) - ) + fun getFirResolveSession(module: KtModule): LLFirResolveSession { + return create(module, cache::getSession) + } - fun getFirResolveSession(module: KtModule): LLFirResolvableResolveSession { - return cache.getOrPut(module) { - createFirResolveSessionFor(module, sessionProviderStorage) + fun getFirResolveSessionNoCaching(module: KtModule): LLFirResolveSession { + return create(module, cache::getSessionNoCaching) + } + + private fun create(module: KtModule, factory: (KtModule) -> LLFirSession): LLFirResolvableResolveSession { + val session = factory(module) + + return when (module) { + is KtSourceModule -> LLFirSourceResolveSession(session) + is KtLibraryModule, is KtLibrarySourceModule -> LLFirLibraryOrLibrarySourceResolvableResolveSession(session) + is KtScriptModule -> LLFirScriptResolveSession(session) + is KtNotUnderContentRootModule -> LLFirNotUnderContentRootResolveSession(session) + else -> { + errorWithFirSpecificEntries("Unexpected ${module::class.java}") { + withEntry("module", module) { it.moduleDescription } + } + } } } companion object { fun getInstance(project: Project): LLFirResolveSessionService = ServiceManager.getService(project, LLFirResolveSessionService::class.java) - - internal fun createFirResolveSessionFor( - useSiteKtModule: KtModule, - sessionProviderStorage: LLFirSessionProviderStorage - ): LLFirResolvableResolveSession { - val sessionProvider = sessionProviderStorage.getSessionProvider(useSiteKtModule) - val useSiteSession = sessionProvider.rootModuleSession - return when (useSiteKtModule) { - is KtSourceModule -> { - LLFirSourceResolveSession( - useSiteSession.moduleComponents.globalResolveComponents, - sessionProviderStorage.project, - useSiteKtModule, - sessionProvider, - ) - } - - is KtLibraryModule, is KtLibrarySourceModule -> { - LLFirLibraryOrLibrarySourceResolvableResolveSession( - useSiteSession.moduleComponents.globalResolveComponents, - sessionProviderStorage.project, - useSiteKtModule, - sessionProvider, - ) - } - - is KtScriptModule -> { - LLFirScriptResolveSession( - useSiteSession.moduleComponents.globalResolveComponents, - sessionProviderStorage.project, - useSiteKtModule, - sessionProvider - ) - } - - is KtNotUnderContentRootModule -> { - LLFirNotUnderContentRootResolveSession( - useSiteSession.moduleComponents.globalResolveComponents, - sessionProviderStorage.project, - useSiteKtModule, - sessionProvider, - ) - } - - else -> { - errorWithFirSpecificEntries("Unexpected ${useSiteKtModule::class.java}") { - withEntry("module", useSiteKtModule) { it.moduleDescription } - } - } - } - - } } -} - -@TestOnly -fun createFirResolveSessionForNoCaching(useSiteKtModule: KtModule, project: Project): LLFirResolveSession { - return LLFirResolveSessionService.createFirResolveSessionFor( - useSiteKtModule = useSiteKtModule, - sessionProviderStorage = LLFirSessionProviderStorage(project) - ) -} - - +} \ No newline at end of file diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/LowLevelFirApiFacadeForResolveOnAir.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/LowLevelFirApiFacadeForResolveOnAir.kt index dbdea70555a..06229c4518e 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/LowLevelFirApiFacadeForResolveOnAir.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/LowLevelFirApiFacadeForResolveOnAir.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.api import com.intellij.psi.PsiElement import com.intellij.psi.util.PsiTreeUtil import org.jetbrains.kotlin.analysis.low.level.api.fir.DeclarationCopyBuilder.withBodyFrom +import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirGlobalResolveComponents import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirResolveSessionDepended import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FileTowerProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirTowerContextProvider @@ -259,7 +260,9 @@ object LowLevelFirApiFacadeForResolveOnAir { val isInBodyReplacement = isInBodyReplacement(nonLocalDeclaration, replacement) - return firResolveSession.globalComponents.lockProvider.withLock(originalFirFile) { + val globalResolveComponents = LLFirGlobalResolveComponents.getInstance(firResolveSession.project) + + return globalResolveComponents.lockProvider.withLock(originalFirFile) { val copiedFirDeclaration = if (isInBodyReplacement) { when (originalDeclaration) { is FirSimpleFunction -> diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/LLFirBuiltinsSessionFactory.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/LLFirBuiltinsSessionFactory.kt index 21e28695617..eb1445a9e0e 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/LLFirBuiltinsSessionFactory.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/LLFirBuiltinsSessionFactory.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure import com.intellij.openapi.project.Project +import com.intellij.openapi.util.ModificationTracker import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLFirBuiltinSymbolProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLFirBuiltinsAndCloneableSessionProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirBuiltinsAndCloneableSession @@ -37,9 +38,7 @@ import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices import java.util.concurrent.ConcurrentHashMap @OptIn(PrivateSessionConstructor::class, SessionConfiguration::class) -class LLFirBuiltinsSessionFactory( - private val project: Project, -) { +class LLFirBuiltinsSessionFactory(private val project: Project) { private val builtInTypes = BuiltinTypes() // TODO should be platform-specific private val builtinsAndCloneableSession = ConcurrentHashMap() @@ -49,10 +48,11 @@ class LLFirBuiltinsSessionFactory( private fun createBuiltinsAndCloneableSession(platform: TargetPlatform): LLFirBuiltinsAndCloneableSession { val builtinsModule = KtBuiltinsModule(platform, platform.getAnalyzerServices(), project) - return LLFirBuiltinsAndCloneableSession(builtinsModule, builtInTypes).apply session@{ - val moduleData = LLFirModuleData(builtinsModule).apply { - bindSession(this@session) - } + + val session = LLFirBuiltinsAndCloneableSession(builtinsModule, ModificationTracker.NEVER_CHANGED, builtInTypes) + val moduleData = LLFirModuleData(builtinsModule).apply { bindSession(session) } + + return session.apply { registerIdeComponents(project) register(FirLazyDeclarationResolver::class, FirDummyCompilerLazyDeclarationResolver) registerCommonComponents(LanguageVersionSettingsImpl.DEFAULT/*TODO*/) @@ -62,10 +62,11 @@ class LLFirBuiltinsSessionFactory( val kotlinScopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped) register(FirKotlinScopeProvider::class, kotlinScopeProvider) + val symbolProvider = createCompositeSymbolProvider(this) { - add(LLFirBuiltinSymbolProvider(this@session, moduleData, kotlinScopeProvider)) - add(FirExtensionSyntheticFunctionInterfaceProvider(this@session, moduleData, kotlinScopeProvider)) - add(FirCloneableSymbolProvider(this@session, moduleData, kotlinScopeProvider)) + add(LLFirBuiltinSymbolProvider(session, moduleData, kotlinScopeProvider)) + add(FirExtensionSyntheticFunctionInterfaceProvider(session, moduleData, kotlinScopeProvider)) + add(FirCloneableSymbolProvider(session, moduleData, kotlinScopeProvider)) } register(FirSymbolProvider::class, symbolProvider) diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/LLFirLibrarySessionFactory.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/LLFirLibrarySessionFactory.kt deleted file mode 100644 index eed6519ef16..00000000000 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/LLFirLibrarySessionFactory.kt +++ /dev/null @@ -1,81 +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.project.structure - -import com.intellij.openapi.project.Project -import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLFirFirClassByPsiClassProvider -import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLFirLibrarySessionProvider -import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirLibrarySession -import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSession -import org.jetbrains.kotlin.analysis.project.structure.KtBinaryModule -import org.jetbrains.kotlin.analysis.project.structure.KtModule -import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl -import org.jetbrains.kotlin.fir.PrivateSessionConstructor -import org.jetbrains.kotlin.fir.SessionConfiguration -import org.jetbrains.kotlin.fir.backend.jvm.FirJvmTypeMapper -import org.jetbrains.kotlin.fir.resolve.providers.FirProvider -import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider -import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider -import org.jetbrains.kotlin.fir.resolve.scopes.wrapScopeWithJvmMapped -import org.jetbrains.kotlin.fir.resolve.transformers.FirDummyCompilerLazyDeclarationResolver -import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider -import org.jetbrains.kotlin.fir.session.* -import org.jetbrains.kotlin.fir.symbols.FirLazyDeclarationResolver -import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver - -@OptIn(PrivateSessionConstructor::class, SessionConfiguration::class) -class LLFirLibrarySessionFactory( - private val project: Project, -) { - - internal fun getLibrarySession(ktBinaryModule: KtBinaryModule, sessionsCache: MutableMap): LLFirLibrarySession { - return sessionsCache.getOrPut(ktBinaryModule) { - createModuleLibrariesSession(ktBinaryModule, sessionsCache) - } as LLFirLibrarySession - } - - private fun createModuleLibrariesSession( - ktLibraryModule: KtBinaryModule, - sessionsCache: MutableMap, - ): LLFirLibrarySession { - val platform = ktLibraryModule.platform - val builtinsSession = LLFirBuiltinsSessionFactory.getInstance(project).getBuiltinsSession(platform) - sessionsCache.putIfAbsent(builtinsSession.ktModule, builtinsSession) - return LLFirLibrarySession(ktLibraryModule, builtinsSession.builtinTypes).apply session@{ - val moduleData = LLFirModuleData(ktLibraryModule).apply { bindSession(this@session) } - registerModuleData(moduleData) - registerIdeComponents(project) - register(FirLazyDeclarationResolver::class, FirDummyCompilerLazyDeclarationResolver) - registerCommonComponents(LanguageVersionSettingsImpl.DEFAULT/*TODO*/) - registerCommonComponentsAfterExtensionsAreConfigured() - registerCommonJavaComponents(JavaModuleResolver.getInstance(project)) - registerJavaSpecificResolveComponents() - - val kotlinScopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped) - register(FirKotlinScopeProvider::class, kotlinScopeProvider) - - val symbolProvider = LLFirLibraryProviderFactory.createLibraryProvidersForScope( - this, - moduleData, - kotlinScopeProvider, - project, - builtinTypes, - ktLibraryModule.contentScope, - builtinsSession.symbolProvider - ) - - register(LLFirFirClassByPsiClassProvider::class, LLFirFirClassByPsiClassProvider(this)) - register(FirProvider::class, LLFirLibrarySessionProvider(symbolProvider)) - register(FirSymbolProvider::class, symbolProvider) - register(FirJvmTypeMapper::class, FirJvmTypeMapper(this)) - } - } - - companion object { - fun getInstance(project: Project): LLFirLibrarySessionFactory = - project.getService(LLFirLibrarySessionFactory::class.java) - } -} diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirBuiltinsAndCloneableSession.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirBuiltinsAndCloneableSession.kt index 5978bf7cd33..6711e894453 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirBuiltinsAndCloneableSession.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirBuiltinsAndCloneableSession.kt @@ -5,11 +5,13 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions +import com.intellij.openapi.util.ModificationTracker import org.jetbrains.kotlin.analysis.project.structure.KtModule import org.jetbrains.kotlin.fir.BuiltinTypes import org.jetbrains.kotlin.fir.PrivateSessionConstructor class LLFirBuiltinsAndCloneableSession @PrivateSessionConstructor constructor( ktModule: KtModule, + dependencyTracker: ModificationTracker, builtinTypes: BuiltinTypes, -) : LLFirLibraryLikeSession(ktModule, builtinTypes) \ No newline at end of file +) : LLFirLibraryLikeSession(ktModule, dependencyTracker, builtinTypes) \ No newline at end of file diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirLibrariesSession.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirLibrariesSession.kt index 39493108b3b..3f8cf7f492e 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirLibrariesSession.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirLibrariesSession.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions +import com.intellij.openapi.util.ModificationTracker import org.jetbrains.kotlin.analysis.project.structure.KtModule import org.jetbrains.kotlin.fir.BuiltinTypes import org.jetbrains.kotlin.fir.PrivateSessionConstructor @@ -14,5 +15,6 @@ import org.jetbrains.kotlin.fir.PrivateSessionConstructor */ internal class LLFirLibrarySession @PrivateSessionConstructor constructor( ktModule: KtModule, + dependencyTracker: ModificationTracker, builtinTypes: BuiltinTypes, -) : LLFirLibraryLikeSession(ktModule, builtinTypes) +) : LLFirLibraryLikeSession(ktModule, dependencyTracker, builtinTypes) diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirLibraryLikeSession.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirLibraryLikeSession.kt index 1698c0b1ec2..de3c621978e 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirLibraryLikeSession.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirLibraryLikeSession.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions +import com.intellij.openapi.util.ModificationTracker import org.jetbrains.kotlin.analysis.low.level.api.fir.util.LLFirScopeSessionProvider import org.jetbrains.kotlin.analysis.project.structure.KtModule import org.jetbrains.kotlin.fir.BuiltinTypes @@ -12,8 +13,9 @@ import org.jetbrains.kotlin.fir.resolve.ScopeSession abstract class LLFirLibraryLikeSession( ktModule: KtModule, + dependencyTracker: ModificationTracker, builtinTypes: BuiltinTypes, -) : LLFirSession(ktModule, builtinTypes, Kind.Library) { +) : LLFirSession(ktModule, dependencyTracker, builtinTypes, Kind.Library) { private val scopeSessionProvider = LLFirScopeSessionProvider.create(project, invalidationTrackers = emptyList()) override fun getScopeSession(): ScopeSession { diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirLibraryOrLibrarySourceResolvableModuleSession.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirLibraryOrLibrarySourceResolvableModuleSession.kt index 8c7892ad6ee..edfcea8e50c 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirLibraryOrLibrarySourceResolvableModuleSession.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirLibraryOrLibrarySourceResolvableModuleSession.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions +import com.intellij.openapi.util.ModificationTracker import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirModuleResolveComponents import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule import org.jetbrains.kotlin.analysis.project.structure.KtLibrarySourceModule @@ -13,9 +14,10 @@ import org.jetbrains.kotlin.fir.BuiltinTypes internal class LLFirLibraryOrLibrarySourceResolvableModuleSession( ktModule: KtModule, + dependencyTracker: ModificationTracker, override val moduleComponents: LLFirModuleResolveComponents, builtinTypes: BuiltinTypes, -) : LLFirResolvableModuleSession(ktModule, builtinTypes) { +) : LLFirResolvableModuleSession(ktModule, dependencyTracker, builtinTypes) { init { checkIsValidKtModule(ktModule) } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirNonUnderContentRootResolvableModuleSession.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirNonUnderContentRootResolvableModuleSession.kt index c52b066b532..0a6ae0d847c 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirNonUnderContentRootResolvableModuleSession.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirNonUnderContentRootResolvableModuleSession.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions +import com.intellij.openapi.util.ModificationTracker import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirModuleResolveComponents import org.jetbrains.kotlin.analysis.project.structure.KtNotUnderContentRootModule import org.jetbrains.kotlin.fir.BuiltinTypes @@ -12,6 +13,7 @@ import org.jetbrains.kotlin.fir.PrivateSessionConstructor internal class LLFirNonUnderContentRootResolvableModuleSession @PrivateSessionConstructor constructor( ktModule: KtNotUnderContentRootModule, + dependencyTracker: ModificationTracker, override val moduleComponents: LLFirModuleResolveComponents, builtinTypes: BuiltinTypes, -) : LLFirResolvableModuleSession(ktModule, builtinTypes) +) : LLFirResolvableModuleSession(ktModule, dependencyTracker, builtinTypes) diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirResolvableModuleSession.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirResolvableModuleSession.kt index de48d398137..3da5770f669 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirResolvableModuleSession.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirResolvableModuleSession.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions +import com.intellij.openapi.util.ModificationTracker import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirModuleResolveComponents import org.jetbrains.kotlin.analysis.project.structure.KtModule import org.jetbrains.kotlin.fir.BuiltinTypes @@ -14,8 +15,9 @@ import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol abstract class LLFirResolvableModuleSession( ktModule: KtModule, + dependencyTracker: ModificationTracker, builtinTypes: BuiltinTypes -) : LLFirModuleSession(ktModule, builtinTypes, Kind.Source) { +) : LLFirModuleSession(ktModule, dependencyTracker, builtinTypes, Kind.Source) { internal abstract val moduleComponents: LLFirModuleResolveComponents final override fun getScopeSession(): ScopeSession { diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirScriptSession.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirScriptSession.kt index 2f05c0c6097..51c9e1cc9f8 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirScriptSession.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirScriptSession.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions +import com.intellij.openapi.util.ModificationTracker import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirModuleResolveComponents import org.jetbrains.kotlin.analysis.project.structure.KtScriptModule import org.jetbrains.kotlin.fir.BuiltinTypes @@ -12,6 +13,7 @@ import org.jetbrains.kotlin.fir.PrivateSessionConstructor internal class LLFirScriptSession @PrivateSessionConstructor constructor( ktModule: KtScriptModule, + dependencyTracker: ModificationTracker, override val moduleComponents: LLFirModuleResolveComponents, builtinTypes: BuiltinTypes -) : LLFirResolvableModuleSession(ktModule, builtinTypes) \ No newline at end of file +) : LLFirResolvableModuleSession(ktModule, dependencyTracker, builtinTypes) \ No newline at end of file diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirSession.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirSession.kt index 2b61f662ee2..e054e512f40 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirSession.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirSession.kt @@ -7,9 +7,11 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions import com.intellij.openapi.project.Project import com.intellij.openapi.util.ModificationTracker -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.BooleanModificationTracker +import com.intellij.psi.PsiFile +import com.intellij.psi.SmartPointerManager import org.jetbrains.kotlin.analysis.project.structure.* import org.jetbrains.kotlin.analysis.providers.KotlinModificationTrackerFactory +import org.jetbrains.kotlin.analysis.providers.KtModuleStateTracker import org.jetbrains.kotlin.analysis.utils.trackers.CompositeModificationTracker import org.jetbrains.kotlin.fir.BuiltinTypes import org.jetbrains.kotlin.fir.FirElementWithResolvePhase @@ -22,16 +24,17 @@ import java.util.concurrent.atomic.AtomicBoolean @OptIn(PrivateSessionConstructor::class) abstract class LLFirSession( val ktModule: KtModule, + dependencyTracker: ModificationTracker, override val builtinTypes: BuiltinTypes, kind: Kind ) : FirSession(sessionProvider = null, kind) { abstract fun getScopeSession(): ScopeSession - val modificationTracker: ModificationTracker - private val initialModificationCount: Long private val isExplicitlyInvalidated = AtomicBoolean(false) + val modificationTracker: ModificationTracker + val project: Project get() = ktModule.project @@ -41,24 +44,49 @@ abstract class LLFirSession( val outOfBlockTracker = when (ktModule) { is KtSourceModule -> trackerFactory.createModuleWithoutDependenciesOutOfBlockModificationTracker(ktModule) - is KtNotUnderContentRootModule -> ModificationTracker { ktModule.file?.modificationStamp ?: 0 } - is KtScriptModule -> ModificationTracker { ktModule.file.modificationStamp } - is KtScriptDependencyModule -> ModificationTracker { ktModule.file?.modificationStamp ?: 0 } - else -> ModificationTracker.NEVER_CHANGED + is KtNotUnderContentRootModule -> ktModule.file?.let(::FileModificationTracker) + is KtScriptModule -> FileModificationTracker(ktModule.file) + is KtScriptDependencyModule -> ktModule.file?.let(::FileModificationTracker) + else -> null } - modificationTracker = CompositeModificationTracker.create( - listOf( + modificationTracker = CompositeModificationTracker.createFlattened( + listOfNotNull( + ExplicitInvalidationTracker(ktModule, isExplicitlyInvalidated), + ModuleStateModificationTracker(ktModule, validityTracker), outOfBlockTracker, - ModificationTracker { validityTracker.rootModificationCount }, - BooleanModificationTracker { validityTracker.isValid }, - BooleanModificationTracker { !isExplicitlyInvalidated.get() } + dependencyTracker ) ) initialModificationCount = modificationTracker.modificationCount } + private class ModuleStateModificationTracker(val module: KtModule, val tracker: KtModuleStateTracker) : ModificationTracker { + override fun getModificationCount(): Long = tracker.rootModificationCount + override fun toString(): String = "Module state tracker for module " + module.moduleDescription + "'" + } + + private class ExplicitInvalidationTracker(val module: KtModule, val isExplicitlyInvalidated: AtomicBoolean) : ModificationTracker { + override fun getModificationCount(): Long = if (isExplicitlyInvalidated.get()) 1 else 0 + override fun toString(): String = "Explicit invalidation tracker for module '" + module.moduleDescription + "'" + } + + private class FileModificationTracker(file: PsiFile) : ModificationTracker { + private val pointer = SmartPointerManager.getInstance(file.project).createSmartPsiElementPointer(file) + + override fun getModificationCount(): Long { + val file = pointer.element ?: return Long.MAX_VALUE + return file.modificationStamp + } + + override fun toString(): String { + val file = pointer.element ?: return "File tracker for a collected file" + val virtualFile = file.virtualFile ?: return "File tracker for a non-physical file '" + file.name + "'" + return "File tracker for path '" + virtualFile.path + "'" + } + } + fun invalidate() { isExplicitlyInvalidated.set(true) } @@ -69,9 +97,10 @@ abstract class LLFirSession( abstract class LLFirModuleSession( ktModule: KtModule, + dependencyTracker: ModificationTracker, builtinTypes: BuiltinTypes, kind: Kind -) : LLFirSession(ktModule, builtinTypes, kind) +) : LLFirSession(ktModule, dependencyTracker, builtinTypes, kind) val FirElementWithResolvePhase.llFirSession: LLFirSession get() = moduleData.session as LLFirSession diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirSessionFactory.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirSessionCache.kt similarity index 66% rename from analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirSessionFactory.kt rename to analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirSessionCache.kt index e7e7c3250bc..7155146fe29 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirSessionFactory.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirSessionCache.kt @@ -6,8 +6,13 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions import com.intellij.openapi.project.Project +import com.intellij.openapi.util.ModificationTracker import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.ProjectScope +import com.intellij.psi.util.CachedValue +import com.intellij.psi.util.CachedValueProvider +import com.intellij.psi.util.CachedValuesManager +import com.intellij.util.containers.CollectionFactory import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirGlobalResolveComponents import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirLazyDeclarationResolver import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirModuleResolveComponents @@ -18,6 +23,7 @@ import org.jetbrains.kotlin.analysis.project.structure.* import org.jetbrains.kotlin.analysis.providers.createAnnotationResolver import org.jetbrains.kotlin.analysis.providers.createDeclarationProvider import org.jetbrains.kotlin.analysis.providers.createPackageProvider +import org.jetbrains.kotlin.analysis.utils.trackers.CompositeModificationTracker import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl @@ -33,6 +39,7 @@ import org.jetbrains.kotlin.fir.java.JavaSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.* import org.jetbrains.kotlin.fir.resolve.providers.impl.FirExtensionSyntheticFunctionInterfaceProvider import org.jetbrains.kotlin.fir.resolve.scopes.wrapScopeWithJvmMapped +import org.jetbrains.kotlin.fir.resolve.transformers.FirDummyCompilerLazyDeclarationResolver import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider import org.jetbrains.kotlin.fir.session.* import org.jetbrains.kotlin.fir.symbols.FirLazyDeclarationResolver @@ -41,37 +48,84 @@ import org.jetbrains.kotlin.platform.jvm.JvmPlatforms import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices +import java.util.concurrent.ConcurrentMap @OptIn(PrivateSessionConstructor::class, SessionConfiguration::class) -internal object LLFirSessionFactory { - fun createSourcesSession( - module: KtSourceModule, - globalResolveComponents: LLFirGlobalResolveComponents, - sessionsCache: MutableMap - ): LLFirSourcesSession { - sessionsCache[module]?.let { return it as LLFirSourcesSession } +internal class LLFirSessionCache(private val project: Project) { + companion object { + fun getInstance(project: Project): LLFirSessionCache { + return project.getService(LLFirSessionCache::class.java) + } + } + + private val globalResolveComponents: LLFirGlobalResolveComponents + get() = LLFirGlobalResolveComponents.getInstance(project) + + private val sourceCache: ConcurrentMap> = CollectionFactory.createConcurrentSoftValueMap() + private val binaryCache: ConcurrentMap> = CollectionFactory.createConcurrentSoftValueMap() + + /** + * Returns the existing session if found, or creates a new session and caches it. + * Analyzable session will be returned for a library module. + */ + fun getSession(module: KtModule, preferBinary: Boolean = false): LLFirSession { + if (module is KtBinaryModule && (preferBinary || module is KtSdkModule)) { + return getCachedSession(module, binaryCache, ::createBinaryLibrarySession) + } + + return getCachedSession(module, sourceCache, ::createSession) + } + + /** + * Returns a session without caching it. + * Note that session dependencies are still cached. + */ + internal fun getSessionNoCaching(module: KtModule): LLFirSession { + return createSession(module) + } + + private fun getCachedSession( + module: T, + storage: ConcurrentMap>, + factory: (T) -> LLFirSession + ): LLFirSession { checkCanceled() - val project = module.project + return storage.computeIfAbsent(module) { + CachedValuesManager.getManager(project).createCachedValue { + val session = factory(module) + CachedValueProvider.Result(session, session.modificationTracker) + } + }.value + } + + private fun createSession(module: KtModule): LLFirSession { + return when (module) { + is KtSourceModule -> createSourcesSession(module) + is KtLibraryModule, is KtLibrarySourceModule -> createLibrarySession(module) + is KtSdkModule -> createBinaryLibrarySession(module) + is KtScriptModule -> createScriptSession(module) + is KtNotUnderContentRootModule -> createNotUnderContentRootResolvableSession(module) + else -> error("Unexpected module kind: ${module::class.simpleName}") + } + } + + private fun createSourcesSession(module: KtSourceModule): LLFirSourcesSession { val platform = module.platform val builtinsSession = LLFirBuiltinsSessionFactory.getInstance(project).getBuiltinsSession(platform) val languageVersionSettings = wrapLanguageVersionSettings(module.languageVersionSettings) val scopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped) - val components = LLFirModuleResolveComponents(module, globalResolveComponents, scopeProvider) - val contentScope = module.contentScope - val session = LLFirSourcesSession( - module, - components, - builtinsSession.builtinTypes - ) - sessionsCache[module] = session + val dependencies = collectSourceModuleDependencies(module) + val dependencyTracker = createSourceModuleDependencyTracker(module, dependencies) + val session = LLFirSourcesSession(module, dependencyTracker, components, builtinsSession.builtinTypes) components.session = session - return session.apply session@{ - val moduleData = LLFirModuleData(module).apply { bindSession(this@session) } + val moduleData = createModuleData(session) + + return session.apply { registerModuleData(moduleData) register(FirKotlinScopeProvider::class, scopeProvider) @@ -81,6 +135,8 @@ internal object LLFirSessionFactory { registerResolveComponents() registerJavaSpecificResolveComponents() + val contentScope = module.contentScope + val provider = LLFirProvider( this, components, @@ -102,8 +158,7 @@ internal object LLFirSessionFactory { } val dependencyProvider = LLFirDependentModuleProvidersBySessions(this) { - processSourceDependencies(module, sessionsCache, globalResolveComponents) - + addAll(dependencies) add(builtinsSession) } @@ -134,36 +189,27 @@ internal object LLFirSessionFactory { } } - - fun createLibraryOrLibrarySourceResolvableSession( - module: KtModule, - globalComponents: LLFirGlobalResolveComponents, - builtinSession: LLFirBuiltinsAndCloneableSession, - sessionsCache: MutableMap, - languageVersionSettings: LanguageVersionSettings = LanguageVersionSettingsImpl.DEFAULT - ): LLFirLibraryOrLibrarySourceResolvableModuleSession { - LLFirLibraryOrLibrarySourceResolvableModuleSession.checkIsValidKtModule(module) - sessionsCache[module]?.let { return it as LLFirLibraryOrLibrarySourceResolvableModuleSession } - checkCanceled() - - val project = module.project - + private fun createLibrarySession(module: KtModule): LLFirLibraryOrLibrarySourceResolvableModuleSession { val libraryModule = when (module) { is KtLibraryModule -> module is KtLibrarySourceModule -> module.binaryLibrary else -> error("Unexpected module ${module::class.simpleName}") } - val scopeProvider = FirKotlinScopeProvider() - val components = LLFirModuleResolveComponents(module, globalComponents, scopeProvider) + val platform = module.platform + val builtinsSession = LLFirBuiltinsSessionFactory.getInstance(project).getBuiltinsSession(platform) + val languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT - val contentScope = module.contentScope - val session = LLFirLibraryOrLibrarySourceResolvableModuleSession(module, components, builtinSession.builtinTypes) - sessionsCache[module] = session + val scopeProvider = FirKotlinScopeProvider() + val components = LLFirModuleResolveComponents(module, globalResolveComponents, scopeProvider) + + val dependencyTracker = builtinsSession.modificationTracker + val session = LLFirLibraryOrLibrarySourceResolvableModuleSession(module, dependencyTracker, components, builtinsSession.builtinTypes) components.session = session - return session.apply session@{ - val moduleData = LLFirModuleData(module).apply { bindSession(this@session) } + val moduleData = createModuleData(session) + + return session.apply { registerModuleData(moduleData) register(FirKotlinScopeProvider::class, scopeProvider) @@ -174,6 +220,8 @@ internal object LLFirSessionFactory { registerResolveComponents() registerJavaSpecificResolveComponents() + val contentScope = module.contentScope + val provider = LLFirProvider( this, components, @@ -188,11 +236,11 @@ internal object LLFirSessionFactory { // We need FirRegisteredPluginAnnotations during extensions' registration process val annotationsResolver = project.createAnnotationResolver(contentScope) - register(FirRegisteredPluginAnnotations::class, LLFirIdeRegisteredPluginAnnotations(this@session, annotationsResolver)) + register(FirRegisteredPluginAnnotations::class, LLFirIdeRegisteredPluginAnnotations(this, annotationsResolver)) register(FirPredicateBasedProvider::class, FirEmptyPredicateBasedProvider) val dependencyProvider = LLFirDependentModuleProvidersByProviders(this) { - add(builtinSession.symbolProvider) + add(builtinsSession.symbolProvider) // Script dependencies are self-contained and should not depend on other libraries if (module !is KtScriptDependencyModule) { @@ -231,29 +279,64 @@ internal object LLFirSessionFactory { } } - fun createScriptSession( - module: KtScriptModule, - sessionsCache: MutableMap - ): LLFirScriptSession { - sessionsCache[module]?.let { return it as LLFirScriptSession } - checkCanceled() + private fun createBinaryLibrarySession(module: KtBinaryModule): LLFirLibrarySession { + val platform = module.platform + val builtinsSession = LLFirBuiltinsSessionFactory.getInstance(project).getBuiltinsSession(platform) - val project = module.project + val dependencyTracker = ModificationTracker.NEVER_CHANGED + val session = LLFirLibrarySession(module, dependencyTracker, builtinsSession.builtinTypes) + + val moduleData = createModuleData(session) + + return session.apply { + registerModuleData(moduleData) + registerIdeComponents(project) + register(FirLazyDeclarationResolver::class, FirDummyCompilerLazyDeclarationResolver) + registerCommonComponents(LanguageVersionSettingsImpl.DEFAULT/*TODO*/) + registerCommonComponentsAfterExtensionsAreConfigured() + registerCommonJavaComponents(JavaModuleResolver.getInstance(project)) + registerJavaSpecificResolveComponents() + + val kotlinScopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped) + register(FirKotlinScopeProvider::class, kotlinScopeProvider) + + val symbolProvider = LLFirLibraryProviderFactory.createLibraryProvidersForScope( + this, + moduleData, + kotlinScopeProvider, + project, + builtinTypes, + module.contentScope, + builtinsSession.symbolProvider + ) + + register(LLFirFirClassByPsiClassProvider::class, LLFirFirClassByPsiClassProvider(this)) + register(FirProvider::class, LLFirLibrarySessionProvider(symbolProvider)) + register(FirSymbolProvider::class, symbolProvider) + register(FirJvmTypeMapper::class, FirJvmTypeMapper(this)) + + LLFirSessionConfigurator.configure(this) + } + } + + private fun createScriptSession(module: KtScriptModule): LLFirScriptSession { val platform = module.platform val builtinsSession = LLFirBuiltinsSessionFactory.getInstance(project).getBuiltinsSession(platform) val languageVersionSettings = wrapLanguageVersionSettings(module.languageVersionSettings) val scopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped) - val globalResolveComponents = LLFirGlobalResolveComponents(project) val components = LLFirModuleResolveComponents(module, globalResolveComponents, scopeProvider) val contentScope = module.contentScope - val session = LLFirScriptSession(module, components, builtinsSession.builtinTypes) - sessionsCache[module] = session + val dependencies = collectSourceModuleDependencies(module) + val dependencyTracker = createSourceModuleDependencyTracker(module, dependencies) + + val session = LLFirScriptSession(module, dependencyTracker, components, builtinsSession.builtinTypes) components.session = session - return session.apply session@{ - val moduleData = LLFirModuleData(module).apply { bindSession(this@session) } + val moduleData = createModuleData(session) + + return session.apply { registerModuleData(moduleData) register(FirKotlinScopeProvider::class, scopeProvider) @@ -276,12 +359,7 @@ internal object LLFirSessionFactory { register(FirLazyDeclarationResolver::class, LLFirLazyDeclarationResolver()) val dependencyProvider = LLFirDependentModuleProvidersBySessions(this) { - processSourceDependencies( - module, - sessionsCache, - globalResolveComponents - ) - + addAll(dependencies) add(builtinsSession) } @@ -309,27 +387,19 @@ internal object LLFirSessionFactory { } } - fun createNotUnderContentRootResolvableSession( - module: KtNotUnderContentRootModule, - sessionsCache: MutableMap - ): LLFirNonUnderContentRootResolvableModuleSession { - sessionsCache[module]?.let { return it as LLFirNonUnderContentRootResolvableModuleSession } - checkCanceled() - - val project = module.project + private fun createNotUnderContentRootResolvableSession(module: KtNotUnderContentRootModule): LLFirNonUnderContentRootResolvableModuleSession { val builtinsSession = LLFirBuiltinsSessionFactory.getInstance(project).getBuiltinsSession(JvmPlatforms.unspecifiedJvmPlatform) val languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT val scopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped) - val globalResolveComponents = LLFirGlobalResolveComponents(project) val components = LLFirModuleResolveComponents(module, globalResolveComponents, scopeProvider) - val contentScope = module.contentScope - val session = LLFirNonUnderContentRootResolvableModuleSession(module, components, builtinsSession.builtinTypes) - sessionsCache[module] = session + val dependencyTracker = builtinsSession.modificationTracker + val session = LLFirNonUnderContentRootResolvableModuleSession(module, dependencyTracker, components, builtinsSession.builtinTypes) components.session = session - return session.apply session@{ - val moduleData = LLFirModuleData(module).apply { bindSession(this@session) } + val moduleData = createModuleData(session) + + return session.apply { registerModuleData(moduleData) register(FirKotlinScopeProvider::class, scopeProvider) @@ -346,7 +416,7 @@ internal object LLFirSessionFactory { this, components, if (ktFile != null) FileBasedKotlinDeclarationProvider(ktFile) else EmptyKotlinDeclarationProvider, - project.createPackageProvider(contentScope), + project.createPackageProvider(module.contentScope), canContainKotlinPackage = true, ) @@ -395,45 +465,46 @@ internal object LLFirSessionFactory { } } - private fun MutableList.processSourceDependencies( - module: KtModule, - sessionsCache: MutableMap, - globalResolveComponents: LLFirGlobalResolveComponents - ) { - val project = module.project + private fun collectSourceModuleDependencies(module: KtModule): List { + val dependencies = mutableListOf() fun getOrCreateSessionForDependency(dependency: KtModule): LLFirSession? = when (dependency) { - is KtBuiltinsModule -> { - // Built-ins are already added - null - } - - is KtBinaryModule -> { - LLFirLibrarySessionFactory.getInstance(project).getLibrarySession(dependency, sessionsCache) - } - - is KtSourceModule -> { - createSourcesSession(dependency, globalResolveComponents, sessionsCache) - } + is KtBuiltinsModule -> null // Built-ins are already added + is KtBinaryModule -> getSession(dependency, preferBinary = true) + is KtSourceModule -> getSession(dependency) is KtScriptModule, is KtScriptDependencyModule, is KtNotUnderContentRootModule, - is KtLibrarySourceModule -> { - error("Module $module cannot depend on ${dependency::class}: $dependency") - } + is KtLibrarySourceModule -> error("Module $module cannot depend on ${dependency::class}: $dependency") } - module.directRegularDependencies.mapNotNullTo(this@processSourceDependencies, ::getOrCreateSessionForDependency) + module.directRegularDependencies.mapNotNullTo(dependencies, ::getOrCreateSessionForDependency) // The dependency provider needs to have access to all direct and indirect `dependsOn` dependencies, as `dependsOn` // dependencies are transitive. val directRegularDependenciesSet = module.directRegularDependencies.toSet() module.transitiveDependsOnDependencies.forEach { dependency -> if (dependency !in directRegularDependenciesSet) { - getOrCreateSessionForDependency(dependency)?.let(this::add) + getOrCreateSessionForDependency(dependency)?.let(dependencies::add) } } + + return dependencies + } + + private fun createSourceModuleDependencyTracker(module: KtModule, exposedDependencies: List): ModificationTracker { + val friendDependencies = module.directFriendDependencies + val trackers = ArrayList(exposedDependencies.size + friendDependencies.size) + + exposedDependencies.forEach { trackers += it.modificationTracker } + friendDependencies.forEach { trackers += getSession(it).modificationTracker } + + return CompositeModificationTracker.createFlattened(trackers) + } + + private fun createModuleData(session: LLFirSession): LLFirModuleData { + return LLFirModuleData(session.ktModule).apply { bindSession(session) } } } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirSessionProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirSessionProvider.kt deleted file mode 100644 index fc0e3a3a961..00000000000 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirSessionProvider.kt +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions - -import com.intellij.openapi.project.Project -import org.jetbrains.annotations.TestOnly -import org.jetbrains.kotlin.analysis.api.impl.barebone.annotations.Immutable -import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirModuleData -import org.jetbrains.kotlin.analysis.project.structure.KtModule -import org.jetbrains.kotlin.analysis.utils.errors.requireIsInstance -import org.jetbrains.kotlin.fir.FirModuleData -import org.jetbrains.kotlin.fir.FirSessionProvider -import java.lang.ref.WeakReference - -@Immutable -class LLFirSessionProvider internal constructor( - val project: Project, - internal val rootModuleSession: LLFirResolvableModuleSession, - private val ktModuleToSession: KtModuleToSessionMapping -) : FirSessionProvider() { - override fun getSession(moduleData: FirModuleData): LLFirSession { - requireIsInstance(moduleData) - return getResolvableSession(moduleData.ktModule) - } - - fun getSession(module: KtModule): LLFirSession = - ktModuleToSession.getSession(module) - - fun getResolvableSession(module: KtModule): LLFirResolvableModuleSession = - ktModuleToSession.getSession(module) as LLFirResolvableModuleSession - - @get:TestOnly - val allSessions: Collection - get() = ktModuleToSession.getAllSessions() -} - -internal abstract class KtModuleToSessionMapping { - abstract fun getSession(module: KtModule): LLFirSession - - @TestOnly - abstract fun getAllSessions(): Collection -} - -internal class KtModuleToSessionMappingByMapImpl( - private val map: Map -) : KtModuleToSessionMapping() { - override fun getSession(module: KtModule): LLFirSession = - map.getValue(module) - - override fun getAllSessions(): Collection = - map.values -} - -internal class KtModuleToSessionMappingByWeakValueMapImpl( - initialMap: Map -) : KtModuleToSessionMapping() { - private val softValuesMap = initialMap.entries.associate { (key, value) -> key to WeakReference(value) } - - override fun getSession(module: KtModule): LLFirSession { - val softReference = softValuesMap.getValue(module) - return softReference.get() - ?: error("soft reference for $module was invalidated") - } - - override fun getAllSessions(): Collection = - softValuesMap.keys.map { getSession(it) } -} \ No newline at end of file diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirSessionProviderStorage.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirSessionProviderStorage.kt deleted file mode 100644 index 45c2c28fb22..00000000000 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirSessionProviderStorage.kt +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions - -import com.intellij.openapi.project.Project -import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirGlobalResolveComponents -import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirBuiltinsSessionFactory -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.addValueFor -import org.jetbrains.kotlin.analysis.project.structure.* -import java.lang.ref.SoftReference - -class LLFirSessionProviderStorage(val project: Project) { - private val sourceAsUseSiteSessionCache = LLFirSessionsCache() - private val libraryAsUseSiteSessionCache = LLFirSessionsCache() - private val notUnderContentRootSessionCache = LLFirSessionsCache() - - private val builtInsSessionFactory = LLFirBuiltinsSessionFactory.getInstance(project) - - private val globalComponents = LLFirGlobalResolveComponents(project) - - fun getSessionProvider(useSiteKtModule: KtModule): LLFirSessionProvider = when (useSiteKtModule) { - is KtSourceModule -> { - createSessionProviderForSourceSession(useSiteKtModule) - } - - is KtLibraryModule, is KtLibrarySourceModule -> { - createSessionProviderForLibraryOrLibrarySource(useSiteKtModule) - } - - is KtScriptModule -> { - createSessionProviderForScriptSession(useSiteKtModule) - } - - is KtNotUnderContentRootModule -> { - createSessionProviderForNotUnderContentRootSession(useSiteKtModule) - } - - else -> error("Unexpected ${useSiteKtModule::class.simpleName}") - } - - private fun createSessionProviderForSourceSession(useSiteKtModule: KtSourceModule): LLFirSessionProvider { - val (sessions, session) = sourceAsUseSiteSessionCache.withMappings { mappings -> - val sessions = mutableMapOf().apply { putAll(mappings) } - val session = LLFirSessionFactory.createSourcesSession(useSiteKtModule, globalComponents, sessions) - sessions to session - } - return LLFirSessionProvider(project, session, KtModuleToSessionMappingByWeakValueMapImpl(sessions)) - } - - - private fun createSessionProviderForLibraryOrLibrarySource(useSiteKtModule: KtModule): LLFirSessionProvider { - val (sessions, session) = libraryAsUseSiteSessionCache.withMappings { mappings -> - val sessions = mutableMapOf().apply { putAll(mappings) } - val session = LLFirSessionFactory.createLibraryOrLibrarySourceResolvableSession( - useSiteKtModule, - globalComponents, - builtInsSessionFactory.getBuiltinsSession(useSiteKtModule.platform), - sessions - ) - sessions to session - } - return LLFirSessionProvider(project, session, KtModuleToSessionMappingByWeakValueMapImpl(sessions)) - } - - private fun createSessionProviderForScriptSession(useSiteKtModule: KtScriptModule): LLFirSessionProvider { - val (sessions, session) = sourceAsUseSiteSessionCache.withMappings { mappings -> - val sessions = mutableMapOf().apply { putAll(mappings) } - val session = LLFirSessionFactory.createScriptSession( - useSiteKtModule, - sessions - ) - sessions to session - } - return LLFirSessionProvider(project, session, KtModuleToSessionMappingByWeakValueMapImpl(sessions)) - } - - private fun createSessionProviderForNotUnderContentRootSession(useSiteKtModule: KtNotUnderContentRootModule): LLFirSessionProvider { - val (sessions, session) = notUnderContentRootSessionCache.withMappings { mappings -> - val sessions = mutableMapOf().apply { putAll(mappings) } - val session = LLFirSessionFactory.createNotUnderContentRootResolvableSession(useSiteKtModule, sessions) - sessions to session - } - return LLFirSessionProvider(project, session, KtModuleToSessionMappingByWeakValueMapImpl(sessions)) - } -} - -private class LLFirSessionsCache { - @Volatile - private var mappings: Map> = emptyMap() - - inline fun withMappings( - action: (Map) -> Pair, R> - ): Pair, R> { - val (newMappings, result) = action(getSessions().mapValues { it.value }) - mappings = newMappings.mapValues { SoftReference(it.value) } - return newMappings to result - } - - private fun getSessions(): Map = buildMap { - // Initially, all sessions are considered to be valid ('true'). - val sessions = LinkedHashMap().apply { - for (sessionRef in mappings.values) { - val session = sessionRef.get() ?: continue - put(session, true) - } - } - - val reversedDependencies = buildMap { - for (session in sessions.keys) { - if (session.isValid) { - val module = session.ktModule - for (dependency in module.directRegularDependencies) { - addValueFor(dependency, module) - } - } - } - } - - fun invalidateRecursively(session: LLFirSession) { - // Invalidate all dependent sessions only if we didn't that before - if (sessions.put(session, false) == true) { - for (dependentModule in reversedDependencies[session.ktModule].orEmpty()) { - val dependentSession = mappings[dependentModule]?.get() ?: continue - invalidateRecursively(dependentSession) - } - } - } - - for (session in sessions.keys) { - if (session.isValid) continue - invalidateRecursively(session) - } - - return buildMap { - for ((session, isValid) in sessions) { - if (!isValid) continue - put(session.ktModule, session) - } - } - } -} \ No newline at end of file diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirSourcesSession.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirSourcesSession.kt index b39ab161a2a..af0a43b5877 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirSourcesSession.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirSourcesSession.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions +import com.intellij.openapi.util.ModificationTracker import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirModuleResolveComponents import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule import org.jetbrains.kotlin.fir.BuiltinTypes @@ -12,6 +13,7 @@ import org.jetbrains.kotlin.fir.PrivateSessionConstructor internal class LLFirSourcesSession @PrivateSessionConstructor constructor( ktModule: KtSourceModule, + dependencyTracker: ModificationTracker, override val moduleComponents: LLFirModuleResolveComponents, builtinTypes: BuiltinTypes, -) : LLFirResolvableModuleSession(ktModule, builtinTypes) +) : LLFirResolvableModuleSession(ktModule, dependencyTracker, builtinTypes) diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirLibraryOrLibrarySourceResolvableResolveSession.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirLibraryOrLibrarySourceResolvableResolveSession.kt index 56689b63015..58ef51cbd48 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirLibraryOrLibrarySourceResolvableResolveSession.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirLibraryOrLibrarySourceResolvableResolveSession.kt @@ -5,23 +5,17 @@ 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.LLFirGlobalResolveComponents import org.jetbrains.kotlin.analysis.low.level.api.fir.api.DiagnosticCheckerFilter -import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSessionProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirLibraryOrLibrarySourceResolvableModuleSession +import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSession 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 LLFirLibraryOrLibrarySourceResolvableResolveSession( - override val globalComponents: LLFirGlobalResolveComponents, - override val project: Project, - override val useSiteKtModule: KtModule, - sessionProvider: LLFirSessionProvider, -) : LLFirResolvableResolveSession(sessionProvider) { + useSiteFirSession: LLFirSession +) : LLFirResolvableResolveSession(useSiteFirSession) { override fun getDiagnostics(element: KtElement, filter: DiagnosticCheckerFilter): List = emptyList() @@ -30,10 +24,7 @@ internal class LLFirLibraryOrLibrarySourceResolvableResolveSession( override fun getModuleKind(module: KtModule): ModuleKind { LLFirLibraryOrLibrarySourceResolvableModuleSession.checkIsValidKtModule(module) - return when { - module == this.useSiteKtModule -> ModuleKind.RESOLVABLE_MODULE - else -> ModuleKind.BINARY_MODULE - } + return if (module == useSiteKtModule) ModuleKind.RESOLVABLE_MODULE else ModuleKind.BINARY_MODULE } } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirNotUnderContentRootResolveSession.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirNotUnderContentRootResolveSession.kt index f26403cf6fa..cd329c54d59 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirNotUnderContentRootResolveSession.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirNotUnderContentRootResolveSession.kt @@ -5,21 +5,16 @@ 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.LLFirGlobalResolveComponents import org.jetbrains.kotlin.analysis.low.level.api.fir.api.DiagnosticCheckerFilter -import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSessionProvider +import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSession 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 LLFirNotUnderContentRootResolveSession( - override val globalComponents: LLFirGlobalResolveComponents, - override val project: Project, - override val useSiteKtModule: KtModule, - sessionProvider: LLFirSessionProvider, -) : LLFirResolvableResolveSession(sessionProvider) { + useSiteFirSession: LLFirSession +) : LLFirResolvableResolveSession(useSiteFirSession) { override fun getDiagnostics(element: KtElement, filter: DiagnosticCheckerFilter): List = emptyList() diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirResolvableResolveSession.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirResolvableResolveSession.kt index 568f8a9403d..1161fc5e0e8 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirResolvableResolveSession.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirResolvableResolveSession.kt @@ -5,14 +5,15 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.state -import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirGlobalResolveComponents +import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.project.Project import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirModuleResolveComponents import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession 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.sessions.LLFirResolvableModuleSession import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSession -import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSessionProvider +import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSessionCache import org.jetbrains.kotlin.analysis.low.level.api.fir.util.FirDeclarationForCompiledElementSearcher import org.jetbrains.kotlin.analysis.low.level.api.fir.util.errorWithFirSpecificEntries import org.jetbrains.kotlin.analysis.low.level.api.fir.util.findSourceNonLocalFirDeclaration @@ -40,18 +41,32 @@ import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtFile +@Suppress("PrivatePropertyName") +private val LOG = Logger.getInstance(LLFirResolvableResolveSession::class.java) + internal abstract class LLFirResolvableResolveSession( - private val sessionProvider: LLFirSessionProvider, + final override val useSiteFirSession: LLFirSession ) : LLFirResolveSession() { - abstract val globalComponents: LLFirGlobalResolveComponents + final override val useSiteKtModule: KtModule + get() = useSiteFirSession.ktModule - final override val useSiteFirSession = sessionProvider.rootModuleSession + final override val project: Project + get() = useSiteKtModule.project - override fun getSessionFor(module: KtModule): LLFirSession = - sessionProvider.getSession(module) + override fun getSessionFor(module: KtModule): LLFirSession { + LOG.assertTrue(useSiteFirSession.isValid, "Use-site session is invalid") - protected open fun getResolvableSessionFor(module: KtModule): LLFirResolvableModuleSession = - sessionProvider.getResolvableSession(module) + if (module == useSiteFirSession.ktModule) { + return useSiteFirSession + } + + val cache = LLFirSessionCache.getInstance(module.project) + return cache.getSession(module, preferBinary = true) + } + + protected open fun getResolvableSessionFor(module: KtModule): LLFirResolvableModuleSession { + return getSessionFor(module) as LLFirResolvableModuleSession + } override fun getScopeSessionFor(firSession: FirSession): ScopeSession { requireIsInstance(firSession) diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirScriptResolveSession.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirScriptResolveSession.kt index c746009ea0e..4d77f7ea962 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirScriptResolveSession.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirScriptResolveSession.kt @@ -5,12 +5,6 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.state -import com.intellij.openapi.components.ServiceManager -import com.intellij.openapi.project.Project -import com.intellij.util.containers.CollectionFactory -import com.intellij.util.containers.FactoryMap -import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirGlobalResolveComponents -import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirResolveSessionService import org.jetbrains.kotlin.analysis.low.level.api.fir.api.DiagnosticCheckerFilter import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.* import org.jetbrains.kotlin.analysis.project.structure.* @@ -20,40 +14,8 @@ import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtFile internal class LLFirScriptResolveSession( - override val globalComponents: LLFirGlobalResolveComponents, - override val project: Project, - override val useSiteKtModule: KtModule, - sessionProvider: LLFirSessionProvider -) : LLFirResolvableResolveSession(sessionProvider) { - private val dependencyCache: Map = - FactoryMap.createMap(::createDependencySession, CollectionFactory::createConcurrentSoftValueMap) - - private fun createDependencySession(module: KtModule): LLFirSession { - when (module) { - is KtScriptDependencyModule -> { - val resolveSessionService = ServiceManager.getService(project, LLFirResolveSessionService::class.java) - return resolveSessionService.getFirResolveSession(module).useSiteFirSession - } - else -> error("Unsupported script dependency session type: ${module.javaClass.name}") - } - } - - override fun getSessionFor(module: KtModule): LLFirSession { - if (module is KtScriptDependencyModule) { - return dependencyCache.getValue(module) - } - - return super.getSessionFor(module) - } - - override fun getResolvableSessionFor(module: KtModule): LLFirResolvableModuleSession { - if (module is KtScriptDependencyModule && module is KtLibrarySourceModule) { - return dependencyCache[module] as LLFirResolvableModuleSession - } - - return super.getResolvableSessionFor(module) - } - + useSiteFirSession: LLFirSession +) : LLFirResolvableResolveSession(useSiteFirSession) { override fun getDiagnostics(element: KtElement, filter: DiagnosticCheckerFilter): List { val moduleComponents = getModuleComponentsForElement(element) return moduleComponents.diagnosticsCollector.getDiagnosticsFor(element, filter) diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirSourceResolveSession.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirSourceResolveSession.kt index 6e2de3cbfca..3beb09b99dd 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirSourceResolveSession.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/state/LLFirSourceResolveSession.kt @@ -5,10 +5,8 @@ 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.LLFirGlobalResolveComponents import org.jetbrains.kotlin.analysis.low.level.api.fir.api.DiagnosticCheckerFilter -import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSessionProvider +import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSession import org.jetbrains.kotlin.analysis.project.structure.KtBuiltinsModule import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule import org.jetbrains.kotlin.analysis.project.structure.KtModule @@ -19,11 +17,8 @@ import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtFile internal class LLFirSourceResolveSession( - override val globalComponents: LLFirGlobalResolveComponents, - override val project: Project, - override val useSiteKtModule: KtModule, - sessionProvider: LLFirSessionProvider, -) : LLFirResolvableResolveSession(sessionProvider) { + useSiteFirSession: LLFirSession +) : LLFirResolvableResolveSession(useSiteFirSession) { override fun getDiagnostics(element: KtElement, filter: DiagnosticCheckerFilter): List { val moduleComponents = getModuleComponentsForElement(element) return moduleComponents.diagnosticsCollector.getDiagnosticsFor(element, filter) diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/utils.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/utils.kt index 1095221d245..79d30469389 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/utils.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/utils.kt @@ -6,7 +6,6 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.util import com.intellij.openapi.progress.ProgressManager -import com.intellij.openapi.util.ModificationTracker import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirResolvableModuleSession import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.declarations.FirDeclaration @@ -73,9 +72,4 @@ internal val FirDeclaration.containingKtFileIfAny: KtFile? internal fun KtDeclaration.isNonAnonymousClassOrObject() = this is KtClassOrObject - && !this.isObjectLiteral() - - -internal fun BooleanModificationTracker(provider: () -> Boolean): ModificationTracker { - return ModificationTracker { if (provider()) 0 else 1 } -} \ No newline at end of file + && !this.isObjectLiteral() \ No newline at end of file diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/AbstractCompilerBasedTestForFir.kt b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/AbstractCompilerBasedTestForFir.kt index fb480ac6004..fb0a9dacca0 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/AbstractCompilerBasedTestForFir.kt +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/AbstractCompilerBasedTestForFir.kt @@ -6,9 +6,9 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.compiler.based +import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirResolveSessionService import org.jetbrains.kotlin.analysis.low.level.api.fir.api.DiagnosticCheckerFilter import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirFile -import org.jetbrains.kotlin.analysis.low.level.api.fir.createFirResolveSessionForNoCaching import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.FirLowLevelCompilerBasedTestConfigurator import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.LLFirLazyTransformer import org.jetbrains.kotlin.analysis.test.framework.AbstractCompilerBasedTest @@ -19,7 +19,6 @@ import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.platform.jvm.JvmPlatforms import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.test.FirParser -import org.jetbrains.kotlin.test.TestInfrastructureInternals import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder import org.jetbrains.kotlin.test.builders.firHandlersStep import org.jetbrains.kotlin.test.builders.testConfiguration @@ -86,8 +85,8 @@ abstract class AbstractCompilerBasedTestForFir : AbstractCompilerBasedTest() { val moduleInfoProvider = testServices.ktModuleProvider val ktModule = moduleInfoProvider.getModule(module.name) as KtSourceModuleByCompilerConfiguration - val project = testServices.compilerConfigurationProvider.getProject(module) - val firResolveSession = createFirResolveSessionForNoCaching(ktModule, project) + val project = ktModule.project + val firResolveSession = LLFirResolveSessionService.getInstance(project).getFirResolveSessionNoCaching(ktModule) val allFirFiles = module.files.filter { it.isKtFile }.zip( diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/SealedClassesInheritorsCaclulatorPreAnalysisHandler.kt b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/SealedClassesInheritorsCaclulatorPreAnalysisHandler.kt index f4864e0ecfa..d47f4e66f9c 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/SealedClassesInheritorsCaclulatorPreAnalysisHandler.kt +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/compiler/based/SealedClassesInheritorsCaclulatorPreAnalysisHandler.kt @@ -5,10 +5,10 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.compiler.based +import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirResolveSessionService import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirFile import org.jetbrains.kotlin.analysis.low.level.api.fir.api.services.FirSealedClassInheritorsProcessorFactory -import org.jetbrains.kotlin.analysis.low.level.api.fir.createFirResolveSessionForNoCaching import org.jetbrains.kotlin.analysis.low.level.api.fir.services.LLFirSealedClassInheritorsProcessorFactoryForTests import org.jetbrains.kotlin.analysis.project.structure.ProjectStructureProvider import org.jetbrains.kotlin.analysis.test.framework.project.structure.ktModuleProvider @@ -51,7 +51,7 @@ class SealedClassesInheritorsCaclulatorPreAnalysisHandler( val ktModuleProvider = project.getService(ProjectStructureProvider::class.java) val ktModule = ktFiles.map(ktModuleProvider::getKtModuleForKtElement).distinct().single() - val tmpFirResolveSession = createFirResolveSessionForNoCaching(ktModule, project) + val tmpFirResolveSession = LLFirResolveSessionService.getInstance(project).getFirResolveSessionNoCaching(ktModule) val firFiles = ktFiles.map { it.getOrBuildFirFile(tmpFirResolveSession) } val sealedInheritors = collectSealedClassInheritors(firFiles, tmpFirResolveSession) val provider = diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/firTestUtils.kt b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/firTestUtils.kt index aa0dd4c8d62..3a1ef43ca7b 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/firTestUtils.kt +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/firTestUtils.kt @@ -42,8 +42,9 @@ internal fun FirDeclaration.name(): String = symbol.name() internal inline fun resolveWithClearCaches(context: KtElement, action: (LLFirResolveSession) -> R): R { val project = context.project - val firResolveSession = createFirResolveSessionForNoCaching(context.getKtModule(project), project) - return action(firResolveSession) + val module = context.getKtModule(project) + val resolveSession = LLFirResolveSessionService.getInstance(project).getFirResolveSessionNoCaching(module) + return action(resolveSession) } internal val LLFirResolveSession.isSourceSession: Boolean diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/test/base/AnalysisApiFirTestServiceRegistrar.kt b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/test/base/AnalysisApiFirTestServiceRegistrar.kt index 2a02c485931..9cb13988726 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/test/base/AnalysisApiFirTestServiceRegistrar.kt +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/test/base/AnalysisApiFirTestServiceRegistrar.kt @@ -13,13 +13,14 @@ import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSessionProvider import org.jetbrains.kotlin.analysis.api.fir.references.ReadWriteAccessCheckerFirImpl import org.jetbrains.kotlin.analysis.api.session.KtAnalysisSessionProvider +import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirGlobalResolveComponents import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirResolveSessionService import org.jetbrains.kotlin.analysis.low.level.api.fir.api.services.FirSealedClassInheritorsProcessorFactory import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirBuiltinsSessionFactory -import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirLibrarySessionFactory import org.jetbrains.kotlin.analysis.low.level.api.fir.services.KtCompilerPluginsProviderForTests import org.jetbrains.kotlin.analysis.low.level.api.fir.services.LLFirSealedClassInheritorsProcessorFactoryForTests import org.jetbrains.kotlin.analysis.low.level.api.fir.services.PackagePartProviderTestImpl +import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSessionCache import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSessionConfigurator import org.jetbrains.kotlin.analysis.project.structure.KtCompilerPluginsProvider import org.jetbrains.kotlin.analysis.providers.PackagePartProviderFactory @@ -49,7 +50,8 @@ object AnalysisApiFirTestServiceRegistrar : AnalysisApiTestServiceRegistrar() { registerService(KtAnalysisSessionProvider::class.java, KtFirAnalysisSessionProvider(this)) registerService(FirSealedClassInheritorsProcessorFactory::class.java, LLFirSealedClassInheritorsProcessorFactoryForTests()) registerService(LLFirResolveSessionService::class.java) - registerService(LLFirLibrarySessionFactory::class.java) + registerService(LLFirSessionCache::class.java) + registerService(LLFirGlobalResolveComponents::class.java) registerService(LLFirBuiltinsSessionFactory::class.java) registerService(PackagePartProviderFactory::class.java, PackagePartProviderTestImpl(testServices))