diff --git a/jadx-core/src/main/java/jadx/core/codegen/ClassGen.java b/jadx-core/src/main/java/jadx/core/codegen/ClassGen.java index b610ebacc..aed7a3349 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/ClassGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/ClassGen.java @@ -147,6 +147,7 @@ public class ClassGen { annotationGen.addForClass(clsCode); insertRenameInfo(clsCode, cls); + CodeGenUtils.addInputFileInfo(clsCode, cls); clsCode.startLineWithNum(cls.getSourceLine()).add(af.makeString()); if (af.isInterface()) { if (af.isAnnotation()) { diff --git a/jadx-core/src/main/java/jadx/core/utils/CodeGenUtils.java b/jadx-core/src/main/java/jadx/core/utils/CodeGenUtils.java index b759c7aa4..01c374945 100644 --- a/jadx-core/src/main/java/jadx/core/utils/CodeGenUtils.java +++ b/jadx-core/src/main/java/jadx/core/utils/CodeGenUtils.java @@ -100,6 +100,15 @@ public class CodeGenUtils { } } + public static void addInputFileInfo(ICodeWriter code, ClassNode node) { + if (node.getClsData() != null) { + String inputFileName = node.getClsData().getInputFileName(); + if (inputFileName != null) { + code.startLine("/* loaded from: ").add(inputFileName).add(" */"); + } + } + } + public static CodeVar getCodeVar(RegisterArg arg) { SSAVar svar = arg.getSVar(); if (svar != null) { diff --git a/jadx-core/src/test/java/jadx/tests/integration/debuginfo/TestLineNumbers2.java b/jadx-core/src/test/java/jadx/tests/integration/debuginfo/TestLineNumbers2.java index 32bee11cb..893cf8f0e 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/debuginfo/TestLineNumbers2.java +++ b/jadx-core/src/test/java/jadx/tests/integration/debuginfo/TestLineNumbers2.java @@ -39,7 +39,7 @@ public class TestLineNumbers2 extends IntegrationTest { ClassNode cls = getClassNode(TestCls.class); Map lineMapping = cls.getCode().getLineMapping(); - assertEquals("{5=17, 8=18, 11=22, 12=23, 13=24, 14=28, 16=25, 17=26, 18=28, 21=31, 22=32}", + assertEquals("{6=17, 9=18, 12=22, 13=23, 14=24, 15=28, 17=25, 18=26, 19=28, 22=31, 23=32}", lineMapping.toString()); } } diff --git a/jadx-core/src/test/java/jadx/tests/integration/loops/TestArrayForEachNegative.java b/jadx-core/src/test/java/jadx/tests/integration/loops/TestArrayForEachNegative.java index f94e228e8..a7f5f1ade 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/loops/TestArrayForEachNegative.java +++ b/jadx-core/src/test/java/jadx/tests/integration/loops/TestArrayForEachNegative.java @@ -50,6 +50,10 @@ public class TestArrayForEachNegative extends IntegrationTest { ClassNode cls = getClassNode(TestCls.class); String code = cls.getCode().toString(); + // Remove all comments - as the comment created by CodeGenUtils.addInputFileInfo + // always contains a colon + code = code.replaceAll("/\\*.*?\\*/", ""); + assertThat(code, not(containsString(":"))); } } diff --git a/jadx-gui/src/main/java/jadx/gui/treemodel/JNode.java b/jadx-gui/src/main/java/jadx/gui/treemodel/JNode.java index 226f0164a..4d60a9f47 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/JNode.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JNode.java @@ -116,6 +116,10 @@ public abstract class JNode extends DefaultMutableTreeNode { return javaNode.getDefPos(); } + public String getTooltip() { + return null; + } + @Override public String toString() { return makeString(); diff --git a/jadx-gui/src/main/java/jadx/gui/treemodel/JRoot.java b/jadx-gui/src/main/java/jadx/gui/treemodel/JRoot.java index 550b4f0fd..eb4683633 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/JRoot.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JRoot.java @@ -152,4 +152,21 @@ public class JRoot extends JNode { } return count + " files"; } + + @Override + public String getTooltip() { + List paths = wrapper.getOpenPaths(); + int count = paths.size(); + if (count < 2) { + return null; + } + // Show list of loaded files (full path) + StringBuilder sb = new StringBuilder(""); + for (Path p : paths) { + sb.append(UiUtils.escapeHtml(p.toString())); + sb.append("
"); + } + sb.append(""); + return sb.toString(); + } } 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 503263017..4d046df6a 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java @@ -60,6 +60,7 @@ import javax.swing.JToggleButton; import javax.swing.JToolBar; import javax.swing.JTree; import javax.swing.SwingUtilities; +import javax.swing.ToolTipManager; import javax.swing.WindowConstants; import javax.swing.event.MenuEvent; import javax.swing.event.MenuListener; @@ -1068,6 +1069,7 @@ public class MainWindow extends JFrame { DefaultMutableTreeNode treeRootNode = new DefaultMutableTreeNode(NLS.str("msg.open_file")); treeModel = new DefaultTreeModel(treeRootNode); tree = new JTree(treeModel); + ToolTipManager.sharedInstance().registerComponent(tree); tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); tree.addMouseListener(new MouseAdapter() { @Override @@ -1094,7 +1096,11 @@ public class MainWindow extends JFrame { boolean isLeaf, int row, boolean focused) { Component c = super.getTreeCellRendererComponent(tree, value, selected, expanded, isLeaf, row, focused); if (value instanceof JNode) { - setIcon(((JNode) value).getIcon()); + JNode jNode = (JNode) value; + setIcon(jNode.getIcon()); + setToolTipText(jNode.getTooltip()); + } else { + setToolTipText(null); } if (value instanceof JPackage) { setEnabled(((JPackage) value).isEnabled()); diff --git a/jadx-gui/src/main/java/jadx/gui/utils/UiUtils.java b/jadx-gui/src/main/java/jadx/gui/utils/UiUtils.java index 0786e7cf1..21c84b9db 100644 --- a/jadx-gui/src/main/java/jadx/gui/utils/UiUtils.java +++ b/jadx-gui/src/main/java/jadx/gui/utils/UiUtils.java @@ -94,7 +94,7 @@ public class UiUtils { } public static String escapeHtml(String str) { - return str.replace("<", "<"); + return str.replace("<", "<").replace(">", ">"); } public static String typeStr(ArgType type) {