[FIR][LightTree] More fixes in diagnostic positioning

Keep tree padding for modifiers
More REFERENCE_EXPRESSIONS kinds
Fix source for some call expressions
This commit is contained in:
Andrey Zinovyev
2021-04-19 14:36:55 +03:00
committed by TeamCityServer
parent f3dc8dfb21
commit 0a68edf3bd
11 changed files with 50 additions and 21 deletions
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.fir.analysis
import com.intellij.lang.LighterASTNode
import com.intellij.psi.tree.IElementType
import com.intellij.psi.tree.TokenSet
import org.jetbrains.kotlin.fir.*
@@ -37,7 +38,13 @@ private fun FirPsiSourceElement<*>.getChild(types: Set<IElementType>, index: Int
private fun FirLightSourceElement.getChild(types: Set<IElementType>, index: Int, depth: Int): FirSourceElement? {
val visitor = LighterTreeElementFinderByType(treeStructure, types, index, depth)
val childNode = visitor.find(lighterASTNode) ?: return null
//we need to keep 'padding' of parent node in child node
return buildChildSourceElement(childNode)
}
/**
* Keeps 'padding' of parent node in child node
*/
internal fun FirLightSourceElement.buildChildSourceElement(childNode: LighterASTNode): FirLightSourceElement {
val offsetDelta = startOffset - lighterASTNode.startOffset
return childNode.toFirLightSourceElement(
treeStructure,
@@ -34,14 +34,15 @@ internal sealed class FirModifierList {
class FirLightModifierList(
val modifierList: LighterASTNode,
val tree: FlyweightCapableTreeStructure<LighterASTNode>
val tree: FlyweightCapableTreeStructure<LighterASTNode>,
private val offsetDelta: Int
) : FirModifierList() {
override val modifiers: List<FirModifier.FirLightModifier>
get() {
val modifierNodes = modifierList.getChildren(tree)
return modifierNodes.filterNotNull()
.filter { it.tokenType is KtModifierKeywordToken }
.map { FirModifier.FirLightModifier(it, it.tokenType as KtModifierKeywordToken, tree) }
.map { FirModifier.FirLightModifier(it, it.tokenType as KtModifierKeywordToken, tree, offsetDelta) }
}
}
@@ -65,10 +66,15 @@ internal sealed class FirModifier<Node : Any>(val node: Node, val token: KtModif
class FirLightModifier(
node: LighterASTNode,
token: KtModifierKeywordToken,
val tree: FlyweightCapableTreeStructure<LighterASTNode>
val tree: FlyweightCapableTreeStructure<LighterASTNode>,
private val offsetDelta: Int
) : FirModifier<LighterASTNode>(node, token) {
override val source: FirSourceElement
get() = node.toFirLightSourceElement(tree)
get() = node.toFirLightSourceElement(
tree,
startOffset = node.startOffset + offsetDelta,
endOffset = node.endOffset + offsetDelta
)
}
abstract val source: FirSourceElement
@@ -81,7 +87,8 @@ internal fun FirSourceElement?.getModifierList(): FirModifierList? {
is FirLightSourceElement -> {
val modifierListNode = lighterASTNode.getChildren(treeStructure).find { it?.tokenType == KtNodeTypes.MODIFIER_LIST }
?: return null
FirModifierList.FirLightModifierList(modifierListNode, treeStructure)
val offsetDelta = startOffset - lighterASTNode.startOffset
FirModifierList.FirLightModifierList(modifierListNode, treeStructure, offsetDelta)
}
}
}
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.lexer.KtTokens.MODALITY_MODIFIERS
import org.jetbrains.kotlin.lexer.KtTokens.VISIBILITY_MODIFIERS
import org.jetbrains.kotlin.psi.KtParameter.VAL_VAR_TOKEN_SET
import org.jetbrains.kotlin.psi.stubs.elements.KtConstantExpressionElementType
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
object LightTreePositioningStrategies {
@@ -625,6 +626,9 @@ private val REFERENCE_EXPRESSIONS = setOf(
KtNodeTypes.CONSTRUCTOR_DELEGATION_REFERENCE,
KtNodeTypes.SUPER_EXPRESSION,
KtNodeTypes.ARRAY_ACCESS_EXPRESSION,
KtNodeTypes.CALL_EXPRESSION,
KtNodeTypes.LABELED_EXPRESSION,
KtNodeTypes.DOT_QUALIFIED_EXPRESSION,
KtNodeTypes.FUN,
)
@@ -648,7 +652,9 @@ private fun FlyweightCapableTreeStructure<LighterASTNode>.referenceExpression(
val childrenRef = Ref<Array<LighterASTNode?>>()
getChildren(node, childrenRef)
var result = childrenRef.get()?.firstOrNull {
it?.tokenType in REFERENCE_EXPRESSIONS || it?.tokenType == KtNodeTypes.PARENTHESIZED
it?.tokenType in REFERENCE_EXPRESSIONS ||
it?.tokenType is KtConstantExpressionElementType ||
it?.tokenType == KtNodeTypes.PARENTHESIZED
}
while (locateReferencedName && result != null && result.tokenType == KtNodeTypes.PARENTHESIZED) {
result = referenceExpression(result, locateReferencedName = true)
@@ -19,7 +19,6 @@ import org.jetbrains.kotlin.fir.types.builder.buildImplicitTypeRef
import org.jetbrains.kotlin.lexer.KtToken
import org.jetbrains.kotlin.lexer.KtTokens.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.stubs.elements.KtFunctionElementType
import kotlin.contracts.ExperimentalContracts
abstract class BaseConverter(
@@ -81,6 +80,15 @@ abstract class BaseConverter(
return null
}
protected fun LighterASTNode.getFirstChildExpressionUnwrapped(): LighterASTNode? {
val expression = getFirstChildExpression() ?: return null
return if (expression.tokenType == KtNodeTypes.PARENTHESIZED) {
expression.getFirstChildExpressionUnwrapped()
} else {
expression
}
}
private fun LighterASTNode.getLastChildExpression(): LighterASTNode? {
var result: LighterASTNode? = null
forEachChildren {
@@ -548,7 +548,7 @@ class ExpressionsConverter(
val (calleeReference, explicitReceiver, isImplicitInvoke) = when {
name != null -> CalleeAndReceiver(
buildSimpleNamedReference {
this.source = source
this.source = callSuffix.getFirstChildExpressionUnwrapped()?.toFirSourceElement() ?: source
this.name = name.nameAsSafeName()
}
)
@@ -4,7 +4,8 @@ package h
class Square() {
var size : Double =
<!UNRESOLVED_REFERENCE!>set<!>(<!UNRESOLVED_REFERENCE!>value<!>) {
<!SYNTAX!>$area<!> <!SYNTAX!>= size * size<!>
//in LT this LAMBDA_EXPRESSION get parsed lazyly, but doesn't got anywhere in FIR tree (as property doesn't have place for it)
<!SYNTAX{PSI}!>$area<!> <!SYNTAX{PSI}!>= size * size<!>
}
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>var area : Double<!>
@@ -15,4 +16,4 @@ fun main() {
val s = Square()
s.size = 2.0
}
}
@@ -6,9 +6,9 @@ enum class Enum {
<!NESTED_CLASS_NOT_ALLOWED!>class TestNested<!>
<!NESTED_CLASS_NOT_ALLOWED!>interface TestInterface<!>
<!LOCAL_INTERFACE_NOT_ALLOWED, NESTED_CLASS_NOT_ALLOWED!>interface TestInterface<!>
object TestObject
<!LOCAL_OBJECT_NOT_ALLOWED!>object TestObject<!>
enum class TestEnumClass {
OTHER_ENTRY
@@ -6,9 +6,9 @@ enum class Enum {
<!NESTED_CLASS_NOT_ALLOWED!>class TestNested<!>
<!NESTED_CLASS_NOT_ALLOWED!>interface TestInterface<!>
<!LOCAL_INTERFACE_NOT_ALLOWED, NESTED_CLASS_NOT_ALLOWED!>interface TestInterface<!>
object TestObject
<!LOCAL_OBJECT_NOT_ALLOWED!>object TestObject<!>
enum class TestEnumClass {
OTHER_ENTRY
@@ -6,9 +6,9 @@ enum class Enum {
<!NESTED_CLASS_NOT_ALLOWED!>class TestNested<!>
<!NESTED_CLASS_NOT_ALLOWED!>interface TestInterface<!>
<!LOCAL_INTERFACE_NOT_ALLOWED, NESTED_CLASS_NOT_ALLOWED!>interface TestInterface<!>
object TestObject
<!LOCAL_OBJECT_NOT_ALLOWED!>object TestObject<!>
enum class TestEnumClass {
OTHER_ENTRY
+3 -3
View File
@@ -6,13 +6,13 @@ package toplevelObjectDeclarations
<!NO_VALUE_FOR_PARAMETER!>class T : <!SUPERTYPE_NOT_INITIALIZED!>Foo<!> {}<!>
object A : <!SUPERTYPE_NOT_INITIALIZED!>Foo<!> {
<!NO_VALUE_FOR_PARAMETER{LT}!>object A : <!SUPERTYPE_NOT_INITIALIZED!>Foo<!> {
val x : Int = 2
fun test() : Int {
return x + foo(<!NO_VALUE_FOR_PARAMETER!>)<!>
return x + foo(<!NO_VALUE_FOR_PARAMETER{PSI}!>)<!>
}
}
}<!>
object B : A {}
@@ -25,5 +25,5 @@ val z = z
fun block(f : () -> Unit) = f()
fun bar3() = block{ <!UNRESOLVED_REFERENCE!>foo3<!>() // <-- missing closing curly bracket
fun foo3() = block{ bar3() }<!SYNTAX!><!>
fun foo3() = block{ bar3() }<!SYNTAX{PSI}!><!>