core: fix issues in variable names and try/catch blocks
This commit is contained in:
@@ -77,9 +77,10 @@ public class MethodGen {
|
||||
|
||||
AccessInfo clsAccFlags = mth.getParentClass().getAccessFlags();
|
||||
AccessInfo ai = mth.getAccessFlags();
|
||||
// don't add 'abstract' to methods in interface
|
||||
// don't add 'abstract' and 'public' to methods in interface
|
||||
if (clsAccFlags.isInterface()) {
|
||||
ai = ai.remove(AccessFlags.ACC_ABSTRACT);
|
||||
ai = ai.remove(AccessFlags.ACC_PUBLIC);
|
||||
}
|
||||
// don't add 'public' for annotations
|
||||
if (clsAccFlags.isAnnotation()) {
|
||||
|
||||
@@ -259,9 +259,9 @@ public class RegionGen extends InsnGen {
|
||||
if (allHandler != null) {
|
||||
makeCatchBlock(code, allHandler);
|
||||
}
|
||||
if (tryCatchBlock.getFinalBlock() != null) {
|
||||
if (tryCatchBlock.getFinalRegion() != null) {
|
||||
code.startLine("} finally {");
|
||||
makeRegionIndent(code, tryCatchBlock.getFinalBlock());
|
||||
makeRegionIndent(code, tryCatchBlock.getFinalRegion());
|
||||
}
|
||||
code.startLine('}');
|
||||
}
|
||||
|
||||
@@ -273,7 +273,7 @@ public class MethodNode extends LineAttrNode implements ILoadable {
|
||||
// each handler must be only in one try/catch block
|
||||
for (TryCatchBlock ct1 : catches) {
|
||||
for (TryCatchBlock ct2 : catches) {
|
||||
if (ct1 != ct2 && ct2.getHandlers().containsAll(ct1.getHandlers())) {
|
||||
if (ct1 != ct2 && ct2.containsAllHandlers(ct1)) {
|
||||
for (ExceptionHandler h : ct1.getHandlers()) {
|
||||
ct2.removeHandler(this, h);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ public class ExceptionHandler {
|
||||
private final ClassInfo catchType;
|
||||
private final int handleOffset;
|
||||
|
||||
private BlockNode handleBlock;
|
||||
private BlockNode handlerBlock;
|
||||
private final List<BlockNode> blocks = new ArrayList<BlockNode>();
|
||||
private IContainer handlerRegion;
|
||||
private NamedArg arg;
|
||||
@@ -39,12 +39,12 @@ public class ExceptionHandler {
|
||||
return handleOffset;
|
||||
}
|
||||
|
||||
public BlockNode getHandleBlock() {
|
||||
return handleBlock;
|
||||
public BlockNode getHandlerBlock() {
|
||||
return handlerBlock;
|
||||
}
|
||||
|
||||
public void setHandleBlock(BlockNode handleBlock) {
|
||||
this.handleBlock = handleBlock;
|
||||
public void setHandlerBlock(BlockNode handlerBlock) {
|
||||
this.handlerBlock = handlerBlock;
|
||||
}
|
||||
|
||||
public List<BlockNode> getBlocks() {
|
||||
|
||||
@@ -12,8 +12,6 @@ import jadx.core.utils.InstructionRemover;
|
||||
import jadx.core.utils.Utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
@@ -21,7 +19,7 @@ import java.util.List;
|
||||
public class TryCatchBlock {
|
||||
|
||||
private final List<ExceptionHandler> handlers;
|
||||
private IContainer finalBlock;
|
||||
private IContainer finalRegion;
|
||||
|
||||
// references for fast remove/modify
|
||||
private final List<InsnNode> insns;
|
||||
@@ -33,8 +31,16 @@ public class TryCatchBlock {
|
||||
attr = new CatchAttr(this);
|
||||
}
|
||||
|
||||
public Collection<ExceptionHandler> getHandlers() {
|
||||
return Collections.unmodifiableCollection(handlers);
|
||||
public Iterable<ExceptionHandler> getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public int getHandlersCount() {
|
||||
return handlers.size();
|
||||
}
|
||||
|
||||
public boolean containsAllHandlers(TryCatchBlock tb) {
|
||||
return handlers.containsAll(tb.handlers);
|
||||
}
|
||||
|
||||
public ExceptionHandler addHandler(MethodNode mth, int addr, ClassInfo type) {
|
||||
@@ -59,7 +65,7 @@ public class TryCatchBlock {
|
||||
}
|
||||
|
||||
private void removeWholeBlock(MethodNode mth) {
|
||||
if (finalBlock != null) {
|
||||
if (finalRegion != null) {
|
||||
// search catch attr
|
||||
for (BlockNode block : mth.getBasicBlocks()) {
|
||||
CatchAttr cb = block.get(AType.CATCH_BLOCK);
|
||||
@@ -67,7 +73,7 @@ public class TryCatchBlock {
|
||||
for (ExceptionHandler eh : mth.getExceptionHandlers()) {
|
||||
if (eh.getBlocks().contains(block)) {
|
||||
TryCatchBlock tb = eh.getTryBlock();
|
||||
tb.setFinalBlockFromInsns(mth, ((IBlock) finalBlock).getInstructions());
|
||||
tb.setFinalRegionFromInsns(mth, ((IBlock) finalRegion).getInstructions());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,17 +108,17 @@ public class TryCatchBlock {
|
||||
return attr;
|
||||
}
|
||||
|
||||
public IContainer getFinalBlock() {
|
||||
return finalBlock;
|
||||
public IContainer getFinalRegion() {
|
||||
return finalRegion;
|
||||
}
|
||||
|
||||
public void setFinalBlock(IContainer finalBlock) {
|
||||
this.finalBlock = finalBlock;
|
||||
public void setFinalRegion(IContainer finalRegion) {
|
||||
this.finalRegion = finalRegion;
|
||||
}
|
||||
|
||||
public void setFinalBlockFromInsns(MethodNode mth, List<InsnNode> insns) {
|
||||
public void setFinalRegionFromInsns(MethodNode mth, List<InsnNode> insns) {
|
||||
List<InsnNode> finalBlockInsns = new ArrayList<InsnNode>(insns);
|
||||
setFinalBlock(new InsnContainer(finalBlockInsns));
|
||||
setFinalRegion(new InsnContainer(finalBlockInsns));
|
||||
|
||||
InstructionRemover.unbindInsnList(mth, finalBlockInsns);
|
||||
|
||||
@@ -135,7 +141,7 @@ public class TryCatchBlock {
|
||||
for (InsnNode insn : tryBlock.getInsns()) {
|
||||
this.addInsn(insn);
|
||||
}
|
||||
this.handlers.addAll(tryBlock.getHandlers());
|
||||
this.handlers.addAll(tryBlock.handlers);
|
||||
for (ExceptionHandler eh : handlers) {
|
||||
eh.setTryBlock(this);
|
||||
}
|
||||
|
||||
@@ -119,8 +119,8 @@ public class BlockMakerVisitor extends AbstractVisitor {
|
||||
List<JumpInfo> jumps = insn.getAll(AType.JUMP);
|
||||
for (JumpInfo jump : jumps) {
|
||||
BlockNode srcBlock = getBlock(jump.getSrc(), blocksMap);
|
||||
BlockNode thisblock = getBlock(jump.getDest(), blocksMap);
|
||||
connect(srcBlock, thisblock);
|
||||
BlockNode thisBlock = getBlock(jump.getDest(), blocksMap);
|
||||
connect(srcBlock, thisBlock);
|
||||
}
|
||||
|
||||
// connect exception handlers
|
||||
|
||||
@@ -137,7 +137,7 @@ public class BlockProcessingHelper {
|
||||
for (BlockNode block : mth.getBasicBlocks()) {
|
||||
ExcHandlerAttr bh = block.get(AType.EXC_HANDLER);
|
||||
if (bh != null && bh.getHandler().getHandleOffset() == addr) {
|
||||
handler.setHandleBlock(block);
|
||||
handler.setHandlerBlock(block);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+29
-27
@@ -119,41 +119,43 @@ public class ProcessTryCatchRegions extends AbstractRegionVisitor {
|
||||
assert tb != null;
|
||||
|
||||
for (IContainer cont : region.getSubBlocks()) {
|
||||
if (RegionUtils.isDominaterBy(dominator, cont)) {
|
||||
boolean pathFromExcHandler = false;
|
||||
for (ExceptionHandler h : tb.getHandlers()) {
|
||||
if (RegionUtils.hasPathThruBlock(h.getHandleBlock(), cont)) {
|
||||
pathFromExcHandler = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!pathFromExcHandler) {
|
||||
newRegion.getSubBlocks().add(cont);
|
||||
} else {
|
||||
if (RegionUtils.isDominatedBy(dominator, cont)) {
|
||||
if (isHandlerPath(tb, cont)) {
|
||||
break;
|
||||
}
|
||||
newRegion.getSubBlocks().add(cont);
|
||||
}
|
||||
}
|
||||
if (!newRegion.getSubBlocks().isEmpty()) {
|
||||
if (DEBUG) {
|
||||
LOG.debug("ProcessTryCatchRegions mark: {}", newRegion);
|
||||
}
|
||||
// replace first node by region
|
||||
IContainer firstNode = newRegion.getSubBlocks().get(0);
|
||||
int i = region.getSubBlocks().indexOf(firstNode);
|
||||
region.getSubBlocks().set(i, newRegion);
|
||||
region.getSubBlocks().removeAll(newRegion.getSubBlocks());
|
||||
if (newRegion.getSubBlocks().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (DEBUG) {
|
||||
LOG.debug("ProcessTryCatchRegions mark: {}", newRegion);
|
||||
}
|
||||
// replace first node by region
|
||||
IContainer firstNode = newRegion.getSubBlocks().get(0);
|
||||
int i = region.getSubBlocks().indexOf(firstNode);
|
||||
region.getSubBlocks().set(i, newRegion);
|
||||
region.getSubBlocks().removeAll(newRegion.getSubBlocks());
|
||||
|
||||
newRegion.addAttr(tb.getCatchAttr());
|
||||
newRegion.addAttr(tb.getCatchAttr());
|
||||
|
||||
// fix parents
|
||||
for (IContainer cont : newRegion.getSubBlocks()) {
|
||||
if (cont instanceof AbstractRegion) {
|
||||
AbstractRegion aReg = (AbstractRegion) cont;
|
||||
aReg.setParent(newRegion);
|
||||
}
|
||||
// fix parents
|
||||
for (IContainer cont : newRegion.getSubBlocks()) {
|
||||
if (cont instanceof AbstractRegion) {
|
||||
AbstractRegion aReg = (AbstractRegion) cont;
|
||||
aReg.setParent(newRegion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isHandlerPath(TryCatchBlock tb, IContainer cont) {
|
||||
for (ExceptionHandler h : tb.getHandlers()) {
|
||||
if (RegionUtils.hasPathThruBlock(h.getHandlerBlock(), cont)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,11 +10,14 @@ 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.SwitchRegion;
|
||||
import jadx.core.dex.visitors.AbstractVisitor;
|
||||
import jadx.core.utils.RegionUtils;
|
||||
import jadx.core.utils.exceptions.JadxException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -137,6 +140,13 @@ public class ProcessVariables extends AbstractVisitor {
|
||||
usageMap.remove(new Variable(arg));
|
||||
}
|
||||
|
||||
if (usageMap.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<IContainer, Integer> regionsOrder = new HashMap<IContainer, Integer>();
|
||||
calculateOrder(mth.getRegion(), regionsOrder, 0, true);
|
||||
|
||||
for (Iterator<Entry<Variable, Usage>> it = usageMap.entrySet().iterator(); it.hasNext(); ) {
|
||||
Entry<Variable, Usage> entry = it.next();
|
||||
Usage u = entry.getValue();
|
||||
@@ -147,10 +157,10 @@ public class ProcessVariables extends AbstractVisitor {
|
||||
continue;
|
||||
}
|
||||
|
||||
// check if we can declare variable at current assigns
|
||||
// check if variable can be declared at current assigns
|
||||
for (IRegion assignRegion : u.getAssigns()) {
|
||||
if (u.getArgRegion() == assignRegion
|
||||
&& canDeclareInRegion(u, assignRegion)) {
|
||||
&& canDeclareInRegion(u, assignRegion, regionsOrder)) {
|
||||
u.getArg().getParentInsn().add(AFlag.DECLARE_VAR);
|
||||
it.remove();
|
||||
break;
|
||||
@@ -178,7 +188,7 @@ public class ProcessVariables extends AbstractVisitor {
|
||||
IRegion parent = region;
|
||||
boolean declare = false;
|
||||
while (parent != null) {
|
||||
if (canDeclareInRegion(u, region)) {
|
||||
if (canDeclareInRegion(u, region, regionsOrder)) {
|
||||
declareVar(region, u.getArg());
|
||||
declare = true;
|
||||
break;
|
||||
@@ -212,13 +222,67 @@ public class ProcessVariables extends AbstractVisitor {
|
||||
dv.addVar(arg);
|
||||
}
|
||||
|
||||
private static boolean canDeclareInRegion(Usage u, IRegion region) {
|
||||
for (IRegion r : u.getAssigns()) {
|
||||
if (!RegionUtils.isRegionContainsRegion(region, r)) {
|
||||
return false;
|
||||
private static int calculateOrder(IContainer container, Map<IContainer, Integer> regionsOrder,
|
||||
int id, boolean inc) {
|
||||
if (!(container instanceof IRegion)) {
|
||||
return id;
|
||||
}
|
||||
IRegion region = (IRegion) container;
|
||||
Integer previous = regionsOrder.put(region, id);
|
||||
if (previous != null) {
|
||||
return id;
|
||||
}
|
||||
for (IContainer c : region.getSubBlocks()) {
|
||||
if (c instanceof IfRegion
|
||||
|| c instanceof SwitchRegion) {
|
||||
// on branch set for all inner regions same order id
|
||||
id = calculateOrder(c, regionsOrder, inc ? id + 1 : id, false);
|
||||
} else {
|
||||
List<IContainer> handlers = RegionUtils.getExcHandlersForRegion(c);
|
||||
if (!handlers.isEmpty()) {
|
||||
for (IContainer handler : handlers) {
|
||||
id = calculateOrder(handler, regionsOrder, inc ? id + 1 : id, inc);
|
||||
}
|
||||
}
|
||||
id = calculateOrder(c, regionsOrder, inc ? id + 1 : id, inc);
|
||||
}
|
||||
}
|
||||
for (IRegion r : u.getUseRegions()) {
|
||||
return id;
|
||||
}
|
||||
|
||||
private static boolean canDeclareInRegion(Usage u, IRegion region, Map<IContainer, Integer> regionsOrder) {
|
||||
Integer pos = regionsOrder.get(region);
|
||||
if (pos == null) {
|
||||
LOG.debug("TODO: Not found order for region {} for {}", region, u);
|
||||
return false;
|
||||
}
|
||||
return isAllRegionsAfter(region, pos, u.getAssigns(), regionsOrder)
|
||||
&& isAllRegionsAfter(region, pos, u.getUseRegions(), regionsOrder);
|
||||
}
|
||||
|
||||
private static boolean isAllRegionsAfter(IRegion region, Integer pos,
|
||||
Set<IRegion> regions, Map<IContainer, Integer> regionsOrder) {
|
||||
for (IRegion r : regions) {
|
||||
if (r == region) {
|
||||
continue;
|
||||
}
|
||||
Integer rPos = regionsOrder.get(r);
|
||||
if (rPos == null) {
|
||||
LOG.debug("TODO: Not found order for region {} in {}", r, regionsOrder);
|
||||
return false;
|
||||
}
|
||||
if (pos > rPos) {
|
||||
return false;
|
||||
}
|
||||
if (pos.equals(rPos)) {
|
||||
return isAllRegionsAfterRecursive(region, regions);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isAllRegionsAfterRecursive(IRegion region, Set<IRegion> others) {
|
||||
for (IRegion r : others) {
|
||||
if (!RegionUtils.isRegionContainsRegion(region, r)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import jadx.core.dex.regions.SwitchRegion;
|
||||
import jadx.core.dex.regions.SynchronizedRegion;
|
||||
import jadx.core.dex.trycatch.ExcHandlerAttr;
|
||||
import jadx.core.dex.trycatch.ExceptionHandler;
|
||||
import jadx.core.dex.trycatch.TryCatchBlock;
|
||||
import jadx.core.utils.BlockUtils;
|
||||
import jadx.core.utils.ErrorsCounter;
|
||||
import jadx.core.utils.InstructionRemover;
|
||||
@@ -410,7 +411,7 @@ public class RegionMaker {
|
||||
ifRegion.setCondition(mergedIf.getCondition());
|
||||
thenBlock = mergedIf.getThenBlock();
|
||||
elseBlock = mergedIf.getElseBlock();
|
||||
out = BlockUtils.getPathCrossBlockFor(mth, thenBlock, elseBlock);
|
||||
out = BlockUtils.getPathCross(mth, thenBlock, elseBlock);
|
||||
} else {
|
||||
// invert condition (compiler often do it)
|
||||
ifnode.invertCondition();
|
||||
@@ -432,7 +433,7 @@ public class RegionMaker {
|
||||
} else if (block.getDominatesOn().size() == 2) {
|
||||
thenBlock = bThen;
|
||||
elseBlock = bElse;
|
||||
out = BlockUtils.getPathCrossBlockFor(mth, bThen, bElse);
|
||||
out = BlockUtils.getPathCross(mth, bThen, bElse);
|
||||
} else if (bElse.getPredecessors().size() != 1) {
|
||||
thenBlock = bThen;
|
||||
elseBlock = null;
|
||||
@@ -679,14 +680,54 @@ public class RegionMaker {
|
||||
return out;
|
||||
}
|
||||
|
||||
public void processExcHandler(ExceptionHandler handler, RegionStack stack) {
|
||||
BlockNode start = handler.getHandleBlock();
|
||||
public void processTryCatchBlocks(MethodNode mth) {
|
||||
Set<TryCatchBlock> tcs = new HashSet<TryCatchBlock>();
|
||||
for (ExceptionHandler handler : mth.getExceptionHandlers()) {
|
||||
tcs.add(handler.getTryBlock());
|
||||
}
|
||||
for (TryCatchBlock tc : tcs) {
|
||||
List<BlockNode> blocks = new ArrayList<BlockNode>(tc.getHandlersCount());
|
||||
Set<BlockNode> splitters = new HashSet<BlockNode>();
|
||||
for (ExceptionHandler handler : tc.getHandlers()) {
|
||||
BlockNode handlerBlock = handler.getHandlerBlock();
|
||||
if (handlerBlock != null) {
|
||||
blocks.add(handlerBlock);
|
||||
splitters.addAll(handlerBlock.getPredecessors());
|
||||
} else {
|
||||
LOG.debug(ErrorsCounter.formatErrorMsg(mth, "No exception handler block: " + handler));
|
||||
}
|
||||
}
|
||||
Set<BlockNode> exits = new HashSet<BlockNode>();
|
||||
for (BlockNode splitter : splitters) {
|
||||
for (BlockNode handler : blocks) {
|
||||
List<BlockNode> s = splitter.getCleanSuccessors();
|
||||
if (s.isEmpty()) {
|
||||
LOG.debug(ErrorsCounter.formatErrorMsg(mth, "No successors for splitter: " + splitter));
|
||||
continue;
|
||||
}
|
||||
BlockNode cross = BlockUtils.getPathCross(mth, s.get(0), handler);
|
||||
if (cross != null) {
|
||||
exits.add(cross);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (ExceptionHandler handler : tc.getHandlers()) {
|
||||
processExcHandler(handler, exits);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processExcHandler(ExceptionHandler handler, Set<BlockNode> exits) {
|
||||
BlockNode start = handler.getHandlerBlock();
|
||||
if (start == null) {
|
||||
LOG.debug(ErrorsCounter.formatErrorMsg(mth, "No exception handler block: " + handler));
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO extract finally part which exists in all handlers from same try block
|
||||
// TODO add blocks common for several handlers to some region
|
||||
|
||||
RegionStack stack = new RegionStack(mth);
|
||||
stack.addExits(exits);
|
||||
handler.setHandlerRegion(makeRegion(start, stack));
|
||||
|
||||
ExcHandlerAttr excHandlerAttr = start.get(AType.EXC_HANDLER);
|
||||
|
||||
@@ -7,7 +7,6 @@ import jadx.core.dex.nodes.MethodNode;
|
||||
import jadx.core.dex.regions.LoopRegion;
|
||||
import jadx.core.dex.regions.Region;
|
||||
import jadx.core.dex.regions.SynchronizedRegion;
|
||||
import jadx.core.dex.trycatch.ExceptionHandler;
|
||||
import jadx.core.dex.visitors.AbstractVisitor;
|
||||
import jadx.core.utils.InstructionRemover;
|
||||
import jadx.core.utils.exceptions.JadxException;
|
||||
@@ -35,10 +34,7 @@ public class RegionMakerVisitor extends AbstractVisitor {
|
||||
mth.setRegion(rm.makeRegion(mth.getEnterBlock(), state));
|
||||
|
||||
if (!mth.isNoExceptionHandlers()) {
|
||||
state = new RegionStack(mth);
|
||||
for (ExceptionHandler handler : mth.getExceptionHandlers()) {
|
||||
rm.processExcHandler(handler, state);
|
||||
}
|
||||
rm.processTryCatchBlocks(mth);
|
||||
}
|
||||
|
||||
postProcessRegions(mth);
|
||||
|
||||
@@ -5,6 +5,7 @@ import jadx.core.dex.nodes.IRegion;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Collection;
|
||||
import java.util.Deque;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
@@ -85,6 +86,12 @@ final class RegionStack {
|
||||
}
|
||||
}
|
||||
|
||||
public void addExits(Collection<BlockNode> exits) {
|
||||
for (BlockNode exit : exits) {
|
||||
addExit(exit);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean containsExit(BlockNode exit) {
|
||||
return curState.exits.contains(exit);
|
||||
}
|
||||
|
||||
@@ -245,7 +245,7 @@ public class BlockUtils {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static BlockNode getPathCrossBlockFor(MethodNode mth, BlockNode b1, BlockNode b2) {
|
||||
public static BlockNode getPathCross(MethodNode mth, BlockNode b1, BlockNode b2) {
|
||||
if (b1 == null || b2 == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ import jadx.core.dex.trycatch.ExceptionHandler;
|
||||
import jadx.core.dex.trycatch.TryCatchBlock;
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -111,6 +113,19 @@ public class RegionUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static List<IContainer> getExcHandlersForRegion(IContainer region) {
|
||||
CatchAttr cb = region.get(AType.CATCH_BLOCK);
|
||||
if (cb != null) {
|
||||
TryCatchBlock tb = cb.getTryBlock();
|
||||
List<IContainer> list = new ArrayList<IContainer>(tb.getHandlersCount());
|
||||
for (ExceptionHandler eh : tb.getHandlers()) {
|
||||
list.add(eh.getHandlerRegion());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private static boolean isRegionContainsExcHandlerRegion(IContainer container, IRegion region) {
|
||||
if (container == region) {
|
||||
return true;
|
||||
@@ -129,8 +144,8 @@ public class RegionUtils {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (tb.getFinalBlock() != null
|
||||
&& isRegionContainsRegion(tb.getFinalBlock(), region)) {
|
||||
if (tb.getFinalRegion() != null
|
||||
&& isRegionContainsRegion(tb.getFinalRegion(), region)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -169,7 +184,7 @@ public class RegionUtils {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean isDominaterBy(BlockNode dom, IContainer cont) {
|
||||
public static boolean isDominatedBy(BlockNode dom, IContainer cont) {
|
||||
if (dom == cont) {
|
||||
return true;
|
||||
}
|
||||
@@ -179,7 +194,7 @@ public class RegionUtils {
|
||||
} else if (cont instanceof IRegion) {
|
||||
IRegion region = (IRegion) cont;
|
||||
for (IContainer c : region.getSubBlocks()) {
|
||||
if (!isDominaterBy(dom, c)) {
|
||||
if (!isDominatedBy(dom, c)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package jadx.tests.internal;
|
||||
|
||||
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 TestClassGen extends InternalJadxTest {
|
||||
|
||||
public static class TestCls {
|
||||
public static interface I {
|
||||
int test();
|
||||
|
||||
public int test3();
|
||||
}
|
||||
|
||||
public static abstract class A {
|
||||
public abstract int test2();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
String code = cls.getCode().toString();
|
||||
System.out.println(code);
|
||||
|
||||
assertThat(code, containsString("public static interface I {"));
|
||||
assertThat(code, containsString(indent(2) + "int test();"));
|
||||
assertThat(code, not(containsString("public int test();")));
|
||||
assertThat(code, containsString(indent(2) + "int test3();"));
|
||||
|
||||
assertThat(code, containsString("public static abstract class A {"));
|
||||
assertThat(code, containsString(indent(2) + "public abstract int test2();"));
|
||||
}
|
||||
}
|
||||
@@ -12,10 +12,16 @@ import static org.junit.Assert.assertThat;
|
||||
public class TestWrongCode extends InternalJadxTest {
|
||||
|
||||
public static class TestCls {
|
||||
private int f() {
|
||||
private int test() {
|
||||
int[] a = null;
|
||||
return a.length;
|
||||
}
|
||||
|
||||
@SuppressWarnings("empty")
|
||||
private int test2(int a) {
|
||||
if (a == 0);
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -26,5 +32,7 @@ public class TestWrongCode extends InternalJadxTest {
|
||||
|
||||
assertThat(code, not(containsString("return false.length;")));
|
||||
assertThat(code, containsString("return null.length;"));
|
||||
|
||||
assertThat(code, containsString("return a == 0 ? a : a;"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ public class TestLineNumbers2 extends InternalJadxTest {
|
||||
System.out.println(code);
|
||||
|
||||
Map<Integer, Integer> lineMapping = codeWriter.getLineMapping();
|
||||
assertEquals("{8=18, 11=22, 13=23, 14=24, 15=28, 17=25, 18=26, 19=28, 22=31, 23=32}",
|
||||
assertEquals("{8=18, 11=22, 12=23, 13=24, 14=28, 16=25, 17=26, 18=28, 21=31, 22=32}",
|
||||
lineMapping.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package jadx.tests.internal.trycatch;
|
||||
|
||||
import jadx.api.InternalJadxTest;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class TestTryCatch5 extends InternalJadxTest {
|
||||
|
||||
public static class TestCls {
|
||||
private Object test(Object obj) {
|
||||
File file = new File("r");
|
||||
FileOutputStream output = null;
|
||||
try {
|
||||
output = new FileOutputStream(file);
|
||||
if (obj.equals("a")) {
|
||||
return new Object();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
System.out.println("Exception");
|
||||
return null;
|
||||
} finally {
|
||||
if (output != null) {
|
||||
try {
|
||||
output.close();
|
||||
} catch (IOException e) {
|
||||
// Ignored
|
||||
}
|
||||
}
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
String code = cls.getCode().toString();
|
||||
System.out.println(code);
|
||||
|
||||
assertThat(code, containsString("try {"));
|
||||
// TODO:
|
||||
// assertThat(code, containsString("output = new FileOutputStream(file);"));
|
||||
// assertThat(code, containsString("} catch (IOException e) {"));
|
||||
assertThat(code, containsString("file.delete();"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package jadx.tests.internal.variables;
|
||||
|
||||
import jadx.api.InternalJadxTest;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class TestVariables2 extends InternalJadxTest {
|
||||
|
||||
public static class TestCls {
|
||||
Object test(Object s) {
|
||||
Object store = s != null ? s : null;
|
||||
if (store == null) {
|
||||
store = new Object();
|
||||
s = store;
|
||||
}
|
||||
return store;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
String code = cls.getCode().toString();
|
||||
System.out.println(code);
|
||||
|
||||
assertThat(code, containsString("Object store = s != null ? s : null;"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package jadx.tests.internal.variables;
|
||||
|
||||
import jadx.api.InternalJadxTest;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class TestVariables3 extends InternalJadxTest {
|
||||
|
||||
public static class TestCls {
|
||||
String test(Object s) {
|
||||
int i;
|
||||
if (s == null) {
|
||||
i = 2;
|
||||
} else {
|
||||
i = 3;
|
||||
s = null;
|
||||
}
|
||||
return s + " " + i;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
String code = cls.getCode().toString();
|
||||
System.out.println(code);
|
||||
|
||||
assertThat(code, containsString("int i;"));
|
||||
assertThat(code, containsString("i = 2;"));
|
||||
assertThat(code, containsString("i = 3;"));
|
||||
assertThat(code, containsString("s = null;"));
|
||||
assertThat(code, containsString("return s + \" \" + i;"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package jadx.tests.internal.variables;
|
||||
|
||||
import jadx.api.InternalJadxTest;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class TestVariables4 extends InternalJadxTest {
|
||||
|
||||
public static class TestCls {
|
||||
private static boolean runTest(String clsName) {
|
||||
try {
|
||||
boolean pass = false;
|
||||
String msg = null;
|
||||
Throwable exc = null;
|
||||
|
||||
Class<?> cls = Class.forName(clsName);
|
||||
if (cls.getSuperclass() == AbstractTest.class) {
|
||||
Method mth = cls.getMethod("testRun");
|
||||
try {
|
||||
AbstractTest test = (AbstractTest) cls.getConstructor().newInstance();
|
||||
pass = (Boolean) mth.invoke(test);
|
||||
} catch (InvocationTargetException e) {
|
||||
pass = false;
|
||||
exc = e.getCause();
|
||||
} catch (Throwable e) {
|
||||
pass = false;
|
||||
exc = e;
|
||||
}
|
||||
} else {
|
||||
msg = "not extends AbstractTest";
|
||||
}
|
||||
System.err.println(">> "
|
||||
+ (pass ? "PASS" : "FAIL") + "\t"
|
||||
+ clsName
|
||||
+ (msg == null ? "" : "\t - " + msg));
|
||||
if (exc != null) {
|
||||
exc.printStackTrace();
|
||||
}
|
||||
return pass;
|
||||
} catch (ClassNotFoundException e) {
|
||||
System.err.println("Class '" + clsName + "' not found");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static class AbstractTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
String code = cls.getCode().toString();
|
||||
System.out.println(code);
|
||||
|
||||
assertThat(code, containsString("} catch (InvocationTargetException e) {"));
|
||||
assertThat(code, containsString("pass = false;"));
|
||||
assertThat(code, containsString("exc = e.getCause();"));
|
||||
assertThat(code, containsString("System.err.println(\"Class '\" + clsName + \"' not found\");"));
|
||||
assertThat(code, containsString("return pass;"));
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package jadx.tests.internal;
|
||||
package jadx.tests.internal.variables;
|
||||
|
||||
import jadx.api.InternalJadxTest;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
Reference in New Issue
Block a user