diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/usage/UsageInfoVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/usage/UsageInfoVisitor.java index a64fb3bd4..19989c8be 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/usage/UsageInfoVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/usage/UsageInfoVisitor.java @@ -6,6 +6,8 @@ import org.slf4j.LoggerFactory; import jadx.api.plugins.input.data.ICodeReader; import jadx.api.plugins.input.insns.InsnData; import jadx.api.plugins.input.insns.Opcode; +import jadx.core.dex.attributes.AType; +import jadx.core.dex.attributes.nodes.MethodOverrideAttr; import jadx.core.dex.info.FieldInfo; import jadx.core.dex.info.MethodInfo; import jadx.core.dex.instructions.args.ArgType; @@ -15,12 +17,14 @@ import jadx.core.dex.nodes.MethodNode; import jadx.core.dex.nodes.RootNode; import jadx.core.dex.visitors.AbstractVisitor; import jadx.core.dex.visitors.JadxVisitor; +import jadx.core.dex.visitors.OverrideMethodVisitor; import jadx.core.dex.visitors.RenameVisitor; @JadxVisitor( name = "UsageInfoVisitor", desc = "Scan class and methods to collect usage info and class dependencies", runAfter = { + OverrideMethodVisitor.class, // add method override as use RenameVisitor.class // sort by alias name } ) @@ -63,6 +67,12 @@ public class UsageInfoVisitor extends AbstractVisitor { } catch (Exception e) { mth.addError("Dependency scan failed", e); } + MethodOverrideAttr overrideAttr = mth.get(AType.METHOD_OVERRIDE); + if (overrideAttr != null) { + for (MethodNode relatedMthNode : overrideAttr.getRelatedMthNodes()) { + usageInfo.methodUse(relatedMthNode, mth); + } + } } private static void processInstructions(MethodNode mth, UsageInfo usageInfo) { diff --git a/jadx-gui/src/main/java/jadx/gui/treemodel/JClass.java b/jadx-gui/src/main/java/jadx/gui/treemodel/JClass.java index f6131dc7d..441358a99 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/JClass.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JClass.java @@ -10,6 +10,7 @@ import jadx.api.JavaClass; import jadx.api.JavaField; import jadx.api.JavaMethod; import jadx.api.JavaNode; +import jadx.core.dex.attributes.AFlag; import jadx.core.dex.info.AccessInfo; import jadx.gui.utils.NLS; import jadx.gui.utils.UiUtils; @@ -50,6 +51,11 @@ public class JClass extends JLoadableNode { getRootClass().load(); } + @Override + public boolean canRename() { + return !cls.getClassNode().contains(AFlag.DONT_RENAME); + } + public synchronized void load() { if (!loaded) { cls.decompile(); diff --git a/jadx-gui/src/main/java/jadx/gui/treemodel/JField.java b/jadx-gui/src/main/java/jadx/gui/treemodel/JField.java index 8d84fc7ef..6f9052d36 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/JField.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JField.java @@ -5,6 +5,7 @@ import javax.swing.ImageIcon; import jadx.api.JavaField; import jadx.api.JavaNode; +import jadx.core.dex.attributes.AFlag; import jadx.core.dex.info.AccessInfo; import jadx.gui.utils.OverlayIcon; import jadx.gui.utils.UiUtils; @@ -43,6 +44,11 @@ public class JField extends JNode { return jParent.getRootClass(); } + @Override + public boolean canRename() { + return !field.getFieldNode().contains(AFlag.DONT_RENAME); + } + @Override public int getLine() { return field.getDecompiledLine(); diff --git a/jadx-gui/src/main/java/jadx/gui/treemodel/JMethod.java b/jadx-gui/src/main/java/jadx/gui/treemodel/JMethod.java index ec185b00f..04f724a26 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/JMethod.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JMethod.java @@ -7,6 +7,7 @@ import javax.swing.ImageIcon; import jadx.api.JavaMethod; import jadx.api.JavaNode; +import jadx.core.dex.attributes.AFlag; import jadx.core.dex.info.AccessInfo; import jadx.core.dex.instructions.args.ArgType; import jadx.gui.utils.OverlayIcon; @@ -68,6 +69,11 @@ public class JMethod extends JNode { return icon; } + @Override + public boolean canRename() { + return !mth.getMethodNode().contains(AFlag.DONT_RENAME); + } + String makeBaseString() { if (mth.isClassInit()) { return "{...}"; 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 96b53ee37..56f31fa94 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/JNode.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JNode.java @@ -75,6 +75,10 @@ public abstract class JNode extends DefaultMutableTreeNode { return javaNode.getName(); } + public boolean canRename() { + return false; + } + public abstract String makeString(); public String makeStringHtml() { diff --git a/jadx-gui/src/main/java/jadx/gui/treemodel/JPackage.java b/jadx-gui/src/main/java/jadx/gui/treemodel/JPackage.java index ccbd855d5..e8e6d4c1a 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/JPackage.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JPackage.java @@ -74,6 +74,11 @@ public class JPackage extends JNode implements Comparable { return name; } + @Override + public boolean canRename() { + return true; + } + public String getFullName() { return fullName; } diff --git a/jadx-gui/src/main/java/jadx/gui/ui/RenameDialog.java b/jadx-gui/src/main/java/jadx/gui/ui/RenameDialog.java index 9a8c18840..ac89928f0 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/RenameDialog.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/RenameDialog.java @@ -26,6 +26,9 @@ import jadx.api.JavaField; import jadx.api.JavaMethod; import jadx.api.JavaNode; import jadx.core.codegen.CodeWriter; +import jadx.core.dex.attributes.AType; +import jadx.core.dex.attributes.nodes.MethodOverrideAttr; +import jadx.core.dex.nodes.MethodNode; import jadx.core.dex.nodes.RootNode; import jadx.core.dex.visitors.RenameVisitor; import jadx.core.utils.Utils; @@ -113,7 +116,13 @@ public class RenameDialog extends JDialog { if (node instanceof JMethod) { JavaMethod javaMethod = (JavaMethod) node.getJavaNode(); type = "m"; - id = javaMethod.getMethodNode().getMethodInfo().getRawFullId(); + MethodNode mthNode = javaMethod.getMethodNode(); + MethodOverrideAttr overrideAttr = mthNode.get(AType.METHOD_OVERRIDE); + if (overrideAttr != null) { + // use method closest to base method + mthNode = Objects.requireNonNull(Utils.last(overrideAttr.getRelatedMthNodes())); + } + id = mthNode.getMethodInfo().getRawFullId(); } else if (node instanceof JField) { JavaField javaField = (JavaField) node.getJavaNode(); type = "f"; diff --git a/jadx-gui/src/main/java/jadx/gui/ui/codearea/CodeLinkGenerator.java b/jadx-gui/src/main/java/jadx/gui/ui/codearea/CodeLinkGenerator.java index 54e7233dd..939230ef3 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/codearea/CodeLinkGenerator.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/codearea/CodeLinkGenerator.java @@ -13,6 +13,7 @@ import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import jadx.api.JavaNode; import jadx.gui.treemodel.JNode; import jadx.gui.utils.JumpPosition; @@ -27,6 +28,22 @@ public class CodeLinkGenerator implements LinkGenerator { this.jNode = codeArea.getNode(); } + public JavaNode getNodeAtOffset(RSyntaxTextArea textArea, int offset) { + try { + if (jNode.getCodeInfo() == null) { + return null; + } + int sourceOffset = getLinkSourceOffset(textArea, offset); + if (sourceOffset == -1) { + return null; + } + return codeArea.getJavaNodeAtOffset(offset); + } catch (Exception e) { + LOG.error("getNodeAtOffset error", e); + return null; + } + } + @Nullable public JumpPosition getJumpLinkAtOffset(RSyntaxTextArea textArea, int offset) { try { diff --git a/jadx-gui/src/main/java/jadx/gui/ui/codearea/MouseHoverHighlighter.java b/jadx-gui/src/main/java/jadx/gui/ui/codearea/MouseHoverHighlighter.java index 16833ffae..225ecbbd8 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/codearea/MouseHoverHighlighter.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/codearea/MouseHoverHighlighter.java @@ -11,7 +11,7 @@ import org.fife.ui.rtextarea.SmartHighlightPainter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import jadx.gui.utils.JumpPosition; +import jadx.api.JavaNode; class MouseHoverHighlighter extends MouseMotionAdapter { private static final Logger LOG = LoggerFactory.getLogger(MouseHoverHighlighter.class); @@ -50,8 +50,8 @@ class MouseHoverHighlighter extends MouseMotionAdapter { // don't repaint highlight return true; } - JumpPosition jump = codeLinkGenerator.getJumpLinkAtOffset(codeArea, tokenOffset); - if (jump == null) { + JavaNode nodeAtOffset = codeLinkGenerator.getNodeAtOffset(codeArea, tokenOffset); + if (nodeAtOffset == null) { return false; } removeHighlight(); diff --git a/jadx-gui/src/main/java/jadx/gui/ui/codearea/RenameAction.java b/jadx-gui/src/main/java/jadx/gui/ui/codearea/RenameAction.java index 0bf175b94..0ee2798b2 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/codearea/RenameAction.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/codearea/RenameAction.java @@ -2,6 +2,8 @@ package jadx.gui.ui.codearea; import java.awt.event.ActionEvent; +import javax.swing.event.PopupMenuEvent; + import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -19,6 +21,12 @@ public final class RenameAction extends JNodeMenuAction { super(NLS.str("popup.rename"), codeArea); } + @Override + public void popupMenuWillBecomeVisible(PopupMenuEvent e) { + super.popupMenuWillBecomeVisible(e); + setEnabled(node != null && node.canRename()); + } + @Override public void actionPerformed(ActionEvent e) { if (node == null) {