UAST: Fix receiverType for JavaUCallExpression

Return correct receiver class for a method call with implicit receiver
instead of super class, when method defined in one of super classes

 #IDEA-177417 Fixed
This commit is contained in:
Vyacheslav Gerasimov
2017-08-11 20:46:31 +02:00
committed by Dmitry Jemerov
parent 605474caf4
commit 3bbbfc3b5b
3 changed files with 156 additions and 20 deletions

View File

@@ -16,7 +16,7 @@
package org.jetbrains.uast.java
import com.intellij.psi.*
import com.intellij.psi.util.PsiTypesUtil
import com.intellij.psi.util.*
import org.jetbrains.uast.*
import org.jetbrains.uast.psi.UElementWithLocation
@@ -52,9 +52,8 @@ class JavaUCallExpression(
override fun resolve() = psi.resolveMethod()
override fun getStartOffset(): Int {
return psi.methodExpression.referenceNameElement?.textOffset ?: psi.methodExpression.textOffset
}
override fun getStartOffset(): Int =
psi.methodExpression.referenceNameElement?.textOffset ?: psi.methodExpression.textOffset
override fun getEndOffset() = psi.textRange.endOffset
@@ -72,10 +71,27 @@ class JavaUCallExpression(
if (qualifierType != null) {
return qualifierType
}
val method = resolve() ?: return null
if (method.hasModifierProperty(PsiModifier.STATIC)) return null
return method.containingClass?.let { PsiTypesUtil.getClassType(it) }
val psiManager = psi.manager
val containingClassForMethod = method.containingClass ?: return null
val containingClass = PsiTreeUtil.getParentOfType(psi, PsiClass::class.java)
val containingClassSequence = generateSequence(containingClass) {
if (it.hasModifierProperty(PsiModifier.STATIC))
null
else
PsiTreeUtil.getParentOfType(it, PsiClass::class.java)
}
val receiverClass = containingClassSequence.find { containingClassForExpression ->
psiManager.areElementsEquivalent(containingClassForMethod, containingClassForExpression) ||
containingClassForExpression.isInheritor(containingClassForMethod, true)
}
return receiverClass?.let { PsiTypesUtil.getClassType(it) }
}
}
@@ -109,25 +125,19 @@ class JavaConstructorUCallExpression(
override val valueArgumentCount: Int
get() {
val initializer = psi.arrayInitializer
return if (initializer != null) {
initializer.initializers.size
} else if (psi.arrayDimensions.isNotEmpty()) {
psi.arrayDimensions.size
} else {
psi.argumentList?.expressions?.size ?: 0
return when {
initializer != null -> initializer.initializers.size
psi.arrayDimensions.isNotEmpty() -> psi.arrayDimensions.size
else -> psi.argumentList?.expressions?.size ?: 0
}
}
override val valueArguments by lz {
val initializer = psi.arrayInitializer
if (initializer != null) {
initializer.initializers.map { JavaConverter.convertOrEmpty(it, this) }
}
else if (psi.arrayDimensions.isNotEmpty()) {
psi.arrayDimensions.map { JavaConverter.convertOrEmpty(it, this) }
}
else {
psi.argumentList?.expressions?.map { JavaConverter.convertOrEmpty(it, this) } ?: emptyList()
when {
initializer != null -> initializer.initializers.map { JavaConverter.convertOrEmpty(it, this) }
psi.arrayDimensions.isNotEmpty() -> psi.arrayDimensions.map { JavaConverter.convertOrEmpty(it, this) }
else -> psi.argumentList?.expressions?.map { JavaConverter.convertOrEmpty(it, this) } ?: emptyList()
}
}

View File

@@ -0,0 +1,93 @@
class TestBaseBase {
void bazBaseBase(int i) {
}
}
class TestBase extends TestBaseBase {
void fooBase(int i) {
}
void barBase(int i) {
}
}
class Test extends TestBase {
Test() {
foo(1);
fooBase(1);
this.barBase(1);
staticMethod(1);
bazBaseBase(1);
}
void foo(int i) {
}
static void staticMethod(int i) {
}
class InnerTest {
InnerTest() {
foo(2);
fooBase(2);
bar(2);
staticMethod(2);
TestBase t = new TestBase() {
void fooBase(int i) {
bazBaseBase(7);
bar(7);
barBase(7);
}
};
}
void bar(int i) {
}
class InnerInnerTest {
InnerInnerTest() {
foo(3);
fooBase(3);
bar(3);
baz(3);
staticMethod(3);
}
void baz(int i) {
}
}
}
class InnerTest2 extends TestBase {
InnerTest2() {
foo(4);
fooBase(4);
}
}
static class StaticTest {
StaticTest() {
bar(5);
staticMethod(5);
}
void bar(int i) {
}
class InnerInStatic {
InnerInStatic() {
bar(6);
}
}
}
}

View File

@@ -61,4 +61,37 @@ class JavaUastApiTest : AbstractJavaUastTest() {
"java.lang.Runnable")
}
}
@Test fun testReceiverType() {
doTest("Simple/ReceiverType.java") { name, file ->
assertEquals("Test", file.findElementByText<UCallExpression>("foo(1)").receiverType?.canonicalText)
assertEquals("Test", file.findElementByText<UCallExpression>("fooBase(1)").receiverType?.canonicalText)
assertEquals("Test", file.findElementByText<UCallExpression>("this.barBase(1)").receiverType?.canonicalText)
assertEquals("Test", file.findElementByText<UCallExpression>("bazBaseBase(1)").receiverType?.canonicalText)
assertNull(file.findElementByText<UCallExpression>("staticMethod(1)").receiverType)
assertEquals("Test", file.findElementByText<UCallExpression>("foo(2)").receiverType?.canonicalText)
assertEquals("Test", file.findElementByText<UCallExpression>("fooBase(2)").receiverType?.canonicalText)
assertEquals("Test.InnerTest", file.findElementByText<UCallExpression>("bar(2)").receiverType?.canonicalText)
assertNull(file.findElementByText<UCallExpression>("staticMethod(2)").receiverType)
assertEquals("Test", file.findElementByText<UCallExpression>("foo(3)").receiverType?.canonicalText)
assertEquals("Test", file.findElementByText<UCallExpression>("fooBase(3)").receiverType?.canonicalText)
assertEquals("Test.InnerTest", file.findElementByText<UCallExpression>("bar(3)").receiverType?.canonicalText)
assertEquals("Test.InnerTest.InnerInnerTest", file.findElementByText<UCallExpression>("baz(3)").receiverType?.canonicalText)
assertNull(file.findElementByText<UCallExpression>("staticMethod(3)").receiverType)
assertEquals("Test", file.findElementByText<UCallExpression>("foo(4)").receiverType?.canonicalText)
assertEquals("Test.InnerTest2", file.findElementByText<UCallExpression>("fooBase(4)").receiverType?.canonicalText)
assertEquals("Test.StaticTest", file.findElementByText<UCallExpression>("bar(5)").receiverType?.canonicalText)
assertNull(file.findElementByText<UCallExpression>("staticMethod(5)").receiverType)
assertEquals("Test.StaticTest", file.findElementByText<UCallExpression>("bar(6)").receiverType?.canonicalText)
assertEquals("TestBase", file.findElementByText<UCallExpression>("bazBaseBase(7)").receiverType?.canonicalText)
assertEquals("Test.InnerTest", file.findElementByText<UCallExpression>("bar(7)").receiverType?.canonicalText)
assertEquals("TestBase", file.findElementByText<UCallExpression>("barBase(7)").receiverType?.canonicalText)
}
}
}