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 {
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;
}
}
......
......@@ -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);
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());
// 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);
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);
}
}
}
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)) {
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);
}
}
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);
}
}
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)) {
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;
}
}
......
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());
}
}
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.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