[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;
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));
}
}
@@ -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)
@@ -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>) : ModificationTracker {
override fun getModificationCount(): Long = trackers.sumOf { it.modificationCount }
public companion object {
public fun create(trackers: List<ModificationTracker>): ModificationTracker = when (trackers.size) {
0 -> ModificationTracker.NEVER_CHANGED
1 -> trackers.single()
else -> CompositeModificationTracker(trackers)
public fun create(trackers: List<ModificationTracker>): ModificationTracker {
return when (trackers.size) {
0 -> ModificationTracker.NEVER_CHANGED
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 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()
}
@@ -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,
@@ -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<KtModule, LLFirResolvableResolveSession>(
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)
)
}
}
@@ -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 ->
@@ -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<TargetPlatform, LLFirBuiltinsAndCloneableSession>()
@@ -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)
@@ -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
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)
) : LLFirLibraryLikeSession(ktModule, dependencyTracker, builtinTypes)
@@ -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)
@@ -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 {
@@ -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)
}
@@ -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)
@@ -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 {
@@ -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)
) : 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.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
@@ -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<KtModule, LLFirSession>
): 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<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()
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<KtModule, LLFirSession>,
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<KtModule, LLFirSession>
): 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<KtModule, LLFirSession>
): 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<LLFirSession>.processSourceDependencies(
module: KtModule,
sessionsCache: MutableMap<KtModule, LLFirSession>,
globalResolveComponents: LLFirGlobalResolveComponents
) {
val project = module.project
private fun collectSourceModuleDependencies(module: KtModule): List<LLFirSession> {
val dependencies = mutableListOf<LLFirSession>()
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<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
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)
@@ -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<KtPsiDiagnostic> =
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
}
}
@@ -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<KtPsiDiagnostic> =
emptyList()
@@ -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<LLFirSession>(firSession)
@@ -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<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)
}
useSiteFirSession: LLFirSession
) : LLFirResolvableResolveSession(useSiteFirSession) {
override fun getDiagnostics(element: KtElement, filter: DiagnosticCheckerFilter): List<KtPsiDiagnostic> {
val moduleComponents = getModuleComponentsForElement(element)
return moduleComponents.diagnosticsCollector.getDiagnosticsFor(element, filter)
@@ -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<KtPsiDiagnostic> {
val moduleComponents = getModuleComponentsForElement(element)
return moduleComponents.diagnosticsCollector.getDiagnosticsFor(element, filter)
@@ -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 }
}
&& !this.isObjectLiteral()
@@ -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(
@@ -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 =
@@ -42,8 +42,9 @@ internal fun FirDeclaration.name(): String = symbol.name()
internal inline fun <R> 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
@@ -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))