Show call sites of overriden members in "Caller Hierarchy"

#KT-4395 Fixed
This commit is contained in:
Alexey Sedunov
2014-01-15 16:18:40 +04:00
parent 7ec21fc5ca
commit 3e6f879571
10 changed files with 113 additions and 64 deletions
@@ -29,9 +29,10 @@ import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ArrayUtil; import com.intellij.util.ArrayUtil;
import com.intellij.util.FilteringProcessor; import com.intellij.util.FilteringProcessor;
import com.intellij.util.Processor; import com.intellij.util.Processor;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashMap; import com.intellij.util.containers.HashMap;
import gnu.trove.TObjectHashingStrategy;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.asJava.LightClassUtil; import org.jetbrains.jet.asJava.LightClassUtil;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
@@ -40,8 +41,7 @@ import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
import org.jetbrains.jet.plugin.references.JetPsiReference; import org.jetbrains.jet.plugin.references.JetPsiReference;
import org.jetbrains.jet.plugin.search.usagesSearch.UsagesSearchPackage; import org.jetbrains.jet.plugin.search.usagesSearch.UsagesSearchPackage;
import java.util.ArrayList; import java.util.*;
import java.util.Map;
public abstract class KotlinCallerMethodsTreeStructure extends KotlinCallTreeStructure { public abstract class KotlinCallerMethodsTreeStructure extends KotlinCallTreeStructure {
private static class WithLocalRoot extends KotlinCallerMethodsTreeStructure { private static class WithLocalRoot extends KotlinCallerMethodsTreeStructure {
@@ -110,17 +110,18 @@ public abstract class KotlinCallerMethodsTreeStructure extends KotlinCallTreeStr
Object[] javaCallers = null; Object[] javaCallers = null;
if (element instanceof PsiMethod) { if (element instanceof PsiMethod) {
javaCallers = javaTreeStructure.getChildElements(getJavaNodeDescriptor(descriptor)); javaCallers = javaTreeStructure.getChildElements(getJavaNodeDescriptor(descriptor));
processPsiMethodCallers((PsiMethod) element, descriptor, methodToDescriptorMap, searchScope, true); processPsiMethodCallers(
Collections.singleton((PsiMethod) element), descriptor, methodToDescriptorMap, searchScope, true
);
} }
if (element instanceof JetNamedFunction) { if (element instanceof JetNamedFunction) {
PsiMethod lightMethod = LightClassUtil.getLightClassMethod((JetNamedFunction) element); PsiMethod lightMethod = LightClassUtil.getLightClassMethod((JetNamedFunction) element);
processPsiMethodCallers(lightMethod, descriptor, methodToDescriptorMap, searchScope, false); processPsiMethodCallers(Collections.singleton(lightMethod), descriptor, methodToDescriptorMap, searchScope, false);
} }
if (element instanceof JetProperty) { if (element instanceof JetProperty) {
LightClassUtil.PropertyAccessorsPsiMethods propertyMethods = LightClassUtil.PropertyAccessorsPsiMethods propertyMethods =
LightClassUtil.getLightClassPropertyMethods((JetProperty) element); LightClassUtil.getLightClassPropertyMethods((JetProperty) element);
processPsiMethodCallers(propertyMethods.getGetter(), descriptor, methodToDescriptorMap, searchScope, false); processPsiMethodCallers(propertyMethods, descriptor, methodToDescriptorMap, searchScope, false);
processPsiMethodCallers(propertyMethods.getSetter(), descriptor, methodToDescriptorMap, searchScope, false);
} }
if (element instanceof JetClassOrObject) { if (element instanceof JetClassOrObject) {
processJetClassOrObjectCallers((JetClassOrObject) element, descriptor, methodToDescriptorMap, searchScope); processJetClassOrObjectCallers((JetClassOrObject) element, descriptor, methodToDescriptorMap, searchScope);
@@ -131,15 +132,40 @@ public abstract class KotlinCallerMethodsTreeStructure extends KotlinCallTreeStr
} }
private void processPsiMethodCallers( private void processPsiMethodCallers(
@Nullable PsiMethod lightMethod, Iterable<PsiMethod> lightMethods,
HierarchyNodeDescriptor descriptor, HierarchyNodeDescriptor descriptor,
Map<PsiElement, HierarchyNodeDescriptor> methodToDescriptorMap, Map<PsiElement, HierarchyNodeDescriptor> methodToDescriptorMap,
SearchScope searchScope, SearchScope searchScope,
boolean kotlinOnly boolean kotlinOnly
) { ) {
if (lightMethod == null) return; Set<PsiMethod> methodsToFind = new HashSet<PsiMethod>();
MethodReferencesSearch.search(lightMethod, searchScope, true) for (PsiMethod lightMethod : lightMethods) {
.forEach(defaultQueryProcessor(descriptor, methodToDescriptorMap, kotlinOnly)); if (lightMethod == null) continue;
PsiMethod[] superMethods = lightMethod.findDeepestSuperMethods();
methodsToFind.add(lightMethod);
ContainerUtil.addAll(methodsToFind, superMethods);
}
if (methodsToFind.isEmpty()) return;
Set<PsiReference> references = ContainerUtil.newTroveSet(
new TObjectHashingStrategy<PsiReference>() {
@Override
public int computeHashCode(PsiReference object) {
return object.getElement().hashCode();
}
@Override
public boolean equals(PsiReference o1, PsiReference o2) {
return o1.getElement().equals(o2.getElement());
}
}
);
for (PsiMethod superMethod: methodsToFind) {
ContainerUtil.addAll(references, MethodReferencesSearch.search(superMethod, searchScope, true));
}
ContainerUtil.process(references, defaultQueryProcessor(descriptor, methodToDescriptorMap, kotlinOnly));
} }
private void processJetClassOrObjectCallers( private void processJetClassOrObjectCallers(
@@ -1,7 +1,7 @@
<node text="KA.foo(String) ()" base="true"> <node text="KA.foo(String) ()" base="true">
<node text="KClient.bar() ()"/> <node text="JA(2 usages) ()"/>
<node text="KClient.getBar() ()"/> <node text="JA.foo()(2 usages) ()"/>
<node text="KClient(2 usages) ()"/> <node text="KClient(4 usages) ()"/>
<node text="JA.foo() ()"/> <node text="KClient.bar()(2 usages) ()"/>
<node text="JA ()"/> <node text="KClient.getBar()(2 usages) ()"/>
</node> </node>
@@ -1,6 +1,13 @@
class KA { class KBase {
public final String name = "A" public String foo(String s) {
return s;
}
}
class KA extends KBase {
public final String name = "A";
@Override
public final String <caret>foo(String s) { public final String <caret>foo(String s) {
return "A " + s; return "A " + s;
} }
@@ -8,16 +15,17 @@ class KA {
class KClient { class KClient {
{ {
new KBase().foo("");
new KA().foo(""); new KA().foo("");
} }
public static final String a = new KA().foo(""); public static final String a = new KBase().foo("") + new KA().foo("");
public final String getBar() { public final String getBar() {
return new KA().foo(""); return new KBase().foo("") + new KA().foo("");
} }
public final String bar() { public final String bar() {
return new KA().foo(""); return new KBase().foo("") + new KA().foo("");
} }
} }
@@ -1,7 +1,7 @@
open class JA() { open class JA() {
public var name: String = KA().foo("") public var name: String = KBase().foo("") + KA().foo("")
public open fun foo(): String { public open fun foo(): String {
return KA().foo("") return KBase().foo("") + KA().foo("")
} }
} }
@@ -1,12 +1,12 @@
<node text="KA.foo(String) ()" base="true"> <node text="KA.foo(String) ()" base="true">
<node text="KClientObj ()"/> <node text="JA(2 usages) ()"/>
<node text="JA.foo() ()"/> <node text="JA.foo()(2 usages) ()"/>
<node text="packageFun(String) ()"/> <node text="KClient(2 usages) ()"/>
<node text="KClient ()"/> <node text="KClient(2 usages) ()"/>
<node text="KClient ()"/> <node text="KClient.bar()(2 usages) ()"/>
<node text="bar.localFun() ()"/> <node text="KClient.bar(2 usages) ()"/>
<node text="KClient.bar() ()"/> <node text="KClientObj(2 usages) ()"/>
<node text="KClient.bar ()"/> <node text="bar.localFun()(2 usages) ()"/>
<node text="main0.kt ()"/> <node text="main0.kt(2 usages) ()"/>
<node text="JA ()"/> <node text="packageFun(String)(2 usages) ()"/>
</node> </node>
@@ -1,31 +1,37 @@
class KA { open class KBase {
val name = "A" open fun foo(s: String): String = s
fun <caret>foo(s: String): String = "A: $s"
} }
fun packageFun(s: String): String = KA().foo(s) class KA: KBase() {
val name = "A"
override fun <caret>foo(s: String): String = "A: $s"
}
val packageVal = KA().foo("") fun packageFun(s: String): String = KBase().foo("") + KA().foo(s)
val packageVal = KBase().foo("") + KA().foo("")
class KClient { class KClient {
{ {
KA().foo("") KA().foo("")
KBase().foo("")
} }
class object { class object {
val a = KA().foo("") val a = KBase().foo("") + KA().foo("")
} }
val bar: String val bar: String
get() = KA().foo("") get() = KBase().foo("") + KA().foo("")
fun bar() { fun bar() {
fun localFun() = KA().foo("") fun localFun() = KBase().foo("") + KA().foo("")
KA().foo("") KA().foo("")
KBase().foo("")
} }
} }
object KClientObj { object KClientObj {
val a = KA().foo("") val a = KBase().foo("") + KA().foo("")
} }
@@ -1,7 +1,7 @@
class JA { class JA {
public String name = new KA().foo(""); public String name = new KBase().foo("") + new KA().foo("");
public String foo() { public String foo() {
return new KA().foo(""); return new KBase().foo("") + new KA().foo("");
} }
} }
@@ -1,12 +1,12 @@
<node text="KA.name ()" base="true"> <node text="KA.name ()" base="true">
<node text="JA(2 usages) ()"/>
<node text="JA.getName()(2 usages) ()"/>
<node text="KClient(2 usages) ()"/> <node text="KClient(2 usages) ()"/>
<node text="main0.kt(2 usages) ()"/>
<node text="KClient(2 usages) ()"/> <node text="KClient(2 usages) ()"/>
<node text="packageFun(String)(2 usages) ()"/> <node text="KClient.bar()(2 usages) ()"/>
<node text="KClient.bar(4 usages) ()"/>
<node text="KClientObj(4 usages) ()"/> <node text="KClientObj(4 usages) ()"/>
<node text="bar.localFun()(2 usages) ()"/> <node text="bar.localFun()(2 usages) ()"/>
<node text="KClient.bar(4 usages) ()"/> <node text="main0.kt(2 usages) ()"/>
<node text="JA.getName() ()"/> <node text="packageFun(String)(2 usages) ()"/>
<node text="KClient.bar()(2 usages) ()"/>
<node text="JA ()"/>
</node> </node>
@@ -1,35 +1,44 @@
class KA { open class KBase {
var <caret>name = "A" open var name = ""
}
class KA: KBase() {
override var <caret>name = "A"
fun foo(s: String): String = "A: $s" fun foo(s: String): String = "A: $s"
} }
fun packageFun(s: String): String = KA().name fun packageFun(s: String): String = KBase().name + KA().name
val packageVal = KA().name val packageVal = KBase().name + KA().name
class KClient { class KClient {
{ {
KBase().name = ""
KA().name = "" KA().name = ""
} }
class object { class object {
val a = KA().name val a = KBase().name + KA().name
} }
val bar: String var bar: String
get() = KA().name get() = KBase().name + KA().name
set(value: String) {KA().name = value} set(value: String) {
KBase().name = value
KA().name = value
}
fun bar() { fun bar() {
fun localFun() = KA().name fun localFun() = KBase().name + KA().name
val s = KA().name val s = KBase().name + KA().name
} }
} }
object KClientObj { object KClientObj {
val a = KA().name val a = KBase().name + KA().name
{ {
KBase().name = ""
KA().name = "" KA().name = ""
} }
} }
@@ -1,7 +1,7 @@
class JA { class JA {
public String name = new KA().getName(); public String name = new KBase().getName() + new KA().getName();
public String getName() { public String getName() {
return new KA().getName(); return new KBase().getName() + new KA().getName();
} }
} }