Commit 37857e88 authored by Skylot's avatar Skylot

core: fix switch statement processing (issue #9 case 2)

parent 6fbcf46a
......@@ -199,7 +199,7 @@ public class RegionGen extends InsnGen {
SwitchNode insn = (SwitchNode) sw.getHeader().getInstructions().get(0);
InsnArg arg = insn.getArg(0);
code.startLine("switch (");
addArg(code, arg);
addArg(code, arg, false);
code.add(") {");
code.incIndent();
......
......@@ -627,7 +627,7 @@ public class RegionMaker {
BitSet succ = BlockUtils.blocksToBitSet(mth, block.getSuccessors());
BitSet domsOn = BlockUtils.blocksToBitSet(mth, block.getDominatesOn());
domsOn.and(succ); // filter 'out' block
domsOn.xor(succ); // filter 'out' block
BlockNode defCase = getBlockByOffset(insn.getDefaultCaseOffset(), block.getSuccessors());
if (defCase != null) {
......@@ -642,13 +642,11 @@ public class RegionMaker {
}
if (outCount > 1) {
// filter successors of other blocks
List<BlockNode> blocks = mth.getBasicBlocks();
for (int i = domsOn.nextSetBit(0); i >= 0; i = domsOn.nextSetBit(i + 1)) {
BlockNode b = mth.getBasicBlocks().get(i);
BlockNode b = blocks.get(i);
for (BlockNode s : b.getCleanSuccessors()) {
int id = s.getId();
if (domsOn.get(id)) {
domsOn.clear(id);
}
domsOn.clear(s.getId());
}
}
outCount = domsOn.cardinality();
......@@ -658,19 +656,27 @@ public class RegionMaker {
if (outCount == 1) {
out = mth.getBasicBlocks().get(domsOn.nextSetBit(0));
} else if (outCount == 0) {
// default and out blocks are same
out = defCase;
// one or several case blocks are empty,
// run expensive algorithm for find 'out' block
for (BlockNode maybeOut : block.getSuccessors()) {
boolean allReached = true;
for (BlockNode s : block.getSuccessors()) {
if (!BlockUtils.isPathExists(s, maybeOut)) {
allReached = false;
break;
}
}
if (allReached) {
out = maybeOut;
break;
}
}
}
stack.push(sw);
if (out != null) {
stack.addExit(out);
}
// else {
// for (BlockNode e : BlockUtils.bitSetToBlocks(mth, domsOn)) {
// stack.addExit(e);
// }
// }
if (!stack.containsExit(defCase)) {
sw.setDefaultCase(makeRegion(defCase, stack));
......
......@@ -203,10 +203,7 @@ public class BlockUtils {
}
public static boolean isPathExists(BlockNode start, BlockNode end) {
if (start == end) {
return true;
}
if (end.isDominator(start)) {
if (start == end || end.isDominator(start)) {
return true;
}
return traverseSuccessorsUntil(start, end, new BitSet());
......
package jadx.tests.internal;
package jadx.tests.internal.switches;
import jadx.api.InternalJadxTest;
import jadx.core.dex.nodes.ClassNode;
......@@ -6,6 +6,7 @@ import jadx.core.dex.nodes.ClassNode;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
public class TestSwitch extends InternalJadxTest {
......@@ -45,5 +46,9 @@ public class TestSwitch extends InternalJadxTest {
assertThat(code, containsString("case '/':"));
assertThat(code, containsString(indent(5) + "break;"));
assertThat(code, containsString(indent(4) + "default:"));
assertEquals(1, count(code, "i++"));
assertEquals(4, count(code, "break;"));
}
}
package jadx.tests.internal;
package jadx.tests.internal.switches;
import jadx.api.InternalJadxTest;
import jadx.core.dex.nodes.ClassNode;
......
package jadx.tests.internal.switches;
import jadx.api.InternalJadxTest;
import jadx.core.dex.nodes.ClassNode;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class TestSwitchNoDefault extends InternalJadxTest {
public static class TestCls {
public void test(int a) {
String s = null;
switch (a) {
case 1:
s = "1";
break;
case 2:
s = "2";
break;
case 3:
s = "3";
break;
case 4:
s = "4";
break;
}
System.out.println(s);
}
}
@Test
public void test() {
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();
System.out.println(code);
assertEquals(4, count(code, "break;"));
assertEquals(1, count(code, "System.out.println(s);"));
}
}
package jadx.tests.internal.switches;
import jadx.api.InternalJadxTest;
import jadx.core.dex.nodes.ClassNode;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
public class TestSwitchSimple extends InternalJadxTest {
public static class TestCls {
public void test(int a) {
String s = null;
switch (a % 4) {
case 1:
s = "1";
break;
case 2:
s = "2";
break;
case 3:
s = "3";
break;
case 4:
s = "4";
break;
default:
System.out.println("Not Reach");
break;
}
System.out.println(s);
}
}
@Test
public void test() {
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();
System.out.println(code);
assertEquals(5, count(code, "break;"));
assertEquals(1, count(code, "System.out.println(s);"));
assertEquals(1, count(code, "System.out.println(\"Not Reach\");"));
assertThat(code, not(containsString("switch ((a % 4)) {")));
assertThat(code, containsString("switch (a % 4) {"));
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment