[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:
Dmitrii Gridin
2023-08-21 16:24:30 +02:00
committed by Space Team
parent 1cf1a84594
commit e68cf38e99
@@ -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()) {