-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
5.5.0: Call Hierarchy added (Slice Provider removed)
- Loading branch information
1 parent
7743604
commit bdd7823
Showing
15 changed files
with
538 additions
and
183 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
88 changes: 88 additions & 0 deletions
88
src/main/java/org/kdb/inside/brains/lang/hierarchy/QCallHierarchyBrowser.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
package org.kdb.inside.brains.lang.hierarchy; | ||
|
||
import com.intellij.ide.hierarchy.CallHierarchyBrowserBase; | ||
import com.intellij.ide.hierarchy.HierarchyBrowserManager; | ||
import com.intellij.ide.hierarchy.HierarchyNodeDescriptor; | ||
import com.intellij.ide.hierarchy.HierarchyTreeStructure; | ||
import com.intellij.ide.util.treeView.AlphaComparator; | ||
import com.intellij.ide.util.treeView.NodeDescriptor; | ||
import com.intellij.openapi.actionSystem.ActionGroup; | ||
import com.intellij.openapi.actionSystem.ActionManager; | ||
import com.intellij.openapi.actionSystem.ActionPlaces; | ||
import com.intellij.openapi.actionSystem.IdeActions; | ||
import com.intellij.psi.PsiElement; | ||
import com.intellij.ui.PopupHandler; | ||
import org.jetbrains.annotations.Nls; | ||
import org.jetbrains.annotations.NotNull; | ||
import org.jetbrains.annotations.Nullable; | ||
import org.kdb.inside.brains.psi.QPsiUtil; | ||
import org.kdb.inside.brains.psi.QVarDeclaration; | ||
|
||
import javax.swing.*; | ||
import java.util.Comparator; | ||
import java.util.Map; | ||
|
||
// PyCallHierarchyBrowser is used as an example | ||
public class QCallHierarchyBrowser extends CallHierarchyBrowserBase { | ||
private static final Comparator<NodeDescriptor<?>> NODE_DESCRIPTOR_COMPARATOR = Comparator.comparingInt(NodeDescriptor::getIndex); | ||
|
||
public QCallHierarchyBrowser(@NotNull PsiElement qVar) { | ||
super(qVar.getProject(), qVar); | ||
} | ||
|
||
@Override | ||
protected @Nullable PsiElement getElementFromDescriptor(@NotNull HierarchyNodeDescriptor descriptor) { | ||
if (descriptor instanceof QHierarchyNodeDescriptor qd) { | ||
return qd.getPsiElement(); | ||
} | ||
return null; | ||
} | ||
|
||
@Override | ||
protected void createTrees(@NotNull Map<? super @Nls String, ? super JTree> trees) { | ||
final ActionGroup group = (ActionGroup) ActionManager.getInstance().getAction(IdeActions.GROUP_CALL_HIERARCHY_POPUP); | ||
|
||
trees.put(getCallerType(), createHierarchyTree(group)); | ||
trees.put(getCalleeType(), createHierarchyTree(group)); | ||
} | ||
|
||
private JTree createHierarchyTree(ActionGroup group) { | ||
final JTree tree = createTree(false); | ||
PopupHandler.installPopupMenu(tree, group, ActionPlaces.CALL_HIERARCHY_VIEW_POPUP); | ||
return tree; | ||
} | ||
|
||
@Override | ||
protected boolean isApplicableElement(@NotNull PsiElement element) { | ||
return element instanceof QVarDeclaration v && QPsiUtil.isGlobalDeclaration(v); | ||
} | ||
|
||
@Override | ||
protected @Nullable HierarchyTreeStructure createHierarchyTreeStructure(@NotNull String type, @NotNull PsiElement psiElement) { | ||
if (getCallerType().equals(type)) { | ||
return new QCallerFunctionTreeStructure(myProject, psiElement, getCurrentScopeType()); | ||
} else if (getCalleeType().equals(type)) { | ||
return new QCalleeFunctionTreeStructure(myProject, psiElement, getCurrentScopeType()); | ||
} else { | ||
return null; | ||
} | ||
} | ||
|
||
@Override | ||
protected @Nullable Comparator<NodeDescriptor<?>> getComparator() { | ||
final HierarchyBrowserManager instance = HierarchyBrowserManager.getInstance(myProject); | ||
if (instance != null && instance.getState() != null && instance.getState().SORT_ALPHABETICALLY) { | ||
return AlphaComparator.INSTANCE; | ||
} else { | ||
return NODE_DESCRIPTOR_COMPARATOR; | ||
} | ||
} | ||
|
||
/* | ||
Defined in PyCallHierarchyBrowser but not sure it's correct | ||
@Override | ||
public @NotNull ActionUpdateThread getActionUpdateThread() { | ||
return ActionUpdateThread.EDT; | ||
} | ||
*/ | ||
} |
38 changes: 38 additions & 0 deletions
38
src/main/java/org/kdb/inside/brains/lang/hierarchy/QCallHierarchyProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package org.kdb.inside.brains.lang.hierarchy; | ||
|
||
import com.intellij.ide.hierarchy.CallHierarchyBrowserBase; | ||
import com.intellij.ide.hierarchy.HierarchyBrowser; | ||
import com.intellij.ide.hierarchy.HierarchyProvider; | ||
import com.intellij.openapi.actionSystem.CommonDataKeys; | ||
import com.intellij.openapi.actionSystem.DataContext; | ||
import com.intellij.openapi.project.Project; | ||
import com.intellij.psi.PsiElement; | ||
import org.jetbrains.annotations.NotNull; | ||
import org.jetbrains.annotations.Nullable; | ||
import org.kdb.inside.brains.psi.QPsiUtil; | ||
import org.kdb.inside.brains.psi.QVarDeclaration; | ||
|
||
public class QCallHierarchyProvider implements HierarchyProvider { | ||
@Override | ||
public @Nullable PsiElement getTarget(@NotNull DataContext dataContext) { | ||
final Project project = CommonDataKeys.PROJECT.getData(dataContext); | ||
if (project == null) { | ||
return null; | ||
} | ||
final PsiElement element = CommonDataKeys.PSI_ELEMENT.getData(dataContext); | ||
if (element instanceof QVarDeclaration v && QPsiUtil.isGlobalDeclaration(v)) { | ||
return element; | ||
} | ||
return null; | ||
} | ||
|
||
@Override | ||
public @NotNull HierarchyBrowser createHierarchyBrowser(@NotNull PsiElement target) { | ||
return new QCallHierarchyBrowser(target); | ||
} | ||
|
||
@Override | ||
public void browserActivated(@NotNull HierarchyBrowser hierarchyBrowser) { | ||
((QCallHierarchyBrowser) hierarchyBrowser).changeView(CallHierarchyBrowserBase.getCallerType()); | ||
} | ||
} |
57 changes: 57 additions & 0 deletions
57
src/main/java/org/kdb/inside/brains/lang/hierarchy/QCallHierarchyTreeStructureBase.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package org.kdb.inside.brains.lang.hierarchy; | ||
|
||
import com.intellij.ide.hierarchy.HierarchyNodeDescriptor; | ||
import com.intellij.ide.hierarchy.HierarchyTreeStructure; | ||
import com.intellij.openapi.project.Project; | ||
import com.intellij.psi.PsiElement; | ||
import com.intellij.util.ArrayUtil; | ||
import org.jetbrains.annotations.NotNull; | ||
import org.kdb.inside.brains.psi.QVarDeclaration; | ||
|
||
import java.util.*; | ||
|
||
public abstract class QCallHierarchyTreeStructureBase extends HierarchyTreeStructure { | ||
private final String myScopeType; | ||
|
||
protected QCallHierarchyTreeStructureBase(@NotNull Project project, PsiElement element, String currentScopeType) { | ||
super(project, new QHierarchyNodeDescriptor(project, null, element, true)); | ||
this.myScopeType = currentScopeType; | ||
} | ||
|
||
@NotNull | ||
protected abstract Map<PsiElement, Collection<PsiElement>> getChildren(@NotNull QVarDeclaration element); | ||
|
||
@Override | ||
protected Object @NotNull [] buildChildren(@NotNull HierarchyNodeDescriptor descriptor) { | ||
if (!(descriptor instanceof QHierarchyNodeDescriptor desc)) { | ||
return ArrayUtil.EMPTY_OBJECT_ARRAY; | ||
} | ||
|
||
if (desc.isRecursion()) { | ||
return ArrayUtil.EMPTY_OBJECT_ARRAY; | ||
} | ||
|
||
final PsiElement element = desc.getPsiElement(); | ||
if (!(element instanceof QVarDeclaration declaration)) { | ||
return ArrayUtil.EMPTY_OBJECT_ARRAY; | ||
} | ||
|
||
final List<QHierarchyNodeDescriptor> descriptors = new ArrayList<>(); | ||
|
||
final Map<PsiElement, Collection<PsiElement>> children = getChildren(declaration); | ||
final Map<PsiElement, QHierarchyNodeDescriptor> callerToDescriptorMap = new HashMap<>(children.size()); | ||
children.forEach((c, u) -> { | ||
if (!isInScope(null, c, myScopeType)) { | ||
return; | ||
} | ||
|
||
QHierarchyNodeDescriptor callerDescriptor = callerToDescriptorMap.get(c); | ||
if (callerDescriptor == null) { | ||
callerDescriptor = new QHierarchyNodeDescriptor(descriptor.getProject(), descriptor, c, u, false); | ||
callerToDescriptorMap.put(c, callerDescriptor); | ||
descriptors.add(callerDescriptor); | ||
} | ||
}); | ||
return ArrayUtil.toObjectArray(descriptors); | ||
} | ||
} |
45 changes: 45 additions & 0 deletions
45
src/main/java/org/kdb/inside/brains/lang/hierarchy/QCalleeFunctionTreeStructure.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package org.kdb.inside.brains.lang.hierarchy; | ||
|
||
import com.intellij.openapi.project.Project; | ||
import com.intellij.psi.PsiElement; | ||
import com.intellij.psi.PsiReference; | ||
import com.intellij.psi.util.PsiTreeUtil; | ||
import com.intellij.util.containers.MultiMap; | ||
import org.jetbrains.annotations.NotNull; | ||
import org.kdb.inside.brains.psi.*; | ||
|
||
import java.util.Collection; | ||
import java.util.Map; | ||
|
||
public class QCalleeFunctionTreeStructure extends QCallHierarchyTreeStructureBase { | ||
protected QCalleeFunctionTreeStructure(@NotNull Project project, PsiElement element, String currentScopeType) { | ||
super(project, element, currentScopeType); | ||
} | ||
|
||
@Override | ||
protected @NotNull Map<PsiElement, Collection<PsiElement>> getChildren(@NotNull QVarDeclaration declaration) { | ||
final PsiElement parent = declaration.getParent(); | ||
if (!(parent instanceof QAssignmentExpr exp)) { | ||
return Map.of(); | ||
} | ||
|
||
if (!(exp.getExpression() instanceof QLambdaExpr)) { | ||
return Map.of(); | ||
} | ||
|
||
final Collection<QPsiElement> children = PsiTreeUtil.findChildrenOfAnyType(exp, QVarReference.class, QSymbol.class); | ||
|
||
final MultiMap<PsiElement, PsiElement> res = MultiMap.createOrderedSet(); | ||
for (QPsiElement child : children) { | ||
final PsiReference reference = child.getReference(); | ||
if (reference == null) { | ||
continue; | ||
} | ||
final PsiElement el = reference.resolve(); | ||
if (el instanceof QVarDeclaration d && QPsiUtil.isGlobalDeclaration(d)) { | ||
res.putValue(el, child); | ||
} | ||
} | ||
return res.freezeValues(); | ||
} | ||
} |
65 changes: 65 additions & 0 deletions
65
src/main/java/org/kdb/inside/brains/lang/hierarchy/QCallerFunctionTreeStructure.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package org.kdb.inside.brains.lang.hierarchy; | ||
|
||
import com.intellij.find.findUsages.FindUsagesHandlerBase; | ||
import com.intellij.openapi.project.Project; | ||
import com.intellij.psi.PsiElement; | ||
import com.intellij.psi.util.PsiTreeUtil; | ||
import com.intellij.usageView.UsageInfo; | ||
import com.intellij.util.CommonProcessors; | ||
import com.intellij.util.containers.MultiMap; | ||
import org.jetbrains.annotations.NotNull; | ||
import org.kdb.inside.brains.psi.*; | ||
|
||
import java.util.Collection; | ||
import java.util.Map; | ||
|
||
public class QCallerFunctionTreeStructure extends QCallHierarchyTreeStructureBase { | ||
protected QCallerFunctionTreeStructure(@NotNull Project project, PsiElement element, String currentScopeType) { | ||
super(project, element, currentScopeType); | ||
} | ||
|
||
@Override | ||
protected @NotNull Map<PsiElement, Collection<PsiElement>> getChildren(@NotNull QVarDeclaration declaration) { | ||
final Collection<UsageInfo> usages = findUsages(declaration); | ||
|
||
final MultiMap<PsiElement, PsiElement> res = MultiMap.createOrderedSet(); | ||
for (UsageInfo usage : usages) { | ||
PsiElement element = usage.getElement(); | ||
if (element == declaration || !(element instanceof QPsiElement qEl)) { | ||
continue; | ||
} | ||
|
||
if (!(element instanceof QVarReference) && !(element instanceof QSymbol)) { | ||
continue; | ||
} | ||
|
||
final QAssignmentExpr assign = getGlobalLambdaAssignment(element); | ||
if (assign != null) { | ||
res.putValue(assign.getVarDeclaration(), element); | ||
} else { | ||
res.putValue(element.getContainingFile(), element); | ||
} | ||
} | ||
return res.freezeValues(); | ||
} | ||
|
||
private QAssignmentExpr getGlobalLambdaAssignment(PsiElement el) { | ||
PsiElement element = el; | ||
while (element != null) { | ||
final QAssignmentExpr assign = PsiTreeUtil.getParentOfType(element, QAssignmentExpr.class); | ||
if (assign != null && QPsiUtil.isGlobalDeclaration(assign) && assign.getExpression() instanceof QLambdaExpr) { | ||
return assign; | ||
} | ||
element = assign; | ||
} | ||
return null; | ||
} | ||
|
||
|
||
private @NotNull Collection<UsageInfo> findUsages(@NotNull QVarDeclaration declaration) { | ||
final FindUsagesHandlerBase handler = new FindUsagesHandlerBase(declaration); | ||
final CommonProcessors.CollectProcessor<UsageInfo> processor = new CommonProcessors.CollectProcessor<>(); | ||
handler.processElementUsages(declaration, processor, handler.getFindUsagesOptions(null)); | ||
return processor.getResults(); | ||
} | ||
} |
Oops, something went wrong.