diff --git a/analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/collections/collectionUtils.kt b/analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/collections/collectionUtils.kt index 453ad9fc6aa..76797e97727 100644 --- a/analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/collections/collectionUtils.kt +++ b/analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/collections/collectionUtils.kt @@ -9,8 +9,11 @@ package org.jetbrains.kotlin.analysis.utils.collections * Maps all elements of this non-empty collection with the given [transform] function to a new mutable set, or returns [emptySet] if this * collection is empty. * - * [mapToSet] should be preferred over `collection.mapTo(mutableSetOf()) { ... }` when `collection` may be empty and the resulting set may - * be cached, because [mapToSet] saves memory by avoiding the creation of an empty mutable set. + * [mapToSetOrEmpty] should be preferred over `collection.mapTo(mutableSetOf()) { ... }` when `collection` may be empty and the resulting + * set may be cached, because [mapToSetOrEmpty] saves memory by avoiding the creation of an empty mutable set. */ -public inline fun Collection.mapToSet(transform: (T) -> R): Set = +public inline fun Collection.mapToSetOrEmpty(transform: (T) -> R): Set = if (isNotEmpty()) mapTo(mutableSetOf(), transform) else emptySet() + +public inline fun Collection.filterToSetOrEmpty(predicate: (T) -> Boolean): Set = + filterTo(mutableSetOf(), predicate).ifEmpty { emptySet() } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirProviderHelper.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirProviderHelper.kt index a354b53fc7e..f994fd5c5da 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirProviderHelper.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirProviderHelper.kt @@ -102,7 +102,7 @@ internal class LLFirProviderHelper( val symbolNameCache = FirCompositeCachedSymbolNamesProvider.create( firSession, listOfNotNull( - object : LLFirKotlinSymbolNamesProvider(declarationProvider) { + object : LLFirKotlinSymbolNamesProvider(declarationProvider, allowKotlinPackage) { // This is a temporary workaround for KTIJ-25536. override fun getPackageNamesWithTopLevelCallables(): Set? = null }, 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 84afb90a3db..f4ad20e4d1c 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 @@ -6,7 +6,9 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.util import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider -import org.jetbrains.kotlin.analysis.utils.collections.mapToSet +import org.jetbrains.kotlin.analysis.utils.collections.filterToSetOrEmpty +import org.jetbrains.kotlin.analysis.utils.collections.mapToSetOrEmpty +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolNamesProvider import org.jetbrains.kotlin.fir.resolve.providers.FirDelegatingCachedSymbolNamesProvider @@ -16,23 +18,42 @@ import org.jetbrains.kotlin.name.Name /** * A [FirSymbolNamesProvider] that fetches top-level names from a Kotlin [declarationProvider]. + * + * @param allowKotlinPackage Whether the associated symbol provider is allowed to provide symbols from the `kotlin` package. */ internal open class LLFirKotlinSymbolNamesProvider( private val declarationProvider: KotlinDeclarationProvider, + private val allowKotlinPackage: Boolean? = null, ) : FirSymbolNamesProvider() { - override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set = - declarationProvider + override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set { + if (allowKotlinPackage == false && packageFqName.isKotlinPackage()) return emptySet() + + return declarationProvider .getTopLevelKotlinClassLikeDeclarationNamesInPackage(packageFqName) - .mapToSet { it.asString() } + .mapToSetOrEmpty { it.asString() } + } - override fun getPackageNamesWithTopLevelCallables(): Set? = - declarationProvider.computePackageSetWithTopLevelCallableDeclarations() + override fun getPackageNamesWithTopLevelCallables(): Set? { + val packageNames = declarationProvider.computePackageSetWithTopLevelCallableDeclarations() - override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set = - declarationProvider.getTopLevelCallableNamesInPackage(packageFqName).ifEmpty { emptySet() } + if (allowKotlinPackage == false && packageNames.any { it.isKotlinPackage() }) { + return packageNames.filterToSetOrEmpty { !it.isKotlinPackage() } + } + + return packageNames + } + + override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set { + if (allowKotlinPackage == false && packageFqName.isKotlinPackage()) return emptySet() + + return declarationProvider.getTopLevelCallableNamesInPackage(packageFqName).ifEmpty { emptySet() } + } companion object { fun cached(session: FirSession, declarationProvider: KotlinDeclarationProvider): FirCachedSymbolNamesProvider = FirDelegatingCachedSymbolNamesProvider(session, LLFirKotlinSymbolNamesProvider(declarationProvider)) } } + +private fun FqName.isKotlinPackage(): Boolean = startsWith(StandardNames.BUILT_INS_PACKAGE_NAME) +private fun String.isKotlinPackage(): Boolean = startsWith(StandardNames.BUILT_INS_PACKAGE_NAME.asString())