core: restore simple indexed loops
This commit is contained in:
@@ -18,6 +18,7 @@ import jadx.core.dex.visitors.ReSugarCode;
|
||||
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.LoopRegionVisitor;
|
||||
import jadx.core.dex.visitors.regions.ProcessVariables;
|
||||
import jadx.core.dex.visitors.regions.RegionMakerVisitor;
|
||||
import jadx.core.dex.visitors.regions.ReturnVisitor;
|
||||
@@ -91,6 +92,7 @@ public class Jadx {
|
||||
passes.add(new MethodInlineVisitor());
|
||||
passes.add(new ClassModifier());
|
||||
passes.add(new PrepareForCodeGen());
|
||||
passes.add(new LoopRegionVisitor());
|
||||
}
|
||||
passes.add(new CodeGen(args));
|
||||
return passes;
|
||||
|
||||
@@ -8,9 +8,9 @@ import jadx.core.dex.instructions.args.InsnArg;
|
||||
import jadx.core.dex.instructions.args.InsnWrapArg;
|
||||
import jadx.core.dex.instructions.args.LiteralArg;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.dex.regions.Compare;
|
||||
import jadx.core.dex.regions.IfCondition;
|
||||
import jadx.core.dex.regions.IfCondition.Mode;
|
||||
import jadx.core.dex.regions.conditions.Compare;
|
||||
import jadx.core.dex.regions.conditions.IfCondition;
|
||||
import jadx.core.dex.regions.conditions.IfCondition.Mode;
|
||||
import jadx.core.utils.ErrorsCounter;
|
||||
import jadx.core.utils.exceptions.CodegenException;
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
|
||||
@@ -58,9 +58,10 @@ public class InsnGen {
|
||||
protected final RootNode root;
|
||||
protected final boolean fallback;
|
||||
|
||||
private enum Flags {
|
||||
protected enum Flags {
|
||||
BODY_ONLY,
|
||||
BODY_ONLY_NOWRAP,
|
||||
INLINE
|
||||
}
|
||||
|
||||
public InsnGen(MethodGen mgen, boolean fallback) {
|
||||
@@ -186,7 +187,7 @@ public class InsnGen {
|
||||
return makeInsn(insn, code, null);
|
||||
}
|
||||
|
||||
private boolean makeInsn(InsnNode insn, CodeWriter code, Flags flag) throws CodegenException {
|
||||
protected boolean makeInsn(InsnNode insn, CodeWriter code, Flags flag) throws CodegenException {
|
||||
try {
|
||||
if (insn.getType() == InsnType.NOP) {
|
||||
return false;
|
||||
@@ -196,13 +197,17 @@ public class InsnGen {
|
||||
state.add(flag);
|
||||
makeInsnBody(code, insn, state);
|
||||
} else {
|
||||
code.startLineWithNum(insn.getSourceLine());
|
||||
if (flag != Flags.INLINE) {
|
||||
code.startLineWithNum(insn.getSourceLine());
|
||||
}
|
||||
if (insn.getResult() != null && insn.getType() != InsnType.ARITH_ONEARG) {
|
||||
assignVar(code, insn);
|
||||
code.add(" = ");
|
||||
}
|
||||
makeInsnBody(code, insn, state);
|
||||
code.add(';');
|
||||
if (flag != Flags.INLINE) {
|
||||
code.add(';');
|
||||
}
|
||||
}
|
||||
} catch (Throwable th) {
|
||||
throw new CodegenException(mth, "Error generate insn: " + insn, th);
|
||||
|
||||
@@ -14,17 +14,20 @@ import jadx.core.dex.nodes.IBlock;
|
||||
import jadx.core.dex.nodes.IContainer;
|
||||
import jadx.core.dex.nodes.IRegion;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.dex.regions.IfCondition;
|
||||
import jadx.core.dex.regions.IfRegion;
|
||||
import jadx.core.dex.regions.LoopRegion;
|
||||
import jadx.core.dex.regions.Region;
|
||||
import jadx.core.dex.regions.SwitchRegion;
|
||||
import jadx.core.dex.regions.SynchronizedRegion;
|
||||
import jadx.core.dex.regions.conditions.IfCondition;
|
||||
import jadx.core.dex.regions.conditions.IfRegion;
|
||||
import jadx.core.dex.regions.loops.IndexLoop;
|
||||
import jadx.core.dex.regions.loops.LoopRegion;
|
||||
import jadx.core.dex.regions.loops.LoopType;
|
||||
import jadx.core.dex.trycatch.CatchAttr;
|
||||
import jadx.core.dex.trycatch.ExceptionHandler;
|
||||
import jadx.core.dex.trycatch.TryCatchBlock;
|
||||
import jadx.core.utils.RegionUtils;
|
||||
import jadx.core.utils.exceptions.CodegenException;
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -92,7 +95,9 @@ public class RegionGen extends InsnGen {
|
||||
|
||||
private void makeSimpleBlock(IBlock block, CodeWriter code) throws CodegenException {
|
||||
for (InsnNode insn : block.getInstructions()) {
|
||||
makeInsn(insn, code);
|
||||
if (!insn.contains(AFlag.SKIP)) {
|
||||
makeInsn(insn, code);
|
||||
}
|
||||
}
|
||||
ForceReturnAttr retAttr = block.get(AType.FORCE_RETURN);
|
||||
if (retAttr != null) {
|
||||
@@ -166,8 +171,24 @@ public class RegionGen extends InsnGen {
|
||||
code.startLine('}');
|
||||
return code;
|
||||
}
|
||||
|
||||
ConditionGen conditionGen = new ConditionGen(this);
|
||||
LoopType type = region.getType();
|
||||
if (type != null) {
|
||||
if (type instanceof IndexLoop) {
|
||||
IndexLoop indexLoop = (IndexLoop) type;
|
||||
code.startLine("for (");
|
||||
makeInsn(indexLoop.getInitInsn(), code, Flags.INLINE);
|
||||
code.add("; ");
|
||||
conditionGen.add(code, condition);
|
||||
code.add("; ");
|
||||
makeInsn(indexLoop.getIncrInsn(), code, Flags.INLINE);
|
||||
code.add(") {");
|
||||
makeRegionIndent(code, region.getBody());
|
||||
code.startLine('}');
|
||||
return code;
|
||||
}
|
||||
throw new JadxRuntimeException("Unknown loop type: " + type.getClass());
|
||||
}
|
||||
if (region.isConditionAtEnd()) {
|
||||
code.startLine("do {");
|
||||
makeRegionIndent(code, region.getBody());
|
||||
|
||||
@@ -23,5 +23,7 @@ public enum AFlag {
|
||||
|
||||
ELSE_IF_CHAIN,
|
||||
|
||||
WRAPPED,
|
||||
|
||||
INCONSISTENT_CODE, // warning about incorrect decompilation
|
||||
}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
package jadx.core.dex.instructions.args;
|
||||
|
||||
import jadx.core.dex.attributes.AFlag;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.utils.InsnUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -76,18 +80,36 @@ public abstract class InsnArg extends Typed {
|
||||
return null;
|
||||
}
|
||||
if (parent == insn) {
|
||||
LOG.debug("Can't wrap instruction info itself: " + insn);
|
||||
LOG.debug("Can't wrap instruction info itself: {}", insn);
|
||||
Thread.dumpStack();
|
||||
return null;
|
||||
}
|
||||
int i = getArgIndex(parent, this);
|
||||
if (i == -1) {
|
||||
return null;
|
||||
}
|
||||
insn.add(AFlag.WRAPPED);
|
||||
InsnArg arg = wrapArg(insn);
|
||||
parent.setArg(i, arg);
|
||||
return arg;
|
||||
}
|
||||
|
||||
public static void updateParentInsn(InsnNode fromInsn, InsnNode toInsn) {
|
||||
List<RegisterArg> args = new ArrayList<RegisterArg>();
|
||||
fromInsn.getRegisterArgs(args);
|
||||
for (RegisterArg reg : args) {
|
||||
reg.setParentInsn(toInsn);
|
||||
}
|
||||
}
|
||||
|
||||
private static int getArgIndex(InsnNode parent, InsnArg arg) {
|
||||
int count = parent.getArgsCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (parent.getArg(i) == this) {
|
||||
InsnArg arg = wrapArg(insn);
|
||||
parent.setArg(i, arg);
|
||||
return arg;
|
||||
if (parent.getArg(i) == arg) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static InsnArg wrapArg(InsnNode insn) {
|
||||
|
||||
@@ -5,7 +5,7 @@ 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;
|
||||
import jadx.core.dex.regions.conditions.IfCondition;
|
||||
import jadx.core.utils.InsnUtils;
|
||||
import jadx.core.utils.Utils;
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package jadx.core.dex.regions;
|
||||
package jadx.core.dex.regions.conditions;
|
||||
|
||||
import jadx.core.dex.instructions.IfNode;
|
||||
import jadx.core.dex.instructions.IfOp;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package jadx.core.dex.regions;
|
||||
package jadx.core.dex.regions.conditions;
|
||||
|
||||
import jadx.core.dex.instructions.IfNode;
|
||||
import jadx.core.dex.instructions.IfOp;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package jadx.core.dex.regions;
|
||||
package jadx.core.dex.regions.conditions;
|
||||
|
||||
import jadx.core.dex.nodes.BlockNode;
|
||||
|
||||
+3
-2
@@ -1,8 +1,9 @@
|
||||
package jadx.core.dex.regions;
|
||||
package jadx.core.dex.regions.conditions;
|
||||
|
||||
import jadx.core.dex.nodes.BlockNode;
|
||||
import jadx.core.dex.nodes.IContainer;
|
||||
import jadx.core.dex.nodes.IRegion;
|
||||
import jadx.core.dex.regions.AbstractRegion;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -77,7 +78,7 @@ public final class IfRegion extends AbstractRegion {
|
||||
|
||||
@Override
|
||||
public List<IContainer> getSubBlocks() {
|
||||
ArrayList<IContainer> all = new ArrayList<IContainer>(3);
|
||||
List<IContainer> all = new ArrayList<IContainer>(3);
|
||||
all.add(header);
|
||||
if (thenRegion != null) {
|
||||
all.add(thenRegion);
|
||||
@@ -0,0 +1,22 @@
|
||||
package jadx.core.dex.regions.loops;
|
||||
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
|
||||
public class IndexLoop extends LoopType {
|
||||
|
||||
private final InsnNode initInsn;
|
||||
private final InsnNode incrInsn;
|
||||
|
||||
public IndexLoop(InsnNode initInsn, InsnNode incrInsn) {
|
||||
this.initInsn = initInsn;
|
||||
this.incrInsn = incrInsn;
|
||||
}
|
||||
|
||||
public InsnNode getInitInsn() {
|
||||
return initInsn;
|
||||
}
|
||||
|
||||
public InsnNode getIncrInsn() {
|
||||
return incrInsn;
|
||||
}
|
||||
}
|
||||
+14
-1
@@ -1,4 +1,4 @@
|
||||
package jadx.core.dex.regions;
|
||||
package jadx.core.dex.regions.loops;
|
||||
|
||||
import jadx.core.dex.instructions.IfNode;
|
||||
import jadx.core.dex.instructions.args.RegisterArg;
|
||||
@@ -6,6 +6,8 @@ import jadx.core.dex.nodes.BlockNode;
|
||||
import jadx.core.dex.nodes.IContainer;
|
||||
import jadx.core.dex.nodes.IRegion;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.dex.regions.AbstractRegion;
|
||||
import jadx.core.dex.regions.conditions.IfCondition;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -21,6 +23,8 @@ public final class LoopRegion extends AbstractRegion {
|
||||
private IContainer body;
|
||||
private final boolean conditionAtEnd;
|
||||
|
||||
private LoopType type;
|
||||
|
||||
public LoopRegion(IRegion parent, BlockNode header, boolean reversed) {
|
||||
super(parent);
|
||||
this.conditionBlock = header;
|
||||
@@ -116,6 +120,15 @@ public final class LoopRegion extends AbstractRegion {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public LoopType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(LoopType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IContainer> getSubBlocks() {
|
||||
List<IContainer> all = new ArrayList<IContainer>(3);
|
||||
@@ -0,0 +1,4 @@
|
||||
package jadx.core.dex.regions.loops;
|
||||
|
||||
public abstract class LoopType {
|
||||
}
|
||||
@@ -214,6 +214,7 @@ public class CodeShrinker extends AbstractVisitor {
|
||||
// another block
|
||||
BlockNode assignBlock = BlockUtils.getBlockByInsn(mth, assignInsn);
|
||||
if (assignBlock != null
|
||||
&& assignInsn != arg.getParentInsn()
|
||||
&& canMoveBetweenBlocks(assignInsn, assignBlock, block, argsInfo.getInsn())) {
|
||||
arg.wrapInstruction(assignInsn);
|
||||
InsnList.remove(assignBlock, assignInsn);
|
||||
|
||||
@@ -141,6 +141,7 @@ public class PrepareForCodeGen extends AbstractVisitor {
|
||||
}
|
||||
if (replace) {
|
||||
ArithNode newArith = new ArithNode(arith.getOp(), res, arith.getArg(1));
|
||||
InsnArg.updateParentInsn(arith, newArith);
|
||||
list.set(i, newArith);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import jadx.core.dex.instructions.mods.TernaryInsn;
|
||||
import jadx.core.dex.nodes.BlockNode;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
import jadx.core.dex.regions.IfCondition;
|
||||
import jadx.core.dex.regions.conditions.IfCondition;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
@@ -6,7 +6,7 @@ import jadx.core.dex.nodes.BlockNode;
|
||||
import jadx.core.dex.nodes.IBlock;
|
||||
import jadx.core.dex.nodes.IRegion;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
import jadx.core.dex.regions.LoopRegion;
|
||||
import jadx.core.dex.regions.loops.LoopRegion;
|
||||
import jadx.core.dex.visitors.AbstractVisitor;
|
||||
import jadx.core.utils.ErrorsCounter;
|
||||
import jadx.core.utils.exceptions.JadxException;
|
||||
|
||||
@@ -9,9 +9,9 @@ import jadx.core.dex.instructions.args.RegisterArg;
|
||||
import jadx.core.dex.nodes.BlockNode;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
import jadx.core.dex.regions.IfCondition;
|
||||
import jadx.core.dex.regions.IfCondition.Mode;
|
||||
import jadx.core.dex.regions.IfInfo;
|
||||
import jadx.core.dex.regions.conditions.IfCondition;
|
||||
import jadx.core.dex.regions.conditions.IfCondition.Mode;
|
||||
import jadx.core.dex.regions.conditions.IfInfo;
|
||||
import jadx.core.utils.BlockUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@@ -6,9 +6,9 @@ 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.IfCondition.Mode;
|
||||
import jadx.core.dex.regions.IfRegion;
|
||||
import jadx.core.dex.regions.conditions.IfCondition;
|
||||
import jadx.core.dex.regions.conditions.IfCondition.Mode;
|
||||
import jadx.core.dex.regions.conditions.IfRegion;
|
||||
import jadx.core.dex.regions.Region;
|
||||
import jadx.core.dex.visitors.AbstractVisitor;
|
||||
import jadx.core.utils.RegionUtils;
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
package jadx.core.dex.visitors.regions;
|
||||
|
||||
import jadx.core.dex.attributes.AFlag;
|
||||
import jadx.core.dex.instructions.PhiInsn;
|
||||
import jadx.core.dex.instructions.args.RegisterArg;
|
||||
import jadx.core.dex.nodes.BlockNode;
|
||||
import jadx.core.dex.nodes.IBlock;
|
||||
import jadx.core.dex.nodes.IRegion;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
import jadx.core.dex.regions.conditions.IfCondition;
|
||||
import jadx.core.dex.regions.loops.IndexLoop;
|
||||
import jadx.core.dex.regions.loops.LoopRegion;
|
||||
import jadx.core.dex.visitors.AbstractVisitor;
|
||||
import jadx.core.utils.BlockUtils;
|
||||
import jadx.core.utils.RegionUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class LoopRegionVisitor extends AbstractVisitor implements IRegionVisitor {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(LoopRegionVisitor.class);
|
||||
|
||||
@Override
|
||||
public void visit(MethodNode mth) {
|
||||
DepthRegionTraversal.traverseAll(mth, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterRegion(MethodNode mth, IRegion region) {
|
||||
if (region instanceof LoopRegion) {
|
||||
processLoopRegion(mth, (LoopRegion) region);
|
||||
}
|
||||
}
|
||||
|
||||
private static void processLoopRegion(MethodNode mth, LoopRegion loopRegion) {
|
||||
if (loopRegion.isConditionAtEnd()) {
|
||||
return;
|
||||
}
|
||||
IfCondition condition = loopRegion.getCondition();
|
||||
if (condition == null) {
|
||||
return;
|
||||
}
|
||||
List<RegisterArg> args = condition.getRegisterArgs();
|
||||
if (checkForIndexedLoop(mth, loopRegion, args)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for indexed loop.
|
||||
*/
|
||||
private static boolean checkForIndexedLoop(MethodNode mth, LoopRegion loopRegion, List<RegisterArg> condArgs) {
|
||||
InsnNode incrInsn = RegionUtils.getLastInsn(loopRegion);
|
||||
if (incrInsn == null) {
|
||||
return false;
|
||||
}
|
||||
RegisterArg incrArg = incrInsn.getResult();
|
||||
if (incrArg == null
|
||||
|| incrArg.getSVar() == null
|
||||
|| !incrArg.getSVar().isUsedInPhi()) {
|
||||
return false;
|
||||
}
|
||||
PhiInsn phiInsn = incrArg.getSVar().getUsedInPhi();
|
||||
if (phiInsn.getArgsCount() != 2
|
||||
|| !phiInsn.getArg(1).equals(incrArg)
|
||||
|| incrArg.getSVar().getUseCount() != 1) {
|
||||
return false;
|
||||
}
|
||||
RegisterArg arg = phiInsn.getResult();
|
||||
if (!condArgs.contains(arg) || arg.getSVar().isUsedInPhi()) {
|
||||
return false;
|
||||
}
|
||||
RegisterArg initArg = phiInsn.getArg(0);
|
||||
InsnNode initInsn = initArg.getAssignInsn();
|
||||
if (initInsn == null || initArg.getSVar().getUseCount() != 1) {
|
||||
return false;
|
||||
}
|
||||
if (!usedOnlyInLoop(mth, loopRegion, arg)) {
|
||||
return false;
|
||||
}
|
||||
initInsn.add(AFlag.SKIP);
|
||||
incrInsn.add(AFlag.SKIP);
|
||||
loopRegion.setType(new IndexLoop(initInsn, incrInsn));
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean usedOnlyInLoop(MethodNode mth, LoopRegion loopRegion, RegisterArg arg) {
|
||||
List<RegisterArg> useList = arg.getSVar().getUseList();
|
||||
for (RegisterArg useArg : useList) {
|
||||
if (!argInLoop(mth, loopRegion, useArg)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean argInLoop(MethodNode mth, LoopRegion loopRegion, RegisterArg arg) {
|
||||
InsnNode parentInsn = arg.getParentInsn();
|
||||
if (parentInsn == null) {
|
||||
return false;
|
||||
}
|
||||
BlockNode block = BlockUtils.getBlockByInsn(mth, parentInsn);
|
||||
if (block == null) {
|
||||
LOG.debug("Instruction not found: {}, mth: {}", parentInsn, mth);
|
||||
return false;
|
||||
}
|
||||
return RegionUtils.isRegionContainsBlock(loopRegion, block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void leaveRegion(MethodNode mth, IRegion region) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processBlock(MethodNode mth, IBlock container) {
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ 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.conditions.IfRegion;
|
||||
import jadx.core.dex.regions.SwitchRegion;
|
||||
import jadx.core.dex.visitors.AbstractVisitor;
|
||||
import jadx.core.utils.RegionUtils;
|
||||
|
||||
@@ -13,9 +13,9 @@ import jadx.core.dex.nodes.Edge;
|
||||
import jadx.core.dex.nodes.IRegion;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
import jadx.core.dex.regions.IfInfo;
|
||||
import jadx.core.dex.regions.IfRegion;
|
||||
import jadx.core.dex.regions.LoopRegion;
|
||||
import jadx.core.dex.regions.conditions.IfInfo;
|
||||
import jadx.core.dex.regions.conditions.IfRegion;
|
||||
import jadx.core.dex.regions.loops.LoopRegion;
|
||||
import jadx.core.dex.regions.Region;
|
||||
import jadx.core.dex.regions.SwitchRegion;
|
||||
import jadx.core.dex.regions.SynchronizedRegion;
|
||||
|
||||
@@ -4,7 +4,7 @@ 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.LoopRegion;
|
||||
import jadx.core.dex.regions.loops.LoopRegion;
|
||||
import jadx.core.dex.regions.Region;
|
||||
import jadx.core.dex.regions.SynchronizedRegion;
|
||||
import jadx.core.dex.visitors.AbstractVisitor;
|
||||
|
||||
@@ -8,8 +8,8 @@ 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.conditions.IfRegion;
|
||||
import jadx.core.dex.regions.loops.LoopRegion;
|
||||
import jadx.core.dex.regions.SwitchRegion;
|
||||
import jadx.core.dex.visitors.AbstractVisitor;
|
||||
import jadx.core.utils.exceptions.JadxException;
|
||||
|
||||
@@ -12,7 +12,7 @@ import jadx.core.dex.nodes.BlockNode;
|
||||
import jadx.core.dex.nodes.IContainer;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
import jadx.core.dex.regions.IfRegion;
|
||||
import jadx.core.dex.regions.conditions.IfRegion;
|
||||
import jadx.core.dex.regions.Region;
|
||||
import jadx.core.dex.visitors.CodeShrinker;
|
||||
import jadx.core.utils.InsnList;
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package jadx.core.utils;
|
||||
|
||||
import jadx.core.dex.attributes.AFlag;
|
||||
import jadx.core.dex.attributes.AType;
|
||||
import jadx.core.dex.instructions.InsnType;
|
||||
import jadx.core.dex.instructions.args.InsnArg;
|
||||
import jadx.core.dex.instructions.args.InsnWrapArg;
|
||||
import jadx.core.dex.nodes.BlockNode;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
@@ -113,7 +116,9 @@ public class BlockUtils {
|
||||
}
|
||||
|
||||
public static BlockNode getBlockByInsn(MethodNode mth, InsnNode insn) {
|
||||
assert insn != null;
|
||||
if (insn.contains(AFlag.WRAPPED)) {
|
||||
return getBlockByWrappedInsn(mth, insn);
|
||||
}
|
||||
for (BlockNode bn : mth.getBasicBlocks()) {
|
||||
if (blockContains(bn, insn)) {
|
||||
return bn;
|
||||
@@ -122,6 +127,29 @@ public class BlockUtils {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static BlockNode getBlockByWrappedInsn(MethodNode mth, InsnNode insn) {
|
||||
for (BlockNode bn : mth.getBasicBlocks()) {
|
||||
for (InsnNode bi : bn.getInstructions()) {
|
||||
if (bi == insn || foundWrappedInsn(bi, insn)) {
|
||||
return bn;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean foundWrappedInsn(InsnNode container, InsnNode insn) {
|
||||
for (InsnArg arg : container.getArguments()) {
|
||||
if (arg.isInsnWrap()) {
|
||||
InsnNode wrapInsn = ((InsnWrapArg) arg).getWrapInsn();
|
||||
if (wrapInsn == insn || foundWrappedInsn(wrapInsn, insn)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static BitSet blocksToBitSet(MethodNode mth, List<BlockNode> blocks) {
|
||||
BitSet bs = new BitSet(mth.getBasicBlocks().size());
|
||||
for (BlockNode block : blocks) {
|
||||
|
||||
@@ -6,6 +6,9 @@ import jadx.core.dex.instructions.InsnType;
|
||||
import jadx.core.dex.nodes.BlockNode;
|
||||
import jadx.core.dex.nodes.IContainer;
|
||||
import jadx.core.dex.nodes.IRegion;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.dex.regions.SwitchRegion;
|
||||
import jadx.core.dex.regions.conditions.IfRegion;
|
||||
import jadx.core.dex.trycatch.CatchAttr;
|
||||
import jadx.core.dex.trycatch.ExceptionHandler;
|
||||
import jadx.core.dex.trycatch.TryCatchBlock;
|
||||
@@ -35,6 +38,29 @@ public class RegionUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static InsnNode getLastInsn(IContainer container) {
|
||||
if (container instanceof BlockNode) {
|
||||
BlockNode block = (BlockNode) container;
|
||||
List<InsnNode> insnList = block.getInstructions();
|
||||
if (insnList.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return insnList.get(insnList.size() - 1);
|
||||
} else if (container instanceof IfRegion
|
||||
|| container instanceof SwitchRegion) {
|
||||
return null;
|
||||
} else if (container instanceof IRegion) {
|
||||
IRegion region = (IRegion) container;
|
||||
List<IContainer> blocks = region.getSubBlocks();
|
||||
if (blocks.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return getLastInsn(blocks.get(blocks.size() - 1));
|
||||
} else {
|
||||
throw new JadxRuntimeException("Unknown container type: " + container.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if last block in region has no successors
|
||||
*/
|
||||
|
||||
@@ -5,15 +5,15 @@ import jadx.core.dex.instructions.IfOp;
|
||||
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.regions.Compare;
|
||||
import jadx.core.dex.regions.IfCondition;
|
||||
import jadx.core.dex.regions.conditions.Compare;
|
||||
import jadx.core.dex.regions.conditions.IfCondition;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static jadx.core.dex.regions.IfCondition.Mode;
|
||||
import static jadx.core.dex.regions.IfCondition.merge;
|
||||
import static jadx.core.dex.regions.IfCondition.not;
|
||||
import static jadx.core.dex.regions.IfCondition.simplify;
|
||||
import static jadx.core.dex.regions.conditions.IfCondition.Mode;
|
||||
import static jadx.core.dex.regions.conditions.IfCondition.merge;
|
||||
import static jadx.core.dex.regions.conditions.IfCondition.not;
|
||||
import static jadx.core.dex.regions.conditions.IfCondition.simplify;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class TestIfCondition {
|
||||
|
||||
@@ -5,7 +5,7 @@ import jadx.core.dex.nodes.ClassNode;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static jadx.tests.utils.JadxMatchers.containsOne;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class TestInline2 extends InternalJadxTest {
|
||||
@@ -30,9 +30,7 @@ public class TestInline2 extends InternalJadxTest {
|
||||
String code = cls.getCode().toString();
|
||||
System.out.println(code);
|
||||
|
||||
assertThat(code, containsString("i < a.length"));
|
||||
assertThat(code, containsString("long i2 ="));
|
||||
assertThat(code, containsString("+ i2"));
|
||||
assertThat(code, containsString("i2--;"));
|
||||
assertThat(code, containsOne("for (int i = 0; i < a.length; i++) {"));
|
||||
assertThat(code, containsOne("for (long i2 = (long) b; i2 > 0; i2--) {"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import jadx.core.dex.nodes.ClassNode;
|
||||
import org.junit.Test;
|
||||
|
||||
import static jadx.tests.utils.JadxMatchers.containsOne;
|
||||
import static jadx.tests.utils.JadxMatchers.countString;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class TestBreakInLoop extends InternalJadxTest {
|
||||
@@ -14,13 +15,11 @@ public class TestBreakInLoop extends InternalJadxTest {
|
||||
private int f;
|
||||
|
||||
private void test(int[] a, int b) {
|
||||
int i = 0;
|
||||
while (i < a.length) {
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
a[i]++;
|
||||
if (i < b) {
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
this.f++;
|
||||
}
|
||||
@@ -32,12 +31,12 @@ public class TestBreakInLoop extends InternalJadxTest {
|
||||
String code = cls.getCode().toString();
|
||||
System.out.println(code);
|
||||
|
||||
assertThat(code, containsOne("this.f++;"));
|
||||
assertThat(code, containsOne("for (int i = 0; i < a.length; i++) {"));
|
||||
// assertThat(code, containsOne("a[i]++;"));
|
||||
assertThat(code, containsOne("if (i < b) {"));
|
||||
assertThat(code, containsOne("break;"));
|
||||
assertThat(code, containsOne("i++;"));
|
||||
assertThat(code, containsOne("this.f++;"));
|
||||
|
||||
// assertThat(code, countString(0, "else"));
|
||||
assertThat(code, countString(0, "else"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package jadx.tests.internal.loops;
|
||||
|
||||
import jadx.api.InternalJadxTest;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static jadx.tests.utils.JadxMatchers.containsLines;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class TestIndexForLoop extends InternalJadxTest {
|
||||
|
||||
public static class TestCls {
|
||||
|
||||
private int test(int[] a, int b) {
|
||||
int sum = 0;
|
||||
for (int i = 0; i < b; i++) {
|
||||
sum += a[i];
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
String code = cls.getCode().toString();
|
||||
System.out.println(code);
|
||||
|
||||
assertThat(code, containsLines(2,
|
||||
"int sum = 0;",
|
||||
"for (int i = 0; i < b; i++) {",
|
||||
indent(1) + "sum += a[i];",
|
||||
"}",
|
||||
"return sum;"
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ 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;
|
||||
@@ -33,9 +34,8 @@ public class TestLoopDetection2 extends InternalJadxTest {
|
||||
String code = cls.getCode().toString();
|
||||
System.out.println(code);
|
||||
|
||||
assertThat(code, containsString("while (i < b) {"));
|
||||
assertThat(code, containsString("int c = a + b;"));
|
||||
assertThat(code, containsOne("int c = a + b;"));
|
||||
assertThat(code, containsOne("for (int i = a; i < b; i++) {"));
|
||||
assertThat(code, not(containsString("c_2")));
|
||||
assertThat(code, containsString("i++"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package jadx.tests.internal.loops;
|
||||
|
||||
import jadx.api.InternalJadxTest;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static jadx.tests.utils.JadxMatchers.containsOne;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class TestNestedLoops2 extends InternalJadxTest {
|
||||
|
||||
public static class TestCls {
|
||||
|
||||
private boolean test(List<String> list) {
|
||||
int j = 0;
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
String s = list.get(i);
|
||||
while (j < s.length()) {
|
||||
j++;
|
||||
}
|
||||
}
|
||||
return j > 10;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
String code = cls.getCode().toString();
|
||||
System.out.println(code);
|
||||
|
||||
assertThat(code, containsOne("for (int i = 0; i < list.size(); i++) {"));
|
||||
assertThat(code, containsOne("while (j < ((String) list.get(i)).length()) {"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user