Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dart: WEB-41595 call hierarchy: jump to caller position #870

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.jetbrains.lang.dart.ide.hierarchy.call;

import com.intellij.psi.PsiElement;

public class DartCallChild {
private PsiElement element;
private PsiElement reference;

public DartCallChild(PsiElement element, PsiElement reference) {
this.element = element;
this.reference = reference;
}

public PsiElement getElement() {
return element;
}

public PsiElement getReference() {
return reference;
}
}
Original file line number Diff line number Diff line change
@@ -1,26 +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 com.jetbrains.lang.dart.ide.hierarchy.call;

import com.intellij.codeInsight.highlighting.HighlightManager;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.hierarchy.HierarchyNodeDescriptor;
import com.intellij.ide.util.treeView.NodeDescriptor;
import com.intellij.navigation.ItemPresentation;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.colors.EditorColors;
import com.intellij.openapi.editor.markup.RangeHighlighter;
import com.intellij.openapi.roots.ui.util.CompositeAppearance;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.TextRange;
import com.intellij.pom.Navigatable;
import com.intellij.psi.NavigatablePsiElement;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiReference;
import com.intellij.psi.util.PsiEditorUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.jetbrains.lang.dart.DartComponentType;
import com.jetbrains.lang.dart.psi.DartClass;
import com.jetbrains.lang.dart.psi.DartMethodDeclaration;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public class DartCallHierarchyNodeDescriptor extends HierarchyNodeDescriptor {
import java.util.ArrayList;
import java.util.List;

public class DartCallHierarchyNodeDescriptor extends HierarchyNodeDescriptor implements Navigatable {

private final List<PsiReference> myReferences = new ArrayList<>();

public DartCallHierarchyNodeDescriptor(final NodeDescriptor parentDescriptor, @NotNull final PsiElement element, final boolean isBase) {
super(element.getProject(), parentDescriptor, element, isBase);
}

public void addReference(PsiReference reference) {
myReferences.add(reference);
}

@Override
public boolean update() {
boolean changes = super.update();
Expand All @@ -47,11 +66,77 @@ public boolean update() {
if (file != null) {
myHighlightedText.getEnding().addText(" (" + file.getName() + ")", HierarchyNodeDescriptor.getPackageNameAttributes());
}
var myUsageCount = myReferences.size();
if (myUsageCount > 1) {
myHighlightedText.getEnding().addText(IdeBundle.message("node.call.hierarchy.N.usages", myUsageCount), HierarchyNodeDescriptor.getUsageCountPrefixAttributes());
}

}
myName = myHighlightedText.getText();
if (!Comparing.equal(myHighlightedText, oldText)) {
changes = true;
}
return changes;
}

private @Nullable Navigatable getNavigatable() {
if (!myReferences.isEmpty()) {
final var reference = myReferences.get(0);
if (reference instanceof Navigatable) {
return (Navigatable)reference;
}
}
final var ret = getPsiElement();
if (ret instanceof Navigatable) {
return (Navigatable)ret;
}
return null;
}

@Override
public void navigate(boolean requestFocus) {
final var nav = getNavigatable();
if (nav == null) {
return;
}
nav.navigate(requestFocus);

if (!(nav instanceof PsiElement)) {
return;
}

Editor editor = PsiEditorUtil.findEditor((PsiElement) nav);

if (editor != null) {
HighlightManager highlightManager = HighlightManager.getInstance(myProject);
List<RangeHighlighter> highlighters = new ArrayList<>();
for (PsiReference psiReference : myReferences) {
PsiElement eachElement = psiReference.getElement();
PsiElement eachMethodCall = eachElement.getParent();
if (eachMethodCall != null) {
TextRange textRange = eachMethodCall.getTextRange();
highlightManager.addRangeHighlight(editor, textRange.getStartOffset(), textRange.getEndOffset(),
EditorColors.SEARCH_RESULT_ATTRIBUTES, false, highlighters);
}
}
}
}

@Override
public boolean canNavigate() {
final var nav = getNavigatable();
if (nav != null) {
return nav.canNavigate();
}
return false;
}

@Override
public boolean canNavigateToSource() {
final var nav = getNavigatable();
if (nav != null) {
return nav.canNavigateToSource();
}
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ArrayUtil;
Expand Down Expand Up @@ -35,21 +36,21 @@ protected static FindUsagesHandler createFindUsageHandler(@NotNull final PsiElem
return new DartServerFindUsagesHandler(element);
}

public static void collectDeclarations(@Nullable final PsiElement element, @NotNull final List<? super PsiElement> results) {
public static void collectDeclarations(@Nullable final PsiElement element, @NotNull final List<DartCallChild> results) {
if (element != null) {
Condition<PsiElement> isExecutable = object -> {
if (object == null) return false;
return DartHierarchyUtil.isExecutable(object);
};
PsiElement ref = PsiTreeUtil.findFirstParent(element, isExecutable);
if (ref != null) {
results.add(ref);
results.add(new DartCallChild(ref, element));
}
}
}

@NotNull
protected abstract List<PsiElement> getChildren(@NotNull PsiElement element);
protected abstract List<DartCallChild> getChildren(@NotNull PsiElement element);

@Override
protected Object @NotNull [] buildChildren(@NotNull HierarchyNodeDescriptor descriptor) {
Expand All @@ -70,18 +71,21 @@ public static void collectDeclarations(@Nullable final PsiElement element, @NotN
return ArrayUtilRt.EMPTY_OBJECT_ARRAY;
}

final List<PsiElement> children = getChildren(name);
final List<DartCallChild> children = getChildren(name);
final HashMap<PsiElement, DartCallHierarchyNodeDescriptor> callerToDescriptorMap = new HashMap<>();
PsiElement baseClass = element instanceof DartMethodDeclaration ? PsiTreeUtil.getParentOfType(name, DartClass.class) : null;

for (PsiElement caller : children) {
if (isInScope(baseClass, caller, myScopeType)) {
DartCallHierarchyNodeDescriptor callerDescriptor = callerToDescriptorMap.get(caller);
for (DartCallChild caller : children) {
if (isInScope(baseClass, caller.getElement(), myScopeType)) {
DartCallHierarchyNodeDescriptor callerDescriptor = callerToDescriptorMap.get(caller.getElement());
if (callerDescriptor == null) {
callerDescriptor = new DartCallHierarchyNodeDescriptor(descriptor, caller, false);
callerToDescriptorMap.put(caller, callerDescriptor);
callerDescriptor = new DartCallHierarchyNodeDescriptor(descriptor, caller.getElement(), false);
callerToDescriptorMap.put(caller.getElement(), callerDescriptor);
descriptors.add(callerDescriptor);
}
if (caller.getReference() instanceof PsiReference) {
callerDescriptor.addReference((PsiReference)caller.getReference());
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public DartCalleeTreeStructure(Project project, PsiElement element, String curre
super(project, element, currentScopeType);
}

private static void getCallees(@NotNull PsiElement element, @NotNull List<PsiElement> results) {
private static void getCallees(@NotNull PsiElement element, @NotNull List<DartCallChild> results) {
DartComponentName name = (DartComponentName)element;
DartComponent decl = (DartComponent)name.getParent();
PsiFile file = decl.getContainingFile();
Expand All @@ -39,7 +39,7 @@ private static void getCallees(@NotNull PsiElement element, @NotNull List<PsiEle

private static void resolveReferences(@NotNull DartComponent component,
@NotNull List<DartNavigationRegion> regions,
@NotNull List<PsiElement> results) {
@NotNull List<DartCallChild> results) {
component.acceptChildren(new DartRecursiveVisitor() {
@Override
public void visitReferenceExpression(@NotNull DartReferenceExpression reference) {
Expand All @@ -49,7 +49,7 @@ public void visitReferenceExpression(@NotNull DartReferenceExpression reference)
if (isExecutable(target)) {
PsiElement element = getDeclaration(target, reference);
if (element != null) {
results.add(element);
results.add(new DartCallChild(element, reference));
}
}
}
Expand Down Expand Up @@ -86,8 +86,8 @@ private static List<DartNavigationTarget> getRegionAt(int offset, @NotNull List<

@NotNull
@Override
protected List<PsiElement> getChildren(@NotNull PsiElement element) {
final List<PsiElement> list = new ArrayList<>();
protected List<DartCallChild> getChildren(@NotNull PsiElement element) {
final List<DartCallChild> list = new ArrayList<>();
getCallees(element, list);
return list;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public DartCallerTreeStructure(Project project, PsiElement element, String curre
super(project, element, currentScopeType);
}

private static void getCallers(@NotNull PsiElement element, @NotNull List<PsiElement> results, @NotNull GlobalSearchScope scope) {
private static void getCallers(@NotNull PsiElement element, @NotNull List<DartCallChild> results, @NotNull GlobalSearchScope scope) {
FindUsagesHandler finder = createFindUsageHandler(element);
final CommonProcessors.CollectProcessor<UsageInfo> processor = new CommonProcessors.CollectProcessor<>();
FindUsagesOptions options = new FindUsagesOptions(scope);
Expand All @@ -33,8 +33,8 @@ private static void getCallers(@NotNull PsiElement element, @NotNull List<PsiEle

@NotNull
@Override
protected List<PsiElement> getChildren(@NotNull PsiElement element) {
final List<PsiElement> list = new ArrayList<>();
protected List<DartCallChild> getChildren(@NotNull PsiElement element) {
final List<DartCallChild> list = new ArrayList<>();
getCallers(element, list, getScope());
return list;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.intellij.util.indexing.FindSymbolParameters;
import com.jetbrains.lang.dart.ide.DartClassContributor;
import com.jetbrains.lang.dart.ide.DartSymbolContributor;
import com.jetbrains.lang.dart.ide.hierarchy.call.DartCallChild;
import com.jetbrains.lang.dart.ide.hierarchy.call.DartCallHierarchyTreeStructure;
import com.jetbrains.lang.dart.ide.hierarchy.call.DartCalleeTreeStructure;
import com.jetbrains.lang.dart.ide.hierarchy.call.DartCallerTreeStructure;
Expand Down Expand Up @@ -103,10 +104,10 @@ public void visitReferenceExpression(@NotNull DartReferenceExpression reference)
if (parent != null) {
type = parent.getNode().getElementType();
if (type == CALL_EXPRESSION) {
List<PsiElement> results = new ArrayList<>();
List<DartCallChild> results = new ArrayList<>();
DartCallHierarchyTreeStructure.collectDeclarations(reference.resolve(), results);
if (!results.isEmpty()) {
result[0] = results.get(0);
result[0] = results.get(0).getElement();
throw new ExitVisitor();
}
}
Expand Down