From 6474ff88fa3f77fb5d605d8c707d813452169b6a Mon Sep 17 00:00:00 2001 From: Marco Pennekamp Date: Mon, 23 Oct 2023 17:41:56 +0200 Subject: [PATCH] [FIR] FirSymbolNamesProvider: Implement classifier package name sets - Previously, only callable package name sets were implemented, because the compiler cannot economically compute classifier package sets for libraries. This has not changed. However, the K2 IntelliJ plugin and standalone Analysis API can very easily compute classifier package sets. Hence, this commit adds support to `FirSymbolNamesProvider` for such sets. - Similar to callable package sets, classifier package sets (1) improve the memory usage of symbol names providers and (2) improve the performance of `mayHaveTopLevelClassifier`, which is a significant bottleneck in the IDE. - In many cases, the package sets for callables and classifiers are the same. For example, the IDE Kotlin declaration provider computes the set of packages that contain any classifier and/or callable, for the following reasons: (1) indexing package names without filtering for declarations is much faster, (2) computing separate sets is not free both in time and memory, and (3) the performance impact of having a more narrow set for callables is expected to be negligible. For this reason, `FirSymbolNamesProvider.getPackageNames` exists to provide a shared package set. - The `hasSpecific*PackageNamesComputation` properties are required to avoid caching the same package set in cached symbol names providers twice. Because these properties are constant, they can be checked very quickly, and no time has to be wasted trying a specific package set computation to find out whether it's supported. ### IDE Performance Results Package set construction performance improved in the IDE in multiple benchmarks. This improves the performance of symbol providers overall, which has a direct impact on completion, code analysis, and Find Usages. In a local manual run of the `intellij_commit/setUp` Find Usages performance test, the total time spent in `getClassLikeSymbolByClassId` improved from ~18.7s to ~11.2s. Due to parallel resolve, this does not translate to a wall clock improvement of 7 seconds, but rather of a few seconds. Some performance tests improved markedly in warmup, with for example `toolbox_enterprise/genUuid` Find Usages having an improvement in `StubBasedFirDeserializedSymbolProvider.getClassLikeSymbolByClassId` from 2.4s to 0.2s. This has a direct impact on the first-run performance of the tested Find Usages command. So far, classifier package sets in the IDE are only implemented for libraries, and library sessions are cached after the first warmup. Because the biggest impact of classifier package sets is avoiding computation of "class names in package" sets, the impact of this optimization is not accurately reflected in the timings reported by our performance tests. `toolbox_enterprise/genUuid` above is a good example, as the warmup timings are great, but after warmup, `StubBasedFirDeserializedSymbolProvider.getClassLikeSymbolByClassId` improved only from 150ms to 70ms. `toolbox_enterprise/genUuid` is another example, as we can confidently say that the first-run Find Usages performance has improved (which makes a difference for the user), but it is unclear by how much, as warmup is not measured in performance tests. The same optimization for source sessions will be easier to measure, as source sessions are invalidated after each performance test run. This commit lays the groundwork for that as well, because source session support only requires the requisite package set computation in the IDE declaration provider to be implemented. ^KT-62553 fixed --- .../providers/KotlinDeclarationProvider.kt | 34 +++++++- .../impl/KotlinStaticDeclarationProvider.kt | 22 +++++- .../CompositeKotlinDeclarationProvider.kt | 18 ++++- .../EmptyKotlinDeclarationProvider.kt | 7 +- .../FileBasedKotlinDeclarationProvider.kt | 8 +- .../LLFirCombinedJavaSymbolProvider.kt | 2 + ...CombinedSyntheticFunctionSymbolProvider.kt | 6 +- .../extensions/LLFirResolveExtensionTool.kt | 19 +++-- .../util/LLFirKotlinSymbolNamesProvider.kt | 31 ++++++-- ...NativeForwardDeclarationsSymbolProvider.kt | 6 ++ .../AbstractFirDeserializedSymbolProvider.kt | 8 ++ .../impl/FirBuiltinSymbolProvider.kt | 7 +- .../kotlin/fir/java/JavaSymbolProvider.kt | 2 + .../FirExtensionDeclarationsSymbolProvider.kt | 17 +++- ...ableExtensionDeclarationsSymbolProvider.kt | 12 +++ .../providers/FirCachedSymbolNamesProvider.kt | 77 ++++++++++++++++++- .../providers/FirSymbolNamesProvider.kt | 68 ++++++++++++++-- .../impl/FirCachingCompositeSymbolProvider.kt | 16 ++++ ...nsionSyntheticFunctionInterfaceProvider.kt | 6 +- .../impl/FirCloneableSymbolProvider.kt | 4 + .../resolve/providers/impl/FirProviderImpl.kt | 7 +- 21 files changed, 333 insertions(+), 44 deletions(-) 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()