[LL API] Refactor session caches

Use 'CachedValue' and dependency handling with 'ModificationTracker'
for dependent session invalidation.
This commit is contained in:
Yan Zhulanow
2023-03-10 16:18:32 +09:00
committed by Space Team
parent c3b2d9dc5b
commit 5c9a9913db
31 changed files with 372 additions and 622 deletions
@@ -6,21 +6,21 @@
package org.jetbrains.kotlin.analysis.api.standalone; package org.jetbrains.kotlin.analysis.api.standalone;
import com.intellij.mock.MockProject; 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.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 { class RegisterComponentService {
static void registerLLFirLibrarySessionFactory(MockProject project) { static void registerLLFirSessionCache(MockProject project) {
project.registerService( project.registerService(LLFirSessionCache.class, new LLFirSessionCache(project));
LLFirLibrarySessionFactory.class, }
new LLFirLibrarySessionFactory(project)
); static void registerLLFirGlobalResolveComponents(MockProject project) {
project.registerService(LLFirGlobalResolveComponents.class, new LLFirGlobalResolveComponents(project));
} }
static void registerLLFirResolveSessionService(MockProject project) { static void registerLLFirResolveSessionService(MockProject project) {
project.registerService( project.registerService(LLFirResolveSessionService.class, new LLFirResolveSessionService(project));
LLFirResolveSessionService.class,
new LLFirResolveSessionService(project)
);
} }
} }
@@ -142,7 +142,8 @@ public class StandaloneAnalysisAPISessionBuilder(
} }
) )
registerService(LLFirBuiltinsSessionFactory::class.java, LLFirBuiltinsSessionFactory(this)) registerService(LLFirBuiltinsSessionFactory::class.java, LLFirBuiltinsSessionFactory(this))
RegisterComponentService.registerLLFirLibrarySessionFactory(this) RegisterComponentService.registerLLFirSessionCache(this)
RegisterComponentService.registerLLFirGlobalResolveComponents(this)
registerService(KotlinReferenceProvidersService::class.java, HLApiReferenceProviderService::class.java) registerService(KotlinReferenceProvidersService::class.java, HLApiReferenceProviderService::class.java)
registerService(KotlinReferenceProviderContributor::class.java, KotlinFirReferenceContributor::class.java) registerService(KotlinReferenceProviderContributor::class.java, KotlinFirReferenceContributor::class.java)
@@ -6,15 +6,39 @@
package org.jetbrains.kotlin.analysis.utils.trackers package org.jetbrains.kotlin.analysis.utils.trackers
import com.intellij.openapi.util.ModificationTracker import com.intellij.openapi.util.ModificationTracker
import java.util.*
import kotlin.collections.ArrayList
public class CompositeModificationTracker private constructor(private val trackers: List<ModificationTracker>) : ModificationTracker { public class CompositeModificationTracker private constructor(private val trackers: List<ModificationTracker>) : ModificationTracker {
override fun getModificationCount(): Long = trackers.sumOf { it.modificationCount } override fun getModificationCount(): Long = trackers.sumOf { it.modificationCount }
public companion object { public companion object {
public fun create(trackers: List<ModificationTracker>): ModificationTracker = when (trackers.size) { public fun create(trackers: List<ModificationTracker>): ModificationTracker {
0 -> ModificationTracker.NEVER_CHANGED return when (trackers.size) {
1 -> trackers.single() 0 -> ModificationTracker.NEVER_CHANGED
else -> CompositeModificationTracker(trackers) 1 -> trackers.single()
else -> CompositeModificationTracker(trackers)
}
}
public fun createFlattened(trackers: List<ModificationTracker>): ModificationTracker {
val map = IdentityHashMap<ModificationTracker, Boolean>()
val flattened = ArrayList<ModificationTracker>()
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)
} }
} }
} }
@@ -7,11 +7,14 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLockProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirLockProvider
import org.jetbrains.kotlin.analysis.project.structure.KtModule
internal class LLFirGlobalResolveComponents( internal class LLFirGlobalResolveComponents(val project: Project) {
val project: Project, companion object {
) { fun getInstance(project: Project): LLFirGlobalResolveComponents {
return project.getService(LLFirGlobalResolveComponents::class.java)
}
}
val phaseRunner: LLFirPhaseRunner = LLFirPhaseRunner() val phaseRunner: LLFirPhaseRunner = LLFirPhaseRunner()
val lockProvider: LLFirLockProvider = LLFirLockProvider() val lockProvider: LLFirLockProvider = LLFirLockProvider()
} }
@@ -30,7 +30,6 @@ import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import java.util.concurrent.ConcurrentHashMap
internal class LLFirResolveSessionDepended( internal class LLFirResolveSessionDepended(
val originalFirResolveSession: LLFirResolvableResolveSession, val originalFirResolveSession: LLFirResolvableResolveSession,
@@ -7,10 +7,9 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir
import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project 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.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.LLFirLibraryOrLibrarySourceResolvableResolveSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirNotUnderContentRootResolveSession import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirNotUnderContentRootResolveSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirResolvableResolveSession 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.state.LLFirSourceResolveSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.errorWithFirSpecificEntries import org.jetbrains.kotlin.analysis.low.level.api.fir.util.errorWithFirSpecificEntries
import org.jetbrains.kotlin.analysis.project.structure.* 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) { class LLFirResolveSessionService(project: Project) {
private val sessionProviderStorage = LLFirSessionProviderStorage(project) private val cache = LLFirSessionCache.getInstance(project)
private val cache = SoftCachedMap.create<KtModule, LLFirResolvableResolveSession>( fun getFirResolveSession(module: KtModule): LLFirResolveSession {
project, return create(module, cache::getSession)
SoftCachedMap.Kind.STRONG_KEYS_SOFT_VALUES, }
listOf(
ProjectRootModificationTracker.getInstance(project),
project.createProjectWideOutOfBlockModificationTracker(),
)
)
fun getFirResolveSession(module: KtModule): LLFirResolvableResolveSession { fun getFirResolveSessionNoCaching(module: KtModule): LLFirResolveSession {
return cache.getOrPut(module) { return create(module, cache::getSessionNoCaching)
createFirResolveSessionFor(module, sessionProviderStorage) }
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 { companion object {
fun getInstance(project: Project): LLFirResolveSessionService = fun getInstance(project: Project): LLFirResolveSessionService =
ServiceManager.getService(project, LLFirResolveSessionService::class.java) 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)
)
}
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.api
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.util.PsiTreeUtil 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.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.LLFirResolveSessionDepended
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FileTowerProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FileTowerProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirTowerContextProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirTowerContextProvider
@@ -259,7 +260,9 @@ object LowLevelFirApiFacadeForResolveOnAir {
val isInBodyReplacement = isInBodyReplacement(nonLocalDeclaration, replacement) 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) { val copiedFirDeclaration = if (isInBodyReplacement) {
when (originalDeclaration) { when (originalDeclaration) {
is FirSimpleFunction -> is FirSimpleFunction ->
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure package org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure
import com.intellij.openapi.project.Project 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.LLFirBuiltinSymbolProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLFirBuiltinsAndCloneableSessionProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLFirBuiltinsAndCloneableSessionProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirBuiltinsAndCloneableSession 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 import java.util.concurrent.ConcurrentHashMap
@OptIn(PrivateSessionConstructor::class, SessionConfiguration::class) @OptIn(PrivateSessionConstructor::class, SessionConfiguration::class)
class LLFirBuiltinsSessionFactory( class LLFirBuiltinsSessionFactory(private val project: Project) {
private val project: Project,
) {
private val builtInTypes = BuiltinTypes() // TODO should be platform-specific private val builtInTypes = BuiltinTypes() // TODO should be platform-specific
private val builtinsAndCloneableSession = ConcurrentHashMap<TargetPlatform, LLFirBuiltinsAndCloneableSession>() private val builtinsAndCloneableSession = ConcurrentHashMap<TargetPlatform, LLFirBuiltinsAndCloneableSession>()
@@ -49,10 +48,11 @@ class LLFirBuiltinsSessionFactory(
private fun createBuiltinsAndCloneableSession(platform: TargetPlatform): LLFirBuiltinsAndCloneableSession { private fun createBuiltinsAndCloneableSession(platform: TargetPlatform): LLFirBuiltinsAndCloneableSession {
val builtinsModule = KtBuiltinsModule(platform, platform.getAnalyzerServices(), project) val builtinsModule = KtBuiltinsModule(platform, platform.getAnalyzerServices(), project)
return LLFirBuiltinsAndCloneableSession(builtinsModule, builtInTypes).apply session@{
val moduleData = LLFirModuleData(builtinsModule).apply { val session = LLFirBuiltinsAndCloneableSession(builtinsModule, ModificationTracker.NEVER_CHANGED, builtInTypes)
bindSession(this@session) val moduleData = LLFirModuleData(builtinsModule).apply { bindSession(session) }
}
return session.apply {
registerIdeComponents(project) registerIdeComponents(project)
register(FirLazyDeclarationResolver::class, FirDummyCompilerLazyDeclarationResolver) register(FirLazyDeclarationResolver::class, FirDummyCompilerLazyDeclarationResolver)
registerCommonComponents(LanguageVersionSettingsImpl.DEFAULT/*TODO*/) registerCommonComponents(LanguageVersionSettingsImpl.DEFAULT/*TODO*/)
@@ -62,10 +62,11 @@ class LLFirBuiltinsSessionFactory(
val kotlinScopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped) val kotlinScopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped)
register(FirKotlinScopeProvider::class, kotlinScopeProvider) register(FirKotlinScopeProvider::class, kotlinScopeProvider)
val symbolProvider = createCompositeSymbolProvider(this) { val symbolProvider = createCompositeSymbolProvider(this) {
add(LLFirBuiltinSymbolProvider(this@session, moduleData, kotlinScopeProvider)) add(LLFirBuiltinSymbolProvider(session, moduleData, kotlinScopeProvider))
add(FirExtensionSyntheticFunctionInterfaceProvider(this@session, moduleData, kotlinScopeProvider)) add(FirExtensionSyntheticFunctionInterfaceProvider(session, moduleData, kotlinScopeProvider))
add(FirCloneableSymbolProvider(this@session, moduleData, kotlinScopeProvider)) add(FirCloneableSymbolProvider(session, moduleData, kotlinScopeProvider))
} }
register(FirSymbolProvider::class, symbolProvider) register(FirSymbolProvider::class, symbolProvider)
@@ -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<KtModule, LLFirSession>): LLFirLibrarySession {
return sessionsCache.getOrPut(ktBinaryModule) {
createModuleLibrariesSession(ktBinaryModule, sessionsCache)
} as LLFirLibrarySession
}
private fun createModuleLibrariesSession(
ktLibraryModule: KtBinaryModule,
sessionsCache: MutableMap<KtModule, LLFirSession>,
): 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)
}
}
@@ -5,11 +5,13 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions 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.analysis.project.structure.KtModule
import org.jetbrains.kotlin.fir.BuiltinTypes import org.jetbrains.kotlin.fir.BuiltinTypes
import org.jetbrains.kotlin.fir.PrivateSessionConstructor import org.jetbrains.kotlin.fir.PrivateSessionConstructor
class LLFirBuiltinsAndCloneableSession @PrivateSessionConstructor constructor( class LLFirBuiltinsAndCloneableSession @PrivateSessionConstructor constructor(
ktModule: KtModule, ktModule: KtModule,
dependencyTracker: ModificationTracker,
builtinTypes: BuiltinTypes, builtinTypes: BuiltinTypes,
) : LLFirLibraryLikeSession(ktModule, builtinTypes) ) : LLFirLibraryLikeSession(ktModule, dependencyTracker, builtinTypes)
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions 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.analysis.project.structure.KtModule
import org.jetbrains.kotlin.fir.BuiltinTypes import org.jetbrains.kotlin.fir.BuiltinTypes
import org.jetbrains.kotlin.fir.PrivateSessionConstructor import org.jetbrains.kotlin.fir.PrivateSessionConstructor
@@ -14,5 +15,6 @@ import org.jetbrains.kotlin.fir.PrivateSessionConstructor
*/ */
internal class LLFirLibrarySession @PrivateSessionConstructor constructor( internal class LLFirLibrarySession @PrivateSessionConstructor constructor(
ktModule: KtModule, ktModule: KtModule,
dependencyTracker: ModificationTracker,
builtinTypes: BuiltinTypes, builtinTypes: BuiltinTypes,
) : LLFirLibraryLikeSession(ktModule, builtinTypes) ) : LLFirLibraryLikeSession(ktModule, dependencyTracker, builtinTypes)
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions 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.low.level.api.fir.util.LLFirScopeSessionProvider
import org.jetbrains.kotlin.analysis.project.structure.KtModule import org.jetbrains.kotlin.analysis.project.structure.KtModule
import org.jetbrains.kotlin.fir.BuiltinTypes import org.jetbrains.kotlin.fir.BuiltinTypes
@@ -12,8 +13,9 @@ import org.jetbrains.kotlin.fir.resolve.ScopeSession
abstract class LLFirLibraryLikeSession( abstract class LLFirLibraryLikeSession(
ktModule: KtModule, ktModule: KtModule,
dependencyTracker: ModificationTracker,
builtinTypes: BuiltinTypes, builtinTypes: BuiltinTypes,
) : LLFirSession(ktModule, builtinTypes, Kind.Library) { ) : LLFirSession(ktModule, dependencyTracker, builtinTypes, Kind.Library) {
private val scopeSessionProvider = LLFirScopeSessionProvider.create(project, invalidationTrackers = emptyList()) private val scopeSessionProvider = LLFirScopeSessionProvider.create(project, invalidationTrackers = emptyList())
override fun getScopeSession(): ScopeSession { override fun getScopeSession(): ScopeSession {
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions 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.low.level.api.fir.LLFirModuleResolveComponents
import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule
import org.jetbrains.kotlin.analysis.project.structure.KtLibrarySourceModule import org.jetbrains.kotlin.analysis.project.structure.KtLibrarySourceModule
@@ -13,9 +14,10 @@ import org.jetbrains.kotlin.fir.BuiltinTypes
internal class LLFirLibraryOrLibrarySourceResolvableModuleSession( internal class LLFirLibraryOrLibrarySourceResolvableModuleSession(
ktModule: KtModule, ktModule: KtModule,
dependencyTracker: ModificationTracker,
override val moduleComponents: LLFirModuleResolveComponents, override val moduleComponents: LLFirModuleResolveComponents,
builtinTypes: BuiltinTypes, builtinTypes: BuiltinTypes,
) : LLFirResolvableModuleSession(ktModule, builtinTypes) { ) : LLFirResolvableModuleSession(ktModule, dependencyTracker, builtinTypes) {
init { init {
checkIsValidKtModule(ktModule) checkIsValidKtModule(ktModule)
} }
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions 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.low.level.api.fir.LLFirModuleResolveComponents
import org.jetbrains.kotlin.analysis.project.structure.KtNotUnderContentRootModule import org.jetbrains.kotlin.analysis.project.structure.KtNotUnderContentRootModule
import org.jetbrains.kotlin.fir.BuiltinTypes import org.jetbrains.kotlin.fir.BuiltinTypes
@@ -12,6 +13,7 @@ import org.jetbrains.kotlin.fir.PrivateSessionConstructor
internal class LLFirNonUnderContentRootResolvableModuleSession @PrivateSessionConstructor constructor( internal class LLFirNonUnderContentRootResolvableModuleSession @PrivateSessionConstructor constructor(
ktModule: KtNotUnderContentRootModule, ktModule: KtNotUnderContentRootModule,
dependencyTracker: ModificationTracker,
override val moduleComponents: LLFirModuleResolveComponents, override val moduleComponents: LLFirModuleResolveComponents,
builtinTypes: BuiltinTypes, builtinTypes: BuiltinTypes,
) : LLFirResolvableModuleSession(ktModule, builtinTypes) ) : LLFirResolvableModuleSession(ktModule, dependencyTracker, builtinTypes)
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions 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.low.level.api.fir.LLFirModuleResolveComponents
import org.jetbrains.kotlin.analysis.project.structure.KtModule import org.jetbrains.kotlin.analysis.project.structure.KtModule
import org.jetbrains.kotlin.fir.BuiltinTypes import org.jetbrains.kotlin.fir.BuiltinTypes
@@ -14,8 +15,9 @@ import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
abstract class LLFirResolvableModuleSession( abstract class LLFirResolvableModuleSession(
ktModule: KtModule, ktModule: KtModule,
dependencyTracker: ModificationTracker,
builtinTypes: BuiltinTypes builtinTypes: BuiltinTypes
) : LLFirModuleSession(ktModule, builtinTypes, Kind.Source) { ) : LLFirModuleSession(ktModule, dependencyTracker, builtinTypes, Kind.Source) {
internal abstract val moduleComponents: LLFirModuleResolveComponents internal abstract val moduleComponents: LLFirModuleResolveComponents
final override fun getScopeSession(): ScopeSession { final override fun getScopeSession(): ScopeSession {
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions 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.low.level.api.fir.LLFirModuleResolveComponents
import org.jetbrains.kotlin.analysis.project.structure.KtScriptModule import org.jetbrains.kotlin.analysis.project.structure.KtScriptModule
import org.jetbrains.kotlin.fir.BuiltinTypes import org.jetbrains.kotlin.fir.BuiltinTypes
@@ -12,6 +13,7 @@ import org.jetbrains.kotlin.fir.PrivateSessionConstructor
internal class LLFirScriptSession @PrivateSessionConstructor constructor( internal class LLFirScriptSession @PrivateSessionConstructor constructor(
ktModule: KtScriptModule, ktModule: KtScriptModule,
dependencyTracker: ModificationTracker,
override val moduleComponents: LLFirModuleResolveComponents, override val moduleComponents: LLFirModuleResolveComponents,
builtinTypes: BuiltinTypes builtinTypes: BuiltinTypes
) : LLFirResolvableModuleSession(ktModule, builtinTypes) ) : LLFirResolvableModuleSession(ktModule, dependencyTracker, builtinTypes)
@@ -7,9 +7,11 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.util.ModificationTracker import 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.project.structure.*
import org.jetbrains.kotlin.analysis.providers.KotlinModificationTrackerFactory 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.analysis.utils.trackers.CompositeModificationTracker
import org.jetbrains.kotlin.fir.BuiltinTypes import org.jetbrains.kotlin.fir.BuiltinTypes
import org.jetbrains.kotlin.fir.FirElementWithResolvePhase import org.jetbrains.kotlin.fir.FirElementWithResolvePhase
@@ -22,16 +24,17 @@ import java.util.concurrent.atomic.AtomicBoolean
@OptIn(PrivateSessionConstructor::class) @OptIn(PrivateSessionConstructor::class)
abstract class LLFirSession( abstract class LLFirSession(
val ktModule: KtModule, val ktModule: KtModule,
dependencyTracker: ModificationTracker,
override val builtinTypes: BuiltinTypes, override val builtinTypes: BuiltinTypes,
kind: Kind kind: Kind
) : FirSession(sessionProvider = null, kind) { ) : FirSession(sessionProvider = null, kind) {
abstract fun getScopeSession(): ScopeSession abstract fun getScopeSession(): ScopeSession
val modificationTracker: ModificationTracker
private val initialModificationCount: Long private val initialModificationCount: Long
private val isExplicitlyInvalidated = AtomicBoolean(false) private val isExplicitlyInvalidated = AtomicBoolean(false)
val modificationTracker: ModificationTracker
val project: Project val project: Project
get() = ktModule.project get() = ktModule.project
@@ -41,24 +44,49 @@ abstract class LLFirSession(
val outOfBlockTracker = when (ktModule) { val outOfBlockTracker = when (ktModule) {
is KtSourceModule -> trackerFactory.createModuleWithoutDependenciesOutOfBlockModificationTracker(ktModule) is KtSourceModule -> trackerFactory.createModuleWithoutDependenciesOutOfBlockModificationTracker(ktModule)
is KtNotUnderContentRootModule -> ModificationTracker { ktModule.file?.modificationStamp ?: 0 } is KtNotUnderContentRootModule -> ktModule.file?.let(::FileModificationTracker)
is KtScriptModule -> ModificationTracker { ktModule.file.modificationStamp } is KtScriptModule -> FileModificationTracker(ktModule.file)
is KtScriptDependencyModule -> ModificationTracker { ktModule.file?.modificationStamp ?: 0 } is KtScriptDependencyModule -> ktModule.file?.let(::FileModificationTracker)
else -> ModificationTracker.NEVER_CHANGED else -> null
} }
modificationTracker = CompositeModificationTracker.create( modificationTracker = CompositeModificationTracker.createFlattened(
listOf( listOfNotNull(
ExplicitInvalidationTracker(ktModule, isExplicitlyInvalidated),
ModuleStateModificationTracker(ktModule, validityTracker),
outOfBlockTracker, outOfBlockTracker,
ModificationTracker { validityTracker.rootModificationCount }, dependencyTracker
BooleanModificationTracker { validityTracker.isValid },
BooleanModificationTracker { !isExplicitlyInvalidated.get() }
) )
) )
initialModificationCount = modificationTracker.modificationCount 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() { fun invalidate() {
isExplicitlyInvalidated.set(true) isExplicitlyInvalidated.set(true)
} }
@@ -69,9 +97,10 @@ abstract class LLFirSession(
abstract class LLFirModuleSession( abstract class LLFirModuleSession(
ktModule: KtModule, ktModule: KtModule,
dependencyTracker: ModificationTracker,
builtinTypes: BuiltinTypes, builtinTypes: BuiltinTypes,
kind: Kind kind: Kind
) : LLFirSession(ktModule, builtinTypes, kind) ) : LLFirSession(ktModule, dependencyTracker, builtinTypes, kind)
val FirElementWithResolvePhase.llFirSession: LLFirSession val FirElementWithResolvePhase.llFirSession: LLFirSession
get() = moduleData.session as LLFirSession get() = moduleData.session as LLFirSession
@@ -6,8 +6,13 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.util.ModificationTracker
import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.ProjectScope 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.LLFirGlobalResolveComponents
import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirLazyDeclarationResolver import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirLazyDeclarationResolver
import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirModuleResolveComponents 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.createAnnotationResolver
import org.jetbrains.kotlin.analysis.providers.createDeclarationProvider import org.jetbrains.kotlin.analysis.providers.createDeclarationProvider
import org.jetbrains.kotlin.analysis.providers.createPackageProvider 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.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl 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.*
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirExtensionSyntheticFunctionInterfaceProvider import org.jetbrains.kotlin.fir.resolve.providers.impl.FirExtensionSyntheticFunctionInterfaceProvider
import org.jetbrains.kotlin.fir.resolve.scopes.wrapScopeWithJvmMapped 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.scopes.FirKotlinScopeProvider
import org.jetbrains.kotlin.fir.session.* import org.jetbrains.kotlin.fir.session.*
import org.jetbrains.kotlin.fir.symbols.FirLazyDeclarationResolver 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.psi.KtFile
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices
import java.util.concurrent.ConcurrentMap
@OptIn(PrivateSessionConstructor::class, SessionConfiguration::class) @OptIn(PrivateSessionConstructor::class, SessionConfiguration::class)
internal object LLFirSessionFactory { internal class LLFirSessionCache(private val project: Project) {
fun createSourcesSession( companion object {
module: KtSourceModule, fun getInstance(project: Project): LLFirSessionCache {
globalResolveComponents: LLFirGlobalResolveComponents, return project.getService(LLFirSessionCache::class.java)
sessionsCache: MutableMap<KtModule, LLFirSession> }
): LLFirSourcesSession { }
sessionsCache[module]?.let { return it as LLFirSourcesSession }
private val globalResolveComponents: LLFirGlobalResolveComponents
get() = LLFirGlobalResolveComponents.getInstance(project)
private val sourceCache: ConcurrentMap<KtModule, CachedValue<LLFirSession>> = CollectionFactory.createConcurrentSoftValueMap()
private val binaryCache: ConcurrentMap<KtModule, CachedValue<LLFirSession>> = 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 <T : KtModule> getCachedSession(
module: T,
storage: ConcurrentMap<KtModule, CachedValue<LLFirSession>>,
factory: (T) -> LLFirSession
): LLFirSession {
checkCanceled() 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 platform = module.platform
val builtinsSession = LLFirBuiltinsSessionFactory.getInstance(project).getBuiltinsSession(platform) val builtinsSession = LLFirBuiltinsSessionFactory.getInstance(project).getBuiltinsSession(platform)
val languageVersionSettings = wrapLanguageVersionSettings(module.languageVersionSettings) val languageVersionSettings = wrapLanguageVersionSettings(module.languageVersionSettings)
val scopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped) val scopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped)
val components = LLFirModuleResolveComponents(module, globalResolveComponents, scopeProvider) val components = LLFirModuleResolveComponents(module, globalResolveComponents, scopeProvider)
val contentScope = module.contentScope val dependencies = collectSourceModuleDependencies(module)
val session = LLFirSourcesSession( val dependencyTracker = createSourceModuleDependencyTracker(module, dependencies)
module, val session = LLFirSourcesSession(module, dependencyTracker, components, builtinsSession.builtinTypes)
components,
builtinsSession.builtinTypes
)
sessionsCache[module] = session
components.session = session components.session = session
return session.apply session@{ val moduleData = createModuleData(session)
val moduleData = LLFirModuleData(module).apply { bindSession(this@session) }
return session.apply {
registerModuleData(moduleData) registerModuleData(moduleData)
register(FirKotlinScopeProvider::class, scopeProvider) register(FirKotlinScopeProvider::class, scopeProvider)
@@ -81,6 +135,8 @@ internal object LLFirSessionFactory {
registerResolveComponents() registerResolveComponents()
registerJavaSpecificResolveComponents() registerJavaSpecificResolveComponents()
val contentScope = module.contentScope
val provider = LLFirProvider( val provider = LLFirProvider(
this, this,
components, components,
@@ -102,8 +158,7 @@ internal object LLFirSessionFactory {
} }
val dependencyProvider = LLFirDependentModuleProvidersBySessions(this) { val dependencyProvider = LLFirDependentModuleProvidersBySessions(this) {
processSourceDependencies(module, sessionsCache, globalResolveComponents) addAll(dependencies)
add(builtinsSession) add(builtinsSession)
} }
@@ -134,36 +189,27 @@ internal object LLFirSessionFactory {
} }
} }
private fun createLibrarySession(module: KtModule): LLFirLibraryOrLibrarySourceResolvableModuleSession {
fun createLibraryOrLibrarySourceResolvableSession(
module: KtModule,
globalComponents: LLFirGlobalResolveComponents,
builtinSession: LLFirBuiltinsAndCloneableSession,
sessionsCache: MutableMap<KtModule, LLFirSession>,
languageVersionSettings: LanguageVersionSettings = LanguageVersionSettingsImpl.DEFAULT
): LLFirLibraryOrLibrarySourceResolvableModuleSession {
LLFirLibraryOrLibrarySourceResolvableModuleSession.checkIsValidKtModule(module)
sessionsCache[module]?.let { return it as LLFirLibraryOrLibrarySourceResolvableModuleSession }
checkCanceled()
val project = module.project
val libraryModule = when (module) { val libraryModule = when (module) {
is KtLibraryModule -> module is KtLibraryModule -> module
is KtLibrarySourceModule -> module.binaryLibrary is KtLibrarySourceModule -> module.binaryLibrary
else -> error("Unexpected module ${module::class.simpleName}") else -> error("Unexpected module ${module::class.simpleName}")
} }
val scopeProvider = FirKotlinScopeProvider() val platform = module.platform
val components = LLFirModuleResolveComponents(module, globalComponents, scopeProvider) val builtinsSession = LLFirBuiltinsSessionFactory.getInstance(project).getBuiltinsSession(platform)
val languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT
val contentScope = module.contentScope val scopeProvider = FirKotlinScopeProvider()
val session = LLFirLibraryOrLibrarySourceResolvableModuleSession(module, components, builtinSession.builtinTypes) val components = LLFirModuleResolveComponents(module, globalResolveComponents, scopeProvider)
sessionsCache[module] = session
val dependencyTracker = builtinsSession.modificationTracker
val session = LLFirLibraryOrLibrarySourceResolvableModuleSession(module, dependencyTracker, components, builtinsSession.builtinTypes)
components.session = session components.session = session
return session.apply session@{ val moduleData = createModuleData(session)
val moduleData = LLFirModuleData(module).apply { bindSession(this@session) }
return session.apply {
registerModuleData(moduleData) registerModuleData(moduleData)
register(FirKotlinScopeProvider::class, scopeProvider) register(FirKotlinScopeProvider::class, scopeProvider)
@@ -174,6 +220,8 @@ internal object LLFirSessionFactory {
registerResolveComponents() registerResolveComponents()
registerJavaSpecificResolveComponents() registerJavaSpecificResolveComponents()
val contentScope = module.contentScope
val provider = LLFirProvider( val provider = LLFirProvider(
this, this,
components, components,
@@ -188,11 +236,11 @@ internal object LLFirSessionFactory {
// We need FirRegisteredPluginAnnotations during extensions' registration process // We need FirRegisteredPluginAnnotations during extensions' registration process
val annotationsResolver = project.createAnnotationResolver(contentScope) val annotationsResolver = project.createAnnotationResolver(contentScope)
register(FirRegisteredPluginAnnotations::class, LLFirIdeRegisteredPluginAnnotations(this@session, annotationsResolver)) register(FirRegisteredPluginAnnotations::class, LLFirIdeRegisteredPluginAnnotations(this, annotationsResolver))
register(FirPredicateBasedProvider::class, FirEmptyPredicateBasedProvider) register(FirPredicateBasedProvider::class, FirEmptyPredicateBasedProvider)
val dependencyProvider = LLFirDependentModuleProvidersByProviders(this) { val dependencyProvider = LLFirDependentModuleProvidersByProviders(this) {
add(builtinSession.symbolProvider) add(builtinsSession.symbolProvider)
// Script dependencies are self-contained and should not depend on other libraries // Script dependencies are self-contained and should not depend on other libraries
if (module !is KtScriptDependencyModule) { if (module !is KtScriptDependencyModule) {
@@ -231,29 +279,64 @@ internal object LLFirSessionFactory {
} }
} }
fun createScriptSession( private fun createBinaryLibrarySession(module: KtBinaryModule): LLFirLibrarySession {
module: KtScriptModule, val platform = module.platform
sessionsCache: MutableMap<KtModule, LLFirSession> val builtinsSession = LLFirBuiltinsSessionFactory.getInstance(project).getBuiltinsSession(platform)
): LLFirScriptSession {
sessionsCache[module]?.let { return it as LLFirScriptSession }
checkCanceled()
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 platform = module.platform
val builtinsSession = LLFirBuiltinsSessionFactory.getInstance(project).getBuiltinsSession(platform) val builtinsSession = LLFirBuiltinsSessionFactory.getInstance(project).getBuiltinsSession(platform)
val languageVersionSettings = wrapLanguageVersionSettings(module.languageVersionSettings) val languageVersionSettings = wrapLanguageVersionSettings(module.languageVersionSettings)
val scopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped) val scopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped)
val globalResolveComponents = LLFirGlobalResolveComponents(project)
val components = LLFirModuleResolveComponents(module, globalResolveComponents, scopeProvider) val components = LLFirModuleResolveComponents(module, globalResolveComponents, scopeProvider)
val contentScope = module.contentScope val contentScope = module.contentScope
val session = LLFirScriptSession(module, components, builtinsSession.builtinTypes) val dependencies = collectSourceModuleDependencies(module)
sessionsCache[module] = session val dependencyTracker = createSourceModuleDependencyTracker(module, dependencies)
val session = LLFirScriptSession(module, dependencyTracker, components, builtinsSession.builtinTypes)
components.session = session components.session = session
return session.apply session@{ val moduleData = createModuleData(session)
val moduleData = LLFirModuleData(module).apply { bindSession(this@session) }
return session.apply {
registerModuleData(moduleData) registerModuleData(moduleData)
register(FirKotlinScopeProvider::class, scopeProvider) register(FirKotlinScopeProvider::class, scopeProvider)
@@ -276,12 +359,7 @@ internal object LLFirSessionFactory {
register(FirLazyDeclarationResolver::class, LLFirLazyDeclarationResolver()) register(FirLazyDeclarationResolver::class, LLFirLazyDeclarationResolver())
val dependencyProvider = LLFirDependentModuleProvidersBySessions(this) { val dependencyProvider = LLFirDependentModuleProvidersBySessions(this) {
processSourceDependencies( addAll(dependencies)
module,
sessionsCache,
globalResolveComponents
)
add(builtinsSession) add(builtinsSession)
} }
@@ -309,27 +387,19 @@ internal object LLFirSessionFactory {
} }
} }
fun createNotUnderContentRootResolvableSession( private fun createNotUnderContentRootResolvableSession(module: KtNotUnderContentRootModule): LLFirNonUnderContentRootResolvableModuleSession {
module: KtNotUnderContentRootModule,
sessionsCache: MutableMap<KtModule, LLFirSession>
): LLFirNonUnderContentRootResolvableModuleSession {
sessionsCache[module]?.let { return it as LLFirNonUnderContentRootResolvableModuleSession }
checkCanceled()
val project = module.project
val builtinsSession = LLFirBuiltinsSessionFactory.getInstance(project).getBuiltinsSession(JvmPlatforms.unspecifiedJvmPlatform) val builtinsSession = LLFirBuiltinsSessionFactory.getInstance(project).getBuiltinsSession(JvmPlatforms.unspecifiedJvmPlatform)
val languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT val languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT
val scopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped) val scopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped)
val globalResolveComponents = LLFirGlobalResolveComponents(project)
val components = LLFirModuleResolveComponents(module, globalResolveComponents, scopeProvider) val components = LLFirModuleResolveComponents(module, globalResolveComponents, scopeProvider)
val contentScope = module.contentScope
val session = LLFirNonUnderContentRootResolvableModuleSession(module, components, builtinsSession.builtinTypes) val dependencyTracker = builtinsSession.modificationTracker
sessionsCache[module] = session val session = LLFirNonUnderContentRootResolvableModuleSession(module, dependencyTracker, components, builtinsSession.builtinTypes)
components.session = session components.session = session
return session.apply session@{ val moduleData = createModuleData(session)
val moduleData = LLFirModuleData(module).apply { bindSession(this@session) }
return session.apply {
registerModuleData(moduleData) registerModuleData(moduleData)
register(FirKotlinScopeProvider::class, scopeProvider) register(FirKotlinScopeProvider::class, scopeProvider)
@@ -346,7 +416,7 @@ internal object LLFirSessionFactory {
this, this,
components, components,
if (ktFile != null) FileBasedKotlinDeclarationProvider(ktFile) else EmptyKotlinDeclarationProvider, if (ktFile != null) FileBasedKotlinDeclarationProvider(ktFile) else EmptyKotlinDeclarationProvider,
project.createPackageProvider(contentScope), project.createPackageProvider(module.contentScope),
canContainKotlinPackage = true, canContainKotlinPackage = true,
) )
@@ -395,45 +465,46 @@ internal object LLFirSessionFactory {
} }
} }
private fun MutableList<LLFirSession>.processSourceDependencies( private fun collectSourceModuleDependencies(module: KtModule): List<LLFirSession> {
module: KtModule, val dependencies = mutableListOf<LLFirSession>()
sessionsCache: MutableMap<KtModule, LLFirSession>,
globalResolveComponents: LLFirGlobalResolveComponents
) {
val project = module.project
fun getOrCreateSessionForDependency(dependency: KtModule): LLFirSession? = when (dependency) { fun getOrCreateSessionForDependency(dependency: KtModule): LLFirSession? = when (dependency) {
is KtBuiltinsModule -> { is KtBuiltinsModule -> null // Built-ins are already added
// Built-ins are already added is KtBinaryModule -> getSession(dependency, preferBinary = true)
null is KtSourceModule -> getSession(dependency)
}
is KtBinaryModule -> {
LLFirLibrarySessionFactory.getInstance(project).getLibrarySession(dependency, sessionsCache)
}
is KtSourceModule -> {
createSourcesSession(dependency, globalResolveComponents, sessionsCache)
}
is KtScriptModule, is KtScriptModule,
is KtScriptDependencyModule, is KtScriptDependencyModule,
is KtNotUnderContentRootModule, is KtNotUnderContentRootModule,
is KtLibrarySourceModule -> { is KtLibrarySourceModule -> error("Module $module cannot depend on ${dependency::class}: $dependency")
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` // The dependency provider needs to have access to all direct and indirect `dependsOn` dependencies, as `dependsOn`
// dependencies are transitive. // dependencies are transitive.
val directRegularDependenciesSet = module.directRegularDependencies.toSet() val directRegularDependenciesSet = module.directRegularDependencies.toSet()
module.transitiveDependsOnDependencies.forEach { dependency -> module.transitiveDependsOnDependencies.forEach { dependency ->
if (dependency !in directRegularDependenciesSet) { if (dependency !in directRegularDependenciesSet) {
getOrCreateSessionForDependency(dependency)?.let(this::add) getOrCreateSessionForDependency(dependency)?.let(dependencies::add)
} }
} }
return dependencies
}
private fun createSourceModuleDependencyTracker(module: KtModule, exposedDependencies: List<LLFirSession>): ModificationTracker {
val friendDependencies = module.directFriendDependencies
val trackers = ArrayList<ModificationTracker>(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) }
} }
} }
@@ -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<LLFirModuleData>(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<LLFirSession>
get() = ktModuleToSession.getAllSessions()
}
internal abstract class KtModuleToSessionMapping {
abstract fun getSession(module: KtModule): LLFirSession
@TestOnly
abstract fun getAllSessions(): Collection<LLFirSession>
}
internal class KtModuleToSessionMappingByMapImpl(
private val map: Map<KtModule, LLFirSession>
) : KtModuleToSessionMapping() {
override fun getSession(module: KtModule): LLFirSession =
map.getValue(module)
override fun getAllSessions(): Collection<LLFirSession> =
map.values
}
internal class KtModuleToSessionMappingByWeakValueMapImpl(
initialMap: Map<KtModule, LLFirSession>
) : 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<LLFirSession> =
softValuesMap.keys.map { getSession(it) }
}
@@ -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<KtModule, LLFirSession>().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<KtModule, LLFirSession>().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<KtModule, LLFirSession>().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<KtModule, LLFirSession>().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<KtModule, SoftReference<LLFirSession>> = emptyMap()
inline fun <R> withMappings(
action: (Map<KtModule, LLFirSession>) -> Pair<Map<KtModule, LLFirSession>, R>
): Pair<Map<KtModule, LLFirSession>, R> {
val (newMappings, result) = action(getSessions().mapValues { it.value })
mappings = newMappings.mapValues { SoftReference(it.value) }
return newMappings to result
}
private fun getSessions(): Map<KtModule, LLFirSession> = buildMap {
// Initially, all sessions are considered to be valid ('true').
val sessions = LinkedHashMap<LLFirSession, Boolean>().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)
}
}
}
}
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions 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.low.level.api.fir.LLFirModuleResolveComponents
import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule
import org.jetbrains.kotlin.fir.BuiltinTypes import org.jetbrains.kotlin.fir.BuiltinTypes
@@ -12,6 +13,7 @@ import org.jetbrains.kotlin.fir.PrivateSessionConstructor
internal class LLFirSourcesSession @PrivateSessionConstructor constructor( internal class LLFirSourcesSession @PrivateSessionConstructor constructor(
ktModule: KtSourceModule, ktModule: KtSourceModule,
dependencyTracker: ModificationTracker,
override val moduleComponents: LLFirModuleResolveComponents, override val moduleComponents: LLFirModuleResolveComponents,
builtinTypes: BuiltinTypes, builtinTypes: BuiltinTypes,
) : LLFirResolvableModuleSession(ktModule, builtinTypes) ) : LLFirResolvableModuleSession(ktModule, dependencyTracker, builtinTypes)
@@ -5,23 +5,17 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.state 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.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.LLFirLibraryOrLibrarySourceResolvableModuleSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSession
import org.jetbrains.kotlin.analysis.project.structure.KtModule import org.jetbrains.kotlin.analysis.project.structure.KtModule
import org.jetbrains.kotlin.diagnostics.KtPsiDiagnostic import org.jetbrains.kotlin.diagnostics.KtPsiDiagnostic
import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
internal class LLFirLibraryOrLibrarySourceResolvableResolveSession( internal class LLFirLibraryOrLibrarySourceResolvableResolveSession(
override val globalComponents: LLFirGlobalResolveComponents, useSiteFirSession: LLFirSession
override val project: Project, ) : LLFirResolvableResolveSession(useSiteFirSession) {
override val useSiteKtModule: KtModule,
sessionProvider: LLFirSessionProvider,
) : LLFirResolvableResolveSession(sessionProvider) {
override fun getDiagnostics(element: KtElement, filter: DiagnosticCheckerFilter): List<KtPsiDiagnostic> = override fun getDiagnostics(element: KtElement, filter: DiagnosticCheckerFilter): List<KtPsiDiagnostic> =
emptyList() emptyList()
@@ -30,10 +24,7 @@ internal class LLFirLibraryOrLibrarySourceResolvableResolveSession(
override fun getModuleKind(module: KtModule): ModuleKind { override fun getModuleKind(module: KtModule): ModuleKind {
LLFirLibraryOrLibrarySourceResolvableModuleSession.checkIsValidKtModule(module) LLFirLibraryOrLibrarySourceResolvableModuleSession.checkIsValidKtModule(module)
return when { return if (module == useSiteKtModule) ModuleKind.RESOLVABLE_MODULE else ModuleKind.BINARY_MODULE
module == this.useSiteKtModule -> ModuleKind.RESOLVABLE_MODULE
else -> ModuleKind.BINARY_MODULE
}
} }
} }
@@ -5,21 +5,16 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.state 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.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.analysis.project.structure.KtModule
import org.jetbrains.kotlin.diagnostics.KtPsiDiagnostic import org.jetbrains.kotlin.diagnostics.KtPsiDiagnostic
import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
internal class LLFirNotUnderContentRootResolveSession( internal class LLFirNotUnderContentRootResolveSession(
override val globalComponents: LLFirGlobalResolveComponents, useSiteFirSession: LLFirSession
override val project: Project, ) : LLFirResolvableResolveSession(useSiteFirSession) {
override val useSiteKtModule: KtModule,
sessionProvider: LLFirSessionProvider,
) : LLFirResolvableResolveSession(sessionProvider) {
override fun getDiagnostics(element: KtElement, filter: DiagnosticCheckerFilter): List<KtPsiDiagnostic> = override fun getDiagnostics(element: KtElement, filter: DiagnosticCheckerFilter): List<KtPsiDiagnostic> =
emptyList() emptyList()
@@ -5,14 +5,15 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.state 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.LLFirModuleResolveComponents
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession 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.FirTowerContextProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.getNonLocalContainingOrThisDeclaration 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.LLFirResolvableModuleSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSession 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.FirDeclarationForCompiledElementSearcher
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.errorWithFirSpecificEntries import org.jetbrains.kotlin.analysis.low.level.api.fir.util.errorWithFirSpecificEntries
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.findSourceNonLocalFirDeclaration 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.KtExpression
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
@Suppress("PrivatePropertyName")
private val LOG = Logger.getInstance(LLFirResolvableResolveSession::class.java)
internal abstract class LLFirResolvableResolveSession( internal abstract class LLFirResolvableResolveSession(
private val sessionProvider: LLFirSessionProvider, final override val useSiteFirSession: LLFirSession
) : LLFirResolveSession() { ) : 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 = override fun getSessionFor(module: KtModule): LLFirSession {
sessionProvider.getSession(module) LOG.assertTrue(useSiteFirSession.isValid, "Use-site session is invalid")
protected open fun getResolvableSessionFor(module: KtModule): LLFirResolvableModuleSession = if (module == useSiteFirSession.ktModule) {
sessionProvider.getResolvableSession(module) 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 { override fun getScopeSessionFor(firSession: FirSession): ScopeSession {
requireIsInstance<LLFirSession>(firSession) requireIsInstance<LLFirSession>(firSession)
@@ -5,12 +5,6 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.state 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.api.DiagnosticCheckerFilter
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.* import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.*
import org.jetbrains.kotlin.analysis.project.structure.* import org.jetbrains.kotlin.analysis.project.structure.*
@@ -20,40 +14,8 @@ import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
internal class LLFirScriptResolveSession( internal class LLFirScriptResolveSession(
override val globalComponents: LLFirGlobalResolveComponents, useSiteFirSession: LLFirSession
override val project: Project, ) : LLFirResolvableResolveSession(useSiteFirSession) {
override val useSiteKtModule: KtModule,
sessionProvider: LLFirSessionProvider
) : LLFirResolvableResolveSession(sessionProvider) {
private val dependencyCache: Map<KtModule, LLFirSession> =
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)
}
override fun getDiagnostics(element: KtElement, filter: DiagnosticCheckerFilter): List<KtPsiDiagnostic> { override fun getDiagnostics(element: KtElement, filter: DiagnosticCheckerFilter): List<KtPsiDiagnostic> {
val moduleComponents = getModuleComponentsForElement(element) val moduleComponents = getModuleComponentsForElement(element)
return moduleComponents.diagnosticsCollector.getDiagnosticsFor(element, filter) return moduleComponents.diagnosticsCollector.getDiagnosticsFor(element, filter)
@@ -5,10 +5,8 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.state 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.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.KtBuiltinsModule
import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule
import org.jetbrains.kotlin.analysis.project.structure.KtModule import org.jetbrains.kotlin.analysis.project.structure.KtModule
@@ -19,11 +17,8 @@ import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
internal class LLFirSourceResolveSession( internal class LLFirSourceResolveSession(
override val globalComponents: LLFirGlobalResolveComponents, useSiteFirSession: LLFirSession
override val project: Project, ) : LLFirResolvableResolveSession(useSiteFirSession) {
override val useSiteKtModule: KtModule,
sessionProvider: LLFirSessionProvider,
) : LLFirResolvableResolveSession(sessionProvider) {
override fun getDiagnostics(element: KtElement, filter: DiagnosticCheckerFilter): List<KtPsiDiagnostic> { override fun getDiagnostics(element: KtElement, filter: DiagnosticCheckerFilter): List<KtPsiDiagnostic> {
val moduleComponents = getModuleComponentsForElement(element) val moduleComponents = getModuleComponentsForElement(element)
return moduleComponents.diagnosticsCollector.getDiagnosticsFor(element, filter) return moduleComponents.diagnosticsCollector.getDiagnosticsFor(element, filter)
@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.util package org.jetbrains.kotlin.analysis.low.level.api.fir.util
import com.intellij.openapi.progress.ProgressManager 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.analysis.low.level.api.fir.sessions.LLFirResolvableModuleSession
import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclaration
@@ -74,8 +73,3 @@ internal val FirDeclaration.containingKtFileIfAny: KtFile?
internal fun KtDeclaration.isNonAnonymousClassOrObject() = internal fun KtDeclaration.isNonAnonymousClassOrObject() =
this is KtClassOrObject this is KtClassOrObject
&& !this.isObjectLiteral() && !this.isObjectLiteral()
internal fun BooleanModificationTracker(provider: () -> Boolean): ModificationTracker {
return ModificationTracker { if (provider()) 0 else 1 }
}
@@ -6,9 +6,9 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.compiler.based 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.DiagnosticCheckerFilter
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirFile import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.createFirResolveSessionForNoCaching
import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.FirLowLevelCompilerBasedTestConfigurator 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.low.level.api.fir.transformers.LLFirLazyTransformer
import org.jetbrains.kotlin.analysis.test.framework.AbstractCompilerBasedTest 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.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.FirParser 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.TestConfigurationBuilder
import org.jetbrains.kotlin.test.builders.firHandlersStep import org.jetbrains.kotlin.test.builders.firHandlersStep
import org.jetbrains.kotlin.test.builders.testConfiguration import org.jetbrains.kotlin.test.builders.testConfiguration
@@ -86,8 +85,8 @@ abstract class AbstractCompilerBasedTestForFir : AbstractCompilerBasedTest() {
val moduleInfoProvider = testServices.ktModuleProvider val moduleInfoProvider = testServices.ktModuleProvider
val ktModule = moduleInfoProvider.getModule(module.name) as KtSourceModuleByCompilerConfiguration val ktModule = moduleInfoProvider.getModule(module.name) as KtSourceModuleByCompilerConfiguration
val project = testServices.compilerConfigurationProvider.getProject(module) val project = ktModule.project
val firResolveSession = createFirResolveSessionForNoCaching(ktModule, project) val firResolveSession = LLFirResolveSessionService.getInstance(project).getFirResolveSessionNoCaching(ktModule)
val allFirFiles = val allFirFiles =
module.files.filter { it.isKtFile }.zip( module.files.filter { it.isKtFile }.zip(
@@ -5,10 +5,10 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.compiler.based 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.LLFirResolveSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirFile import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.services.FirSealedClassInheritorsProcessorFactory 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.low.level.api.fir.services.LLFirSealedClassInheritorsProcessorFactoryForTests
import org.jetbrains.kotlin.analysis.project.structure.ProjectStructureProvider import org.jetbrains.kotlin.analysis.project.structure.ProjectStructureProvider
import org.jetbrains.kotlin.analysis.test.framework.project.structure.ktModuleProvider import org.jetbrains.kotlin.analysis.test.framework.project.structure.ktModuleProvider
@@ -51,7 +51,7 @@ class SealedClassesInheritorsCaclulatorPreAnalysisHandler(
val ktModuleProvider = project.getService(ProjectStructureProvider::class.java) val ktModuleProvider = project.getService(ProjectStructureProvider::class.java)
val ktModule = ktFiles.map(ktModuleProvider::getKtModuleForKtElement).distinct().single() 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 firFiles = ktFiles.map { it.getOrBuildFirFile(tmpFirResolveSession) }
val sealedInheritors = collectSealedClassInheritors(firFiles, tmpFirResolveSession) val sealedInheritors = collectSealedClassInheritors(firFiles, tmpFirResolveSession)
val provider = val provider =
@@ -42,8 +42,9 @@ internal fun FirDeclaration.name(): String = symbol.name()
internal inline fun <R> resolveWithClearCaches(context: KtElement, action: (LLFirResolveSession) -> R): R { internal inline fun <R> resolveWithClearCaches(context: KtElement, action: (LLFirResolveSession) -> R): R {
val project = context.project val project = context.project
val firResolveSession = createFirResolveSessionForNoCaching(context.getKtModule(project), project) val module = context.getKtModule(project)
return action(firResolveSession) val resolveSession = LLFirResolveSessionService.getInstance(project).getFirResolveSessionNoCaching(module)
return action(resolveSession)
} }
internal val LLFirResolveSession.isSourceSession: Boolean internal val LLFirResolveSession.isSourceSession: Boolean
@@ -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.KtFirAnalysisSessionProvider
import org.jetbrains.kotlin.analysis.api.fir.references.ReadWriteAccessCheckerFirImpl import org.jetbrains.kotlin.analysis.api.fir.references.ReadWriteAccessCheckerFirImpl
import org.jetbrains.kotlin.analysis.api.session.KtAnalysisSessionProvider 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.LLFirResolveSessionService
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.services.FirSealedClassInheritorsProcessorFactory 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.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.KtCompilerPluginsProviderForTests
import org.jetbrains.kotlin.analysis.low.level.api.fir.services.LLFirSealedClassInheritorsProcessorFactoryForTests 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.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.low.level.api.fir.sessions.LLFirSessionConfigurator
import org.jetbrains.kotlin.analysis.project.structure.KtCompilerPluginsProvider import org.jetbrains.kotlin.analysis.project.structure.KtCompilerPluginsProvider
import org.jetbrains.kotlin.analysis.providers.PackagePartProviderFactory import org.jetbrains.kotlin.analysis.providers.PackagePartProviderFactory
@@ -49,7 +50,8 @@ object AnalysisApiFirTestServiceRegistrar : AnalysisApiTestServiceRegistrar() {
registerService(KtAnalysisSessionProvider::class.java, KtFirAnalysisSessionProvider(this)) registerService(KtAnalysisSessionProvider::class.java, KtFirAnalysisSessionProvider(this))
registerService(FirSealedClassInheritorsProcessorFactory::class.java, LLFirSealedClassInheritorsProcessorFactoryForTests()) registerService(FirSealedClassInheritorsProcessorFactory::class.java, LLFirSealedClassInheritorsProcessorFactoryForTests())
registerService(LLFirResolveSessionService::class.java) registerService(LLFirResolveSessionService::class.java)
registerService(LLFirLibrarySessionFactory::class.java) registerService(LLFirSessionCache::class.java)
registerService(LLFirGlobalResolveComponents::class.java)
registerService(LLFirBuiltinsSessionFactory::class.java) registerService(LLFirBuiltinsSessionFactory::class.java)
registerService(PackagePartProviderFactory::class.java, PackagePartProviderTestImpl(testServices)) registerService(PackagePartProviderFactory::class.java, PackagePartProviderTestImpl(testServices))