core: fix source line for some return instructions

This commit is contained in:
Skylot 2015-02-21 17:14:00 +03:00
parent ec3b71e5b6
commit 2b7f8931a4
4 changed files with 104 additions and 20 deletions

View File

@ -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;
}
}
}

View File

@ -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<RegisterArg> use = new ArrayList<RegisterArg>(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();

View File

@ -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)) {")));
}

View File

@ -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);
}
}