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

Add Call Graph [WIP] #605

Closed
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
7ef9b65
Add Call Graph with Pane
Amejonah1200 Sep 4, 2022
265183d
Make getCalls() return a Set sorted by insertion order
Amejonah1200 Sep 6, 2022
2dab3aa
Add Callers Pane and Fix NPE related to CallGraphRegistry
Amejonah1200 Sep 8, 2022
0cfbcc4
Fix merge error in MethodCallGraphPane
Amejonah1200 Oct 2, 2022
b5754e7
Add jlinker and Make CallGraph resolve virtual, special and interface…
Amejonah1200 Oct 25, 2022
8f67a5d
Move Call Graphs to own Window
Amejonah1200 Oct 26, 2022
0d25058
Bundle Call Graph in one TabPane for Docking
Amejonah1200 Oct 27, 2022
5b57ea2
Add option to change current method in Call Graph
Amejonah1200 Oct 27, 2022
4166e87
Add focus icon
Amejonah1200 Oct 27, 2022
341cb39
Add MethodHandle Support for Call Graph
Amejonah1200 Oct 30, 2022
40ae122
Bump jlinker to 1.0.4
Amejonah1200 Nov 1, 2022
5533798
Add Workspace and Class Addition Support for CallGraphRegistry
Amejonah1200 Nov 1, 2022
3e23edc
Add library and class removal
Amejonah1200 Nov 6, 2022
aa77944
Memoize LinkResolver
Amejonah1200 Nov 6, 2022
656845b
Add also unresolved calls available in Graph Pane
Amejonah1200 Nov 6, 2022
77d997b
Add debug messages for better tracking issues.
Amejonah1200 Nov 6, 2022
4f43df9
Make call graph and control flow graph accessible for methods in seco…
Amejonah1200 Nov 6, 2022
9415503
Merge branch 'dev3' into pr/605
Col-E Nov 20, 2022
7fbc434
Merge branch 'dev3' into feature/graf-van-call
Amejonah1200 Aug 20, 2023
2262e77
Update jlink to 1.0.6
Amejonah1200 Aug 20, 2023
b4a8ae0
Changed some prints from debug to info
Amejonah1200 Aug 20, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
36 changes: 7 additions & 29 deletions recaf-ui/src/main/java/me/coley/recaf/ui/ClassView.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package me.coley.recaf.ui;

