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 e6c6851f5c1..54a7f45a624 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 @@ -12,6 +12,8 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.llFirMo import org.jetbrains.kotlin.analysis.project.structure.KtModule import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.java.JavaSymbolProvider +import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolNamesProvider +import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolNamesProviderWithoutCallables import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals import org.jetbrains.kotlin.fir.symbols.impl.* @@ -48,6 +50,11 @@ internal class LLFirCombinedJavaSymbolProvider private constructor( */ private val classCache: NullableCaffeineCache = NullableCaffeineCache { it.maximumSize(2500) } + override val symbolNamesProvider: FirSymbolNamesProvider = object : FirSymbolNamesProviderWithoutCallables() { + override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set? = null + override fun mayHaveTopLevelClassifier(classId: ClassId): Boolean = true + } + override fun getClassLikeSymbolByClassId(classId: ClassId): FirClassLikeSymbol<*>? = classCache.get(classId) { computeClassLikeSymbolByClassId(it) } @@ -82,10 +89,6 @@ internal class LLFirCombinedJavaSymbolProvider private constructor( override fun getPackage(fqName: FqName): FqName? = providers.firstNotNullOfOrNull { it.getPackage(fqName) } - override fun computePackageSetWithTopLevelCallables(): Set? = null - override fun knownTopLevelClassifiersInPackage(packageFqName: FqName): Set? = null - override fun computeCallableNamesInPackage(packageFqName: FqName): Set? = null - companion object { fun merge(session: FirSession, project: Project, providers: List): FirSymbolProvider? = if (providers.size > 1) { diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirCombinedKotlinSymbolProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirCombinedKotlinSymbolProvider.kt index 41ccbea9859..587738f58d9 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirCombinedKotlinSymbolProvider.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirCombinedKotlinSymbolProvider.kt @@ -10,14 +10,14 @@ import com.intellij.psi.search.GlobalSearchScope import org.jetbrains.kotlin.analysis.low.level.api.fir.caches.NullableCaffeineCache import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.llFirModuleData import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSession -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.LLFirSymbolProviderNameCacheBase import org.jetbrains.kotlin.analysis.project.structure.KtModule import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider import org.jetbrains.kotlin.analysis.providers.createDeclarationProvider import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.resolve.providers.FirCompositeCachedSymbolNamesProvider +import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolNamesProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals -import org.jetbrains.kotlin.fir.resolve.providers.flatMapToNullableSet import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol @@ -47,21 +47,12 @@ internal class LLFirCombinedKotlinSymbolProvider private constructor( providers: List, private val declarationProvider: KotlinDeclarationProvider, ) : LLFirSelectingCombinedSymbolProvider(session, project, providers) { - private val symbolNameCache = object : LLFirSymbolProviderNameCacheBase(session) { - override fun computeClassifierNames(packageFqName: FqName): Set? = - providers.flatMapToNullableSet { it.knownTopLevelClassifiersInPackage(packageFqName) } - - override fun computeCallableNames(packageFqName: FqName): Set? = - providers.flatMapToNullableSet { it.computeCallableNamesInPackage(packageFqName) } - - override fun computePackageNamesWithTopLevelCallables(): Set? = - providers.flatMapToNullableSet { it.computePackageSetWithTopLevelCallables() } - } + override val symbolNamesProvider: FirSymbolNamesProvider = FirCompositeCachedSymbolNamesProvider.fromSymbolProviders(session, providers) private val classifierCache = NullableCaffeineCache> { it.maximumSize(500) } override fun getClassLikeSymbolByClassId(classId: ClassId): FirClassLikeSymbol<*>? { - if (!symbolNameCache.mayHaveTopLevelClassifier(classId, mayHaveFunctionClass = false)) return null + if (!symbolNamesProvider.mayHaveTopLevelClassifier(classId)) return null return classifierCache.get(classId) { computeClassLikeSymbolByClassId(it) } } @@ -107,7 +98,7 @@ internal class LLFirCombinedKotlinSymbolProvider private constructor( getCallables: (CallableId) -> Collection, provide: LLFirKotlinSymbolProvider.(CallableId, Collection) -> Unit, ) { - if (!symbolNameCache.mayHaveTopLevelCallable(packageFqName, name)) return + if (!symbolNamesProvider.mayHaveTopLevelCallable(packageFqName, name)) return val callableId = CallableId(packageFqName, name) @@ -124,14 +115,6 @@ internal class LLFirCombinedKotlinSymbolProvider private constructor( override fun getPackage(fqName: FqName): FqName? = providers.firstNotNullOfOrNull { it.getPackage(fqName) } - override fun computePackageSetWithTopLevelCallables(): Set? = null - - override fun knownTopLevelClassifiersInPackage(packageFqName: FqName): Set? = - symbolNameCache.getTopLevelClassifierNamesInPackage(packageFqName) - - override fun computeCallableNamesInPackage(packageFqName: FqName): Set? = - symbolNameCache.getTopLevelCallableNamesInPackage(packageFqName) - companion object { fun merge(session: LLFirSession, project: Project, providers: List): FirSymbolProvider? = if (providers.size > 1) { 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 c20e83d154c..bc04e4bfe67 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 @@ -6,6 +6,8 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.providers import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.resolve.providers.FirCompositeSymbolNamesProvider +import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolNamesProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals import org.jetbrains.kotlin.fir.resolve.providers.impl.FirSyntheticFunctionInterfaceProviderBase @@ -29,11 +31,20 @@ internal class LLFirCombinedSyntheticFunctionSymbolProvider private constructor( ) : FirSymbolProvider(session) { private val combinedPackageNames: Set = providers.flatMapTo(mutableSetOf()) { it.getFunctionKindPackageNames() } + override val symbolNamesProvider: FirSymbolNamesProvider = + // `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 getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set = emptySet() + override fun getPackageNamesWithTopLevelCallables(): Set = emptySet() + override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set = emptySet() + } + override fun getClassLikeSymbolByClassId(classId: ClassId): FirClassLikeSymbol<*>? { if (!classId.mayBeSyntheticFunctionClassName()) return null if (classId.packageFqName !in combinedPackageNames) return null - return providers.firstNotNullOfOrNull { it.getClassLikeSymbolByClassIdWithoutClassIdChecks(classId) } + return providers.firstNotNullOfOrNull { it.getClassLikeSymbolByClassId(classId) } } @FirSymbolProviderInternals @@ -50,10 +61,6 @@ internal class LLFirCombinedSyntheticFunctionSymbolProvider private constructor( override fun getPackage(fqName: FqName): FqName? = fqName.takeIf { it in combinedPackageNames } - override fun computePackageSetWithTopLevelCallables(): Set? = null - override fun knownTopLevelClassifiersInPackage(packageFqName: FqName): Set? = null - override fun computeCallableNamesInPackage(packageFqName: FqName): Set? = null - companion object { fun merge(session: FirSession, providers: List): FirSymbolProvider? = if (providers.size > 1) LLFirCombinedSyntheticFunctionSymbolProvider(session, providers) diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirKotlinSymbolProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirKotlinSymbolProvider.kt index 6e9d56b7264..a1564bbb51c 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirKotlinSymbolProvider.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirKotlinSymbolProvider.kt @@ -5,7 +5,6 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.providers -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.LLFirSymbolProviderNameCache import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider @@ -16,8 +15,6 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.name.ClassId -import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtCallableDeclaration import org.jetbrains.kotlin.psi.KtClassLikeDeclaration import org.jetbrains.kotlin.psi.KtNamedFunction @@ -65,15 +62,3 @@ internal abstract class LLFirKotlinSymbolProvider(session: FirSession) : FirSymb properties: Collection, ) } - -internal abstract class LLFirKotlinSymbolProviderWithNameCache(session: FirSession) : LLFirKotlinSymbolProvider(session) { - protected abstract val symbolNameCache: LLFirSymbolProviderNameCache - - final override fun knownTopLevelClassifiersInPackage(packageFqName: FqName): Set? = - symbolNameCache.getTopLevelClassifierNamesInPackage(packageFqName) - - final override fun computeCallableNamesInPackage(packageFqName: FqName): Set? = - symbolNameCache.getTopLevelCallableNamesInPackage(packageFqName) - - final override fun computePackageSetWithTopLevelCallables(): Set? = symbolNameCache.getPackageNamesWithTopLevelCallables() -} diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirModuleWithDependenciesSymbolProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirModuleWithDependenciesSymbolProvider.kt index 61a494cb8ac..32d307e8144 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirModuleWithDependenciesSymbolProvider.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirModuleWithDependenciesSymbolProvider.kt @@ -8,6 +8,8 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.providers import org.jetbrains.kotlin.analysis.low.level.api.fir.stubBased.deserialization.JvmStubBasedFirDeserializedSymbolProvider import org.jetbrains.kotlin.analysis.utils.collections.buildSmartList import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.resolve.providers.FirNullSymbolNamesProvider +import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolNamesProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol @@ -29,6 +31,8 @@ internal class LLFirModuleWithDependenciesSymbolProvider( val providers: List, val dependencyProvider: LLFirDependenciesSymbolProvider, ) : FirSymbolProvider(session) { + override val symbolNamesProvider: FirSymbolNamesProvider = FirNullSymbolNamesProvider + override fun getClassLikeSymbolByClassId(classId: ClassId): FirClassLikeSymbol<*>? = getClassLikeSymbolByClassIdWithoutDependencies(classId) ?: dependencyProvider.getClassLikeSymbolByClassId(classId) @@ -96,10 +100,6 @@ internal class LLFirModuleWithDependenciesSymbolProvider( fun getPackageWithoutDependencies(fqName: FqName): FqName? = providers.firstNotNullOfOrNull { it.getPackage(fqName) } - - override fun computePackageSetWithTopLevelCallables(): Set? = null - override fun knownTopLevelClassifiersInPackage(packageFqName: FqName): Set? = null - override fun computeCallableNamesInPackage(packageFqName: FqName): Set? = null } internal class LLFirDependenciesSymbolProvider( @@ -113,6 +113,8 @@ internal class LLFirDependenciesSymbolProvider( } } + override val symbolNamesProvider: FirSymbolNamesProvider = FirNullSymbolNamesProvider + override fun getClassLikeSymbolByClassId(classId: ClassId): FirClassLikeSymbol<*>? = providers.firstNotNullOfOrNull { it.getClassLikeSymbolByClassId(classId) } @@ -151,10 +153,6 @@ internal class LLFirDependenciesSymbolProvider( override fun getPackage(fqName: FqName): FqName? = providers.firstNotNullOfOrNull { it.getPackage(fqName) } - override fun computePackageSetWithTopLevelCallables(): Set? = null - override fun knownTopLevelClassifiersInPackage(packageFqName: FqName): Set? = null - override fun computeCallableNamesInPackage(packageFqName: FqName): Set? = null - private fun > addNewSymbolsConsideringJvmFacades( destination: MutableList, newSymbols: List, diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirProvider.kt index 36e0c75373b..db3c8950aca 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirProvider.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirProvider.kt @@ -7,7 +7,6 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.providers import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirModuleResolveComponents import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.SyntheticFirClassProvider -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.LLFirSymbolProviderNameCache import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider import org.jetbrains.kotlin.analysis.providers.KotlinPackageProvider import org.jetbrains.kotlin.fir.FirSession @@ -17,10 +16,7 @@ import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty import org.jetbrains.kotlin.fir.originalForSubstitutionOverride -import org.jetbrains.kotlin.fir.resolve.providers.FirProvider -import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider -import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals -import org.jetbrains.kotlin.fir.resolve.providers.firProvider +import org.jetbrains.kotlin.fir.resolve.providers.* import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.name.ClassId @@ -112,12 +108,11 @@ internal class LLFirProvider( declarationProvider.getTopLevelKotlinClassLikeDeclarationNamesInPackage(fqName) @NoMutableState - internal inner class SymbolProvider : LLFirKotlinSymbolProviderWithNameCache(session) { - override val symbolNameCache: LLFirSymbolProviderNameCache - get() = providerHelper.symbolNameCache + internal inner class SymbolProvider : LLFirKotlinSymbolProvider(session) { + override val symbolNamesProvider: FirSymbolNamesProvider get() = providerHelper.symbolNameCache override fun getClassLikeSymbolByClassId(classId: ClassId): FirClassLikeSymbol<*>? { - if (!providerHelper.symbolNameCache.mayHaveTopLevelClassifier(classId, mayHaveFunctionClass = false)) return null + if (!providerHelper.symbolNameCache.mayHaveTopLevelClassifier(classId)) return null return getFirClassifierByFqName(classId)?.symbol } 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 63d6990a518..5ecdbf63421 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 @@ -10,8 +10,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.Composi import org.jetbrains.kotlin.analysis.low.level.api.fir.resolve.extensions.LLFirResolveExtensionTool import org.jetbrains.kotlin.analysis.low.level.api.fir.resolve.extensions.llResolveExtensionTool import org.jetbrains.kotlin.analysis.low.level.api.fir.util.FirElementFinder -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.LLFirCompositeSymbolProviderNameCache -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.LLFirKotlinSymbolProviderNameCache +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.LLFirKotlinSymbolNamesProvider import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider import org.jetbrains.kotlin.analysis.providers.KotlinPackageProvider import org.jetbrains.kotlin.analysis.providers.impl.CompositeKotlinDeclarationProvider @@ -24,6 +23,7 @@ import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.languageVersionSettings +import org.jetbrains.kotlin.fir.resolve.providers.FirCompositeCachedSymbolNamesProvider import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol @@ -80,10 +80,11 @@ internal class LLFirProviderHelper( } } - val symbolNameCache = LLFirCompositeSymbolProviderNameCache.create( + val symbolNameCache = FirCompositeCachedSymbolNamesProvider.create( + firSession, listOfNotNull( - LLFirKotlinSymbolProviderNameCache(firSession, declarationProvider), - extensionTool?.symbolNameCache, + LLFirKotlinSymbolNamesProvider(declarationProvider), + extensionTool?.symbolNamesProvider, ) ) 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 6a3386717c9..a622038786a 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 @@ -14,7 +14,6 @@ import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionFi import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionProvider import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionReferencePsiTargetsProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSession -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.LLFirSymbolProviderNameCache import org.jetbrains.kotlin.analysis.project.structure.KtModule import org.jetbrains.kotlin.analysis.project.structure.KtModuleStructureInternals import org.jetbrains.kotlin.analysis.project.structure.analysisExtensionFileContextModule @@ -23,6 +22,7 @@ import org.jetbrains.kotlin.analysis.providers.KotlinPackageProvider import org.jetbrains.kotlin.analysis.providers.impl.FileBasedKotlinDeclarationProvider import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSessionComponent +import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolNamesProvider import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils import org.jetbrains.kotlin.name.* import org.jetbrains.kotlin.platform.TargetPlatform @@ -32,14 +32,15 @@ import java.util.concurrent.ConcurrentHashMap /** * Encapsulate all the work with the [KtResolveExtension] for the LL API. * - * Caches generated [KtResolveExtensionFile]s, creates [KotlinDeclarationProvider], [KotlinPackageProvider], [LLFirSymbolProviderNameCache] needed for the [org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider]. + * Caches generated [KtResolveExtensionFile]s, creates [KotlinDeclarationProvider], [KotlinPackageProvider], [FirSymbolNamesProvider] needed + * for the [org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider]. */ abstract class LLFirResolveExtensionTool : FirSessionComponent { abstract val modificationTrackers: List abstract val declarationProvider: LLFirResolveExtensionToolDeclarationProvider abstract val packageProvider: KotlinPackageProvider abstract val packageFilter: LLFirResolveExtensionToolPackageFilter - internal abstract val symbolNameCache: LLFirSymbolProviderNameCache + internal abstract val symbolNamesProvider: FirSymbolNamesProvider } val FirSession.llResolveExtensionTool: LLFirResolveExtensionTool? by FirSession.nullableSessionComponentAccessor() @@ -63,13 +64,13 @@ internal class LLFirNonEmptyResolveExtensionTool( override val packageProvider: KotlinPackageProvider = LLFirResolveExtensionToolPackageProvider(packageFilter) - override val symbolNameCache: LLFirSymbolProviderNameCache = LLFirResolveExtensionToolNameCache(packageFilter, fileProvider) + override val symbolNamesProvider: FirSymbolNamesProvider = LLFirResolveExtensionToolSymbolNamesProvider(packageFilter, fileProvider) } -private class LLFirResolveExtensionToolNameCache( +private class LLFirResolveExtensionToolSymbolNamesProvider( private val packageFilter: LLFirResolveExtensionToolPackageFilter, private val fileProvider: LLFirResolveExtensionsFileProvider, -) : LLFirSymbolProviderNameCache() { +) : FirSymbolNamesProvider() { override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set = forbidAnalysis { if (!packageFilter.packageExists(packageFqName)) return emptySet() fileProvider.getFilesByPackage(packageFqName) @@ -87,7 +88,7 @@ private class LLFirResolveExtensionToolNameCache( .flatMapTo(mutableSetOf()) { it.getTopLevelCallableNames() } } - override fun mayHaveTopLevelClassifier(classId: ClassId, mayHaveFunctionClass: Boolean): Boolean = forbidAnalysis { + override fun mayHaveTopLevelClassifier(classId: ClassId): Boolean = forbidAnalysis { if (!packageFilter.packageExists(classId.packageFqName)) return false fileProvider.getFilesByPackage(classId.packageFqName) diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/JvmStubBasedFirDeserializedSymbolProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/JvmStubBasedFirDeserializedSymbolProvider.kt index 7d7b0b44193..23253d57192 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/JvmStubBasedFirDeserializedSymbolProvider.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/stubBased/deserialization/JvmStubBasedFirDeserializedSymbolProvider.kt @@ -5,10 +5,10 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.stubBased.deserialization +import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLFirKotlinSymbolProvider +import org.jetbrains.kotlin.analysis.low.level.api.fir.util.LLFirKotlinSymbolNamesProvider import com.intellij.openapi.project.Project import com.intellij.psi.search.GlobalSearchScope -import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLFirKotlinSymbolProviderWithNameCache -import org.jetbrains.kotlin.analysis.low.level.api.fir.util.LLFirKotlinSymbolProviderNameCache import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider import org.jetbrains.kotlin.analysis.providers.createDeclarationProvider import org.jetbrains.kotlin.fir.FirSession @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin import org.jetbrains.kotlin.fir.deserialization.SingleModuleDataProvider import org.jetbrains.kotlin.fir.java.deserialization.JvmClassFileBasedSymbolProvider import org.jetbrains.kotlin.fir.java.deserialization.KotlinBuiltins +import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolNamesProvider import org.jetbrains.kotlin.fir.realPsi import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider @@ -50,11 +51,11 @@ internal open class JvmStubBasedFirDeserializedSymbolProvider( project: Project, scope: GlobalSearchScope, private val initialOrigin: FirDeclarationOrigin -) : LLFirKotlinSymbolProviderWithNameCache(session) { +) : LLFirKotlinSymbolProvider(session) { private val declarationProvider by lazy(LazyThreadSafetyMode.PUBLICATION) { project.createDeclarationProvider(scope, module = null) } private val moduleData = moduleDataProvider.getModuleData(null) - override val symbolNameCache: LLFirKotlinSymbolProviderNameCache = LLFirKotlinSymbolProviderNameCache(session, declarationProvider) + override val symbolNamesProvider: FirSymbolNamesProvider = LLFirKotlinSymbolNamesProvider.cached(session, declarationProvider) private val typeAliasCache: FirCache = session.firCachesFactory.createCacheWithPostCompute( @@ -192,7 +193,7 @@ internal open class JvmStubBasedFirDeserializedSymbolProvider( private fun , CONTEXT> FirCache, CONTEXT?>.getCallablesWithoutContext( id: CallableId, ): List { - if (!symbolNameCache.mayHaveTopLevelCallable(id.packageName, id.callableName)) return emptyList() + if (!symbolNamesProvider.mayHaveTopLevelCallable(id.packageName, id.callableName)) return emptyList() return getValue(id, null) } @@ -241,12 +242,12 @@ internal open class JvmStubBasedFirDeserializedSymbolProvider( override fun getPackage(fqName: FqName): FqName? = fqName.takeIf { - symbolNameCache.getTopLevelClassifierNamesInPackage(fqName)?.isNotEmpty() == true || - symbolNameCache.getPackageNamesWithTopLevelCallables()?.contains(fqName.asString()) == true + symbolNamesProvider.getTopLevelClassifierNamesInPackage(fqName)?.isNotEmpty() == true || + symbolNamesProvider.getPackageNamesWithTopLevelCallables()?.contains(fqName.asString()) == true } override fun getClassLikeSymbolByClassId(classId: ClassId): FirClassLikeSymbol<*>? { - if (!symbolNameCache.mayHaveTopLevelClassifier(classId, mayHaveFunctionClass = false)) return null + if (!symbolNamesProvider.mayHaveTopLevelClassifier(classId)) return null return getClass(classId) ?: getTypeAlias(classId) } 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 new file mode 100644 index 00000000000..753f53e8794 --- /dev/null +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/LLFirKotlinSymbolNamesProvider.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.analysis.low.level.api.fir.util + +import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolNamesProvider +import org.jetbrains.kotlin.fir.resolve.providers.FirDelegatingCachedSymbolNamesProvider +import org.jetbrains.kotlin.fir.resolve.providers.FirCachedSymbolNamesProvider +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name + +/** + * A [FirSymbolNamesProvider] that fetches top-level names from a Kotlin [declarationProvider]. + */ +internal class LLFirKotlinSymbolNamesProvider( + private val declarationProvider: KotlinDeclarationProvider, +) : FirSymbolNamesProvider() { + override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set = + declarationProvider + .getTopLevelKotlinClassLikeDeclarationNamesInPackage(packageFqName) + .mapTo(mutableSetOf()) { it.asString() } + + override fun getPackageNamesWithTopLevelCallables(): Set = + declarationProvider.computePackageSetWithTopLevelCallableDeclarations() + + override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set = + declarationProvider.getTopLevelCallableNamesInPackage(packageFqName) + + companion object { + fun cached(session: FirSession, declarationProvider: KotlinDeclarationProvider): FirCachedSymbolNamesProvider = + FirDelegatingCachedSymbolNamesProvider(session, LLFirKotlinSymbolNamesProvider(declarationProvider)) + } +} diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/LLFirKotlinSymbolProviderNameCache.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/LLFirKotlinSymbolProviderNameCache.kt deleted file mode 100644 index 85f98aba65a..00000000000 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/LLFirKotlinSymbolProviderNameCache.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.analysis.low.level.api.fir.util - -import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider -import org.jetbrains.kotlin.fir.FirSession -import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.name.Name - -/** - * An [LLFirSymbolProviderNameCache] that fetches top-level names from a Kotlin [declarationProvider]. - */ -internal class LLFirKotlinSymbolProviderNameCache( - firSession: FirSession, - private val declarationProvider: KotlinDeclarationProvider, -) : LLFirSymbolProviderNameCacheBase(firSession) { - override fun computeClassifierNames(packageFqName: FqName): Set = - declarationProvider - .getTopLevelKotlinClassLikeDeclarationNamesInPackage(packageFqName) - .mapTo(mutableSetOf()) { it.asString() } - - override fun computePackageNamesWithTopLevelCallables(): Set = - declarationProvider.computePackageSetWithTopLevelCallableDeclarations() - - override fun computeCallableNames(packageFqName: FqName): Set = - declarationProvider.getTopLevelCallableNamesInPackage(packageFqName) -} diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/LLFirSymbolProviderNameCache.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/LLFirSymbolProviderNameCache.kt deleted file mode 100644 index c03afca9871..00000000000 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/LLFirSymbolProviderNameCache.kt +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.analysis.low.level.api.fir.util - -import org.jetbrains.kotlin.fir.FirSession -import org.jetbrains.kotlin.fir.caches.createCache -import org.jetbrains.kotlin.fir.caches.firCachesFactory -import org.jetbrains.kotlin.fir.caches.getValue -import org.jetbrains.kotlin.fir.resolve.providers.flatMapToNullableSet -import org.jetbrains.kotlin.fir.resolve.providers.mayHaveTopLevelClassifier -import org.jetbrains.kotlin.name.ClassId -import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.name.Name - -/** - * Caches the names of classifiers and callables contained in a package. [LLFirSymbolProviderNameCache] is used by symbol providers to abort - * symbol finding early if the symbol name isn't contained in the symbol provider's domain. - * - * For [getTopLevelClassifierNamesInPackage], [getTopLevelCallableNamesInPackage], and [getPackageNamesWithTopLevelCallables], the result - * may have false-positive entries but cannot have false-negative entries. - * It should contain all the names in the package/all package names but may have some additional names that are not there. - * Also, `null` might be returned when it's too expensive to calculate the sets. - * - * For [mayHaveTopLevelClassifier] and [mayHaveTopLevelCallable], the result may be a false-positive result but cannot be a false-negative. - */ -internal abstract class LLFirSymbolProviderNameCache { - /** - * Returns the set of top-level classifier names (classes, interfaces, objects, and type aliases) inside the [packageFqName] package - * within the cache's scope. - * - * @see LLFirSymbolProviderNameCache - */ - abstract fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set? - - /** - * Returns the set of package names which contain a top-level callable declaration within the cache's scope. - * - * @see LLFirSymbolProviderNameCache - */ - abstract fun getPackageNamesWithTopLevelCallables(): Set? - - /** - * Returns the set of top-level callable names (functions and properties) inside the [packageFqName] package within the cache's scope. - * - * @see LLFirSymbolProviderNameCache - */ - abstract fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set? - - /** - * Checks if the cache's scope may contain a top-level classifier (class, interface, object, or type alias) with the given [classId]. - * - * @see LLFirSymbolProviderNameCache - */ - abstract fun mayHaveTopLevelClassifier(classId: ClassId, mayHaveFunctionClass: Boolean): Boolean - - /** - * Checks if the cache's scope may contain a top-level callable (function or property) called [name] inside the [packageFqName] package. - * - * @see LLFirSymbolProviderNameCache - */ - abstract fun mayHaveTopLevelCallable(packageFqName: FqName, name: Name): Boolean -} - -internal abstract class LLFirSymbolProviderNameCacheBase( - private val firSession: FirSession -) : LLFirSymbolProviderNameCache() { - abstract fun computeClassifierNames(packageFqName: FqName): Set? - abstract fun computePackageNamesWithTopLevelCallables(): Set? - abstract fun computeCallableNames(packageFqName: FqName): Set? - - private val topLevelClassifierNamesByPackage = - firSession.firCachesFactory.createCache(::computeClassifierNames) - - private val topLevelCallablePackageNames by lazy(LazyThreadSafetyMode.PUBLICATION) { - computePackageNamesWithTopLevelCallables() - } - - private val topLevelCallableNamesByPackage = - firSession.firCachesFactory.createCache(::computeCallableNames) - - final override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set? = - topLevelClassifierNamesByPackage.getValue(packageFqName) - - final override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set? { - val packageNames = getPackageNamesWithTopLevelCallables() - if (packageNames != null && packageFqName.asString() !in packageNames) return null - - return topLevelCallableNamesByPackage.getValue(packageFqName) - } - - final override fun getPackageNamesWithTopLevelCallables(): Set? = topLevelCallablePackageNames - - final override fun mayHaveTopLevelClassifier(classId: ClassId, mayHaveFunctionClass: Boolean): Boolean { - val names = getTopLevelClassifierNamesInPackage(classId.packageFqName) ?: return true - return names.mayHaveTopLevelClassifier(classId, firSession, mayHaveFunctionClass) - } - - override fun mayHaveTopLevelCallable(packageFqName: FqName, name: Name): Boolean { - if (name.isSpecial) return true - val names = getTopLevelCallableNamesInPackage(packageFqName) ?: return true - return name in names - } -} - -internal object LLFirEmptySymbolProviderNameCache : LLFirSymbolProviderNameCache() { - override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set = emptySet() - override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set = emptySet() - override fun getPackageNamesWithTopLevelCallables(): Set = emptySet() - override fun mayHaveTopLevelClassifier(classId: ClassId, mayHaveFunctionClass: Boolean): Boolean = false - override fun mayHaveTopLevelCallable(packageFqName: FqName, name: Name): Boolean = false -} - -internal class LLFirCompositeSymbolProviderNameCache -private constructor( - private val caches: List -) : LLFirSymbolProviderNameCache() { - override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set? { - return caches.flatMapToNullableSet { it.getTopLevelClassifierNamesInPackage(packageFqName) } - } - - override fun getPackageNamesWithTopLevelCallables(): Set? { - return caches.flatMapToNullableSet { it.getPackageNamesWithTopLevelCallables() } - } - - override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set? { - return caches.flatMapToNullableSet { it.getTopLevelCallableNamesInPackage(packageFqName) } - } - - override fun mayHaveTopLevelClassifier(classId: ClassId, mayHaveFunctionClass: Boolean): Boolean { - return caches.any { it.mayHaveTopLevelClassifier(classId, mayHaveFunctionClass) } - } - - override fun mayHaveTopLevelCallable(packageFqName: FqName, name: Name): Boolean { - return caches.any { it.mayHaveTopLevelCallable(packageFqName, name) } - } - - companion object { - fun create(caches: List): LLFirSymbolProviderNameCache { - return when (caches.size) { - 0 -> LLFirEmptySymbolProviderNameCache - 1 -> caches.single() - else -> LLFirCompositeSymbolProviderNameCache(caches) - } - } - } -} 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 18f59eb1b47..ee984e25508 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 @@ -18,6 +18,8 @@ import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.declarations.builder.buildRegularClass import org.jetbrains.kotlin.fir.declarations.getDeprecationsProvider import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl +import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolNamesProvider +import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolNamesProviderWithoutCallables import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider @@ -137,11 +139,8 @@ class NativeForwardDeclarationsSymbolProvider( return null } - override fun knownTopLevelClassifiersInPackage(packageFqName: FqName): Set { - return includedForwardDeclarationsByPackage[packageFqName].orEmpty() + override val symbolNamesProvider: FirSymbolNamesProvider = object : FirSymbolNamesProviderWithoutCallables() { + override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set = + includedForwardDeclarationsByPackage[packageFqName].orEmpty() } - - override fun computePackageSetWithTopLevelCallables(): Set = emptySet() - - override fun computeCallableNamesInPackage(packageFqName: FqName): Set = emptySet() -} \ No newline at end of file +} 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 f1aae62e290..284c382925d 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 @@ -13,8 +13,10 @@ import org.jetbrains.kotlin.fir.caches.firCachesFactory import org.jetbrains.kotlin.fir.caches.getValue import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin import org.jetbrains.kotlin.fir.isNewPlaceForBodyGeneration +import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolNamesProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals +import org.jetbrains.kotlin.fir.resolve.providers.FirCachedSymbolNamesProvider import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.metadata.ProtoBuf @@ -83,23 +85,46 @@ abstract class AbstractFirDeserializedSymbolProvider( ) : FirSymbolProvider(session) { // ------------------------ Caches ------------------------ + /** + * [packageNamesForNonClassDeclarations] might contain names of packages containing type aliases, on top of packages containing + * callables, so it's not the same as `symbolNamesProvider.getPackageNamesWithTopLevelCallables` and cannot be replaced by it. + */ private val packageNamesForNonClassDeclarations: Set by lazy(LazyThreadSafetyMode.PUBLICATION) { computePackageSetWithNonClassDeclarations() } + override val symbolNamesProvider: FirSymbolNamesProvider = object : FirCachedSymbolNamesProvider(session) { + override fun computeTopLevelClassifierNames(packageFqName: FqName): Set? { + val classesInPackage = knownTopLevelClassesInPackage(packageFqName) ?: return null + + if (packageFqName.asString() !in packageNamesForNonClassDeclarations) return classesInPackage + + val typeAliasNames = typeAliasesNamesByPackage.getValue(packageFqName) + if (typeAliasNames.isEmpty()) return classesInPackage + + return buildSet { + addAll(classesInPackage) + typeAliasNames.mapTo(this) { it.asString() } + } + } + + override fun getPackageNamesWithTopLevelCallables(): Set = packageNamesForNonClassDeclarations + + override fun computePackageNamesWithTopLevelCallables(): Set = packageNamesForNonClassDeclarations + + override fun computeTopLevelCallableNames(packageFqName: FqName): Set = + getPackageParts(packageFqName).flatMapTo(mutableSetOf()) { + it.topLevelFunctionNameIndex.keys + it.topLevelPropertyNameIndex.keys + } + } + private val typeAliasesNamesByPackage: FirCache, Nothing?> = session.firCachesFactory.createCache { fqName: FqName -> getPackageParts(fqName).flatMapTo(mutableSetOf()) { it.typeAliasNameIndex.keys } } - private val allNamesByPackage: FirCache, Nothing?> = - session.firCachesFactory.createCache { fqName: FqName -> - getPackageParts(fqName).flatMapTo(mutableSetOf()) { - it.topLevelFunctionNameIndex.keys + it.topLevelPropertyNameIndex.keys - } - } - private val packagePartsCache = session.firCachesFactory.createCache(::tryComputePackagePartInfos) + private val typeAliasCache: FirCache = session.firCachesFactory.createCacheWithPostCompute( createValue = { classId, _ -> findAndDeserializeTypeAlias(classId) }, @@ -109,6 +134,7 @@ abstract class AbstractFirDeserializedSymbolProvider( } } ) + private val classCache: FirCache = session.firCachesFactory.createCacheWithPostCompute( createValue = { classId, context -> findAndDeserializeClass(classId, context) }, @@ -132,24 +158,6 @@ abstract class AbstractFirDeserializedSymbolProvider( // This method should only be used for sake of optimization to avoid having too many empty-list/null values in our caches protected abstract fun computePackageSetWithNonClassDeclarations(): Set - override fun computePackageSetWithTopLevelCallables(): Set = computePackageSetWithNonClassDeclarations() - - override fun computeCallableNamesInPackage(packageFqName: FqName): Set = allNamesByPackage.getValue(packageFqName) - - override fun knownTopLevelClassifiersInPackage(packageFqName: FqName): Set? { - val classesInPackage = knownTopLevelClassesInPackage(packageFqName) ?: return null - - if (packageFqName.asString() !in packageNamesForNonClassDeclarations) return classesInPackage - - val typeAliasNames = typeAliasesNamesByPackage.getValue(packageFqName) - if (typeAliasNames.isEmpty()) return classesInPackage - - return buildSet { - addAll(classesInPackage) - typeAliasNames.mapTo(this) { it.asString() } - } - } - protected abstract fun knownTopLevelClassesInPackage(packageFqName: FqName): Set? protected abstract fun extractClassMetadata( @@ -253,8 +261,8 @@ abstract class AbstractFirDeserializedSymbolProvider( val parentClassId = classId.outerClassId // Actually, the second "if" should be enough but the first one might work faster - if (parentClassId == null && !mayHaveTopLevelClass(classId)) return null - if (parentClassId != null && !mayHaveTopLevelClass(classId.outermostClassId)) return null + if (parentClassId == null && !symbolNamesProvider.mayHaveTopLevelClassifier(classId)) return null + if (parentClassId != null && !symbolNamesProvider.mayHaveTopLevelClassifier(classId.outermostClassId)) return null if (parentContext == null && parentClassId != null) { val alreadyLoaded = classCache.getValueIfComputed(classId) @@ -266,11 +274,6 @@ abstract class AbstractFirDeserializedSymbolProvider( return classCache.getValue(classId, parentContext) } - private fun mayHaveTopLevelClass(topLevelClassId: ClassId): Boolean { - val knownClassNames = knownTopLevelClassifiersInPackage(topLevelClassId.packageFqName) ?: return true - return topLevelClassId.shortClassName.asString() in knownClassNames - } - private fun getTypeAlias(classId: ClassId): FirTypeAliasSymbol? { if (!classId.relativeClassName.isOneSegmentFQN()) return null @@ -295,8 +298,7 @@ abstract class AbstractFirDeserializedSymbolProvider( private fun > FirCache, Nothing?>.getCallables(id: CallableId): List { // Don't actually query FirCache when we're sure there are no relevant value // It helps to decrease the size of a cache thus leading to better query time - if (id.packageName.asString() !in packageNamesForNonClassDeclarations) return emptyList() - if (id.callableName !in allNamesByPackage.getValue(id.packageName)) return emptyList() + if (!symbolNamesProvider.mayHaveTopLevelCallable(id.packageName, id.callableName)) return emptyList() return getValue(id) } 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 0733ad51a4a..9c4ba1ddec3 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 @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.fir.deserialization.FirBuiltinAnnotationDeserializer import org.jetbrains.kotlin.fir.deserialization.FirConstDeserializer import org.jetbrains.kotlin.fir.deserialization.FirDeserializationContext import org.jetbrains.kotlin.fir.deserialization.deserializeClassToSymbol +import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolNamesProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider @@ -71,18 +72,26 @@ open class FirBuiltinSymbolProvider( } ?: syntheticFunctionInterfaceProvider.getClassLikeSymbolByClassId(classId) } - override fun computePackageSetWithTopLevelCallables(): Set = - allPackageFragments.keys.mapTo(mutableSetOf()) { it.asString() } + override val symbolNamesProvider: FirSymbolNamesProvider = object : FirSymbolNamesProvider() { + override fun getPackageNamesWithTopLevelCallables(): Set = + allPackageFragments.keys.mapTo(mutableSetOf()) { it.asString() } - override fun knownTopLevelClassifiersInPackage(packageFqName: FqName): Set = - allPackageFragments[packageFqName]?.flatMapTo(mutableSetOf()) { fragment -> - fragment.classDataFinder.allClassIds.map { it.shortClassName.asString() } - }.orEmpty() + override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set = + allPackageFragments[packageFqName]?.flatMapTo(mutableSetOf()) { fragment -> + fragment.classDataFinder.allClassIds.map { it.shortClassName.asString() } + }.orEmpty() - override fun computeCallableNamesInPackage(packageFqName: FqName): Set = - allPackageFragments[packageFqName]?.flatMapTo(mutableSetOf()) { - it.getTopLevelCallableNames() - }.orEmpty() + override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set = + allPackageFragments[packageFqName]?.flatMapTo(mutableSetOf()) { + it.getTopLevelCallableNames() + }.orEmpty() + + // This symbol provider delegates to `FirBuiltinSyntheticFunctionInterfaceProvider`, so synthetic function types can be provided. + override val mayHaveSyntheticFunctionTypes: Boolean get() = true + + override fun mayHaveSyntheticFunctionType(classId: ClassId): Boolean = + syntheticFunctionInterfaceProvider.symbolNamesProvider.mayHaveSyntheticFunctionType(classId) + } @FirSymbolProviderInternals override fun getTopLevelCallableSymbolsTo(destination: MutableList>, packageFqName: FqName, name: Name) { 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 8f7a78362f4..58148c475b1 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 @@ -7,6 +7,8 @@ package org.jetbrains.kotlin.fir.java import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.caches.firCachesFactory +import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolNamesProvider +import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolNamesProviderWithoutCallables import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol @@ -68,9 +70,10 @@ class JavaSymbolProvider( override fun getPackage(fqName: FqName): FqName? = javaFacade.getPackage(fqName) - override fun computePackageSetWithTopLevelCallables(): Set = emptySet() - override fun knownTopLevelClassifiersInPackage(packageFqName: FqName): Set? = javaFacade.knownClassNamesInPackage(packageFqName) - override fun computeCallableNamesInPackage(packageFqName: FqName): Set = emptySet() + override val symbolNamesProvider: FirSymbolNamesProvider = object : FirSymbolNamesProviderWithoutCallables() { + override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set? = + javaFacade.knownClassNamesInPackage(packageFqName) + } } val FirSession.javaSymbolProvider: JavaSymbolProvider? by FirSession.nullableSessionComponentAccessor() 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 4995779f44d..dace95ae9b1 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 @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.fir.caches.* import org.jetbrains.kotlin.fir.declarations.validate import org.jetbrains.kotlin.fir.ownerGenerator import org.jetbrains.kotlin.fir.render +import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolNamesProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider @@ -146,6 +147,19 @@ class FirExtensionDeclarationsSymbolProvider private constructor( // ------------------------------------------ provider methods ------------------------------------------ + override val symbolNamesProvider: FirSymbolNamesProvider = object : FirSymbolNamesProvider() { + override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set = + classNamesInPackageCache.getValue()[packageFqName] ?: emptySet() + + override fun getPackageNamesWithTopLevelCallables(): Set = + extensions.flatMapTo(mutableSetOf()) { extension -> + extension.topLevelCallableIdsCache.getValue().map { it.packageName.asString() } + } + + override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set = + callableNamesInPackageCache.getValue()[packageFqName].orEmpty() + } + override fun getClassLikeSymbolByClassId(classId: ClassId): FirClassLikeSymbol<*>? { return classCache.getValue(classId) } @@ -170,15 +184,4 @@ class FirExtensionDeclarationsSymbolProvider private constructor( override fun getPackage(fqName: FqName): FqName? { return fqName.takeIf { packageCache.getValue(fqName, null) } } - - override fun computePackageSetWithTopLevelCallables(): Set = - extensions.flatMapTo(mutableSetOf()) { extension -> - extension.topLevelCallableIdsCache.getValue().map { it.packageName.asString() } - } - - override fun knownTopLevelClassifiersInPackage(packageFqName: FqName): Set = - classNamesInPackageCache.getValue()[packageFqName] ?: emptySet() - - override fun computeCallableNamesInPackage(packageFqName: FqName): Set = - callableNamesInPackageCache.getValue()[packageFqName].orEmpty() } 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 24dbcd4e4f1..1a9dc0e4ac2 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 @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.fir.extensions import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolNamesProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol @@ -33,6 +34,17 @@ class FirSwitchableExtensionDeclarationsSymbolProvider private constructor( private var disabled: Boolean = false + override val symbolNamesProvider: FirSymbolNamesProvider = object : FirSymbolNamesProvider() { + override fun getPackageNamesWithTopLevelCallables(): Set? = + if (disabled) null else delegate.symbolNamesProvider.getPackageNamesWithTopLevelCallables() + + override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set? = + if (disabled) null else delegate.symbolNamesProvider.getTopLevelClassifierNamesInPackage(packageFqName) + + override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set? = + if (disabled) null else delegate.symbolNamesProvider.getTopLevelCallableNamesInPackage(packageFqName) + } + override fun getClassLikeSymbolByClassId(classId: ClassId): FirClassLikeSymbol<*>? { if (disabled) return null return delegate.getClassLikeSymbolByClassId(classId) @@ -70,16 +82,6 @@ class FirSwitchableExtensionDeclarationsSymbolProvider private constructor( fun enable() { disabled = false } - - override fun computePackageSetWithTopLevelCallables(): Set? = - if (disabled) null else delegate.computePackageSetWithTopLevelCallables() - - override fun knownTopLevelClassifiersInPackage(packageFqName: FqName): Set? = - if (disabled) null else delegate.knownTopLevelClassifiersInPackage(packageFqName) - - override fun computeCallableNamesInPackage(packageFqName: FqName): Set? = - if (disabled) null else delegate.computeCallableNamesInPackage(packageFqName) - } val FirSession.generatedDeclarationsSymbolProvider: FirSwitchableExtensionDeclarationsSymbolProvider? by FirSession.nullableSessionComponentAccessor() 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 new file mode 100644 index 00000000000..c1d8c120f2e --- /dev/null +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/providers/FirCachedSymbolNamesProvider.kt @@ -0,0 +1,110 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.resolve.providers + +import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.caches.createCache +import org.jetbrains.kotlin.fir.caches.firCachesFactory +import org.jetbrains.kotlin.fir.caches.getValue +import org.jetbrains.kotlin.fir.resolve.providers.impl.FirSyntheticFunctionInterfaceProviderBase.Companion.mayBeSyntheticFunctionClassName +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name + +/** + * A [FirSymbolNamesProvider] that caches all name sets. + */ +abstract class FirCachedSymbolNamesProvider(protected val session: FirSession) : FirSymbolNamesProvider() { + abstract fun computeTopLevelClassifierNames(packageFqName: FqName): Set? + abstract fun computePackageNamesWithTopLevelCallables(): Set? + abstract fun computeTopLevelCallableNames(packageFqName: FqName): Set? + + private val topLevelClassifierNamesByPackage = + session.firCachesFactory.createCache(::computeTopLevelClassifierNames) + + private val topLevelCallablePackageNames by lazy(LazyThreadSafetyMode.PUBLICATION) { + computePackageNamesWithTopLevelCallables() + } + + private val topLevelCallableNamesByPackage = + session.firCachesFactory.createCache(::computeTopLevelCallableNames) + + override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set? = + topLevelClassifierNamesByPackage.getValue(packageFqName) + + override fun getPackageNamesWithTopLevelCallables(): Set? = topLevelCallablePackageNames + + override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set? { + val packageNames = getPackageNamesWithTopLevelCallables() + if (packageNames != null && packageFqName.asString() !in packageNames) return emptySet() + + return topLevelCallableNamesByPackage.getValue(packageFqName) + } +} + +class FirDelegatingCachedSymbolNamesProvider( + session: FirSession, + private val delegate: FirSymbolNamesProvider, +) : FirCachedSymbolNamesProvider(session) { + override fun computeTopLevelClassifierNames(packageFqName: FqName): Set? = + delegate.getTopLevelClassifierNamesInPackage(packageFqName) + + override fun computePackageNamesWithTopLevelCallables(): Set? = + delegate.getPackageNamesWithTopLevelCallables() + + override fun computeTopLevelCallableNames(packageFqName: FqName): Set? = + delegate.getTopLevelCallableNamesInPackage(packageFqName) + + override val mayHaveSyntheticFunctionTypes: Boolean + get() = delegate.mayHaveSyntheticFunctionTypes + + override fun mayHaveSyntheticFunctionType(classId: ClassId): Boolean = delegate.mayHaveSyntheticFunctionType(classId) +} + +open class FirCompositeCachedSymbolNamesProvider( + session: FirSession, + val providers: List, +) : FirCachedSymbolNamesProvider(session) { + override fun computeTopLevelClassifierNames(packageFqName: FqName): Set? = + providers.flatMapToNullableSet { it.getTopLevelClassifierNamesInPackage(packageFqName) } + + override fun computePackageNamesWithTopLevelCallables(): Set? = + providers.flatMapToNullableSet { it.getPackageNamesWithTopLevelCallables() } + + override fun computeTopLevelCallableNames(packageFqName: FqName): Set? = + providers.flatMapToNullableSet { it.getTopLevelCallableNamesInPackage(packageFqName) } + + override val mayHaveSyntheticFunctionTypes: Boolean = providers.any { it.mayHaveSyntheticFunctionTypes } + + @OptIn(FirSymbolProviderInternals::class) + override fun mayHaveSyntheticFunctionType(classId: ClassId): Boolean { + if (!classId.mayBeSyntheticFunctionClassName()) return false + + // We cannot use `session`'s function type service directly, because the sessions of `providers` aren't necessarily the same as + // `session`. So we might miss some other session's synthetic function type. + return providers.any { it.mayHaveSyntheticFunctionType(classId) } + } + + companion object { + fun create(session: FirSession, providers: List): FirSymbolNamesProvider = when (providers.size) { + 0 -> FirEmptySymbolNamesProvider + 1 -> when (val provider = providers.single()) { + is FirCachedSymbolNamesProvider -> provider + else -> FirDelegatingCachedSymbolNamesProvider(session, provider) + } + else -> FirCompositeCachedSymbolNamesProvider(session, providers) + } + + fun fromSymbolProviders(session: FirSession, providers: List): FirSymbolNamesProvider = + create(session, providers.map { it.symbolNamesProvider }) + } +} + +/** + * Works almost as regular flatMap, but returns a set and returns null if any lambda call returned null + */ +inline fun Iterable.flatMapToNullableSet(transform: (T) -> Iterable?): Set? = + flatMapTo(mutableSetOf()) { transform(it) ?: return null } 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 new file mode 100644 index 00000000000..e210f92d9f5 --- /dev/null +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/providers/FirSymbolNamesProvider.kt @@ -0,0 +1,160 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.resolve.providers + +import org.jetbrains.kotlin.builtins.functions.FunctionTypeKind +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name + +/** + * [FirSymbolNamesProvider] provides information about which symbols may be provided by a [FirSymbolProvider] given the symbol's name. This + * 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. + * - It is usually not cheap to compute such sets on each query, so their result should be cached properly (see [FirCachedSymbolNamesProvider]). + * [FirSymbolNamesProvider]s may choose not to cache name sets if they are only going to be used for the construction of composite symbol + * name caches (to avoid useless layered caches) and the `mayHaveTopLevel*` functions aren't expected to be used. + * + * The result of [mayHaveTopLevelClassifier] and [mayHaveTopLevelCallable] may be a false positive but cannot be a false negative. + */ +abstract class FirSymbolNamesProvider { + /** + * Returns the set of top-level classifier names (classes, interfaces, objects, and type aliases) inside the [packageFqName] package + * within the provider's scope. + * + * All usages must take into account that the result might not include `kotlin.FunctionN` (and others for which a [FunctionTypeKind] + * exists). + */ + abstract fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set? + + /** + * Returns the set of fully qualified package names which contain a top-level callable declaration within the provider's scope. + */ + abstract fun getPackageNamesWithTopLevelCallables(): Set? + + /** + * Returns the set of top-level callable names (functions and properties) inside the [packageFqName] package within the provider's + * scope. + * + * When implementing this function, [getPackageNamesWithTopLevelCallables] should be taken into account. Specifically, if a package name + * is not in the set of package names with top-level callables, [getTopLevelCallableNamesInPackage] must return an empty set or `null`. + */ + abstract fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set? + + /** + * Whether the [FirSymbolProvider] supported by this [FirSymbolNamesProvider] may contain generated function types (see + * [FunctionTypeKind]). Names of such function types cannot be included in [getTopLevelClassifierNamesInPackage], because they are + * generated on demand. + * + * [mayHaveSyntheticFunctionTypes] only needs to be overridden together with [mayHaveSyntheticFunctionType] if the supported + * [FirSymbolProvider] can provide generated function types. The value should be constant, which allows composite symbol providers to + * cache the result and achieve acceptable performance. + */ + open val mayHaveSyntheticFunctionTypes: Boolean = false + + /** + * Whether [classId] is considered a generated function type within the provider's scope and session. + */ + open fun mayHaveSyntheticFunctionType(classId: ClassId): Boolean = + error("`mayHaveSyntheticFunctionType` needs to be implemented when `mayHaveSyntheticFunctionTypes` is true.") + + /** + * Checks if the provider's scope may contain a top-level classifier (class, interface, object, or type alias) with the given [classId]. + */ + open fun mayHaveTopLevelClassifier(classId: ClassId): Boolean { + if (mayHaveSyntheticFunctionTypes && mayHaveSyntheticFunctionType(classId)) return true + + val names = getTopLevelClassifierNamesInPackage(classId.packageFqName) ?: return true + if (classId.outerClassId == null) { + if (!names.mayContainTopLevelClassifier(classId.shortClassName)) return false + } else { + if (!names.mayContainTopLevelClassifier(classId.outermostClassId.shortClassName)) return false + } + return true + } + + /** + * Checks if the provider's scope may contain a top-level callable (function or property) called [name] inside the [packageFqName] + * package. + */ + open fun mayHaveTopLevelCallable(packageFqName: FqName, name: Name): Boolean { + // 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`. + val names = getTopLevelCallableNamesInPackage(packageFqName) ?: return true + return name in names + } +} + +private fun Set.mayContainTopLevelClassifier(shortClassName: Name): Boolean { + // Symbol providers can potentially provide symbols for special names. Hence, special names have to be allowed. + return shortClassName.isSpecial || shortClassName.asString() in this +} + +/** + * A [FirSymbolNamesProvider] for symbol providers which can't provide any symbol name sets. + */ +object FirNullSymbolNamesProvider : FirSymbolNamesProvider() { + override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set? = null + 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 +} + +/** + * A [FirSymbolNamesProvider] for symbol providers which don't contain *any* symbols. + */ +object FirEmptySymbolNamesProvider : FirSymbolNamesProvider() { + override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set = emptySet() + 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 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 getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set? { + return providers.flatMapToNullableSet { it.getTopLevelClassifierNamesInPackage(packageFqName) } + } + + override fun getPackageNamesWithTopLevelCallables(): Set? { + return providers.flatMapToNullableSet { it.getPackageNamesWithTopLevelCallables() } + } + + override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set? { + return providers.flatMapToNullableSet { it.getTopLevelCallableNamesInPackage(packageFqName) } + } + + override val mayHaveSyntheticFunctionTypes: Boolean = providers.any { it.mayHaveSyntheticFunctionTypes } + + override fun mayHaveSyntheticFunctionType(classId: ClassId): Boolean = providers.any { it.mayHaveSyntheticFunctionType(classId) } + + companion object { + fun create(providers: List): FirSymbolNamesProvider = when (providers.size) { + 0 -> FirEmptySymbolNamesProvider + 1 -> providers.single() + else -> FirCompositeSymbolNamesProvider(providers) + } + + fun fromSymbolProviders(providers: List): FirSymbolNamesProvider { + return create(providers.map { it.symbolNamesProvider }) + } + } +} diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/providers/FirSymbolProvider.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/providers/FirSymbolProvider.kt index e52f44d522f..6fd55d100db 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/providers/FirSymbolProvider.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/providers/FirSymbolProvider.kt @@ -9,7 +9,6 @@ import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSessionComponent import org.jetbrains.kotlin.fir.resolve.fullyExpandedType import org.jetbrains.kotlin.fir.resolve.getSymbolByLookupTag -import org.jetbrains.kotlin.fir.resolve.providers.impl.FirSyntheticFunctionInterfaceProviderBase.Companion.mayBeSyntheticFunctionClassName import org.jetbrains.kotlin.fir.scopes.FirScope import org.jetbrains.kotlin.fir.scopes.getDeclaredConstructors import org.jetbrains.kotlin.fir.scopes.getFunctions @@ -17,7 +16,10 @@ import org.jetbrains.kotlin.fir.scopes.getProperties import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.* -import org.jetbrains.kotlin.fir.types.* +import org.jetbrains.kotlin.fir.types.ConeLookupTagBasedType +import org.jetbrains.kotlin.fir.types.ConeSimpleKotlinType +import org.jetbrains.kotlin.fir.types.FirTypeRef +import org.jetbrains.kotlin.fir.types.coneTypeSafe import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name @@ -26,6 +28,8 @@ import org.jetbrains.kotlin.name.Name annotation class FirSymbolProviderInternals abstract class FirSymbolProvider(val session: FirSession) : FirSessionComponent { + abstract val symbolNamesProvider: FirSymbolNamesProvider + abstract fun getClassLikeSymbolByClassId(classId: ClassId): FirClassLikeSymbol<*>? @OptIn(FirSymbolProviderInternals::class) @@ -53,37 +57,8 @@ abstract class FirSymbolProvider(val session: FirSession) : FirSessionComponent abstract fun getTopLevelPropertySymbolsTo(destination: MutableList, packageFqName: FqName, name: Name) abstract fun getPackage(fqName: FqName): FqName? // TODO: Replace to symbol sometime - - /** - * All the three "compute*" functions below have the following common contract: - * - They return null in case necessary name set is too hard/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 belong to the provider. - * - It might be non-cheap to compute them on each query, thus their result should be cached properly. - * - * @returns full package names that contain some top-level callables - */ - abstract fun computePackageSetWithTopLevelCallables(): Set? - - /** - * @returns top-level classifier names that belong to `packageFqName` or null if it's complicated to compute the set - * - * All usages must take into account that the result might not include kotlin.FunctionN - * (and others for which org.jetbrains.kotlin.builtins.functions.FunctionClassKind.Companion.byClassNamePrefix not-null) - */ - abstract fun knownTopLevelClassifiersInPackage(packageFqName: FqName): Set? - - /** - * @returns top-level callable names that belong to `packageFqName` or null if it's complicated to compute the set - */ - abstract fun computeCallableNamesInPackage(packageFqName: FqName): Set? } -/** - * Works almost as regular flatMap, but returns a set and returns null if any lambda call returned null - */ -inline fun Iterable.flatMapToNullableSet(transform: (T) -> Iterable?): Set? = - flatMapTo(mutableSetOf()) { transform(it) ?: return null } - private fun FirSymbolProvider.getClassDeclaredMemberScope(classId: ClassId): FirScope? { val classSymbol = getClassLikeSymbolByClassId(classId) as? FirRegularClassSymbol ?: return null return session.declaredMemberScope(classSymbol.fir, memberRequiredPhase = null) @@ -114,39 +89,6 @@ fun FirSymbolProvider.getRegularClassSymbolByClassId(classId: ClassId): FirRegul return getClassLikeSymbolByClassId(classId) as? FirRegularClassSymbol } -/** - * Whether [classId] may be contained in the set of known classifier names. - * - * If it's certain that [classId] cannot be a function class (for example when [classId] is known to come from a package without - * function classes), [mayBeFunctionClass] can be set to `false`. This avoids a hash map access in - * [org.jetbrains.kotlin.builtins.functions.FunctionTypeKindExtractor.getFunctionalClassKindWithArity]. - */ -fun Set.mayHaveTopLevelClassifier( - classId: ClassId, - session: FirSession, - mayBeFunctionClass: Boolean = true, -): Boolean { - if (mayBeFunctionClass && isNameForFunctionClass(classId, session)) return true - - if (classId.outerClassId == null) { - if (!mayHaveTopLevelClassifier(classId.shortClassName)) return false - } else { - if (!mayHaveTopLevelClassifier(classId.outermostClassId.shortClassName)) return false - } - - return true -} - -@Suppress("NOTHING_TO_INLINE") -private inline fun Set.mayHaveTopLevelClassifier(shortClassName: Name): Boolean = - shortClassName.asString() in this || shortClassName.isSpecial - -@OptIn(FirSymbolProviderInternals::class) -private fun isNameForFunctionClass(classId: ClassId, session: FirSession): Boolean { - if (!classId.mayBeSyntheticFunctionClassName()) return false - return session.functionTypeService.getKindByClassNamePrefix(classId.packageFqName, classId.shortClassName.asString()) != null -} - fun ClassId.toSymbol(session: FirSession): FirClassifierSymbol<*>? { return session.symbolProvider.getClassLikeSymbolByClassId(this) } 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 f4cf2634b80..f9f84b2af8b 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 @@ -7,14 +7,14 @@ package org.jetbrains.kotlin.fir.resolve.providers.impl import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.NoMutableState -import org.jetbrains.kotlin.fir.caches.FirCache import org.jetbrains.kotlin.fir.caches.createCache import org.jetbrains.kotlin.fir.caches.firCachesFactory import org.jetbrains.kotlin.fir.caches.getValue +import org.jetbrains.kotlin.fir.resolve.providers.FirCompositeCachedSymbolNamesProvider +import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolNamesProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals -import org.jetbrains.kotlin.fir.resolve.providers.flatMapToNullableSet -import org.jetbrains.kotlin.fir.resolve.providers.mayHaveTopLevelClassifier +import org.jetbrains.kotlin.fir.resolve.providers.impl.FirSyntheticFunctionInterfaceProviderBase.Companion.isNameForFunctionClass import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol @@ -39,25 +39,31 @@ class FirCachingCompositeSymbolProvider( private val topLevelPropertyCache = session.firCachesFactory.createCache(::computeTopLevelProperties) private val packageCache = session.firCachesFactory.createCache(::computePackage) - private val callablePackageSet: Set? by lazy(LazyThreadSafetyMode.PUBLICATION) { - computePackageSetWithTopLevelCallables().also { - ensureNotNull(it) { "package names with callables" } - } - } - - private val knownTopLevelClassifierNamesInPackage: FirCache?, Nothing?> = - session.firCachesFactory.createCache { packageFqName -> - knownTopLevelClassifiersInPackage(packageFqName).also { + override val symbolNamesProvider: FirSymbolNamesProvider = object : FirCompositeCachedSymbolNamesProvider( + session, + providers.map { it.symbolNamesProvider }, + ) { + override fun computeTopLevelClassifierNames(packageFqName: FqName): Set? = + super.computeTopLevelClassifierNames(packageFqName).also { ensureNotNull(it) { "classifier names in package $packageFqName" } } - } - private val callableNamesInPackage: FirCache?, Nothing?> = - session.firCachesFactory.createCache { packageFqName -> - computeCallableNamesInPackage(packageFqName).also { + override fun computePackageNamesWithTopLevelCallables(): Set? = + super.computePackageNamesWithTopLevelCallables().also { + ensureNotNull(it) { "package names with top-level callables" } + } + + override fun computeTopLevelCallableNames(packageFqName: FqName): Set? = + super.computeTopLevelCallableNames(packageFqName).also { ensureNotNull(it) { "callable names in package $packageFqName" } } + + @OptIn(FirSymbolProviderInternals::class) + override fun mayHaveSyntheticFunctionType(classId: ClassId): Boolean { + // We know that `session` is the same as the sessions of all `providers`, so we can take a shortcut here. + return classId.isNameForFunctionClass(session) } + } private inline fun ensureNotNull(v: Any?, representation: () -> String) { require(v != null || expectedCachesToBeCleanedOnce) { @@ -73,16 +79,10 @@ class FirCachingCompositeSymbolProvider( } override fun getTopLevelCallableSymbols(packageFqName: FqName, name: Name): List> { - if (!mayHaveTopLevelCallablesInPackage(packageFqName, name)) return emptyList() + if (!symbolNamesProvider.mayHaveTopLevelCallable(packageFqName, name)) return emptyList() return topLevelCallableCache.getValue(CallableId(packageFqName, name)) } - private fun mayHaveTopLevelCallablesInPackage(packageFqName: FqName, name: Name): Boolean { - if (callablePackageSet != null && packageFqName.asString() !in callablePackageSet!!) return false - val callableNamesInPackage = callableNamesInPackage.getValue(packageFqName) ?: return true - return name in callableNamesInPackage - } - @FirSymbolProviderInternals override fun getTopLevelCallableSymbolsTo(destination: MutableList>, packageFqName: FqName, name: Name) { destination += getTopLevelCallableSymbols(packageFqName, name) @@ -90,13 +90,13 @@ class FirCachingCompositeSymbolProvider( @FirSymbolProviderInternals override fun getTopLevelFunctionSymbolsTo(destination: MutableList, packageFqName: FqName, name: Name) { - if (!mayHaveTopLevelCallablesInPackage(packageFqName, name)) return + if (!symbolNamesProvider.mayHaveTopLevelCallable(packageFqName, name)) return destination += topLevelFunctionCache.getValue(CallableId(packageFqName, name)) } @FirSymbolProviderInternals override fun getTopLevelPropertySymbolsTo(destination: MutableList, packageFqName: FqName, name: Name) { - if (!mayHaveTopLevelCallablesInPackage(packageFqName, name)) return + if (!symbolNamesProvider.mayHaveTopLevelCallable(packageFqName, name)) return destination += topLevelPropertyCache.getValue(CallableId(packageFqName, name)) } @@ -105,9 +105,7 @@ class FirCachingCompositeSymbolProvider( } override fun getClassLikeSymbolByClassId(classId: ClassId): FirClassLikeSymbol<*>? { - val knownClassifierNames = knownTopLevelClassifierNamesInPackage.getValue(classId.packageFqName) - if (knownClassifierNames != null && !knownClassifierNames.mayHaveTopLevelClassifier(classId, session)) return null - + if (!symbolNamesProvider.mayHaveTopLevelClassifier(classId)) return null return classLikeCache.getValue(classId) } @@ -131,13 +129,4 @@ class FirCachingCompositeSymbolProvider( private fun computeClass(classId: ClassId): FirClassLikeSymbol<*>? = providers.firstNotNullOfOrNull { provider -> provider.getClassLikeSymbolByClassId(classId) } - - override fun computePackageSetWithTopLevelCallables(): Set? = - providers.flatMapToNullableSet { it.computePackageSetWithTopLevelCallables() } - - override fun knownTopLevelClassifiersInPackage(packageFqName: FqName): Set? = - providers.flatMapToNullableSet { it.knownTopLevelClassifiersInPackage(packageFqName) } - - override fun computeCallableNamesInPackage(packageFqName: FqName): Set? = - providers.flatMapToNullableSet { it.computeCallableNamesInPackage(packageFqName) } } diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirCompositeSymbolProvider.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirCompositeSymbolProvider.kt index a17772ac4b5..d8386775387 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirCompositeSymbolProvider.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirCompositeSymbolProvider.kt @@ -7,9 +7,10 @@ package org.jetbrains.kotlin.fir.resolve.providers.impl import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.NoMutableState +import org.jetbrains.kotlin.fir.resolve.providers.FirCompositeSymbolNamesProvider +import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolNamesProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals -import org.jetbrains.kotlin.fir.resolve.providers.flatMapToNullableSet import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol @@ -20,6 +21,8 @@ import org.jetbrains.kotlin.name.Name @NoMutableState class FirCompositeSymbolProvider(session: FirSession, val providers: List) : FirSymbolProvider(session) { + override val symbolNamesProvider: FirSymbolNamesProvider = FirCompositeSymbolNamesProvider.fromSymbolProviders(providers) + override fun getTopLevelCallableSymbols(packageFqName: FqName, name: Name): List> { return providers.flatMap { it.getTopLevelCallableSymbols(packageFqName, name) } } @@ -50,13 +53,4 @@ class FirCompositeSymbolProvider(session: FirSession, val providers: List? { return providers.firstNotNullOfOrNull { it.getClassLikeSymbolByClassId(classId) } } - - override fun computePackageSetWithTopLevelCallables(): Set? = - providers.flatMapToNullableSet { it.computePackageSetWithTopLevelCallables() } - - override fun knownTopLevelClassifiersInPackage(packageFqName: FqName): Set? = - providers.flatMapToNullableSet { it.knownTopLevelClassifiersInPackage(packageFqName) } - - override fun computeCallableNamesInPackage(packageFqName: FqName): Set? = - providers.flatMapToNullableSet { it.computeCallableNamesInPackage(packageFqName) } } 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 cdbeb22dd63..5bcd1e9cd9c 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 @@ -14,9 +14,7 @@ import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.fir.FirModuleData import org.jetbrains.kotlin.fir.FirSession -import org.jetbrains.kotlin.fir.caches.createCache import org.jetbrains.kotlin.fir.caches.firCachesFactory -import org.jetbrains.kotlin.fir.caches.getValue import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.declarations.builder.buildRegularClass @@ -28,6 +26,7 @@ import org.jetbrains.kotlin.fir.declarations.utils.addDeclaration import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotation import org.jetbrains.kotlin.fir.expressions.impl.FirEmptyAnnotationArgumentMapping import org.jetbrains.kotlin.fir.resolve.defaultType +import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolNamesProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider @@ -84,14 +83,29 @@ abstract class FirSyntheticFunctionInterfaceProviderBase( val moduleData: FirModuleData, val kotlinScopeProvider: FirKotlinScopeProvider ) : FirSymbolProvider(session) { - @OptIn(FirSymbolProviderInternals::class) - override fun getClassLikeSymbolByClassId(classId: ClassId): FirRegularClassSymbol? { - if (!classId.mayBeSyntheticFunctionClassName()) return null - return getClassLikeSymbolByClassIdWithoutClassIdChecks(classId) + override val symbolNamesProvider: FirSymbolNamesProvider = object : FirSymbolNamesProvider() { + override val mayHaveSyntheticFunctionTypes: Boolean get() = true + + override fun mayHaveSyntheticFunctionType(classId: ClassId): Boolean = classId.getAcceptableFunctionTypeKind() != null + + 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) + override fun mayHaveTopLevelCallable(packageFqName: FqName, name: Name): Boolean = false } - @FirSymbolProviderInternals - fun getClassLikeSymbolByClassIdWithoutClassIdChecks(classId: ClassId): FirRegularClassSymbol? = cache.getValue(classId) + override fun getClassLikeSymbolByClassId(classId: ClassId): FirRegularClassSymbol? { + val functionTypeKind = classId.getAcceptableFunctionTypeKind() ?: return null + return cache.getValue(classId, functionTypeKind) + } + + @OptIn(FirSymbolProviderInternals::class) + private fun ClassId.getAcceptableFunctionTypeKind(): FunctionTypeKind? = getFunctionTypeKind(session)?.takeIf { it.isAcceptable() } @FirSymbolProviderInternals override fun getTopLevelCallableSymbolsTo(destination: MutableList>, packageFqName: FqName, name: Name) { @@ -112,29 +126,13 @@ abstract class FirSyntheticFunctionInterfaceProviderBase( return fqName.takeIf { session.functionTypeService.hasKindWithSpecificPackage(it) } } - override fun computePackageSetWithTopLevelCallables(): Set { - return emptySet() - } - - /** - * This method has no sense for synthetic function interfaces - */ - override fun knownTopLevelClassifiersInPackage(packageFqName: FqName): Set? { - return emptySet() - } - - override fun computeCallableNamesInPackage(packageFqName: FqName): Set? { - return emptySet() - } - private val cache = moduleData.session.firCachesFactory.createCache(::createSyntheticFunctionInterface) protected abstract fun FunctionTypeKind.isAcceptable(): Boolean - private fun createSyntheticFunctionInterface(classId: ClassId): FirRegularClassSymbol? { + private fun createSyntheticFunctionInterface(classId: ClassId, kind: FunctionTypeKind): FirRegularClassSymbol? { return with(classId) { val className = relativeClassName.asString() - val kind = session.functionTypeService.getKindByClassNamePrefix(packageFqName, className) ?: return null if (!kind.isAcceptable()) return null val prefix = kind.classNamePrefix val arity = className.substring(prefix.length).toIntOrNull() ?: return null @@ -258,6 +256,15 @@ abstract class FirSyntheticFunctionInterfaceProviderBase( private fun FunctionTypeKind.classId(arity: Int) = ClassId(packageFqName, numberedClassName(arity)) companion object { + @FirSymbolProviderInternals + fun ClassId.isNameForFunctionClass(session: FirSession): Boolean = getFunctionTypeKind(session) != null + + @FirSymbolProviderInternals + private fun ClassId.getFunctionTypeKind(session: FirSession): FunctionTypeKind? { + if (!mayBeSyntheticFunctionClassName()) return null + return session.functionTypeService.getKindByClassNamePrefix(packageFqName, shortClassName.asString()) + } + /** * A [ClassId] can only be a name for a generated function class if it ends with a digit. See [FunctionTypeKind]. * 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 6a07e13eb26..75070da6752 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 @@ -16,6 +16,9 @@ import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.declarations.builder.buildRegularClass import org.jetbrains.kotlin.fir.declarations.builder.buildSimpleFunction +import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl +import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolNamesProvider +import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolNamesProviderWithoutCallables import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals @@ -67,6 +70,13 @@ class FirCloneableSymbolProvider( } + override val symbolNamesProvider: FirSymbolNamesProvider = object : FirSymbolNamesProviderWithoutCallables() { + override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set = + if (packageFqName == StandardClassIds.Cloneable.packageFqName) { + setOf(StandardClassIds.Cloneable.shortClassName.asString()) + } else emptySet() + } + override fun getClassLikeSymbolByClassId(classId: ClassId): FirClassLikeSymbol<*>? { return if (classId == StandardClassIds.Cloneable) klass.symbol else null } @@ -86,13 +96,4 @@ class FirCloneableSymbolProvider( override fun getPackage(fqName: FqName): FqName? { return null } - - override fun computePackageSetWithTopLevelCallables(): Set = emptySet() - override fun knownTopLevelClassifiersInPackage(packageFqName: FqName): Set = - if (packageFqName == StandardClassIds.Cloneable.packageFqName) - setOf(StandardClassIds.Cloneable.shortClassName.asString()) - else - emptySet() - - override fun computeCallableNamesInPackage(packageFqName: FqName): Set = emptySet() } 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 a0495997b3b..085f4470741 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 @@ -9,10 +9,7 @@ import org.jetbrains.annotations.TestOnly import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty -import org.jetbrains.kotlin.fir.resolve.providers.FirProvider -import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider -import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals -import org.jetbrains.kotlin.fir.resolve.providers.firProvider +import org.jetbrains.kotlin.fir.resolve.providers.* import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor @@ -80,22 +77,24 @@ class FirProviderImpl(val session: FirSession, val kotlinScopeProvider: FirKotli return null } - override fun computePackageSetWithTopLevelCallables(): Set = - state.allSubPackages.mapTo(mutableSetOf()) { it.asString() } + override val symbolNamesProvider: FirSymbolNamesProvider = object : FirSymbolNamesProvider() { + override fun getPackageNamesWithTopLevelCallables(): Set = + state.allSubPackages.mapTo(mutableSetOf()) { it.asString() } - override fun knownTopLevelClassifiersInPackage(packageFqName: FqName): Set = - state.classifierInPackage[packageFqName].orEmpty().mapTo(mutableSetOf()) { it.asString() } + override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set = + state.classifierInPackage[packageFqName].orEmpty().mapTo(mutableSetOf()) { it.asString() } - override fun computeCallableNamesInPackage(packageFqName: FqName): Set = buildSet { - for (key in state.functionMap.keys) { - if (key.packageName == packageFqName) { - add(key.callableName) + override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set = buildSet { + for (key in state.functionMap.keys) { + if (key.packageName == packageFqName) { + add(key.callableName) + } } - } - for (key in state.propertyMap.keys) { - if (key.packageName == packageFqName) { - add(key.callableName) + for (key in state.propertyMap.keys) { + if (key.packageName == packageFqName) { + add(key.callableName) + } } } }