[LL FIR] move in-block analysis declarations closer to service

^KT-61842
This commit is contained in:
Dmitrii Gridin
2023-09-15 17:59:45 +02:00
parent 0db4f464bb
commit f7fe33bd98
2 changed files with 55 additions and 52 deletions
@@ -5,17 +5,12 @@
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.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.psiUtil.isAncestor
import org.jetbrains.kotlin.psi.psiUtil.isContractDescriptionCallPsiCheck
internal object FileElementFactory { internal object FileElementFactory {
fun createFileStructureElement( fun createFileStructureElement(
@@ -74,50 +69,3 @@ internal object FileElementFactory {
) )
} }
} }
/**
* Covered by org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.AbstractInBlockModificationTest
* on the compiler side and by
* org.jetbrains.kotlin.idea.fir.analysis.providers.trackers.AbstractProjectWideOutOfBlockKotlinModificationTrackerTest
* on the plugin part
*
* @return The declaration in which a change of the passed receiver parameter can be treated as in-block modification
*/
internal fun PsiElement.getNonLocalReanalyzableContainingDeclaration(): KtDeclaration? {
return when (val declaration = getNonLocalContainingOrThisDeclaration()) {
is KtNamedFunction -> declaration.takeIf { function ->
function.isReanalyzableContainer() && isElementInsideBody(declaration = function, child = this)
}
is KtPropertyAccessor -> declaration.takeIf { accessor ->
accessor.isReanalyzableContainer() && isElementInsideBody(declaration = accessor, child = this)
}
is KtProperty -> declaration.takeIf { property ->
property.isReanalyzableContainer() && property.delegateExpressionOrInitializer?.isAncestor(this) == true
}
else -> null
}
}
private fun isElementInsideBody(declaration: KtDeclarationWithBody, child: PsiElement): Boolean {
val body = declaration.bodyExpression ?: return false
if (!body.isAncestor(child)) return false
return !isInsideContract(body = body, child = child)
}
private fun isInsideContract(body: KtExpression, child: PsiElement): Boolean {
if (body !is KtBlockExpression) return false
val firstStatement = body.firstStatement ?: return false
if (!firstStatement.isContractDescriptionCallPsiCheck()) return false
return firstStatement.isAncestor(child)
}
private fun KtNamedFunction.isReanalyzableContainer(): Boolean = hasBlockBody() || typeReference != null
private fun KtPropertyAccessor.isReanalyzableContainer(): Boolean = isSetter || hasBlockBody() || property.typeReference != null
private fun KtProperty.isReanalyzableContainer(): Boolean = typeReference != null && !hasDelegateExpressionOrInitializer()
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirInternals
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getFirResolveSession import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getFirResolveSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirFile import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.resolveToFirSymbol import org.jetbrains.kotlin.analysis.low.level.api.fir.api.resolveToFirSymbol
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.getNonLocalContainingOrThisDeclaration
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.LLFirDeclarationModificationService.ModificationType import org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.LLFirDeclarationModificationService.ModificationType
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirResolvableModuleSession import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirResolvableModuleSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.llFirResolvableSession import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.llFirResolvableSession
@@ -27,9 +28,17 @@ import org.jetbrains.kotlin.analysis.providers.analysisMessageBus
import org.jetbrains.kotlin.analysis.providers.topics.KotlinTopics.MODULE_OUT_OF_BLOCK_MODIFICATION import org.jetbrains.kotlin.analysis.providers.topics.KotlinTopics.MODULE_OUT_OF_BLOCK_MODIFICATION
import org.jetbrains.kotlin.idea.KotlinLanguage import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.psi.KtAnnotated import org.jetbrains.kotlin.psi.KtAnnotated
import org.jetbrains.kotlin.psi.KtBlockExpression
import org.jetbrains.kotlin.psi.KtCodeFragment import org.jetbrains.kotlin.psi.KtCodeFragment
import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtDeclarationWithBody
import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.KtPropertyAccessor
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
import org.jetbrains.kotlin.psi.psiUtil.isContractDescriptionCallPsiCheck
/** /**
* This service is responsible for processing incoming [PsiElement] changes to reflect them on FIR tree. * This service is responsible for processing incoming [PsiElement] changes to reflect them on FIR tree.
@@ -221,3 +230,49 @@ private sealed class ChangeType {
override fun hashCode(): Int = blockOwner.hashCode() override fun hashCode(): Int = blockOwner.hashCode()
} }
} }
/**
* Covered by org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.AbstractInBlockModificationTest
* on the compiler side and by
* org.jetbrains.kotlin.idea.fir.analysis.providers.trackers.AbstractProjectWideOutOfBlockKotlinModificationTrackerTest
* on the plugin part
*
* @return The declaration in which a change of the passed receiver parameter can be treated as in-block modification
*/
internal fun PsiElement.getNonLocalReanalyzableContainingDeclaration(): KtDeclaration? {
return when (val declaration = getNonLocalContainingOrThisDeclaration()) {
is KtNamedFunction -> declaration.takeIf { function ->
function.isReanalyzableContainer() && isElementInsideBody(declaration = function, child = this)
}
is KtPropertyAccessor -> declaration.takeIf { accessor ->
accessor.isReanalyzableContainer() && isElementInsideBody(declaration = accessor, child = this)
}
is KtProperty -> declaration.takeIf { property ->
property.isReanalyzableContainer() && property.delegateExpressionOrInitializer?.isAncestor(this) == true
}
else -> null
}
}
private fun isElementInsideBody(declaration: KtDeclarationWithBody, child: PsiElement): Boolean {
val body = declaration.bodyExpression ?: return false
if (!body.isAncestor(child)) return false
return !isInsideContract(body = body, child = child)
}
private fun isInsideContract(body: KtExpression, child: PsiElement): Boolean {
if (body !is KtBlockExpression) return false
val firstStatement = body.firstStatement ?: return false
if (!firstStatement.isContractDescriptionCallPsiCheck()) return false
return firstStatement.isAncestor(child)
}
private fun KtNamedFunction.isReanalyzableContainer(): Boolean = hasBlockBody() || typeReference != null
private fun KtPropertyAccessor.isReanalyzableContainer(): Boolean = isSetter || hasBlockBody() || property.typeReference != null
private fun KtProperty.isReanalyzableContainer(): Boolean = typeReference != null && !hasDelegateExpressionOrInitializer()