[LL FIR] do not reanalyze non-top level properties with initializer
Treat changes inside non-top level property initializer as OOB It is OOB because CFG for a class depends on a property initializer, so we must rebuild CFG for the class Also, this commit makes the API more understandable ^KT-59687
This commit is contained in:
-13
@@ -36,7 +36,6 @@ import org.jetbrains.kotlin.fir.resolve.providers.firProvider
|
|||||||
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
|
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
|
||||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.isObjectLiteral
|
import org.jetbrains.kotlin.psi.psiUtil.isObjectLiteral
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||||
|
|
||||||
@@ -307,15 +306,3 @@ internal fun PsiElement.getNonLocalContainingOrThisDeclaration(predicate: (KtDec
|
|||||||
|
|
||||||
return candidate
|
return candidate
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("unused") // Used in the IDE plugin
|
|
||||||
fun PsiElement.getNonLocalContainingInBodyDeclarationWith(): KtDeclaration? =
|
|
||||||
getNonLocalContainingOrThisDeclaration { declaration ->
|
|
||||||
when (declaration) {
|
|
||||||
is KtNamedFunction -> declaration.bodyExpression?.isAncestor(this) == true
|
|
||||||
is KtProperty -> declaration.initializer?.isAncestor(this) == true ||
|
|
||||||
declaration.getter?.bodyExpression?.isAncestor(this) == true ||
|
|
||||||
declaration.setter?.bodyExpression?.isAncestor(this) == true
|
|
||||||
else -> false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
+31
-17
@@ -5,18 +5,19 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure
|
package org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
||||||
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirInternals
|
||||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirModuleResolveComponents
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirModuleResolveComponents
|
||||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.collectDesignationWithFile
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.collectDesignationWithFile
|
||||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirClassWithSpecificMembersResolveTarget
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirClassWithSpecificMembersResolveTarget
|
||||||
|
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.getNonLocalContainingOrThisDeclaration
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.declarations.impl.FirPrimaryConstructor
|
import org.jetbrains.kotlin.fir.declarations.impl.FirPrimaryConstructor
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
||||||
|
|
||||||
internal object FileElementFactory {
|
internal object FileElementFactory {
|
||||||
/**
|
|
||||||
* should be consistent with [isReanalyzableContainer]
|
|
||||||
*/
|
|
||||||
fun createFileStructureElement(
|
fun createFileStructureElement(
|
||||||
firDeclaration: FirDeclaration,
|
firDeclaration: FirDeclaration,
|
||||||
ktDeclaration: KtDeclaration,
|
ktDeclaration: KtDeclaration,
|
||||||
@@ -103,22 +104,35 @@ internal object FileElementFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* should be consistent with [createFileStructureElement]
|
* @return The declaration in which a change of the passed receiver parameter can be treated as in-block modification
|
||||||
*/
|
*/
|
||||||
//TODO make internal
|
@LLFirInternals
|
||||||
fun isReanalyzableContainer(
|
@Suppress("unused") // Used in the IDE plugin
|
||||||
ktDeclaration: KtDeclaration,
|
fun PsiElement.getNonLocalReanalyzableContainingDeclaration(): KtDeclaration? {
|
||||||
): Boolean = when (ktDeclaration) {
|
return when (val declaration = getNonLocalContainingOrThisDeclaration()) {
|
||||||
is KtNamedFunction -> ktDeclaration.isReanalyzableContainer()
|
is KtNamedFunction -> declaration.takeIf { function ->
|
||||||
is KtProperty -> ktDeclaration.isReanalyzableContainer()
|
function.isReanalyzableContainer() && function.bodyExpression?.isAncestor(this) == true
|
||||||
else -> false
|
}
|
||||||
|
|
||||||
|
is KtPropertyAccessor -> declaration.takeIf { accessor ->
|
||||||
|
accessor.isReanalyzableContainer() && accessor.bodyExpression?.isAncestor(this) == true
|
||||||
|
}
|
||||||
|
|
||||||
|
is KtProperty -> declaration.takeIf { property ->
|
||||||
|
property.isReanalyzableContainer() && property.delegateExpressionOrInitializer?.isAncestor(this) == true
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun KtNamedFunction.isReanalyzableContainer() =
|
private fun KtNamedFunction.isReanalyzableContainer(): Boolean = name != null && (hasBlockBody() || typeReference != null)
|
||||||
name != null && hasExplicitTypeOrUnit
|
|
||||||
|
|
||||||
private fun KtProperty.isReanalyzableContainer() =
|
private fun KtPropertyAccessor.isReanalyzableContainer(): Boolean {
|
||||||
name != null && typeReference != null
|
val property = property
|
||||||
|
return property.name != null && (hasBlockBody() || property.typeReference != null)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun KtProperty.isReanalyzableContainer(): Boolean =
|
||||||
|
name != null && typeReference != null && (isTopLevel || !hasDelegateExpressionOrInitializer())
|
||||||
|
|
||||||
private val KtNamedFunction.hasExplicitTypeOrUnit
|
|
||||||
get() = hasBlockBody() || typeReference != null
|
|
||||||
|
|||||||
@@ -7,5 +7,5 @@ class X {/* NonReanalyzableClassDeclarationStructureElement */
|
|||||||
|
|
||||||
val y = 42/* NonReanalyzableNonClassDeclarationStructureElement */
|
val y = 42/* NonReanalyzableNonClassDeclarationStructureElement */
|
||||||
|
|
||||||
var z: Int = 15/* ReanalyzablePropertyStructureElement */
|
var z: Int = 15/* NonReanalyzableNonClassDeclarationStructureElement */
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ var x: Int = 10/* ReanalyzablePropertyStructureElement */
|
|||||||
}
|
}
|
||||||
|
|
||||||
class X {/* NonReanalyzableClassDeclarationStructureElement */
|
class X {/* NonReanalyzableClassDeclarationStructureElement */
|
||||||
var y: Int = 10/* ReanalyzablePropertyStructureElement */
|
var y: Int = 10/* NonReanalyzableNonClassDeclarationStructureElement */
|
||||||
get() = field
|
get() = field
|
||||||
set(value) {
|
set(value) {
|
||||||
field = value
|
field = value
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
open class A
|
open class A
|
||||||
(init: A.() -> Unit)/* NonReanalyzableNonClassDeclarationStructureElement */
|
(init: A.() -> Unit)/* NonReanalyzableNonClassDeclarationStructureElement */
|
||||||
{/* NonReanalyzableClassDeclarationStructureElement */
|
{/* NonReanalyzableClassDeclarationStructureElement */
|
||||||
val prop: String = ""/* ReanalyzablePropertyStructureElement */
|
val prop: String = ""/* NonReanalyzableNonClassDeclarationStructureElement */
|
||||||
}
|
}
|
||||||
|
|
||||||
class B()/* NonReanalyzableNonClassDeclarationStructureElement */ : A()/* NonReanalyzableClassDeclarationStructureElement */
|
class B()/* NonReanalyzableNonClassDeclarationStructureElement */ : A()/* NonReanalyzableClassDeclarationStructureElement */
|
||||||
|
|||||||
Reference in New Issue
Block a user