From c8df26f227bb9d102225e19c9330da074116f219 Mon Sep 17 00:00:00 2001 From: Skylot Date: Thu, 18 Jul 2019 22:58:54 +0300 Subject: [PATCH] feat(gui): add class links for AndroidManifest.xml and other minor fixes --- .../src/main/java/jadx/api/ICodeInfo.java | 11 +++ .../main/java/jadx/api/JadxDecompiler.java | 43 +++++++++ .../src/main/java/jadx/api/JavaClass.java | 41 ++------- .../main/java/jadx/api/ResourcesLoader.java | 4 +- .../java/jadx/core/codegen/CodeWriter.java | 9 +- .../java/jadx/core/dex/nodes/RootNode.java | 14 +++ .../jadx/core/xmlgen/BinaryXMLParser.java | 23 ++++- .../main/java/jadx/core/xmlgen/XmlDeobf.java | 7 +- .../src/main/java/jadx/gui/JadxWrapper.java | 4 + .../main/java/jadx/gui/treemodel/JClass.java | 13 +-- .../main/java/jadx/gui/treemodel/JNode.java | 23 ++++- .../java/jadx/gui/treemodel/JResource.java | 53 ++++++----- .../java/jadx/gui/ui/CommonSearchDialog.java | 6 +- .../src/main/java/jadx/gui/ui/ImagePanel.java | 4 +- .../src/main/java/jadx/gui/ui/LogViewer.java | 4 +- .../src/main/java/jadx/gui/ui/MainWindow.java | 43 +++------ .../src/main/java/jadx/gui/ui/TabbedPane.java | 8 +- .../gui/ui/codearea/AbstractCodeArea.java | 78 ++++++++++++++--- .../ui/codearea/ClassCodeContentPanel.java | 19 ++-- .../java/jadx/gui/ui/codearea/CodeArea.java | 87 ++++--------------- .../gui/ui/codearea/CodeContentPanel.java | 4 +- .../gui/ui/codearea/CodeLinkGenerator.java | 34 +++++--- .../java/jadx/gui/ui/codearea/CodePanel.java | 34 +++++--- .../jadx/gui/ui/codearea/FindUsageAction.java | 7 +- .../ui/codearea/GoToDeclarationAction.java | 2 +- .../jadx/gui/ui/codearea/JadxTokenMaker.java | 7 +- .../jadx/gui/ui/codearea/LineNumbers.java | 16 ++-- .../java/jadx/gui/ui/codearea/SmaliArea.java | 15 +++- 28 files changed, 357 insertions(+), 256 deletions(-) create mode 100644 jadx-core/src/main/java/jadx/api/ICodeInfo.java diff --git a/jadx-core/src/main/java/jadx/api/ICodeInfo.java b/jadx-core/src/main/java/jadx/api/ICodeInfo.java new file mode 100644 index 000000000..50ac1aa14 --- /dev/null +++ b/jadx-core/src/main/java/jadx/api/ICodeInfo.java @@ -0,0 +1,11 @@ +package jadx.api; + +import java.util.Map; + +public interface ICodeInfo { + String getCodeStr(); + + Map getLineMapping(); + + Map getAnnotations(); +} diff --git a/jadx-core/src/main/java/jadx/api/JadxDecompiler.java b/jadx-core/src/main/java/jadx/api/JadxDecompiler.java index 6bb3b84d6..85f34ed2c 100644 --- a/jadx-core/src/main/java/jadx/api/JadxDecompiler.java +++ b/jadx-core/src/main/java/jadx/api/JadxDecompiler.java @@ -15,6 +15,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.function.Predicate; +import org.jetbrains.annotations.Nullable; import org.jf.baksmali.Adaptors.ClassDefinition; import org.jf.baksmali.BaksmaliOptions; import org.jf.dexlib2.DexFileFactory; @@ -28,6 +29,7 @@ import org.slf4j.LoggerFactory; import jadx.core.Jadx; import jadx.core.ProcessClass; import jadx.core.dex.attributes.AFlag; +import jadx.core.dex.attributes.nodes.LineAttrNode; import jadx.core.dex.nodes.ClassNode; import jadx.core.dex.nodes.FieldNode; import jadx.core.dex.nodes.MethodNode; @@ -390,6 +392,47 @@ public final class JadxDecompiler { return null; } + @Nullable + JavaNode convertNode(Object obj) { + if (!(obj instanceof LineAttrNode)) { + return null; + } + if (obj instanceof ClassNode) { + return getClassesMap().get(obj); + } + if (obj instanceof MethodNode) { + return getJavaMethodByNode(((MethodNode) obj)); + } + if (obj instanceof FieldNode) { + return getJavaFieldByNode((FieldNode) obj); + } + return null; + } + + @Nullable + public JavaNode getJavaNodeAtPosition(ICodeInfo codeInfo, int line, int offset) { + Map map = codeInfo.getAnnotations(); + if (map.isEmpty()) { + return null; + } + Object obj = map.get(new CodePosition(line, offset)); + if (obj == null) { + return null; + } + return convertNode(obj); + } + + @Nullable + public CodePosition getDefinitionPosition(JavaNode javaNode) { + JavaClass jCls = javaNode.getTopParentClass(); + jCls.decompile(); + int defLine = javaNode.getDecompiledLine(); + if (defLine == 0) { + return null; + } + return new CodePosition(jCls, defLine, 0); + } + public JadxArgs getArgs() { return args; } diff --git a/jadx-core/src/main/java/jadx/api/JavaClass.java b/jadx-core/src/main/java/jadx/api/JavaClass.java index e9387b2fd..571878753 100644 --- a/jadx-core/src/main/java/jadx/api/JavaClass.java +++ b/jadx-core/src/main/java/jadx/api/JavaClass.java @@ -152,7 +152,7 @@ public final class JavaClass implements JavaNode { CodePosition codePosition = entry.getKey(); Object obj = entry.getValue(); if (obj instanceof LineAttrNode) { - JavaNode node = convertNode(obj); + JavaNode node = getRootDecompiler().convertNode(obj); if (node != null) { resultMap.put(codePosition, node); } @@ -161,45 +161,15 @@ public final class JavaClass implements JavaNode { return resultMap; } - @Nullable - private JavaNode convertNode(Object obj) { - if (!(obj instanceof LineAttrNode)) { - return null; - } - if (obj instanceof ClassNode) { - return getRootDecompiler().getClassesMap().get(obj); - } - if (obj instanceof MethodNode) { - return getRootDecompiler().getJavaMethodByNode(((MethodNode) obj)); - } - if (obj instanceof FieldNode) { - return getRootDecompiler().getJavaFieldByNode((FieldNode) obj); - } - return null; - } - @Nullable public JavaNode getJavaNodeAtPosition(int line, int offset) { - Map map = getCodeAnnotations(); - if (map.isEmpty()) { - return null; - } - Object obj = map.get(new CodePosition(line, offset)); - if (obj == null) { - return null; - } - return convertNode(obj); + decompile(); + return getRootDecompiler().getJavaNodeAtPosition(cls.getCode(), line, offset); } @Nullable - public CodePosition getDefinitionPosition(JavaNode javaNode) { - JavaClass jCls = javaNode.getTopParentClass(); - jCls.decompile(); - int defLine = javaNode.getDecompiledLine(); - if (defLine == 0) { - return null; - } - return new CodePosition(jCls, defLine, 0); + public CodePosition getDefinitionPosition() { + return getRootDecompiler().getDefinitionPosition(this); } public Integer getSourceLine(int decompiledLine) { @@ -250,6 +220,7 @@ public final class JavaClass implements JavaNode { return methods; } + @Override public int getDecompiledLine() { return cls.getDecompiledLine(); } diff --git a/jadx-core/src/main/java/jadx/api/ResourcesLoader.java b/jadx-core/src/main/java/jadx/api/ResourcesLoader.java index 0eeae35a1..12ff1fa35 100644 --- a/jadx-core/src/main/java/jadx/api/ResourcesLoader.java +++ b/jadx-core/src/main/java/jadx/api/ResourcesLoader.java @@ -164,10 +164,8 @@ public final class ResourcesLoader { } public static CodeWriter loadToCodeWriter(InputStream is) throws IOException { - CodeWriter cw = new CodeWriter(); ByteArrayOutputStream baos = new ByteArrayOutputStream(READ_BUFFER_SIZE); copyStream(is, baos); - cw.add(baos.toString("UTF-8")); - return cw; + return new CodeWriter(baos.toString("UTF-8")); } } diff --git a/jadx-core/src/main/java/jadx/core/codegen/CodeWriter.java b/jadx-core/src/main/java/jadx/core/codegen/CodeWriter.java index 459575388..33511e518 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/CodeWriter.java +++ b/jadx-core/src/main/java/jadx/core/codegen/CodeWriter.java @@ -12,12 +12,13 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import jadx.api.CodePosition; +import jadx.api.ICodeInfo; import jadx.core.dex.attributes.nodes.LineAttrNode; import jadx.core.utils.StringUtils; import jadx.core.utils.files.FileUtils; import jadx.core.utils.files.ZipSecurity; -public class CodeWriter { +public class CodeWriter implements ICodeInfo { private static final Logger LOG = LoggerFactory.getLogger(CodeWriter.class); public static final String NL = System.getProperty("line.separator"); @@ -242,6 +243,7 @@ public class CodeWriter { return annotations.put(pos, obj); } + @Override public Map getAnnotations() { return annotations; } @@ -260,6 +262,7 @@ public class CodeWriter { lineMap.put(decompiledLine, sourceLine); } + @Override public Map getLineMapping() { return lineMap; } @@ -293,7 +296,11 @@ public class CodeWriter { return buf.length(); } + @Override public String getCodeStr() { + if (code == null) { + throw new NullPointerException("Code not set"); + } return code; } diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java index a8d2f2294..b6f5cdf20 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java @@ -164,6 +164,20 @@ public class RootNode { return resolveClass(clsInfo); } + @Nullable + public ClassNode searchClassByFullAlias(String fullName) { + for (DexNode dexNode : dexNodes) { + for (ClassNode cls : dexNode.getClasses()) { + ClassInfo classInfo = cls.getClassInfo(); + if (classInfo.getFullName().equals(fullName) + || classInfo.getAliasFullName().equals(fullName)) { + return cls; + } + } + } + return null; + } + public List searchClassByShortName(String shortName) { List list = new ArrayList<>(); for (DexNode dexNode : dexNodes) { diff --git a/jadx-core/src/main/java/jadx/core/xmlgen/BinaryXMLParser.java b/jadx-core/src/main/java/jadx/core/xmlgen/BinaryXMLParser.java index 2c4247215..3e777fe08 100644 --- a/jadx-core/src/main/java/jadx/core/xmlgen/BinaryXMLParser.java +++ b/jadx-core/src/main/java/jadx/core/xmlgen/BinaryXMLParser.java @@ -15,6 +15,7 @@ import org.slf4j.LoggerFactory; import jadx.api.ResourcesLoader; import jadx.core.codegen.CodeWriter; import jadx.core.dex.info.ConstStorage; +import jadx.core.dex.nodes.ClassNode; import jadx.core.dex.nodes.RootNode; import jadx.core.utils.StringUtils; import jadx.core.utils.exceptions.JadxRuntimeException; @@ -32,7 +33,6 @@ import jadx.core.xmlgen.entry.ValuesParser; * Check Element chunk size */ -@SuppressWarnings("unused") public class BinaryXMLParser extends CommonBinaryParser { private static final Logger LOG = LoggerFactory.getLogger(BinaryXMLParser.class); @@ -306,6 +306,7 @@ public class BinaryXMLParser extends CommonBinaryParser { if (isDeobfCandidateAttr(shortNsName, attrName)) { decodedAttr = deobfClassName(decodedAttr); } + attachClassNode(writer, attrName, decodedAttr); writer.add(StringUtils.escapeXML(decodedAttr)); } else { decodeAttribute(attributeNS, attrValDataType, attrValData, @@ -401,6 +402,7 @@ public class BinaryXMLParser extends CommonBinaryParser { if (isDeobfCandidateAttr(shortNsName, attrName)) { str = deobfClassName(str); } + attachClassNode(writer, attrName, str); writer.add(str != null ? StringUtils.escapeXML(str) : "null"); } } @@ -459,9 +461,24 @@ public class BinaryXMLParser extends CommonBinaryParser { return sb.toString(); } + private void attachClassNode(CodeWriter writer, String attrName, String clsName) { + if (clsName == null || !attrName.equals("name")) { + return; + } + String clsFullName; + if (clsName.startsWith(".")) { + clsFullName = appPackageName + clsName; + } else { + clsFullName = clsName; + } + ClassNode classNode = rootNode.searchClassByFullAlias(clsFullName); + if (classNode != null) { + writer.attachAnnotation(classNode); + } + } + private String deobfClassName(String className) { - String newName = XmlDeobf.deobfClassName(rootNode, className, - appPackageName); + String newName = XmlDeobf.deobfClassName(rootNode, className, appPackageName); if (newName != null) { return newName; } diff --git a/jadx-core/src/main/java/jadx/core/xmlgen/XmlDeobf.java b/jadx-core/src/main/java/jadx/core/xmlgen/XmlDeobf.java index 4e3942a57..3eb2e0acc 100644 --- a/jadx-core/src/main/java/jadx/core/xmlgen/XmlDeobf.java +++ b/jadx-core/src/main/java/jadx/core/xmlgen/XmlDeobf.java @@ -3,6 +3,8 @@ package jadx.core.xmlgen; import java.util.HashMap; import java.util.Map; +import org.jetbrains.annotations.Nullable; + import jadx.core.dex.info.ClassInfo; import jadx.core.dex.nodes.ClassNode; import jadx.core.dex.nodes.RootNode; @@ -17,9 +19,8 @@ public class XmlDeobf { private XmlDeobf() { } - public static String deobfClassName(RootNode rootNode, String potencialClassName, - String packageName) { - + @Nullable + public static String deobfClassName(RootNode rootNode, String potencialClassName, String packageName) { if (packageName != null && potencialClassName.startsWith(".")) { potencialClassName = packageName + potencialClassName; } diff --git a/jadx-gui/src/main/java/jadx/gui/JadxWrapper.java b/jadx-gui/src/main/java/jadx/gui/JadxWrapper.java index 6d87c99f8..7b3f5667b 100644 --- a/jadx-gui/src/main/java/jadx/gui/JadxWrapper.java +++ b/jadx-gui/src/main/java/jadx/gui/JadxWrapper.java @@ -131,6 +131,10 @@ public class JadxWrapper { return openFile; } + public JadxDecompiler getDecompiler() { + return decompiler; + } + public JadxArgs getArgs() { return decompiler.getArgs(); } 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 1d80d3f55..46becf9ab 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/JClass.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JClass.java @@ -3,7 +3,9 @@ package jadx.gui.treemodel; import javax.swing.*; import org.fife.ui.rsyntaxtextarea.SyntaxConstants; +import org.jetbrains.annotations.Nullable; +import jadx.api.ICodeInfo; import jadx.api.JavaClass; import jadx.api.JavaField; import jadx.api.JavaMethod; @@ -76,6 +78,12 @@ public class JClass extends JLoadableNode { } } + @Override + public @Nullable ICodeInfo getCodeInfo() { + load(); + return cls.getClassNode().getCode(); + } + @Override public String getContent() { return cls.getCode(); @@ -147,11 +155,6 @@ public class JClass extends JLoadableNode { return cls.getDecompiledLine(); } - @Override - public Integer getSourceLine(int line) { - return cls.getSourceLine(line); - } - @Override public int hashCode() { return cls.hashCode(); 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 40593c64a..85750bc25 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/JNode.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JNode.java @@ -4,7 +4,10 @@ import javax.swing.*; import javax.swing.tree.DefaultMutableTreeNode; import org.fife.ui.rsyntaxtextarea.SyntaxConstants; +import org.jetbrains.annotations.Nullable; +import jadx.api.ICodeInfo; +import jadx.api.JadxDecompiler; import jadx.api.JavaNode; public abstract class JNode extends DefaultMutableTreeNode { @@ -40,10 +43,28 @@ public abstract class JNode extends DefaultMutableTreeNode { return 0; } - public Integer getSourceLine(int line) { + @Nullable + public ICodeInfo getCodeInfo() { return null; } + public final Integer getSourceLine(int line) { + ICodeInfo codeInfo = getCodeInfo(); + if (codeInfo == null) { + return null; + } + return codeInfo.getLineMapping().get(line); + } + + @Nullable + public JavaNode getJavaNodeAtPosition(JadxDecompiler decompiler, int line, int offset) { + ICodeInfo codeInfo = getCodeInfo(); + if (codeInfo == null) { + return null; + } + return decompiler.getJavaNodeAtPosition(codeInfo, line, offset); + } + public abstract Icon getIcon(); public String getName() { diff --git a/jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java b/jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java index 9cad1dc2a..608517f20 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JResource.java @@ -1,7 +1,6 @@ package jadx.gui.treemodel; import java.util.ArrayList; -import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; @@ -10,7 +9,9 @@ import javax.swing.*; import org.fife.ui.rsyntaxtextarea.SyntaxConstants; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import jadx.api.ICodeInfo; import jadx.api.ResourceFile; import jadx.api.ResourceFileContent; import jadx.api.ResourceType; @@ -44,8 +45,7 @@ public class JResource extends JLoadableNode implements Comparable { private final transient ResourceFile resFile; private transient boolean loaded; - private transient String content; - private transient Map lineMapping = Collections.emptyMap(); + private transient ICodeInfo content; public JResource(ResourceFile resFile, String name, JResType type) { this(resFile, name, name, type); @@ -98,10 +98,19 @@ public class JResource extends JLoadableNode implements Comparable { return files; } + @Override + public @Nullable ICodeInfo getCodeInfo() { + getContent(); + return content; + } + @Override public synchronized String getContent() { if (loaded) { - return content; + if (content == null) { + return null; + } + return content.getCodeStr(); } if (resFile == null || type != JResType.FILE) { return null; @@ -111,6 +120,7 @@ public class JResource extends JLoadableNode implements Comparable { } ResContainer rc = resFile.loadContent(); if (rc == null) { + loaded = true; return null; } if (rc.getDataType() == ResContainer.DataType.RES_TABLE) { @@ -118,36 +128,35 @@ public class JResource extends JLoadableNode implements Comparable { for (ResContainer subFile : rc.getSubFiles()) { loadSubNodes(this, subFile, 1); } - loaded = true; - return content; + } else { + // single node + content = loadCurrentSingleRes(rc); } - // single node - return loadCurrentSingleRes(rc); + loaded = true; + return content.getCodeStr(); } - private String loadCurrentSingleRes(ResContainer rc) { + private ICodeInfo loadCurrentSingleRes(ResContainer rc) { switch (rc.getDataType()) { case TEXT: case RES_TABLE: - CodeWriter cw = rc.getText(); - lineMapping = cw.getLineMapping(); - return cw.toString(); + return rc.getText(); case RES_LINK: try { return ResourcesLoader.decodeStream(rc.getResLink(), (size, is) -> { if (size > 10 * 1024 * 1024L) { - return "File too large for view"; + return new CodeWriter("File too large for view"); } - return ResourcesLoader.loadToCodeWriter(is).toString(); + return ResourcesLoader.loadToCodeWriter(is); }); } catch (Exception e) { - return "Failed to load resource file: \n" + jadx.core.utils.Utils.getStackTrace(e); + return new CodeWriter("Failed to load resource file: \n" + jadx.core.utils.Utils.getStackTrace(e)); } case DECODED_DATA: default: - return "Unexpected resource type: " + rc; + return new CodeWriter("Unexpected resource type: " + rc); } } @@ -192,14 +201,6 @@ public class JResource extends JLoadableNode implements Comparable { return resDir; } - @Override - public Integer getSourceLine(int line) { - if (lineMapping == null) { - return null; - } - return lineMapping.get(line); - } - @Override public String getSyntaxName() { if (resFile == null) { @@ -291,10 +292,6 @@ public class JResource extends JLoadableNode implements Comparable { return resFile; } - public Map getLineMapping() { - return lineMapping; - } - @Override public JClass getJParent() { return null; diff --git a/jadx-gui/src/main/java/jadx/gui/ui/CommonSearchDialog.java b/jadx-gui/src/main/java/jadx/gui/ui/CommonSearchDialog.java index dd9eba74c..86073aa15 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/CommonSearchDialog.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/CommonSearchDialog.java @@ -32,7 +32,7 @@ import jadx.gui.jobs.BackgroundJob; import jadx.gui.jobs.BackgroundWorker; import jadx.gui.jobs.DecompileJob; import jadx.gui.treemodel.JNode; -import jadx.gui.ui.codearea.CodeArea; +import jadx.gui.ui.codearea.AbstractCodeArea; import jadx.gui.utils.CacheObject; import jadx.gui.utils.JumpPosition; import jadx.gui.utils.NLS; @@ -403,7 +403,7 @@ public abstract class CommonSearchDialog extends JDialog { private final Map componentCache = new HashMap<>(); public ResultsTableCellRenderer() { - RSyntaxTextArea area = CodeArea.getDefaultArea(mainWindow); + RSyntaxTextArea area = AbstractCodeArea.getDefaultArea(mainWindow); this.font = area.getFont(); this.codeSelectedColor = area.getSelectionColor(); this.codeBackground = area.getBackground(); @@ -455,7 +455,7 @@ public abstract class CommonSearchDialog extends JDialog { if (!node.hasDescString()) { return emptyLabel; } - RSyntaxTextArea textArea = CodeArea.getDefaultArea(mainWindow); + RSyntaxTextArea textArea = AbstractCodeArea.getDefaultArea(mainWindow); textArea.setLayout(new GridLayout(1, 1)); textArea.setEditable(false); textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); diff --git a/jadx-gui/src/main/java/jadx/gui/ui/ImagePanel.java b/jadx-gui/src/main/java/jadx/gui/ui/ImagePanel.java index 24bc9ca52..f3d64a029 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/ImagePanel.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/ImagePanel.java @@ -16,7 +16,7 @@ import jadx.core.utils.Utils; import jadx.core.utils.exceptions.JadxRuntimeException; import jadx.core.xmlgen.ResContainer; import jadx.gui.treemodel.JResource; -import jadx.gui.ui.codearea.CodeArea; +import jadx.gui.ui.codearea.AbstractCodeArea; public class ImagePanel extends ContentPanel { private static final long serialVersionUID = 4071356367073142688L; @@ -29,7 +29,7 @@ public class ImagePanel extends ContentPanel { ImageViewer imageViewer = new ImageViewer(img); add(imageViewer.getComponent()); } catch (Exception e) { - RSyntaxTextArea textArea = CodeArea.getDefaultArea(panel.getMainWindow()); + RSyntaxTextArea textArea = AbstractCodeArea.getDefaultArea(panel.getMainWindow()); textArea.setText("Image load error: \n" + Utils.getStackTrace(e)); add(textArea); } diff --git a/jadx-gui/src/main/java/jadx/gui/ui/LogViewer.java b/jadx-gui/src/main/java/jadx/gui/ui/LogViewer.java index 978be5726..27413bf52 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/LogViewer.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/LogViewer.java @@ -9,7 +9,7 @@ import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; import ch.qos.logback.classic.Level; import jadx.gui.settings.JadxSettings; -import jadx.gui.ui.codearea.CodeArea; +import jadx.gui.ui.codearea.AbstractCodeArea; import jadx.gui.utils.NLS; import jadx.gui.utils.logs.ILogListener; import jadx.gui.utils.logs.LogCollector; @@ -31,7 +31,7 @@ class LogViewer extends JDialog { } public final void initUI(MainWindow mainWindow) { - textPane = CodeArea.getDefaultArea(mainWindow); + textPane = AbstractCodeArea.getDefaultArea(mainWindow); textPane.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15)); JPanel controlPane = new JPanel(); 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 f903d691c..41278a3d9 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java @@ -1,12 +1,6 @@ package jadx.gui.ui; -import java.awt.BorderLayout; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.DisplayMode; -import java.awt.Font; -import java.awt.GraphicsDevice; -import java.awt.GraphicsEnvironment; +import java.awt.*; import java.awt.dnd.DnDConstants; import java.awt.dnd.DropTarget; import java.awt.event.ActionEvent; @@ -29,27 +23,7 @@ import java.util.Locale; import java.util.Timer; import java.util.TimerTask; -import javax.swing.AbstractAction; -import javax.swing.Action; -import javax.swing.Box; -import javax.swing.ImageIcon; -import javax.swing.JCheckBoxMenuItem; -import javax.swing.JFileChooser; -import javax.swing.JFrame; -import javax.swing.JMenu; -import javax.swing.JMenuBar; -import javax.swing.JMenuItem; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JPopupMenu; -import javax.swing.JScrollPane; -import javax.swing.JSplitPane; -import javax.swing.JToggleButton; -import javax.swing.JToolBar; -import javax.swing.JTree; -import javax.swing.ProgressMonitor; -import javax.swing.SwingUtilities; -import javax.swing.WindowConstants; +import javax.swing.*; import javax.swing.event.MenuEvent; import javax.swing.event.MenuListener; import javax.swing.event.TreeExpansionEvent; @@ -518,7 +492,7 @@ public class MainWindow extends JFrame { if (resFile != null && JResource.isSupportedForView(resFile.getType())) { tabbedPane.showResource(res); } - } else if ((obj instanceof JCertificate) || (obj instanceof ApkSignature)) { + } else if (obj instanceof JCertificate || obj instanceof ApkSignature) { tabbedPane.showSimpleNode((JNode) obj); } else if (obj instanceof JNode) { JNode node = (JNode) obj; @@ -533,10 +507,13 @@ public class MainWindow extends JFrame { } private void treeRightClickAction(MouseEvent e) { - Object obj = tree.getLastSelectedPathComponent(); - if (obj instanceof JPackage) { - JPackagePopUp menu = new JPackagePopUp((JPackage) obj); - menu.show(e.getComponent(), e.getX(), e.getY()); + TreePath path = tree.getPathForLocation(e.getX(), e.getY()); + if (path != null) { + Object obj = path.getLastPathComponent(); + if (obj instanceof JPackage) { + JPackagePopUp menu = new JPackagePopUp((JPackage) obj); + menu.show(e.getComponent(), e.getX(), e.getY()); + } } } diff --git a/jadx-gui/src/main/java/jadx/gui/ui/TabbedPane.java b/jadx-gui/src/main/java/jadx/gui/ui/TabbedPane.java index 42ccfc3e3..f389de0af 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/TabbedPane.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/TabbedPane.java @@ -42,7 +42,7 @@ public class TabbedPane extends JTabbedPane { private final transient MainWindow mainWindow; private final transient Map openTabs = new LinkedHashMap<>(); - private transient JumpManager jumps = new JumpManager(); + private final transient JumpManager jumps = new JumpManager(); TabbedPane(MainWindow window) { this.mainWindow = window; @@ -216,7 +216,7 @@ public class TabbedPane extends JTabbedPane { button.setBorderPainted(false); button.addActionListener(e -> closeCodePanel(contentPanel)); - panel.addMouseListener(new MouseAdapter() { + MouseAdapter clickAdapter = new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { if (SwingUtilities.isMiddleMouseButton(e)) { @@ -228,7 +228,9 @@ public class TabbedPane extends JTabbedPane { setSelectedComponent(contentPanel); } } - }); + }; + panel.addMouseListener(clickAdapter); + label.addMouseListener(clickAdapter); panel.add(label); panel.add(button); diff --git a/jadx-gui/src/main/java/jadx/gui/ui/codearea/AbstractCodeArea.java b/jadx-gui/src/main/java/jadx/gui/ui/codearea/AbstractCodeArea.java index 6862b781c..6d93b7a69 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/codearea/AbstractCodeArea.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/codearea/AbstractCodeArea.java @@ -1,14 +1,17 @@ package jadx.gui.ui.codearea; -import java.awt.Dimension; -import java.awt.Point; -import java.awt.Rectangle; +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; -import javax.swing.JViewport; -import javax.swing.SwingUtilities; +import javax.swing.*; import javax.swing.text.BadLocationException; +import javax.swing.text.Caret; +import javax.swing.text.DefaultCaret; import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; +import org.fife.ui.rtextarea.SearchContext; +import org.fife.ui.rtextarea.SearchEngine; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,6 +33,19 @@ public abstract class AbstractCodeArea extends RSyntaxTextArea { public AbstractCodeArea(ContentPanel contentPanel) { this.contentPanel = contentPanel; this.node = contentPanel.getNode(); + + setMarkOccurrences(true); + setEditable(false); + setCodeFoldingEnabled(false); + loadSettings(); + + Caret caret = getCaret(); + if (caret instanceof DefaultCaret) { + ((DefaultCaret) caret).setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE); + } + caret.setVisible(true); + + registerWordHighlighter(); } /** @@ -37,6 +53,22 @@ public abstract class AbstractCodeArea extends RSyntaxTextArea { */ public abstract void load(); + public static RSyntaxTextArea getDefaultArea(MainWindow mainWindow) { + RSyntaxTextArea area = new RSyntaxTextArea(); + area.setEditable(false); + area.setCodeFoldingEnabled(false); + loadCommonSettings(mainWindow, area); + return area; + } + + public static void loadCommonSettings(MainWindow mainWindow, RSyntaxTextArea area) { + area.setAntiAliasingEnabled(true); + mainWindow.getEditorTheme().apply(area); + + JadxSettings settings = mainWindow.getSettings(); + area.setFont(settings.getFont()); + } + public void loadSettings() { loadCommonSettings(contentPanel.getTabbedPane().getMainWindow(), this); } @@ -85,6 +117,34 @@ public abstract class AbstractCodeArea extends RSyntaxTextArea { } } + private void registerWordHighlighter() { + addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent evt) { + if (evt.getClickCount() % 2 == 0 && !evt.isConsumed()) { + evt.consume(); + String str = getSelectedText(); + if (str != null) { + highlightAllMatches(str); + } + } else { + highlightAllMatches(null); + } + } + }); + } + + /** + * @param str - if null -> reset current highlights + */ + private void highlightAllMatches(@Nullable String str) { + SearchContext context = new SearchContext(str); + context.setMarkAll(true); + context.setMatchCase(true); + context.setWholeWord(true); + SearchEngine.markAll(this, context); + } + public JumpPosition getCurrentPosition() { return new JumpPosition(node, getCaretLineNumber() + 1); } @@ -101,12 +161,4 @@ public abstract class AbstractCodeArea extends RSyntaxTextArea { public JNode getNode() { return node; } - - public static void loadCommonSettings(MainWindow mainWindow, RSyntaxTextArea area) { - area.setAntiAliasingEnabled(true); - mainWindow.getEditorTheme().apply(area); - - JadxSettings settings = mainWindow.getSettings(); - area.setFont(settings.getFont()); - } } diff --git a/jadx-gui/src/main/java/jadx/gui/ui/codearea/ClassCodeContentPanel.java b/jadx-gui/src/main/java/jadx/gui/ui/codearea/ClassCodeContentPanel.java index 9e51a71b8..ff9b1ebde 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/codearea/ClassCodeContentPanel.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/codearea/ClassCodeContentPanel.java @@ -1,8 +1,9 @@ package jadx.gui.ui.codearea; -import java.awt.BorderLayout; +import java.awt.*; -import javax.swing.JTabbedPane; +import javax.swing.*; +import javax.swing.border.EmptyBorder; import jadx.gui.treemodel.JNode; import jadx.gui.ui.TabbedPane; @@ -19,18 +20,22 @@ import jadx.gui.utils.NLS; public final class ClassCodeContentPanel extends AbstractCodeContentPanel { private static final long serialVersionUID = -7229931102504634591L; - private final CodePanel javaCodePanel; - private final CodePanel smaliCodePanel; - private JTabbedPane areaTabbedPane = new JTabbedPane(JTabbedPane.BOTTOM); + private final transient CodePanel javaCodePanel; + private final transient CodePanel smaliCodePanel; + // private final transient JTabbedPane areaTabbedPane; public ClassCodeContentPanel(TabbedPane panel, JNode jnode) { super(panel, jnode); - javaCodePanel = new CodePanel(this, new CodeArea(this)); - smaliCodePanel = new CodePanel(this, new SmaliArea(this)); + javaCodePanel = new CodePanel(new CodeArea(this)); + smaliCodePanel = new CodePanel(new SmaliArea(this)); setLayout(new BorderLayout()); + setBorder(new EmptyBorder(0, 0, 0, 0)); + JTabbedPane areaTabbedPane = new JTabbedPane(JTabbedPane.BOTTOM); + areaTabbedPane.setBorder(new EmptyBorder(0, 0, 0, 0)); + areaTabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT); areaTabbedPane.add(javaCodePanel, NLS.str("tabs.code")); areaTabbedPane.add(smaliCodePanel, NLS.str("tabs.smali")); add(areaTabbedPane); diff --git a/jadx-gui/src/main/java/jadx/gui/ui/codearea/CodeArea.java b/jadx-gui/src/main/java/jadx/gui/ui/codearea/CodeArea.java index 4cff715a2..2e8836916 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/codearea/CodeArea.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/codearea/CodeArea.java @@ -1,26 +1,17 @@ package jadx.gui.ui.codearea; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; - -import javax.swing.JPopupMenu; -import javax.swing.text.Caret; -import javax.swing.text.DefaultCaret; +import javax.swing.*; import org.fife.ui.rsyntaxtextarea.RSyntaxDocument; -import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; -import org.fife.ui.rtextarea.SearchContext; -import org.fife.ui.rtextarea.SearchEngine; -import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import jadx.api.CodePosition; +import jadx.api.JadxDecompiler; import jadx.api.JavaNode; import jadx.gui.treemodel.JClass; import jadx.gui.treemodel.JNode; import jadx.gui.ui.ContentPanel; -import jadx.gui.ui.MainWindow; import jadx.gui.utils.JumpPosition; /** @@ -34,29 +25,18 @@ public final class CodeArea extends AbstractCodeArea { CodeArea(ContentPanel contentPanel) { super(contentPanel); - - setMarkOccurrences(true); - setEditable(false); - loadSettings(); - - Caret caret = getCaret(); - if (caret instanceof DefaultCaret) { - ((DefaultCaret) caret).setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE); - } - caret.setVisible(true); - setSyntaxEditingStyle(node.getSyntaxName()); + if (node instanceof JClass) { JClass jClsNode = (JClass) this.node; - ((RSyntaxDocument) getDocument()).setSyntaxStyle(new JadxTokenMaker(this, jClsNode)); - - setHyperlinksEnabled(true); - CodeLinkGenerator codeLinkProcessor = new CodeLinkGenerator(contentPanel, this, jClsNode); - setLinkGenerator(codeLinkProcessor); - addHyperlinkListener(codeLinkProcessor); + ((RSyntaxDocument) getDocument()).setSyntaxStyle(new JadxTokenMaker(this)); addMenuItems(jClsNode); } - registerWordHighlighter(); + + setHyperlinksEnabled(true); + CodeLinkGenerator codeLinkProcessor = new CodeLinkGenerator(this); + setLinkGenerator(codeLinkProcessor); + addHyperlinkListener(codeLinkProcessor); } @Override @@ -67,36 +47,8 @@ public final class CodeArea extends AbstractCodeArea { } } - private void registerWordHighlighter() { - addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent evt) { - if (evt.getClickCount() % 2 == 0 && !evt.isConsumed()) { - evt.consume(); - String str = getSelectedText(); - if (str != null) { - highlightAllMatches(str); - } - } else { - highlightAllMatches(null); - } - } - }); - } - - /** - * @param str - if null -> reset current highlights - */ - private void highlightAllMatches(@Nullable String str) { - SearchContext context = new SearchContext(str); - context.setMarkAll(true); - context.setMatchCase(true); - context.setWholeWord(true); - SearchEngine.markAll(this, context); - } - private void addMenuItems(JClass jCls) { - FindUsageAction findUsage = new FindUsageAction(contentPanel, this, jCls); + FindUsageAction findUsage = new FindUsageAction(contentPanel, this); GoToDeclarationAction goToDeclaration = new GoToDeclarationAction(contentPanel, this, jCls); JPopupMenu popup = getPopupMenu(); @@ -107,22 +59,16 @@ public final class CodeArea extends AbstractCodeArea { popup.addPopupMenuListener(goToDeclaration); } - public static RSyntaxTextArea getDefaultArea(MainWindow mainWindow) { - RSyntaxTextArea area = new RSyntaxTextArea(); - loadCommonSettings(mainWindow, area); - return area; - } - /** * Search node by offset in {@code jCls} code and return its definition position * (useful for jumps from usage) */ - public JumpPosition getDefPosForNodeAtOffset(JClass jCls, int offset) { - JavaNode foundNode = getJavaNodeAtOffset(jCls, offset); + public JumpPosition getDefPosForNodeAtOffset(int offset) { + JavaNode foundNode = getJavaNodeAtOffset(offset); if (foundNode == null) { return null; } - CodePosition pos = jCls.getCls().getDefinitionPosition(foundNode); + CodePosition pos = getDecompiler().getDefinitionPosition(foundNode); if (pos == null) { return null; } @@ -133,16 +79,19 @@ public final class CodeArea extends AbstractCodeArea { /** * Search referenced java node by offset in {@code jCls} code */ - public JavaNode getJavaNodeAtOffset(JClass jCls, int offset) { + public JavaNode getJavaNodeAtOffset(int offset) { try { // TODO: add direct mapping for code offset to CodeWriter (instead of line and line offset pair) int line = this.getLineOfOffset(offset); int lineOffset = offset - this.getLineStartOffset(line); - return jCls.getCls().getJavaNodeAtPosition(line + 1, lineOffset + 1); + return node.getJavaNodeAtPosition(getDecompiler(), line + 1, lineOffset + 1); } catch (Exception e) { LOG.error("Can't get java node by offset: {}", offset, e); } return null; } + private JadxDecompiler getDecompiler() { + return contentPanel.getTabbedPane().getMainWindow().getWrapper().getDecompiler(); + } } diff --git a/jadx-gui/src/main/java/jadx/gui/ui/codearea/CodeContentPanel.java b/jadx-gui/src/main/java/jadx/gui/ui/codearea/CodeContentPanel.java index ddd9013a1..0d7135232 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/codearea/CodeContentPanel.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/codearea/CodeContentPanel.java @@ -1,6 +1,6 @@ package jadx.gui.ui.codearea; -import java.awt.BorderLayout; +import java.awt.*; import jadx.gui.treemodel.JNode; import jadx.gui.ui.TabbedPane; @@ -13,7 +13,7 @@ public final class CodeContentPanel extends AbstractCodeContentPanel { public CodeContentPanel(TabbedPane panel, JNode jnode) { super(panel, jnode); setLayout(new BorderLayout()); - codePanel = new CodePanel(this, new CodeArea(this)); + codePanel = new CodePanel(new CodeArea(this)); add(codePanel, BorderLayout.CENTER); codePanel.load(); } 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 f0747c21b..b15fe862b 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 @@ -14,6 +14,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import jadx.gui.treemodel.JClass; +import jadx.gui.treemodel.JNode; import jadx.gui.ui.ContentPanel; import jadx.gui.utils.JumpPosition; @@ -22,29 +23,40 @@ public class CodeLinkGenerator implements LinkGenerator, HyperlinkListener { private final ContentPanel contentPanel; private final CodeArea codeArea; - private final JClass jCls; + private final JNode jNode; - public CodeLinkGenerator(ContentPanel contentPanel, CodeArea codeArea, JClass cls) { - this.contentPanel = contentPanel; + public CodeLinkGenerator(CodeArea codeArea) { + this.contentPanel = codeArea.getContentPanel(); this.codeArea = codeArea; - this.jCls = cls; + this.jNode = codeArea.getNode(); } @Override public LinkGeneratorResult isLinkAtOffset(RSyntaxTextArea textArea, int offset) { try { + if (jNode.getCodeInfo() == null) { + return null; + } Token token = textArea.modelToToken(offset); if (token == null) { return null; } int type = token.getType(); final int sourceOffset; - if (type == TokenTypes.IDENTIFIER) { - sourceOffset = token.getOffset(); - } else if (type == TokenTypes.ANNOTATION && token.length() > 1) { - sourceOffset = token.getOffset() + 1; + if (jNode instanceof JClass) { + if (type == TokenTypes.IDENTIFIER) { + sourceOffset = token.getOffset(); + } else if (type == TokenTypes.ANNOTATION && token.length() > 1) { + sourceOffset = token.getOffset() + 1; + } else { + return null; + } } else { - return null; + if (type == TokenTypes.MARKUP_TAG_ATTRIBUTE_VALUE) { + sourceOffset = token.getOffset() + 1; // skip quote at start (") + } else { + return null; + } } // fast skip if (token.length() == 1) { @@ -53,11 +65,11 @@ public class CodeLinkGenerator implements LinkGenerator, HyperlinkListener { return null; } } - final JumpPosition defPos = codeArea.getDefPosForNodeAtOffset(jCls, sourceOffset); + final JumpPosition defPos = codeArea.getDefPosForNodeAtOffset(sourceOffset); if (defPos == null) { return null; } - if (Objects.equals(defPos.getNode().getRootClass(), jCls) + if (Objects.equals(defPos.getNode().getRootClass(), jNode) && defPos.getLine() == textArea.getLineOfOffset(sourceOffset) + 1) { // ignore self jump return null; diff --git a/jadx-gui/src/main/java/jadx/gui/ui/codearea/CodePanel.java b/jadx-gui/src/main/java/jadx/gui/ui/codearea/CodePanel.java index 765bc6686..f715092f3 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/codearea/CodePanel.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/codearea/CodePanel.java @@ -3,14 +3,14 @@ package jadx.gui.ui.codearea; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; import javax.swing.*; +import javax.swing.border.EmptyBorder; -import org.fife.ui.rtextarea.RTextScrollPane; - -import jadx.gui.treemodel.JNode; -import jadx.gui.treemodel.JResource; -import jadx.gui.ui.ContentPanel; +import jadx.api.ICodeInfo; import jadx.gui.utils.UiUtils; /** @@ -21,14 +21,15 @@ public class CodePanel extends JPanel { private final SearchBar searchBar; private final AbstractCodeArea codeArea; - private final RTextScrollPane codeScrollPane; + private final JScrollPane codeScrollPane; - public CodePanel(ContentPanel contentPanel, AbstractCodeArea codeArea) { + public CodePanel(AbstractCodeArea codeArea) { this.codeArea = codeArea; searchBar = new SearchBar(codeArea); - codeScrollPane = new RTextScrollPane(codeArea, false); + codeScrollPane = new JScrollPane(codeArea); setLayout(new BorderLayout()); + setBorder(new EmptyBorder(0, 0, 0, 0)); add(searchBar, BorderLayout.NORTH); add(codeScrollPane, BorderLayout.CENTER); @@ -60,12 +61,19 @@ public class CodePanel extends JPanel { } private boolean isUseSourceLines() { - JNode node = codeArea.getNode(); - if (node instanceof JResource) { - JResource resNode = (JResource) node; - return !resNode.getLineMapping().isEmpty(); + if (codeArea instanceof SmaliArea) { + return false; } - return false; + ICodeInfo codeInfo = codeArea.getNode().getCodeInfo(); + if (codeInfo == null) { + return false; + } + Map lineMapping = codeInfo.getLineMapping(); + if (lineMapping.isEmpty()) { + return false; + } + Set uniqueSourceLines = new HashSet<>(lineMapping.values()); + return uniqueSourceLines.size() > 3; } public SearchBar getSearchBar() { 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 012126a34..68276b51f 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 @@ -10,7 +10,6 @@ import javax.swing.event.PopupMenuListener; import org.fife.ui.rsyntaxtextarea.Token; import jadx.api.JavaNode; -import jadx.gui.treemodel.JClass; import jadx.gui.treemodel.JNode; import jadx.gui.ui.ContentPanel; import jadx.gui.ui.MainWindow; @@ -22,15 +21,13 @@ public final class FindUsageAction extends AbstractAction implements PopupMenuLi private final transient ContentPanel contentPanel; private final transient CodeArea codeArea; - private final transient JClass jCls; private transient JavaNode node; - public FindUsageAction(ContentPanel contentPanel, CodeArea codeArea, JClass jCls) { + public FindUsageAction(ContentPanel contentPanel, CodeArea codeArea) { super(NLS.str("popup.find_usage")); this.contentPanel = contentPanel; this.codeArea = codeArea; - this.jCls = jCls; } @Override @@ -51,7 +48,7 @@ public final class FindUsageAction extends AbstractAction implements PopupMenuLi if (pos != null) { Token token = codeArea.viewToToken(pos); if (token != null) { - node = codeArea.getJavaNodeAtOffset(jCls, token.getOffset()); + node = codeArea.getJavaNodeAtOffset(token.getOffset()); } } setEnabled(node != null); diff --git a/jadx-gui/src/main/java/jadx/gui/ui/codearea/GoToDeclarationAction.java b/jadx-gui/src/main/java/jadx/gui/ui/codearea/GoToDeclarationAction.java index d127c82ba..d05857899 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/codearea/GoToDeclarationAction.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/codearea/GoToDeclarationAction.java @@ -49,7 +49,7 @@ public final class GoToDeclarationAction extends AbstractAction implements Popup if (pos != null) { Token token = codeArea.viewToToken(pos); if (token != null) { - node = codeArea.getJavaNodeAtOffset(jCls, token.getOffset()); + node = codeArea.getJavaNodeAtOffset(token.getOffset()); } } setEnabled(node != null); diff --git a/jadx-gui/src/main/java/jadx/gui/ui/codearea/JadxTokenMaker.java b/jadx-gui/src/main/java/jadx/gui/ui/codearea/JadxTokenMaker.java index 4491dc7f9..a0e23af1b 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/codearea/JadxTokenMaker.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/codearea/JadxTokenMaker.java @@ -13,17 +13,14 @@ import org.slf4j.LoggerFactory; import jadx.api.JavaClass; import jadx.api.JavaNode; -import jadx.gui.treemodel.JClass; public final class JadxTokenMaker extends JavaTokenMaker { private static final Logger LOG = LoggerFactory.getLogger(JadxTokenMaker.class); private final CodeArea codeArea; - private final JClass jCls; - public JadxTokenMaker(CodeArea codeArea, JClass jCls) { + public JadxTokenMaker(CodeArea codeArea) { this.codeArea = codeArea; - this.jCls = jCls; } @Override @@ -62,7 +59,7 @@ public final class JadxTokenMaker extends JavaTokenMaker { if (annotation) { offset++; } - JavaNode javaNode = codeArea.getJavaNodeAtOffset(jCls, offset); + JavaNode javaNode = codeArea.getJavaNodeAtOffset(offset); if (javaNode instanceof JavaClass) { String name = javaNode.getName(); String lexeme = current.getLexeme(); diff --git a/jadx-gui/src/main/java/jadx/gui/ui/codearea/LineNumbers.java b/jadx-gui/src/main/java/jadx/gui/ui/codearea/LineNumbers.java index 04cace2ee..9c807b210 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/codearea/LineNumbers.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/codearea/LineNumbers.java @@ -20,6 +20,8 @@ import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import jadx.api.ICodeInfo; + public class LineNumbers extends JPanel implements CaretListener { private static final Logger LOG = LoggerFactory.getLogger(LineNumbers.class); @@ -41,6 +43,7 @@ public class LineNumbers extends JPanel implements CaretListener { private transient Insets textAreaInsets; private transient Rectangle visibleRect = new Rectangle(); + private transient ICodeInfo codeInfo; public LineNumbers(AbstractCodeArea codeArea) { this.codeArea = codeArea; @@ -60,10 +63,8 @@ public class LineNumbers extends JPanel implements CaretListener { addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { - if (e.getClickCount() == 2) { - useSourceLines = !useSourceLines; - repaint(); - } + useSourceLines = !useSourceLines; + repaint(); } }); } @@ -96,6 +97,8 @@ public class LineNumbers extends JPanel implements CaretListener { @Override public void paintComponent(Graphics g) { + codeInfo = codeArea.getNode().getCodeInfo(); + visibleRect = g.getClipBounds(visibleRect); if (visibleRect == null) { visibleRect = getVisibleRect(); @@ -131,8 +134,7 @@ public class LineNumbers extends JPanel implements CaretListener { int y = actualTopY + ascent; int endY = visibleRect.y + visibleRect.height + ascent; - Element rootElement = codeArea.getDocument().getDefaultRootElement(); - int currentLine = 1 + rootElement.getElementIndex(codeArea.getCaretPosition()); + int currentLine = 1 + codeArea.getCaretLineNumber(); int lineNum = topLine + 1; int linesCount = codeArea.getLineCount(); boolean isCurLine = updateColor(g, false, true); @@ -186,7 +188,7 @@ public class LineNumbers extends JPanel implements CaretListener { if (!useSourceLines) { return String.valueOf(lineNumber); } - Integer sourceLine = codeArea.getSourceLine(lineNumber); + Integer sourceLine = codeInfo.getLineMapping().get(lineNumber); if (sourceLine == null) { return null; } diff --git a/jadx-gui/src/main/java/jadx/gui/ui/codearea/SmaliArea.java b/jadx-gui/src/main/java/jadx/gui/ui/codearea/SmaliArea.java index c5271a2a5..41200a3bf 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/codearea/SmaliArea.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/codearea/SmaliArea.java @@ -1,13 +1,20 @@ package jadx.gui.ui.codearea; +import org.fife.ui.rsyntaxtextarea.SyntaxConstants; + +import jadx.gui.treemodel.JNode; +import jadx.gui.treemodel.TextNode; import jadx.gui.ui.ContentPanel; public final class SmaliArea extends AbstractCodeArea { private static final long serialVersionUID = 1334485631870306494L; + private final JNode textNode; + SmaliArea(ContentPanel contentPanel) { super(contentPanel); - setEditable(false); + this.textNode = new TextNode(node.getName()); + setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); } @Override @@ -17,4 +24,10 @@ public final class SmaliArea extends AbstractCodeArea { setCaretPosition(0); } } + + @Override + public JNode getNode() { + // this area contains only smali without other node attributes + return textNode; + } }