[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.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
@@ -25,8 +26,10 @@ 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.KtFile
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtProperty
@ThreadSafeMutableState
internal class LLFirProvider(
@@ -109,17 +112,17 @@ internal class LLFirProvider(
declarationProvider.getTopLevelKotlinClassLikeDeclarationNamesInPackage(fqName)
@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<*>? {
if (!providerHelper.symbolNameCache.mayHaveTopLevelClassifier(classId, mayHaveFunctionClass = false)) return null
return getFirClassifierByFqName(classId)?.symbol
}
/**
* This function is optimized for a known [classLikeDeclaration].
*/
@FirSymbolProviderInternals
fun getClassLikeSymbolByClassId(classId: ClassId, classLikeDeclaration: KtClassLikeDeclaration): FirClassLikeSymbol<*>? {
override fun getClassLikeSymbolByClassId(classId: ClassId, classLikeDeclaration: KtClassLikeDeclaration): FirClassLikeSymbol<*>? {
return getFirClassifierByFqNameAndDeclaration(classId, classLikeDeclaration)?.symbol
}
@@ -134,16 +137,13 @@ 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(
override fun getTopLevelCallableSymbolsTo(
destination: MutableList<FirCallableSymbol<*>>,
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> {
@@ -157,16 +157,13 @@ 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(
override fun getTopLevelFunctionSymbolsTo(
destination: MutableList<FirNamedFunctionSymbol>,
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> {
@@ -180,28 +177,16 @@ 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(
override fun getTopLevelPropertySymbolsTo(
destination: MutableList<FirPropertySymbol>,
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? =
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)
}
}