[FIR] Refactor deserialized dependency providers and session factories with FirModuleData

This commit is contained in:
Dmitriy Novozhilov
2021-04-30 16:57:46 +03:00
committed by TeamCityServer
parent 24f1f7b7b2
commit 02c58b7a8f
23 changed files with 566 additions and 196 deletions
@@ -0,0 +1,169 @@
/*
* Copyright 2010-2021 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.fir
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.name.Name
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
import java.nio.file.Path
import java.nio.file.Paths
class DependencyListForCliModule(
val platform: TargetPlatform,
val analyzerServices: PlatformDependentAnalyzerServices,
val regularDependencies: List<FirModuleData>,
val dependsOnDependencies: List<FirModuleData>,
val friendsDependencies: List<FirModuleData>,
val moduleDataProvider: ModuleDataProvider,
) {
companion object {
fun createDependencyModuleData(
name: Name,
platform: TargetPlatform,
analyzerServices: PlatformDependentAnalyzerServices
): FirModuleData {
return FirModuleDataImpl(
name,
dependencies = emptyList(),
dependsOnDependencies = emptyList(),
friendDependencies = emptyList(),
platform,
analyzerServices,
)
}
inline fun build(
mainModuleName: Name,
platform: TargetPlatform,
analyzerServices: PlatformDependentAnalyzerServices,
init: Builder.() -> Unit = {}
): DependencyListForCliModule {
return Builder(mainModuleName, platform, analyzerServices).apply(init).build()
}
}
class Builder(val mainModuleName: Name, val platform: TargetPlatform, val analyzerServices: PlatformDependentAnalyzerServices) {
private fun createData(name: String): FirModuleData = createDependencyModuleData(Name.special(name), platform, analyzerServices)
private val binaryRegularDependenciesModuleData: FirModuleData = createData("<regular dependencies of $mainModuleName>")
private val binaryDependsOnModuleData: FirModuleData = createData("<dependsOn dependencies of $mainModuleName")
private val binaryFriendsModuleData: FirModuleData = createData("<friends dependencies of $mainModuleName")
private val allRegularDependencies = mutableListOf<FirModuleData>()
private val allFriendsDependencies = mutableListOf<FirModuleData>()
private val allDependsOnDependencies = mutableListOf<FirModuleData>()
private val filtersMap: Map<FirModuleData, MutableSet<Path>> =
listOf(
binaryDependsOnModuleData,
binaryFriendsModuleData,
binaryRegularDependenciesModuleData
).map { it to mutableSetOf<Path>() }.toMap()
fun dependency(vararg path: Path) {
filtersMap.getValue(binaryRegularDependenciesModuleData) += path
}
fun friendDependency(vararg path: Path) {
filtersMap.getValue(binaryFriendsModuleData) += path
}
fun dependsOnDependency(vararg path: Path) {
filtersMap.getValue(binaryDependsOnModuleData) += path
}
fun dependency(vararg path: String) {
path.mapTo(filtersMap.getValue(binaryRegularDependenciesModuleData)) { Paths.get(it) }
}
fun friendDependency(vararg path: String) {
path.mapTo(filtersMap.getValue(binaryFriendsModuleData)) { Paths.get(it) }
}
fun dependsOnDependency(vararg path: String) {
path.mapTo(filtersMap.getValue(binaryDependsOnModuleData)) { Paths.get(it) }
}
@JvmName("dependenciesString")
fun dependencies(paths: Collection<String>) {
paths.mapTo(filtersMap.getValue(binaryRegularDependenciesModuleData)) { Paths.get(it) }
}
@JvmName("friendDependenciesString")
fun friendDependencies(paths: Collection<String>) {
paths.mapTo(filtersMap.getValue(binaryFriendsModuleData)) { Paths.get(it) }
}
@JvmName("dependsOnDependenciesString")
fun dependsOnDependencies(paths: Collection<String>) {
paths.mapTo(filtersMap.getValue(binaryDependsOnModuleData)) { Paths.get(it) }
}
fun dependencies(paths: Collection<Path>) {
filtersMap.getValue(binaryRegularDependenciesModuleData) += paths
}
fun friendDependencies(paths: Collection<Path>) {
filtersMap.getValue(binaryFriendsModuleData) += paths
}
fun dependsOnDependencies(paths: Collection<Path>) {
filtersMap.getValue(binaryDependsOnModuleData) += paths
}
fun sourceDependencies(modules: Collection<FirModuleData>) {
allRegularDependencies += modules
}
fun sourceFriendsDependencies(modules: Collection<FirModuleData>) {
allFriendsDependencies += modules
}
fun sourceDependsOnDependencies(modules: Collection<FirModuleData>) {
allDependsOnDependencies += modules
}
fun build(): DependencyListForCliModule {
val pathFiltersMap: MutableMap<FirModuleData, LibraryPathFilter> = filtersMap
.filterValues { it.isNotEmpty() }
.mapValues { LibraryPathFilter.LibraryList(it.value) }
.toMutableMap()
allRegularDependencies += binaryRegularDependenciesModuleData
if (pathFiltersMap.isEmpty()) {
return DependencyListForCliModule(
platform,
analyzerServices,
allRegularDependencies,
dependsOnDependencies = allDependsOnDependencies,
friendsDependencies = allFriendsDependencies,
SingleModuleDataProvider(binaryRegularDependenciesModuleData)
)
}
if (binaryFriendsModuleData in pathFiltersMap) {
allFriendsDependencies += binaryFriendsModuleData
}
if (binaryDependsOnModuleData in pathFiltersMap) {
allDependsOnDependencies += binaryDependsOnModuleData
}
val moduleDataProvider = MultipleModuleDataProvider(pathFiltersMap)
pathFiltersMap.putIfAbsent(binaryRegularDependenciesModuleData, LibraryPathFilter.TakeAll)
return DependencyListForCliModule(
platform,
analyzerServices,
allRegularDependencies,
allDependsOnDependencies,
allFriendsDependencies,
moduleDataProvider
)
}
}
}
@@ -9,13 +9,10 @@ import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElementFinder
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.analyzer.common.CommonPlatformAnalyzerServices
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
import org.jetbrains.kotlin.fir.FirModuleData
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.PrivateSessionConstructor
import org.jetbrains.kotlin.fir.SessionConfiguration
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.DeclarationCheckers
import org.jetbrains.kotlin.fir.analysis.checkers.expression.ExpressionCheckers
import org.jetbrains.kotlin.fir.analysis.checkers.type.TypeCheckers
@@ -23,6 +20,8 @@ import org.jetbrains.kotlin.fir.analysis.checkersComponent
import org.jetbrains.kotlin.fir.analysis.extensions.additionalCheckers
import org.jetbrains.kotlin.fir.checkers.registerCommonCheckers
import org.jetbrains.kotlin.fir.checkers.registerJvmCheckers
import org.jetbrains.kotlin.fir.deserialization.ModuleDataProvider
import org.jetbrains.kotlin.fir.deserialization.SingleModuleDataProvider
import org.jetbrains.kotlin.fir.extensions.BunchOfRegisteredExtensions
import org.jetbrains.kotlin.fir.extensions.extensionService
import org.jetbrains.kotlin.fir.extensions.registerExtensions
@@ -37,6 +36,11 @@ import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.load.java.JavaClassFinderImpl
import org.jetbrains.kotlin.load.kotlin.PackagePartProvider
import org.jetbrains.kotlin.load.kotlin.VirtualFileFinderFactory
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices
@OptIn(PrivateSessionConstructor::class, SessionConfiguration::class)
object FirSessionFactory {
@@ -66,20 +70,24 @@ object FirSessionFactory {
}
}
data class ProviderAndScopeForIncrementalCompilation(
val packagePartProvider: PackagePartProvider,
val scope: GlobalSearchScope
)
fun createJavaModuleBasedSession(
moduleInfo: ModuleInfo,
moduleData: FirModuleData,
sessionProvider: FirProjectSessionProvider,
scope: GlobalSearchScope,
project: Project,
additionalPackagePartProvider: PackagePartProvider? = null,
additionalScope: GlobalSearchScope? = null,
dependenciesProvider: FirSymbolProvider? = null,
providerAndScopeForIncrementalCompilation: ProviderAndScopeForIncrementalCompilation?,
languageVersionSettings: LanguageVersionSettings = LanguageVersionSettingsImpl.DEFAULT,
lookupTracker: LookupTracker? = null,
init: FirSessionConfigurator.() -> Unit = {}
): FirSession {
return FirCliSession(sessionProvider, FirCliSession.Kind.Source).apply session@{
val moduleData = FirModuleInfoBasedModuleData(moduleInfo).apply { bindSession(this@session) }
moduleData.bindSession(this@session)
sessionProvider.registerSession(moduleData, this@session)
registerModuleData(moduleData)
registerCliCompilerOnlyComponents()
registerCommonComponents(languageVersionSettings)
@@ -91,20 +99,19 @@ object FirSessionFactory {
val firProvider = FirProviderImpl(this, kotlinScopeProvider)
register(FirProvider::class, firProvider)
val deserializedJvmSymbolsProvider =
if (additionalPackagePartProvider == null) null
else {
val javaSymbolProvider = JavaSymbolProvider(this, moduleData, project, additionalScope ?: scope)
val symbolProviderForBinariesFromIncrementalCompilation = providerAndScopeForIncrementalCompilation?.let {
val javaSymbolProvider = JavaSymbolProvider(this, moduleData, project, it.scope)
makeDeserializedJvmSymbolsProvider(
moduleData,
project,
additionalScope ?: scope,
additionalPackagePartProvider,
javaSymbolProvider,
kotlinScopeProvider
)
}
makeDeserializedJvmSymbolsProvider(
this@session,
SingleModuleDataProvider(moduleData),
project,
it.scope,
it.packagePartProvider,
javaSymbolProvider,
kotlinScopeProvider
)
}
register(
FirSymbolProvider::class,
@@ -112,11 +119,11 @@ object FirSessionFactory {
this,
listOfNotNull(
firProvider.symbolProvider,
symbolProviderForBinariesFromIncrementalCompilation,
JavaSymbolProvider(this, moduleData, project, scope),
dependenciesProvider ?: FirDependenciesSymbolProviderImpl(this),
deserializedJvmSymbolsProvider
FirDependenciesSymbolProviderImpl(this)
)
) as FirSymbolProvider
)
)
FirSessionConfigurator(this).apply {
@@ -130,34 +137,50 @@ object FirSessionFactory {
}
fun createLibrarySession(
moduleInfo: ModuleInfo,
mainModuleName: Name,
sessionProvider: FirProjectSessionProvider,
moduleDataProvider: ModuleDataProvider,
scope: GlobalSearchScope,
project: Project,
packagePartProvider: PackagePartProvider,
languageVersionSettings: LanguageVersionSettings = LanguageVersionSettingsImpl.DEFAULT,
): FirSession {
return FirCliSession(sessionProvider, FirCliSession.Kind.Library).apply session@{
val moduleData = FirModuleInfoBasedModuleData(moduleInfo).apply { bindSession(this@session) }
sessionProvider.registerSession(moduleData, this)
moduleDataProvider.allModuleData.forEach {
sessionProvider.registerSession(it, this)
it.bindSession(this)
}
registerCliCompilerOnlyComponents()
registerCommonComponents(languageVersionSettings)
val javaSymbolProvider = JavaSymbolProvider(this, moduleData, project, scope)
val javaSymbolProvider = JavaSymbolProvider(this, moduleDataProvider.allModuleData.last(), project, scope)
val kotlinScopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped)
val deserializedJvmSymbolsProvider = makeDeserializedJvmSymbolsProvider(
moduleData, project, scope, packagePartProvider, javaSymbolProvider, kotlinScopeProvider
librarySession = this,
moduleDataProvider,
project,
scope,
packagePartProvider,
javaSymbolProvider,
kotlinScopeProvider
)
val builtinsModuleData = createModuleDataForBuiltins(
mainModuleName,
moduleDataProvider.platform,
moduleDataProvider.analyzerServices
).also { it.bindSession(this@session) }
val symbolProvider = FirCompositeSymbolProvider(
this,
listOf(
deserializedJvmSymbolsProvider,
FirBuiltinSymbolProvider(this, moduleData, kotlinScopeProvider),
FirCloneableSymbolProvider(this, moduleData, kotlinScopeProvider),
javaSymbolProvider,
FirBuiltinSymbolProvider(this, builtinsModuleData, kotlinScopeProvider),
FirCloneableSymbolProvider(this, builtinsModuleData, kotlinScopeProvider),
javaSymbolProvider, // TODO: looks like it can be removed
FirDependenciesSymbolProviderImpl(this)
)
)
@@ -167,7 +190,8 @@ object FirSessionFactory {
}
private fun makeDeserializedJvmSymbolsProvider(
moduleData: FirModuleData,
librarySession: FirSession,
moduleDataProvider: ModuleDataProvider,
project: Project,
scope: GlobalSearchScope,
packagePartProvider: PackagePartProvider,
@@ -182,12 +206,41 @@ object FirSessionFactory {
}
return KotlinDeserializedJvmSymbolsProvider(
moduleData, kotlinScopeProvider, packagePartProvider, kotlinClassFinder, javaSymbolProvider, javaClassFinder
librarySession,
moduleDataProvider,
kotlinScopeProvider,
packagePartProvider,
kotlinClassFinder,
javaSymbolProvider,
javaClassFinder
)
}
@TestOnly
fun createEmptySession(): FirSession {
return object : FirSession(null) {}
return object : FirSession(null) {}.apply {
val moduleData = FirModuleDataImpl(
Name.identifier("<stub module>"),
dependencies = emptyList(),
dependsOnDependencies = emptyList(),
friendDependencies = emptyList(),
platform = JvmPlatforms.unspecifiedJvmPlatform,
analyzerServices = JvmPlatformAnalyzerServices
)
registerModuleData(moduleData)
moduleData.bindSession(this)
}
}
fun createModuleDataForBuiltins(
parentModuleName: Name,
platform: TargetPlatform,
analyzerServices: PlatformDependentAnalyzerServices
): FirModuleData {
return DependencyListForCliModule.createDependencyModuleData(
Name.special("<builtins of ${parentModuleName.identifier}"),
platform,
analyzerServices,
)
}
}
@@ -7,95 +7,125 @@ package org.jetbrains.kotlin.fir
import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
import org.jetbrains.kotlin.fir.session.FirJvmModuleInfo
import org.jetbrains.kotlin.fir.session.FirSessionFactory
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.load.kotlin.PackagePartProvider
import org.jetbrains.kotlin.modules.Module
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
fun createSessionWithDependencies(
@OptIn(PrivateForInline::class)
inline fun createSessionWithDependencies(
name: Name,
friendPaths: List<String>,
outputDirectory: String?,
platform: TargetPlatform,
analyzerServices: PlatformDependentAnalyzerServices,
externalSessionProvider: FirProjectSessionProvider?,
project: Project,
languageVersionSettings: LanguageVersionSettings,
sourceScope: GlobalSearchScope,
librariesScope: GlobalSearchScope,
lookupTracker: LookupTracker?,
getPackagePartProvider: (GlobalSearchScope) -> PackagePartProvider,
getAdditionalModulePackagePartProvider: (GlobalSearchScope) -> PackagePartProvider?,
sessionConfigurator: FirSessionFactory.FirSessionConfigurator.() -> Unit = {}
getProviderAndScopeForIncrementalCompilation: () -> FirSessionFactory.ProviderAndScopeForIncrementalCompilation?,
dependenciesConfigurator: DependencyListForCliModule.Builder.() -> Unit = {},
noinline sessionConfigurator: FirSessionFactory.FirSessionConfigurator.() -> Unit = {},
): FirSession {
return createSessionWithDependencies(
name.identifier,
val dependencyList = DependencyListForCliModule.build(name, platform, analyzerServices, dependenciesConfigurator)
return createSessionWithDependenciesImpl(
name,
dependencyList,
externalSessionProvider,
project,
languageVersionSettings,
sourceScope,
librariesScope,
lookupTracker,
getPackagePartProvider,
getAdditionalModulePackagePartProvider,
getProviderAndScopeForIncrementalCompilation,
sessionConfigurator
) {
FirJvmModuleInfo(name, it, friendPaths, outputDirectory)
}
)
}
fun createSessionWithDependencies(
@OptIn(PrivateForInline::class)
inline fun createSessionWithDependencies(
module: Module,
platform: TargetPlatform,
analyzerServices: PlatformDependentAnalyzerServices,
externalSessionProvider: FirProjectSessionProvider?,
project: Project,
languageVersionSettings: LanguageVersionSettings,
sourceScope: GlobalSearchScope,
librariesScope: GlobalSearchScope,
lookupTracker: LookupTracker?,
getPackagePartProvider: (GlobalSearchScope) -> PackagePartProvider,
getAdditionalModulePackagePartProvider: (GlobalSearchScope) -> PackagePartProvider?,
sessionConfigurator: FirSessionFactory.FirSessionConfigurator.() -> Unit = {}
getProviderAndScopeForIncrementalCompilation: () -> FirSessionFactory.ProviderAndScopeForIncrementalCompilation?,
noinline sessionConfigurator: FirSessionFactory.FirSessionConfigurator.() -> Unit = {},
): FirSession {
return createSessionWithDependencies(
module.getModuleName(),
val moduleName = Name.identifier(module.getModuleName())
val dependencyList = DependencyListForCliModule.build(
moduleName,
platform,
analyzerServices
) {
friendDependencies(module.getFriendPaths())
dependencies(module.getClasspathRoots())
}
return createSessionWithDependenciesImpl(
moduleName,
dependencyList,
externalSessionProvider,
project,
languageVersionSettings,
sourceScope,
librariesScope,
lookupTracker,
getPackagePartProvider,
getAdditionalModulePackagePartProvider,
getProviderAndScopeForIncrementalCompilation,
sessionConfigurator
) {
FirJvmModuleInfo(module, it)
}
)
}
private inline fun createSessionWithDependencies(
moduleName: String,
@PrivateForInline
inline fun createSessionWithDependenciesImpl(
moduleName: Name,
dependencyListForCliModule: DependencyListForCliModule,
externalSessionProvider: FirProjectSessionProvider?,
project: Project,
languageVersionSettings: LanguageVersionSettings,
sourceScope: GlobalSearchScope,
librariesScope: GlobalSearchScope,
lookupTracker: LookupTracker?,
getPackagePartProvider: (GlobalSearchScope) -> PackagePartProvider,
getAdditionalModulePackagePartProvider: (GlobalSearchScope) -> PackagePartProvider?,
getProviderAndScopeForIncrementalCompilation: () -> FirSessionFactory.ProviderAndScopeForIncrementalCompilation?,
noinline sessionConfigurator: FirSessionFactory.FirSessionConfigurator.() -> Unit,
moduleInfoProvider: (dependencies: List<ModuleInfo>) -> ModuleInfo,
): FirSession {
val provider = FirProjectSessionProvider()
val librariesModuleInfo = FirJvmModuleInfo.createForLibraries(moduleName)
val sessionProvider = externalSessionProvider ?: FirProjectSessionProvider()
FirSessionFactory.createLibrarySession(
librariesModuleInfo, provider, librariesScope,
project, getPackagePartProvider(librariesScope)
moduleName,
sessionProvider,
dependencyListForCliModule.moduleDataProvider,
librariesScope,
project,
getPackagePartProvider(librariesScope)
)
val mainModuleData = FirModuleDataImpl(
moduleName,
dependencyListForCliModule.regularDependencies,
dependencyListForCliModule.dependsOnDependencies,
dependencyListForCliModule.friendsDependencies,
dependencyListForCliModule.platform,
dependencyListForCliModule.analyzerServices
)
return FirSessionFactory.createJavaModuleBasedSession(
moduleInfoProvider(listOf(librariesModuleInfo)),
provider,
mainModuleData,
sessionProvider,
sourceScope,
project,
additionalPackagePartProvider = getAdditionalModulePackagePartProvider(sourceScope),
additionalScope = librariesScope,
providerAndScopeForIncrementalCompilation = getProviderAndScopeForIncrementalCompilation(),
languageVersionSettings = languageVersionSettings,
lookupTracker = lookupTracker,
init = sessionConfigurator