[LL FIR] KT-58325 Introduce LLFirKotlinSymbolProvider

- `LLFirKotlinSymbolProvider` is a shared interface for any symbol
  providers that are based on `KotlinDeclarationProvider`.
- `LLFirKotlinSymbolProviderWithNameCache` simplifies symbol provider
  implementations which use a `LLFirSymbolProviderNameCache`.
  - Note that the domain is not limited to "Kotlin symbol providers",
    but I don't want to introduce a general base class like
    `LLFirSymbolProviderWithNameCache` without multiple class
    inheritance (think Scala traits).
  - It would be possible to use delegation instead of such a base class,
    but that would require a shared interface for the "package name"
    functions, which would require some compiler refactoring as well.
- We can base `LLFirProvider$SymbolProvider` on
  `LLFirKotlinSymbolProvider`.
- The callables functions in `LLFirKotlinSymbolProvider` expect
  `KtCallableDeclaration`s instead of `KtFile`s. This is the preferred
  interface, because callable files are only needed for `LLFirProvider`,
  not Kotlin symbol providers in general (such as the stub-based
  deserialized symbol provider). This also has the advantage that FIR
  files containing only properties won't be built for
  `getTopLevelFunctionSymbolsTo` and vice versa.
This commit is contained in:
Marco Pennekamp
2023-05-08 16:09:06 +02:00
committed by Space Team
parent 29f7e922f6
commit f4d3cceabd
2 changed files with 97 additions and 33 deletions
@@ -0,0 +1,79 @@
/*
* 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.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
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
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
import org.jetbrains.kotlin.psi.KtProperty
/**
* A [FirSymbolProvider] which provides symbols from Kotlin sources via [KotlinDeclarationProvider].
*
* @see LLFirCombinedKotlinSymbolProvider
*/
internal abstract class LLFirKotlinSymbolProvider(session: FirSession) : FirSymbolProvider(session) {
/**
* This function is optimized for a known [classLikeDeclaration].
*/
@FirSymbolProviderInternals
abstract fun getClassLikeSymbolByClassId(classId: ClassId, classLikeDeclaration: KtClassLikeDeclaration): FirClassLikeSymbol<*>?
/**
* This function is optimized for known [callables].
*/
@FirSymbolProviderInternals
abstract fun getTopLevelCallableSymbolsTo(
destination: MutableList<FirCallableSymbol<*>>,
callableId: CallableId,
callables: Collection<KtCallableDeclaration>,
)
/**
* This function is optimized for known [functions].
*/
@FirSymbolProviderInternals
abstract fun getTopLevelFunctionSymbolsTo(
destination: MutableList<FirNamedFunctionSymbol>,
callableId: CallableId,
functions: Collection<KtNamedFunction>,
)
/**
* This function is optimized for known [properties].
*/
@FirSymbolProviderInternals
abstract fun getTopLevelPropertySymbolsTo(
destination: MutableList<FirPropertySymbol>,
callableId: CallableId,
properties: Collection<KtProperty>,
)
}
internal abstract class LLFirKotlinSymbolProviderWithNameCache(session: FirSession) : LLFirKotlinSymbolProvider(session) {
protected abstract val symbolNameCache: LLFirSymbolProviderNameCache
final override fun knownTopLevelClassifiersInPackage(packageFqName: FqName): Set<String>? =
symbolNameCache.getTopLevelClassifierNamesInPackage(packageFqName)
final override fun computeCallableNamesInPackage(packageFqName: FqName): Set<Name>? =
symbolNameCache.getTopLevelCallableNamesInPackage(packageFqName)
final override fun computePackageSetWithTopLevelCallables(): Set<String>? = symbolNameCache.getPackageNamesWithTopLevelCallables()
}
@@ -7,6 +7,7 @@ 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.LLFirModuleResolveComponents
import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.SyntheticFirClassProvider 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.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.FirSession
@@ -25,8 +26,10 @@ 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.KtCallableDeclaration
import org.jetbrains.kotlin.psi.KtClassLikeDeclaration import org.jetbrains.kotlin.psi.KtClassLikeDeclaration
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtProperty
@ThreadSafeMutableState @ThreadSafeMutableState
internal class LLFirProvider( internal class LLFirProvider(
@@ -109,17 +112,17 @@ internal class LLFirProvider(
declarationProvider.getTopLevelKotlinClassLikeDeclarationNamesInPackage(fqName) declarationProvider.getTopLevelKotlinClassLikeDeclarationNamesInPackage(fqName)
@NoMutableState @NoMutableState
internal inner class SymbolProvider : FirSymbolProvider(session) { internal inner class SymbolProvider : LLFirKotlinSymbolProviderWithNameCache(session) {
override val symbolNameCache: LLFirSymbolProviderNameCache
get() = providerHelper.symbolNameCache
override fun getClassLikeSymbolByClassId(classId: ClassId): FirClassLikeSymbol<*>? { override fun getClassLikeSymbolByClassId(classId: ClassId): FirClassLikeSymbol<*>? {
if (!providerHelper.symbolNameCache.mayHaveTopLevelClassifier(classId, mayHaveFunctionClass = false)) return null if (!providerHelper.symbolNameCache.mayHaveTopLevelClassifier(classId, mayHaveFunctionClass = false)) return null
return getFirClassifierByFqName(classId)?.symbol return getFirClassifierByFqName(classId)?.symbol
} }
/**
* This function is optimized for a known [classLikeDeclaration].
*/
@FirSymbolProviderInternals @FirSymbolProviderInternals
fun getClassLikeSymbolByClassId(classId: ClassId, classLikeDeclaration: KtClassLikeDeclaration): FirClassLikeSymbol<*>? { override fun getClassLikeSymbolByClassId(classId: ClassId, classLikeDeclaration: KtClassLikeDeclaration): FirClassLikeSymbol<*>? {
return getFirClassifierByFqNameAndDeclaration(classId, classLikeDeclaration)?.symbol return getFirClassifierByFqNameAndDeclaration(classId, classLikeDeclaration)?.symbol
} }
@@ -134,16 +137,13 @@ internal class LLFirProvider(
destination += providerHelper.getTopLevelCallableSymbols(packageFqName, name) 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 @FirSymbolProviderInternals
fun getTopLevelCallableSymbolsTo( override fun getTopLevelCallableSymbolsTo(
destination: MutableList<FirCallableSymbol<*>>, destination: MutableList<FirCallableSymbol<*>>,
callableId: CallableId, callableId: CallableId,
callableFiles: Collection<KtFile>, callables: Collection<KtCallableDeclaration>
) { ) {
destination += providerHelper.getTopLevelCallableSymbols(callableId, callableFiles) destination += providerHelper.getTopLevelCallableSymbols(callableId, callables.map { it.containingKtFile })
} }
override fun getTopLevelFunctionSymbols(packageFqName: FqName, name: Name): List<FirNamedFunctionSymbol> { override fun getTopLevelFunctionSymbols(packageFqName: FqName, name: Name): List<FirNamedFunctionSymbol> {
@@ -157,16 +157,13 @@ internal class LLFirProvider(
destination += providerHelper.getTopLevelFunctionSymbols(packageFqName, name) 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 @FirSymbolProviderInternals
fun getTopLevelFunctionSymbolsTo( override fun getTopLevelFunctionSymbolsTo(
destination: MutableList<FirNamedFunctionSymbol>, destination: MutableList<FirNamedFunctionSymbol>,
callableId: CallableId, callableId: CallableId,
callableFiles: Collection<KtFile>, functions: Collection<KtNamedFunction>
) { ) {
destination += providerHelper.getTopLevelFunctionSymbols(callableId, callableFiles) destination += providerHelper.getTopLevelFunctionSymbols(callableId, functions.map { it.containingKtFile })
} }
override fun getTopLevelPropertySymbols(packageFqName: FqName, name: Name): List<FirPropertySymbol> { override fun getTopLevelPropertySymbols(packageFqName: FqName, name: Name): List<FirPropertySymbol> {
@@ -180,28 +177,16 @@ internal class LLFirProvider(
destination += providerHelper.getTopLevelPropertySymbols(packageFqName, name) 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 @FirSymbolProviderInternals
fun getTopLevelPropertySymbolsTo( override fun getTopLevelPropertySymbolsTo(
destination: MutableList<FirPropertySymbol>, destination: MutableList<FirPropertySymbol>,
callableId: CallableId, callableId: CallableId,
callableFiles: Collection<KtFile>, properties: Collection<KtProperty>
) { ) {
destination += providerHelper.getTopLevelPropertySymbols(callableId, callableFiles) destination += providerHelper.getTopLevelPropertySymbols(callableId, properties.mapTo(mutableSetOf()) { it.containingKtFile })
} }
override fun getPackage(fqName: FqName): FqName? = override fun getPackage(fqName: FqName): FqName? =
providerHelper.getPackage(fqName) providerHelper.getPackage(fqName)
override fun computePackageSetWithTopLevelCallables(): Set<String>? =
providerHelper.symbolNameCache.getPackageNamesWithTopLevelCallables()
override fun knownTopLevelClassifiersInPackage(packageFqName: FqName): Set<String>? =
providerHelper.symbolNameCache.getTopLevelClassifierNamesInPackage(packageFqName)
override fun computeCallableNamesInPackage(packageFqName: FqName): Set<Name>? =
providerHelper.symbolNameCache.getTopLevelCallableNamesInPackage(packageFqName)
} }
} }