KTIJ-25823 [Analysis API][FIR] Filter reanalysed parts by type in FirBodyReanalyzingVisitorVoid

There are SOE exceptions caused by the fact that `getOrBuildFir` can
return a FIR declaration for the parent PSI. I wasn't able to reproduce
it locally, but this commit should prevent such problems by using
`getOrBuildFirSafe` with explicit type specification
This commit is contained in:
Roman Golyshev
2023-06-13 12:08:10 +02:00
committed by teamcity
parent 0c464450a9
commit 9f819b4c57
@@ -6,18 +6,16 @@
package org.jetbrains.kotlin.analysis.api.fir.utils
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFir
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirSafe
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirPropertyAccessor
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.KtPropertyAccessor
import org.jetbrains.kotlin.psi.*
/**
* A hacky visitor which forces the resolve of declarations' bodies.
@@ -79,7 +77,7 @@ internal abstract class FirBodyReanalyzingVisitorVoid(private val firResolveSess
valueParameters.forEach { it.accept(thisVisitor) }
val simpleFunctionPsi = psi as? KtFunction
simpleFunctionPsi?.bodyExpression?.getOrBuildFir(firResolveSession)?.accept(thisVisitor)
reanalyzePsiBody(simpleFunctionPsi)?.accept(thisVisitor)
contractDescription.accept(thisVisitor)
annotations.forEach { it.accept(thisVisitor) }
@@ -97,7 +95,7 @@ internal abstract class FirBodyReanalyzingVisitorVoid(private val firResolveSess
receiverParameter?.accept(thisVisitor)
val propertyPsi = psi as? KtProperty
propertyPsi?.initializer?.getOrBuildFir(firResolveSession)?.accept(thisVisitor)
reanalyzePsiInitializer(propertyPsi)?.accept(thisVisitor)
reanalyzePsiAccessorOrUseDefault(propertyPsi?.getter, getter)?.accept(thisVisitor)
reanalyzePsiAccessorOrUseDefault(propertyPsi?.setter, setter)?.accept(thisVisitor)
@@ -113,13 +111,28 @@ internal abstract class FirBodyReanalyzingVisitorVoid(private val firResolveSess
* If there are default accessor present, we want to correctly visit it, because it can contain important
* information (annotations, for example).
*/
private fun reanalyzePsiAccessorOrUseDefault(psiAccessor: KtPropertyAccessor?, firAccessor: FirPropertyAccessor?): FirElement? =
private fun reanalyzePsiAccessorOrUseDefault(
psiAccessor: KtPropertyAccessor?,
firAccessor: FirPropertyAccessor?,
): FirPropertyAccessor? =
if (psiAccessor == null) {
firAccessor as? FirDefaultPropertyAccessor
} else {
psiAccessor.getOrBuildFir(firResolveSession)
// we want only FirPropertyAccessors and nothing else, see KTIJ-25823
psiAccessor.getOrBuildFirSafe<FirPropertyAccessor>(firResolveSession)
}
/**
* N.B. Reanalysing single-expression body returns a [FirExpression], not
* [org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock].
*/
private fun reanalyzePsiBody(declaration: KtDeclarationWithBody?): FirExpression? =
declaration?.bodyExpression?.getOrBuildFirSafe<FirExpression>(firResolveSession)
private fun reanalyzePsiInitializer(declaration: KtDeclarationWithInitializer?): FirExpression? =
declaration?.initializer?.getOrBuildFirSafe<FirExpression>(firResolveSession)
private fun FirPropertyAccessor.acceptChildrenAndForceBodyReanalysis() {
status.accept(thisVisitor)
returnTypeRef.accept(thisVisitor)
@@ -128,7 +141,7 @@ internal abstract class FirBodyReanalyzingVisitorVoid(private val firResolveSess
valueParameters.forEach { it.accept(thisVisitor) }
val propertyAccessorPsi = psi as? KtPropertyAccessor
propertyAccessorPsi?.bodyExpression?.getOrBuildFir(firResolveSession)?.accept(thisVisitor)
reanalyzePsiBody(propertyAccessorPsi)?.accept(thisVisitor)
contractDescription.accept(thisVisitor)
annotations.forEach { it.accept(thisVisitor) }