Uast: proper identifiers for KotlinUBinaryExpression (KT-25092)

This commit is contained in:
Nicolay Mitropolsky
2018-06-26 12:22:16 +03:00
parent eb92b7ed7f
commit bef3d4ace2
5 changed files with 22 additions and 8 deletions
@@ -361,6 +361,8 @@ internal object KotlinConverter {
if (element.elementType != KtTokens.OBJECT_KEYWORD || element.getParentOfType<KtObjectDeclaration>(false)?.nameIdentifier == null) if (element.elementType != KtTokens.OBJECT_KEYWORD || element.getParentOfType<KtObjectDeclaration>(false)?.nameIdentifier == null)
el<UIdentifier>(build(::KotlinUIdentifier)) el<UIdentifier>(build(::KotlinUIdentifier))
else null else null
else if (element.elementType in KtTokens.OPERATIONS && element.parent is KtOperationReferenceExpression)
el<UIdentifier>(build(::KotlinUIdentifier))
else if (element.elementType == KtTokens.LBRACKET && element.parent is KtCollectionLiteralExpression) else if (element.elementType == KtTokens.LBRACKET && element.parent is KtCollectionLiteralExpression)
el<UIdentifier> { el<UIdentifier> {
UIdentifier( UIdentifier(
@@ -43,7 +43,7 @@ class KotlinUBinaryExpression(
override val rightOperand by lz { KotlinConverter.convertOrEmpty(psi.right, this) } override val rightOperand by lz { KotlinConverter.convertOrEmpty(psi.right, this) }
override val operatorIdentifier: UIdentifier? override val operatorIdentifier: UIdentifier?
get() = KotlinUIdentifier(psi.operationReference, this) get() = KotlinUIdentifier(psi.operationReference.getReferencedNameElement(), this)
override fun resolveOperator() = psi.operationReference.resolveCallToDeclaration(context = this) as? PsiMethod override fun resolveOperator() = psi.operationReference.resolveCallToDeclaration(context = this) as? PsiMethod
@@ -38,12 +38,14 @@ constructor -> UAnnotationMethod (name = AWithSecondary)
i -> UParameter (name = i) i -> UParameter (name = i)
Int -> USimpleNameReferenceExpression (identifier = Int) Int -> USimpleNameReferenceExpression (identifier = Int)
a -> USimpleNameReferenceExpression (identifier = a) a -> USimpleNameReferenceExpression (identifier = a)
= -> USimpleNameReferenceExpression (identifier = =)
i -> USimpleNameReferenceExpression (identifier = i) i -> USimpleNameReferenceExpression (identifier = i)
toString -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) toString -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0))
constructor -> UAnnotationMethod (name = AWithSecondary) constructor -> UAnnotationMethod (name = AWithSecondary)
s -> UParameter (name = s) s -> UParameter (name = s)
String -> USimpleNameReferenceExpression (identifier = String) String -> USimpleNameReferenceExpression (identifier = String)
a -> USimpleNameReferenceExpression (identifier = a) a -> USimpleNameReferenceExpression (identifier = a)
= -> USimpleNameReferenceExpression (identifier = =)
s -> USimpleNameReferenceExpression (identifier = s) s -> USimpleNameReferenceExpression (identifier = s)
AWithSecondaryInit -> UClass (name = AWithSecondaryInit) AWithSecondaryInit -> UClass (name = AWithSecondaryInit)
a -> UField (name = a) a -> UField (name = a)
@@ -53,12 +55,14 @@ constructor -> UAnnotationMethod (name = AWithSecondaryInit)
i -> UParameter (name = i) i -> UParameter (name = i)
Int -> USimpleNameReferenceExpression (identifier = Int) Int -> USimpleNameReferenceExpression (identifier = Int)
a -> USimpleNameReferenceExpression (identifier = a) a -> USimpleNameReferenceExpression (identifier = a)
= -> USimpleNameReferenceExpression (identifier = =)
i -> USimpleNameReferenceExpression (identifier = i) i -> USimpleNameReferenceExpression (identifier = i)
toString -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) toString -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0))
constructor -> UAnnotationMethod (name = AWithSecondaryInit) constructor -> UAnnotationMethod (name = AWithSecondaryInit)
s -> UParameter (name = s) s -> UParameter (name = s)
String -> USimpleNameReferenceExpression (identifier = String) String -> USimpleNameReferenceExpression (identifier = String)
a -> USimpleNameReferenceExpression (identifier = a) a -> USimpleNameReferenceExpression (identifier = a)
= -> USimpleNameReferenceExpression (identifier = =)
s -> USimpleNameReferenceExpression (identifier = s) s -> USimpleNameReferenceExpression (identifier = s)
local -> ULocalVariable (name = local) local -> ULocalVariable (name = local)
String -> USimpleNameReferenceExpression (identifier = String) String -> USimpleNameReferenceExpression (identifier = String)
@@ -11,4 +11,5 @@ Boolean -> USimpleNameReferenceExpression (identifier = Boolean)
String -> USimpleNameReferenceExpression (identifier = String) String -> USimpleNameReferenceExpression (identifier = String)
LocalObject -> UClass (name = LocalObject) LocalObject -> UClass (name = LocalObject)
bar -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) bar -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0))
== -> USimpleNameReferenceExpression (identifier = ==)
Local -> UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) Local -> UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0))
@@ -14,6 +14,7 @@ import org.jetbrains.uast.test.env.assertEqualsToFile
import org.jetbrains.uast.visitor.AbstractUastVisitor import org.jetbrains.uast.visitor.AbstractUastVisitor
import org.junit.ComparisonFailure import org.junit.ComparisonFailure
import java.io.File import java.io.File
import kotlin.test.fail
interface IdentifiersTestBase { interface IdentifiersTestBase {
fun getIdentifiersFile(testName: String): File fun getIdentifiersFile(testName: String): File
@@ -42,22 +43,28 @@ interface IdentifiersTestBase {
private fun UFile.testIdentifiersParents() { private fun UFile.testIdentifiersParents() {
accept(object : AbstractUastVisitor() { accept(object : AbstractUastVisitor() {
override fun visitElement(node: UElement): Boolean { override fun visitElement(node: UElement): Boolean {
if (node is UAnchorOwner) { val uIdentifier = when (node) {
val uastAnchor = node.uastAnchor ?: return false is UAnchorOwner -> node.uastAnchor ?: return false
assertParents(node, uastAnchor) is UBinaryExpression -> node.operatorIdentifier ?: return false
val uastAnchorFromSource = (uastAnchor.sourcePsi ?: return false).toUElementOfType<UIdentifier>() else -> return false
assertParents(node, uastAnchorFromSource)
} }
assertParents(node, uIdentifier)
val identifierSourcePsi = uIdentifier.sourcePsi ?: return false
val operatorIdentifierFromSource = identifierSourcePsi.toUElementOfType<UIdentifier>()
?: fail("$identifierSourcePsi of ${identifierSourcePsi.javaClass} should be convertable to UIdentifier")
assertParents(node, operatorIdentifierFromSource)
return false return false
} }
}) })
} }
fun assertParents(node: UAnchorOwner, uastAnchor: UIdentifier?) { fun assertParents(node: UElement, uastAnchor: UIdentifier?) {
//skipping such elements because they are ambiguous (properties and getters for instance) //skipping such elements because they are ambiguous (properties and getters for instance)
if (node.sourcePsi.toUElement() != node) return if (node.sourcePsi.toUElement() != node) return
if (uastAnchor == null) if (uastAnchor == null)
throw AssertionError("no uast anchor for ${node.uastAnchor?.sourcePsi}(${node.uastAnchor?.sourcePsi?.javaClass}) for node = $node") throw AssertionError("no uast anchor for node = $node")
val nodeParents = node.withContainingElements.log() val nodeParents = node.withContainingElements.log()
val anchorParentParents = uastAnchor.uastParent?.withContainingElements?.log() ?: "" val anchorParentParents = uastAnchor.uastParent?.withContainingElements?.log() ?: ""
// dropping node itself because we allow children to share identifiers with parents (primary constructor for instance) // dropping node itself because we allow children to share identifiers with parents (primary constructor for instance)