diff --git a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinDeclarationProvider.kt b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinDeclarationProvider.kt index a838d315ac2..d1fbb80818a 100644 --- a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinDeclarationProvider.kt +++ b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinDeclarationProvider.kt @@ -46,11 +46,41 @@ public abstract class KotlinDeclarationProvider : KotlinComposableProvider { public abstract fun findFilesForScript(scriptFqName: FqName): Collection /** - * Calculates the set of package names which can be provided by this declaration provider and contain callables. + * Calculates the set of package names which can be provided by this declaration provider. + * + * The set may contain false positives. `null` may be returned if the package set is too expensive or impossible to compute. + * + * [computePackageNames] is used as the default implementation for [computePackageNamesWithTopLevelClassifiers] and + * [computePackageNamesWithTopLevelCallables] if either returns `null`. It depends on the declaration provider whether it's worth + * computing separate package sets for classifiers and callables, or just one set containing all package names. + */ + public open fun computePackageNames(): Set? = null + + /** + * Whether the declaration provider has a specific implementation of [computePackageNamesWithTopLevelClassifiers]. This allows the + * Analysis API backend to determine whether classifier package sets are computed and cached separately or with [computePackageNames]. + */ + public abstract val hasSpecificClassifierPackageNamesComputation: Boolean + + /** + * Calculates the set of package names which contain classifiers and can be provided by this declaration provider. * * The set may contain false positives. `null` may be returned if the package set is too expensive or impossible to compute. */ - public abstract fun computePackageSetWithTopLevelCallableDeclarations(): Set? + public open fun computePackageNamesWithTopLevelClassifiers(): Set? = computePackageNames() + + /** + * Whether the declaration provider has a specific implementation of [computePackageNamesWithTopLevelCallables]. This allows the + * Analysis API backend to determine whether callable package sets are computed and cached separately or with [computePackageNames]. + */ + public abstract val hasSpecificCallablePackageNamesComputation: Boolean + + /** + * Calculates the set of package names which contain callables and can be provided by this declaration provider. + * + * The set may contain false positives. `null` may be returned if the package set is too expensive or impossible to compute. + */ + public open fun computePackageNamesWithTopLevelCallables(): Set? = computePackageNames() } public abstract class KotlinDeclarationProviderFactory { diff --git a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinStaticDeclarationProvider.kt b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinStaticDeclarationProvider.kt index 90e60a5a535..8dc0e17e1df 100644 --- a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinStaticDeclarationProvider.kt +++ b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinStaticDeclarationProvider.kt @@ -40,6 +40,7 @@ import org.jetbrains.kotlin.psi.stubs.KotlinClassOrObjectStub import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes import org.jetbrains.kotlin.psi.stubs.impl.* import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol +import org.jetbrains.kotlin.utils.ifEmpty import java.util.concurrent.ConcurrentHashMap public class KotlinStaticDeclarationProvider internal constructor( @@ -100,10 +101,23 @@ public class KotlinStaticDeclarationProvider internal constructor( return index.scriptMap[scriptFqName].orEmpty().filter { it.containingKtFile.virtualFile in scope } } - override fun computePackageSetWithTopLevelCallableDeclarations(): Set { - val packageNames = index.topLevelPropertyMap.keys + index.topLevelFunctionMap.keys - return packageNames.mapTo(mutableSetOf()) { it.asString() } - } + override val hasSpecificClassifierPackageNamesComputation: Boolean get() = true + + override fun computePackageNamesWithTopLevelClassifiers(): Set = + buildPackageNamesSetFrom(index.classMap.keys, index.typeAliasMap.keys) + + override val hasSpecificCallablePackageNamesComputation: Boolean get() = true + + override fun computePackageNamesWithTopLevelCallables(): Set = + buildPackageNamesSetFrom(index.topLevelPropertyMap.keys, index.topLevelFunctionMap.keys) + + @Suppress("NOTHING_TO_INLINE") + private inline fun buildPackageNamesSetFrom(vararg fqNameSets: Set): Set = + buildSet { + for (fqNameSet in fqNameSets) { + fqNameSet.mapTo(this, FqName::asString) + } + } override fun getTopLevelProperties(callableId: CallableId): Collection = index.topLevelPropertyMap[callableId.packageName] diff --git a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/declarationProviders/CompositeKotlinDeclarationProvider.kt b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/declarationProviders/CompositeKotlinDeclarationProvider.kt index af3318e848e..1aaeca5510c 100644 --- a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/declarationProviders/CompositeKotlinDeclarationProvider.kt +++ b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/declarationProviders/CompositeKotlinDeclarationProvider.kt @@ -66,8 +66,22 @@ public class CompositeKotlinDeclarationProvider private constructor( return providers.flatMapTo(mutableListOf()) { it.findFilesForScript(scriptFqName) } } - override fun computePackageSetWithTopLevelCallableDeclarations(): Set? { - return providers.flatMapToNullableSet { it.computePackageSetWithTopLevelCallableDeclarations() } + override fun computePackageNames(): Set? { + return providers.flatMapToNullableSet { it.computePackageNames() } + } + + override val hasSpecificClassifierPackageNamesComputation: Boolean + get() = providers.any { it.hasSpecificClassifierPackageNamesComputation } + + override fun computePackageNamesWithTopLevelClassifiers(): Set? { + return providers.flatMapToNullableSet { it.computePackageNamesWithTopLevelClassifiers() } + } + + override val hasSpecificCallablePackageNamesComputation: Boolean + get() = providers.any { it.hasSpecificCallablePackageNamesComputation } + + override fun computePackageNamesWithTopLevelCallables(): Set? { + return providers.flatMapToNullableSet { it.computePackageNamesWithTopLevelCallables() } } public companion object { diff --git a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/declarationProviders/EmptyKotlinDeclarationProvider.kt b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/declarationProviders/EmptyKotlinDeclarationProvider.kt index aeaf7e1be91..474889e1c27 100644 --- a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/declarationProviders/EmptyKotlinDeclarationProvider.kt +++ b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/declarationProviders/EmptyKotlinDeclarationProvider.kt @@ -25,5 +25,8 @@ public object EmptyKotlinDeclarationProvider : KotlinDeclarationProvider() { override fun findFilesForFacade(facadeFqName: FqName): List = emptyList() override fun findInternalFilesForFacade(facadeFqName: FqName): List = emptyList() override fun findFilesForScript(scriptFqName: FqName): List = emptyList() - override fun computePackageSetWithTopLevelCallableDeclarations(): Set = emptySet() -} \ No newline at end of file + + override fun computePackageNames(): Set = emptySet() + override val hasSpecificClassifierPackageNamesComputation: Boolean get() = false + override val hasSpecificCallablePackageNamesComputation: Boolean get() = false +} diff --git a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/declarationProviders/FileBasedKotlinDeclarationProvider.kt b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/declarationProviders/FileBasedKotlinDeclarationProvider.kt index 7ea563d483f..6db1f62c526 100644 --- a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/declarationProviders/FileBasedKotlinDeclarationProvider.kt +++ b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/declarationProviders/FileBasedKotlinDeclarationProvider.kt @@ -129,9 +129,11 @@ public class FileBasedKotlinDeclarationProvider(public val kotlinFile: KtFile) : } override fun findInternalFilesForFacade(facadeFqName: FqName): Collection = emptyList() - override fun computePackageSetWithTopLevelCallableDeclarations(): Set { - return setOf(kotlinFile.packageFqName.asString()) - } + + override fun computePackageNames(): Set = setOf(kotlinFile.packageFqName.asString()) + + override val hasSpecificClassifierPackageNamesComputation: Boolean get() = false + override val hasSpecificCallablePackageNamesComputation: Boolean get() = false override fun findFilesForScript(scriptFqName: FqName): Collection = listOfNotNull(kotlinFile.script?.takeIf { it.fqName == scriptFqName }) diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirCombinedJavaSymbolProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirCombinedJavaSymbolProvider.kt index e02ed6881c6..d38b5ea7469 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirCombinedJavaSymbolProvider.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirCombinedJavaSymbolProvider.kt @@ -51,6 +51,8 @@ internal class LLFirCombinedJavaSymbolProvider private constructor( private val classCache: NullableCaffeineCache = NullableCaffeineCache { it.maximumSize(2500) } override val symbolNamesProvider: FirSymbolNamesProvider = object : FirSymbolNamesProviderWithoutCallables() { + override val hasSpecificClassifierPackageNamesComputation: Boolean get() = false + override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set? = null override fun mayHaveTopLevelClassifier(classId: ClassId): Boolean = true } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirCombinedSyntheticFunctionSymbolProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirCombinedSyntheticFunctionSymbolProvider.kt index c5f714788f3..6b93424f549 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirCombinedSyntheticFunctionSymbolProvider.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirCombinedSyntheticFunctionSymbolProvider.kt @@ -35,8 +35,12 @@ internal class LLFirCombinedSyntheticFunctionSymbolProvider private constructor( // `FirCompositeSymbolNamesProvider` defines `mayHaveSyntheticFunctionTypes` and `mayHaveSyntheticFunctionType` correctly, which is // needed for consistency should this symbol provider be part of another composite symbol provider. object : FirCompositeSymbolNamesProvider(providers.map { it.symbolNamesProvider }) { + override fun getPackageNames(): Set = emptySet() + + override val hasSpecificClassifierPackageNamesComputation: Boolean get() = false override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set = emptySet() - override fun getPackageNamesWithTopLevelCallables(): Set = emptySet() + + override val hasSpecificCallablePackageNamesComputation: Boolean get() = false override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set = emptySet() } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/resolve/extensions/LLFirResolveExtensionTool.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/resolve/extensions/LLFirResolveExtensionTool.kt index 4dfbe2f8f5e..bfdb3642596 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/resolve/extensions/LLFirResolveExtensionTool.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/resolve/extensions/LLFirResolveExtensionTool.kt @@ -27,6 +27,7 @@ import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils import org.jetbrains.kotlin.name.* import org.jetbrains.kotlin.platform.TargetPlatform import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.utils.mapToSetOrEmpty import java.util.concurrent.ConcurrentHashMap /** @@ -75,15 +76,18 @@ private class LLFirResolveExtensionToolSymbolNamesProvider( private val packageFilter: LLFirResolveExtensionToolPackageFilter, private val fileProvider: LLFirResolveExtensionsFileProvider, ) : FirSymbolNamesProvider() { + override fun getPackageNames(): Set = forbidAnalysis { + packageFilter.getAllPackages().mapToSetOrEmpty(FqName::asString) + } + + override val hasSpecificClassifierPackageNamesComputation: Boolean get() = false + override val hasSpecificCallablePackageNamesComputation: Boolean get() = false + override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set = forbidAnalysis { if (!packageFilter.packageExists(packageFqName)) return emptySet() fileProvider.getFilesByPackage(packageFqName).flatMap { it.getTopLevelClassifierNames() }.toSet() } - override fun getPackageNamesWithTopLevelCallables(): Set = forbidAnalysis { - packageFilter.getAllPackages().mapTo(mutableSetOf()) { it.asString() } - } - override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set = forbidAnalysis { if (!packageFilter.packageExists(packageFqName)) return emptySet() fileProvider.getFilesByPackage(packageFqName) @@ -245,9 +249,10 @@ class LLFirResolveExtensionToolDeclarationProvider internal constructor( .mapNotNullTo(mutableListOf()) { it.kotlinFile.script } } - override fun computePackageSetWithTopLevelCallableDeclarations(): Set { - return emptySet() - } + override fun computePackageNames(): Set? = null + + override val hasSpecificClassifierPackageNamesComputation: Boolean get() = false + override val hasSpecificCallablePackageNamesComputation: Boolean get() = false private inline fun getDeclarationProvidersByPackage( packageFqName: FqName, diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/LLFirKotlinSymbolNamesProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/LLFirKotlinSymbolNamesProvider.kt index 9d3f4120c44..9d8b2bd4846 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/LLFirKotlinSymbolNamesProvider.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/LLFirKotlinSymbolNamesProvider.kt @@ -24,21 +24,29 @@ internal open class LLFirKotlinSymbolNamesProvider( private val declarationProvider: KotlinDeclarationProvider, private val allowKotlinPackage: Boolean? = null, ) : FirSymbolNamesProvider() { + override fun getPackageNames(): Set? = declarationProvider.computePackageNames()?.excludeKotlinPackageNamesIfNecessary() + + override val hasSpecificClassifierPackageNamesComputation: Boolean + get() = declarationProvider.hasSpecificClassifierPackageNamesComputation + + override fun getPackageNamesWithTopLevelClassifiers(): Set? = + declarationProvider + .computePackageNamesWithTopLevelClassifiers() + ?.excludeKotlinPackageNamesIfNecessary() + override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set { if (allowKotlinPackage == false && packageFqName.isKotlinPackage()) return emptySet() return declarationProvider.getTopLevelKotlinClassLikeDeclarationNamesInPackage(packageFqName) } - override fun getPackageNamesWithTopLevelCallables(): Set? { - val packageNames = declarationProvider.computePackageSetWithTopLevelCallableDeclarations() ?: return null + override val hasSpecificCallablePackageNamesComputation: Boolean + get() = declarationProvider.hasSpecificCallablePackageNamesComputation - if (allowKotlinPackage == false && packageNames.any { it.isKotlinPackage() }) { - return packageNames.filterToSetOrEmpty { !it.isKotlinPackage() } - } - - return packageNames - } + override fun getPackageNamesWithTopLevelCallables(): Set? = + declarationProvider + .computePackageNamesWithTopLevelCallables() + ?.excludeKotlinPackageNamesIfNecessary() override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set { if (allowKotlinPackage == false && packageFqName.isKotlinPackage()) return emptySet() @@ -46,6 +54,13 @@ internal open class LLFirKotlinSymbolNamesProvider( return declarationProvider.getTopLevelCallableNamesInPackage(packageFqName).ifEmpty { emptySet() } } + private fun Set.excludeKotlinPackageNamesIfNecessary(): Set { + if (allowKotlinPackage == false && any { it.isKotlinPackage() }) { + return filterToSetOrEmpty { !it.isKotlinPackage() } + } + return this + } + companion object { fun cached(session: FirSession, declarationProvider: KotlinDeclarationProvider): FirCachedSymbolNamesProvider = FirDelegatingCachedSymbolNamesProvider(session, LLFirKotlinSymbolNamesProvider(declarationProvider)) diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/NativeForwardDeclarationsSymbolProvider.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/NativeForwardDeclarationsSymbolProvider.kt index 1aaaca724e8..b8f54525173 100644 --- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/NativeForwardDeclarationsSymbolProvider.kt +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/NativeForwardDeclarationsSymbolProvider.kt @@ -38,6 +38,7 @@ import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.NativeForwardDeclarationKind import org.jetbrains.kotlin.name.NativeStandardInteropNames +import org.jetbrains.kotlin.utils.mapToSetOrEmpty class NativeForwardDeclarationsSymbolProvider( session: FirSession, @@ -157,6 +158,11 @@ class NativeForwardDeclarationsSymbolProvider( } override val symbolNamesProvider: FirSymbolNamesProvider = object : FirSymbolNamesProviderWithoutCallables() { + override val hasSpecificClassifierPackageNamesComputation: Boolean get() = true + + override fun getPackageNamesWithTopLevelClassifiers(): Set? = + includedForwardDeclarationsByPackage.keys.mapToSetOrEmpty(FqName::asString) + override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set = includedForwardDeclarationsByPackage[packageFqName].orEmpty() } diff --git a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/AbstractFirDeserializedSymbolProvider.kt b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/AbstractFirDeserializedSymbolProvider.kt index d7302c3516e..e5e7cd76a12 100644 --- a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/AbstractFirDeserializedSymbolProvider.kt +++ b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/AbstractFirDeserializedSymbolProvider.kt @@ -95,6 +95,12 @@ abstract class AbstractFirDeserializedSymbolProvider( } override val symbolNamesProvider: FirSymbolNamesProvider = object : FirCachedSymbolNamesProvider(session) { + override fun computePackageNames(): Set? = null + + override val hasSpecificClassifierPackageNamesComputation: Boolean get() = false + + override fun computePackageNamesWithTopLevelClassifiers(): Set? = null + override fun computeTopLevelClassifierNames(packageFqName: FqName): Set? { val classesInPackage = knownTopLevelClassesInPackage(packageFqName)?.mapToSetOrEmpty { Name.identifier(it) } ?: return null @@ -109,6 +115,8 @@ abstract class AbstractFirDeserializedSymbolProvider( } } + override val hasSpecificCallablePackageNamesComputation: Boolean get() = true + override fun getPackageNamesWithTopLevelCallables(): Set = packageNamesForNonClassDeclarations override fun computePackageNamesWithTopLevelCallables(): Set = packageNamesForNonClassDeclarations diff --git a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirBuiltinSymbolProvider.kt b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirBuiltinSymbolProvider.kt index 5797402ac02..5119fabc6a3 100644 --- a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirBuiltinSymbolProvider.kt +++ b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirBuiltinSymbolProvider.kt @@ -33,6 +33,7 @@ import org.jetbrains.kotlin.name.StandardClassIds import org.jetbrains.kotlin.serialization.deserialization.ProtoBasedClassDataFinder import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol import org.jetbrains.kotlin.serialization.deserialization.getName +import org.jetbrains.kotlin.utils.mapToSetOrEmpty import java.io.InputStream /** @@ -85,8 +86,10 @@ open class FirBuiltinSymbolProvider( } override val symbolNamesProvider: FirSymbolNamesProvider = object : FirSymbolNamesProvider() { - override fun getPackageNamesWithTopLevelCallables(): Set = - allPackageFragments.keys.mapTo(mutableSetOf()) { it.asString() } + override fun getPackageNames(): Set? = allPackageFragments.keys.mapToSetOrEmpty(FqName::asString) + + override val hasSpecificClassifierPackageNamesComputation: Boolean get() = false + override val hasSpecificCallablePackageNamesComputation: Boolean get() = false override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set = allPackageFragments[packageFqName]?.flatMapTo(mutableSetOf()) { fragment -> diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaSymbolProvider.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaSymbolProvider.kt index 7962fe9deb5..ebbd2644d36 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaSymbolProvider.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaSymbolProvider.kt @@ -72,6 +72,8 @@ open class JavaSymbolProvider( override fun getPackage(fqName: FqName): FqName? = javaFacade.getPackage(fqName) override val symbolNamesProvider: FirSymbolNamesProvider = object : FirSymbolNamesProviderWithoutCallables() { + override val hasSpecificClassifierPackageNamesComputation: Boolean get() = false + override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set? = javaFacade.knownClassNamesInPackage(packageFqName)?.mapToSetOrEmpty { Name.identifier(it) } } diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/extensions/FirExtensionDeclarationsSymbolProvider.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/extensions/FirExtensionDeclarationsSymbolProvider.kt index d3060a4da35..84cb34a86d7 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/extensions/FirExtensionDeclarationsSymbolProvider.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/extensions/FirExtensionDeclarationsSymbolProvider.kt @@ -149,12 +149,25 @@ class FirExtensionDeclarationsSymbolProvider private constructor( // ------------------------------------------ provider methods ------------------------------------------ override val symbolNamesProvider: FirSymbolNamesProvider = object : FirSymbolNamesProvider() { + override val hasSpecificClassifierPackageNamesComputation: Boolean get() = true + + override fun getPackageNamesWithTopLevelClassifiers(): Set? = + buildSet { + extensions.forEach { extension -> + extension.topLevelClassIdsCache.getValue().mapTo(this) { it.packageFqName.asString() } + } + } + override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set = classNamesInPackageCache.getValue()[packageFqName] ?: emptySet() + override val hasSpecificCallablePackageNamesComputation: Boolean get() = true + override fun getPackageNamesWithTopLevelCallables(): Set = - extensions.flatMapTo(mutableSetOf()) { extension -> - extension.topLevelCallableIdsCache.getValue().map { it.packageName.asString() } + buildSet { + extensions.forEach { extension -> + extension.topLevelCallableIdsCache.getValue().mapTo(this) { it.packageName.asString() } + } } override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set = diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/extensions/FirSwitchableExtensionDeclarationsSymbolProvider.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/extensions/FirSwitchableExtensionDeclarationsSymbolProvider.kt index ff5dfc4b37a..a9a3ad31390 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/extensions/FirSwitchableExtensionDeclarationsSymbolProvider.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/extensions/FirSwitchableExtensionDeclarationsSymbolProvider.kt @@ -35,6 +35,18 @@ class FirSwitchableExtensionDeclarationsSymbolProvider private constructor( private var disabled: Boolean = false override val symbolNamesProvider: FirSymbolNamesProvider = object : FirSymbolNamesProvider() { + override fun getPackageNames(): Set? = + if (disabled) null else delegate.symbolNamesProvider.getPackageNames() + + override val hasSpecificClassifierPackageNamesComputation: Boolean + get() = delegate.symbolNamesProvider.hasSpecificClassifierPackageNamesComputation + + override fun getPackageNamesWithTopLevelClassifiers(): Set? = + if (disabled) null else delegate.symbolNamesProvider.getPackageNamesWithTopLevelClassifiers() + + override val hasSpecificCallablePackageNamesComputation: Boolean + get() = delegate.symbolNamesProvider.hasSpecificCallablePackageNamesComputation + override fun getPackageNamesWithTopLevelCallables(): Set? = if (disabled) null else delegate.symbolNamesProvider.getPackageNamesWithTopLevelCallables() diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/providers/FirCachedSymbolNamesProvider.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/providers/FirCachedSymbolNamesProvider.kt index 4a3fcf5d8f9..ba6bdaf65e5 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/providers/FirCachedSymbolNamesProvider.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/providers/FirCachedSymbolNamesProvider.kt @@ -19,21 +19,76 @@ import org.jetbrains.kotlin.utils.flatMapToNullableSet * A [FirSymbolNamesProvider] that caches all name sets. */ abstract class FirCachedSymbolNamesProvider(protected val session: FirSession) : FirSymbolNamesProvider() { + abstract fun computePackageNames(): Set? + + /** + * This function is only called if [hasSpecificClassifierPackageNamesComputation] is `true`. Otherwise, the classifier package set will + * be taken from the cached general package names to avoid building duplicate sets. + */ + abstract fun computePackageNamesWithTopLevelClassifiers(): Set? + abstract fun computeTopLevelClassifierNames(packageFqName: FqName): Set? + + /** + * This function is only called if [hasSpecificCallablePackageNamesComputation] is `true`. Otherwise, the callable package set will be + * taken from the cached general package names to avoid building duplicate sets. + */ abstract fun computePackageNamesWithTopLevelCallables(): Set? + abstract fun computeTopLevelCallableNames(packageFqName: FqName): Set? + private val cachedPackageNames by lazy(LazyThreadSafetyMode.PUBLICATION) { + computePackageNames() + } + + private val topLevelClassifierPackageNames by lazy(LazyThreadSafetyMode.PUBLICATION) { + // If there is no specific classifier package names computation, we can cache the general package names, instead of computing and + // caching a duplicate of the general package names set. Without the static knowledge in + // `hasSpecificClassifierPackageNamesComputation`, a composite or delegate cached symbol names provider cannot know if its child + // providers may return a separate set from `getPackageNamesWithTopLevelClassifiers` or it just falls back to `getPackageNames`. So + // it wouldn't be able to make a decision about whether to compute the specific package names set for classifiers. + // + // To illustrate this, consider the following example: A combined cached symbol names provider will build its `cachedPackageNames` + // by calling `getPackageNames` on all child providers. Let's call the result **S1**. To build its `topLevelClassifierPackageNames`, + // it calls `getPackageNamesWithTopLevelClassifiers` on all child providers. This produces a different set, which we'll call **S2**. + // If the symbol names provider has no specific computation for classifier package names, S1 and S2 would be equal, but different + // instances. A naive implementation would cache both S1 in `cachedPackageNames` and S2 in `topLevelClassifierPackageNames`. + // `hasSpecificClassifierPackageNamesComputation` gives the provider enough information to avoid computing and caching S2 entirely, + // so that S1 will also be cached in `topLevelClassifierPackageNames`. + if (hasSpecificClassifierPackageNamesComputation) { + computePackageNamesWithTopLevelClassifiers()?.let { return@lazy it } + } + cachedPackageNames + } + private val topLevelClassifierNamesByPackage = session.firCachesFactory.createCache(::computeTopLevelClassifierNames) private val topLevelCallablePackageNames by lazy(LazyThreadSafetyMode.PUBLICATION) { - computePackageNamesWithTopLevelCallables() + // See the comment in `topLevelClassifierPackageNames` above for reasoning about `hasSpecific*PackageNamesComputation`. + if (hasSpecificCallablePackageNamesComputation) { + computePackageNamesWithTopLevelCallables()?.let { return@lazy it } + } + cachedPackageNames } private val topLevelCallableNamesByPackage = session.firCachesFactory.createCache(::computeTopLevelCallableNames) - override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set? = + override fun getPackageNames(): Set? = cachedPackageNames + + override fun getPackageNamesWithTopLevelClassifiers(): Set? = topLevelClassifierPackageNames + + override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set? { + val packageNames = getPackageNamesWithTopLevelClassifiers() + if (packageNames != null && packageFqName.asString() !in packageNames) return emptySet() + + return getTopLevelClassifierNamesInPackageSkippingPackageCheck(packageFqName) + } + + // This is used by the compiler `FirCachingCompositeSymbolProvider` to bypass the cache access for classifier package names, because + // the compiler never computes this package set. + protected fun getTopLevelClassifierNamesInPackageSkippingPackageCheck(packageFqName: FqName): Set? = topLevelClassifierNamesByPackage.getValue(packageFqName) override fun getPackageNamesWithTopLevelCallables(): Set? = topLevelCallablePackageNames @@ -50,9 +105,18 @@ class FirDelegatingCachedSymbolNamesProvider( session: FirSession, private val delegate: FirSymbolNamesProvider, ) : FirCachedSymbolNamesProvider(session) { + override fun computePackageNames(): Set? = delegate.getPackageNames() + + override val hasSpecificClassifierPackageNamesComputation: Boolean get() = delegate.hasSpecificClassifierPackageNamesComputation + + override fun computePackageNamesWithTopLevelClassifiers(): Set? = + delegate.getPackageNamesWithTopLevelClassifiers() + override fun computeTopLevelClassifierNames(packageFqName: FqName): Set? = delegate.getTopLevelClassifierNamesInPackage(packageFqName) + override val hasSpecificCallablePackageNamesComputation: Boolean get() = delegate.hasSpecificCallablePackageNamesComputation + override fun computePackageNamesWithTopLevelCallables(): Set? = delegate.getPackageNamesWithTopLevelCallables() @@ -69,9 +133,18 @@ open class FirCompositeCachedSymbolNamesProvider( session: FirSession, val providers: List, ) : FirCachedSymbolNamesProvider(session) { + override fun computePackageNames(): Set? = providers.flatMapToNullableSet { it.getPackageNames() } + + override val hasSpecificClassifierPackageNamesComputation: Boolean = providers.any { it.hasSpecificClassifierPackageNamesComputation } + + override fun computePackageNamesWithTopLevelClassifiers(): Set? = + providers.flatMapToNullableSet { it.getPackageNamesWithTopLevelClassifiers() } + override fun computeTopLevelClassifierNames(packageFqName: FqName): Set? = providers.flatMapToNullableSet { it.getTopLevelClassifierNamesInPackage(packageFqName) } + override val hasSpecificCallablePackageNamesComputation: Boolean = providers.any { it.hasSpecificCallablePackageNamesComputation } + override fun computePackageNamesWithTopLevelCallables(): Set? = providers.flatMapToNullableSet { it.getPackageNamesWithTopLevelCallables() } diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/providers/FirSymbolNamesProvider.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/providers/FirSymbolNamesProvider.kt index 5fa8114503a..480d41cb6b0 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/providers/FirSymbolNamesProvider.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/providers/FirSymbolNamesProvider.kt @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.utils.flatMapToNullableSet * is usually checked before the symbol is requested with functions such as [FirSymbolProvider.getClassLikeSymbolByClassId]. * * All `get*` functions in this interface have the following common contract: + * * - They return `null` in case a name set is too hard, expensive, or even impossible to compute. * - They might return a strict superset of the name set, i.e. the resulting set might contain some names that do not exist in the symbol * provider. In other words, these sets allow false positives, but not false negatives. @@ -26,6 +27,32 @@ import org.jetbrains.kotlin.utils.flatMapToNullableSet * The result of [mayHaveTopLevelClassifier] and [mayHaveTopLevelCallable] may be a false positive but cannot be a false negative. */ abstract class FirSymbolNamesProvider { + /** + * Returns the set of fully qualified package names which contain any top-level declaration within the provider's scope. + * + * [getPackageNames] is used as the default implementation for [getPackageNamesWithTopLevelClassifiers] and + * [getPackageNamesWithTopLevelCallables]. It depends on the symbol names provider whether it's worth computing separate package sets + * for classifiers and callables, or just one set containing all package names. + */ + open fun getPackageNames(): Set? = null + + /** + * Whether the symbol names provider has a specific computation for [getPackageNamesWithTopLevelClassifiers], instead of just falling + * back to [getPackageNames]. It *does not mean* that [getPackageNamesWithTopLevelClassifiers] returns a non-null result. Rather, it + * means that the symbol provider makes an effort to compute specific classifier package names before falling back to [getPackageNames]. + * + * [FirCachedSymbolNamesProvider]s rely on this property to decide whether they should compute and cache classifier package names + * separately or fall back to the cached general package names (saving time and memory). + * + * The value should be constant, because it allows composite symbol providers to cache their own value. + */ + abstract val hasSpecificClassifierPackageNamesComputation: Boolean + + /** + * Returns the set of fully qualified package names which contain a top-level classifier declaration within the provider's scope. + */ + open fun getPackageNamesWithTopLevelClassifiers(): Set? = getPackageNames() + /** * Returns the set of top-level classifier names (classes, interfaces, objects, and type aliases) inside the [packageFqName] package * within the provider's scope. @@ -35,10 +62,15 @@ abstract class FirSymbolNamesProvider { */ abstract fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set? + /** + * @see hasSpecificClassifierPackageNamesComputation + */ + abstract val hasSpecificCallablePackageNamesComputation: Boolean + /** * Returns the set of fully qualified package names which contain a top-level callable declaration within the provider's scope. */ - abstract fun getPackageNamesWithTopLevelCallables(): Set? + open fun getPackageNamesWithTopLevelCallables(): Set? = getPackageNames() /** * Returns the set of top-level callable names (functions and properties) inside the [packageFqName] package within the provider's @@ -71,6 +103,9 @@ abstract class FirSymbolNamesProvider { open fun mayHaveTopLevelClassifier(classId: ClassId): Boolean { if (mayHaveSyntheticFunctionTypes && mayHaveSyntheticFunctionType(classId)) return true + // `packageNamesWithTopLevelClassifiers` is checked in `FirCachedSymbolNamesProvider.getTopLevelClassifierNamesInPackage`. It is not + // worth checking it in uncached situations, since building the package set is as or more expensive as just building the "names in + // package" set. val names = getTopLevelClassifierNamesInPackage(classId.packageFqName) ?: return true if (classId.outerClassId == null) { if (!names.mayContainTopLevelClassifier(classId.shortClassName)) return false @@ -88,9 +123,9 @@ abstract class FirSymbolNamesProvider { // Symbol providers can potentially provide symbols for special names. Hence, special names have to be allowed. if (name.isSpecial) return true - // The `packageNamesWithTopLevelCallables` check is implemented in `FirCachedSymbolNamesProvider` via - // `getTopLevelCallableNamesInPackage`. It is probably not worth checking it in uncached situations, since building the set of - // package names with top-level callables is likely as expensive as just calling an uncached `getTopLevelCallableNamesInPackage`. + // `packageNamesWithTopLevelCallables` is checked in `FirCachedSymbolNamesProvider.getTopLevelCallableNamesInPackage`. It is not + // worth checking it in uncached situations, since building the package set is as or more expensive as just building the "names in + // package" set. val names = getTopLevelCallableNamesInPackage(packageFqName) ?: return true return name in names } @@ -105,9 +140,12 @@ private fun Set.mayContainTopLevelClassifier(shortClassName: Name): Boolea * A [FirSymbolNamesProvider] for symbol providers which can't provide any symbol name sets. */ object FirNullSymbolNamesProvider : FirSymbolNamesProvider() { + override val hasSpecificClassifierPackageNamesComputation: Boolean get() = false override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set? = null + + override val hasSpecificCallablePackageNamesComputation: Boolean get() = false override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set? = null - override fun getPackageNamesWithTopLevelCallables(): Set? = null + override fun mayHaveTopLevelClassifier(classId: ClassId): Boolean = true override fun mayHaveTopLevelCallable(packageFqName: FqName, name: Name): Boolean = true } @@ -116,24 +154,42 @@ object FirNullSymbolNamesProvider : FirSymbolNamesProvider() { * A [FirSymbolNamesProvider] for symbol providers which don't contain *any* symbols. */ object FirEmptySymbolNamesProvider : FirSymbolNamesProvider() { + override fun getPackageNames(): Set = emptySet() + + override val hasSpecificClassifierPackageNamesComputation: Boolean get() = false override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set = emptySet() + + override val hasSpecificCallablePackageNamesComputation: Boolean get() = false override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set = emptySet() - override fun getPackageNamesWithTopLevelCallables(): Set = emptySet() + override fun mayHaveTopLevelClassifier(classId: ClassId): Boolean = false override fun mayHaveTopLevelCallable(packageFqName: FqName, name: Name): Boolean = false } abstract class FirSymbolNamesProviderWithoutCallables : FirSymbolNamesProvider() { + override val hasSpecificCallablePackageNamesComputation: Boolean get() = true override fun getPackageNamesWithTopLevelCallables(): Set = emptySet() override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set? = emptySet() override fun mayHaveTopLevelCallable(packageFqName: FqName, name: Name): Boolean = false } open class FirCompositeSymbolNamesProvider(val providers: List) : FirSymbolNamesProvider() { + override fun getPackageNames(): Set? { + return providers.flatMapToNullableSet { it.getPackageNames() } + } + + override val hasSpecificClassifierPackageNamesComputation: Boolean = providers.any { it.hasSpecificClassifierPackageNamesComputation } + + override fun getPackageNamesWithTopLevelClassifiers(): Set? { + return providers.flatMapToNullableSet { it.getPackageNamesWithTopLevelClassifiers() } + } + override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set? { return providers.flatMapToNullableSet { it.getTopLevelClassifierNamesInPackage(packageFqName) } } + override val hasSpecificCallablePackageNamesComputation: Boolean = providers.any { it.hasSpecificCallablePackageNamesComputation } + override fun getPackageNamesWithTopLevelCallables(): Set? { return providers.flatMapToNullableSet { it.getPackageNamesWithTopLevelCallables() } } diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirCachingCompositeSymbolProvider.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirCachingCompositeSymbolProvider.kt index 1675118ad81..de44de4faa0 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirCachingCompositeSymbolProvider.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirCachingCompositeSymbolProvider.kt @@ -48,6 +48,8 @@ class FirCachingCompositeSymbolProvider( ensureNotNull(it) { "classifier names in package $packageFqName" } } + override val hasSpecificCallablePackageNamesComputation: Boolean get() = true + override fun computePackageNamesWithTopLevelCallables(): Set? = super.computePackageNamesWithTopLevelCallables().also { ensureNotNull(it) { "package names with top-level callables" } @@ -63,6 +65,20 @@ class FirCachingCompositeSymbolProvider( // We know that `session` is the same as the sessions of all `providers`, so we can take a shortcut here. return classId.isNameForFunctionClass(session) } + + // The compiler does not compute classifier and general package name sets because it is too expensive, so we can disable them. + // `FirCachingCompositeSymbolProvider` is only used by the compiler. + override fun computePackageNames(): Set? = null + override fun computePackageNamesWithTopLevelClassifiers(): Set? = null + + override val hasSpecificClassifierPackageNamesComputation: Boolean get() = false + + // Avoid cache accesses. + override fun getPackageNames(): Set? = null + override fun getPackageNamesWithTopLevelClassifiers(): Set? = null + + override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set? = + super.getTopLevelClassifierNamesInPackageSkippingPackageCheck(packageFqName) } private inline fun ensureNotNull(v: Any?, representation: () -> String) { diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirExtensionSyntheticFunctionInterfaceProvider.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirExtensionSyntheticFunctionInterfaceProvider.kt index 6aa51468f2d..eeec9da470f 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirExtensionSyntheticFunctionInterfaceProvider.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirExtensionSyntheticFunctionInterfaceProvider.kt @@ -92,11 +92,15 @@ abstract class FirSyntheticFunctionInterfaceProviderBase( override fun mayHaveSyntheticFunctionType(classId: ClassId): Boolean = classId.getAcceptableFunctionTypeKind() != null + override fun getPackageNames(): Set = emptySet() + + override val hasSpecificClassifierPackageNamesComputation: Boolean get() = false + override val hasSpecificCallablePackageNamesComputation: Boolean get() = false + override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set = // Generated function type names aren't included in the top-level classifier names set. emptySet() - override fun getPackageNamesWithTopLevelCallables(): Set = emptySet() override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set = emptySet() override fun mayHaveTopLevelClassifier(classId: ClassId): Boolean = mayHaveSyntheticFunctionType(classId) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirCloneableSymbolProvider.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirCloneableSymbolProvider.kt index 9d0039a0f06..4c96209aab0 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirCloneableSymbolProvider.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirCloneableSymbolProvider.kt @@ -79,6 +79,10 @@ class FirCloneableSymbolProvider( } override val symbolNamesProvider: FirSymbolNamesProvider = object : FirSymbolNamesProviderWithoutCallables() { + override val hasSpecificClassifierPackageNamesComputation: Boolean get() = true + + override fun getPackageNamesWithTopLevelClassifiers(): Set = setOf(StandardClassIds.Cloneable.packageFqName.asString()) + override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set = if (packageFqName == StandardClassIds.Cloneable.packageFqName) { setOf(StandardClassIds.Cloneable.shortClassName) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirProviderImpl.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirProviderImpl.kt index b46f73024b1..0ba3ec3b5c4 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirProviderImpl.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirProviderImpl.kt @@ -14,6 +14,7 @@ import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor import org.jetbrains.kotlin.name.* +import org.jetbrains.kotlin.utils.mapToSetOrEmpty @ThreadSafeMutableState class FirProviderImpl(val session: FirSession, val kotlinScopeProvider: FirKotlinScopeProvider) : FirProvider() { @@ -82,8 +83,10 @@ class FirProviderImpl(val session: FirSession, val kotlinScopeProvider: FirKotli } override val symbolNamesProvider: FirSymbolNamesProvider = object : FirSymbolNamesProvider() { - override fun getPackageNamesWithTopLevelCallables(): Set = - state.allSubPackages.mapTo(mutableSetOf()) { it.asString() } + override fun getPackageNames(): Set = state.allSubPackages.mapToSetOrEmpty(FqName::asString) + + override val hasSpecificClassifierPackageNamesComputation: Boolean get() = false + override val hasSpecificCallablePackageNamesComputation: Boolean get() = false override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set = state.classifierInPackage[packageFqName].orEmpty()