From bef3d4ace256ede0e39d98c9c5a13544f7b79990 Mon Sep 17 00:00:00 2001 From: Nicolay Mitropolsky Date: Tue, 26 Jun 2018 12:22:16 +0300 Subject: [PATCH] Uast: proper identifiers for `KotlinUBinaryExpression` (KT-25092) --- .../uast/kotlin/KotlinUastLanguagePlugin.kt | 2 ++ .../expressions/KotlinUBinaryExpression.kt | 2 +- .../testData/Constructors.identifiers.txt | 4 ++++ .../LocalDeclarations.identifiers.txt | 1 + .../uast/test/common/IdentifiersTestBase.kt | 21 ++++++++++++------- 5 files changed, 22 insertions(+), 8 deletions(-) diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt index ec847267a70..ef6dab21c84 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt @@ -361,6 +361,8 @@ internal object KotlinConverter { if (element.elementType != KtTokens.OBJECT_KEYWORD || element.getParentOfType(false)?.nameIdentifier == null) el(build(::KotlinUIdentifier)) else null + else if (element.elementType in KtTokens.OPERATIONS && element.parent is KtOperationReferenceExpression) + el(build(::KotlinUIdentifier)) else if (element.elementType == KtTokens.LBRACKET && element.parent is KtCollectionLiteralExpression) el { UIdentifier( diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUBinaryExpression.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUBinaryExpression.kt index 9aebf47d10d..9a9751267f7 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUBinaryExpression.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUBinaryExpression.kt @@ -43,7 +43,7 @@ class KotlinUBinaryExpression( override val rightOperand by lz { KotlinConverter.convertOrEmpty(psi.right, this) } 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 diff --git a/plugins/uast-kotlin/testData/Constructors.identifiers.txt b/plugins/uast-kotlin/testData/Constructors.identifiers.txt index 560dd4fdad2..48074656b4e 100644 --- a/plugins/uast-kotlin/testData/Constructors.identifiers.txt +++ b/plugins/uast-kotlin/testData/Constructors.identifiers.txt @@ -38,12 +38,14 @@ constructor -> UAnnotationMethod (name = AWithSecondary) i -> UParameter (name = i) Int -> USimpleNameReferenceExpression (identifier = Int) a -> USimpleNameReferenceExpression (identifier = a) + = -> USimpleNameReferenceExpression (identifier = =) i -> USimpleNameReferenceExpression (identifier = i) toString -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) constructor -> UAnnotationMethod (name = AWithSecondary) s -> UParameter (name = s) String -> USimpleNameReferenceExpression (identifier = String) a -> USimpleNameReferenceExpression (identifier = a) + = -> USimpleNameReferenceExpression (identifier = =) s -> USimpleNameReferenceExpression (identifier = s) AWithSecondaryInit -> UClass (name = AWithSecondaryInit) a -> UField (name = a) @@ -53,12 +55,14 @@ constructor -> UAnnotationMethod (name = AWithSecondaryInit) i -> UParameter (name = i) Int -> USimpleNameReferenceExpression (identifier = Int) a -> USimpleNameReferenceExpression (identifier = a) + = -> USimpleNameReferenceExpression (identifier = =) i -> USimpleNameReferenceExpression (identifier = i) toString -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) constructor -> UAnnotationMethod (name = AWithSecondaryInit) s -> UParameter (name = s) String -> USimpleNameReferenceExpression (identifier = String) a -> USimpleNameReferenceExpression (identifier = a) + = -> USimpleNameReferenceExpression (identifier = =) s -> USimpleNameReferenceExpression (identifier = s) local -> ULocalVariable (name = local) String -> USimpleNameReferenceExpression (identifier = String) diff --git a/plugins/uast-kotlin/testData/LocalDeclarations.identifiers.txt b/plugins/uast-kotlin/testData/LocalDeclarations.identifiers.txt index 0e28e7b947b..90899dfe053 100644 --- a/plugins/uast-kotlin/testData/LocalDeclarations.identifiers.txt +++ b/plugins/uast-kotlin/testData/LocalDeclarations.identifiers.txt @@ -11,4 +11,5 @@ Boolean -> USimpleNameReferenceExpression (identifier = Boolean) String -> USimpleNameReferenceExpression (identifier = String) LocalObject -> UClass (name = LocalObject) bar -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) + == -> USimpleNameReferenceExpression (identifier = ==) Local -> UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) diff --git a/plugins/uast-kotlin/tests/org/jetbrains/uast/test/common/IdentifiersTestBase.kt b/plugins/uast-kotlin/tests/org/jetbrains/uast/test/common/IdentifiersTestBase.kt index 0af939c673a..67e122c8b1c 100644 --- a/plugins/uast-kotlin/tests/org/jetbrains/uast/test/common/IdentifiersTestBase.kt +++ b/plugins/uast-kotlin/tests/org/jetbrains/uast/test/common/IdentifiersTestBase.kt @@ -14,6 +14,7 @@ import org.jetbrains.uast.test.env.assertEqualsToFile import org.jetbrains.uast.visitor.AbstractUastVisitor import org.junit.ComparisonFailure import java.io.File +import kotlin.test.fail interface IdentifiersTestBase { fun getIdentifiersFile(testName: String): File @@ -42,22 +43,28 @@ interface IdentifiersTestBase { private fun UFile.testIdentifiersParents() { accept(object : AbstractUastVisitor() { override fun visitElement(node: UElement): Boolean { - if (node is UAnchorOwner) { - val uastAnchor = node.uastAnchor ?: return false - assertParents(node, uastAnchor) - val uastAnchorFromSource = (uastAnchor.sourcePsi ?: return false).toUElementOfType() - assertParents(node, uastAnchorFromSource) + val uIdentifier = when (node) { + is UAnchorOwner -> node.uastAnchor ?: return false + is UBinaryExpression -> node.operatorIdentifier ?: return false + else -> return false } + + assertParents(node, uIdentifier) + val identifierSourcePsi = uIdentifier.sourcePsi ?: return false + val operatorIdentifierFromSource = identifierSourcePsi.toUElementOfType() + ?: fail("$identifierSourcePsi of ${identifierSourcePsi.javaClass} should be convertable to UIdentifier") + assertParents(node, operatorIdentifierFromSource) + 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) if (node.sourcePsi.toUElement() != node) return 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 anchorParentParents = uastAnchor.uastParent?.withContainingElements?.log() ?: "" // dropping node itself because we allow children to share identifiers with parents (primary constructor for instance)