[LL API] use FirCacheFactory in LLFirProviderHelper

This commit is contained in:
Ilya Kirillov
2022-06-23 19:34:21 +02:00
parent d8dad02f08
commit 706d20a523
3 changed files with 39 additions and 61 deletions
@@ -8,16 +8,11 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder
import com.intellij.concurrency.ConcurrentCollectionFactory import com.intellij.concurrency.ConcurrentCollectionFactory
import org.jetbrains.kotlin.analysis.api.impl.barebone.annotations.ThreadSafe import org.jetbrains.kotlin.analysis.api.impl.barebone.annotations.ThreadSafe
import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirModuleResolveComponents import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirModuleResolveComponents
import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration
import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.psi import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import java.util.* import java.util.*
import java.util.concurrent.ConcurrentHashMap
/** /**
* Caches mapping [KtFile] -> [FirFile] of module [KtModule] * Caches mapping [KtFile] -> [FirFile] of module [KtModule]
@@ -26,18 +21,6 @@ import java.util.concurrent.ConcurrentHashMap
internal abstract class ModuleFileCache { internal abstract class ModuleFileCache {
abstract val moduleComponents: LLFirModuleResolveComponents abstract val moduleComponents: LLFirModuleResolveComponents
/**
* Maps [ClassId] to corresponding classifiers
* If classifier with required [ClassId] is not found in given module then map contains [Optional.EMPTY]
*/
abstract val classifierByClassId: ConcurrentHashMap<ClassId, Optional<FirClassLikeDeclaration>>
/**
* Maps [CallableId] to corresponding callable
* If callable with required [CallableId]] is not found in given module then map contains emptyList
*/
abstract val callableByCallableId: ConcurrentHashMap<CallableId, List<FirCallableSymbol<*>>>
/** /**
* @return [FirFile] by [file] if it was previously built or runs [createValue] otherwise * @return [FirFile] by [file] if it was previously built or runs [createValue] otherwise
* The [createValue] is run under the lock so [createValue] is executed at most once for each [KtFile] * The [createValue] is run under the lock so [createValue] is executed at most once for each [KtFile]
@@ -51,10 +34,6 @@ internal abstract class ModuleFileCache {
internal class ModuleFileCacheImpl(override val moduleComponents: LLFirModuleResolveComponents) : ModuleFileCache() { internal class ModuleFileCacheImpl(override val moduleComponents: LLFirModuleResolveComponents) : ModuleFileCache() {
private val ktFileToFirFile = ConcurrentCollectionFactory.createConcurrentIdentityMap<KtFile, FirFile>() private val ktFileToFirFile = ConcurrentCollectionFactory.createConcurrentIdentityMap<KtFile, FirFile>()
override val classifierByClassId: ConcurrentHashMap<ClassId, Optional<FirClassLikeDeclaration>> = ConcurrentHashMap()
override val callableByCallableId: ConcurrentHashMap<CallableId, List<FirCallableSymbol<*>>> = ConcurrentHashMap()
override fun fileCached(file: KtFile, createValue: () -> FirFile): FirFile = override fun fileCached(file: KtFile, createValue: () -> FirFile): FirFile =
ktFileToFirFile.computeIfAbsent(file) { createValue() } ktFileToFirFile.computeIfAbsent(file) { createValue() }
@@ -34,7 +34,7 @@ internal class LLFirProvider(
override val symbolProvider: FirSymbolProvider = SymbolProvider() override val symbolProvider: FirSymbolProvider = SymbolProvider()
private val providerHelper = LLFirProviderHelper( private val providerHelper = LLFirProviderHelper(
moduleComponents.cache, session,
moduleComponents.firFileBuilder, moduleComponents.firFileBuilder,
declarationProvider, declarationProvider,
packageProvider, packageProvider,
@@ -6,71 +6,70 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.providers package org.jetbrains.kotlin.analysis.low.level.api.fir.providers
import com.google.common.collect.Sets import com.google.common.collect.Sets
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirFileBuilder
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.FirElementFinder
import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider
import org.jetbrains.kotlin.analysis.providers.KotlinPackageProvider import org.jetbrains.kotlin.analysis.providers.KotlinPackageProvider
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 import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirFileBuilder
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.ModuleFileCache
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.FirElementFinder
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.executeOrReturnDefaultValueOnPCE
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import java.util.*
internal class LLFirProviderHelper( internal class LLFirProviderHelper(
private val cache: ModuleFileCache, firSession: FirSession,
private val firFileBuilder: LLFirFileBuilder, private val firFileBuilder: LLFirFileBuilder,
private val declarationProvider: KotlinDeclarationProvider, private val declarationProvider: KotlinDeclarationProvider,
private val packageProvider: KotlinPackageProvider, private val packageProvider: KotlinPackageProvider,
) { ) {
fun getFirClassifierByFqName(classId: ClassId): FirClassLikeDeclaration? { private val classifierByClassId = firSession.firCachesFactory.createCache<ClassId, FirClassLikeDeclaration?> { classId ->
if (classId.isLocal) return null val ktClass = declarationProvider.getClassLikeDeclarationByClassId(classId)
return executeOrReturnDefaultValueOnPCE(null) { ?: return@createCache null
cache.classifierByClassId.computeIfAbsent(classId) { if (ktClass.getClassId() == null) return@createCache null
val ktClass = declarationProvider.getClassLikeDeclarationByClassId(classId) val firFile = firFileBuilder.buildRawFirFileWithCaching(ktClass.containingKtFile)
?: return@computeIfAbsent Optional.empty() FirElementFinder.findElementIn<FirClassLikeDeclaration>(
if (ktClass.getClassId() == null) return@computeIfAbsent Optional.empty() firFile,
val firFile = firFileBuilder.buildRawFirFileWithCaching(ktClass.containingKtFile) canGoInside = { it is FirRegularClass },
val classifier = FirElementFinder.findElementIn<FirClassLikeDeclaration>( predicate = { it.symbol.classId == classId },
firFile, )
canGoInside = { it is FirRegularClass }, ?: error("Classifier $classId was found in file ${ktClass.containingKtFile.virtualFilePath} but was not found in FirFile")
predicate = { it.symbol.classId == classId },
)
?: error("Classifier $classId was found in file ${ktClass.containingKtFile.virtualFilePath} but was not found in FirFile")
Optional.of(classifier)
}.getOrNull()
}
} }
fun getTopLevelCallableSymbols(packageFqName: FqName, name: Name): List<FirCallableSymbol<*>> { private val callablesByCallableId = firSession.firCachesFactory.createCache<CallableId, List<FirCallableSymbol<*>>> { callableId ->
val callableId = CallableId(packageFqName, name) val files = Sets.newIdentityHashSet<KtFile>().apply {
return executeOrReturnDefaultValueOnPCE(emptyList()) { declarationProvider.getTopLevelFunctions(callableId).mapTo(this) { it.containingKtFile }
cache.callableByCallableId.computeIfAbsent(callableId) { declarationProvider.getTopLevelProperties(callableId).mapTo(this) { it.containingKtFile }
val files = Sets.newIdentityHashSet<KtFile>().apply { }
declarationProvider.getTopLevelFunctions(callableId).mapTo(this) { it.containingKtFile } buildList {
declarationProvider.getTopLevelProperties(callableId).mapTo(this) { it.containingKtFile } files.forEach { ktFile ->
} val firFile = firFileBuilder.buildRawFirFileWithCaching(ktFile)
@OptIn(ExperimentalStdlibApi::class) firFile.collectCallableDeclarationsTo(this, callableId.callableName)
buildList {
files.forEach { ktFile ->
val firFile = firFileBuilder.buildRawFirFileWithCaching(ktFile)
firFile.collectCallableDeclarationsTo(this, name)
}
}
} }
} }
} }
fun getFirClassifierByFqName(classId: ClassId): FirClassLikeDeclaration? {
if (classId.isLocal) return null
return classifierByClassId.getValue(classId)
}
fun getTopLevelCallableSymbols(packageFqName: FqName, name: Name): List<FirCallableSymbol<*>> {
val callableId = CallableId(packageFqName, name)
return callablesByCallableId.getValue(callableId)
}
fun getTopLevelFunctionSymbols(packageFqName: FqName, name: Name): List<FirNamedFunctionSymbol> { fun getTopLevelFunctionSymbols(packageFqName: FqName, name: Name): List<FirNamedFunctionSymbol> {
return getTopLevelCallableSymbols(packageFqName, name).filterIsInstance<FirNamedFunctionSymbol>() return getTopLevelCallableSymbols(packageFqName, name).filterIsInstance<FirNamedFunctionSymbol>()
} }