Commit 29840e03 authored by Skylot's avatar Skylot

Generate code for 'if-else-if' construction

parent 326b1979
...@@ -5,7 +5,7 @@ import jadx.dex.info.ClassInfo; ...@@ -5,7 +5,7 @@ import jadx.dex.info.ClassInfo;
import jadx.dex.nodes.ClassNode; import jadx.dex.nodes.ClassNode;
import jadx.dex.nodes.RootNode; import jadx.dex.nodes.RootNode;
import jadx.dex.visitors.BlockMakerVisitor; import jadx.dex.visitors.BlockMakerVisitor;
import jadx.dex.visitors.ClassCheck; import jadx.dex.visitors.ClassModifier;
import jadx.dex.visitors.CodeShrinker; import jadx.dex.visitors.CodeShrinker;
import jadx.dex.visitors.ConstInlinerVisitor; import jadx.dex.visitors.ConstInlinerVisitor;
import jadx.dex.visitors.DotGraphVisitor; import jadx.dex.visitors.DotGraphVisitor;
...@@ -14,6 +14,7 @@ import jadx.dex.visitors.FallbackModeVisitor; ...@@ -14,6 +14,7 @@ import jadx.dex.visitors.FallbackModeVisitor;
import jadx.dex.visitors.IDexTreeVisitor; import jadx.dex.visitors.IDexTreeVisitor;
import jadx.dex.visitors.ModVisitor; import jadx.dex.visitors.ModVisitor;
import jadx.dex.visitors.regions.CheckRegions; import jadx.dex.visitors.regions.CheckRegions;
import jadx.dex.visitors.regions.CleanRegions;
import jadx.dex.visitors.regions.PostRegionVisitor; import jadx.dex.visitors.regions.PostRegionVisitor;
import jadx.dex.visitors.regions.ProcessVariables; import jadx.dex.visitors.regions.ProcessVariables;
import jadx.dex.visitors.regions.RegionMakerVisitor; import jadx.dex.visitors.regions.RegionMakerVisitor;
...@@ -94,11 +95,11 @@ public class Main { ...@@ -94,11 +95,11 @@ public class Main {
passes.add(new ConstInlinerVisitor()); passes.add(new ConstInlinerVisitor());
passes.add(new FinishTypeResolver()); passes.add(new FinishTypeResolver());
passes.add(new ClassCheck());
if (args.isRawCFGOutput()) if (args.isRawCFGOutput())
passes.add(new DotGraphVisitor(args.getOutDir(), false, true)); passes.add(new DotGraphVisitor(args.getOutDir(), false, true));
passes.add(new ClassModifier());
passes.add(new ModVisitor()); passes.add(new ModVisitor());
passes.add(new EnumVisitor()); passes.add(new EnumVisitor());
...@@ -113,6 +114,8 @@ public class Main { ...@@ -113,6 +114,8 @@ public class Main {
passes.add(new CheckRegions()); passes.add(new CheckRegions());
if (args.isCFGOutput()) if (args.isCFGOutput())
passes.add(new DotGraphVisitor(args.getOutDir(), true)); passes.add(new DotGraphVisitor(args.getOutDir(), true));
passes.add(new CleanRegions());
} }
passes.add(new CodeGen(args)); passes.add(new CodeGen(args));
return passes; return passes;
......
...@@ -66,7 +66,7 @@ public class MethodGen { ...@@ -66,7 +66,7 @@ public class MethodGen {
} else { } else {
if (mth.getAttributes().contains(AttributeFlag.INCONSISTENT_CODE)) { if (mth.getAttributes().contains(AttributeFlag.INCONSISTENT_CODE)) {
code.startLine("// FIXME: Jadx generate inconsistent code"); code.startLine("// FIXME: Jadx generate inconsistent code");
// ErrorsCounter.methodError(mth, "Inconsistent code"); LOG.debug(ErrorsCounter.formatErrorMsg(mth, " Inconsistent code"));
} }
annotationGen.addForMethod(code, mth); annotationGen.addForMethod(code, mth);
......
...@@ -58,6 +58,7 @@ public class RegionGen extends InsnGen { ...@@ -58,6 +58,7 @@ public class RegionGen extends InsnGen {
makeRegion(code, c); makeRegion(code, c);
} }
} else if (cont instanceof IfRegion) { } else if (cont instanceof IfRegion) {
code.startLine();
makeIf((IfRegion) cont, code); makeIf((IfRegion) cont, code);
} else if (cont instanceof SwitchRegion) { } else if (cont instanceof SwitchRegion) {
makeSwitch((SwitchRegion) cont, code); makeSwitch((SwitchRegion) cont, code);
...@@ -104,13 +105,25 @@ public class RegionGen extends InsnGen { ...@@ -104,13 +105,25 @@ public class RegionGen extends InsnGen {
private void makeIf(IfRegion region, CodeWriter code) throws CodegenException { private void makeIf(IfRegion region, CodeWriter code) throws CodegenException {
IfNode insn = region.getIfInsn(); IfNode insn = region.getIfInsn();
code.startLine("if ").add(makeCondition(insn)).add(" {"); code.add("if ").add(makeCondition(insn)).add(" {");
makeRegionIndent(code, region.getThenRegion()); makeRegionIndent(code, region.getThenRegion());
code.startLine("}"); code.startLine("}");
IContainer els = region.getElseRegion(); IContainer els = region.getElseRegion();
if (els != null && RegionUtils.notEmpty(els)) { if (els != null && RegionUtils.notEmpty(els)) {
code.add(" else {"); code.add(" else ");
// connect if-else-if block
if (els instanceof Region) {
Region re = (Region) els;
if (re.getSubBlocks().size() == 1
&& re.getSubBlocks().get(0) instanceof IfRegion) {
makeIf((IfRegion) re.getSubBlocks().get(0), code);
return;
}
}
code.add("{");
code.incIndent(); code.incIndent();
makeRegion(code, els); makeRegion(code, els);
code.decIndent(); code.decIndent();
......
...@@ -6,6 +6,7 @@ import jadx.dex.nodes.IContainer; ...@@ -6,6 +6,7 @@ import jadx.dex.nodes.IContainer;
import jadx.dex.nodes.IRegion; import jadx.dex.nodes.IRegion;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
public final class IfRegion extends AbstractRegion { public final class IfRegion extends AbstractRegion {
...@@ -52,7 +53,7 @@ public final class IfRegion extends AbstractRegion { ...@@ -52,7 +53,7 @@ public final class IfRegion extends AbstractRegion {
all.add(thenRegion); all.add(thenRegion);
if (elseRegion != null) if (elseRegion != null)
all.add(elseRegion); all.add(elseRegion);
return all; return Collections.unmodifiableList(all);
} }
@Override @Override
......
...@@ -8,6 +8,7 @@ import jadx.dex.nodes.IRegion; ...@@ -8,6 +8,7 @@ import jadx.dex.nodes.IRegion;
import jadx.dex.nodes.InsnNode; import jadx.dex.nodes.InsnNode;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
public final class LoopRegion extends AbstractRegion { public final class LoopRegion extends AbstractRegion {
...@@ -112,7 +113,7 @@ public final class LoopRegion extends AbstractRegion { ...@@ -112,7 +113,7 @@ public final class LoopRegion extends AbstractRegion {
if (conditionBlock != null) if (conditionBlock != null)
all.add(conditionBlock); all.add(conditionBlock);
all.add(body); all.add(body);
return all; return Collections.unmodifiableList(all);
} }
@Override @Override
......
...@@ -5,6 +5,7 @@ import jadx.dex.nodes.IContainer; ...@@ -5,6 +5,7 @@ import jadx.dex.nodes.IContainer;
import jadx.dex.nodes.IRegion; import jadx.dex.nodes.IRegion;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
public final class SwitchRegion extends AbstractRegion { public final class SwitchRegion extends AbstractRegion {
...@@ -54,7 +55,7 @@ public final class SwitchRegion extends AbstractRegion { ...@@ -54,7 +55,7 @@ public final class SwitchRegion extends AbstractRegion {
all.addAll(cases); all.addAll(cases);
if (defCase != null) if (defCase != null)
all.add(defCase); all.add(defCase);
return all; return Collections.unmodifiableList(all);
} }
@Override @Override
......
...@@ -7,7 +7,7 @@ import jadx.utils.exceptions.JadxException; ...@@ -7,7 +7,7 @@ import jadx.utils.exceptions.JadxException;
import java.util.Iterator; import java.util.Iterator;
public class ClassCheck extends AbstractVisitor { public class ClassModifier extends AbstractVisitor {
@Override @Override
public boolean visit(ClassNode cls) throws JadxException { public boolean visit(ClassNode cls) throws JadxException {
......
...@@ -7,8 +7,6 @@ import jadx.utils.ErrorsCounter; ...@@ -7,8 +7,6 @@ import jadx.utils.ErrorsCounter;
public class DepthTraverser { public class DepthTraverser {
public static void visit(IDexTreeVisitor visitor, ClassNode cls) { public static void visit(IDexTreeVisitor visitor, ClassNode cls) {
// if (!cls.toString().contains("ProcessClass"))
// return;
try { try {
if (visitor.visit(cls)) { if (visitor.visit(cls)) {
for (ClassNode inCls : cls.getInnerClasses()) for (ClassNode inCls : cls.getInnerClasses())
......
...@@ -174,6 +174,8 @@ public class DotGraphVisitor extends AbstractVisitor { ...@@ -174,6 +174,8 @@ public class DotGraphVisitor extends AbstractVisitor {
private String escape(String string) { private String escape(String string) {
return string return string
.replace("\\", "") // TODO replace \"
.replace("/", "\\/")
.replace(">", "\\>").replace("<", "\\<") .replace(">", "\\>").replace("<", "\\<")
.replace("{", "\\{").replace("}", "\\}") .replace("{", "\\{").replace("}", "\\}")
.replace("\"", "\\\"") .replace("\"", "\\\"")
......
package jadx.dex.visitors.regions;
import jadx.dex.nodes.BlockNode;
import jadx.dex.nodes.IContainer;
import jadx.dex.nodes.IRegion;
import jadx.dex.nodes.MethodNode;
import jadx.dex.regions.Region;
import jadx.dex.visitors.AbstractVisitor;
import jadx.utils.exceptions.JadxException;
import java.util.Iterator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CleanRegions extends AbstractVisitor {
private static final Logger LOG = LoggerFactory.getLogger(CleanRegions.class);
@Override
public void visit(MethodNode mth) throws JadxException {
if (mth.isNoCode() || mth.getBasicBlocks().size() == 0)
return;
IRegionVisitor removeEmptyBlocks = new AbstractRegionVisitor() {
@Override
public void enterRegion(MethodNode mth, IRegion region) {
if (!(region instanceof Region))
return;
for (Iterator<IContainer> it = region.getSubBlocks().iterator(); it.hasNext();) {
IContainer container = it.next();
if (container instanceof BlockNode) {
BlockNode block = (BlockNode) container;
if (block.getInstructions().isEmpty()) {
try {
it.remove();
} catch (UnsupportedOperationException e) {
LOG.warn("Can't remove block: {} from: {}, mth: {}", block, region, mth);
}
}
}
}
}
};
DepthRegionTraverser.traverseAll(mth, removeEmptyBlocks);
}
}
...@@ -79,7 +79,7 @@ public class MarkTryCatchRegions extends AbstractRegionVisitor { ...@@ -79,7 +79,7 @@ public class MarkTryCatchRegions extends AbstractRegionVisitor {
TryCatchBlock prevTB = tryBlocksMap.put(domBlock, tb); TryCatchBlock prevTB = tryBlocksMap.put(domBlock, tb);
if (prevTB != null) { if (prevTB != null) {
LOG.info("!!! TODO merge try blocks"); LOG.info("!!! TODO merge try blocks in " + mth);
} }
} }
......
...@@ -113,7 +113,7 @@ public class RegionMaker { ...@@ -113,7 +113,7 @@ public class RegionMaker {
next = BlockUtils.getNextBlock(block); next = BlockUtils.getNextBlock(block);
} }
if (!stack.containsExit(block) && next != null && !stack.containsExit(next)) if (next != null && !stack.containsExit(block) && !stack.containsExit(next))
return next; return next;
else else
return null; return null;
......
...@@ -28,10 +28,12 @@ public class RegionStack { ...@@ -28,10 +28,12 @@ public class RegionStack {
exits = new HashSet<BlockNode>(); exits = new HashSet<BlockNode>();
} }
private State(State c) {
exits = new HashSet<BlockNode>(c.exits);
}
public State copy() { public State copy() {
State c = new State(); return new State(this);
c.exits.addAll(exits);
return c;
} }
@Override @Override
...@@ -57,8 +59,10 @@ public class RegionStack { ...@@ -57,8 +59,10 @@ public class RegionStack {
curState = curState.copy(); curState = curState.copy();
curState.region = region; curState.region = region;
if (DEBUG) if (DEBUG) {
LOG.debug("Stack push: {} = {}", region, curState); LOG.debug("Stack push: {} = {}", region, curState);
LOG.debug("Stack size: {}", size());
}
} }
public void pop() { public void pop() {
...@@ -89,4 +93,9 @@ public class RegionStack { ...@@ -89,4 +93,9 @@ public class RegionStack {
public int size() { public int size() {
return stack.size(); return stack.size();
} }
@Override
public String toString() {
return "Region stack size: " + size() + ", last: " + curState;
}
} }
...@@ -19,6 +19,8 @@ public class RegionUtils { ...@@ -19,6 +19,8 @@ public class RegionUtils {
} else if (container instanceof IRegion) { } else if (container instanceof IRegion) {
IRegion region = (IRegion) container; IRegion region = (IRegion) container;
List<IContainer> blocks = region.getSubBlocks(); List<IContainer> blocks = region.getSubBlocks();
if (blocks.isEmpty())
return false;
return hasExitEdge(blocks.get(blocks.size() - 1)); return hasExitEdge(blocks.get(blocks.size() - 1));
} else { } else {
throw new JadxRuntimeException("Unknown container type: " + container.getClass()); throw new JadxRuntimeException("Unknown container type: " + container.getClass());
......
...@@ -132,6 +132,23 @@ public class TestCF extends AbstractTest { ...@@ -132,6 +132,23 @@ public class TestCF extends AbstractTest {
return c; return c;
} }
public int testIfElse(String str) {
int r;
if (str.equals("a"))
r = 1;
else if (str.equals("b"))
r = 2;
else if (str.equals("3"))
r = 3;
else if (str.equals("$"))
r = 4;
else
r = -1;
r = r * 10;
return Math.abs(r);
}
public void testInfiniteLoop() { public void testInfiniteLoop() {
while (true) { while (true) {
System.out.println("test"); System.out.println("test");
...@@ -174,6 +191,9 @@ public class TestCF extends AbstractTest { ...@@ -174,6 +191,9 @@ public class TestCF extends AbstractTest {
assertEquals(c.test4(5, 9), 3240); assertEquals(c.test4(5, 9), 3240);
assertEquals(c.test4(8, 15), 0); assertEquals(c.test4(8, 15), 0);
assertEquals(c.testIfElse("b"), 20);
assertEquals(c.testIfElse("c"), 10);
return true; return true;
} }
......
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