diff --git a/jadx-core/src/main/java/jadx/api/impl/AnnotatedCodeWriter.java b/jadx-core/src/main/java/jadx/api/impl/AnnotatedCodeWriter.java index 8999eb5f3..4dc445282 100644 --- a/jadx-core/src/main/java/jadx/api/impl/AnnotatedCodeWriter.java +++ b/jadx-core/src/main/java/jadx/api/impl/AnnotatedCodeWriter.java @@ -154,7 +154,6 @@ public class AnnotatedCodeWriter extends SimpleCodeWriter implements ICodeWriter @Override public ICodeInfo finish() { - processDefinitionAnnotations(); validateAnnotations(); String code = buf.toString(); buf = null; @@ -166,18 +165,6 @@ public class AnnotatedCodeWriter extends SimpleCodeWriter implements ICodeWriter return annotations; } - private void processDefinitionAnnotations() { - if (!annotations.isEmpty()) { - annotations.forEach((k, v) -> { - if (v instanceof NodeDeclareRef) { - NodeDeclareRef declareRef = (NodeDeclareRef) v; - declareRef.setDefPos(k); - declareRef.getNode().setDefPosition(k); - } - }); - } - } - private void validateAnnotations() { if (annotations.isEmpty()) { return; diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java index 5aab2eef9..9c89fb09a 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java @@ -23,6 +23,8 @@ import jadx.api.ICodeWriter; import jadx.api.JadxArgs; import jadx.api.JavaClass; import jadx.api.impl.SimpleCodeInfo; +import jadx.api.metadata.ICodeAnnotation; +import jadx.api.metadata.annotations.NodeDeclareRef; import jadx.api.plugins.input.data.IClassData; import jadx.api.plugins.input.data.IFieldData; import jadx.api.plugins.input.data.IMethodData; @@ -312,6 +314,8 @@ public class ClassNode extends NotificationAttrNode return decompile(true); } + private static final Object DECOMPILE_WITH_MODE_SYNC = new Object(); + /** * WARNING: Slow operation! Use with caution! */ @@ -320,15 +324,18 @@ public class ClassNode extends NotificationAttrNode if (mode == baseMode) { return decompile(true); } - JadxArgs args = root.getArgs(); - try { - unload(); - args.setDecompilationMode(mode); - ProcessClass process = new ProcessClass(args); - process.initPasses(root); - return process.generateCode(this); - } finally { - args.setDecompilationMode(baseMode); + synchronized (DECOMPILE_WITH_MODE_SYNC) { + JadxArgs args = root.getArgs(); + try { + unload(); + args.setDecompilationMode(mode); + ProcessClass process = new ProcessClass(args); + process.initPasses(root); + return process.generateCode(this); + } finally { + args.setDecompilationMode(baseMode); + unload(); + } } } @@ -383,22 +390,46 @@ public class ClassNode extends NotificationAttrNode return code; } } - ICodeInfo codeInfo; - try { - if (Consts.DEBUG) { - LOG.debug("Decompiling class: {}", this); - } - codeInfo = root.getProcessClasses().generateCode(this); - } catch (Throwable e) { - addError("Code generation failed", e); - codeInfo = new SimpleCodeInfo(Utils.getStackTrace(e)); - } + ICodeInfo codeInfo = generateClassCode(); if (codeInfo != ICodeInfo.EMPTY) { codeCache.add(clsRawName, codeInfo); } return codeInfo; } + private ICodeInfo generateClassCode() { + try { + if (Consts.DEBUG) { + LOG.debug("Decompiling class: {}", this); + } + ICodeInfo codeInfo = root.getProcessClasses().generateCode(this); + processDefinitionAnnotations(codeInfo); + return codeInfo; + } catch (Throwable e) { + addError("Code generation failed", e); + return new SimpleCodeInfo(Utils.getStackTrace(e)); + } + } + + /** + * Save node definition positions found in code + */ + private static void processDefinitionAnnotations(ICodeInfo codeInfo) { + Map annotations = codeInfo.getCodeMetadata().getAsMap(); + if (annotations.isEmpty()) { + return; + } + for (Map.Entry entry : annotations.entrySet()) { + ICodeAnnotation ann = entry.getValue(); + if (ann.getAnnType() == AnnType.DECLARATION) { + NodeDeclareRef declareRef = (NodeDeclareRef) ann; + int pos = entry.getKey(); + declareRef.setDefPos(pos); + declareRef.getNode().setDefPosition(pos); + } + } + } + @Nullable public ICodeInfo getCodeFromCache() { ICodeCache codeCache = root().getCodeCache(); 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 78c035ff4..496010203 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 @@ -134,10 +134,22 @@ public class CodePanel extends JPanel { codeScrollPane.setLineNumbersEnabled(true); } + private static final LineNumberFormatter SIMPLE_LINE_FORMATTER = new LineNumberFormatter() { + @Override + public String format(int lineNumber) { + return Integer.toString(lineNumber); + } + + @Override + public int getMaxLength(int maxLineNumber) { + return SourceLineFormatter.getNumberLength(maxLineNumber); + } + }; + private synchronized void applyLineFormatter() { LineNumberFormatter linesFormatter = useSourceLines ? new SourceLineFormatter(codeArea.getCodeInfo()) - : LineNumberList.DEFAULT_LINE_NUMBER_FORMATTER; + : SIMPLE_LINE_FORMATTER; codeScrollPane.getGutter().setLineNumberFormatter(linesFormatter); } @@ -170,15 +182,13 @@ public class CodePanel extends JPanel { } private void initLinesModeSwitch() { - if (canShowDebugLines()) { - MousePressedHandler lineModeSwitch = new MousePressedHandler(ev -> { - useSourceLines = !useSourceLines; - applyLineFormatter(); - }); - for (Component gutterComp : codeScrollPane.getGutter().getComponents()) { - if (gutterComp instanceof LineNumberList) { - gutterComp.addMouseListener(lineModeSwitch); - } + MousePressedHandler lineModeSwitch = new MousePressedHandler(ev -> { + useSourceLines = !useSourceLines; + applyLineFormatter(); + }); + for (Component gutterComp : codeScrollPane.getGutter().getComponents()) { + if (gutterComp instanceof LineNumberList) { + gutterComp.addMouseListener(lineModeSwitch); } } } diff --git a/jadx-gui/src/main/java/jadx/gui/ui/codearea/SourceLineFormatter.java b/jadx-gui/src/main/java/jadx/gui/ui/codearea/SourceLineFormatter.java index adcf1c0af..44b7bb9e8 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/codearea/SourceLineFormatter.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/codearea/SourceLineFormatter.java @@ -32,8 +32,10 @@ public class SourceLineFormatter implements LineNumberFormatter { .values().stream() .mapToInt(Integer::intValue) .max().orElse(1); - // maxLine can be anything including zero and negative numbers, - // so use safe 'stringify' method instead faster 'Math.log10' - return Integer.toString(maxLine).length(); + return getNumberLength(maxLine); + } + + public static int getNumberLength(int num) { + return num < 10 ? 1 : 1 + (int) Math.log10(num); } }