[FIR] Commonize code for creating common, JVM and JS session

Extract FirAbstractSessionFactory
This commit is contained in:
Ivan Kochurkin
2022-06-21 18:38:15 +03:00
parent d6f235679b
commit 94527e24e8
4 changed files with 369 additions and 451 deletions
@@ -5,11 +5,9 @@
package org.jetbrains.kotlin.test.frontend.fir
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.StandardFileSystems
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.psi.PsiElementFinder
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.ProjectScope
import org.jetbrains.kotlin.analyzer.common.CommonPlatformAnalyzerServices
import org.jetbrains.kotlin.asJava.finder.JavaElementFinder
@@ -21,13 +19,10 @@ import org.jetbrains.kotlin.cli.jvm.config.jvmClasspathRoots
import org.jetbrains.kotlin.cli.jvm.config.jvmModularRoots
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.FirAnalyzerFacade
import org.jetbrains.kotlin.fir.checkers.registerExtendedCommonCheckers
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
import org.jetbrains.kotlin.fir.session.FirSessionFactory
import org.jetbrains.kotlin.ir.backend.js.jsResolveLibraries
import org.jetbrains.kotlin.ir.backend.js.toResolverLogger
@@ -101,33 +96,82 @@ class FirFrontendFacade(
additionalSessionConfiguration?.invoke(this)
}
val isCommonOrJvm = module.targetPlatform.isJvm() || module.targetPlatform.isCommon()
val dependencyList: DependencyListForCliModule = buildDependencyList(module, moduleName, moduleInfoProvider, analyzerServices) {
if (isCommonOrJvm) {
configureJvmDependencies(configuration)
} else {
configureJsDependencies(module, testServices)
}
}
val projectEnvironment: VfsBasedProjectEnvironment?
if (isCommonOrJvm) {
val packagePartProviderFactory = compilerConfigurationProvider.getPackagePartProviderFactory(module)
projectEnvironment = VfsBasedProjectEnvironment(
project, VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL),
) { packagePartProviderFactory.invoke(it) }
val projectFileSearchScope = PsiBasedProjectFileSearchScope(ProjectScope.getLibrariesScope(project))
val packagePartProvider = projectEnvironment.getPackagePartProvider(projectFileSearchScope)
FirSessionFactory.createLibrarySession(
moduleName,
moduleInfoProvider.firSessionProvider,
dependencyList,
projectEnvironment,
projectFileSearchScope,
packagePartProvider,
languageVersionSettings,
)
} else {
projectEnvironment = null
FirJsSessionFactory.createLibrarySession(
moduleName,
moduleInfoProvider.firSessionProvider,
dependencyList,
module,
testServices,
configuration,
languageVersionSettings,
)
}
val mainModuleData = FirModuleDataImpl(
moduleName,
dependencyList.regularDependencies,
dependencyList.dependsOnDependencies,
dependencyList.friendsDependencies,
dependencyList.platform,
dependencyList.analyzerServices
)
val session = when {
module.targetPlatform.isJvm() || module.targetPlatform.isCommon() -> {
configureSessionsForJvmOrCommon(
module,
moduleName,
project,
ktFiles,
compilerConfigurationProvider,
moduleInfoProvider,
analyzerServices,
configuration,
sessionConfigurator,
isCommonOrJvm -> {
FirSessionFactory.createModuleBasedSession(
mainModuleData,
moduleInfoProvider.firSessionProvider,
PsiBasedProjectFileSearchScope(TopDownAnalyzerFacadeForJVM.newModuleSearchScope(project, ktFiles)),
projectEnvironment!!,
incrementalCompilationContext = null,
extensionRegistrars,
languageVersionSettings,
lookupTracker = null,
enumWhenTracker = null,
needRegisterJavaElementFinder = true,
sessionConfigurator,
)
}
module.targetPlatform.isJs() -> {
configureSessionsForJs(
module,
moduleName,
moduleInfoProvider,
analyzerServices,
configuration,
testServices,
sessionConfigurator,
FirJsSessionFactory.createModuleBasedSession(
mainModuleData,
moduleInfoProvider.firSessionProvider,
extensionRegistrars,
languageVersionSettings,
null,
sessionConfigurator,
)
}
else -> error("Unsupported")
@@ -213,166 +257,6 @@ private fun buildDependencyList(
sourceDependsOnDependencies(moduleInfoProvider.getDependentDependsOnSourceModules(module))
}
private fun configureSessionsForJvmOrCommon(
module: TestModule,
moduleName: Name,
project: Project,
ktFiles: Collection<KtFile>,
compilerConfigurationProvider: CompilerConfigurationProvider,
moduleInfoProvider: FirModuleInfoProvider,
analyzerServices: PlatformDependentAnalyzerServices,
configuration: CompilerConfiguration,
sessionConfigurator: FirSessionFactory.FirSessionConfigurator.() -> Unit,
extensionRegistrars: List<FirExtensionRegistrar>,
languageVersionSettings: LanguageVersionSettings = LanguageVersionSettingsImpl.DEFAULT,
): FirSession {
val librariesScope = ProjectScope.getLibrariesScope(project)
val sourcesScope = TopDownAnalyzerFacadeForJVM.newModuleSearchScope(project, ktFiles)
val dependencyList = buildDependencyList(module, moduleName, moduleInfoProvider, analyzerServices) {
configureJvmDependencies(configuration)
}
configureLibrarySessionForJvmOrCommon(
module,
moduleName,
moduleInfoProvider.firSessionProvider,
dependencyList,
librariesScope,
project,
compilerConfigurationProvider,
languageVersionSettings,
)
val mainModuleData = FirModuleDataImpl(
moduleName,
dependencyList.regularDependencies,
dependencyList.dependsOnDependencies,
dependencyList.friendsDependencies,
dependencyList.platform,
dependencyList.analyzerServices
)
return configureMainSessionForJvmOrCommon(
module,
project,
compilerConfigurationProvider,
sessionConfigurator,
extensionRegistrars,
sourcesScope,
mainModuleData,
moduleInfoProvider.firSessionProvider,
languageVersionSettings,
)
}
private fun configureLibrarySessionForJvmOrCommon(
module: TestModule,
moduleName: Name,
sessionProvider: FirProjectSessionProvider,
dependencyList: DependencyListForCliModule,
librariesScope: GlobalSearchScope,
project: Project,
compilerConfigurationProvider: CompilerConfigurationProvider,
languageVersionSettings: LanguageVersionSettings = LanguageVersionSettingsImpl.DEFAULT,
): FirSession {
val packagePartProviderFactory = compilerConfigurationProvider.getPackagePartProviderFactory(module)
val projectEnvironment = VfsBasedProjectEnvironment(
project, VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL),
) { packagePartProviderFactory.invoke(it) }
val projectFileSearchScope = PsiBasedProjectFileSearchScope(librariesScope)
return FirSessionFactory.createLibrarySession(
moduleName,
sessionProvider,
dependencyList.moduleDataProvider,
projectFileSearchScope,
projectEnvironment,
projectEnvironment.getPackagePartProvider(projectFileSearchScope),
languageVersionSettings,
)
}
private fun configureMainSessionForJvmOrCommon(
module: TestModule,
project: Project,
compilerConfigurationProvider: CompilerConfigurationProvider,
sessionConfigurator: FirSessionFactory.FirSessionConfigurator.() -> Unit,
extensionRegistrars: List<FirExtensionRegistrar>,
sourcesScope: GlobalSearchScope,
mainModuleData: FirModuleData,
sessionProvider: FirProjectSessionProvider,
languageVersionSettings: LanguageVersionSettings = LanguageVersionSettingsImpl.DEFAULT,
): FirSession {
val packagePartProviderFactory = compilerConfigurationProvider.getPackagePartProviderFactory(module)
val projectEnvironment = VfsBasedProjectEnvironment(
project, VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL),
) { packagePartProviderFactory.invoke(it) }
val projectFileSearchScope = PsiBasedProjectFileSearchScope(sourcesScope)
return FirSessionFactory.createJavaModuleBasedSession(
mainModuleData,
sessionProvider,
projectFileSearchScope,
projectEnvironment,
incrementalCompilationContext = null,
extensionRegistrars,
languageVersionSettings,
lookupTracker = null,
enumWhenTracker = null,
needRegisterJavaElementFinder = true,
sessionConfigurator,
)
}
private fun configureSessionsForJs(
module: TestModule,
moduleName: Name,
moduleInfoProvider: FirModuleInfoProvider,
analyzerServices: PlatformDependentAnalyzerServices,
configuration: CompilerConfiguration,
testServices: TestServices,
sessionConfigurator: FirSessionFactory.FirSessionConfigurator.() -> Unit,
extensionRegistrars: List<FirExtensionRegistrar>,
languageVersionSettings: LanguageVersionSettings = LanguageVersionSettingsImpl.DEFAULT,
): FirSession {
val dependencyList = buildDependencyList(module, moduleName, moduleInfoProvider, analyzerServices) {
configureJsDependencies(module, testServices)
}
FirJsSessionFactory.createJsLibrarySession(
moduleName,
module,
testServices,
configuration,
moduleInfoProvider.firSessionProvider,
dependencyList.moduleDataProvider,
languageVersionSettings,
)
val mainModuleData = FirModuleDataImpl(
moduleName,
dependencyList.regularDependencies,
dependencyList.dependsOnDependencies,
dependencyList.friendsDependencies,
dependencyList.platform,
dependencyList.analyzerServices
)
return FirJsSessionFactory.createJsModuleBasedSession(
mainModuleData,
moduleInfoProvider.firSessionProvider,
extensionRegistrars,
languageVersionSettings,
null,
sessionConfigurator,
)
}
fun TargetPlatform.getAnalyzerServices(): PlatformDependentAnalyzerServices {
return when {
isJvm() -> JvmPlatformAnalyzerServices
@@ -10,72 +10,79 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.analysis.FirOverridesBackwardCompatibilityHelper
import org.jetbrains.kotlin.fir.checkers.registerCommonCheckers
import org.jetbrains.kotlin.fir.checkers.registerJsCheckers
import org.jetbrains.kotlin.fir.deserialization.ModuleDataProvider
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar
import org.jetbrains.kotlin.fir.extensions.FirSwitchableExtensionDeclarationsSymbolProvider
import org.jetbrains.kotlin.fir.java.FirCliSession
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
import org.jetbrains.kotlin.fir.resolve.calls.ConeCallConflictResolverFactory
import org.jetbrains.kotlin.fir.resolve.calls.FirSyntheticNamesProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirDependenciesSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.impl.*
import org.jetbrains.kotlin.fir.resolve.scopes.wrapScopeWithJvmMapped
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirBuiltinSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirCloneableSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirDependenciesSymbolProviderImpl
import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider
import org.jetbrains.kotlin.fir.scopes.FirPlatformClassMapper
import org.jetbrains.kotlin.fir.session.*
import org.jetbrains.kotlin.fir.session.FirAbstractSessionFactory
import org.jetbrains.kotlin.fir.session.FirSessionFactory
import org.jetbrains.kotlin.fir.session.KlibBasedSymbolProvider
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestServices
object FirJsSessionFactory {
@OptIn(PrivateSessionConstructor::class, SessionConfiguration::class)
fun createJsLibrarySession(
object FirJsSessionFactory : FirAbstractSessionFactory() {
fun createLibrarySession(
mainModuleName: Name,
sessionProvider: FirProjectSessionProvider,
dependencyListForCliModule: DependencyListForCliModule,
module: TestModule,
testServices: TestServices,
configuration: CompilerConfiguration,
sessionProvider: FirProjectSessionProvider,
moduleDataProvider: ModuleDataProvider,
languageVersionSettings: LanguageVersionSettings = LanguageVersionSettingsImpl.DEFAULT,
languageVersionSettings: LanguageVersionSettings,
): FirSession {
return FirCliSession(sessionProvider, FirSession.Kind.Library).apply session@{
moduleDataProvider.allModuleData.forEach {
sessionProvider.registerSession(it, this)
it.bindSession(this)
val moduleDataProvider = dependencyListForCliModule.moduleDataProvider
return createLibrarySession(
mainModuleName,
sessionProvider,
moduleDataProvider,
languageVersionSettings,
null,
createKotlinScopeProvider = { FirKotlinScopeProvider { _, declaredMemberScope, _, _ -> declaredMemberScope } },
createProviders = { session, builtinsModuleData, kotlinScopeProvider ->
listOf(
FirBuiltinSymbolProvider(session, builtinsModuleData, kotlinScopeProvider),
FirCloneableSymbolProvider(session, builtinsModuleData, kotlinScopeProvider),
FirDependenciesSymbolProviderImpl(session),
) + resolveJsLibraries(module, testServices, configuration).map {
KlibBasedSymbolProvider(session, moduleDataProvider, kotlinScopeProvider, it)
}
})
}
fun createModuleBasedSession(
moduleData: FirModuleData,
sessionProvider: FirProjectSessionProvider,
extensionRegistrars: List<FirExtensionRegistrar>,
languageVersionSettings: LanguageVersionSettings = LanguageVersionSettingsImpl.DEFAULT,
lookupTracker: LookupTracker?,
init: FirSessionConfigurator.() -> Unit
): FirSession {
return createModuleBasedSession(
moduleData,
sessionProvider,
extensionRegistrars,
languageVersionSettings,
lookupTracker,
null,
init,
registerExtraComponents = { it.registerJsSpecificResolveComponents() },
registerExtraCheckers = { it.registerJsCheckers() },
createKotlinScopeProvider = { FirKotlinScopeProvider { _, declaredMemberScope, _, _ -> declaredMemberScope } },
createProviders = { _, _, symbolProvider, generatedSymbolsProvider, dependenciesSymbolProvider ->
listOfNotNull(
symbolProvider,
generatedSymbolsProvider,
dependenciesSymbolProvider,
)
}
registerCliCompilerOnlyComponents()
registerCommonComponents(languageVersionSettings)
val kotlinScopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped)
register(FirKotlinScopeProvider::class, kotlinScopeProvider)
val builtinsModuleData = FirSessionFactory.createModuleDataForBuiltins(
mainModuleName,
moduleDataProvider.platform,
moduleDataProvider.analyzerServices
).also { it.bindSession(this@session) }
val klibProviders = resolveJsLibraries(module, testServices, configuration).map {
KlibBasedSymbolProvider(this@session, moduleDataProvider, kotlinScopeProvider, it)
}
val otherProviders = listOf(
FirBuiltinSymbolProvider(this, builtinsModuleData, kotlinScopeProvider),
FirCloneableSymbolProvider(this, builtinsModuleData, kotlinScopeProvider),
FirDependenciesSymbolProviderImpl(this)
)
val symbolProvider = FirCompositeSymbolProvider(this, otherProviders + klibProviders)
register(FirSymbolProvider::class, symbolProvider)
register(FirProvider::class, FirLibrarySessionProvider(symbolProvider))
}
)
}
@OptIn(SessionConfiguration::class)
@@ -86,60 +93,4 @@ object FirJsSessionFactory {
register(FirSyntheticNamesProvider::class, FirJsSyntheticNamesProvider)
register(FirOverridesBackwardCompatibilityHelper::class, FirOverridesBackwardCompatibilityHelper.Default())
}
@OptIn(PrivateSessionConstructor::class, SessionConfiguration::class)
fun createJsModuleBasedSession(
moduleData: FirModuleData,
sessionProvider: FirProjectSessionProvider,
extensionRegistrars: List<FirExtensionRegistrar>,
languageVersionSettings: LanguageVersionSettings = LanguageVersionSettingsImpl.DEFAULT,
lookupTracker: LookupTracker? = null,
init: FirSessionFactory.FirSessionConfigurator.() -> Unit = {}
): FirSession {
return FirCliSession(sessionProvider, FirSession.Kind.Source).apply session@{
moduleData.bindSession(this@session)
sessionProvider.registerSession(moduleData, this@session)
registerModuleData(moduleData)
registerCliCompilerOnlyComponents()
registerCommonComponents(languageVersionSettings)
registerResolveComponents(lookupTracker)
registerJsSpecificResolveComponents()
val kotlinScopeProvider = FirKotlinScopeProvider { _, declaredMemberScope, _, _ -> declaredMemberScope }
register(FirKotlinScopeProvider::class, kotlinScopeProvider)
val firProvider = FirProviderImpl(this, kotlinScopeProvider)
register(FirProvider::class, firProvider)
FirSessionFactory.FirSessionConfigurator(this).apply {
registerCommonCheckers()
registerJsCheckers()
for (extensionRegistrar in extensionRegistrars) {
registerExtensions(extensionRegistrar.configure())
}
init()
}.configure()
val dependenciesSymbolProvider = FirDependenciesSymbolProviderImpl(this)
val generatedSymbolsProvider = FirSwitchableExtensionDeclarationsSymbolProvider.create(this)
register(
FirSymbolProvider::class,
FirCompositeSymbolProvider(
this,
listOfNotNull(
firProvider.symbolProvider,
generatedSymbolsProvider,
dependenciesSymbolProvider,
)
)
)
generatedSymbolsProvider?.let { register(FirSwitchableExtensionDeclarationsSymbolProvider::class, it) }
register(
FirDependenciesSymbolProvider::class,
dependenciesSymbolProvider
)
}
}
}