[LL FIR] KT-58325 Base LLFirCombinedKotlinSymbolProvider on LLFirKotlinSymbolProvider

This commit is contained in:
Marco Pennekamp
2023-05-08 16:11:51 +02:00
committed by Space Team
parent f4d3cceabd
commit 3322ec9dd9
2 changed files with 31 additions and 20 deletions
@@ -26,10 +26,10 @@ import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtCallableDeclaration
/** /**
* [LLFirCombinedKotlinSymbolProvider] combines multiple [LLFirProvider.SymbolProvider]s with the following advantages: * [LLFirCombinedKotlinSymbolProvider] combines multiple [LLFirKotlinSymbolProvider]s with the following advantages:
* *
* - The combined symbol provider can combine the "names in package" sets built by individual providers. The name set can then be checked * - The combined symbol provider can combine the "names in package" sets built by individual providers. The name set can then be checked
* once instead of for each subordinate symbol provider. Because Kotlin symbol providers are ordered first in * once instead of for each subordinate symbol provider. Because Kotlin symbol providers are ordered first in
@@ -43,10 +43,10 @@ import org.jetbrains.kotlin.psi.KtFile
*/ */
internal class LLFirCombinedKotlinSymbolProvider private constructor( internal class LLFirCombinedKotlinSymbolProvider private constructor(
session: FirSession, session: FirSession,
private val project: Project, project: Project,
providers: List<LLFirProvider.SymbolProvider>, providers: List<LLFirKotlinSymbolProvider>,
private val declarationProvider: KotlinDeclarationProvider, private val declarationProvider: KotlinDeclarationProvider,
) : LLFirSelectingCombinedSymbolProvider<LLFirProvider.SymbolProvider>(session, project, providers) { ) : LLFirSelectingCombinedSymbolProvider<LLFirKotlinSymbolProvider>(session, project, providers) {
private val symbolNameCache = object : LLFirSymbolProviderNameCacheBase(session) { private val symbolNameCache = object : LLFirSymbolProviderNameCacheBase(session) {
override fun computeClassifierNames(packageFqName: FqName): Set<String>? = override fun computeClassifierNames(packageFqName: FqName): Set<String>? =
providers.flatMapToNullableSet { it.knownTopLevelClassifiersInPackage(packageFqName) } providers.flatMapToNullableSet { it.knownTopLevelClassifiersInPackage(packageFqName) }
@@ -75,45 +75,50 @@ internal class LLFirCombinedKotlinSymbolProvider private constructor(
@FirSymbolProviderInternals @FirSymbolProviderInternals
override fun getTopLevelCallableSymbolsTo(destination: MutableList<FirCallableSymbol<*>>, packageFqName: FqName, name: Name) { override fun getTopLevelCallableSymbolsTo(destination: MutableList<FirCallableSymbol<*>>, packageFqName: FqName, name: Name) {
forEachCallableProvider(packageFqName, name) { callableId, callableFiles -> forEachCallableProvider(
getTopLevelCallableSymbolsTo(destination, callableId, callableFiles) packageFqName,
name,
declarationProvider::getTopLevelCallables,
) { callableId, callables ->
getTopLevelCallableSymbolsTo(destination, callableId, callables)
} }
} }
@FirSymbolProviderInternals @FirSymbolProviderInternals
override fun getTopLevelFunctionSymbolsTo(destination: MutableList<FirNamedFunctionSymbol>, packageFqName: FqName, name: Name) { override fun getTopLevelFunctionSymbolsTo(destination: MutableList<FirNamedFunctionSymbol>, packageFqName: FqName, name: Name) {
forEachCallableProvider(packageFqName, name) { callableId, callableFiles -> forEachCallableProvider(packageFqName, name, declarationProvider::getTopLevelFunctions) { callableId, functions ->
getTopLevelFunctionSymbolsTo(destination, callableId, callableFiles) getTopLevelFunctionSymbolsTo(destination, callableId, functions)
} }
} }
@FirSymbolProviderInternals @FirSymbolProviderInternals
override fun getTopLevelPropertySymbolsTo(destination: MutableList<FirPropertySymbol>, packageFqName: FqName, name: Name) { override fun getTopLevelPropertySymbolsTo(destination: MutableList<FirPropertySymbol>, packageFqName: FqName, name: Name) {
forEachCallableProvider(packageFqName, name) { callableId, callableFiles -> forEachCallableProvider(packageFqName, name, declarationProvider::getTopLevelProperties) { callableId, properties ->
getTopLevelPropertySymbolsTo(destination, callableId, callableFiles) getTopLevelPropertySymbolsTo(destination, callableId, properties)
} }
} }
/** /**
* Calls [provide] on those providers which can contribute a callable of the given name. * Calls [provide] on those providers which can contribute a callable of the given name.
*/ */
private fun forEachCallableProvider( private inline fun <A : KtCallableDeclaration> forEachCallableProvider(
packageFqName: FqName, packageFqName: FqName,
name: Name, name: Name,
provide: LLFirProvider.SymbolProvider.(CallableId, Collection<KtFile>) -> Unit, getCallables: (CallableId) -> Collection<A>,
provide: LLFirKotlinSymbolProvider.(CallableId, Collection<A>) -> Unit,
) { ) {
if (!symbolNameCache.mayHaveTopLevelCallable(packageFqName, name)) return if (!symbolNameCache.mayHaveTopLevelCallable(packageFqName, name)) return
val callableId = CallableId(packageFqName, name) val callableId = CallableId(packageFqName, name)
declarationProvider.getTopLevelCallableFiles(callableId) getCallables(callableId)
.groupBy { getModule(it) } .groupBy { getModule(it) }
.forEach { (ktModule, ktFiles) -> .forEach { (ktModule, callables) ->
// If `ktModule` cannot be found in the map, `ktFiles` cannot be processed by any of the available providers, because none // If `ktModule` cannot be found in the map, `callables` cannot be processed by any of the available providers, because none
// of them belong to the correct module. We can skip in that case, because iterating through all providers wouldn't lead to // of them belong to the correct module. We can skip in that case, because iterating through all providers wouldn't lead to
// any results for `ktFiles`. // any results for `callables`.
val provider = providersByKtModule[ktModule] ?: return@forEach val provider = providersByKtModule[ktModule] ?: return@forEach
provider.provide(callableId, ktFiles) provider.provide(callableId, callables)
} }
} }
@@ -128,7 +133,7 @@ internal class LLFirCombinedKotlinSymbolProvider private constructor(
symbolNameCache.getTopLevelCallableNamesInPackage(packageFqName) symbolNameCache.getTopLevelCallableNamesInPackage(packageFqName)
companion object { companion object {
fun merge(session: LLFirSession, project: Project, providers: List<LLFirProvider.SymbolProvider>): FirSymbolProvider? = fun merge(session: LLFirSession, project: Project, providers: List<LLFirKotlinSymbolProvider>): FirSymbolProvider? =
if (providers.size > 1) { if (providers.size > 1) {
val combinedScope = GlobalSearchScope.union(providers.map { it.session.llFirModuleData.ktModule.contentScope }) val combinedScope = GlobalSearchScope.union(providers.map { it.session.llFirModuleData.ktModule.contentScope })
val declarationProvider = project.createDeclarationProvider(combinedScope, session.ktModule) val declarationProvider = project.createDeclarationProvider(combinedScope, session.ktModule)
@@ -136,3 +141,9 @@ internal class LLFirCombinedKotlinSymbolProvider private constructor(
} else providers.singleOrNull() } else providers.singleOrNull()
} }
} }
/**
* Callables are provided very rarely (compared to functions/properties individually), so it's okay to hit indices twice here.
*/
private fun KotlinDeclarationProvider.getTopLevelCallables(callableId: CallableId): List<KtCallableDeclaration> =
getTopLevelFunctions(callableId) + getTopLevelProperties(callableId)
@@ -504,7 +504,7 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje
destination: MutableList<FirSymbolProvider>, destination: MutableList<FirSymbolProvider>,
) { ) {
SymbolProviderMerger(this, destination).apply { SymbolProviderMerger(this, destination).apply {
merge<LLFirProvider.SymbolProvider> { LLFirCombinedKotlinSymbolProvider.merge(session, project, it) } merge<LLFirKotlinSymbolProvider> { LLFirCombinedKotlinSymbolProvider.merge(session, project, it) }
merge<JavaSymbolProvider> { LLFirCombinedJavaSymbolProvider.merge(session, project, it) } merge<JavaSymbolProvider> { LLFirCombinedJavaSymbolProvider.merge(session, project, it) }
merge<FirExtensionSyntheticFunctionInterfaceProvider> { LLFirCombinedSyntheticFunctionSymbolProvider.merge(session, it) } merge<FirExtensionSyntheticFunctionInterfaceProvider> { LLFirCombinedSyntheticFunctionSymbolProvider.merge(session, it) }
finish() finish()