Commit e2018535 authored by Skylot's avatar Skylot

core: add ternary conditions processing

parent ee56610f
......@@ -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
......
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")));
}
}
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