Implement navigation to references from Call Hierarchy view
#KT-4518 Fixed
This commit is contained in:
committed by
Aleksei Sedunov
parent
c6c1389144
commit
7e1c9194f1
+13
-8
@@ -14,6 +14,7 @@ import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.pom.Navigatable;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.ui.LayeredIcon;
|
||||
import com.intellij.util.Function;
|
||||
@@ -30,9 +31,12 @@ import org.jetbrains.jet.renderer.DescriptorRenderer;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class KotlinCallHierarchyNodeDescriptor extends HierarchyNodeDescriptor implements Navigatable {
|
||||
private int usageCount = 1;
|
||||
private int usageCount = 0;
|
||||
private final Set<PsiReference> references = new HashSet<PsiReference>();
|
||||
private final CallHierarchyNodeDescriptor javaDelegate;
|
||||
|
||||
public KotlinCallHierarchyNodeDescriptor(@NotNull Project project,
|
||||
@@ -48,8 +52,11 @@ public class KotlinCallHierarchyNodeDescriptor extends HierarchyNodeDescriptor i
|
||||
return javaDelegate;
|
||||
}
|
||||
|
||||
public final void incrementUsageCount(){
|
||||
usageCount++;
|
||||
public final void addReference(PsiReference reference) {
|
||||
if (references.add(reference)) {
|
||||
usageCount++;
|
||||
}
|
||||
javaDelegate.addReference(reference);
|
||||
}
|
||||
|
||||
public final PsiElement getTargetElement(){
|
||||
@@ -210,18 +217,16 @@ public class KotlinCallHierarchyNodeDescriptor extends HierarchyNodeDescriptor i
|
||||
|
||||
@Override
|
||||
public void navigate(boolean requestFocus) {
|
||||
if (myElement instanceof Navigatable) {
|
||||
((Navigatable)myElement).navigate(requestFocus);
|
||||
}
|
||||
javaDelegate.navigate(requestFocus);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canNavigate() {
|
||||
return myElement instanceof Navigatable && ((Navigatable) myElement).canNavigate();
|
||||
return javaDelegate.canNavigate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canNavigateToSource() {
|
||||
return canNavigate();
|
||||
return javaDelegate.canNavigateToSource();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import jet.Function1;
|
||||
@@ -16,14 +17,13 @@ import org.jetbrains.jet.asJava.LightClassUtil;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.psi.psiUtil.PsiUtilPackage;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class KotlinCallTreeStructure extends HierarchyTreeStructure {
|
||||
protected final String scopeType;
|
||||
|
||||
public KotlinCallTreeStructure(@NotNull Project project, PsiElement element, String scopeType) {
|
||||
super(project, createNodeDescriptor(project, element, null));
|
||||
super(project, createNodeDescriptor(project, element, null, false));
|
||||
this.scopeType = scopeType;
|
||||
}
|
||||
|
||||
@@ -33,11 +33,13 @@ public abstract class KotlinCallTreeStructure extends HierarchyTreeStructure {
|
||||
: null;
|
||||
}
|
||||
|
||||
protected static HierarchyNodeDescriptor createNodeDescriptor(Project project, PsiElement element, HierarchyNodeDescriptor parent) {
|
||||
protected static HierarchyNodeDescriptor createNodeDescriptor(
|
||||
Project project, PsiElement element, HierarchyNodeDescriptor parent, boolean navigateToReference
|
||||
) {
|
||||
boolean root = (parent == null);
|
||||
return element instanceof JetElement
|
||||
? new KotlinCallHierarchyNodeDescriptor(project, parent, element, root, false)
|
||||
: new CallHierarchyNodeDescriptor(project, parent, element, root, false);
|
||||
? new KotlinCallHierarchyNodeDescriptor(project, parent, element, root, navigateToReference)
|
||||
: new CallHierarchyNodeDescriptor(project, parent, element, root, navigateToReference);
|
||||
}
|
||||
|
||||
protected static PsiElement getTargetElement(HierarchyNodeDescriptor descriptor) {
|
||||
@@ -102,34 +104,40 @@ public abstract class KotlinCallTreeStructure extends HierarchyTreeStructure {
|
||||
}
|
||||
|
||||
protected Object[] collectNodeDescriptors(
|
||||
HierarchyNodeDescriptor descriptor, List<? extends PsiElement> calleeElements, PsiClass basePsiClass
|
||||
HierarchyNodeDescriptor descriptor, Map<PsiReference, PsiElement> referencesToCalleeElements, PsiClass basePsiClass
|
||||
) {
|
||||
HashMap<PsiElement, HierarchyNodeDescriptor> declarationToDescriptorMap = new HashMap<PsiElement, HierarchyNodeDescriptor>();
|
||||
for (PsiElement callee : calleeElements) {
|
||||
for (Map.Entry<PsiReference, PsiElement> refToCallee : referencesToCalleeElements.entrySet()) {
|
||||
PsiReference ref = refToCallee.getKey();
|
||||
PsiElement callee = refToCallee.getValue();
|
||||
|
||||
if (basePsiClass != null && !isInScope(basePsiClass, callee, scopeType)) continue;
|
||||
|
||||
addNodeDescriptorForElement(callee, declarationToDescriptorMap, descriptor);
|
||||
addNodeDescriptorForElement(ref, callee, declarationToDescriptorMap, descriptor);
|
||||
}
|
||||
return declarationToDescriptorMap.values().toArray(new Object[declarationToDescriptorMap.size()]);
|
||||
}
|
||||
|
||||
protected final void addNodeDescriptorForElement(
|
||||
PsiReference reference,
|
||||
PsiElement element,
|
||||
Map<PsiElement, HierarchyNodeDescriptor> declarationToDescriptorMap,
|
||||
HierarchyNodeDescriptor descriptor
|
||||
) {
|
||||
HierarchyNodeDescriptor d = declarationToDescriptorMap.get(element);
|
||||
if (d == null) {
|
||||
d = createNodeDescriptor(myProject, element, descriptor);
|
||||
d = createNodeDescriptor(myProject, element, descriptor, true);
|
||||
declarationToDescriptorMap.put(element, d);
|
||||
}
|
||||
else {
|
||||
if (d instanceof CallHierarchyNodeDescriptor) {
|
||||
((CallHierarchyNodeDescriptor) d).incrementUsageCount();
|
||||
}
|
||||
else if (d instanceof KotlinCallHierarchyNodeDescriptor) {
|
||||
((KotlinCallHierarchyNodeDescriptor) d).incrementUsageCount();
|
||||
}
|
||||
else if (d instanceof CallHierarchyNodeDescriptor) {
|
||||
((CallHierarchyNodeDescriptor) d).incrementUsageCount();
|
||||
}
|
||||
|
||||
if (d instanceof CallHierarchyNodeDescriptor) {
|
||||
((CallHierarchyNodeDescriptor) d).addReference(reference);
|
||||
}
|
||||
else if (d instanceof KotlinCallHierarchyNodeDescriptor) {
|
||||
((KotlinCallHierarchyNodeDescriptor) d).addReference(reference);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+9
-6
@@ -23,13 +23,16 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.java.jetAsJava.KotlinLightMethod;
|
||||
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class KotlinCalleeMethodsTreeStructure extends KotlinCallTreeStructure {
|
||||
private final CalleeMethodsTreeStructure javaTreeStructure;
|
||||
@@ -45,7 +48,7 @@ public class KotlinCalleeMethodsTreeStructure extends KotlinCallTreeStructure {
|
||||
this.javaTreeStructure = new CalleeMethodsTreeStructure(project, representativePsiMethod, scopeType);
|
||||
}
|
||||
|
||||
private static List<? extends PsiElement> getCalleeElements(@NotNull JetElement rootElement) {
|
||||
private static Map<PsiReference, PsiElement> getReferencesToCalleeElements(@NotNull JetElement rootElement) {
|
||||
List<JetElement> elementsToAnalyze = new ArrayList<JetElement>();
|
||||
if (rootElement instanceof JetNamedFunction) {
|
||||
elementsToAnalyze.add(((JetNamedFunction) rootElement).getBodyExpression());
|
||||
@@ -78,19 +81,19 @@ public class KotlinCalleeMethodsTreeStructure extends KotlinCallTreeStructure {
|
||||
}
|
||||
}
|
||||
|
||||
final ArrayList<PsiElement> result = new ArrayList<PsiElement>();
|
||||
final Map<PsiReference, PsiElement> referencesToCalleeElements = new HashMap<PsiReference, PsiElement>();
|
||||
for (JetElement element : elementsToAnalyze) {
|
||||
element.accept(
|
||||
new CalleeReferenceVisitorBase(AnalyzerFacadeWithCache.getContextForElement(element), false) {
|
||||
@Override
|
||||
protected void processDeclaration(JetReferenceExpression reference, PsiElement declaration) {
|
||||
result.add(declaration);
|
||||
referencesToCalleeElements.put(reference.getReference(), declaration);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
return referencesToCalleeElements;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -126,7 +129,7 @@ public class KotlinCalleeMethodsTreeStructure extends KotlinCallTreeStructure {
|
||||
}
|
||||
|
||||
private Object[] buildChildrenByKotlinTarget(HierarchyNodeDescriptor descriptor, JetElement targetElement) {
|
||||
List<? extends PsiElement> calleeDescriptors = getCalleeElements(targetElement);
|
||||
return collectNodeDescriptors(descriptor, calleeDescriptors, representativePsiClass);
|
||||
Map<PsiReference, PsiElement> referencesToCalleeElements = getReferencesToCalleeElements(targetElement);
|
||||
return collectNodeDescriptors(descriptor, referencesToCalleeElements, representativePsiClass);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -66,7 +66,7 @@ public abstract class KotlinCallerMethodsTreeStructure extends KotlinCallTreeStr
|
||||
|
||||
BindingContext bindingContext = AnalyzerFacadeWithCache.getContextForElement((JetElement) element);
|
||||
|
||||
final ArrayList<PsiElement> result = new ArrayList<PsiElement>();
|
||||
final Map<PsiReference, PsiElement> referencesToElements = new HashMap<PsiReference, PsiElement>();
|
||||
codeBlockForLocalDeclaration.accept(new CalleeReferenceVisitorBase(bindingContext, true) {
|
||||
@Override
|
||||
protected void processDeclaration(JetReferenceExpression reference, PsiElement declaration) {
|
||||
@@ -80,11 +80,11 @@ public abstract class KotlinCallerMethodsTreeStructure extends KotlinCallTreeStr
|
||||
}
|
||||
|
||||
if (container != null) {
|
||||
result.add(container);
|
||||
referencesToElements.put(reference.getReference(), container);
|
||||
}
|
||||
}
|
||||
});
|
||||
return collectNodeDescriptors(descriptor, result, null);
|
||||
return collectNodeDescriptors(descriptor, referencesToElements, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,7 +230,7 @@ public abstract class KotlinCallerMethodsTreeStructure extends KotlinCallTreeStr
|
||||
}
|
||||
|
||||
if (element != null) {
|
||||
addNodeDescriptorForElement(element, methodToDescriptorMap, descriptor);
|
||||
addNodeDescriptorForElement(ref, element, methodToDescriptorMap, descriptor);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user