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.FilteringProcessor;
import com.intellij.util.Processor;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashMap;
import gnu.trove.TObjectHashingStrategy;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.asJava.LightClassUtil;
import org.jetbrains.jet.lang.psi.*;
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.search.usagesSearch.UsagesSearchPackage;
import java.util.ArrayList;
import java.util.Map;
import java.util.*;
public abstract class KotlinCallerMethodsTreeStructure extends KotlinCallTreeStructure {
private static class WithLocalRoot extends KotlinCallerMethodsTreeStructure {
@@ -110,17 +110,18 @@ public abstract class KotlinCallerMethodsTreeStructure extends KotlinCallTreeStr
Object[] javaCallers = null;
if (element instanceof PsiMethod) {
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) {
PsiMethod lightMethod = LightClassUtil.getLightClassMethod((JetNamedFunction) element);
processPsiMethodCallers(lightMethod, descriptor, methodToDescriptorMap, searchScope, false);
processPsiMethodCallers(Collections.singleton(lightMethod), descriptor, methodToDescriptorMap, searchScope, false);
}
if (element instanceof JetProperty) {
LightClassUtil.PropertyAccessorsPsiMethods propertyMethods =
LightClassUtil.getLightClassPropertyMethods((JetProperty) element);
processPsiMethodCallers(propertyMethods.getGetter(), descriptor, methodToDescriptorMap, searchScope, false);
processPsiMethodCallers(propertyMethods.getSetter(), descriptor, methodToDescriptorMap, searchScope, false);
processPsiMethodCallers(propertyMethods, descriptor, methodToDescriptorMap, searchScope, false);
}
if (element instanceof JetClassOrObject) {
processJetClassOrObjectCallers((JetClassOrObject) element, descriptor, methodToDescriptorMap, searchScope);
@@ -131,15 +132,40 @@ public abstract class KotlinCallerMethodsTreeStructure extends KotlinCallTreeStr
}
private void processPsiMethodCallers(
@Nullable PsiMethod lightMethod,
Iterable<PsiMethod> lightMethods,
HierarchyNodeDescriptor descriptor,
Map<PsiElement, HierarchyNodeDescriptor> methodToDescriptorMap,
SearchScope searchScope,
boolean kotlinOnly
) {
if (lightMethod == null) return;
MethodReferencesSearch.search(lightMethod, searchScope, true)
.forEach(defaultQueryProcessor(descriptor, methodToDescriptorMap, kotlinOnly));
Set<PsiMethod> methodsToFind = new HashSet<PsiMethod>();
for (PsiMethod lightMethod : lightMethods) {
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(
@@ -1,7 +1,7 @@
<node text="KA.foo(String) ()" base="true">
<node text="KClient.bar() ()"/>
<node text="KClient.getBar() ()"/>
<node text="KClient(2 usages) ()"/>
<node text="JA.foo() ()"/>
<node text="JA ()"/>
<node text="JA(2 usages) ()"/>
<node text="JA.foo()(2 usages) ()"/>
<node text="KClient(4 usages) ()"/>
<node text="KClient.bar()(2 usages) ()"/>
<node text="KClient.getBar()(2 usages) ()"/>
</node>
@@ -1,6 +1,13 @@
class KA {
public final String name = "A"
class KBase {
public String foo(String s) {
return s;
}
}
class KA extends KBase {
public final String name = "A";
@Override
public final String <caret>foo(String s) {
return "A " + s;
}
@@ -8,16 +15,17 @@ class KA {
class KClient {
{
new KBase().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() {
return new KA().foo("");
return new KBase().foo("") + new KA().foo("");
}
public final String bar() {
return new KA().foo("");
return new KBase().foo("") + new KA().foo("");
}
}
@@ -1,7 +1,7 @@
open class JA() {
public var name: String = KA().foo("")
public var name: String = KBase().foo("") + KA().foo("")
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="KClientObj ()"/>
<node text="JA.foo() ()"/>
<node text="packageFun(String) ()"/>
<node text="KClient ()"/>
<node text="KClient ()"/>
<node text="bar.localFun() ()"/>
<node text="KClient.bar() ()"/>
<node text="KClient.bar ()"/>
<node text="main0.kt ()"/>
<node text="JA ()"/>
<node text="JA(2 usages) ()"/>
<node text="JA.foo()(2 usages) ()"/>
<node text="KClient(2 usages) ()"/>
<node text="KClient(2 usages) ()"/>
<node text="KClient.bar()(2 usages) ()"/>
<node text="KClient.bar(2 usages) ()"/>
<node text="KClientObj(2 usages) ()"/>
<node text="bar.localFun()(2 usages) ()"/>
<node text="main0.kt(2 usages) ()"/>
<node text="packageFun(String)(2 usages) ()"/>
</node>
@@ -1,31 +1,37 @@
class KA {
val name = "A"
fun <caret>foo(s: String): String = "A: $s"
open class KBase {
open fun foo(s: String): String = 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 {
{
KA().foo("")
KBase().foo("")
}
class object {
val a = KA().foo("")
val a = KBase().foo("") + KA().foo("")
}
val bar: String
get() = KA().foo("")
get() = KBase().foo("") + KA().foo("")
fun bar() {
fun localFun() = KA().foo("")
fun localFun() = KBase().foo("") + KA().foo("")
KA().foo("")
KBase().foo("")
}
}
object KClientObj {
val a = KA().foo("")
val a = KBase().foo("") + KA().foo("")
}
@@ -1,7 +1,7 @@
class JA {
public String name = new KA().foo("");
public String name = new KBase().foo("") + new KA().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="JA(2 usages) ()"/>
<node text="JA.getName()(2 usages) ()"/>
<node text="KClient(2 usages) ()"/>
<node text="main0.kt(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="bar.localFun()(2 usages) ()"/>
<node text="KClient.bar(4 usages) ()"/>
<node text="JA.getName() ()"/>
<node text="KClient.bar()(2 usages) ()"/>
<node text="JA ()"/>
<node text="main0.kt(2 usages) ()"/>
<node text="packageFun(String)(2 usages) ()"/>
</node>
@@ -1,35 +1,44 @@
class KA {
var <caret>name = "A"
open class KBase {
open var name = ""
}
class KA: KBase() {
override var <caret>name = "A"
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 {
{
KBase().name = ""
KA().name = ""
}
class object {
val a = KA().name
val a = KBase().name + KA().name
}
val bar: String
get() = KA().name
set(value: String) {KA().name = value}
var bar: String
get() = KBase().name + KA().name
set(value: String) {
KBase().name = value
KA().name = value
}
fun bar() {
fun localFun() = KA().name
fun localFun() = KBase().name + KA().name
val s = KA().name
val s = KBase().name + KA().name
}
}
object KClientObj {
val a = KA().name
val a = KBase().name + KA().name
{
KBase().name = ""
KA().name = ""
}
}
@@ -1,7 +1,7 @@
class JA {
public String name = new KA().getName();
public String name = new KBase().getName() + new KA().getName();
public String getName() {
return new KA().getName();
return new KBase().getName() + new KA().getName();
}
}