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)
el<UIdentifier>(build(::KotlinUIdentifier))
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)
el<UIdentifier> {
UIdentifier(
@@ -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
@@ -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)
@@ -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))
@@ -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<UIdentifier>()
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<UIdentifier>()
?: 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)