From 16af67e99c1876c00c4d273275ce4631af995a68 Mon Sep 17 00:00:00 2001 From: Marco Pennekamp Date: Wed, 22 Mar 2023 18:24:37 +0100 Subject: [PATCH] [LL FIR] KT-57314 Allow passing index results to Kotlin symbol provider - If a `KtClassLikeDeclaration` or all `KtFile`s which contain a callable are already known, they can now be passed to `LLFirProvider$SymbolProvider` directly. This avoids index accesses in `providerHelper`. --- .../level/api/fir/providers/LLFirProvider.kt | 46 +++++++++++++++++++ .../api/fir/providers/LLFirProviderHelper.kt | 34 ++++++++++---- 2 files changed, 72 insertions(+), 8 deletions(-) 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 11d5ca5209e..afc2a2ff1b2 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 @@ -21,10 +21,12 @@ 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.symbols.impl.* +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.KtClassLikeDeclaration +import org.jetbrains.kotlin.psi.KtFile @ThreadSafeMutableState internal class LLFirProvider( @@ -113,6 +115,14 @@ internal class LLFirProvider( return getFirClassifierByFqName(classId)?.symbol } + /** + * This function is optimized for a known [classLikeDeclaration]. + */ + @FirSymbolProviderInternals + fun getClassLikeSymbolByClassId(classId: ClassId, classLikeDeclaration: KtClassLikeDeclaration): FirClassLikeSymbol<*>? { + return getFirClassifierByFqNameAndDeclaration(classId, classLikeDeclaration)?.symbol + } + override fun getTopLevelCallableSymbols(packageFqName: FqName, name: Name): List> { if (!providerHelper.symbolNameCache.mayHaveTopLevelCallable(packageFqName, name)) return emptyList() return providerHelper.getTopLevelCallableSymbols(packageFqName, name) @@ -124,6 +134,18 @@ internal class LLFirProvider( destination += providerHelper.getTopLevelCallableSymbols(packageFqName, name) } + /** + * This function is optimized for known [callableFiles], which should be the list of all [KtFile]s that contain the callables. + */ + @FirSymbolProviderInternals + fun getTopLevelCallableSymbolsTo( + destination: MutableList>, + callableId: CallableId, + callableFiles: Collection, + ) { + destination += providerHelper.getTopLevelCallableSymbols(callableId, callableFiles) + } + override fun getTopLevelFunctionSymbols(packageFqName: FqName, name: Name): List { if (!providerHelper.symbolNameCache.mayHaveTopLevelCallable(packageFqName, name)) return emptyList() return providerHelper.getTopLevelFunctionSymbols(packageFqName, name) @@ -135,6 +157,18 @@ internal class LLFirProvider( destination += providerHelper.getTopLevelFunctionSymbols(packageFqName, name) } + /** + * This function is optimized for known [callableFiles], which should be the list of all [KtFile]s that contain the functions. + */ + @FirSymbolProviderInternals + fun getTopLevelFunctionSymbolsTo( + destination: MutableList, + callableId: CallableId, + callableFiles: Collection, + ) { + destination += providerHelper.getTopLevelFunctionSymbols(callableId, callableFiles) + } + override fun getTopLevelPropertySymbols(packageFqName: FqName, name: Name): List { if (!providerHelper.symbolNameCache.mayHaveTopLevelCallable(packageFqName, name)) return emptyList() return providerHelper.getTopLevelPropertySymbols(packageFqName, name) @@ -146,6 +180,18 @@ internal class LLFirProvider( destination += providerHelper.getTopLevelPropertySymbols(packageFqName, name) } + /** + * This function is optimized for known [callableFiles], which should be the list of all [KtFile]s that contain the properties. + */ + @FirSymbolProviderInternals + fun getTopLevelPropertySymbolsTo( + destination: MutableList, + callableId: CallableId, + callableFiles: Collection, + ) { + destination += providerHelper.getTopLevelPropertySymbols(callableId, callableFiles) + } + override fun getPackage(fqName: FqName): FqName? = providerHelper.getPackage(fqName) 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 f5d753ccf9d..a60ea2e8d0b 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 @@ -13,7 +13,6 @@ import org.jetbrains.kotlin.analysis.providers.KotlinPackageProvider import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.config.AnalysisFlags 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.FirCallableDeclaration @@ -28,6 +27,7 @@ import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtClassLikeDeclaration +import org.jetbrains.kotlin.psi.KtFile internal class LLFirProviderHelper( firSession: FirSession, @@ -49,15 +49,16 @@ internal class LLFirProviderHelper( ?: error("Classifier $classId was found in file ${ktClass.containingKtFile.virtualFilePath} but was not found in FirFile") } - private val callablesByCallableId = firSession.firCachesFactory.createCache>> { callableId -> - val files = declarationProvider.getTopLevelCallableFiles(callableId).ifEmpty { return@createCache emptyList() } - buildList { - files.forEach { ktFile -> - val firFile = firFileBuilder.buildRawFirFileWithCaching(ktFile) - firFile.collectCallableDeclarationsTo(this, callableId.callableName) + private val callablesByCallableId = + firSession.firCachesFactory.createCache>, Collection?> { callableId, context -> + val files = context ?: declarationProvider.getTopLevelCallableFiles(callableId).ifEmpty { return@createCache emptyList() } + buildList { + files.forEach { ktFile -> + val firFile = firFileBuilder.buildRawFirFileWithCaching(ktFile) + firFile.collectCallableDeclarationsTo(this, callableId.callableName) + } } } - } val symbolNameCache = object : LLFirSymbolProviderNameCache(firSession) { override fun computeClassifierNames(packageFqName: FqName): Set? = @@ -84,14 +85,31 @@ internal class LLFirProviderHelper( return callablesByCallableId.getValue(callableId) } + /** + * [callableFiles] are the [KtFile]s which contain callables of the given package and name. If already known, they can be provided to + * avoid index accesses. + */ + fun getTopLevelCallableSymbols(callableId: CallableId, callableFiles: Collection?): List> { + if (!allowKotlinPackage && callableId.packageName.isKotlinPackage()) return emptyList() + return callablesByCallableId.getValue(callableId, callableFiles) + } + fun getTopLevelFunctionSymbols(packageFqName: FqName, name: Name): List { return getTopLevelCallableSymbols(packageFqName, name).filterIsInstance() } + fun getTopLevelFunctionSymbols(callableId: CallableId, callableFiles: Collection): List { + return getTopLevelCallableSymbols(callableId, callableFiles).filterIsInstance() + } + fun getTopLevelPropertySymbols(packageFqName: FqName, name: Name): List { return getTopLevelCallableSymbols(packageFqName, name).filterIsInstance() } + fun getTopLevelPropertySymbols(callableId: CallableId, callableFiles: Collection): List { + return getTopLevelCallableSymbols(callableId, callableFiles).filterIsInstance() + } + private fun FirFile.collectCallableDeclarationsTo(list: MutableList>, name: Name) { declarations.mapNotNullTo(list) { declaration -> if (declaration is FirCallableDeclaration && declaration.symbol.callableId.callableName == name) {