From 46b8dbe4c21e72efb9e7543a6fa3c0609273985c Mon Sep 17 00:00:00 2001 From: Yuriy Artamonov Date: Mon, 16 Dec 2019 22:22:58 +0300 Subject: [PATCH] UAST: JavaConstructorUCallExpression multiResolve() must resolve to PsiMethod in case there is explicit constructor GitOrigin-RevId: 3ebd0a55953d0482638287aa8b90cdb386f67e9b --- .../java/expressions/javaUCallExpressions.kt | 12 ++++- .../Simple/ConstructorCallWithParameters.java | 11 +++++ ...ConstructorCallWithParameters.resolved.txt | 14 ++++++ .../java/Simple/DefaultConstructorCall.java | 5 +++ .../DefaultConstructorCall.resolved.txt | 5 +++ .../AbstractJavaExpressionMultiResolveTest.kt | 45 +++++++++++++++++++ .../java/JavaExpressionMultiResolveTest.kt | 12 +++++ 7 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 uast/uast-tests/java/Simple/ConstructorCallWithParameters.java create mode 100644 uast/uast-tests/java/Simple/ConstructorCallWithParameters.resolved.txt create mode 100644 uast/uast-tests/java/Simple/DefaultConstructorCall.java create mode 100644 uast/uast-tests/java/Simple/DefaultConstructorCall.resolved.txt create mode 100644 uast/uast-tests/test/org/jetbrains/uast/test/java/AbstractJavaExpressionMultiResolveTest.kt create mode 100644 uast/uast-tests/test/org/jetbrains/uast/test/java/JavaExpressionMultiResolveTest.kt diff --git a/uast/uast-java/src/org/jetbrains/uast/java/expressions/javaUCallExpressions.kt b/uast/uast-java/src/org/jetbrains/uast/java/expressions/javaUCallExpressions.kt index 5f5acac3f14e..192b54074c46 100644 --- a/uast/uast-java/src/org/jetbrains/uast/java/expressions/javaUCallExpressions.kt +++ b/uast/uast-java/src/org/jetbrains/uast/java/expressions/javaUCallExpressions.kt @@ -180,8 +180,16 @@ class JavaConstructorUCallExpression( get() = null override fun resolve(): PsiMethod? = sourcePsi.resolveMethod() - override fun multiResolve(): Iterable = - sourcePsi.classReference?.multiResolve(false)?.asIterable() ?: emptyList() + override fun multiResolve(): Iterable { + val methodResolve = sourcePsi.resolveMethodGenerics() + if (methodResolve != JavaResolveResult.EMPTY) { + // if there is a non-default constructor + return arrayOf(methodResolve).asIterable() + } + // no default constructor - resolve to class + val classResolve = sourcePsi.classReference?.multiResolve(false) ?: emptyArray() + return classResolve.asIterable() + } } class JavaArrayInitializerUCallExpression( diff --git a/uast/uast-tests/java/Simple/ConstructorCallWithParameters.java b/uast/uast-tests/java/Simple/ConstructorCallWithParameters.java new file mode 100644 index 000000000000..8962ffff0c11 --- /dev/null +++ b/uast/uast-tests/java/Simple/ConstructorCallWithParameters.java @@ -0,0 +1,11 @@ +public class Foo { + private int number; + + public Foo(int number) { + this.number = number; + } + + public static void test() { + new Foo(10); + } +} diff --git a/uast/uast-tests/java/Simple/ConstructorCallWithParameters.resolved.txt b/uast/uast-tests/java/Simple/ConstructorCallWithParameters.resolved.txt new file mode 100644 index 000000000000..36b6be1c5f80 --- /dev/null +++ b/uast/uast-tests/java/Simple/ConstructorCallWithParameters.resolved.txt @@ -0,0 +1,14 @@ + UField (name = number) -> UTypeReferenceExpression (name = int) -> null + UParameter (name = number) -> UTypeReferenceExpression (name = int) -> null + UMethod (name = Foo) -> UBlockExpression -> null + UBlockExpression -> UBinaryExpression (operator = =) -> null + UBlockExpression -> UBinaryExpression (operator = =) -> null + UBinaryExpression (operator = =) -> UQualifiedReferenceExpression -> [M] PsiFieldImpl + UQualifiedReferenceExpression -> UThisExpression (label = null) -> [M] + UBinaryExpression (operator = =) -> USimpleNameReferenceExpression (identifier = number) -> [M] PsiParameterImpl + UMethod (name = test) -> UTypeReferenceExpression (name = void) -> null + UMethod (name = test) -> UBlockExpression -> null + UBlockExpression -> UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 1)) -> [M] PsiMethodImpl + UBlockExpression -> UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 1)) -> [M] PsiMethodImpl + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 1)) -> USimpleNameReferenceExpression (identifier = Foo) -> [M] PsiClassImpl + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 1)) -> ULiteralExpression (value = 10) -> null diff --git a/uast/uast-tests/java/Simple/DefaultConstructorCall.java b/uast/uast-tests/java/Simple/DefaultConstructorCall.java new file mode 100644 index 000000000000..f74062c5b756 --- /dev/null +++ b/uast/uast-tests/java/Simple/DefaultConstructorCall.java @@ -0,0 +1,5 @@ +public class Foo { + public static void test() { + new Foo(); + } +} diff --git a/uast/uast-tests/java/Simple/DefaultConstructorCall.resolved.txt b/uast/uast-tests/java/Simple/DefaultConstructorCall.resolved.txt new file mode 100644 index 000000000000..c2f88315573d --- /dev/null +++ b/uast/uast-tests/java/Simple/DefaultConstructorCall.resolved.txt @@ -0,0 +1,5 @@ + UMethod (name = test) -> UTypeReferenceExpression (name = void) -> null + UMethod (name = test) -> UBlockExpression -> null + UBlockExpression -> UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) -> [M] PsiClassImpl + UBlockExpression -> UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) -> [M] PsiClassImpl + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) -> USimpleNameReferenceExpression (identifier = Foo) -> [M] PsiClassImpl diff --git a/uast/uast-tests/test/org/jetbrains/uast/test/java/AbstractJavaExpressionMultiResolveTest.kt b/uast/uast-tests/test/org/jetbrains/uast/test/java/AbstractJavaExpressionMultiResolveTest.kt new file mode 100644 index 000000000000..88b9b06665e3 --- /dev/null +++ b/uast/uast-tests/test/org/jetbrains/uast/test/java/AbstractJavaExpressionMultiResolveTest.kt @@ -0,0 +1,45 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.uast.test.java + +import com.intellij.psi.PsiCodeBlock +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiIdentifier +import com.intellij.psi.PsiModifierListOwner +import org.jetbrains.uast.* +import org.jetbrains.uast.test.common.visitUFileAndGetResult +import org.jetbrains.uast.test.env.assertEqualsToFile +import org.jetbrains.uast.util.IndentedPrintingVisitor +import java.io.File + +abstract class AbstractJavaExpressionMultiResolveTest : AbstractJavaUastTest() { + private fun UFile.resolvableWithTargets() = object : IndentedPrintingVisitor(PsiCodeBlock::class, PsiModifierListOwner::class) { + override fun render(element: PsiElement): CharSequence? = + element + .takeIf { it !is PsiIdentifier } // no sense to handle PsiIdentifier, see IDEA-207979 + ?.toUElementOfType()?.let { ref -> + StringBuilder().apply { + val parent = ref.uastParent + append(parent?.asLogString()) + append(" -> ") + append(ref.asLogString()) + append(" -> ") + append(multiResolve(ref)) + } + } + }.visitUFileAndGetResult(this) + + private fun multiResolve(ref: UExpression): String { + if (ref is UMultiResolvable) { + return "[M] " + ref.multiResolve().joinToString(",") { it.element?.javaClass?.simpleName ?: "null" } + } + if (ref is UResolvable) { + return "[S] " + (ref.resolve()?.toString() ?: "null") + } + return "null" + } + + override fun check(testName: String, file: UFile) { + val expected = File(testDataPath, testName.substringBeforeLast('.') + ".resolved.txt") + assertEqualsToFile("resolved", expected, file.resolvableWithTargets()) + } +} diff --git a/uast/uast-tests/test/org/jetbrains/uast/test/java/JavaExpressionMultiResolveTest.kt b/uast/uast-tests/test/org/jetbrains/uast/test/java/JavaExpressionMultiResolveTest.kt new file mode 100644 index 000000000000..af1b4b4b1bc2 --- /dev/null +++ b/uast/uast-tests/test/org/jetbrains/uast/test/java/JavaExpressionMultiResolveTest.kt @@ -0,0 +1,12 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.uast.test.java + +import org.junit.Test + +class JavaExpressionMultiResolveTest : AbstractJavaExpressionMultiResolveTest() { + @Test + fun testConstructorCallWithParameters() = doTest("Simple/ConstructorCallWithParameters.java") // must resolve to PsiMethodImpl + + @Test + fun testDefaultConstructorCall() = doTest("Simple/DefaultConstructorCall.java") // must resolve to PsiClassImpl +} \ No newline at end of file