[LL FIR] introduce platform-aware LL FIR session factories

KT-58769
This commit is contained in:
Pavel Kirpichenkov
2023-04-24 21:09:42 +03:00
committed by Space Team
parent e11f7daae4
commit 2a79643dcf
10 changed files with 833 additions and 493 deletions
@@ -20,6 +20,7 @@ dependencies {
api(project(":compiler:backend.common.jvm"))
api(project(":analysis:analysis-api-impl-barebone"))
api(project(":js:js.config"))
api(project(":compiler:cli-common"))
testApi(project(":analysis:analysis-api-fir"))
implementation(project(":compiler:frontend.common"))
implementation(project(":compiler:fir:entrypoint"))
@@ -26,10 +26,12 @@ import org.jetbrains.kotlin.fir.analysis.js.checkers.JsExpressionCheckers
import org.jetbrains.kotlin.fir.analysis.jvm.checkers.JvmDeclarationCheckers
import org.jetbrains.kotlin.fir.analysis.jvm.checkers.JvmExpressionCheckers
import org.jetbrains.kotlin.fir.analysis.jvm.checkers.JvmTypeCheckers
import org.jetbrains.kotlin.fir.analysis.native.checkers.NativeDeclarationCheckers
import org.jetbrains.kotlin.fir.extensions.extensionService
import org.jetbrains.kotlin.platform.SimplePlatform
import org.jetbrains.kotlin.platform.jvm.JvmPlatform
import org.jetbrains.kotlin.platform.JsPlatform
import org.jetbrains.kotlin.platform.konan.NativePlatform
internal abstract class AbstractLLFirDiagnosticsCollector(
session: FirSession,
@@ -81,6 +83,7 @@ private object CheckersFactory {
when (platform) {
is JvmPlatform -> add(JvmDeclarationCheckers)
is JsPlatform -> add(JsDeclarationCheckers)
is NativePlatform -> add(NativeDeclarationCheckers)
else -> {}
}
addAll(extensionCheckers.map { it.declarationCheckers })
@@ -0,0 +1,511 @@
/*
* Copyright 2010-2023 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 com.intellij.openapi.util.ModificationTracker
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.ProjectScope
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
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.*
import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.*
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.providers.impl.EmptyKotlinDeclarationProvider
import org.jetbrains.kotlin.analysis.providers.impl.FileBasedKotlinDeclarationProvider
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
import org.jetbrains.kotlin.fir.PrivateSessionConstructor
import org.jetbrains.kotlin.fir.SessionConfiguration
import org.jetbrains.kotlin.fir.analysis.checkersComponent
import org.jetbrains.kotlin.fir.analysis.extensions.additionalCheckers
import org.jetbrains.kotlin.fir.backend.jvm.FirJvmTypeMapper
import org.jetbrains.kotlin.fir.extensions.*
import org.jetbrains.kotlin.fir.java.JavaSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.DEPENDENCIES_SYMBOL_PROVIDER_QUALIFIED_KEY
import org.jetbrains.kotlin.fir.resolve.providers.FirProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirExtensionSyntheticFunctionInterfaceProvider
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.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.partitionIsInstance
@OptIn(PrivateSessionConstructor::class, SessionConfiguration::class)
internal abstract class LLFirAbstractSessionFactory(protected val project: Project) {
private val globalResolveComponents: LLFirGlobalResolveComponents
get() = LLFirGlobalResolveComponents.getInstance(project)
abstract fun createSourcesSession(module: KtSourceModule): LLFirSourcesSession
abstract fun createLibrarySession(module: KtModule): LLFirLibraryOrLibrarySourceResolvableModuleSession
abstract fun createBinaryLibrarySession(module: KtBinaryModule): LLFirLibrarySession
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 components = LLFirModuleResolveComponents(module, globalResolveComponents, scopeProvider)
val contentScope = module.contentScope
val dependencies = collectSourceModuleDependencies(module)
val dependencyTracker = createSourceModuleDependencyTracker(module, dependencies)
val session = LLFirScriptSession(module, dependencyTracker, components, builtinsSession.builtinTypes)
components.session = session
val moduleData = createModuleData(session)
return session.apply {
registerModuleData(moduleData)
register(FirKotlinScopeProvider::class, scopeProvider)
registerIdeComponents(project)
registerCommonComponents(languageVersionSettings)
registerCommonComponentsAfterExtensionsAreConfigured()
registerCommonJavaComponents(JavaModuleResolver.getInstance(project))
registerResolveComponents()
registerJavaSpecificResolveComponents()
val provider = LLFirProvider(
this,
components,
FileBasedKotlinDeclarationProvider(module.file),
project.createPackageProvider(contentScope),
canContainKotlinPackage = true,
)
register(FirProvider::class, provider)
register(FirLazyDeclarationResolver::class, LLFirLazyDeclarationResolver())
val dependencyProvider = LLFirDependenciesSymbolProvider(this, buildList {
addDependencySymbolProvidersTo(session, dependencies, this)
add(builtinsSession.symbolProvider)
})
val javaSymbolProvider = createJavaSymbolProvider(this, moduleData, project, contentScope)
register(JavaSymbolProvider::class, javaSymbolProvider)
register(
FirSymbolProvider::class,
LLFirModuleWithDependenciesSymbolProvider(
this,
providers = listOfNotNull(
javaSymbolProvider,
provider.symbolProvider,
),
dependencyProvider,
)
)
register(FirPredicateBasedProvider::class, FirEmptyPredicateBasedProvider)
register(DEPENDENCIES_SYMBOL_PROVIDER_QUALIFIED_KEY, dependencyProvider)
register(FirRegisteredPluginAnnotations::class, FirRegisteredPluginAnnotations.Empty)
LLFirSessionConfigurator.configure(this)
}
}
fun createNotUnderContentRootResolvableSession(module: KtNotUnderContentRootModule): LLFirNonUnderContentRootResolvableModuleSession {
val builtinsSession = LLFirBuiltinsSessionFactory.getInstance(project).getBuiltinsSession(JvmPlatforms.unspecifiedJvmPlatform)
val languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT
val scopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped)
val components = LLFirModuleResolveComponents(module, globalResolveComponents, scopeProvider)
val dependencyTracker = builtinsSession.modificationTracker
val session = LLFirNonUnderContentRootResolvableModuleSession(module, dependencyTracker, components, builtinsSession.builtinTypes)
components.session = session
val moduleData = createModuleData(session)
return session.apply {
registerModuleData(moduleData)
register(FirKotlinScopeProvider::class, scopeProvider)
registerIdeComponents(project)
registerCommonComponents(languageVersionSettings)
registerCommonComponentsAfterExtensionsAreConfigured()
registerCommonJavaComponents(JavaModuleResolver.getInstance(project))
registerResolveComponents()
registerJavaSpecificResolveComponents()
val ktFile = module.file as? KtFile
val provider = LLFirProvider(
this,
components,
if (ktFile != null) FileBasedKotlinDeclarationProvider(ktFile) else EmptyKotlinDeclarationProvider,
project.createPackageProvider(module.contentScope),
canContainKotlinPackage = true,
)
register(FirProvider::class, provider)
register(FirLazyDeclarationResolver::class, LLFirLazyDeclarationResolver())
val dependencyProvider = LLFirDependenciesSymbolProvider(this, listOf(builtinsSession.symbolProvider))
register(
FirSymbolProvider::class,
LLFirModuleWithDependenciesSymbolProvider(
this,
providers = listOf(
provider.symbolProvider,
),
dependencyProvider,
)
)
register(FirPredicateBasedProvider::class, FirEmptyPredicateBasedProvider)
register(DEPENDENCIES_SYMBOL_PROVIDER_QUALIFIED_KEY, dependencyProvider)
register(FirJvmTypeMapper::class, FirJvmTypeMapper(this))
register(FirRegisteredPluginAnnotations::class, FirRegisteredPluginAnnotations.Empty)
LLFirSessionConfigurator.configure(this)
}
}
protected class SourceSessionCreationContext(
val moduleData: LLFirModuleData,
val contentScope: GlobalSearchScope,
val firProvider: LLFirProvider,
val dependencyProvider: LLFirDependenciesSymbolProvider,
val syntheticFunctionInterfaceProvider: FirExtensionSyntheticFunctionInterfaceProvider?,
val switchableExtensionDeclarationsSymbolProvider: FirSwitchableExtensionDeclarationsSymbolProvider?,
)
protected fun doCreateSourcesSession(
module: KtSourceModule,
scopeProvider: FirKotlinScopeProvider = FirKotlinScopeProvider(),
additionalSessionConfiguration: LLFirSourcesSession.(context: SourceSessionCreationContext) -> Unit,
): LLFirSourcesSession {
val platform = module.platform
val builtinsSession = LLFirBuiltinsSessionFactory.getInstance(project).getBuiltinsSession(platform)
val languageVersionSettings = wrapLanguageVersionSettings(module.languageVersionSettings)
val components = LLFirModuleResolveComponents(module, globalResolveComponents, scopeProvider)
val dependencies = collectSourceModuleDependencies(module)
val dependencyTracker = createSourceModuleDependencyTracker(module, dependencies)
val session = LLFirSourcesSession(module, dependencyTracker, components, builtinsSession.builtinTypes)
components.session = session
val moduleData = createModuleData(session)
val contentScope = module.contentScope
return session.apply {
registerModuleData(moduleData)
register(FirKotlinScopeProvider::class, scopeProvider)
registerIdeComponents(project)
registerCommonComponents(languageVersionSettings)
registerResolveComponents()
val firProvider = LLFirProvider(
this,
components,
project.createDeclarationProvider(contentScope, module),
project.createPackageProvider(contentScope),
/* Source modules can contain `kotlin` package only if `-Xallow-kotlin-package` is specified, this is handled in LLFirProvider */
canContainKotlinPackage = false,
)
register(FirProvider::class, firProvider)
register(FirLazyDeclarationResolver::class, LLFirLazyDeclarationResolver())
registerCompilerPluginServices(contentScope, project, module)
registerCompilerPluginExtensions(project, module)
registerCommonComponentsAfterExtensionsAreConfigured()
val dependencyProvider = LLFirDependenciesSymbolProvider(this, buildList {
addDependencySymbolProvidersTo(session, dependencies, this)
add(builtinsSession.symbolProvider)
})
register(DEPENDENCIES_SYMBOL_PROVIDER_QUALIFIED_KEY, dependencyProvider)
register(LLFirFirClassByPsiClassProvider::class, LLFirFirClassByPsiClassProvider(this))
LLFirSessionConfigurator.configure(this)
extensionService.additionalCheckers.forEach(session.checkersComponent::register)
val syntheticFunctionInterfaceProvider =
FirExtensionSyntheticFunctionInterfaceProvider.createIfNeeded(this, moduleData, scopeProvider)
val switchableExtensionDeclarationsSymbolProvider =
FirSwitchableExtensionDeclarationsSymbolProvider.createIfNeeded(this)?.also {
register(FirSwitchableExtensionDeclarationsSymbolProvider::class, it)
}
val context = SourceSessionCreationContext(
moduleData, contentScope, firProvider, dependencyProvider, syntheticFunctionInterfaceProvider,
switchableExtensionDeclarationsSymbolProvider,
)
additionalSessionConfiguration(context)
}
}
protected class LibrarySessionCreationContext(
val moduleData: LLFirModuleData,
val contentScope: GlobalSearchScope,
val firProvider: LLFirProvider,
val dependencyProvider: LLFirDependenciesSymbolProvider
)
protected fun doCreateLibrarySession(
module: KtModule,
additionalSessionConfiguration: LLFirLibraryOrLibrarySourceResolvableModuleSession.(context: LibrarySessionCreationContext) -> Unit
): LLFirLibraryOrLibrarySourceResolvableModuleSession {
val libraryModule = when (module) {
is KtLibraryModule -> module
is KtLibrarySourceModule -> module.binaryLibrary
else -> error("Unexpected module ${module::class.simpleName}")
}
val platform = module.platform
val builtinsSession = LLFirBuiltinsSessionFactory.getInstance(project).getBuiltinsSession(platform)
val languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT
val scopeProvider = FirKotlinScopeProvider()
val components = LLFirModuleResolveComponents(module, globalResolveComponents, scopeProvider)
val dependencyTracker = builtinsSession.modificationTracker
val session =
LLFirLibraryOrLibrarySourceResolvableModuleSession(module, dependencyTracker, components, builtinsSession.builtinTypes)
components.session = session
val moduleData = createModuleData(session)
return session.apply {
registerModuleData(moduleData)
register(FirKotlinScopeProvider::class, scopeProvider)
registerIdeComponents(project)
registerCommonComponents(languageVersionSettings)
registerCommonComponentsAfterExtensionsAreConfigured()
registerResolveComponents()
val contentScope = module.contentScope
val firProvider = LLFirProvider(
this,
components,
project.createDeclarationProvider(contentScope, module),
project.createPackageProvider(contentScope),
canContainKotlinPackage = true,
)
register(FirProvider::class, firProvider)
register(FirLazyDeclarationResolver::class, LLFirLazyDeclarationResolver())
// We need FirRegisteredPluginAnnotations during extensions' registration process
val annotationsResolver = project.createAnnotationResolver(contentScope)
register(FirRegisteredPluginAnnotations::class, LLFirIdeRegisteredPluginAnnotations(this, annotationsResolver))
register(FirPredicateBasedProvider::class, FirEmptyPredicateBasedProvider)
val dependencyProvider = LLFirDependenciesSymbolProvider(this, buildList {
add(builtinsSession.symbolProvider)
// Script dependencies are self-contained and should not depend on other libraries
if (module !is KtScriptDependencyModule) {
// Add all libraries excluding the current one
val librariesSearchScope = ProjectScope.getLibrariesScope(project)
.intersectWith(GlobalSearchScope.notScope(libraryModule.contentScope))
val restLibrariesProvider = LLFirLibraryProviderFactory.createLibraryProvidersForAllProjectLibraries(
session, moduleData, scopeProvider,
project, builtinTypes, librariesSearchScope
)
addAll(restLibrariesProvider)
}
})
register(DEPENDENCIES_SYMBOL_PROVIDER_QUALIFIED_KEY, dependencyProvider)
register(LLFirFirClassByPsiClassProvider::class, LLFirFirClassByPsiClassProvider(this))
val context = LibrarySessionCreationContext(moduleData, contentScope, firProvider, dependencyProvider)
additionalSessionConfiguration(context)
LLFirSessionConfigurator.configure(this)
}
}
protected class BinaryLibrarySessionCreationContext
protected fun doCreateBinaryLibrarySession(
module: KtBinaryModule,
additionalSessionConfiguration: LLFirLibrarySession.(context: BinaryLibrarySessionCreationContext) -> Unit,
): LLFirLibrarySession {
val platform = module.platform
val builtinsSession = LLFirBuiltinsSessionFactory.getInstance(project).getBuiltinsSession(platform)
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()
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)
val context = BinaryLibrarySessionCreationContext()
additionalSessionConfiguration(context)
LLFirSessionConfigurator.configure(this)
}
}
private fun wrapLanguageVersionSettings(original: LanguageVersionSettings): LanguageVersionSettings {
return object : LanguageVersionSettings by original {
override fun getFeatureSupport(feature: LanguageFeature): LanguageFeature.State {
return when (feature) {
LanguageFeature.EnableDfaWarningsInK2 -> LanguageFeature.State.ENABLED
else -> original.getFeatureSupport(feature)
}
}
override fun supportsFeature(feature: LanguageFeature): Boolean {
return when (getFeatureSupport(feature)) {
LanguageFeature.State.ENABLED, LanguageFeature.State.ENABLED_WITH_WARNING -> true
else -> false
}
}
}
}
private fun collectSourceModuleDependencies(module: KtModule): List<LLFirSession> {
val llFirSessionCache = LLFirSessionCache.getInstance(project)
fun getOrCreateSessionForDependency(dependency: KtModule): LLFirSession? = when (dependency) {
is KtBuiltinsModule -> null // Built-ins are already added
is KtBinaryModule -> llFirSessionCache.getSession(dependency, preferBinary = true)
is KtSourceModule -> llFirSessionCache.getSession(dependency)
is KtScriptModule,
is KtScriptDependencyModule,
is KtNotUnderContentRootModule,
is KtLibrarySourceModule -> error("Module $module cannot depend on ${dependency::class}: $dependency")
}
val dependencyModules = buildSet {
addAll(module.directRegularDependencies)
// The dependency provider needs to have access to all direct and indirect `dependsOn` dependencies, as `dependsOn`
// dependencies are transitive.
addAll(module.transitiveDependsOnDependencies)
}
return dependencyModules.mapNotNull(::getOrCreateSessionForDependency)
}
private fun createSourceModuleDependencyTracker(module: KtModule, exposedDependencies: List<LLFirSession>): ModificationTracker {
val llFirSessionCache = LLFirSessionCache.getInstance(project)
val friendDependencies = module.directFriendDependencies
val trackers = ArrayList<ModificationTracker>(exposedDependencies.size + friendDependencies.size)
exposedDependencies.forEach { trackers += it.modificationTracker }
friendDependencies.forEach { trackers += llFirSessionCache.getSession(it).modificationTracker }
return CompositeModificationTracker.createFlattened(trackers)
}
private fun createModuleData(session: LLFirSession): LLFirModuleData {
return LLFirModuleData(session.ktModule).apply { bindSession(session) }
}
/**
* Adds dependency symbol providers from [dependencies] to [destination]. The function might combine, reorder, or exclude specific
* symbol providers for optimization.
*/
private fun addDependencySymbolProvidersTo(
session: LLFirSession,
dependencies: List<LLFirSession>,
destination: MutableList<FirSymbolProvider>,
) {
val dependencyProviders = buildList {
dependencies.forEach { session ->
when (val dependencyProvider = session.symbolProvider) {
is LLFirModuleWithDependenciesSymbolProvider -> addAll(dependencyProvider.providers)
else -> add(dependencyProvider)
}
}
}
dependencyProviders.mergeDependencySymbolProvidersInto(session, destination)
}
/**
* Merges dependency symbol providers of the same kind if possible. The merged symbol provider usually delegates to its subordinate
* symbol providers to preserve session semantics, but it will have some form of advantage over individual symbol providers (such as
* querying an index once instead of N times).
*
* [session] should be the session of the dependent module. Because all symbol providers are tied to a session, we need a session to
* create a combined symbol provider.
*/
private fun List<FirSymbolProvider>.mergeDependencySymbolProvidersInto(
session: LLFirSession,
destination: MutableList<FirSymbolProvider>,
) {
SymbolProviderMerger(this, destination).apply {
merge<LLFirProvider.SymbolProvider> { LLFirCombinedKotlinSymbolProvider.merge(session, project, it) }
merge<JavaSymbolProvider> { LLFirCombinedJavaSymbolProvider.merge(session, project, it) }
merge<FirExtensionSyntheticFunctionInterfaceProvider> { LLFirCombinedSyntheticFunctionSymbolProvider.merge(session, it) }
finish()
}
}
private class SymbolProviderMerger(
symbolProviders: List<FirSymbolProvider>,
private val destination: MutableList<FirSymbolProvider>
) {
private var remainingSymbolProviders = symbolProviders
inline fun <reified A : FirSymbolProvider> merge(create: (List<A>) -> FirSymbolProvider?) {
val (specificSymbolProviders, remainingSymbolProviders) = remainingSymbolProviders.partitionIsInstance<_, A>()
destination.addIfNotNull(create(specificSymbolProviders))
this.remainingSymbolProviders = remainingSymbolProviders
}
fun finish() {
destination.addAll(remainingSymbolProviders)
remainingSymbolProviders = emptyList()
}
}
}
@@ -0,0 +1,70 @@
/*
* Copyright 2010-2023 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.providers.LLFirModuleWithDependenciesSymbolProvider
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.fir.FirVisibilityChecker
import org.jetbrains.kotlin.fir.SessionConfiguration
import org.jetbrains.kotlin.fir.analysis.FirOverridesBackwardCompatibilityHelper
import org.jetbrains.kotlin.fir.analysis.jvm.FirJvmOverridesBackwardCompatibilityHelper
import org.jetbrains.kotlin.fir.resolve.calls.ConeCallConflictResolverFactory
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.fir.scopes.FirPlatformClassMapper
import org.jetbrains.kotlin.fir.session.DefaultCallConflictResolverFactory
@OptIn(SessionConfiguration::class)
internal class LLFirCommonSessionFactory(project: Project) : LLFirAbstractSessionFactory(project) {
override fun createSourcesSession(module: KtSourceModule): LLFirSourcesSession {
return doCreateSourcesSession(module) { context ->
registerModuleIndependentCommonComponents()
register(
FirSymbolProvider::class,
LLFirModuleWithDependenciesSymbolProvider(
this,
providers = listOf(
context.firProvider.symbolProvider,
),
context.dependencyProvider,
)
)
}
}
override fun createLibrarySession(module: KtModule): LLFirLibraryOrLibrarySourceResolvableModuleSession {
return doCreateLibrarySession(module) { context ->
registerModuleIndependentCommonComponents()
register(
FirSymbolProvider::class,
LLFirModuleWithDependenciesSymbolProvider(
this,
providers = listOf(
context.firProvider.symbolProvider,
),
context.dependencyProvider,
)
)
}
}
override fun createBinaryLibrarySession(module: KtBinaryModule): LLFirLibrarySession {
return doCreateBinaryLibrarySession(module) {
registerModuleIndependentCommonComponents()
}
}
private fun LLFirSession.registerModuleIndependentCommonComponents() {
register(FirVisibilityChecker::class, FirVisibilityChecker.Default)
register(ConeCallConflictResolverFactory::class, DefaultCallConflictResolverFactory)
register(FirPlatformClassMapper::class, FirPlatformClassMapper.Default)
register(FirOverridesBackwardCompatibilityHelper::class, FirJvmOverridesBackwardCompatibilityHelper)
}
}
@@ -0,0 +1,75 @@
/*
* Copyright 2010-2023 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.providers.LLFirModuleWithDependenciesSymbolProvider
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.fir.FirVisibilityChecker
import org.jetbrains.kotlin.fir.SessionConfiguration
import org.jetbrains.kotlin.fir.analysis.FirOverridesBackwardCompatibilityHelper
import org.jetbrains.kotlin.fir.analysis.checkers.FirPlatformDiagnosticSuppressor
import org.jetbrains.kotlin.fir.analysis.js.checkers.FirJsPlatformDiagnosticSuppressor
import org.jetbrains.kotlin.fir.analysis.jvm.FirJvmOverridesBackwardCompatibilityHelper
import org.jetbrains.kotlin.fir.resolve.calls.ConeCallConflictResolverFactory
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.fir.scopes.FirPlatformClassMapper
import org.jetbrains.kotlin.fir.session.JsCallConflictResolverFactory
@OptIn(SessionConfiguration::class)
internal class LLFirJsSessionFactory(project: Project) : LLFirAbstractSessionFactory(project) {
override fun createSourcesSession(module: KtSourceModule): LLFirSourcesSession {
return doCreateSourcesSession(module) { context ->
registerModuleIndependentJsComponents()
register(
FirSymbolProvider::class,
LLFirModuleWithDependenciesSymbolProvider(
this,
providers = listOfNotNull(
context.firProvider.symbolProvider,
context.switchableExtensionDeclarationsSymbolProvider,
context.syntheticFunctionInterfaceProvider,
),
context.dependencyProvider,
)
)
}
}
override fun createLibrarySession(module: KtModule): LLFirLibraryOrLibrarySourceResolvableModuleSession {
return doCreateLibrarySession(module) { context ->
registerModuleIndependentJsComponents()
register(
FirSymbolProvider::class,
LLFirModuleWithDependenciesSymbolProvider(
this,
providers = listOf(
context.firProvider.symbolProvider,
),
context.dependencyProvider,
)
)
}
}
override fun createBinaryLibrarySession(module: KtBinaryModule): LLFirLibrarySession {
return doCreateBinaryLibrarySession(module) {
registerModuleIndependentJsComponents()
}
}
private fun LLFirSession.registerModuleIndependentJsComponents() {
register(FirVisibilityChecker::class, FirVisibilityChecker.Default)
register(ConeCallConflictResolverFactory::class, JsCallConflictResolverFactory)
register(FirPlatformClassMapper::class, FirPlatformClassMapper.Default)
register(FirOverridesBackwardCompatibilityHelper::class, FirJvmOverridesBackwardCompatibilityHelper)
register(FirPlatformDiagnosticSuppressor::class, FirJsPlatformDiagnosticSuppressor())
}
}
@@ -0,0 +1,77 @@
/*
* Copyright 2010-2023 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.project.structure.*
import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.*
import org.jetbrains.kotlin.analysis.project.structure.*
import org.jetbrains.kotlin.fir.SessionConfiguration
import org.jetbrains.kotlin.fir.backend.jvm.FirJvmTypeMapper
import org.jetbrains.kotlin.fir.java.JavaSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.scopes.wrapScopeWithJvmMapped
import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider
import org.jetbrains.kotlin.fir.session.*
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver
@OptIn(SessionConfiguration::class)
internal class LLFirJvmSessionFactory(project: Project) : LLFirAbstractSessionFactory(project) {
override fun createSourcesSession(module: KtSourceModule): LLFirSourcesSession {
return doCreateSourcesSession(module, FirKotlinScopeProvider(::wrapScopeWithJvmMapped)) { context ->
registerCommonJavaComponents(JavaModuleResolver.getInstance(project))
registerJavaSpecificResolveComponents()
val javaSymbolProvider = createJavaSymbolProvider(this, context.moduleData, project, context.contentScope)
register(JavaSymbolProvider::class, javaSymbolProvider)
register(
FirSymbolProvider::class,
LLFirModuleWithDependenciesSymbolProvider(
this,
providers = listOfNotNull(
context.firProvider.symbolProvider,
context.switchableExtensionDeclarationsSymbolProvider,
javaSymbolProvider,
context.syntheticFunctionInterfaceProvider,
),
context.dependencyProvider,
)
)
register(FirJvmTypeMapper::class, FirJvmTypeMapper(this))
}
}
override fun createLibrarySession(module: KtModule): LLFirLibraryOrLibrarySourceResolvableModuleSession {
return doCreateLibrarySession(module) { context ->
registerCommonJavaComponents(JavaModuleResolver.getInstance(project))
registerJavaSpecificResolveComponents()
val javaSymbolProvider = createJavaSymbolProvider(this, context.moduleData, project, context.contentScope)
register(
FirSymbolProvider::class,
LLFirModuleWithDependenciesSymbolProvider(
this,
providers = listOf(
context.firProvider.symbolProvider,
javaSymbolProvider,
),
context.dependencyProvider,
)
)
register(JavaSymbolProvider::class, javaSymbolProvider)
register(FirJvmTypeMapper::class, FirJvmTypeMapper(this))
}
}
override fun createBinaryLibrarySession(module: KtBinaryModule): LLFirLibrarySession {
return doCreateBinaryLibrarySession(module) {
registerCommonJavaComponents(JavaModuleResolver.getInstance(project))
registerJavaSpecificResolveComponents()
register(FirJvmTypeMapper::class, FirJvmTypeMapper(this))
}
}
}
@@ -0,0 +1,71 @@
/*
* Copyright 2010-2023 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.providers.LLFirModuleWithDependenciesSymbolProvider
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.fir.FirVisibilityChecker
import org.jetbrains.kotlin.fir.SessionConfiguration
import org.jetbrains.kotlin.fir.analysis.FirDefaultOverridesBackwardCompatibilityHelper
import org.jetbrains.kotlin.fir.analysis.FirOverridesBackwardCompatibilityHelper
import org.jetbrains.kotlin.fir.resolve.calls.ConeCallConflictResolverFactory
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.fir.scopes.FirPlatformClassMapper
import org.jetbrains.kotlin.fir.session.DefaultCallConflictResolverFactory
@OptIn(SessionConfiguration::class)
internal class LLFirNativeSessionFactory(project: Project) : LLFirAbstractSessionFactory(project) {
override fun createSourcesSession(module: KtSourceModule): LLFirSourcesSession {
return doCreateSourcesSession(module) { context ->
registerModuleIndependentNativeComponents()
register(
FirSymbolProvider::class,
LLFirModuleWithDependenciesSymbolProvider(
this,
providers = listOfNotNull(
context.firProvider.symbolProvider,
context.switchableExtensionDeclarationsSymbolProvider,
context.syntheticFunctionInterfaceProvider,
),
context.dependencyProvider,
)
)
}
}
override fun createLibrarySession(module: KtModule): LLFirLibraryOrLibrarySourceResolvableModuleSession {
return doCreateLibrarySession(module) { context ->
registerModuleIndependentNativeComponents()
register(
FirSymbolProvider::class,
LLFirModuleWithDependenciesSymbolProvider(
this,
providers = listOf(
context.firProvider.symbolProvider,
),
context.dependencyProvider,
)
)
}
}
override fun createBinaryLibrarySession(module: KtBinaryModule): LLFirLibrarySession {
return doCreateBinaryLibrarySession(module) {
registerModuleIndependentNativeComponents()
}
}
private fun LLFirSession.registerModuleIndependentNativeComponents() {
register(FirVisibilityChecker::class, FirVisibilityChecker.Default)
register(ConeCallConflictResolverFactory::class, DefaultCallConflictResolverFactory)
register(FirPlatformClassMapper::class, FirPlatformClassMapper.Default)
register(FirOverridesBackwardCompatibilityHelper::class, FirDefaultOverridesBackwardCompatibilityHelper)
}
}
@@ -6,55 +6,28 @@
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
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.*
import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.*
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.checkCanceled
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.providers.impl.EmptyKotlinDeclarationProvider
import org.jetbrains.kotlin.analysis.providers.impl.FileBasedKotlinDeclarationProvider
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
import org.jetbrains.kotlin.fir.FirModuleDataImpl
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.PrivateSessionConstructor
import org.jetbrains.kotlin.fir.SessionConfiguration
import org.jetbrains.kotlin.fir.analysis.checkersComponent
import org.jetbrains.kotlin.fir.analysis.extensions.additionalCheckers
import org.jetbrains.kotlin.fir.backend.jvm.FirJvmTypeMapper
import org.jetbrains.kotlin.fir.extensions.*
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
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.platform.JsPlatform
import org.jetbrains.kotlin.platform.jvm.JvmPlatform
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.platform.konan.NativePlatform
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.partitionIsInstance
import java.util.concurrent.ConcurrentMap
@OptIn(PrivateSessionConstructor::class, SessionConfiguration::class)
internal class LLFirSessionCache(private val project: Project) {
companion object {
fun getInstance(project: Project): LLFirSessionCache {
@@ -62,9 +35,6 @@ internal class LLFirSessionCache(private val project: Project) {
}
}
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()
@@ -74,7 +44,9 @@ internal class LLFirSessionCache(private val project: Project) {
*/
fun getSession(module: KtModule, preferBinary: Boolean = false): LLFirSession {
if (module is KtBinaryModule && (preferBinary || module is KtSdkModule)) {
return getCachedSession(module, binaryCache, ::createBinaryLibrarySession)
return getCachedSession(module, binaryCache) {
createPlatformAwareSessionFactory(module).createBinaryLibrarySession(module)
}
}
return getCachedSession(module, sourceCache, ::createSession)
@@ -104,464 +76,24 @@ internal class LLFirSessionCache(private val project: Project) {
}
private fun createSession(module: KtModule): LLFirSession {
val sessionFactory = createPlatformAwareSessionFactory(module)
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)
is KtSourceModule -> sessionFactory.createSourcesSession(module)
is KtLibraryModule, is KtLibrarySourceModule -> sessionFactory.createLibrarySession(module)
is KtSdkModule -> sessionFactory.createBinaryLibrarySession(module)
is KtScriptModule -> sessionFactory.createScriptSession(module)
is KtNotUnderContentRootModule -> sessionFactory.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 dependencies = collectSourceModuleDependencies(module)
val dependencyTracker = createSourceModuleDependencyTracker(module, dependencies)
val session = LLFirSourcesSession(module, dependencyTracker, components, builtinsSession.builtinTypes)
components.session = session
val moduleData = createModuleData(session)
return session.apply {
registerModuleData(moduleData)
register(FirKotlinScopeProvider::class, scopeProvider)
registerIdeComponents(project)
registerCommonComponents(languageVersionSettings)
registerCommonJavaComponents(JavaModuleResolver.getInstance(project))
registerResolveComponents()
registerJavaSpecificResolveComponents()
val contentScope = module.contentScope
val provider = LLFirProvider(
this,
components,
project.createDeclarationProvider(contentScope, module),
project.createPackageProvider(contentScope),
/* Source modules can contain `kotlin` package only if `-Xallow-kotlin-package` is specified, this is handled in LLFirProvider */
canContainKotlinPackage = false,
)
register(FirProvider::class, provider)
register(FirLazyDeclarationResolver::class, LLFirLazyDeclarationResolver())
registerCompilerPluginServices(contentScope, project, module)
registerCompilerPluginExtensions(project, module)
registerCommonComponentsAfterExtensionsAreConfigured()
val switchableExtensionDeclarationsSymbolProvider =
FirSwitchableExtensionDeclarationsSymbolProvider.createIfNeeded(session)?.also {
register(FirSwitchableExtensionDeclarationsSymbolProvider::class, it)
}
val dependencyProvider = LLFirDependenciesSymbolProvider(this, buildList {
addDependencySymbolProvidersTo(session, dependencies, this)
add(builtinsSession.symbolProvider)
})
val javaSymbolProvider = createJavaSymbolProvider(this, moduleData, project, contentScope)
val syntheticFunctionInterfaceProvider =
FirExtensionSyntheticFunctionInterfaceProvider.createIfNeeded(this, moduleData, scopeProvider)
register(
FirSymbolProvider::class,
LLFirModuleWithDependenciesSymbolProvider(
this,
providers = listOfNotNull(
provider.symbolProvider,
switchableExtensionDeclarationsSymbolProvider,
javaSymbolProvider,
syntheticFunctionInterfaceProvider,
),
dependencyProvider,
)
)
register(JavaSymbolProvider::class, javaSymbolProvider)
register(DEPENDENCIES_SYMBOL_PROVIDER_QUALIFIED_KEY, dependencyProvider)
register(FirJvmTypeMapper::class, FirJvmTypeMapper(this))
register(LLFirFirClassByPsiClassProvider::class, LLFirFirClassByPsiClassProvider(this))
LLFirSessionConfigurator.configure(this)
extensionService.additionalCheckers.forEach(session.checkersComponent::register)
}
}
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 platform = module.platform
val builtinsSession = LLFirBuiltinsSessionFactory.getInstance(project).getBuiltinsSession(platform)
val languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT
val scopeProvider = FirKotlinScopeProvider()
val components = LLFirModuleResolveComponents(module, globalResolveComponents, scopeProvider)
val dependencyTracker = builtinsSession.modificationTracker
val session = LLFirLibraryOrLibrarySourceResolvableModuleSession(module, dependencyTracker, components, builtinsSession.builtinTypes)
components.session = session
val moduleData = createModuleData(session)
return session.apply {
registerModuleData(moduleData)
register(FirKotlinScopeProvider::class, scopeProvider)
registerIdeComponents(project)
registerCommonComponents(languageVersionSettings)
registerCommonComponentsAfterExtensionsAreConfigured()
registerCommonJavaComponents(JavaModuleResolver.getInstance(project))
registerResolveComponents()
registerJavaSpecificResolveComponents()
val contentScope = module.contentScope
val provider = LLFirProvider(
this,
components,
project.createDeclarationProvider(contentScope, module),
project.createPackageProvider(contentScope),
canContainKotlinPackage = true,
)
register(FirProvider::class, provider)
register(FirLazyDeclarationResolver::class, LLFirLazyDeclarationResolver())
// We need FirRegisteredPluginAnnotations during extensions' registration process
val annotationsResolver = project.createAnnotationResolver(contentScope)
register(FirRegisteredPluginAnnotations::class, LLFirIdeRegisteredPluginAnnotations(this, annotationsResolver))
register(FirPredicateBasedProvider::class, FirEmptyPredicateBasedProvider)
val dependencyProvider = LLFirDependenciesSymbolProvider(this, buildList {
add(builtinsSession.symbolProvider)
// Script dependencies are self-contained and should not depend on other libraries
if (module !is KtScriptDependencyModule) {
// Add all libraries excluding the current one
val librariesSearchScope = ProjectScope.getLibrariesScope(project)
.intersectWith(GlobalSearchScope.notScope(libraryModule.contentScope))
val restLibrariesProvider = LLFirLibraryProviderFactory.createLibraryProvidersForAllProjectLibraries(
session, moduleData, scopeProvider,
project, builtinTypes, librariesSearchScope
)
addAll(restLibrariesProvider)
}
})
val javaSymbolProvider = createJavaSymbolProvider(this, moduleData, project, contentScope)
register(
FirSymbolProvider::class,
LLFirModuleWithDependenciesSymbolProvider(
this,
providers = listOf(
provider.symbolProvider,
javaSymbolProvider,
),
dependencyProvider,
)
)
register(JavaSymbolProvider::class, javaSymbolProvider)
register(DEPENDENCIES_SYMBOL_PROVIDER_QUALIFIED_KEY, dependencyProvider)
register(FirJvmTypeMapper::class, FirJvmTypeMapper(this))
register(LLFirFirClassByPsiClassProvider::class, LLFirFirClassByPsiClassProvider(this))
LLFirSessionConfigurator.configure(this)
}
}
private fun createBinaryLibrarySession(module: KtBinaryModule): LLFirLibrarySession {
val platform = module.platform
val builtinsSession = LLFirBuiltinsSessionFactory.getInstance(project).getBuiltinsSession(platform)
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 components = LLFirModuleResolveComponents(module, globalResolveComponents, scopeProvider)
val contentScope = module.contentScope
val dependencies = collectSourceModuleDependencies(module)
val dependencyTracker = createSourceModuleDependencyTracker(module, dependencies)
val session = LLFirScriptSession(module, dependencyTracker, components, builtinsSession.builtinTypes)
components.session = session
val moduleData = createModuleData(session)
return session.apply {
registerModuleData(moduleData)
register(FirKotlinScopeProvider::class, scopeProvider)
registerIdeComponents(project)
registerCommonComponents(languageVersionSettings)
registerCommonComponentsAfterExtensionsAreConfigured()
registerCommonJavaComponents(JavaModuleResolver.getInstance(project))
registerResolveComponents()
registerJavaSpecificResolveComponents()
val provider = LLFirProvider(
this,
components,
FileBasedKotlinDeclarationProvider(module.file),
project.createPackageProvider(contentScope),
canContainKotlinPackage = true,
)
register(FirProvider::class, provider)
register(FirLazyDeclarationResolver::class, LLFirLazyDeclarationResolver())
val dependencyProvider = LLFirDependenciesSymbolProvider(this, buildList {
addDependencySymbolProvidersTo(session, dependencies, this)
add(builtinsSession.symbolProvider)
})
val javaSymbolProvider = createJavaSymbolProvider(this, moduleData, project, contentScope)
register(JavaSymbolProvider::class, javaSymbolProvider)
register(
FirSymbolProvider::class,
LLFirModuleWithDependenciesSymbolProvider(
this,
providers = listOfNotNull(
javaSymbolProvider,
provider.symbolProvider,
),
dependencyProvider,
)
)
register(FirPredicateBasedProvider::class, FirEmptyPredicateBasedProvider)
register(DEPENDENCIES_SYMBOL_PROVIDER_QUALIFIED_KEY, dependencyProvider)
register(FirJvmTypeMapper::class, FirJvmTypeMapper(this))
register(FirRegisteredPluginAnnotations::class, FirRegisteredPluginAnnotations.Empty)
LLFirSessionConfigurator.configure(this)
}
}
private fun createNotUnderContentRootResolvableSession(module: KtNotUnderContentRootModule): LLFirNonUnderContentRootResolvableModuleSession {
val builtinsSession = LLFirBuiltinsSessionFactory.getInstance(project).getBuiltinsSession(JvmPlatforms.unspecifiedJvmPlatform)
val languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT
val scopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped)
val components = LLFirModuleResolveComponents(module, globalResolveComponents, scopeProvider)
val dependencyTracker = builtinsSession.modificationTracker
val session = LLFirNonUnderContentRootResolvableModuleSession(module, dependencyTracker, components, builtinsSession.builtinTypes)
components.session = session
val moduleData = createModuleData(session)
return session.apply {
registerModuleData(moduleData)
register(FirKotlinScopeProvider::class, scopeProvider)
registerIdeComponents(project)
registerCommonComponents(languageVersionSettings)
registerCommonComponentsAfterExtensionsAreConfigured()
registerCommonJavaComponents(JavaModuleResolver.getInstance(project))
registerResolveComponents()
registerJavaSpecificResolveComponents()
val ktFile = module.file as? KtFile
val provider = LLFirProvider(
this,
components,
if (ktFile != null) FileBasedKotlinDeclarationProvider(ktFile) else EmptyKotlinDeclarationProvider,
project.createPackageProvider(module.contentScope),
canContainKotlinPackage = true,
)
register(FirProvider::class, provider)
register(FirLazyDeclarationResolver::class, LLFirLazyDeclarationResolver())
val dependencyProvider = LLFirDependenciesSymbolProvider(this, listOf(builtinsSession.symbolProvider))
register(
FirSymbolProvider::class,
LLFirModuleWithDependenciesSymbolProvider(
this,
providers = listOf(
provider.symbolProvider,
),
dependencyProvider,
)
)
register(FirPredicateBasedProvider::class, FirEmptyPredicateBasedProvider)
register(DEPENDENCIES_SYMBOL_PROVIDER_QUALIFIED_KEY, dependencyProvider)
register(FirJvmTypeMapper::class, FirJvmTypeMapper(this))
register(FirRegisteredPluginAnnotations::class, FirRegisteredPluginAnnotations.Empty)
LLFirSessionConfigurator.configure(this)
}
}
private fun wrapLanguageVersionSettings(original: LanguageVersionSettings): LanguageVersionSettings {
return object : LanguageVersionSettings by original {
override fun getFeatureSupport(feature: LanguageFeature): LanguageFeature.State {
return when (feature) {
LanguageFeature.EnableDfaWarningsInK2 -> LanguageFeature.State.ENABLED
else -> original.getFeatureSupport(feature)
}
}
override fun supportsFeature(feature: LanguageFeature): Boolean {
return when (getFeatureSupport(feature)) {
LanguageFeature.State.ENABLED, LanguageFeature.State.ENABLED_WITH_WARNING -> true
else -> false
}
}
}
}
private fun collectSourceModuleDependencies(module: KtModule): List<LLFirSession> {
fun getOrCreateSessionForDependency(dependency: KtModule): LLFirSession? = when (dependency) {
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")
}
val dependencyModules = buildSet {
addAll(module.directRegularDependencies)
// The dependency provider needs to have access to all direct and indirect `dependsOn` dependencies, as `dependsOn`
// dependencies are transitive.
addAll(module.transitiveDependsOnDependencies)
}
return dependencyModules.mapNotNull(::getOrCreateSessionForDependency)
}
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) }
}
/**
* Adds dependency symbol providers from [dependencies] to [destination]. The function might combine, reorder, or exclude specific
* symbol providers for optimization.
*/
private fun addDependencySymbolProvidersTo(
session: LLFirSession,
dependencies: List<LLFirSession>,
destination: MutableList<FirSymbolProvider>,
) {
val dependencyProviders = buildList {
dependencies.forEach { session ->
when (val dependencyProvider = session.symbolProvider) {
is LLFirModuleWithDependenciesSymbolProvider -> addAll(dependencyProvider.providers)
else -> add(dependencyProvider)
}
}
}
dependencyProviders.mergeDependencySymbolProvidersInto(session, destination)
}
/**
* Merges dependency symbol providers of the same kind if possible. The merged symbol provider usually delegates to its subordinate
* symbol providers to preserve session semantics, but it will have some form of advantage over individual symbol providers (such as
* querying an index once instead of N times).
*
* [session] should be the session of the dependent module. Because all symbol providers are tied to a session, we need a session to
* create a combined symbol provider.
*/
private fun List<FirSymbolProvider>.mergeDependencySymbolProvidersInto(
session: LLFirSession,
destination: MutableList<FirSymbolProvider>,
) {
SymbolProviderMerger(this, destination).apply {
merge<LLFirProvider.SymbolProvider> { LLFirCombinedKotlinSymbolProvider.merge(session, project, it) }
merge<JavaSymbolProvider> { LLFirCombinedJavaSymbolProvider.merge(session, project, it) }
merge<FirExtensionSyntheticFunctionInterfaceProvider> { LLFirCombinedSyntheticFunctionSymbolProvider.merge(session, it) }
finish()
}
}
private class SymbolProviderMerger(
symbolProviders: List<FirSymbolProvider>,
private val destination: MutableList<FirSymbolProvider>
) {
private var remainingSymbolProviders = symbolProviders
inline fun <reified A : FirSymbolProvider> merge(create: (List<A>) -> FirSymbolProvider?) {
val (specificSymbolProviders, remainingSymbolProviders) = remainingSymbolProviders.partitionIsInstance<_, A>()
destination.addIfNotNull(create(specificSymbolProviders))
this.remainingSymbolProviders = remainingSymbolProviders
}
fun finish() {
destination.addAll(remainingSymbolProviders)
remainingSymbolProviders = emptyList()
private fun createPlatformAwareSessionFactory(module: KtModule): LLFirAbstractSessionFactory {
val targetPlatform = module.platform
return when {
targetPlatform.all { it is JvmPlatform } -> LLFirJvmSessionFactory(project)
targetPlatform.all { it is JsPlatform } -> LLFirJsSessionFactory(project)
targetPlatform.all { it is NativePlatform } -> LLFirNativeSessionFactory(project)
else -> LLFirCommonSessionFactory(project)
}
}
}
@@ -50,9 +50,10 @@ object FirNativeSessionFactory : FirAbstractSessionFactory() {
).apply {
bindSession(session)
}
val kotlinLibraries = resolvedLibraries.map { it.library }
listOfNotNull(
KlibBasedSymbolProvider(session, moduleDataProvider, kotlinScopeProvider, resolvedLibraries.map { it.library }),
NativeForwardDeclarationsSymbolProvider(session, forwardDeclarationsModuleData, kotlinScopeProvider, resolvedLibraries),
KlibBasedSymbolProvider(session, moduleDataProvider, kotlinScopeProvider, kotlinLibraries),
NativeForwardDeclarationsSymbolProvider(session, forwardDeclarationsModuleData, kotlinScopeProvider, kotlinLibraries),
FirBuiltinSymbolProvider(session, builtinsModuleData, kotlinScopeProvider),
FirExtensionSyntheticFunctionInterfaceProvider.createIfNeeded(session, builtinsModuleData, kotlinScopeProvider),
FirCloneableSymbolProvider(session, builtinsModuleData, kotlinScopeProvider),
@@ -24,10 +24,10 @@ import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.constructClassType
import org.jetbrains.kotlin.library.KotlinLibrary
import org.jetbrains.kotlin.library.includedForwardDeclarations
import org.jetbrains.kotlin.library.isInterop
import org.jetbrains.kotlin.library.metadata.impl.ForwardDeclarationKind
import org.jetbrains.kotlin.library.metadata.resolver.KotlinResolvedLibrary
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
@@ -36,7 +36,7 @@ class NativeForwardDeclarationsSymbolProvider(
session: FirSession,
private val forwardDeclarationsModuleData: FirModuleData,
private val kotlinScopeProvider: FirKotlinScopeProvider,
private val resolvedLibraries: Collection<KotlinResolvedLibrary>,
private val kotlinLibraries: Collection<KotlinLibrary>,
) : FirSymbolProvider(session) {
private companion object {
private val validPackages = ForwardDeclarationKind.packageFqNameToKind.keys
@@ -44,8 +44,7 @@ class NativeForwardDeclarationsSymbolProvider(
private val includedForwardDeclarations: Set<ClassId> by lazy {
buildSet {
for (resolvedLibrary in resolvedLibraries) {
val library = resolvedLibrary.library
for (library in kotlinLibraries) {
if (!library.isInterop) continue
for (fqName in library.includedForwardDeclarations) {