Commit 8a464e82 authored by Skylot's avatar Skylot

core: fix condition processing errors

parent 066b5a89
......@@ -15,9 +15,9 @@ import jadx.core.dex.visitors.ModVisitor;
import jadx.core.dex.visitors.PrepareForCodeGen;
import jadx.core.dex.visitors.SimplifyVisitor;
import jadx.core.dex.visitors.regions.CheckRegions;
import jadx.core.dex.visitors.regions.IfRegionVisitor;
import jadx.core.dex.visitors.regions.ProcessVariables;
import jadx.core.dex.visitors.regions.RegionMakerVisitor;
import jadx.core.dex.visitors.regions.TernaryVisitor;
import jadx.core.dex.visitors.typeresolver.FinishTypeResolver;
import jadx.core.dex.visitors.typeresolver.TypeResolver;
import jadx.core.utils.Utils;
......@@ -70,7 +70,7 @@ public class Jadx {
passes.add(new CodeShrinker());
passes.add(new RegionMakerVisitor());
passes.add(new TernaryVisitor());
passes.add(new IfRegionVisitor());
passes.add(new CodeShrinker());
passes.add(new SimplifyVisitor());
......
......@@ -2,6 +2,7 @@ package jadx.core.dex.instructions.mods;
import jadx.core.dex.instructions.InsnType;
import jadx.core.dex.instructions.args.InsnArg;
import jadx.core.dex.instructions.args.LiteralArg;
import jadx.core.dex.instructions.args.RegisterArg;
import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.regions.IfCondition;
......@@ -14,10 +15,18 @@ public class TernaryInsn extends InsnNode {
public TernaryInsn(IfCondition condition, RegisterArg result, InsnArg th, InsnArg els) {
super(InsnType.TERNARY, 2);
this.condition = condition;
setResult(result);
addArg(th);
addArg(els);
if (th.equals(LiteralArg.FALSE) && els.equals(LiteralArg.TRUE)) {
// inverted
this.condition = IfCondition.invert(condition);
addArg(els);
addArg(th);
} else {
this.condition = condition;
addArg(th);
addArg(els);
}
}
public IfCondition getCondition() {
......
......@@ -22,8 +22,13 @@ public class BlockNode extends AttrNode implements IBlock {
private List<BlockNode> successors = new ArrayList<BlockNode>(1);
private List<BlockNode> cleanSuccessors;
private BitSet doms; // all dominators
private BlockNode idom; // immediate dominator
// all dominators
private BitSet doms;
// dominance frontier
private BitSet domFrontier;
// immediate dominator
private BlockNode idom;
// blocks on which dominates this block
private final List<BlockNode> dominatesOn = new ArrayList<BlockNode>(1);
private BlockRegState startState;
......@@ -118,6 +123,14 @@ public class BlockNode extends AttrNode implements IBlock {
this.doms = doms;
}
public BitSet getDomFrontier() {
return domFrontier;
}
public void setDomFrontier(BitSet domFrontier) {
this.domFrontier = domFrontier;
}
/**
* Immediate dominator
*/
......
......@@ -8,4 +8,5 @@ public interface IRegion extends IContainer {
List<IContainer> getSubBlocks();
boolean replaceSubBlock(IContainer oldBlock, IContainer newBlock);
}
package jadx.core.dex.regions;
import jadx.core.dex.attributes.AttrNode;
import jadx.core.dex.nodes.IContainer;
import jadx.core.dex.nodes.IRegion;
public abstract class AbstractRegion extends AttrNode implements IRegion {
......@@ -19,4 +20,10 @@ public abstract class AbstractRegion extends AttrNode implements IRegion {
public void setParent(IRegion parent) {
this.parent = parent;
}
@Override
public boolean replaceSubBlock(IContainer oldBlock, IContainer newBlock) {
// TODO: implement for others regions
return false;
}
}
......@@ -21,6 +21,23 @@ public final class Region extends AbstractRegion {
return blocks;
}
public void add(IContainer region) {
if (region instanceof AbstractRegion) {
((AbstractRegion) region).setParent(this);
}
blocks.add(region);
}
@Override
public boolean replaceSubBlock(IContainer oldBlock, IContainer newBlock) {
int i = blocks.indexOf(oldBlock);
if (i != -1) {
blocks.set(i, newBlock);
return true;
}
return false;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
......@@ -35,5 +52,4 @@ public final class Region extends AbstractRegion {
}
return sb.toString();
}
}
......@@ -19,6 +19,7 @@ import jadx.core.dex.trycatch.CatchAttr;
import jadx.core.dex.trycatch.ExceptionHandler;
import jadx.core.dex.trycatch.SplitterBlockAttr;
import jadx.core.utils.BlockUtils;
import jadx.core.utils.EmptyBitSet;
import jadx.core.utils.exceptions.JadxRuntimeException;
import java.util.ArrayList;
......@@ -41,6 +42,8 @@ public class BlockMakerVisitor extends AbstractVisitor {
InsnType.MONITOR_ENTER,
InsnType.MONITOR_EXIT);
private static final BitSet EMPTY_BITSET = new EmptyBitSet();
private static int nextBlockId;
@Override
......@@ -298,6 +301,56 @@ public class BlockMakerVisitor extends AbstractVisitor {
}
}
}
computeDominanceFrontier(mth);
}
private static void computeDominanceFrontier(MethodNode mth) {
for (BlockNode exit : mth.getExitBlocks()) {
exit.setDomFrontier(EMPTY_BITSET);
}
for (BlockNode block : mth.getBasicBlocks()) {
computeBlockDF(block);
}
}
private static void computeBlockDF(BlockNode block) {
if (block.getDomFrontier() != null) {
return;
}
BitSet domFrontier = null;
BitSet doms = block.getDoms();
int id = block.getId();
for (BlockNode s : block.getSuccessors()) {
if (s.getIDom() != block) {
if (domFrontier == null) {
domFrontier = new BitSet();
}
domFrontier.set(s.getId());
}
}
for (BlockNode node : block.getDominatesOn()) {
if (node.getIDom() == block) {
BitSet frontier = node.getDomFrontier();
if (frontier == null) {
computeBlockDF(node);
frontier = node.getDomFrontier();
}
for (int w = frontier.nextSetBit(0); w >= 0; w = frontier.nextSetBit(w + 1)) {
if (id == w || !doms.get(w)) {
if (domFrontier == null) {
domFrontier = new BitSet();
}
domFrontier.set(w);
}
}
}
}
if (domFrontier == null || domFrontier.cardinality() == 0) {
domFrontier = EMPTY_BITSET;
}
block.setDomFrontier(domFrontier);
}
private static void markReturnBlocks(MethodNode mth) {
......
......@@ -11,6 +11,7 @@ import jadx.core.dex.nodes.IRegion;
import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.trycatch.ExceptionHandler;
import jadx.core.utils.BlockUtils;
import jadx.core.utils.InsnUtils;
import jadx.core.utils.RegionUtils;
import jadx.core.utils.Utils;
......@@ -23,6 +24,7 @@ import java.util.Set;
public class DotGraphVisitor extends AbstractVisitor {
private static final String NL = "\\l";
private static final boolean PRINT_DOMINATORS = false;
private final File dir;
private final boolean useRegions;
......@@ -161,14 +163,31 @@ public class DotGraphVisitor extends AbstractVisitor {
falsePath = ((IfNode) list.get(0)).getElseBlock();
}
for (BlockNode next : block.getSuccessors()) {
conn.startLine(makeName(block)).add(" -> ").add(makeName(next));
if (next == falsePath) {
conn.add("[style=dotted]");
String style = next == falsePath ? "[style=dashed]" : "";
addEdge(block, next, style);
}
if (PRINT_DOMINATORS) {
for (BlockNode dom : BlockUtils.bitSetToBlocks(mth, block.getDoms())) {
String style = "[color=green]";
if (dom == block.getIDom()) {
style = "[style=dashed, color=green]";
}
addEdge(block, dom, style);
}
for (BlockNode dom : BlockUtils.bitSetToBlocks(mth, block.getDomFrontier())) {
addEdge(block, dom, "[color=blue]");
}
conn.add(';');
}
}
private void addEdge(BlockNode from, BlockNode to, String style) {
conn.startLine(makeName(from)).add(" -> ").add(makeName(to));
conn.add(style);
conn.add(';');
}
private String attributesString(IAttributeNode block) {
StringBuilder attrs = new StringBuilder();
for (String attr : block.getAttributes().getAttributeStrings()) {
......
......@@ -22,7 +22,8 @@ public class MethodInlineVisitor extends AbstractVisitor {
&& accessFlags.isStatic()
&& mth.getBasicBlocks().size() == 2) {
BlockNode block = mth.getBasicBlocks().get(1);
if (block.getAttributes().contains(AttributeFlag.RETURN)) {
if (block.getInstructions().isEmpty()
|| block.getAttributes().contains(AttributeFlag.RETURN)) {
inlineMth(mth);
}
}
......
......@@ -38,7 +38,7 @@ public class CheckRegions extends AbstractVisitor {
}
}
};
DepthRegionTraverser.traverseAll(mth, collectBlocks);
DepthRegionTraversal.traverseAll(mth, collectBlocks);
if (mth.getBasicBlocks().size() != blocksInRegions.size()) {
for (BlockNode block : mth.getBasicBlocks()) {
......@@ -65,6 +65,6 @@ public class CheckRegions extends AbstractVisitor {
}
}
};
DepthRegionTraverser.traverseAll(mth, checkLoops);
DepthRegionTraversal.traverseAll(mth, checkLoops);
}
}
......@@ -44,6 +44,6 @@ public class CleanRegions {
}
}
};
DepthRegionTraverser.traverseAll(mth, removeEmptyBlocks);
DepthRegionTraversal.traverseAll(mth, removeEmptyBlocks);
}
}
......@@ -6,26 +6,66 @@ import jadx.core.dex.nodes.IRegion;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.trycatch.ExceptionHandler;
public class DepthRegionTraverser {
public class DepthRegionTraversal {
public static void traverse(MethodNode mth, IRegionVisitor visitor, IContainer container) {
private DepthRegionTraversal() {
}
public static void traverse(MethodNode mth, IRegionVisitor visitor) {
traverseInternal(mth, visitor, mth.getRegion());
}
public static void traverseAll(MethodNode mth, IRegionVisitor visitor) {
traverse(mth, visitor);
for (ExceptionHandler h : mth.getExceptionHandlers()) {
traverseInternal(mth, visitor, h.getHandlerRegion());
}
}
public static void traverseAllIterative(MethodNode mth, IRegionIterativeVisitor visitor) {
boolean repeat;
do {
repeat = traverseAllIterativeIntern(mth, visitor);
} while (repeat);
}
private static void traverseInternal(MethodNode mth, IRegionVisitor visitor, IContainer container) {
if (container instanceof IBlock) {
visitor.processBlock(mth, (IBlock) container);
} else if (container instanceof IRegion) {
IRegion region = (IRegion) container;
visitor.enterRegion(mth, region);
for (IContainer subCont : region.getSubBlocks()) {
traverse(mth, visitor, subCont);
traverseInternal(mth, visitor, subCont);
}
visitor.leaveRegion(mth, region);
}
}
public static void traverseAll(MethodNode mth, IRegionVisitor visitor) {
traverse(mth, visitor, mth.getRegion());
private static boolean traverseAllIterativeIntern(MethodNode mth, IRegionIterativeVisitor visitor) {
if (traverseIterativeInternal(mth, visitor, mth.getRegion())) {
return true;
}
for (ExceptionHandler h : mth.getExceptionHandlers()) {
traverse(mth, visitor, h.getHandlerRegion());
if (traverseIterativeInternal(mth, visitor, h.getHandlerRegion())) {
return true;
}
}
return false;
}
public static boolean traverseIterativeInternal(MethodNode mth, IRegionIterativeVisitor visitor, IContainer container) {
if (container instanceof IRegion) {
IRegion region = (IRegion) container;
if (visitor.visitRegion(mth, region)) {
return true;
}
for (IContainer subCont : region.getSubBlocks()) {
if (traverseIterativeInternal(mth, visitor, subCont)) {
return true;
}
}
}
return false;
}
}
package jadx.core.dex.visitors.regions;
import jadx.core.dex.nodes.IRegion;
import jadx.core.dex.nodes.MethodNode;
public interface IRegionIterativeVisitor {
/**
* If return 'true' traversal will be restarted.
*/
boolean visitRegion(MethodNode mth, IRegion region);
}
package jadx.core.dex.visitors.regions;
import jadx.core.dex.attributes.AttributeFlag;
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.nodes.IBlock;
import jadx.core.dex.nodes.IContainer;
import jadx.core.dex.nodes.IRegion;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.regions.IfCondition;
import jadx.core.dex.regions.IfRegion;
import jadx.core.dex.regions.Region;
import jadx.core.dex.visitors.AbstractVisitor;
import jadx.core.utils.RegionUtils;
import java.util.List;
public class IfRegionVisitor extends AbstractVisitor implements IRegionVisitor, IRegionIterativeVisitor {
@Override
public void visit(MethodNode mth) {
DepthRegionTraversal.traverseAll(mth, this);
DepthRegionTraversal.traverseAllIterative(mth, this);
}
@Override
public void enterRegion(MethodNode mth, IRegion region) {
if (region instanceof IfRegion) {
processIfRegion(mth, (IfRegion) region);
}
}
@Override
public boolean visitRegion(MethodNode mth, IRegion region) {
if (region instanceof IfRegion) {
return removeRedundantElseBlock((IfRegion) region);
}
return false;
}
@Override
public void processBlock(MethodNode mth, IBlock container) {
}
@Override
public void leaveRegion(MethodNode mth, IRegion region) {
}
private static void processIfRegion(MethodNode mth, IfRegion ifRegion) {
simplifyIfCondition(ifRegion);
moveReturnToThenBlock(mth, ifRegion);
markElseIfChains(ifRegion);
TernaryMod.makeTernaryInsn(mth, ifRegion);
}
private static void simplifyIfCondition(IfRegion ifRegion) {
if (ifRegion.simplifyCondition()) {
IfCondition condition = ifRegion.getCondition();
if (condition.getMode() == IfCondition.Mode.NOT) {
tryInvertIfRegion(ifRegion);
}
}
}
private static void moveReturnToThenBlock(MethodNode mth, IfRegion ifRegion) {
if (!mth.getReturnType().equals(ArgType.VOID)
&& hasSimpleReturnBlock(ifRegion.getElseRegion())
&& !hasSimpleReturnBlock(ifRegion.getThenRegion())) {
tryInvertIfRegion(ifRegion);
}
}
private static boolean removeRedundantElseBlock(IfRegion ifRegion) {
if (ifRegion.getElseRegion() != null && hasSimpleReturnBlock(ifRegion.getThenRegion())) {
IRegion parent = ifRegion.getParent();
Region newRegion = new Region(parent);
if (parent.replaceSubBlock(ifRegion, newRegion)) {
newRegion.add(ifRegion);
newRegion.add(ifRegion.getElseRegion());
ifRegion.setElseRegion(null);
return true;
}
}
return false;
}
/**
* Mark if-else-if chains
*/
private static void markElseIfChains(IfRegion ifRegion) {
IContainer elsRegion = ifRegion.getElseRegion();
if (elsRegion != null) {
if (elsRegion instanceof IfRegion) {
elsRegion.getAttributes().add(AttributeFlag.ELSE_IF_CHAIN);
} else if (elsRegion instanceof Region) {
List<IContainer> subBlocks = ((Region) elsRegion).getSubBlocks();
if (subBlocks.size() == 1 && subBlocks.get(0) instanceof IfRegion) {
subBlocks.get(0).getAttributes().add(AttributeFlag.ELSE_IF_CHAIN);
}
}
}
}
private static void tryInvertIfRegion(IfRegion ifRegion) {
IContainer elseRegion = ifRegion.getElseRegion();
if (elseRegion != null && RegionUtils.notEmpty(elseRegion)) {
ifRegion.invert();
}
}
private static boolean hasSimpleReturnBlock(IContainer region) {
if (region == null) {
return false;
}
if (region.getAttributes().contains(AttributeFlag.RETURN)) {
return true;
}
if (region instanceof IRegion) {
List<IContainer> subBlocks = ((IRegion) region).getSubBlocks();
if (subBlocks.size() == 1
&& subBlocks.get(0).getAttributes().contains(AttributeFlag.RETURN)) {
return true;
}
}
return false;
}
}
......@@ -32,6 +32,7 @@ public class ProcessReturnInsns extends TracedRegionVisitor {
&& blockNotInLoop(mth, block)
&& noTrailInstructions(block)) {
insns.remove(insns.size() - 1);
block.getAttributes().remove(AttributeFlag.RETURN);
}
}
}
......
......@@ -104,7 +104,7 @@ public class ProcessVariables extends AbstractVisitor {
}
}
};
DepthRegionTraverser.traverseAll(mth, collect);
DepthRegionTraversal.traverseAll(mth, collect);
// reduce assigns map
List<RegisterArg> mthArgs = mth.getArguments(true);
......
......@@ -412,27 +412,22 @@ public class RegionMaker {
BlockNode thenBlock = null;
BlockNode elseBlock = null;
for (BlockNode d : block.getDominatesOn()) {
if (d != bThen && d != bElse) {
out = d;
break;
}
}
IfRegion ifRegion = new IfRegion(currentRegion, block);
currentRegion.getSubBlocks().add(ifRegion);
IfInfo mergedIf = mergeNestedIfNodes(block, bThen, bElse, null);
if (mergedIf != null) {
block = mergedIf.getIfnode();
ifRegion.setCondition(mergedIf.getCondition());
thenBlock = mergedIf.getThenBlock();
elseBlock = mergedIf.getElseBlock();
bThen = thenBlock;
bElse = elseBlock;
}
if (thenBlock == null) {
out = BlockUtils.getPathCrossBlockFor(mth, thenBlock, elseBlock);
} else {
for (BlockNode d : block.getDominatesOn()) {
if (d != bThen && d != bElse) {
out = d;
break;
}
}
// invert condition (compiler often do it)
ifnode.invertCondition();
BlockNode tmp = bThen;
......
package jadx.core.dex.visitors.regions;
import jadx.core.dex.attributes.AttributeFlag;
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.nodes.IContainer;
import jadx.core.dex.nodes.IRegion;
import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.regions.IfRegion;
import jadx.core.dex.regions.LoopRegion;
import jadx.core.dex.regions.Region;
import jadx.core.dex.regions.SynchronizedRegion;
......@@ -49,11 +47,11 @@ public class RegionMakerVisitor extends AbstractVisitor {
private static void postProcessRegions(MethodNode mth) {
// make try-catch regions
DepthRegionTraverser.traverse(mth, new ProcessTryCatchRegions(mth), mth.getRegion());
DepthRegionTraversal.traverse(mth, new ProcessTryCatchRegions(mth));
// merge conditions in loops
if (mth.getLoopsCount() != 0) {
DepthRegionTraverser.traverseAll(mth, new AbstractRegionVisitor() {
DepthRegionTraversal.traverseAll(mth, new AbstractRegionVisitor() {
@Override
public void enterRegion(MethodNode mth, IRegion region) {
if (region instanceof LoopRegion) {
......@@ -66,45 +64,14 @@ public class RegionMakerVisitor extends AbstractVisitor {
CleanRegions.process(mth);
DepthRegionTraverser.traverseAll(mth, new AbstractRegionVisitor() {
@Override
public void leaveRegion(MethodNode mth, IRegion region) {
if (region instanceof IfRegion) {
processIfRegion((IfRegion) region);
}
}
});
// remove useless returns in void methods
if (mth.getReturnType().equals(ArgType.VOID)) {
DepthRegionTraverser.traverseAll(mth, new ProcessReturnInsns());
DepthRegionTraversal.traverseAll(mth, new ProcessReturnInsns());
}
if (mth.getAccessFlags().isSynchronized()) {
removeSynchronized(mth);
}
}
private static void processIfRegion(IfRegion ifRegion) {
if (ifRegion.simplifyCondition()) {
// IfCondition condition = ifRegion.getCondition();
// if (condition.getMode() == IfCondition.Mode.NOT) {
// ifRegion.invert();
// }
}
// mark if-else-if chains
IContainer elsRegion = ifRegion.getElseRegion();
if (elsRegion instanceof IfRegion) {
elsRegion.getAttributes().add(AttributeFlag.ELSE_IF_CHAIN);
} else if (elsRegion instanceof Region) {
List<IContainer> subBlocks = ((Region) elsRegion).getSubBlocks();
if (subBlocks.size() == 1 && subBlocks.get(0) instanceof IfRegion) {
subBlocks.get(0).getAttributes().add(AttributeFlag.ELSE_IF_CHAIN);
}
}
}
private static void removeSynchronized(MethodNode mth) {
......
......@@ -4,49 +4,28 @@ import jadx.core.dex.attributes.AttributeFlag;
import jadx.core.dex.instructions.InsnType;
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.instructions.args.InsnArg;
import jadx.core.dex.instructions.args.LiteralArg;
import jadx.core.dex.instructions.mods.TernaryInsn;
import jadx.core.dex.nodes.BlockNode;
import jadx.core.dex.nodes.ClassNode;
import jadx.core.dex.nodes.IContainer;
import jadx.core.dex.nodes.IRegion;
import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.regions.IfCondition;
import jadx.core.dex.regions.IfRegion;
import jadx.core.dex.regions.Region;
import jadx.core.dex.regions.TernaryRegion;
import jadx.core.dex.visitors.CodeShrinker;
import jadx.core.dex.visitors.IDexTreeVisitor;
import jadx.core.utils.InsnList;
import jadx.core.utils.exceptions.JadxException;
import java.util.List;
public class TernaryVisitor extends AbstractRegionVisitor implements IDexTreeVisitor {
public class TernaryMod {
private static final LiteralArg FALSE_ARG = InsnArg.lit(0, ArgType.BOOLEAN);
private static final LiteralArg TRUE_ARG = InsnArg.lit(1, ArgType.BOOLEAN);
@Override
public boolean visit(ClassNode cls) throws JadxException {
return true;
}
@Override
public void visit(MethodNode mth) {
DepthRegionTraverser.traverseAll(mth, this);
private TernaryMod() {
}
@Override
public void enterRegion(MethodNode mth, IRegion region) {
if (!(region instanceof IfRegion)) {
static void makeTernaryInsn(MethodNode mth, IfRegion ifRegion) {
if (ifRegion.getAttributes().contains(AttributeFlag.ELSE_IF_CHAIN)) {
return;
}
if (region.getAttributes().contains(AttributeFlag.ELSE_IF_CHAIN)) {
return;
}
IfRegion ifRegion = (IfRegion) region;
IContainer thenRegion = ifRegion.getThenRegion();
IContainer elseRegion = ifRegion.getElseRegion();
if (thenRegion == null || elseRegion == null) {
......@@ -89,25 +68,12 @@ public class TernaryVisitor extends AbstractRegionVisitor implements IDexTreeVis
if (!mth.getReturnType().equals(ArgType.VOID)
&& t.getType() == InsnType.RETURN && e.getType() == InsnType.RETURN) {
boolean inverted = false;
InsnArg thenArg = t.getArg(0);
InsnArg elseArg = e.getArg(0);
if (thenArg.equals(FALSE_ARG) && elseArg.equals(TRUE_ARG)) {
inverted = true;
}
InsnList.remove(tb, t);
InsnList.remove(eb, e);
tb.getAttributes().remove(AttributeFlag.RETURN);
eb.getAttributes().remove(AttributeFlag.RETURN);
IfCondition condition = ifRegion.getCondition();
if (inverted) {
condition = IfCondition.invert(condition);
InsnArg tmp = thenArg;
thenArg = elseArg;
elseArg = tmp;
}
TernaryInsn ternInsn = new TernaryInsn(condition, null, thenArg, elseArg);
TernaryInsn ternInsn = new TernaryInsn(ifRegion.getCondition(), null, t.getArg(0), e.getArg(0));
InsnNode retInsn = new InsnNode(InsnType.RETURN, 1);
retInsn.addArg(InsnArg.wrapArg(ternInsn));
......
......@@ -169,17 +169,18 @@ public class BlockUtils {
}
}
private static boolean traverseSuccessorsUntil(BlockNode from, BlockNode until, Set<BlockNode> checked) {
private static boolean traverseSuccessorsUntil(BlockNode from, BlockNode until, BitSet visited) {
for (BlockNode s : from.getCleanSuccessors()) {
if (s == until) {
return true;
}
if (!checked.contains(s)) {
checked.add(s);
int id = s.getId();
if (!visited.get(id)) {
visited.set(id);
if (until.isDominator(s)) {
return true;
}
if (traverseSuccessorsUntil(s, until, checked)) {
if (traverseSuccessorsUntil(s, until, visited)) {
return true;
}
}
......@@ -194,7 +195,7 @@ public class BlockUtils {
if (end.isDominator(start)) {
return true;
}
return traverseSuccessorsUntil(start, end, new HashSet<BlockNode>());
return traverseSuccessorsUntil(start, end, new BitSet());
}
public static boolean isOnlyOnePathExists(BlockNode start, BlockNode end) {
......@@ -230,6 +231,24 @@ public class BlockUtils {
return null;
}
public static BlockNode getPathCrossBlockFor(MethodNode mth, BlockNode b1, BlockNode b2) {
if (b1 == null || b2 == null) {
return null;
}
BitSet b = new BitSet();
b.or(b1.getDomFrontier());
b.or(b2.getDomFrontier());
b.clear(b1.getId());
b.clear(b2.getId());
if (b.cardinality() == 1) {
BlockNode end = mth.getBasicBlocks().get(b.nextSetBit(0));
if (isPathExists(b1, end) && isPathExists(b2, end)) {
return end;
}
}
return null;
}
/**
* Collect all block dominated by 'dominator', starting from 'start'
*/
......
package jadx.core.utils;
import java.util.BitSet;
public class EmptyBitSet extends BitSet {
public EmptyBitSet() {
super(0);
}
@Override
public int cardinality() {
return 0;
}
@Override
public boolean isEmpty() {
return true;
}
@Override
public int nextSetBit(int fromIndex) {
return -1;
}
@Override
public int length() {
return 0;
}
@Override
public int size() {
return 0;
}
@Override
public void set(int bitIndex) {
throw new UnsupportedOperationException();
}
@Override
public void set(int bitIndex, boolean value) {
throw new UnsupportedOperationException();
}
@Override
public void set(int fromIndex, int toIndex) {
throw new UnsupportedOperationException();
}
@Override
public void set(int fromIndex, int toIndex, boolean value) {
throw new UnsupportedOperationException();
}
@Override
public boolean get(int bitIndex) {
return false;
}
@Override
public BitSet get(int fromIndex, int toIndex) {
throw new UnsupportedOperationException();
}
@Override
public void and(BitSet set) {
throw new UnsupportedOperationException();
}
@Override
public void or(BitSet set) {
throw new UnsupportedOperationException();
}
@Override
public void xor(BitSet set) {
throw new UnsupportedOperationException();
}
@Override
public void andNot(BitSet set) {
throw new UnsupportedOperationException();
}
}
......@@ -12,7 +12,7 @@ import static org.junit.Assert.assertThat;
public class TestConditions extends InternalJadxTest {
public static class TestCls {
private boolean f1(boolean a, boolean b, boolean c) {
private boolean test(boolean a, boolean b, boolean c) {
return (a && b) || c;
}
}
......@@ -24,7 +24,6 @@ public class TestConditions extends InternalJadxTest {
System.out.println(code);
assertThat(code, not(containsString("(!a || !b) && !c")));
assertThat(code, containsString("(a && b) || c"));
// assertThat(code, containsString("return (a && b) || c;"));
assertThat(code, containsString("return (a && b) || c;"));
}
}
package jadx.tests.internal.conditions;
import jadx.api.InternalJadxTest;
import jadx.core.dex.nodes.ClassNode;
import java.util.List;
import java.util.regex.Pattern;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertThat;
public class TestConditions3 extends InternalJadxTest {
public static class TestCls {
private static final Pattern PATTERN = Pattern.compile("[a-f0-9]{20}");
public static Object test(final A a) {
List<String> list = a.getList();
if (list == null) {
return null;
}
if (list.size() != 1) {
return null;
}
String s = list.get(0);
if (isEmpty(s)) {
return null;
}
if (isDigitsOnly(s)) {
return new A().set(s);
}
if (PATTERN.matcher(s).matches()) {
return new A().set(s);
}
return null;
}
private static boolean isDigitsOnly(String s) {
return false;
}
private static boolean isEmpty(String s) {
return false;
}
private static class A {
public Object set(String s) {
return null;
}
public List<String> getList() {
return null;
}
}
}
@Test
public void test() {
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();
System.out.println(code);
assertThat(code, containsString("return null;"));
assertThat(code, not(containsString("else")));
// TODO: fix constant inline
// assertThat(code, not(containsString("AnonymousClass_1")));
}
}
package jadx.tests.internal.conditions;
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.assertThat;
public class TestConditions4 extends InternalJadxTest {
public static class TestCls {
public int test(int num) {
boolean inRange = (num >= 59 && num <= 66);
return inRange ? num + 1 : num;
}
}
@Test
public void test() {
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();
System.out.println(code);
assertThat(code, containsString("num >= 59 && num <= 66"));
assertThat(code, containsString("return inRange ? num + 1 : num;"));
assertThat(code, not(containsString("else")));
}
}
package jadx.tests.internal.conditions;
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.assertThat;
public class TestConditions5 extends InternalJadxTest {
public static class TestCls {
public static void assertEquals(Object a1, Object a2) {
if (a1 == null) {
if (a2 != null)
throw new AssertionError(a1 + " != " + a2);
} else if (!a1.equals(a2)) {
throw new AssertionError(a1 + " != " + a2);
}
}
}
@Test
public void test() {
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();
System.out.println(code);
assertThat(code, containsString("if (a1 == null) {"));
assertThat(code, containsString("if (a2 != null) {"));
assertThat(code, containsString("throw new AssertionError(a1 + \" != \" + a2);"));
assertThat(code, not(containsString("if (a1.equals(a2)) {")));
assertThat(code, containsString("} else if (!a1.equals(a2)) {"));
}
}
package jadx.tests.internal.inner;
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.assertThat;
public class TestInnerClass3 extends InternalJadxTest {
public static class TestCls {
private String c;
private void setC(String c) {
this.c = c;
}
public class C {
public String c() {
setC("c");
return c;
}
}
}
@Test
public void test() {
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();
System.out.println(code);
assertThat(code, not(containsString("synthetic")));
assertThat(code, not(containsString("access$")));
assertThat(code, not(containsString("x0")));
assertThat(code, containsString("setC(\"c\");"));
}
}
package jadx.samples;
/**
* Failed tests for current jadx version
*/
public class TestConditions extends AbstractTest {
public int test1(int num) {
......
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