From 2b7f8931a478861f82fae865057a46bbc7ea33a2 Mon Sep 17 00:00:00 2001 From: Skylot Date: Sat, 21 Feb 2015 17:14:00 +0300 Subject: [PATCH] core: fix source line for some return instructions --- .../jadx/core/dex/visitors/CodeShrinker.java | 33 +++++--- .../dex/visitors/ConstInlinerVisitor.java | 11 +-- .../integration/conditions/TestTernary3.java | 5 +- .../debuginfo/TestReturnSourceLine.java | 75 +++++++++++++++++++ 4 files changed, 104 insertions(+), 20 deletions(-) create mode 100644 jadx-core/src/test/java/jadx/tests/integration/debuginfo/TestReturnSourceLine.java diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/CodeShrinker.java b/jadx-core/src/main/java/jadx/core/dex/visitors/CodeShrinker.java index bb771e1a..654cd66d 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/CodeShrinker.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/CodeShrinker.java @@ -249,19 +249,28 @@ public class CodeShrinker extends AbstractVisitor { private static boolean inline(RegisterArg arg, InsnNode insn, @Nullable BlockNode block, MethodNode mth) { InsnNode parentInsn = arg.getParentInsn(); // replace move instruction if needed - if (parentInsn != null && parentInsn.getType() == InsnType.MOVE) { - if (block == null) { - block = BlockUtils.getBlockByInsn(mth, parentInsn); - } - if (block != null) { - int index = InsnList.getIndex(block.getInstructions(), parentInsn); - if (index != -1) { - insn.setResult(parentInsn.getResult()); - insn.copyAttributesFrom(parentInsn); - insn.setOffset(parentInsn.getOffset()); + if (parentInsn != null) { + switch (parentInsn.getType()) { + case MOVE: { + if (block == null) { + block = BlockUtils.getBlockByInsn(mth, parentInsn); + } + if (block != null) { + int index = InsnList.getIndex(block.getInstructions(), parentInsn); + if (index != -1) { + insn.setResult(parentInsn.getResult()); + insn.copyAttributesFrom(parentInsn); + insn.setOffset(parentInsn.getOffset()); - block.getInstructions().set(index, insn); - return true; + block.getInstructions().set(index, insn); + return true; + } + } + break; + } + case RETURN: { + parentInsn.setSourceLine(insn.getSourceLine()); + break; } } } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/ConstInlinerVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/ConstInlinerVisitor.java index 1e2c046a..77c13a45 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/ConstInlinerVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/ConstInlinerVisitor.java @@ -69,7 +69,7 @@ public class ConstInlinerVisitor extends AbstractVisitor { if (!arg.getType().isTypeKnown()) { arg.merge(resType); } - return replaceConst(mth, sVar, lit); + return replaceConst(mth, insn, lit); } /** @@ -98,13 +98,11 @@ public class ConstInlinerVisitor extends AbstractVisitor { return false; } - private static boolean replaceConst(MethodNode mth, SSAVar sVar, long literal) { + private static boolean replaceConst(MethodNode mth, InsnNode constInsn, long literal) { + SSAVar sVar = constInsn.getResult().getSVar(); List use = new ArrayList(sVar.getUseList()); int replaceCount = 0; for (RegisterArg arg : use) { -// if (arg.getSVar().isUsedInPhi()) { -// continue; -// } InsnNode useInsn = arg.getParentInsn(); if (useInsn == null || useInsn.getType() == InsnType.PHI) { continue; @@ -125,6 +123,9 @@ public class ConstInlinerVisitor extends AbstractVisitor { if (useInsn.replaceArg(arg, litArg)) { fixTypes(mth, useInsn, litArg); replaceCount++; + if (useInsn.getType() == InsnType.RETURN) { + useInsn.setSourceLine(constInsn.getSourceLine()); + } FieldNode f = null; ArgType litArgType = litArg.getType(); diff --git a/jadx-core/src/test/java/jadx/tests/integration/conditions/TestTernary3.java b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestTernary3.java index b1ecc296..b62cc222 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/conditions/TestTernary3.java +++ b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestTernary3.java @@ -41,9 +41,8 @@ public class TestTernary3 extends IntegrationTest { ClassNode cls = getClassNode(TestCls.class); String code = cls.getCode().toString(); - // TODO: - assertThat(code, containsOne("return (n == null || !(arg instanceof Named)) " - + "? false : n.equals(((Named) arg).getName());")); + assertThat(code, containsOne("if (n == null || !(arg instanceof Named)) {")); + assertThat(code, containsOne("return n.equals(((Named) arg).getName());")); assertThat(code, not(containsString("if ((arg instanceof RegisterArg)) {"))); } diff --git a/jadx-core/src/test/java/jadx/tests/integration/debuginfo/TestReturnSourceLine.java b/jadx-core/src/test/java/jadx/tests/integration/debuginfo/TestReturnSourceLine.java new file mode 100644 index 00000000..af87b5e6 --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/debuginfo/TestReturnSourceLine.java @@ -0,0 +1,75 @@ +package jadx.tests.integration.debuginfo; + +import jadx.core.codegen.CodeWriter; +import jadx.core.dex.attributes.nodes.LineAttrNode; +import jadx.core.dex.nodes.ClassNode; +import jadx.core.dex.nodes.MethodNode; +import jadx.tests.api.IntegrationTest; + +import org.junit.Test; + +import static jadx.tests.api.utils.JadxMatchers.containsOne; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; + +public class TestReturnSourceLine extends IntegrationTest { + + public static class TestCls { + public int test1(boolean v) { + if (v) { + f(); + return 1; + } + f(); + return 0; + } + + public int test2(int v) { + if (v == 0) { + f(); + return v - 1; + } + f(); + return v + 1; + } + + public int test3(int v) { + if (v == 0) { + f(); + return v; + } + f(); + return v + 1; + } + + private void f() { + } + } + + @Test + public void test() { + ClassNode cls = getClassNode(TestCls.class); + CodeWriter codeWriter = cls.getCode(); + String code = codeWriter.toString(); + String[] lines = code.split(CodeWriter.NL); + + MethodNode test1 = cls.searchMethodByName("test1(Z)I"); + checkLine(lines, codeWriter, test1, 3, "return 1;"); + + MethodNode test2 = cls.searchMethodByName("test2(I)I"); + checkLine(lines, codeWriter, test2, 3, "return v - 1;"); + +// TODO: +// MethodNode test3 = cls.searchMethodByName("test3(I)I"); +// checkLine(lines, codeWriter, test3, 3, "return v;"); + } + + private static void checkLine(String[] lines, CodeWriter cw, LineAttrNode node, int offset, String str) { + int decompiledLine = node.getDecompiledLine() + offset; + assertThat(lines[decompiledLine - 1], containsOne(str)); + Integer sourceLine = cw.getLineMapping().get(decompiledLine); + assertNotNull(sourceLine); + assertEquals(node.getSourceLine() + offset, (int) sourceLine); + } +} -- GitLab