[LL FIR] create separate library session for each library

This commit is contained in:
Ilya Kirillov
2022-07-18 20:20:02 +02:00
parent dbfeeae696
commit dc4527462f
18 changed files with 254 additions and 184 deletions
@@ -35,8 +35,8 @@ fun FirBasedSymbol<*>.getContainingKtModule(firResolveSession: LLFirResolveSessi
}
return when (val moduleData = target.firModuleData) {
is LLFirKtModuleBasedModuleData -> moduleData.ktModule
is LLFirBuiltinsModuleData -> firResolveSession.project.getService(ProjectStructureProvider::class.java).getStdlibWithBuiltinsModule(moduleData.useSiteKtModule)
?: error("Builtins not found for the ${moduleData.useSiteKtModule.moduleDescription}")
is LLFirBuiltinsModuleData -> firResolveSession.project.getService(ProjectStructureProvider::class.java).getStdlibWithBuiltinsModule(moduleData.platform)
?: error("Builtins not found for the $moduleData")
}
}
@@ -66,7 +66,7 @@ object LibraryUtils {
?.let { getAllVirtualFilesFromRoot(it, includeRoot) } ?: emptySet()
}
private fun getAllVirtualFilesFromRoot(
fun getAllVirtualFilesFromRoot(
root: VirtualFile,
includeRoot: Boolean,
): Collection<VirtualFile> {
@@ -12,11 +12,12 @@ import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.Stand
import org.jetbrains.kotlin.analysis.project.structure.KtBinaryModule
import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule
import org.jetbrains.kotlin.analysis.project.structure.KtModule
import org.jetbrains.kotlin.platform.TargetPlatform
data class KtModuleProjectStructure(
val mainModules: List<KtModuleWithFiles>,
val binaryModules: Iterable<KtBinaryModule>,
val stdlibFor: (KtModule) -> KtLibraryModule,
val stdlibFor: (TargetPlatform) -> KtLibraryModule,
) {
fun allKtModules(): List<KtModule> = buildList {
mainModules.mapTo(this) { it.ktModule }
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.analysis.api.standalone.base.project.structure
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.analysis.project.structure.*
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.psi.psiUtil.contains
class KtStaticModuleProvider(
@@ -23,7 +24,7 @@ class KtStaticModuleProvider(
return projectStructure.allKtModules().filterIsInstance<KtBinaryModule>()
}
override fun getStdlibWithBuiltinsModule(module: KtModule): KtLibraryModule {
return projectStructure.stdlibFor(module)
override fun getStdlibWithBuiltinsModule(platform: TargetPlatform): KtLibraryModule {
return projectStructure.stdlibFor(platform)
}
}
@@ -14,6 +14,7 @@ import com.intellij.mock.MockProject
import com.intellij.openapi.Disposable
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.roots.PackageIndex
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.psi.PsiDirectory
import com.intellij.psi.PsiFileSystemItem
@@ -181,6 +182,28 @@ object StandaloneProjectFactory {
.filterIsInstance<KtBinaryModule>()
.flatMap { it.getJavaRoots(environment) }
fun getVirtualFilesForLibraryRoots(
roots: Collection<Path>,
environment: KotlinCoreProjectEnvironment
): List<VirtualFile> {
return roots.mapNotNull { path ->
val pathString = path.toAbsolutePath().toString()
when {
pathString.endsWith(JAR_PROTOCOL) -> {
environment.environment.jarFileSystem.findFileByPath(pathString + JAR_SEPARATOR)
}
pathString.contains(JAR_SEPARATOR) -> {
environment.environment.jrtFileSystem?.findFileByPath(adjustModulePath(pathString))
}
else -> {
VirtualFileManager.getInstance().findFileByNioPath(path)
}
}
}
}
private fun withAllTransitiveDependencies(ktModules: List<KtModule>): List<KtModule> {
val visited = hashSetOf<KtModule>()
val stack = ktModules.toMutableList()
@@ -212,24 +235,7 @@ object StandaloneProjectFactory {
private fun KtBinaryModule.getJavaRoots(
environment: KotlinCoreProjectEnvironment,
): List<JavaRoot> {
return buildList {
getBinaryRoots().forEach { path ->
val pathString = path.toAbsolutePath().toString()
when {
pathString.endsWith(JAR_PROTOCOL) -> {
environment.environment.jarFileSystem.findFileByPath(pathString + JAR_SEPARATOR)
}
pathString.contains(JAR_SEPARATOR) -> {
environment.environment.jrtFileSystem?.findFileByPath(adjustModulePath(pathString))
}
else -> {
VirtualFileManager.getInstance().findFileByNioPath(path)
}
}?.let { root ->
add(JavaRoot(root, JavaRoot.RootType.BINARY))
}
}
}
return getVirtualFilesForLibraryRoots(getBinaryRoots(), environment).map { root -> JavaRoot(root, JavaRoot.RootType.BINARY)}
}
private fun adjustModulePath(pathString: String): String {
@@ -10,6 +10,7 @@ import com.intellij.psi.PsiFileSystemItem
import com.intellij.psi.PsiJavaFile
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.StandaloneProjectFactory.findJvmRootsForJavaFiles
import org.jetbrains.kotlin.analysis.project.structure.*
import org.jetbrains.kotlin.platform.TargetPlatform
internal class KtModuleProviderImpl(
internal val mainModules: List<KtModule>,
@@ -37,10 +38,10 @@ internal class KtModuleProviderImpl(
return binaryModules
}
override fun getStdlibWithBuiltinsModule(module: KtModule): KtLibraryModule? {
override fun getStdlibWithBuiltinsModule(platform: TargetPlatform): KtLibraryModule? {
return binaryModules
.filterIsInstance<KtLibraryModuleImpl>()
.firstOrNull { it.isBuiltinsContainingStdlib }
.firstOrNull { it.isBuiltinsContainingStdlib && it.platform == platform }
}
internal fun allSourceFiles(): List<PsiFileSystemItem> = buildList {
@@ -17,6 +17,7 @@ dependencies {
testApi(project(":analysis:analysis-api"))
testApi(project(":analysis:analysis-api-standalone:analysis-api-standalone-base"))
testApi(project(":analysis:analysis-api-impl-barebone"))
testApi(project(":analysis:analysis-api-impl-base"))
}
sourceSets {
@@ -9,9 +9,10 @@ import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiManager
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.ProjectScope
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.KtModuleWithFiles
import org.jetbrains.kotlin.analysis.api.impl.base.util.LibraryUtils
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.KtModuleProjectStructure
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.KtModuleWithFiles
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.StandaloneProjectFactory
import org.jetbrains.kotlin.analysis.project.structure.KtBinaryModule
import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule
import org.jetbrains.kotlin.analysis.project.structure.KtModule
@@ -85,8 +86,8 @@ object TestModuleStructureFactory {
addModuleDependencies(testModule, moduleByName, ktModule)
buildList {
addIfNotNull(getJdkModule(testModule, project))
addAll(getStdlibModules(testModule, project))
addIfNotNull(getJdkModule(testModule, project, testServices))
addAll(getStdlibModules(testModule, project, testServices))
addAll(getLibraryModules(testServices, testModule, project))
addAll(createLibrariesByCompilerConfigurators(testModule, testServices, project))
}.forEach { library ->
@@ -95,8 +96,11 @@ object TestModuleStructureFactory {
}
}
return KtModuleProjectStructure(modulesFromTestServices, binaryModulesBySourceRoots.values) { module ->
module.allDirectDependenciesOfType<KtLibraryModuleImpl>().first { it.isBuitinsContainingStdlib }
val allStdLibCandidates = modulesFromTestServices.flatMap { module ->
module.ktModule.allDirectDependenciesOfType<KtLibraryModuleImpl>()
}.filter { it.isBuitinsContainingStdlib }
return KtModuleProjectStructure(modulesFromTestServices, binaryModulesBySourceRoots.values) { platform ->
allStdLibCandidates.first { it.platform == platform }
}
}
@@ -110,7 +114,7 @@ object TestModuleStructureFactory {
val contentRoots = compilerConfiguration[CLIConfigurationKeys.CONTENT_ROOTS, emptyList()]
return contentRoots
.filterIsInstance<JvmClasspathRoot>()
.map { root -> createKtLibraryModuleByJar(root.file.toPath(), project, isBuitinsContainingStdlib = false) }
.map { root -> createKtLibraryModuleByJar(root.file.toPath(), testServices, project, isBuitinsContainingStdlib = false) }
}
@@ -144,11 +148,12 @@ object TestModuleStructureFactory {
): List<KtLibraryModuleImpl> {
val configurationKind = JvmEnvironmentConfigurator.extractConfigurationKind(testModule.directives)
return JvmEnvironmentConfigurator
.getLibraryFilesExceptRealRuntime( testServices, configurationKind, testModule.directives)
.getLibraryFilesExceptRealRuntime(testServices, configurationKind, testModule.directives)
.map { it.toPath().toAbsolutePath() }
.map { jar ->
createKtLibraryModuleByJar(
jar,
testServices,
project,
isBuitinsContainingStdlib = jar.nameWithoutExtension == "kotlin-stdlib-jvm-minimal-for-test"
)
@@ -157,6 +162,7 @@ object TestModuleStructureFactory {
private fun createKtLibraryModuleByJar(
jar: Path,
testServices: TestServices,
project: Project,
libraryName: String = jar.nameWithoutExtension,
isBuitinsContainingStdlib: Boolean = false,
@@ -166,7 +172,7 @@ object TestModuleStructureFactory {
return KtLibraryModuleImpl(
libraryName,
JvmPlatforms.defaultJvmPlatform,
ProjectScope.getLibrariesScope(project),
getScopeForLibraryByRoots(listOf(jar), project, testServices),
project,
listOf(jar),
librarySources = null,
@@ -176,7 +182,8 @@ object TestModuleStructureFactory {
private fun getStdlibModules(
testModule: TestModule,
project: Project
project: Project,
testServices: TestServices,
): List<KtLibraryModule> {
val configurationKind = JvmEnvironmentConfigurator.extractConfigurationKind(testModule.directives)
if (!configurationKind.withRuntime) return emptyList()
@@ -184,13 +191,14 @@ object TestModuleStructureFactory {
KotlinPaths.Jar.StdLib to PathUtil.KOTLIN_JAVA_STDLIB_NAME,
).map { (jar, name) ->
val lib = PathUtil.kotlinPathsForDistDirectory.jar(jar).toPath().toAbsolutePath()
createKtLibraryModuleByJar(lib, project, name, isBuitinsContainingStdlib = jar == KotlinPaths.Jar.StdLib)
createKtLibraryModuleByJar(lib, testServices, project, name, isBuitinsContainingStdlib = jar == KotlinPaths.Jar.StdLib)
}
}
private fun getJdkModule(
testModule: TestModule,
project: Project
project: Project,
testServices: TestServices,
): KtJdkModuleImpl? {
val jdkKind = JvmEnvironmentConfigurator.extractJdkKind(testModule.directives)
@@ -204,12 +212,26 @@ object TestModuleStructureFactory {
return KtJdkModuleImpl(
"jdk",
JvmPlatforms.defaultJvmPlatform,
ProjectScope.getLibrariesScope(project),
getScopeForLibraryByRoots(jdkSourceRoots, project, testServices),
project,
jdkSourceRoots
)
}
private fun getScopeForLibraryByRoots(roots: Collection<Path>, project: Project, testServices: TestServices): GlobalSearchScope {
val virtualFileRoots = StandaloneProjectFactory.getVirtualFilesForLibraryRoots(
roots,
testServices.environmentManager.getProjectEnvironment()
)
return GlobalSearchScope.filesScope(
project,
buildList {
addAll(virtualFileRoots)
virtualFileRoots.flatMapTo(this) { LibraryUtils.getAllVirtualFilesFromRoot(it, includeRoot = true) }
}
)
}
private fun TestModule.toKtModule(
testServices: TestServices,
project: Project,
@@ -0,0 +1,68 @@
/*
* 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.LLFirBuiltinSymbolProvider
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.fir.BuiltinTypes
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.impl.FirCloneableSymbolProvider
import org.jetbrains.kotlin.fir.resolve.scopes.wrapScopeWithJvmMapped
import org.jetbrains.kotlin.fir.resolve.transformers.FirPhaseCheckingPhaseManager
import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider
import org.jetbrains.kotlin.fir.session.registerCommonComponents
import org.jetbrains.kotlin.fir.session.registerModuleData
import org.jetbrains.kotlin.fir.symbols.FirPhaseManager
import java.util.concurrent.ConcurrentHashMap
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices
@OptIn(PrivateSessionConstructor::class, SessionConfiguration::class)
class LLFirBuiltinsSessionFactory(
private val project: Project,
) {
private val builtInTypes = BuiltinTypes() // TODO should be platform-specific
private val builtinsAndCloneableSession = ConcurrentHashMap<TargetPlatform, LLFirBuiltinsAndCloneableSession>()
fun getBuiltinsSession(platform: TargetPlatform): LLFirBuiltinsAndCloneableSession {
return builtinsAndCloneableSession.getOrPut(platform) { createBuiltinsAndCloneableSession(platform) }
}
private fun createBuiltinsAndCloneableSession(platform: TargetPlatform): LLFirBuiltinsAndCloneableSession {
return LLFirBuiltinsAndCloneableSession(project, builtInTypes).apply session@{
val moduleData = LLFirBuiltinsModuleData(platform, JvmPlatformAnalyzerServices/*TODO*/).apply {
bindSession(this@session)
}
registerIdeComponents(project)
register(FirPhaseManager::class, FirPhaseCheckingPhaseManager)
registerCommonComponents(LanguageVersionSettingsImpl.DEFAULT/*TODO*/)
registerModuleData(moduleData)
val kotlinScopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped)
register(FirKotlinScopeProvider::class, kotlinScopeProvider)
val symbolProvider = createCompositeSymbolProvider(this) {
add(LLFirBuiltinSymbolProvider(this@session, moduleData, kotlinScopeProvider))
add(FirCloneableSymbolProvider(this@session, moduleData, kotlinScopeProvider))
}
register(FirSymbolProvider::class, symbolProvider)
register(FirProvider::class, LLFirBuiltinsAndCloneableSessionProvider(symbolProvider))
register(FirJvmTypeMapper::class, FirJvmTypeMapper(this))
}
}
companion object {
fun getInstance(project: Project): LLFirBuiltinsSessionFactory =
project.getService(LLFirBuiltinsSessionFactory::class.java)
}
}
@@ -11,15 +11,8 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.services.createPackag
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirJavaFacadeForBinaries
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.analysis.project.structure.allDirectDependenciesOfType
import org.jetbrains.kotlin.analysis.utils.errors.checkIsInstance
import org.jetbrains.kotlin.fir.BuiltinTypes
import org.jetbrains.kotlin.fir.FirModuleData
import org.jetbrains.kotlin.fir.deserialization.EmptyModuleDataProvider
import org.jetbrains.kotlin.fir.deserialization.LibraryPathFilter
import org.jetbrains.kotlin.fir.deserialization.ModuleDataProvider
import org.jetbrains.kotlin.fir.deserialization.MultipleModuleDataProvider
import org.jetbrains.kotlin.fir.deserialization.SingleModuleDataProvider
import org.jetbrains.kotlin.fir.java.deserialization.JvmClassFileBasedSymbolProvider
import org.jetbrains.kotlin.fir.java.deserialization.OptionalAnnotationClassesProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
@@ -28,56 +21,55 @@ import org.jetbrains.kotlin.load.java.createJavaClassFinder
import org.jetbrains.kotlin.load.kotlin.VirtualFileFinderFactory
internal object LLFirLibraryProviderFactory {
fun createProvidersByModuleLibraryDependencies(
fun createLibraryProvidersForSingleBinaryModule(
session: LLFirSession,
module: KtModule,
moduleData: LLFirModuleData,
module: KtBinaryModule,
kotlinScopeProvider: FirKotlinScopeProvider,
project: Project,
builtinTypes: BuiltinTypes,
createSearchScopeForModules: (List<KtBinaryModule>) -> GlobalSearchScope
): List<FirSymbolProvider> = buildList {
module
.allDirectDependenciesOfType<KtBinaryModule>()
.groupBy { it.platform }
.forEach { (_, binaryDependencies) ->
val moduleDataProvider = createModuleDataProviderWithLibraryDependencies(module, binaryDependencies, session)
val scope = createSearchScopeForModules(binaryDependencies)
val packagePartProvider = project.createPackagePartProviderForLibrary(scope)
add(
JvmClassFileBasedSymbolProvider(
session,
moduleDataProvider,
kotlinScopeProvider,
packagePartProvider,
VirtualFileFinderFactory.getInstance(project).create(scope),
LLFirJavaFacadeForBinaries(session, builtinTypes, project.createJavaClassFinder(scope), moduleDataProvider)
)
): List<FirSymbolProvider> {
val moduleDataProvider = SingleModuleDataProvider(moduleData)
val scope = module.contentScope
val packagePartProvider = project.createPackagePartProviderForLibrary(scope)
return buildList {
add(
JvmClassFileBasedSymbolProvider(
session,
moduleDataProvider,
kotlinScopeProvider,
packagePartProvider,
VirtualFileFinderFactory.getInstance(project).create(scope),
LLFirJavaFacadeForBinaries(session, builtinTypes, project.createJavaClassFinder(scope), moduleDataProvider)
)
add(OptionalAnnotationClassesProvider(session, moduleDataProvider, kotlinScopeProvider, packagePartProvider))
}
}
private fun createModuleDataProviderWithLibraryDependencies(
sourceModule: KtModule,
binaryDependencies: List<KtBinaryModule>,
session: LLFirSession
): ModuleDataProvider {
val moduleDatas = binaryDependencies.map { LLFirKtModuleBasedModuleData(it) }
if (moduleDatas.isEmpty()) {
return EmptyModuleDataProvider(sourceModule.platform, sourceModule.analyzerServices)
)
add(OptionalAnnotationClassesProvider(session, moduleDataProvider, kotlinScopeProvider, packagePartProvider))
}
moduleDatas.forEach { it.bindSession(session) }
val moduleDataWithFilters: Map<FirModuleData, LibraryPathFilter.LibraryList> =
moduleDatas.associateWith { moduleData ->
checkIsInstance<LLFirKtModuleBasedModuleData>(moduleData)
val ktBinaryModule = moduleData.ktModule as KtBinaryModule
val moduleBinaryRoots = ktBinaryModule.getBinaryRoots().mapTo(mutableSetOf()) { it.toAbsolutePath() }
LibraryPathFilter.LibraryList(moduleBinaryRoots)
}
return MultipleModuleDataProvider(moduleDataWithFilters)
}
fun createLibraryProvidersForAllProjectLibraries(
session: LLFirSession,
moduleData: LLFirModuleData,
kotlinScopeProvider: FirKotlinScopeProvider,
project: Project,
builtinTypes: BuiltinTypes,
scope: GlobalSearchScope,
): List<FirSymbolProvider> {
val moduleDataProvider = SingleModuleDataProvider(moduleData)
val packagePartProvider = project.createPackagePartProviderForLibrary(scope)
return buildList {
add(
JvmClassFileBasedSymbolProvider(
session,
moduleDataProvider,
kotlinScopeProvider,
packagePartProvider,
VirtualFileFinderFactory.getInstance(project).create(scope),
LLFirJavaFacadeForBinaries(session, builtinTypes, project.createJavaClassFinder(scope), moduleDataProvider)
)
)
add(OptionalAnnotationClassesProvider(session, moduleDataProvider, kotlinScopeProvider, packagePartProvider))
}
}
}
@@ -6,23 +6,20 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure
import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope
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.LLFirLibrariesSessionProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirBuiltinsAndCloneableSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirLibrariesSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLFirLibrarySessionProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirLibraryLikeSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirLibrarySession
import org.jetbrains.kotlin.analysis.project.structure.KtBinaryModule
import org.jetbrains.kotlin.analysis.project.structure.KtModule
import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.fir.BuiltinTypes
import org.jetbrains.kotlin.analysis.project.structure.allDirectDependenciesOfType
import org.jetbrains.kotlin.analysis.providers.createLibrariesModificationTracker
import org.jetbrains.kotlin.analysis.utils.caches.softCachedValue
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.impl.FirCloneableSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirCompositeSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
import org.jetbrains.kotlin.fir.resolve.scopes.wrapScopeWithJvmMapped
import org.jetbrains.kotlin.fir.resolve.transformers.FirPhaseCheckingPhaseManager
@@ -34,78 +31,66 @@ import org.jetbrains.kotlin.fir.session.registerModuleData
import org.jetbrains.kotlin.fir.symbols.FirPhaseManager
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver
import java.util.concurrent.ConcurrentHashMap
import org.jetbrains.kotlin.analysis.utils.caches.getValue
@OptIn(PrivateSessionConstructor::class, SessionConfiguration::class)
internal class LLFirLibrarySessionFactory(
private val project: Project,
private val useSiteModule: KtModule,
private val useSiteLanguageVersionSettings: LanguageVersionSettings,
) {
val builtInTypes = BuiltinTypes()
val builtinsAndCloneableSession = createBuiltinsAndCloneableSession()
private val librarySessionByModule = ConcurrentHashMap<KtModule, LLFirLibrariesSession>()
fun getLibrarySessionForSourceModule(ktModule: KtSourceModule): LLFirLibrariesSession {
return librarySessionByModule.getOrPut(ktModule) { createModuleLibrariesSession(ktModule) }
private val librarySessionByModule by softCachedValue(project, project.createLibrariesModificationTracker()) {
ConcurrentHashMap<KtBinaryModule, LLFirLibrarySession>()
}
fun getLibrarySessionsForModule(module: KtModule): List<LLFirLibraryLikeSession> = buildList {
LLFirBuiltinsSessionFactory.getInstance(project).getBuiltinsSession(module.platform).let(::add)
return module.allDirectDependenciesOfType<KtBinaryModule>().mapTo(this) { getLibrarySession(it) }
}
private fun getLibrarySession(ktBinaryModule: KtBinaryModule): LLFirLibrarySession {
return librarySessionByModule.getOrPut(ktBinaryModule) { createModuleLibrariesSession(ktBinaryModule) }
}
private fun createModuleLibrariesSession(
sourceModule: KtSourceModule,
): LLFirLibrariesSession {
return LLFirLibrariesSession(project, builtInTypes).apply session@{
registerModuleData(LLFirKtModuleBasedModuleData(sourceModule).apply { bindSession(this@session) })
ktLibraryModule: KtBinaryModule,
): LLFirLibrarySession {
val platform = ktLibraryModule.platform
val builtinsSession = LLFirBuiltinsSessionFactory.getInstance(project).getBuiltinsSession(platform)
return LLFirLibrarySession(project, builtinsSession.builtinTypes).apply session@{
val moduleData = LLFirKtModuleBasedModuleData(ktLibraryModule).apply { bindSession(this@session) }
registerModuleData(moduleData)
registerIdeComponents(project)
register(FirPhaseManager::class, FirPhaseCheckingPhaseManager)
registerCommonComponents(sourceModule.languageVersionSettings)
registerCommonComponents(LanguageVersionSettingsImpl.DEFAULT/*TODO*/)
registerCommonJavaComponents(JavaModuleResolver.getInstance(project))
registerJavaSpecificResolveComponents()
val kotlinScopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped)
register(FirKotlinScopeProvider::class, kotlinScopeProvider)
val providers = LLFirLibraryProviderFactory.createProvidersByModuleLibraryDependencies(
val providers = LLFirLibraryProviderFactory.createLibraryProvidersForSingleBinaryModule(
this,
sourceModule,
moduleData,
ktLibraryModule,
kotlinScopeProvider,
project,
builtinTypes
) { binaryDependencies ->
GlobalSearchScope.union(binaryDependencies.map { it.contentScope })
}
)
val symbolProvider = createCompositeSymbolProvider(this) {
addAll(providers)
add(builtinsAndCloneableSession.symbolProvider)
add(builtinsSession.symbolProvider)
}
register(FirProvider::class, LLFirLibrariesSessionProvider(symbolProvider))
register(FirProvider::class, LLFirLibrarySessionProvider(symbolProvider))
register(FirSymbolProvider::class, symbolProvider)
register(FirJvmTypeMapper::class, FirJvmTypeMapper(this))
}
}
private fun createBuiltinsAndCloneableSession(): LLFirBuiltinsAndCloneableSession {
return LLFirBuiltinsAndCloneableSession(project, builtInTypes).apply session@{
val moduleData = LLFirBuiltinsModuleData(useSiteModule).apply {
bindSession(this@session)
}
registerIdeComponents(project)
register(FirPhaseManager::class, FirPhaseCheckingPhaseManager)
registerCommonComponents(useSiteLanguageVersionSettings)
registerModuleData(moduleData)
val kotlinScopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped)
register(FirKotlinScopeProvider::class, kotlinScopeProvider)
val symbolProvider = createCompositeSymbolProvider(this) {
add(LLFirBuiltinSymbolProvider(this@session, moduleData, kotlinScopeProvider))
add(FirCloneableSymbolProvider(this@session, moduleData, kotlinScopeProvider))
}
register(FirSymbolProvider::class, symbolProvider)
register(FirProvider::class, LLFirBuiltinsAndCloneableSessionProvider(symbolProvider))
register(FirJvmTypeMapper::class, FirJvmTypeMapper(this))
}
companion object {
fun getInstance(project: Project): LLFirLibrarySessionFactory =
project.getService(LLFirLibrarySessionFactory::class.java)
}
}
@@ -14,7 +14,7 @@ import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
internal class LLFirLibrariesSessionProvider(
internal class LLFirLibrarySessionProvider(
override val symbolProvider: FirSymbolProvider
) : FirProvider() {
override fun getFirClassifierByFqName(classId: ClassId): FirClassLikeDeclaration? =
@@ -28,6 +28,6 @@ internal class LLFirLibrariesSessionProvider(
override fun getClassNamesInPackage(fqName: FqName): Set<Name> = shouldNotBeCalled()
private fun shouldNotBeCalled(): Nothing = error("Should not be called for LLFirLibrariesSessionProvider")
private fun shouldNotBeCalled(): Nothing = error("Should not be called for LLFirLibrarySessionProvider")
}
@@ -13,7 +13,7 @@ import org.jetbrains.kotlin.fir.PrivateSessionConstructor
* [org.jetbrains.kotlin.fir.FirSession] responsible for all libraries analysing module transitively depends on
*/
@OptIn(PrivateSessionConstructor::class)
internal class LLFirLibrariesSession @PrivateSessionConstructor constructor(
internal class LLFirLibrarySession @PrivateSessionConstructor constructor(
project: Project,
builtinTypes: BuiltinTypes,
) : LLFirLibraryLikeSession(project, builtinTypes)
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirGlobalResolveCompone
import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirModuleResolveComponents
import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirPhaseManager
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.*
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirLibraryProviderFactory
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirLibrarySessionFactory
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.registerIdeComponents
import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.*
@@ -55,6 +54,7 @@ internal object LLFirSessionFactory {
configureSession: (LLFirSession.() -> Unit)? = null
): LLFirSourcesSession {
sessionsCache[module]?.let { return it as LLFirSourcesSession }
val platform = module.platform
val languageVersionSettings = object : LanguageVersionSettings by module.languageVersionSettings {
override fun getFeatureSupport(feature: LanguageFeature): LanguageFeature.State =
if (feature == LanguageFeature.EnableDfaWarningsInK2) LanguageFeature.State.ENABLED
@@ -72,7 +72,12 @@ internal object LLFirSessionFactory {
val contentScope = module.contentScope
val dependentModules = module.directRegularDependenciesOfType<KtSourceModule>()
val session = LLFirSourcesSession(module, project, components, librariesSessionFactory.builtInTypes)
val session = LLFirSourcesSession(
module,
project,
components,
LLFirBuiltinsSessionFactory.getInstance(project).getBuiltinsSession(platform).builtinTypes
)
sessionsCache[module] = session
components.session = session
@@ -105,7 +110,7 @@ internal object LLFirSessionFactory {
}
val dependencyProvider = LLFirDependentModuleProviders(this) {
add(librariesSessionFactory.getLibrarySessionForSourceModule(module).symbolProvider)
librariesSessionFactory.getLibrarySessionsForModule(module).mapTo(this) { it.symbolProvider }
dependentModules
.mapTo(this) { dependentSourceModule ->
val dependentSourceSession = createSourcesSession(
@@ -148,10 +153,9 @@ internal object LLFirSessionFactory {
fun createLibraryOrLibrarySourceResolvableSession(
project: Project,
module: KtModule,
builtinsAndCloneableSession: LLFirBuiltinsAndCloneableSession,
globalComponents: LLFirGlobalResolveComponents,
sessionInvalidator: LLFirSessionInvalidator,
builtinTypes: BuiltinTypes,
builtinSession: LLFirBuiltinsAndCloneableSession,
sessionsCache: MutableMap<KtModule, LLFirResolvableModuleSession>,
languageVersionSettings: LanguageVersionSettings = LanguageVersionSettingsImpl.DEFAULT,
configureSession: (LLFirSession.() -> Unit)? = null
@@ -170,7 +174,7 @@ internal object LLFirSessionFactory {
val components = LLFirModuleResolveComponents(module, globalComponents, scopeProvider)
val contentScope = module.contentScope
val session = LLFirLibraryOrLibrarySourceResolvableModuleSession(module, project, components, builtinTypes)
val session = LLFirLibraryOrLibrarySourceResolvableModuleSession(module, project, components, builtinSession.builtinTypes)
sessionsCache[module] = session
components.session = session
@@ -205,11 +209,11 @@ internal object LLFirSessionFactory {
// <all libraries scope> - <current library scope>
val librariesSearchScope =
ProjectScope.getLibrariesScope(project).intersectWith(GlobalSearchScope.notScope(libraryModule.contentScope))
add(builtinsAndCloneableSession.symbolProvider)
add(builtinSession.symbolProvider)
addAll(
LLFirLibraryProviderFactory.createProvidersByModuleLibraryDependencies(
session, module, scopeProvider, project, builtinTypes
) { librariesSearchScope }
LLFirLibraryProviderFactory.createLibraryProvidersForAllProjectLibraries(
session, moduleData, scopeProvider, project, builtinTypes, librariesSearchScope
)
)
}
@@ -16,20 +16,15 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.firKtMo
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.addValueFor
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.executeWithoutPCE
import org.jetbrains.kotlin.analysis.project.structure.*
import org.jetbrains.kotlin.analysis.providers.createLibrariesModificationTracker
import org.jetbrains.kotlin.analysis.providers.createModuleWithoutDependenciesOutOfBlockModificationTracker
import org.jetbrains.kotlin.analysis.utils.caches.getValue
import org.jetbrains.kotlin.analysis.utils.caches.softCachedValue
import org.jetbrains.kotlin.analysis.utils.errors.unexpectedElementError
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
import java.util.concurrent.ConcurrentHashMap
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.LLFirBuiltinsSessionFactory
class LLFirSessionProviderStorage(val project: Project) {
private val sessionsCache = ConcurrentHashMap<KtModule, FromModuleViewSessionCache>()
private val librariesFactoryByUseSiteModule by softCachedValue(project, project.createLibrariesModificationTracker()) {
ConcurrentHashMap<KtModule, LLFirLibrarySessionFactory>()
}
private val librariesSessionFactory = LLFirLibrarySessionFactory.getInstance(project)
private val builtInsSessionFactopry = LLFirBuiltinsSessionFactory.getInstance(project)
fun getSessionProvider(
useSiteKtModule: KtModule,
@@ -37,15 +32,6 @@ class LLFirSessionProviderStorage(val project: Project) {
): LLFirSessionProvider {
val globalComponents = LLFirGlobalResolveComponents(useSiteKtModule, project)
val librariesSessionFactory = librariesFactoryByUseSiteModule.getOrPut(useSiteKtModule) {
val languageVersionSettings = when (useSiteKtModule) {
is KtSourceModule -> useSiteKtModule.languageVersionSettings
is KtLibraryModule, is KtLibrarySourceModule -> LanguageVersionSettingsImpl.DEFAULT
else -> unexpectedElementError("module", useSiteKtModule)
}
LLFirLibrarySessionFactory(project, useSiteKtModule, languageVersionSettings)
}
val cache = sessionsCache.getOrPut(useSiteKtModule) { FromModuleViewSessionCache() }
val (sessions, session) = cache.withMappings(project) { mappings ->
val sessions = mutableMapOf<KtModule, LLFirResolvableModuleSession>().apply { putAll(mappings) }
@@ -58,7 +44,7 @@ class LLFirSessionProviderStorage(val project: Project) {
globalComponents,
cache.sessionInvalidator,
sessions,
librariesSessionFactory = librariesSessionFactory,
librariesSessionFactory,
configureSession = configureSession,
)
}
@@ -66,10 +52,9 @@ class LLFirSessionProviderStorage(val project: Project) {
LLFirSessionFactory.createLibraryOrLibrarySourceResolvableSession(
project,
useSiteKtModule,
librariesSessionFactory.builtinsAndCloneableSession,
globalComponents,
cache.sessionInvalidator,
librariesSessionFactory.builtInTypes,
builtInsSessionFactopry.getBuiltinsSession(useSiteKtModule.platform),
sessions,
configureSession = configureSession,
)
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.analysis.api.fir.references.ReadWriteAccessCheckerFi
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.PackagePartProviderFactory
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.*
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
@@ -46,6 +47,8 @@ object AnalysisApiFirTestServiceRegistrar : AnalysisApiTestServiceRegistrar() {
registerService(KtAnalysisSessionProvider::class.java, KtFirAnalysisSessionProvider(this))
registerService(FirSealedClassInheritorsProcessorFactory::class.java, LLFirSealedClassInheritorsProcessorFactoryForTests())
registerService(LLFirResolveSessionService::class.java)
registerService(LLFirLibrarySessionFactory::class.java)
registerService(LLFirBuiltinsSessionFactory::class.java)
registerService(PackagePartProviderFactory::class.java, PackagePartProviderTestImpl(testServices))
registerService(SymbolLightClassFacadeCache::class.java)
@@ -58,18 +58,18 @@ object FirLowLevelCompilerBasedTestConfigurator : AnalysisApiTestConfigurator()
return KtModuleProjectStructure(
mainModules = mainModules,
binaryModules = mainModules.asSequence().flatMap { it.ktModule.allDirectDependenciesOfType<KtLibraryModule>() }.asIterable(),
stdlibFor = { module ->
createFakeStdlibModule(module, project)
stdlibFor = { platform ->
createFakeStdlibModule(platform, project)
}
)
}
private fun createFakeStdlibModule(
module: KtModule,
platform: TargetPlatform,
project: Project
): KtLibraryModule = KtLibraryModuleImpl(
libraryName = "fake-std-lib",
platform = module.platform,
platform = platform,
contentScope = ProjectScope.getLibrariesScope(project),
project = project,
binaryRoots = emptyList(),
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.analysis.project.structure
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.platform.TargetPlatform
public abstract class ProjectStructureProvider {
/**
@@ -20,7 +21,7 @@ public abstract class ProjectStructureProvider {
// TODO: We rather need a session or facade that maintains this information.
public abstract fun getKtBinaryModules(): Collection<KtBinaryModule>
public abstract fun getStdlibWithBuiltinsModule(module: KtModule): KtLibraryModule?
public abstract fun getStdlibWithBuiltinsModule(platform: TargetPlatform): KtLibraryModule?
}
/**