core: add ternary conditions processing
This commit is contained in:
@@ -33,6 +33,10 @@ public class ConditionGen extends InsnGen {
|
||||
addCompare(code, condition.getCompare());
|
||||
break;
|
||||
|
||||
case TERNARY:
|
||||
addTernary(code, condition);
|
||||
break;
|
||||
|
||||
case NOT:
|
||||
addNot(code, condition);
|
||||
break;
|
||||
@@ -43,7 +47,7 @@ public class ConditionGen extends InsnGen {
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new JadxRuntimeException("Unknown condition mode: " + condition);
|
||||
throw new JadxRuntimeException("Unknown condition mode: " + condition.getMode());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,6 +98,14 @@ public class ConditionGen extends InsnGen {
|
||||
addArg(code, secondArg, isArgWrapNeeded(secondArg));
|
||||
}
|
||||
|
||||
private void addTernary(CodeWriter code, IfCondition condition) throws CodegenException {
|
||||
add(code, condition.first());
|
||||
code.add(" ? ");
|
||||
add(code, condition.second());
|
||||
code.add(" : ");
|
||||
add(code, condition.third());
|
||||
}
|
||||
|
||||
private void addNot(CodeWriter code, IfCondition condition) throws CodegenException {
|
||||
code.add('!');
|
||||
wrap(code, condition.getArgs().get(0));
|
||||
|
||||
@@ -11,7 +11,11 @@ import jadx.core.utils.Utils;
|
||||
|
||||
public class TernaryInsn extends InsnNode {
|
||||
|
||||
private final IfCondition condition;
|
||||
private IfCondition condition;
|
||||
|
||||
public TernaryInsn(IfCondition condition, RegisterArg result) {
|
||||
this(condition, result, LiteralArg.TRUE, LiteralArg.FALSE);
|
||||
}
|
||||
|
||||
public TernaryInsn(IfCondition condition, RegisterArg result, InsnArg th, InsnArg els) {
|
||||
super(InsnType.TERNARY, 2);
|
||||
@@ -33,6 +37,20 @@ public class TernaryInsn extends InsnNode {
|
||||
return condition;
|
||||
}
|
||||
|
||||
public void simplifyCondition() {
|
||||
condition = IfCondition.simplify(condition);
|
||||
if (condition.getMode() == IfCondition.Mode.NOT) {
|
||||
invert();
|
||||
}
|
||||
}
|
||||
|
||||
private void invert() {
|
||||
condition = IfCondition.invert(condition);
|
||||
InsnArg tmp = getArg(0);
|
||||
setArg(0, getArg(1));
|
||||
setArg(1, tmp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
|
||||
@@ -22,6 +22,7 @@ public final class IfCondition {
|
||||
|
||||
public enum Mode {
|
||||
COMPARE,
|
||||
TERNARY,
|
||||
NOT,
|
||||
AND,
|
||||
OR
|
||||
@@ -64,6 +65,10 @@ public final class IfCondition {
|
||||
return new IfCondition(new Compare(insn));
|
||||
}
|
||||
|
||||
public static IfCondition ternary(IfCondition a, IfCondition b, IfCondition c) {
|
||||
return new IfCondition(Mode.TERNARY, Arrays.asList(a, b, c));
|
||||
}
|
||||
|
||||
public static IfCondition merge(Mode mode, IfCondition a, IfCondition b) {
|
||||
if (a.getMode() == mode) {
|
||||
IfCondition n = new IfCondition(a);
|
||||
@@ -89,6 +94,10 @@ public final class IfCondition {
|
||||
return args.get(1);
|
||||
}
|
||||
|
||||
public IfCondition third() {
|
||||
return args.get(2);
|
||||
}
|
||||
|
||||
public void addArg(IfCondition c) {
|
||||
args.add(c);
|
||||
}
|
||||
@@ -106,6 +115,8 @@ public final class IfCondition {
|
||||
switch (mode) {
|
||||
case COMPARE:
|
||||
return new IfCondition(cond.getCompare().invert());
|
||||
case TERNARY:
|
||||
return ternary(not(cond.first()), cond.third(), cond.second());
|
||||
case NOT:
|
||||
return cond.first();
|
||||
case AND:
|
||||
@@ -154,7 +165,10 @@ public final class IfCondition {
|
||||
cond = new IfCondition(cond.getMode(), args);
|
||||
}
|
||||
if (cond.getMode() == Mode.NOT && cond.first().getMode() == Mode.NOT) {
|
||||
cond = cond.first().first();
|
||||
cond = invert(cond.first());
|
||||
}
|
||||
if (cond.getMode() == Mode.TERNARY && cond.first().getMode() == Mode.NOT) {
|
||||
cond = invert(cond);
|
||||
}
|
||||
|
||||
// for condition with a lot of negations => make invert
|
||||
@@ -216,6 +230,8 @@ public final class IfCondition {
|
||||
switch (mode) {
|
||||
case COMPARE:
|
||||
return compare.toString();
|
||||
case TERNARY:
|
||||
return first() + " ? " + second() + " : " + third();
|
||||
case NOT:
|
||||
return "!" + first();
|
||||
case AND:
|
||||
|
||||
@@ -65,7 +65,7 @@ public class SimplifyVisitor extends AbstractVisitor {
|
||||
simplifyIf((IfNode) insn);
|
||||
break;
|
||||
case TERNARY:
|
||||
simplifyTernary((TernaryInsn)insn);
|
||||
simplifyTernary((TernaryInsn) insn);
|
||||
break;
|
||||
|
||||
case INVOKE:
|
||||
@@ -117,6 +117,8 @@ public class SimplifyVisitor extends AbstractVisitor {
|
||||
IfCondition condition = insn.getCondition();
|
||||
if (condition.isCompare()) {
|
||||
simplifyIf(condition.getCompare().getInsn());
|
||||
} else {
|
||||
insn.simplifyCondition();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -101,6 +101,11 @@ public class IfMakerHelper {
|
||||
return c1.size() == c2.size() && c1.containsAll(c2);
|
||||
}
|
||||
|
||||
static IfInfo searchNestedIf(IfInfo info) {
|
||||
IfInfo tmp = mergeNestedIfNodes(info);
|
||||
return tmp != null ? tmp : info;
|
||||
}
|
||||
|
||||
static IfInfo mergeNestedIfNodes(IfInfo currentIf) {
|
||||
BlockNode curThen = currentIf.getThenBlock();
|
||||
BlockNode curElse = currentIf.getElseBlock();
|
||||
@@ -126,12 +131,13 @@ public class IfMakerHelper {
|
||||
if (!RegionMaker.isEqualPaths(curElse, nextIf.getElseBlock())
|
||||
&& !RegionMaker.isEqualPaths(curThen, nextIf.getThenBlock())) {
|
||||
// complex condition, run additional checks
|
||||
if (checkConditionBranches(curThen, curElse) || checkConditionBranches(curElse, curThen)) {
|
||||
if (checkConditionBranches(curThen, curElse)
|
||||
|| checkConditionBranches(curElse, curThen)) {
|
||||
return null;
|
||||
}
|
||||
BlockNode otherBranchBlock = followThenBranch ? curElse : curThen;
|
||||
if (!isPathExists(nextIf.getIfBlock(), otherBranchBlock)) {
|
||||
return null;
|
||||
return checkForTernaryInCondition(currentIf);
|
||||
}
|
||||
if (isPathExists(nextIf.getThenBlock(), otherBranchBlock)
|
||||
&& isPathExists(nextIf.getElseBlock(), otherBranchBlock)) {
|
||||
@@ -152,9 +158,43 @@ public class IfMakerHelper {
|
||||
|
||||
IfInfo result = mergeIfInfo(currentIf, nextIf, followThenBranch);
|
||||
// search next nested if block
|
||||
IfInfo next = mergeNestedIfNodes(result);
|
||||
if (next != null) {
|
||||
return next;
|
||||
return searchNestedIf(result);
|
||||
}
|
||||
|
||||
private static IfInfo checkForTernaryInCondition(IfInfo currentIf) {
|
||||
IfInfo nextThen = getNextIf(currentIf, currentIf.getThenBlock());
|
||||
IfInfo nextElse = getNextIf(currentIf, currentIf.getElseBlock());
|
||||
if (nextThen == null || nextElse == null) {
|
||||
return null;
|
||||
}
|
||||
if (!nextThen.getIfBlock().getDomFrontier().equals(nextElse.getIfBlock().getDomFrontier())) {
|
||||
return null;
|
||||
}
|
||||
nextThen = searchNestedIf(nextThen);
|
||||
nextElse = searchNestedIf(nextElse);
|
||||
if (nextThen.getThenBlock() == nextElse.getThenBlock()
|
||||
&& nextThen.getElseBlock() == nextElse.getElseBlock()) {
|
||||
return mergeTernaryConditions(currentIf, nextThen, nextElse);
|
||||
}
|
||||
if (nextThen.getThenBlock() == nextElse.getElseBlock()
|
||||
&& nextThen.getElseBlock() == nextElse.getThenBlock()) {
|
||||
nextElse = IfInfo.invert(nextElse);
|
||||
return mergeTernaryConditions(currentIf, nextThen, nextElse);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static IfInfo mergeTernaryConditions(IfInfo currentIf, IfInfo nextThen, IfInfo nextElse) {
|
||||
IfCondition newCondition = IfCondition.ternary(currentIf.getCondition(),
|
||||
nextThen.getCondition(), nextElse.getCondition());
|
||||
IfInfo result = new IfInfo(newCondition, nextThen.getThenBlock(), nextThen.getElseBlock());
|
||||
result.setIfBlock(currentIf.getIfBlock());
|
||||
result.getMergedBlocks().addAll(currentIf.getMergedBlocks());
|
||||
result.getMergedBlocks().addAll(nextThen.getMergedBlocks());
|
||||
result.getMergedBlocks().addAll(nextElse.getMergedBlocks());
|
||||
for (BlockNode blockNode : result.getMergedBlocks()) {
|
||||
blockNode.add(AFlag.SKIP);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -20,15 +20,6 @@ public class TestConditions14 extends InternalJadxTest {
|
||||
System.out.println("1");
|
||||
return true;
|
||||
}
|
||||
|
||||
// public static boolean test2(Object a, Object b) {
|
||||
// if (a == null ? b != null : !a.equals(b)) {
|
||||
// return false;
|
||||
// }
|
||||
// System.out.println("2");
|
||||
// return true;
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package jadx.tests.internal.conditions;
|
||||
|
||||
import jadx.api.InternalJadxTest;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static jadx.tests.utils.JadxMatchers.containsOne;
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class TestTernaryInIf extends InternalJadxTest {
|
||||
|
||||
public static class TestCls {
|
||||
public boolean test1(boolean a, boolean b, boolean c) {
|
||||
return a ? b : c;
|
||||
}
|
||||
|
||||
public int test2(boolean a, boolean b, boolean c) {
|
||||
return (a ? b : c) ? 1 : 2;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
String code = cls.getCode().toString();
|
||||
System.out.println(code);
|
||||
|
||||
assertThat(code, containsOne("return a ? b : c;"));
|
||||
assertThat(code, containsOne("return (a ? b : c) ? 1 : 2;"));
|
||||
assertThat(code, not(containsString("if")));
|
||||
assertThat(code, not(containsString("else")));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user