import javafx.beans.binding.Bindings;
import javafx.beans.binding.ObjectBinding;
import javafx.beans.property.IntegerProperty;
import javafx.geometry.Side;
import javafx.scene.Node;
Expand All @@ -11,16 +9,16 @@
import javafx.scene.control.TabPane;
import javafx.scene.layout.BorderPane;
import me.coley.recaf.RecafUI;
import me.coley.recaf.code.*;
import me.coley.recaf.code.ClassInfo;
import me.coley.recaf.code.CommonClassInfo;
import me.coley.recaf.code.DexClassInfo;
import me.coley.recaf.code.MemberInfo;
import me.coley.recaf.config.Configs;
import me.coley.recaf.scripting.impl.WorkspaceAPI;
import me.coley.recaf.ui.behavior.*;
import me.coley.recaf.ui.control.CollapsibleTabPane;
import me.coley.recaf.ui.control.NavigationBar;
import me.coley.recaf.ui.control.hex.HexClassView;
import me.coley.recaf.ui.pane.DecompilePane;
import me.coley.recaf.ui.pane.HierarchyPane;
import me.coley.recaf.ui.pane.MethodCallGraphPane;
import me.coley.recaf.ui.pane.SmaliAssemblerPane;
import me.coley.recaf.ui.pane.outline.OutlinePane;
import me.coley.recaf.ui.util.Icons;
Expand All @@ -35,14 +33,13 @@
*
* @author Matt Coley
*/
public class ClassView extends BorderPane implements ClassRepresentation, ToolSideTabbed, Cleanable, Undoable, FontSizeChangeable {
public class ClassView extends BorderPane
implements ClassRepresentation, ToolSideTabbed, Cleanable, Undoable, FontSizeChangeable {
private final OutlinePane outline;
private final HierarchyPane hierarchy;
private final BorderPane mainViewWrapper = new BorderPane();
private final CollapsibleTabPane sideTabs = new CollapsibleTabPane();
private final SplitPane contentSplit = new SplitPane();
private final MethodCallGraphPane methodCallGraphCalls;
private final MethodCallGraphPane methodCallGraphCallers;
private ClassViewMode mode = Configs.editor().defaultClassMode;
private ClassRepresentation mainView;
private CommonClassInfo info;
Expand All @@ -55,16 +52,8 @@ public ClassView(CommonClassInfo info) {
this.info = info;
outline = new OutlinePane(this);
hierarchy = new HierarchyPane();
methodCallGraphCalls = new MethodCallGraphPane(WorkspaceAPI.getWorkspace(), MethodCallGraphPane.CallGraphMode.CALLS);
methodCallGraphCallers = new MethodCallGraphPane(WorkspaceAPI.getWorkspace(), MethodCallGraphPane.CallGraphMode.CALLERS);
// Setup main view
mainView = createViewForClass(info);
final ObjectBinding<MethodInfo> currentMethodBinding = Bindings.createObjectBinding(() -> {
final ItemInfo itemInfo = NavigationBar.getInstance().currentItemProperty().get();
return itemInfo instanceof MethodInfo ? (MethodInfo) itemInfo : null;
}, NavigationBar.getInstance().currentItemProperty());
methodCallGraphCalls.currentMethodProperty().bind(currentMethodBinding);
methodCallGraphCallers.currentMethodProperty().bind(currentMethodBinding);
mainViewWrapper.setCenter(mainView.getNodeRepresentation());
contentSplit.getItems().add(mainViewWrapper);
contentSplit.getStyleClass().add("view-split-pane");
Expand Down Expand Up @@ -118,8 +107,6 @@ public void onUpdate(CommonClassInfo newValue) {
info = newValue;
outline.onUpdate(newValue);
hierarchy.onUpdate(newValue);
methodCallGraphCalls.onUpdate(newValue);
methodCallGraphCallers.onUpdate(newValue);
if (mainView != null) {
mainView.onUpdate(newValue);
}
Expand Down Expand Up @@ -213,9 +200,7 @@ public void installSideTabs(CollapsibleTabPane tabPane) {
public void populateSideTabs(CollapsibleTabPane tabPane) {
tabPane.getTabs().addAll(
createOutlineTab(),
createHierarchyTab(),
createCallGraphTabCalls(),
createCallGraphTabCallers()
createHierarchyTab()
);
if (mainView instanceof ToolSideTabbed) {
((ToolSideTabbed) mainView).populateSideTabs(tabPane);
Expand Down Expand Up @@ -284,13 +269,6 @@ private Tab createHierarchyTab() {
return createTab("hierarchy.title", Icons.T_TREE, hierarchy);
}

private Tab createCallGraphTabCalls() {
return createTab("callgraph.calls.title", Icons.T_TREE, methodCallGraphCalls);
}
private Tab createCallGraphTabCallers() {
return createTab("callgraph.callers.title", Icons.T_TREE, methodCallGraphCallers);
}

private static Resource getPrimary() {
Workspace workspace = RecafUI.getController().getWorkspace();
if (workspace != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import me.coley.recaf.code.MethodInfo;
import me.coley.recaf.config.Configs;
import me.coley.recaf.mapping.MappingsAdapter;
import me.coley.recaf.scripting.impl.WorkspaceAPI;
import me.coley.recaf.search.TextMatchMode;
import me.coley.recaf.ssvm.SsvmIntegration;
import me.coley.recaf.ui.CommonUX;
Expand All @@ -20,6 +21,7 @@
import me.coley.recaf.ui.docking.DockTab;
import me.coley.recaf.ui.docking.RecafDockingManager;
import me.coley.recaf.ui.docking.impl.ClassTab;
import me.coley.recaf.ui.pane.MethodCallGraphsPane;
import me.coley.recaf.ui.pane.SearchPane;
import me.coley.recaf.ui.pane.assembler.AssemblerPane;
import me.coley.recaf.ui.pane.graph.MethodGraphPane;
Expand All @@ -36,7 +38,9 @@

import java.util.Optional;

import static me.coley.recaf.ui.util.Menus.*;
import static me.coley.recaf.ui.util.Menus.action;
import static me.coley.recaf.ui.util.Menus.createHeader;
import static me.coley.recaf.ui.util.Menus.menu;

/**
* Context menu builder for methods.
Expand Down Expand Up @@ -77,6 +81,7 @@ public ContextMenu build() {
menu.getItems().add(refactor);
Menu view = menu("menu.view", Icons.EYE);
view.getItems().add(action("menu.view.methodcfg", Icons.CHILDREN, this::graph));
Col-E marked this conversation as resolved.
Show resolved Hide resolved
view.getItems().add(action("menu.view.methodcallgraph", Icons.CHILDREN, this::callGraph));
menu.getItems().add(view);
}
if (canUseVm()) {
Expand All @@ -95,6 +100,10 @@ public ContextMenu build() {
return menu;
}

private void callGraph() {
new GenericWindow(new MethodCallGraphsPane(WorkspaceAPI.getWorkspace(), methodInfo)).show();
}

@Override
public MethodContextBuilder setOwnerInfo(CommonClassInfo info) {
this.ownerInfo = info;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableObjectValue;
import javafx.beans.value.ObservableValue;
import javafx.event.EventHandler;
import javafx.scene.control.Label;
Expand Down Expand Up @@ -32,6 +33,8 @@
import me.coley.recaf.util.threading.ThreadUtil;
import me.coley.recaf.workspace.Workspace;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
Expand All @@ -55,12 +58,16 @@ public enum CallGraphMode {
}
}

public MethodCallGraphPane(Workspace workspace, CallGraphMode mode) {
public MethodCallGraphPane(@Nonnull Workspace workspace, @Nonnull CallGraphMode mode, @Nullable ObservableObjectValue<MethodInfo> methodInfoObservable) {
this.mode = mode;
this.workspace = workspace;
currentMethod.addListener((ChangeListener<? super MethodInfo>) this::onUpdateMethod);
graphTreeView.onUpdate(classInfo);
setCenter(graphTreeView);
if (methodInfoObservable != null) currentMethod.bind(methodInfoObservable);
}
public MethodCallGraphPane(@Nonnull Workspace workspace, @Nonnull CallGraphMode mode) {
this(workspace, mode, null);
}

private void onUpdateMethod(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package me.coley.recaf.ui.pane;

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.layout.BorderPane;
import me.coley.recaf.code.MethodInfo;
import me.coley.recaf.ui.docking.DockTab;
import me.coley.recaf.ui.docking.DockingRegion;
import me.coley.recaf.ui.docking.RecafDockingManager;
import me.coley.recaf.workspace.Workspace;

import javax.annotation.Nonnull;

public class MethodCallGraphsPane extends BorderPane {

private final ObjectProperty<MethodInfo> currentMethodInfo;

public MethodCallGraphsPane(@Nonnull Workspace workspace, @Nonnull MethodInfo methodInfo) {
currentMethodInfo = new SimpleObjectProperty<>(methodInfo);
DockingWrapperPane wrapper = DockingWrapperPane.builder()
.title(currentMethodInfo.map(method -> "Calls: " + method.getOwner() + "#" + method.getName() + method.getDescriptor()))
.content(new MethodCallGraphPane(workspace, MethodCallGraphPane.CallGraphMode.CALLS, currentMethodInfo))
.size(600, 300)
.build();
DockingRegion region = wrapper.getTab().getParent();
RecafDockingManager.getInstance().createTabIn(region,
() -> new DockTab(currentMethodInfo.map(method -> "Callers: " + method.getOwner() + "#" + method.getName() + method.getDescriptor()),
new MethodCallGraphPane(workspace, MethodCallGraphPane.CallGraphMode.CALLERS, currentMethodInfo)));
region.getDockTabs().forEach(t -> t.setClosable(true));
setCenter(wrapper);
}

public MethodInfo getCurrentMethodInfo() {
return currentMethodInfo.get();
}

public ObjectProperty<MethodInfo> currentMethodInfoProperty() {
return currentMethodInfo;
}
}
1 change: 1 addition & 0 deletions recaf-ui/src/main/resources/translations/en_US.lang
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ menu.view.hierarchy=Class hierarchy
menu.view.hierarchy.children=Children
menu.view.hierarchy.parents=Parents
menu.view.methodcfg=Control flow graph
menu.view.methodcallgraph=Call Graph
menu.tab.close=Close
menu.tab.closeothers=Close others
menu.tab.closeall=Close all
Expand Down