diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/FirSourceChildren.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/FirSourceChildren.kt index 40d8c8f5d2f..b698d7cfff1 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/FirSourceChildren.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/FirSourceChildren.kt @@ -35,7 +35,7 @@ private fun FirPsiSourceElement<*>.getChild(types: Set, index: Int } private fun FirLightSourceElement.getChild(types: Set, index: Int, depth: Int): FirSourceElement? { - val visitor = LighterTreeElementFinderByType(tree, types, index, depth) + val visitor = LighterTreeElementFinderByType(treeStructure, types, index, depth) - return visitor.find(lighterASTNode)?.let { it.toFirLightSourceElement(it.startOffset, it.endOffset, tree) } + return visitor.find(lighterASTNode)?.let { it.toFirLightSourceElement(it.startOffset, it.endOffset, treeStructure) } } \ No newline at end of file diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirModifierList.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirModifierList.kt index dba6f998b87..ec7b5f02374 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirModifierList.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirModifierList.kt @@ -28,9 +28,9 @@ fun FirSourceElement?.getModifierList(): FirModifierList? { is FirPsiSourceElement<*> -> (psi as? KtModifierListOwner)?.modifierList?.let { FirPsiModifierList(it) } is FirLightSourceElement -> { val kidsRef = Ref>() - tree.getChildren(lighterASTNode, kidsRef) + treeStructure.getChildren(lighterASTNode, kidsRef) val modifierListNode = kidsRef.get().find { it?.tokenType == KtNodeTypes.MODIFIER_LIST } ?: return null - FirLightModifierList(modifierListNode, tree) + FirLightModifierList(modifierListNode, treeStructure) } } } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirAnnotationArgumentChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirAnnotationArgumentChecker.kt index 0d2a46e10b9..6ec8f2a054c 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirAnnotationArgumentChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirAnnotationArgumentChecker.kt @@ -241,9 +241,9 @@ object FirAnnotationArgumentChecker : FirBasicDeclarationChecker() { is FirPsiSourceElement<*> -> source.psi.parent.toFirPsiSourceElement() is FirLightSourceElement -> { - val elementOfParent = source.tree.getParent(source.lighterASTNode) ?: source.lighterASTNode + val elementOfParent = source.treeStructure.getParent(source.lighterASTNode) ?: source.lighterASTNode - elementOfParent.toFirLightSourceElement(elementOfParent.startOffset, elementOfParent.endOffset, source.tree) + elementOfParent.toFirLightSourceElement(elementOfParent.startOffset, elementOfParent.endOffset, source.treeStructure) } else -> source diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirAnnotationClassDeclarationChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirAnnotationClassDeclarationChecker.kt index 83c75be6085..124933ff5ed 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirAnnotationClassDeclarationChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirAnnotationClassDeclarationChecker.kt @@ -53,7 +53,7 @@ object FirAnnotationClassDeclarationChecker : FirBasicDeclarationChecker() { } is FirLightSourceElement -> { val kidsRef = Ref>() - parameterSourceElement.tree.getChildren(parameterSourceElement.lighterASTNode, kidsRef) + parameterSourceElement.treeStructure.getChildren(parameterSourceElement.lighterASTNode, kidsRef) if (kidsRef.get().any { it?.tokenType == VAR_KEYWORD }) reporter.report(parameterSourceElement, FirErrors.VAR_ANNOTATION_PARAMETER) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConstructorInInterfaceChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConstructorInInterfaceChecker.kt index 7ada834666c..36caea305fe 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConstructorInInterfaceChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirConstructorInInterfaceChecker.kt @@ -40,7 +40,7 @@ object FirConstructorInInterfaceChecker : FirBasicDeclarationChecker() { if (localPsi != null && localPsi !is PsiErrorElement) { return localPsi.hasPrimaryConstructor() } else if (this is FirLightSourceElement) { - return localLightNode.hasPrimaryConstructor(tree) + return localLightNode.hasPrimaryConstructor(treeStructure) } return false diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDelegationInInterfaceChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDelegationInInterfaceChecker.kt index c98213ba7fd..476966fbe53 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDelegationInInterfaceChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDelegationInInterfaceChecker.kt @@ -40,7 +40,7 @@ object FirDelegationInInterfaceChecker : FirMemberDeclarationChecker() { if (localPsi != null && localPsi !is PsiErrorElement) { return localPsi.findSuperTypeDelegation() } else if (this is FirLightSourceElement) { - return localLightNode.findSuperTypeDelegation(tree) + return localLightNode.findSuperTypeDelegation(treeStructure) } return -1 diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirExposedVisibilityDeclarationChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirExposedVisibilityDeclarationChecker.kt index 46b8c798cbb..ea7ad8510fa 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirExposedVisibilityDeclarationChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirExposedVisibilityDeclarationChecker.kt @@ -234,9 +234,9 @@ object FirExposedVisibilityDeclarationChecker : FirMemberDeclarationChecker() { is FirPsiSourceElement<*> -> (this.psi as? PsiNameIdentifierOwner)?.nameIdentifier?.toFirPsiSourceElement() is FirLightSourceElement -> { val kidsRef = Ref>() - this.tree.getChildren(lighterASTNode, kidsRef) + this.treeStructure.getChildren(lighterASTNode, kidsRef) val identifier = kidsRef.get().find { it?.tokenType == KtTokens.IDENTIFIER } - identifier?.toFirLightSourceElement(this.tree.getStartOffset(identifier), this.tree.getEndOffset(identifier), this.tree) + identifier?.toFirLightSourceElement(this.treeStructure.getStartOffset(identifier), this.treeStructure.getEndOffset(identifier), this.treeStructure) } } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirSupertypeInitializedInInterfaceChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirSupertypeInitializedInInterfaceChecker.kt index b69a4575cdc..6a1a4deb5d6 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirSupertypeInitializedInInterfaceChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirSupertypeInitializedInInterfaceChecker.kt @@ -40,7 +40,7 @@ object FirSupertypeInitializedInInterfaceChecker : FirMemberDeclarationChecker() if (localPsi != null && localPsi !is PsiErrorElement) { return localPsi.findSuperTypeCall() } else if (this is FirLightSourceElement) { - return localLightNode.findSuperTypeCall(tree) + return localLightNode.findSuperTypeCall(treeStructure) } return -1 diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirSupertypeInitializedWithoutPrimaryConstructor.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirSupertypeInitializedWithoutPrimaryConstructor.kt index 898935b1019..b3f44874443 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirSupertypeInitializedWithoutPrimaryConstructor.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirSupertypeInitializedWithoutPrimaryConstructor.kt @@ -44,7 +44,7 @@ object FirSupertypeInitializedWithoutPrimaryConstructor : FirMemberDeclarationCh if (localPsi != null && localPsi !is PsiErrorElement) { return localPsi.anySupertypeHasConstructorParentheses() } else if (this is FirLightSourceElement) { - return localLightNode.anySupertypeHasConstructorParentheses(tree) + return localLightNode.anySupertypeHasConstructorParentheses(treeStructure) } return false diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirTypeArgumentsNotAllowedExpressionChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirTypeArgumentsNotAllowedExpressionChecker.kt index b902ba825ef..0e3f306a8ba 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirTypeArgumentsNotAllowedExpressionChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirTypeArgumentsNotAllowedExpressionChecker.kt @@ -42,7 +42,7 @@ object FirTypeArgumentsNotAllowedExpressionChecker : FirQualifiedAccessChecker() if (localPsi != null && localPsi !is PsiErrorElement) { return localPsi.hasAnyArguments() } else if (this is FirLightSourceElement) { - return localLight.hasAnyArguments(this.tree) + return localLight.hasAnyArguments(this.treeStructure) } return false diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/CanBeReplacedWithOperatorAssignmentChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/CanBeReplacedWithOperatorAssignmentChecker.kt index 873695acb44..0486053f2f3 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/CanBeReplacedWithOperatorAssignmentChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/CanBeReplacedWithOperatorAssignmentChecker.kt @@ -71,7 +71,7 @@ object CanBeReplacedWithOperatorAssignmentChecker : FirExpressionChecker>() tree.getChildren(expression, childrenNullable) val children = childrenNullable.get().filterNotNull() diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/CanBeValChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/CanBeValChecker.kt index c746feb47e7..1ed0369812b 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/CanBeValChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/CanBeValChecker.kt @@ -102,7 +102,7 @@ object CanBeValChecker : AbstractFirPropertyInitializationChecker() { is FirPsiSourceElement<*> -> fir.psi?.children?.size?.minus(1) // -1 cuz we don't need expression node after equals operator is FirLightSourceElement -> { val source = fir.source as FirLightSourceElement - val tree = (fir.source as FirLightSourceElement).tree + val tree = (fir.source as FirLightSourceElement).treeStructure val children = Ref>() tree.getChildren(source.lighterASTNode, children) children.get().filterNotNull().filter { it.tokenType == KtNodeTypes.DESTRUCTURING_DECLARATION_ENTRY }.size diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/RedundantSingleExpressionStringTemplateChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/RedundantSingleExpressionStringTemplateChecker.kt index 301e9f554fe..be4b8c50a43 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/RedundantSingleExpressionStringTemplateChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/extended/RedundantSingleExpressionStringTemplateChecker.kt @@ -54,10 +54,10 @@ object RedundantSingleExpressionStringTemplateChecker : FirBasicExpressionChecke } private fun LighterASTNode.stringParentChildrenCount(source: FirLightSourceElement): Int? { - val parent = source.tree.getParent(this) + val parent = source.treeStructure.getParent(this) return if (parent?.tokenType == KtNodeTypes.STRING_TEMPLATE) { val childrenOfParent = Ref>() - source.tree.getChildren(parent!!, childrenOfParent) + source.treeStructure.getChildren(parent!!, childrenOfParent) childrenOfParent.get().filter { it is PsiBuilder.Marker }.size } else { parent?.stringParentChildrenCount(source) diff --git a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/fir/ValueParameter.kt b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/fir/ValueParameter.kt index a579dbd9a7c..9573f985fba 100644 --- a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/fir/ValueParameter.kt +++ b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/fir/ValueParameter.kt @@ -46,7 +46,7 @@ class ValueParameter( val parameterSource = firValueParameter.source as? FirLightSourceElement val parameterNode = parameterSource?.lighterASTNode source = parameterNode?.toFirLightSourceElement( - parameterSource.startOffset, parameterSource.endOffset, parameterSource.tree, + parameterSource.startOffset, parameterSource.endOffset, parameterSource.treeStructure, FirFakeSourceElementKind.PropertyFromParameter ) this.session = session diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirSourceElement.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirSourceElement.kt index 4ab52409b97..b4ac9b28b32 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirSourceElement.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirSourceElement.kt @@ -7,7 +7,9 @@ package org.jetbrains.kotlin.fir import com.intellij.lang.LighterASTNode import com.intellij.lang.TreeBackedLighterAST +import com.intellij.openapi.util.Ref import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile import com.intellij.psi.tree.IElementType import com.intellij.util.diff.FlyweightCapableTreeStructure @@ -154,6 +156,7 @@ sealed class FirSourceElement { abstract val endOffset: Int abstract val kind: FirSourceElementKind abstract val lighterASTNode: LighterASTNode + abstract val treeStructure: FlyweightCapableTreeStructure } // NB: in certain situations, psi.node could be null @@ -169,6 +172,37 @@ sealed class FirPsiSourceElement(val psi: P) : FirSourceElem get() = psi.textRange.endOffset override val lighterASTNode by lazy { TreeBackedLighterAST.wrap(psi.node) } + + override val treeStructure: FlyweightCapableTreeStructure by lazy { WrappedTreeStructure(psi.containingFile) } + + private class WrappedTreeStructure(file: PsiFile) : FlyweightCapableTreeStructure { + private val lighterAST = TreeBackedLighterAST(file.node) + + private fun LighterASTNode.unwrap() = lighterAST.unwrap(this) + + override fun toString(node: LighterASTNode): CharSequence = node.unwrap().text + + override fun getRoot(): LighterASTNode = lighterAST.root + + override fun getParent(node: LighterASTNode): LighterASTNode? = node.unwrap().psi.parent?.node?.let { TreeBackedLighterAST.wrap(it) } + + override fun getChildren(node: LighterASTNode, nodesRef: Ref>): Int { + val children = node.unwrap().psi.children + if (children.isEmpty()) { + nodesRef.set(LighterASTNode.EMPTY_ARRAY) + } else { + nodesRef.set(children.map { TreeBackedLighterAST.wrap(it.node) }.toTypedArray()) + } + return children.size + } + + override fun disposeChildren(p0: Array?, p1: Int) { + } + + override fun getStartOffset(node: LighterASTNode): Int = node.unwrap().startOffset + + override fun getEndOffset(node: LighterASTNode): Int = node.unwrap().let { it.startOffset + it.textLength - 1 } + } } class FirRealPsiSourceElement(psi: P) : FirPsiSourceElement

(psi) { @@ -179,7 +213,7 @@ class FirFakeSourceElement(psi: P, override val kind: FirFak fun FirSourceElement.fakeElement(newKind: FirFakeSourceElementKind): FirSourceElement { return when (this) { - is FirLightSourceElement -> FirLightSourceElement(lighterASTNode, startOffset, endOffset, tree, newKind) + is FirLightSourceElement -> FirLightSourceElement(lighterASTNode, startOffset, endOffset, treeStructure, newKind) is FirPsiSourceElement<*> -> FirFakeSourceElement(psi, newKind) } } @@ -188,7 +222,7 @@ class FirLightSourceElement( override val lighterASTNode: LighterASTNode, override val startOffset: Int, override val endOffset: Int, - val tree: FlyweightCapableTreeStructure, + override val treeStructure: FlyweightCapableTreeStructure, override val kind: FirSourceElementKind = FirRealSourceElementKind, ) : FirSourceElement() { override val elementType: IElementType