diff --git a/jadx-core/src/main/java/jadx/api/plugins/gui/JadxGuiContext.java b/jadx-core/src/main/java/jadx/api/plugins/gui/JadxGuiContext.java index 90ea62ab9..84df21161 100644 --- a/jadx-core/src/main/java/jadx/api/plugins/gui/JadxGuiContext.java +++ b/jadx-core/src/main/java/jadx/api/plugins/gui/JadxGuiContext.java @@ -83,6 +83,11 @@ public interface JadxGuiContext { */ boolean open(ICodeNodeRef ref); + /** + * Open usage dialog for a node + */ + void openUsageDialog(ICodeNodeRef ref); + /** * Reload code in active tab */ diff --git a/jadx-gui/src/main/java/jadx/gui/plugins/context/GuiPluginContext.java b/jadx-gui/src/main/java/jadx/gui/plugins/context/GuiPluginContext.java index da2bb60d8..c0b750896 100644 --- a/jadx-gui/src/main/java/jadx/gui/plugins/context/GuiPluginContext.java +++ b/jadx-gui/src/main/java/jadx/gui/plugins/context/GuiPluginContext.java @@ -22,18 +22,15 @@ import jadx.api.plugins.events.types.NodeRenamedByUser; import jadx.api.plugins.gui.ISettingsGroup; import jadx.api.plugins.gui.JadxGuiContext; import jadx.api.plugins.gui.JadxGuiSettings; -import jadx.core.dex.nodes.ClassNode; -import jadx.core.dex.nodes.FieldNode; -import jadx.core.dex.nodes.MethodNode; import jadx.core.plugins.PluginContext; import jadx.core.utils.exceptions.JadxRuntimeException; import jadx.gui.treemodel.JNode; import jadx.gui.ui.codearea.AbstractCodeArea; import jadx.gui.ui.codearea.AbstractCodeContentPanel; import jadx.gui.ui.codearea.CodeArea; +import jadx.gui.ui.dialog.UsageDialog; import jadx.gui.ui.panel.ContentPanel; import jadx.gui.utils.IconsCache; -import jadx.gui.utils.JNodeCache; import jadx.gui.utils.UiUtils; public class GuiPluginContext implements JadxGuiContext { @@ -183,24 +180,19 @@ public class GuiPluginContext implements JadxGuiContext { @Override public boolean open(ICodeNodeRef ref) { - JNodeCache cache = commonContext.getMainWindow().getWrapper().getCache().getNodeCache(); - JNode node; - if (ref instanceof ClassNode) { - node = cache.makeFrom(((ClassNode) ref).getJavaNode()); - } else if (ref instanceof MethodNode) { - node = cache.makeFrom(((MethodNode) ref).getJavaNode()); - } else if (ref instanceof FieldNode) { - node = cache.makeFrom(((FieldNode) ref).getJavaNode()); - } else { - // Package node - cannot jump to it - // TODO: Var node - might be possible - return false; - } - - commonContext.getMainWindow().getTabsController().codeJump(node); + commonContext.getMainWindow().getTabsController().codeJump(getJNodeFromRef(ref)); return true; } + @Override + public void openUsageDialog(ICodeNodeRef ref) { + UsageDialog.open(commonContext.getMainWindow(), getJNodeFromRef(ref)); + } + + private JNode getJNodeFromRef(ICodeNodeRef ref) { + return commonContext.getMainWindow().getCacheObject().getNodeCache().makeFrom(ref); + } + @Override public void reloadActiveTab() { UiUtils.uiRun(() -> { diff --git a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java index 3d04976e4..f47154301 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java @@ -254,9 +254,9 @@ public class MainWindow extends JFrame implements ExportProjectDialog.ExportProj public MainWindow(JadxSettings settings) { this.settings = settings; - this.cacheObject = new CacheObject(); this.project = new JadxProject(this); this.wrapper = new JadxWrapper(this); + this.cacheObject = new CacheObject(wrapper); this.liveReloadWorker = new LiveReloadWorker(this); this.renameMappings = new RenameMappingsGui(this); this.cacheManager = new CacheManager(settings); diff --git a/jadx-gui/src/main/java/jadx/gui/ui/codearea/FindUsageAction.java b/jadx-gui/src/main/java/jadx/gui/ui/codearea/FindUsageAction.java index 37b06c945..2f413654c 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/codearea/FindUsageAction.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/codearea/FindUsageAction.java @@ -1,7 +1,6 @@ package jadx.gui.ui.codearea; import jadx.gui.treemodel.JNode; -import jadx.gui.ui.MainWindow; import jadx.gui.ui.action.ActionModel; import jadx.gui.ui.dialog.UsageDialog; @@ -14,15 +13,6 @@ public final class FindUsageAction extends JNodeAction { @Override public void runAction(JNode node) { - MainWindow mw = getCodeArea().getMainWindow(); - UsageDialog usageDialog = new UsageDialog(mw, node); - mw.addLoadListener(loaded -> { - if (!loaded) { - usageDialog.dispose(); - return true; - } - return false; - }); - usageDialog.setVisible(true); + UsageDialog.open(getCodeArea().getMainWindow(), node); } } diff --git a/jadx-gui/src/main/java/jadx/gui/ui/dialog/UsageDialog.java b/jadx-gui/src/main/java/jadx/gui/ui/dialog/UsageDialog.java index 5155c4a60..7c4573120 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/dialog/UsageDialog.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/dialog/UsageDialog.java @@ -42,7 +42,19 @@ public class UsageDialog extends CommonSearchDialog { private transient List usageList; - public UsageDialog(MainWindow mainWindow, JNode node) { + public static void open(MainWindow mainWindow, JNode node) { + UsageDialog usageDialog = new UsageDialog(mainWindow, node); + mainWindow.addLoadListener(loaded -> { + if (!loaded) { + usageDialog.dispose(); + return true; + } + return false; + }); + usageDialog.setVisible(true); + } + + private UsageDialog(MainWindow mainWindow, JNode node) { super(mainWindow, NLS.str("usage_dialog.title")); this.node = node; diff --git a/jadx-gui/src/main/java/jadx/gui/utils/CacheObject.java b/jadx-gui/src/main/java/jadx/gui/utils/CacheObject.java index 6e45dc221..de7673485 100644 --- a/jadx-gui/src/main/java/jadx/gui/utils/CacheObject.java +++ b/jadx-gui/src/main/java/jadx/gui/utils/CacheObject.java @@ -8,10 +8,12 @@ import java.util.Set; import org.jetbrains.annotations.Nullable; import jadx.api.JavaClass; +import jadx.gui.JadxWrapper; import jadx.gui.ui.dialog.SearchDialog; import jadx.gui.utils.pkgs.PackageHelper; public class CacheObject { + private final JadxWrapper wrapper; private String lastSearch; private JNodeCache jNodeCache; @@ -23,13 +25,14 @@ public class CacheObject { private volatile boolean fullDecompilationFinished; - public CacheObject() { + public CacheObject(JadxWrapper wrapper) { + this.wrapper = wrapper; reset(); } public void reset() { lastSearch = null; - jNodeCache = new JNodeCache(); + jNodeCache = new JNodeCache(wrapper); lastSearchOptions = new HashMap<>(); lastSearchPackage = null; decompileBatches = null; diff --git a/jadx-gui/src/main/java/jadx/gui/utils/JNodeCache.java b/jadx-gui/src/main/java/jadx/gui/utils/JNodeCache.java index e6b20bc90..ac63f650d 100644 --- a/jadx-gui/src/main/java/jadx/gui/utils/JNodeCache.java +++ b/jadx-gui/src/main/java/jadx/gui/utils/JNodeCache.java @@ -8,7 +8,9 @@ import jadx.api.JavaField; import jadx.api.JavaMethod; import jadx.api.JavaNode; import jadx.api.JavaVariable; +import jadx.api.metadata.ICodeNodeRef; import jadx.core.utils.exceptions.JadxRuntimeException; +import jadx.gui.JadxWrapper; import jadx.gui.treemodel.JClass; import jadx.gui.treemodel.JField; import jadx.gui.treemodel.JMethod; @@ -16,36 +18,48 @@ import jadx.gui.treemodel.JNode; import jadx.gui.treemodel.JVariable; public class JNodeCache { + private final JadxWrapper wrapper; + private final Map cache = new ConcurrentHashMap<>(); - private final Map cache = new ConcurrentHashMap<>(); + public JNodeCache(JadxWrapper wrapper) { + this.wrapper = wrapper; + } + + public JNode makeFrom(ICodeNodeRef nodeRef) { + if (nodeRef == null) { + return null; + } + // don't use 'computeIfAbsent' method here, it will cause 'Recursive update' exception + JNode jNode = cache.get(nodeRef); + if (jNode == null || jNode.getJavaNode().getCodeNodeRef() != nodeRef) { + jNode = convert(nodeRef); + cache.put(nodeRef, jNode); + } + return jNode; + } public JNode makeFrom(JavaNode javaNode) { if (javaNode == null) { return null; } - // don't use 'computeIfAbsent' method here, it will cause 'Recursive update' exception - JNode jNode = cache.get(javaNode); - if (jNode == null || jNode.getJavaNode() != javaNode) { - jNode = convert(javaNode); - cache.put(javaNode, jNode); - } - return jNode; + return makeFrom(javaNode.getCodeNodeRef()); } public JClass makeFrom(JavaClass javaCls) { if (javaCls == null) { return null; } - JClass jCls = (JClass) cache.get(javaCls); + ICodeNodeRef nodeRef = javaCls.getCodeNodeRef(); + JClass jCls = (JClass) cache.get(nodeRef); if (jCls == null || jCls.getCls() != javaCls) { jCls = convert(javaCls); - cache.put(javaCls, jCls); + cache.put(nodeRef, jCls); } return jCls; } public void remove(JavaNode javaNode) { - cache.remove(javaNode); + cache.remove(javaNode.getCodeNodeRef()); } public void removeWholeClass(JavaClass javaCls) { @@ -64,12 +78,17 @@ public class JNodeCache { return new JClass(cls, makeFrom(parentCls)); } + private JNode convert(ICodeNodeRef nodeRef) { + JavaNode javaNode = wrapper.getDecompiler().getJavaNodeByRef(nodeRef); + return convert(javaNode); + } + private JNode convert(JavaNode node) { if (node == null) { return null; } if (node instanceof JavaClass) { - return convert(((JavaClass) node)); + return convert((JavaClass) node); } if (node instanceof JavaMethod) { return new JMethod((JavaMethod) node, makeFrom(node.getDeclaringClass()));