[LL FIR] Add top-level callable package name set support to LLFirSymbolProviderNameCache
- `KotlinDeclarationProvider` supports computing the top-level callable package name set now, so we can propagate it to the symbol name cache implementation. - Adds the package name check to `getTopLevelCallableNamesInPackage` directly, which will likely reduce the size of `topLevelCallableNamesByPackage`, because it needs to store fewer empty sets.
This commit is contained in:
committed by
Space Team
parent
e10a9263d0
commit
63f29b5d24
+8
-6
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.analysis.providers.createDeclarationProvider
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.flatMapToNullableSet
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
@@ -47,13 +48,14 @@ internal class LLFirCombinedKotlinSymbolProvider private constructor(
|
||||
private val declarationProvider: KotlinDeclarationProvider,
|
||||
) : LLFirSelectingCombinedSymbolProvider<LLFirProvider.SymbolProvider>(session, project, providers) {
|
||||
private val symbolNameCache = object : LLFirSymbolProviderNameCacheBase(session) {
|
||||
override fun computeClassifierNames(packageFqName: FqName): Set<String>? = buildSet {
|
||||
providers.forEach { addAll(it.knownTopLevelClassifiersInPackage(packageFqName) ?: return null) }
|
||||
}
|
||||
override fun computeClassifierNames(packageFqName: FqName): Set<String>? =
|
||||
providers.flatMapToNullableSet { it.knownTopLevelClassifiersInPackage(packageFqName) }
|
||||
|
||||
override fun computeCallableNames(packageFqName: FqName): Set<Name>? = buildSet {
|
||||
providers.forEach { addAll(it.computeCallableNamesInPackage(packageFqName) ?: return null) }
|
||||
}
|
||||
override fun computeCallableNames(packageFqName: FqName): Set<Name>? =
|
||||
providers.flatMapToNullableSet { it.computeCallableNamesInPackage(packageFqName) }
|
||||
|
||||
override fun computePackageNamesWithTopLevelCallables(): Set<String>? =
|
||||
providers.flatMapToNullableSet { it.computePackageSetWithTopLevelCallables() }
|
||||
}
|
||||
|
||||
private val classifierCache = NullableCaffeineCache<ClassId, FirClassLikeSymbol<*>> { it.maximumSize(500) }
|
||||
|
||||
+2
-2
@@ -195,8 +195,8 @@ internal class LLFirProvider(
|
||||
override fun getPackage(fqName: FqName): FqName? =
|
||||
providerHelper.getPackage(fqName)
|
||||
|
||||
// Computing the set of such package names is expensive and would require a new index. For now, it is not worth the marginal gains.
|
||||
override fun computePackageSetWithTopLevelCallables(): Set<String>? = null
|
||||
override fun computePackageSetWithTopLevelCallables(): Set<String>? =
|
||||
providerHelper.symbolNameCache.getPackageNamesWithTopLevelCallables()
|
||||
|
||||
override fun knownTopLevelClassifiersInPackage(packageFqName: FqName): Set<String>? =
|
||||
providerHelper.symbolNameCache.getTopLevelClassifierNamesInPackage(packageFqName)
|
||||
|
||||
+9
-5
@@ -70,30 +70,34 @@ private class LLFirResolveExtensionToolNameCache(
|
||||
private val packageFilter: LLFirResolveExtensionToolPackageFilter,
|
||||
private val fileProvider: LLFirResolveExtensionsFileProvider,
|
||||
) : LLFirSymbolProviderNameCache() {
|
||||
override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set<String>? = forbidAnalysis {
|
||||
override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set<String> = forbidAnalysis {
|
||||
if (!packageFilter.packageExists(packageFqName)) return emptySet()
|
||||
return fileProvider.getFilesByPackage(packageFqName)
|
||||
fileProvider.getFilesByPackage(packageFqName)
|
||||
.flatMap { it.getTopLevelClassifierNames() }
|
||||
.mapTo(mutableSetOf()) { it.asString() }
|
||||
}
|
||||
|
||||
override fun getPackageNamesWithTopLevelCallables(): Set<String> = forbidAnalysis {
|
||||
packageFilter.getAllPackages().mapTo(mutableSetOf()) { it.asString() }
|
||||
}
|
||||
|
||||
override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set<Name> = forbidAnalysis {
|
||||
if (!packageFilter.packageExists(packageFqName)) return emptySet()
|
||||
return fileProvider.getFilesByPackage(packageFqName)
|
||||
fileProvider.getFilesByPackage(packageFqName)
|
||||
.flatMapTo(mutableSetOf()) { it.getTopLevelCallableNames() }
|
||||
}
|
||||
|
||||
override fun mayHaveTopLevelClassifier(classId: ClassId, mayHaveFunctionClass: Boolean): Boolean = forbidAnalysis {
|
||||
if (!packageFilter.packageExists(classId.packageFqName)) return false
|
||||
|
||||
return fileProvider.getFilesByPackage(classId.packageFqName)
|
||||
fileProvider.getFilesByPackage(classId.packageFqName)
|
||||
.any { it.mayHaveTopLevelClassifier(classId.getTopLevelShortClassName()) }
|
||||
}
|
||||
|
||||
override fun mayHaveTopLevelCallable(packageFqName: FqName, name: Name): Boolean = forbidAnalysis {
|
||||
if (!packageFilter.packageExists(packageFqName)) return false
|
||||
|
||||
return fileProvider.getFilesByPackage(packageFqName)
|
||||
fileProvider.getFilesByPackage(packageFqName)
|
||||
.any { it.mayHaveTopLevelCallable(name) }
|
||||
}
|
||||
}
|
||||
|
||||
+7
-13
@@ -52,9 +52,6 @@ internal open class JvmStubBasedFirDeserializedSymbolProvider(
|
||||
) : FirSymbolProvider(session) {
|
||||
private val declarationProvider by lazy(LazyThreadSafetyMode.PUBLICATION) { project.createDeclarationProvider(scope, module = null) }
|
||||
private val moduleData = moduleDataProvider.getModuleData(null)
|
||||
private val packageSetWithTopLevelCallableDeclarations: Set<String> by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||
declarationProvider.computePackageSetWithTopLevelCallableDeclarations()
|
||||
}
|
||||
|
||||
private val namesByPackageCache by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||
LLFirKotlinSymbolProviderNameCache(
|
||||
@@ -80,8 +77,8 @@ internal open class JvmStubBasedFirDeserializedSymbolProvider(
|
||||
private val functionCache = session.firCachesFactory.createCache(::loadFunctionsByCallableId)
|
||||
private val propertyCache = session.firCachesFactory.createCache(::loadPropertiesByCallableId)
|
||||
|
||||
override fun computePackageSetWithTopLevelCallables(): Set<String> {
|
||||
return packageSetWithTopLevelCallableDeclarations
|
||||
override fun computePackageSetWithTopLevelCallables(): Set<String>? {
|
||||
return namesByPackageCache.getPackageNamesWithTopLevelCallables()
|
||||
}
|
||||
|
||||
override fun computeCallableNamesInPackage(packageFqName: FqName): Set<Name>? =
|
||||
@@ -203,7 +200,6 @@ internal open class JvmStubBasedFirDeserializedSymbolProvider(
|
||||
}
|
||||
|
||||
private fun <C : FirCallableSymbol<*>> FirCache<CallableId, List<C>, Nothing?>.getCallables(id: CallableId): List<C> {
|
||||
if (id.packageName.asString() !in packageSetWithTopLevelCallableDeclarations) return emptyList()
|
||||
if (!namesByPackageCache.mayHaveTopLevelCallable(id.packageName, id.callableName)) return emptyList()
|
||||
return getValue(id)
|
||||
}
|
||||
@@ -218,13 +214,11 @@ internal open class JvmStubBasedFirDeserializedSymbolProvider(
|
||||
destination += propertyCache.getCallables(CallableId(packageFqName, name))
|
||||
}
|
||||
|
||||
override fun getPackage(fqName: FqName): FqName? {
|
||||
return if (!namesByPackageCache.getTopLevelClassifierNamesInPackage(fqName)
|
||||
.isNullOrEmpty() || packageSetWithTopLevelCallableDeclarations.contains(fqName.asString())
|
||||
) {
|
||||
fqName
|
||||
} else null
|
||||
}
|
||||
override fun getPackage(fqName: FqName): FqName? =
|
||||
fqName.takeIf {
|
||||
namesByPackageCache.getTopLevelClassifierNamesInPackage(fqName)?.isNotEmpty() == true ||
|
||||
namesByPackageCache.getPackageNamesWithTopLevelCallables()?.contains(fqName.asString()) == true
|
||||
}
|
||||
|
||||
override fun getClassLikeSymbolByClassId(classId: ClassId): FirClassLikeSymbol<*>? {
|
||||
if (!namesByPackageCache.mayHaveTopLevelClassifier(classId, mayHaveFunctionClass = false)) return null
|
||||
|
||||
+3
@@ -22,6 +22,9 @@ internal class LLFirKotlinSymbolProviderNameCache(
|
||||
.getTopLevelKotlinClassLikeDeclarationNamesInPackage(packageFqName)
|
||||
.mapTo(mutableSetOf()) { it.asString() }
|
||||
|
||||
override fun computePackageNamesWithTopLevelCallables(): Set<String> =
|
||||
declarationProvider.computePackageSetWithTopLevelCallableDeclarations()
|
||||
|
||||
override fun computeCallableNames(packageFqName: FqName): Set<Name> =
|
||||
declarationProvider.getTopLevelCallableNamesInPackage(packageFqName)
|
||||
}
|
||||
|
||||
+28
-10
@@ -19,7 +19,7 @@ import org.jetbrains.kotlin.name.Name
|
||||
* Caches the names of classifiers and callables contained in a package. [LLFirSymbolProviderNameCache] is used by symbol providers to abort
|
||||
* symbol finding early if the symbol name isn't contained in the symbol provider's domain.
|
||||
*
|
||||
* For the [getTopLevelClassifierNamesInPackage] and [getTopLevelCallableNamesInPackage] functions,
|
||||
* For the [getTopLevelClassifierNamesInPackage], [getTopLevelCallableNamesInPackage], and [getPackageNamesWithTopLevelCallables] functions,
|
||||
* the result may have false-positive entries but cannot have false-negative entries.
|
||||
* It should contain all the names in the package but may have some additional names that are not there.
|
||||
* Also, the `null` value might be returned when it's too heavyweight to calculate the results.
|
||||
@@ -35,6 +35,10 @@ internal abstract class LLFirSymbolProviderNameCache {
|
||||
*/
|
||||
abstract fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set<String>?
|
||||
|
||||
/**
|
||||
* Returns the set of package names which contain a top-level callable declaration within the cache's scope.
|
||||
*/
|
||||
abstract fun getPackageNamesWithTopLevelCallables(): Set<String>?
|
||||
|
||||
/**
|
||||
* Returns the set of top-level callable (functions and properties) names in a given scope inside the [packageFqName].
|
||||
@@ -59,24 +63,34 @@ internal abstract class LLFirSymbolProviderNameCache {
|
||||
abstract fun mayHaveTopLevelCallable(packageFqName: FqName, name: Name): Boolean
|
||||
}
|
||||
|
||||
|
||||
internal abstract class LLFirSymbolProviderNameCacheBase(
|
||||
private val firSession: FirSession
|
||||
) : LLFirSymbolProviderNameCache() {
|
||||
abstract fun computeClassifierNames(packageFqName: FqName): Set<String>?
|
||||
abstract fun computePackageNamesWithTopLevelCallables(): Set<String>?
|
||||
abstract fun computeCallableNames(packageFqName: FqName): Set<Name>?
|
||||
|
||||
private val topLevelClassifierNamesByPackage =
|
||||
firSession.firCachesFactory.createCache<FqName, Set<String>?>(::computeClassifierNames)
|
||||
firSession.firCachesFactory.createCache(::computeClassifierNames)
|
||||
|
||||
private val topLevelCallablePackageNames by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||
computePackageNamesWithTopLevelCallables()
|
||||
}
|
||||
|
||||
private val topLevelCallableNamesByPackage =
|
||||
firSession.firCachesFactory.createCache<FqName, Set<Name>?>(::computeCallableNames)
|
||||
firSession.firCachesFactory.createCache(::computeCallableNames)
|
||||
|
||||
final override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set<String>? =
|
||||
topLevelClassifierNamesByPackage.getValue(packageFqName)
|
||||
|
||||
final override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set<Name>? =
|
||||
topLevelCallableNamesByPackage.getValue(packageFqName)
|
||||
final override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set<Name>? {
|
||||
val packageNames = getPackageNamesWithTopLevelCallables()
|
||||
if (packageNames != null && packageFqName.asString() !in packageNames) return null
|
||||
|
||||
return topLevelCallableNamesByPackage.getValue(packageFqName)
|
||||
}
|
||||
|
||||
final override fun getPackageNamesWithTopLevelCallables(): Set<String>? = topLevelCallablePackageNames
|
||||
|
||||
final override fun mayHaveTopLevelClassifier(classId: ClassId, mayHaveFunctionClass: Boolean): Boolean {
|
||||
val names = getTopLevelClassifierNamesInPackage(classId.packageFqName) ?: return true
|
||||
@@ -90,10 +104,10 @@ internal abstract class LLFirSymbolProviderNameCacheBase(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal object LLFirEmptySymbolProviderNameCache : LLFirSymbolProviderNameCache() {
|
||||
override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set<String>? = emptySet()
|
||||
override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set<Name>? = emptySet()
|
||||
override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set<String> = emptySet()
|
||||
override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set<Name> = emptySet()
|
||||
override fun getPackageNamesWithTopLevelCallables(): Set<String> = emptySet()
|
||||
override fun mayHaveTopLevelClassifier(classId: ClassId, mayHaveFunctionClass: Boolean): Boolean = false
|
||||
override fun mayHaveTopLevelCallable(packageFqName: FqName, name: Name): Boolean = false
|
||||
}
|
||||
@@ -106,6 +120,10 @@ private constructor(
|
||||
return caches.flatMapToNullableSet { it.getTopLevelClassifierNamesInPackage(packageFqName) }
|
||||
}
|
||||
|
||||
override fun getPackageNamesWithTopLevelCallables(): Set<String>? {
|
||||
return caches.flatMapToNullableSet { it.getPackageNamesWithTopLevelCallables() }
|
||||
}
|
||||
|
||||
override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set<Name>? {
|
||||
return caches.flatMapToNullableSet { it.getTopLevelCallableNamesInPackage(packageFqName) }
|
||||
}
|
||||
@@ -127,4 +145,4 @@ private constructor(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user