[LL] don't request provider with non-physical element

Otherwise, if fir was requested with non-physical element
 inside existing analysis session (not on-air, e.g.,
`FirPositionCompletionContextDetector#analyzeInContext` with
 `FirSimpleParameterPositionContext`) all consequent requests
 would return fir with that non-physical source,
 which might be already invalidated.

 On-air sessions should be protected from invalidation problem but some clients
 might expect original elements anyway and in this case, it would be
 impossible to retrieve correct fir for them.

 In order to find parameters, allow to traverse tree till functions.
This commit is contained in:
Anna Kozlova
2023-06-07 09:50:16 +02:00
committed by Space Team
parent 3fc334d2eb
commit 70b9af0566
2 changed files with 16 additions and 5 deletions
@@ -72,6 +72,7 @@ internal class LLFirProviderHelper(
private val classifierByClassId =
firSession.firCachesFactory.createCache<ClassId, FirClassLikeDeclaration?, KtClassLikeDeclaration?> { classId, context ->
require(context == null || context.isPhysical)
val ktClass = context ?: declarationProvider.getClassLikeDeclarationByClassId(classId) ?: return@createCache null
if (ktClass.getClassId() == null) return@createCache null
@@ -82,6 +83,7 @@ internal class LLFirProviderHelper(
private val callablesByCallableId =
firSession.firCachesFactory.createCache<CallableId, List<FirCallableSymbol<*>>, Collection<KtFile>?> { callableId, context ->
require(context == null || context.all { it.isPhysical })
val files = context ?: declarationProvider.getTopLevelCallableFiles(callableId).ifEmpty { return@createCache emptyList() }
buildList {
files.forEach { ktFile ->
@@ -32,7 +32,12 @@ internal fun KtDeclaration.findSourceNonLocalFirDeclaration(
//TODO test what way faster
findSourceNonLocalFirDeclarationByProvider(firFileBuilder, provider, containerFirFile)?.let { return it }
findSourceByTraversingWholeTree(firFileBuilder, containerFirFile)?.let { return it }
errorWithFirSpecificEntries("No fir element was found for", psi = this)
errorWithFirSpecificEntries(
"No fir element was found for",
psi = this,
fir = containerFirFile ?: firFileBuilder.buildRawFirFileWithCaching(containingKtFile),
additionalInfos = { withEntry("isPhysical", isPhysical.toString()) }
)
}
internal fun KtDeclaration.findFirDeclarationForAnyFirSourceDeclaration(
@@ -68,7 +73,7 @@ internal fun KtElement.findSourceByTraversingWholeTree(
val isDeclaration = this is KtDeclaration
return FirElementFinder.findElementIn(
firFile,
canGoInside = { it is FirRegularClass || it is FirScript },
canGoInside = { it is FirRegularClass || it is FirScript || it is FirFunction },
predicate = { firDeclaration ->
firDeclaration.psi == this || isDeclaration && firDeclaration.psi == originalDeclaration
}
@@ -80,6 +85,11 @@ private fun KtDeclaration.findSourceNonLocalFirDeclarationByProvider(
provider: FirProvider,
containerFirFile: FirFile?,
): FirDeclaration? {
if (!isPhysical) {
//do not request providers with non-physical psi in order not to leak them there and
//to avoid inconsistency between physical psi and its copy during completion
return null
}
val candidate = when {
this is KtClassOrObject -> findFir(provider)
this is KtNamedDeclaration && (this is KtProperty || this is KtNamedFunction) -> {
@@ -97,19 +107,18 @@ private fun KtDeclaration.findSourceNonLocalFirDeclarationByProvider(
firFile.declarations
}
}
val original = originalDeclaration
/*
It is possible that we will not be able to find needed declaration here when the code is invalid,
e.g, we have two conflicting declarations with the same name and we are searching in the wrong one
*/
declarations?.firstOrNull { it.psi == this || it.psi == original }
declarations?.firstOrNull { it.psi == this }
}
this is KtConstructor<*> || this is KtClassInitializer -> {
val containingClass = containingClassOrObject
?: errorWithFirSpecificEntries("Container class should be not null for KtConstructor", psi = this)
val containerClassFir = containingClass.findFir(provider) as? FirRegularClass ?: return null
containerClassFir.declarations.firstOrNull { it.psi === this }
containerClassFir.declarations.firstOrNull { it.psi == this }
}
this is KtTypeAlias -> findFir(provider)
this is KtDestructuringDeclaration -> {