Commit b940b99e authored by Skylot's avatar Skylot

core: fix issues in variable names and try/catch blocks

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