diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/element/builder/FirElementBuilder.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/element/builder/FirElementBuilder.kt index 970c1e27484..a78928bbfdd 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/element/builder/FirElementBuilder.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/element/builder/FirElementBuilder.kt @@ -36,7 +36,6 @@ import org.jetbrains.kotlin.fir.resolve.providers.firProvider import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase import org.jetbrains.kotlin.fir.types.FirTypeRef 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.parentsWithSelf @@ -307,15 +306,3 @@ internal fun PsiElement.getNonLocalContainingOrThisDeclaration(predicate: (KtDec 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 - } - } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileElementFactory.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileElementFactory.kt index ce93b68a2a4..84975c74c0d 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileElementFactory.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileElementFactory.kt @@ -5,18 +5,19 @@ 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.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.api.collectDesignationWithFile 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.impl.FirPrimaryConstructor import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.isAncestor internal object FileElementFactory { - /** - * should be consistent with [isReanalyzableContainer] - */ fun createFileStructureElement( firDeclaration: FirDeclaration, 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 -fun isReanalyzableContainer( - ktDeclaration: KtDeclaration, -): Boolean = when (ktDeclaration) { - is KtNamedFunction -> ktDeclaration.isReanalyzableContainer() - is KtProperty -> ktDeclaration.isReanalyzableContainer() - else -> false +@LLFirInternals +@Suppress("unused") // Used in the IDE plugin +fun PsiElement.getNonLocalReanalyzableContainingDeclaration(): KtDeclaration? { + return when (val declaration = getNonLocalContainingOrThisDeclaration()) { + is KtNamedFunction -> declaration.takeIf { function -> + function.isReanalyzableContainer() && function.bodyExpression?.isAncestor(this) == true + } + + 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() = - name != null && hasExplicitTypeOrUnit +private fun KtNamedFunction.isReanalyzableContainer(): Boolean = name != null && (hasBlockBody() || typeReference != null) -private fun KtProperty.isReanalyzableContainer() = - name != null && typeReference != null +private fun KtPropertyAccessor.isReanalyzableContainer(): Boolean { + 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 diff --git a/analysis/low-level-api-fir/testdata/fileStructure/classMemberProperty.kt b/analysis/low-level-api-fir/testdata/fileStructure/classMemberProperty.kt index 04eb8421779..1f7dda523f8 100644 --- a/analysis/low-level-api-fir/testdata/fileStructure/classMemberProperty.kt +++ b/analysis/low-level-api-fir/testdata/fileStructure/classMemberProperty.kt @@ -7,5 +7,5 @@ class X {/* NonReanalyzableClassDeclarationStructureElement */ val y = 42/* NonReanalyzableNonClassDeclarationStructureElement */ - var z: Int = 15/* ReanalyzablePropertyStructureElement */ + var z: Int = 15/* NonReanalyzableNonClassDeclarationStructureElement */ } diff --git a/analysis/low-level-api-fir/testdata/fileStructure/propertyAccessors.kt b/analysis/low-level-api-fir/testdata/fileStructure/propertyAccessors.kt index baa56881652..411f5aaa16c 100644 --- a/analysis/low-level-api-fir/testdata/fileStructure/propertyAccessors.kt +++ b/analysis/low-level-api-fir/testdata/fileStructure/propertyAccessors.kt @@ -5,7 +5,7 @@ var x: Int = 10/* ReanalyzablePropertyStructureElement */ } class X {/* NonReanalyzableClassDeclarationStructureElement */ - var y: Int = 10/* ReanalyzablePropertyStructureElement */ + var y: Int = 10/* NonReanalyzableNonClassDeclarationStructureElement */ get() = field set(value) { field = value diff --git a/analysis/low-level-api-fir/testdata/fileStructure/superClassCall.kt b/analysis/low-level-api-fir/testdata/fileStructure/superClassCall.kt index 2df75c08190..c1b267c6426 100644 --- a/analysis/low-level-api-fir/testdata/fileStructure/superClassCall.kt +++ b/analysis/low-level-api-fir/testdata/fileStructure/superClassCall.kt @@ -1,7 +1,7 @@ open class A (init: A.() -> Unit)/* NonReanalyzableNonClassDeclarationStructureElement */ {/* NonReanalyzableClassDeclarationStructureElement */ - val prop: String = ""/* ReanalyzablePropertyStructureElement */ + val prop: String = ""/* NonReanalyzableNonClassDeclarationStructureElement */ } class B()/* NonReanalyzableNonClassDeclarationStructureElement */ : A()/* NonReanalyzableClassDeclarationStructureElement */