[LL FIR] FirDeclarationForCompiledElementSearcher: avoid providers search for member declarations
This should improve performance and increase stability ^KT-61331 ^KT-61014
This commit is contained in:
committed by
Space Team
parent
1cf1a84594
commit
e68cf38e99
+70
-73
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* 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.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -18,6 +18,9 @@ import org.jetbrains.kotlin.fir.declarations.*
|
|||||||
import org.jetbrains.kotlin.fir.moduleData
|
import org.jetbrains.kotlin.fir.moduleData
|
||||||
import org.jetbrains.kotlin.fir.realPsi
|
import org.jetbrains.kotlin.fir.realPsi
|
||||||
import org.jetbrains.kotlin.fir.resolve.providers.*
|
import org.jetbrains.kotlin.fir.resolve.providers.*
|
||||||
|
import org.jetbrains.kotlin.fir.scopes.getFunctions
|
||||||
|
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.FirBasedSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||||
@@ -26,6 +29,7 @@ import org.jetbrains.kotlin.fir.utils.exceptions.withFirEntry
|
|||||||
import org.jetbrains.kotlin.name.StandardClassIds
|
import org.jetbrains.kotlin.name.StandardClassIds
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||||
|
import org.jetbrains.kotlin.utils.exceptions.withPsiEntry
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows to search for FIR declarations by compiled [KtDeclaration]s.
|
* Allows to search for FIR declarations by compiled [KtDeclaration]s.
|
||||||
@@ -36,18 +40,55 @@ internal class FirDeclarationForCompiledElementSearcher(private val symbolProvid
|
|||||||
ProjectStructureProvider.getInstance(project)
|
ProjectStructureProvider.getInstance(project)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun findNonLocalDeclaration(ktDeclaration: KtDeclaration): FirDeclaration {
|
fun findNonLocalDeclaration(ktDeclaration: KtDeclaration): FirDeclaration = when (ktDeclaration) {
|
||||||
return when (ktDeclaration) {
|
is KtEnumEntry -> findNonLocalEnumEntry(ktDeclaration)
|
||||||
is KtEnumEntry -> findNonLocalEnumEntry(ktDeclaration)
|
is KtClassLikeDeclaration -> findNonLocalClassLikeDeclaration(ktDeclaration)
|
||||||
is KtClassLikeDeclaration -> findNonLocalClassLikeDeclaration(ktDeclaration)
|
is KtConstructor<*> -> findConstructorOfNonLocalClass(ktDeclaration)
|
||||||
is KtConstructor<*> -> findConstructorOfNonLocalClass(ktDeclaration)
|
is KtNamedFunction -> findNonLocalFunction(ktDeclaration)
|
||||||
is KtNamedFunction -> findNonLocalFunction(ktDeclaration)
|
is KtProperty -> findNonLocalProperty(ktDeclaration)
|
||||||
is KtProperty -> findNonLocalProperty(ktDeclaration)
|
is KtParameter -> findParameter(ktDeclaration)
|
||||||
is KtParameter -> findParameter(ktDeclaration)
|
is KtPropertyAccessor -> findNonLocalPropertyAccessor(ktDeclaration)
|
||||||
is KtPropertyAccessor -> findNonLocalPropertyAccessor(ktDeclaration)
|
is KtTypeParameter -> findNonLocalTypeParameter(ktDeclaration)
|
||||||
is KtTypeParameter -> findNonLocalTypeParameter(ktDeclaration)
|
|
||||||
|
|
||||||
else -> errorWithFirSpecificEntries("Unsupported compiled declaration of type", psi = ktDeclaration)
|
else -> errorWithFirSpecificEntries("Unsupported compiled declaration of type", psi = ktDeclaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun FirSymbolProvider.findFunctionCandidates(function: KtNamedFunction): List<FirFunctionSymbol<*>> =
|
||||||
|
findCallableCandidates(function, function.isTopLevel).filterIsInstance<FirFunctionSymbol<*>>()
|
||||||
|
|
||||||
|
private fun FirSymbolProvider.findPropertyCandidates(property: KtProperty): List<FirPropertySymbol> =
|
||||||
|
findCallableCandidates(property, property.isTopLevel).filterIsInstance<FirPropertySymbol>()
|
||||||
|
|
||||||
|
private fun FirSymbolProvider.findCallableCandidates(
|
||||||
|
declaration: KtCallableDeclaration,
|
||||||
|
isTopLevel: Boolean,
|
||||||
|
): List<FirCallableSymbol<*>> {
|
||||||
|
val shortName = declaration.nameAsSafeName
|
||||||
|
|
||||||
|
if (isTopLevel) {
|
||||||
|
val packageFqName = declaration.containingKtFile.packageFqName
|
||||||
|
|
||||||
|
@OptIn(FirSymbolProviderInternals::class)
|
||||||
|
return when (this) {
|
||||||
|
is LLFirModuleWithDependenciesSymbolProvider -> buildList {
|
||||||
|
getTopLevelDeserializedCallableSymbolsToWithoutDependencies(this, packageFqName, shortName, declaration)
|
||||||
|
friendBuiltinsProvider?.getTopLevelCallableSymbolsTo(this, packageFqName, shortName)
|
||||||
|
}
|
||||||
|
else -> getTopLevelCallableSymbols(packageFqName, shortName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val containingClass = declaration.containingClassOrObject?.let(::findNonLocalClassLikeDeclaration)
|
||||||
|
?: errorWithFirSpecificEntries("No containing non-local declaration found for", psi = declaration)
|
||||||
|
|
||||||
|
val scope = session.declaredMemberScope(containingClass as FirClass, memberRequiredPhase = null)
|
||||||
|
return when (declaration) {
|
||||||
|
is KtProperty -> scope.getProperties(shortName)
|
||||||
|
is KtNamedFunction -> scope.getFunctions(shortName)
|
||||||
|
else -> errorWithFirSpecificEntries("Unexpected callable ${declaration::class.simpleName}") {
|
||||||
|
withEntry("isTopLevel", isTopLevel.toString())
|
||||||
|
withPsiEntry("declaration", declaration)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,8 +98,9 @@ internal class FirDeclarationForCompiledElementSearcher(private val symbolProvid
|
|||||||
val firTypeParameterRefOwner = firDeclaration as? FirTypeParameterRefsOwner ?: errorWithFirSpecificEntries(
|
val firTypeParameterRefOwner = firDeclaration as? FirTypeParameterRefsOwner ?: errorWithFirSpecificEntries(
|
||||||
"No fir found by $owner",
|
"No fir found by $owner",
|
||||||
psi = owner,
|
psi = owner,
|
||||||
fir = firDeclaration
|
fir = firDeclaration,
|
||||||
)
|
)
|
||||||
|
|
||||||
return firTypeParameterRefOwner.typeParameters.find { it.realPsi === param } as FirDeclaration
|
return firTypeParameterRefOwner.typeParameters.find { it.realPsi === param } as FirDeclaration
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,21 +117,16 @@ internal class FirDeclarationForCompiledElementSearcher(private val symbolProvid
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun findNonLocalEnumEntry(declaration: KtEnumEntry): FirEnumEntry {
|
private fun findNonLocalEnumEntry(declaration: KtEnumEntry): FirEnumEntry {
|
||||||
require(!declaration.isLocal)
|
val classCandidate = declaration.containingClassOrObject?.let(::findNonLocalClassLikeDeclaration)
|
||||||
val classId = declaration.containingClassOrObject?.getClassId()
|
?: errorWithFirSpecificEntries("Enum entry must have containing class", psi = declaration)
|
||||||
?: errorWithFirSpecificEntries("Non-local class should have classId", psi = declaration)
|
|
||||||
|
|
||||||
val classCandidate = symbolProvider.getClassLikeSymbolByClassId(classId)
|
return (classCandidate as FirRegularClass).declarations.first {
|
||||||
?: errorWithFirSpecificEntries("We should be able to find a symbol for $classId", psi = declaration)
|
|
||||||
|
|
||||||
return (classCandidate.fir as? FirRegularClass)?.declarations?.first {
|
|
||||||
it is FirEnumEntry && it.realPsi === declaration
|
it is FirEnumEntry && it.realPsi === declaration
|
||||||
} as FirEnumEntry
|
} as FirEnumEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun findNonLocalClassLikeDeclaration(declaration: KtClassLikeDeclaration): FirClassLikeDeclaration {
|
private fun findNonLocalClassLikeDeclaration(declaration: KtClassLikeDeclaration): FirClassLikeDeclaration {
|
||||||
val classId = declaration.getClassId()
|
val classId = declaration.getClassId() ?: errorWithFirSpecificEntries("Non-local class should have classId", psi = declaration)
|
||||||
?: errorWithFirSpecificEntries("Non-local class should have classId", psi = declaration)
|
|
||||||
|
|
||||||
val classCandidate = when (symbolProvider) {
|
val classCandidate = when (symbolProvider) {
|
||||||
is LLFirModuleWithDependenciesSymbolProvider -> {
|
is LLFirModuleWithDependenciesSymbolProvider -> {
|
||||||
@@ -118,14 +155,9 @@ internal class FirDeclarationForCompiledElementSearcher(private val symbolProvid
|
|||||||
val containingClass = declaration.containingClassOrObject
|
val containingClass = declaration.containingClassOrObject
|
||||||
?: errorWithFirSpecificEntries("Constructor must have outer class", psi = declaration)
|
?: errorWithFirSpecificEntries("Constructor must have outer class", psi = declaration)
|
||||||
|
|
||||||
require(!containingClass.isLocal)
|
val containingFirClass = findNonLocalClassLikeDeclaration(containingClass) as FirClass
|
||||||
val classId = containingClass.getClassId()
|
val constructorCandidate = containingFirClass.constructors(symbolProvider.session).singleOrNull { it.fir.realPsi === declaration }
|
||||||
?: errorWithFirSpecificEntries("Non-local class should have classId", psi = declaration)
|
?: errorWithFirSpecificEntries("We should be able to find a constructor", psi = declaration, fir = containingFirClass)
|
||||||
|
|
||||||
val constructorCandidate =
|
|
||||||
symbolProvider.getClassDeclaredConstructors(classId)
|
|
||||||
.singleOrNull { it.fir.realPsi === declaration }
|
|
||||||
?: errorWithFirSpecificEntries("We should be able to find a constructor", psi = declaration)
|
|
||||||
|
|
||||||
return constructorCandidate.fir
|
return constructorCandidate.fir
|
||||||
}
|
}
|
||||||
@@ -134,12 +166,10 @@ internal class FirDeclarationForCompiledElementSearcher(private val symbolProvid
|
|||||||
require(!declaration.isLocal)
|
require(!declaration.isLocal)
|
||||||
|
|
||||||
val candidates = symbolProvider.findFunctionCandidates(declaration)
|
val candidates = symbolProvider.findFunctionCandidates(declaration)
|
||||||
val functionCandidate =
|
val functionCandidate = candidates.firstOrNull { it.fir.realPsi === declaration }
|
||||||
candidates
|
?: errorWithFirSpecificEntries("We should be able to find a symbol for function", psi = declaration) {
|
||||||
.firstOrNull { it.fir.realPsi === declaration }
|
withCandidates(candidates)
|
||||||
?: errorWithFirSpecificEntries("We should be able to find a symbol for function", psi = declaration) {
|
}
|
||||||
withCandidates(candidates)
|
|
||||||
}
|
|
||||||
|
|
||||||
return functionCandidate.fir
|
return functionCandidate.fir
|
||||||
}
|
}
|
||||||
@@ -149,11 +179,10 @@ internal class FirDeclarationForCompiledElementSearcher(private val symbolProvid
|
|||||||
require(!declaration.isLocal)
|
require(!declaration.isLocal)
|
||||||
|
|
||||||
val candidates = symbolProvider.findPropertyCandidates(declaration)
|
val candidates = symbolProvider.findPropertyCandidates(declaration)
|
||||||
val propertyCandidate =
|
val propertyCandidate = candidates.firstOrNull { it.fir.realPsi === declaration }
|
||||||
candidates.firstOrNull { it.fir.realPsi === declaration }
|
?: errorWithFirSpecificEntries("We should be able to find a symbol for property", psi = declaration) {
|
||||||
?: errorWithFirSpecificEntries("We should be able to find a symbol for property", psi = declaration) {
|
withCandidates(candidates)
|
||||||
withCandidates(candidates)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return propertyCandidate.fir
|
return propertyCandidate.fir
|
||||||
}
|
}
|
||||||
@@ -181,38 +210,6 @@ private val LLFirModuleWithDependenciesSymbolProvider.friendBuiltinsProvider: Fi
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun FirSymbolProvider.findFunctionCandidates(function: KtNamedFunction): List<FirFunctionSymbol<*>> =
|
|
||||||
findCallableCandidates(function, function.isTopLevel).filterIsInstance<FirFunctionSymbol<*>>()
|
|
||||||
|
|
||||||
private fun FirSymbolProvider.findPropertyCandidates(property: KtProperty): List<FirPropertySymbol> =
|
|
||||||
findCallableCandidates(property, property.isTopLevel).filterIsInstance<FirPropertySymbol>()
|
|
||||||
|
|
||||||
private fun FirSymbolProvider.findCallableCandidates(
|
|
||||||
declaration: KtCallableDeclaration,
|
|
||||||
isTopLevel: Boolean
|
|
||||||
): List<FirCallableSymbol<*>> {
|
|
||||||
val shortName = declaration.nameAsSafeName
|
|
||||||
|
|
||||||
if (isTopLevel) {
|
|
||||||
val packageFqName = declaration.containingKtFile.packageFqName
|
|
||||||
|
|
||||||
@OptIn(FirSymbolProviderInternals::class)
|
|
||||||
return when (this) {
|
|
||||||
is LLFirModuleWithDependenciesSymbolProvider -> buildList {
|
|
||||||
getTopLevelDeserializedCallableSymbolsToWithoutDependencies(this, packageFqName, shortName, declaration)
|
|
||||||
friendBuiltinsProvider?.getTopLevelCallableSymbolsTo(this, packageFqName, shortName)
|
|
||||||
}
|
|
||||||
else -> getTopLevelCallableSymbols(packageFqName, shortName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val containerClassId = declaration.containingClassOrObject?.getClassId()
|
|
||||||
?: errorWithFirSpecificEntries("No containing non-local declaration found for", psi = declaration)
|
|
||||||
|
|
||||||
return getClassDeclaredFunctionSymbols(containerClassId, shortName) +
|
|
||||||
getClassDeclaredPropertySymbols(containerClassId, shortName)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun ExceptionAttachmentBuilder.withCandidates(candidates: List<FirBasedSymbol<*>>) {
|
private fun ExceptionAttachmentBuilder.withCandidates(candidates: List<FirBasedSymbol<*>>) {
|
||||||
withEntry("Candidates count", candidates.size.toString())
|
withEntry("Candidates count", candidates.size.toString())
|
||||||
for ((index, candidate) in candidates.withIndex()) {
|
for ((index, candidate) in candidates.withIndex()) {
|
||||||
|
|||||||
Reference in New Issue
Block a user