@@ -146,7 +146,7 @@ public class InsnGen {
|
||||
|
||||
private String sfield(FieldInfo field) {
|
||||
String thisClass = mth.getParentClass().getFullName();
|
||||
if (field.getDeclClass().getFullName().equals(thisClass)) {
|
||||
if (thisClass.startsWith(field.getDeclClass().getFullName())) {
|
||||
return field.getName();
|
||||
} else {
|
||||
return useClass(field.getDeclClass()) + '.' + field.getName();
|
||||
|
||||
@@ -5,8 +5,10 @@ import jadx.core.dex.attributes.AttributeType;
|
||||
import jadx.core.dex.attributes.DeclareVariableAttr;
|
||||
import jadx.core.dex.attributes.ForceReturnAttr;
|
||||
import jadx.core.dex.attributes.IAttribute;
|
||||
import jadx.core.dex.info.FieldInfo;
|
||||
import jadx.core.dex.instructions.ArithNode;
|
||||
import jadx.core.dex.instructions.IfOp;
|
||||
import jadx.core.dex.instructions.IndexInsnNode;
|
||||
import jadx.core.dex.instructions.InsnType;
|
||||
import jadx.core.dex.instructions.SwitchNode;
|
||||
import jadx.core.dex.instructions.args.ArgType;
|
||||
@@ -232,15 +234,19 @@ public class RegionGen extends InsnGen {
|
||||
SwitchNode insn = (SwitchNode) sw.getHeader().getInstructions().get(0);
|
||||
InsnArg arg = insn.getArg(0);
|
||||
code.startLine("switch(").add(arg(arg)).add(") {");
|
||||
code.incIndent();
|
||||
|
||||
int size = sw.getKeys().size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
List<Integer> keys = sw.getKeys().get(i);
|
||||
List<Object> keys = sw.getKeys().get(i);
|
||||
IContainer c = sw.getCases().get(i);
|
||||
for (Integer k : keys) {
|
||||
for (Object k : keys) {
|
||||
code.startLine("case ");
|
||||
code.add(TypeGen.literalToString(k, arg.getType()));
|
||||
if (k instanceof IndexInsnNode) {
|
||||
code.add(sfield((FieldInfo) ((IndexInsnNode) k).getIndex()));
|
||||
}
|
||||
else {
|
||||
code.add(TypeGen.literalToString((Integer) k, arg.getType()));
|
||||
}
|
||||
code.add(':');
|
||||
}
|
||||
makeCaseBlock(c, code);
|
||||
@@ -249,13 +255,12 @@ public class RegionGen extends InsnGen {
|
||||
code.startLine("default:");
|
||||
makeCaseBlock(sw.getDefaultCase(), code);
|
||||
}
|
||||
code.decIndent();
|
||||
|
||||
code.startLine('}');
|
||||
return code;
|
||||
}
|
||||
|
||||
private void makeCaseBlock(IContainer c, CodeWriter code) throws CodegenException {
|
||||
code.add(" {");
|
||||
if (RegionUtils.notEmpty(c)) {
|
||||
makeRegionIndent(code, c);
|
||||
if (RegionUtils.hasExitEdge(c)) {
|
||||
@@ -264,7 +269,6 @@ public class RegionGen extends InsnGen {
|
||||
} else {
|
||||
code.startLine(1, "break;");
|
||||
}
|
||||
code.startLine('}');
|
||||
}
|
||||
|
||||
private void makeTryCatch(IContainer region, TryCatchBlock tryCatchBlock, CodeWriter code)
|
||||
@@ -305,4 +309,13 @@ public class RegionGen extends InsnGen {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: !!code from InsnGen.sfield
|
||||
private String sfield(FieldInfo field) {
|
||||
String thisClass = mth.getParentClass().getFullName();
|
||||
if (thisClass.startsWith(field.getDeclClass().getFullName())) {
|
||||
return field.getName();
|
||||
} else {
|
||||
return useClass(field.getDeclClass()) + '.' + field.getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -571,19 +571,21 @@ public class InsnDecoder {
|
||||
private InsnNode decodeSwitch(DecodedInstruction insn, int offset, boolean packed) {
|
||||
int payloadOffset = insn.getTarget();
|
||||
DecodedInstruction payload = insnArr[payloadOffset];
|
||||
int[] keys;
|
||||
Object[] keys;
|
||||
int[] targets;
|
||||
if (packed) {
|
||||
PackedSwitchPayloadDecodedInstruction ps = (PackedSwitchPayloadDecodedInstruction) payload;
|
||||
targets = ps.getTargets();
|
||||
keys = new int[targets.length];
|
||||
keys = new Object[targets.length];
|
||||
int k = ps.getFirstKey();
|
||||
for (int i = 0; i < keys.length; i++)
|
||||
keys[i] = k++;
|
||||
} else {
|
||||
SparseSwitchPayloadDecodedInstruction ss = (SparseSwitchPayloadDecodedInstruction) payload;
|
||||
targets = ss.getTargets();
|
||||
keys = ss.getKeys();
|
||||
keys = new Object[targets.length];
|
||||
for (int i = 0; i < keys.length; i++)
|
||||
keys[i] = ss.getKeys()[i];
|
||||
}
|
||||
// convert from relative to absolute offsets
|
||||
for (int i = 0; i < targets.length; i++) {
|
||||
|
||||
@@ -8,11 +8,11 @@ import java.util.Arrays;
|
||||
|
||||
public class SwitchNode extends InsnNode {
|
||||
|
||||
private final int[] keys;
|
||||
private final Object[] keys;
|
||||
private final int[] targets;
|
||||
private final int def; // next instruction
|
||||
|
||||
public SwitchNode(InsnArg arg, int[] keys, int[] targets, int def) {
|
||||
public SwitchNode(InsnArg arg, Object[] keys, int[] targets, int def) {
|
||||
super(InsnType.SWITCH, 1);
|
||||
this.keys = keys;
|
||||
this.targets = targets;
|
||||
@@ -24,7 +24,7 @@ public class SwitchNode extends InsnNode {
|
||||
return keys.length;
|
||||
}
|
||||
|
||||
public int[] getKeys() {
|
||||
public Object[] getKeys() {
|
||||
return keys;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import jadx.core.dex.info.ClassInfo;
|
||||
import jadx.core.dex.info.FieldInfo;
|
||||
import jadx.core.dex.info.MethodInfo;
|
||||
import jadx.core.dex.instructions.args.ArgType;
|
||||
import jadx.core.dex.instructions.args.LiteralArg;
|
||||
import jadx.core.dex.nodes.parser.AnnotationsParser;
|
||||
import jadx.core.dex.nodes.parser.FieldValueAttr;
|
||||
import jadx.core.dex.nodes.parser.StaticValuesParser;
|
||||
@@ -237,12 +238,37 @@ public class ClassNode extends LineAttrNode implements ILoadable {
|
||||
}
|
||||
|
||||
public FieldNode getConstField(Object o) {
|
||||
FieldNode field = constFields.get(o);
|
||||
ClassNode cn = this;
|
||||
FieldNode field;
|
||||
do {
|
||||
field = cn.constFields.get(o);
|
||||
}
|
||||
while (field == null
|
||||
&& (cn.clsInfo.getParentClass() != null)
|
||||
&& (cn = dex.resolveClass(cn.clsInfo.getParentClass())) != null);
|
||||
|
||||
if (field == null)
|
||||
field = dex.getConstFields().get(o);
|
||||
return field;
|
||||
}
|
||||
|
||||
public FieldNode getConstFieldByLiteralArg(LiteralArg arg) {
|
||||
ArgType type = arg.getType();
|
||||
long literal = arg.getLiteral();
|
||||
|
||||
if (type.equals(ArgType.DOUBLE))
|
||||
return getConstField(Double.longBitsToDouble(literal));
|
||||
else if (type.equals(ArgType.FLOAT))
|
||||
return getConstField(Float.intBitsToFloat((int) literal));
|
||||
else if (Math.abs(literal) > 0x1) {
|
||||
if (type.equals(ArgType.INT))
|
||||
return getConstField((int) literal);
|
||||
else if (type.equals(ArgType.LONG))
|
||||
return getConstField(literal);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public FieldNode searchFieldById(int id) {
|
||||
String name = FieldInfo.getNameById(dex, id);
|
||||
for (FieldNode f : fields) {
|
||||
|
||||
@@ -12,14 +12,14 @@ public final class SwitchRegion extends AbstractRegion {
|
||||
|
||||
private final BlockNode header;
|
||||
|
||||
private final List<List<Integer>> keys;
|
||||
private final List<List<Object>> keys;
|
||||
private final List<IContainer> cases;
|
||||
private IContainer defCase;
|
||||
|
||||
public SwitchRegion(IRegion parent, BlockNode header) {
|
||||
super(parent);
|
||||
this.header = header;
|
||||
this.keys = new ArrayList<List<Integer>>();
|
||||
this.keys = new ArrayList<List<Object>>();
|
||||
this.cases = new ArrayList<IContainer>();
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ public final class SwitchRegion extends AbstractRegion {
|
||||
return header;
|
||||
}
|
||||
|
||||
public void addCase(List<Integer> keysList, IContainer c) {
|
||||
public void addCase(List<Object> keysList, IContainer c) {
|
||||
keys.add(keysList);
|
||||
cases.add(c);
|
||||
}
|
||||
@@ -40,7 +40,7 @@ public final class SwitchRegion extends AbstractRegion {
|
||||
return defCase;
|
||||
}
|
||||
|
||||
public List<List<Integer>> getKeys() {
|
||||
public List<List<Object>> getKeys() {
|
||||
return keys;
|
||||
}
|
||||
|
||||
|
||||
@@ -349,44 +349,70 @@ public class BlockMakerVisitor extends AbstractVisitor {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// splice return block if several precessors presents
|
||||
if (false && block.getAttributes().contains(AttributeFlag.RETURN)
|
||||
&& block.getPredecessors().size() > 1
|
||||
&& !block.getInstructions().get(0).getAttributes().contains(AttributeType.CATCH_BLOCK)) {
|
||||
}
|
||||
// splice return block if several predecessors presents
|
||||
for (BlockNode block : mth.getExitBlocks()) {
|
||||
if (block.getInstructions().size() == 1
|
||||
&& block.getInstructions().get(0).getArgsCount() > 0
|
||||
&& !block.getInstructions().get(0).getAttributes().contains(AttributeType.CATCH_BLOCK)
|
||||
&& !block.getAttributes().contains(AttributeFlag.SYNTHETIC)) {
|
||||
List<BlockNode> preds = new ArrayList<BlockNode>(block.getPredecessors());
|
||||
|
||||
BlockNode origRetBlock = block;
|
||||
origRetBlock.getPredecessors().clear();
|
||||
origRetBlock.getPredecessors().add(preds.get(0));
|
||||
preds.remove(0);
|
||||
|
||||
InsnNode origReturnInsn = origRetBlock.getInstructions().get(0);
|
||||
InsnNode origReturnInsn = block.getInstructions().get(0);
|
||||
RegisterArg retArg = null;
|
||||
if (origReturnInsn.getArgsCount() != 0)
|
||||
retArg = (RegisterArg) origReturnInsn.getArg(0);
|
||||
|
||||
for (BlockNode pred : preds) {
|
||||
pred.getSuccessors().remove(origRetBlock);
|
||||
// make copy of return block and connect to predecessor
|
||||
BlockNode newRetBlock = startNewBlock(mth, origRetBlock.getStartOffset());
|
||||
BlockNode newRetBlock;
|
||||
InsnNode predInsn = pred.getInstructions().get(0);
|
||||
|
||||
switch (predInsn.getType()) {
|
||||
case IF:
|
||||
// make copy of return block and connect to predecessor
|
||||
newRetBlock = startNewBlock(mth, block.getStartOffset());
|
||||
newRetBlock.getAttributes().add(AttributeFlag.SYNTHETIC);
|
||||
|
||||
if (pred.getSuccessors().get(0) == block) {
|
||||
pred.getSuccessors().set(0, newRetBlock);
|
||||
} else if (pred.getSuccessors().get(1) == block){
|
||||
pred.getSuccessors().set(1, newRetBlock);
|
||||
}
|
||||
block.getPredecessors().remove(pred);
|
||||
newRetBlock.getPredecessors().add(pred);
|
||||
break;
|
||||
|
||||
case SWITCH:
|
||||
// TODO: is it ok to just skip this predecessor?
|
||||
block.getAttributes().add(AttributeFlag.SYNTHETIC);
|
||||
continue;
|
||||
|
||||
default:
|
||||
removeConnection(pred, block);
|
||||
newRetBlock = pred;
|
||||
break;
|
||||
}
|
||||
|
||||
InsnNode ret = new InsnNode(InsnType.RETURN, 1);
|
||||
if (retArg != null)
|
||||
if (retArg != null) {
|
||||
ret.addArg(InsnArg.reg(retArg.getRegNum(), retArg.getType()));
|
||||
ret.getArg(0).forceSetTypedVar(retArg.getTypedVar());
|
||||
}
|
||||
ret.getAttributes().addAll(origReturnInsn.getAttributes());
|
||||
|
||||
newRetBlock.getInstructions().add(ret);
|
||||
newRetBlock.getAttributes().add(AttributeFlag.RETURN);
|
||||
|
||||
connect(pred, newRetBlock);
|
||||
mth.addExitBlock(newRetBlock);
|
||||
}
|
||||
return true;
|
||||
if (block.getPredecessors().size() == 0) {
|
||||
mth.getBasicBlocks().remove(block);
|
||||
mth.getExitBlocks().remove(block);
|
||||
return true;
|
||||
}
|
||||
return block.getAttributes().contains(AttributeFlag.SYNTHETIC);
|
||||
}
|
||||
|
||||
// TODO detect ternary operator
|
||||
}
|
||||
// TODO detect ternary operator
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -81,13 +81,17 @@ public class CodeShrinker extends AbstractVisitor {
|
||||
}
|
||||
}
|
||||
if (wrap) {
|
||||
// if (useInsn.getType() == InsnType.MOVE) {
|
||||
// // TODO
|
||||
// // remover.add(useInsn);
|
||||
// } else {
|
||||
useInsnArg.wrapInstruction(insn);
|
||||
if (insn.getType() == InsnType.MOVE) {
|
||||
for (int r = 0; r < useInsn.getArgsCount(); r++) {
|
||||
if (useInsn.getArg(r).getTypedVar() == insn.getResult().getTypedVar()) {
|
||||
useInsn.setArg(r, insn.getArg(0));
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
useInsnArg.wrapInstruction(insn);
|
||||
}
|
||||
remover.add(insn);
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,22 +3,10 @@ package jadx.core.dex.visitors;
|
||||
import jadx.core.deobf.NameMapper;
|
||||
import jadx.core.dex.attributes.AttributeType;
|
||||
import jadx.core.dex.info.MethodInfo;
|
||||
import jadx.core.dex.instructions.ConstClassNode;
|
||||
import jadx.core.dex.instructions.ConstStringNode;
|
||||
import jadx.core.dex.instructions.FillArrayNode;
|
||||
import jadx.core.dex.instructions.IndexInsnNode;
|
||||
import jadx.core.dex.instructions.InsnType;
|
||||
import jadx.core.dex.instructions.InvokeNode;
|
||||
import jadx.core.dex.instructions.args.ArgType;
|
||||
import jadx.core.dex.instructions.args.InsnArg;
|
||||
import jadx.core.dex.instructions.args.LiteralArg;
|
||||
import jadx.core.dex.instructions.args.RegisterArg;
|
||||
import jadx.core.dex.instructions.*;
|
||||
import jadx.core.dex.instructions.args.*;
|
||||
import jadx.core.dex.instructions.mods.ConstructorInsn;
|
||||
import jadx.core.dex.nodes.BlockNode;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.core.dex.nodes.FieldNode;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
import jadx.core.dex.nodes.*;
|
||||
import jadx.core.dex.trycatch.ExcHandlerAttr;
|
||||
import jadx.core.dex.trycatch.ExceptionHandler;
|
||||
import jadx.core.utils.BlockUtils;
|
||||
@@ -59,6 +47,8 @@ public class ModVisitor extends AbstractVisitor {
|
||||
int size = block.getInstructions().size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
InsnNode insn = block.getInstructions().get(i);
|
||||
ClassNode parentClass = mth.getParentClass();
|
||||
FieldNode f = null;
|
||||
|
||||
switch (insn.getType()) {
|
||||
case INVOKE:
|
||||
@@ -102,8 +92,6 @@ public class ModVisitor extends AbstractVisitor {
|
||||
case CONST:
|
||||
case CONST_STR:
|
||||
case CONST_CLASS:
|
||||
ClassNode parentClass = mth.getParentClass();
|
||||
FieldNode f = null;
|
||||
if (insn.getType() == InsnType.CONST_STR) {
|
||||
String s = ((ConstStringNode) insn).getString();
|
||||
f = parentClass.getConstField(s);
|
||||
@@ -111,19 +99,7 @@ public class ModVisitor extends AbstractVisitor {
|
||||
ArgType t = ((ConstClassNode) insn).getClsType();
|
||||
f = parentClass.getConstField(t);
|
||||
} else {
|
||||
LiteralArg arg = (LiteralArg) insn.getArg(0);
|
||||
ArgType type = arg.getType();
|
||||
long lit = arg.getLiteral();
|
||||
if (Math.abs(lit) > 0xFF) {
|
||||
if (type.equals(ArgType.INT))
|
||||
f = parentClass.getConstField((int) lit);
|
||||
else if (type.equals(ArgType.LONG))
|
||||
f = parentClass.getConstField(lit);
|
||||
}
|
||||
if (type.equals(ArgType.DOUBLE))
|
||||
f = parentClass.getConstField(Double.longBitsToDouble(lit));
|
||||
else if (type.equals(ArgType.FLOAT))
|
||||
f = parentClass.getConstField(Float.intBitsToFloat((int) lit));
|
||||
f = parentClass.getConstFieldByLiteralArg((LiteralArg) insn.getArg(0));
|
||||
}
|
||||
if (f != null) {
|
||||
InsnNode inode = new IndexInsnNode(InsnType.SGET, f.getFieldInfo(), 0);
|
||||
@@ -132,6 +108,27 @@ public class ModVisitor extends AbstractVisitor {
|
||||
}
|
||||
break;
|
||||
|
||||
case SWITCH:
|
||||
SwitchNode sn = (SwitchNode) insn;
|
||||
for (int k = 0; k < sn.getCasesCount(); k++) {
|
||||
f = parentClass.getConstField(sn.getKeys()[k]);
|
||||
if (f != null) {
|
||||
sn.getKeys()[k] = new IndexInsnNode(InsnType.SGET, f.getFieldInfo(), 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RETURN:
|
||||
if (insn.getArgsCount() > 0
|
||||
&& insn.getArg(0).isLiteral()) {
|
||||
LiteralArg arg = (LiteralArg) insn.getArg(0);
|
||||
f = parentClass.getConstFieldByLiteralArg(arg);
|
||||
if (f != null) {
|
||||
arg.wrapInstruction(new IndexInsnNode(InsnType.SGET, f.getFieldInfo(), 0));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -583,21 +583,21 @@ public class RegionMaker {
|
||||
|
||||
int len = insn.getTargets().length;
|
||||
// sort by target
|
||||
Map<Integer, List<Integer>> casesMap = new LinkedHashMap<Integer, List<Integer>>(len);
|
||||
Map<Integer, List<Object>> casesMap = new LinkedHashMap<Integer, List<Object>>(len);
|
||||
for (int i = 0; i < len; i++) {
|
||||
int key = insn.getKeys()[i];
|
||||
Object key = insn.getKeys()[i];
|
||||
int targ = insn.getTargets()[i];
|
||||
List<Integer> keys = casesMap.get(targ);
|
||||
List<Object> keys = casesMap.get(targ);
|
||||
if (keys == null) {
|
||||
keys = new ArrayList<Integer>(1);
|
||||
keys = new ArrayList<Object>(2);
|
||||
casesMap.put(targ, keys);
|
||||
}
|
||||
keys.add(key);
|
||||
}
|
||||
|
||||
Map<BlockNode, List<Integer>> blocksMap = new LinkedHashMap<BlockNode, List<Integer>>(len);
|
||||
for (Entry<Integer, List<Integer>> entry : casesMap.entrySet()) {
|
||||
BlockNode c = getBlockByOffset(entry.getKey(), block.getSuccessors());
|
||||
Map<BlockNode, List<Object>> blocksMap = new LinkedHashMap<BlockNode, List<Object>>(len);
|
||||
for (Entry<Integer, List<Object>> entry : casesMap.entrySet()) {
|
||||
BlockNode c = getBlockByOffset((int) entry.getKey(), block.getSuccessors());
|
||||
assert c != null;
|
||||
blocksMap.put(c, entry.getValue());
|
||||
}
|
||||
@@ -650,7 +650,7 @@ public class RegionMaker {
|
||||
if (!stack.containsExit(defCase)) {
|
||||
sw.setDefaultCase(makeRegion(defCase, stack));
|
||||
}
|
||||
for (Entry<BlockNode, List<Integer>> entry : blocksMap.entrySet()) {
|
||||
for (Entry<BlockNode, List<Object>> entry : blocksMap.entrySet()) {
|
||||
BlockNode c = entry.getKey();
|
||||
if (stack.containsExit(c)) {
|
||||
// empty case block
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
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.junit.Assert.assertThat;
|
||||
|
||||
public class TestReturnWrapping extends InternalJadxTest {
|
||||
public static class TestCls {
|
||||
/**/
|
||||
public static int f1(int arg0) {
|
||||
switch (arg0) {
|
||||
case 1:
|
||||
return 255;
|
||||
}
|
||||
return arg0 + 1;
|
||||
}/**/
|
||||
|
||||
/**/
|
||||
public static Object f2(Object arg0, int arg1) {
|
||||
Object ret = null;
|
||||
int i = arg1;
|
||||
if (arg0 == null) {
|
||||
return ret + Integer.toHexString(i);
|
||||
} else {
|
||||
i++;
|
||||
try {
|
||||
ret = new Object().getClass();
|
||||
} catch (Exception e) {
|
||||
ret = "Qwerty";
|
||||
}
|
||||
return i > 128 ? arg0.toString() + ret.toString() : i;
|
||||
}
|
||||
}/**/
|
||||
|
||||
/**/
|
||||
public static int f3(int arg0) {
|
||||
while (arg0 > 10) {
|
||||
int abc = 951;
|
||||
if (arg0 == 255) {
|
||||
return arg0 + 2;
|
||||
}
|
||||
arg0 -= abc;
|
||||
}
|
||||
return arg0;
|
||||
}/**/
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
String code = cls.getCode().toString();
|
||||
assertThat(code, containsString("return 255;"));
|
||||
assertThat(code, containsString("return arg0 + 1;"));
|
||||
//assertThat(code, containsString("return Integer.toHexString(i);"));
|
||||
assertThat(code, containsString("return arg0.toString() + ret.toString();"));
|
||||
assertThat(code, containsString("return arg0 + 2;"));
|
||||
assertThat(code, containsString("arg0 -= 951;"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
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;
|
||||
import static org.mockito.AdditionalMatchers.or;
|
||||
|
||||
public class TestSwitchLabels extends InternalJadxTest {
|
||||
public static class TestCls {
|
||||
public static final int CONST_ABC = 0xABC;
|
||||
public static final int CONST_CDE = 0xCDE;
|
||||
|
||||
public static class Inner {
|
||||
private static final int CONST_CDE_PRIVATE = 0xCDE;
|
||||
public int f1(int arg0) {
|
||||
switch (arg0) {
|
||||
case CONST_CDE_PRIVATE:
|
||||
return CONST_ABC;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static int f1(int arg0) {
|
||||
switch (arg0) {
|
||||
case CONST_ABC:
|
||||
return CONST_CDE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
String code = cls.getCode().toString();
|
||||
assertThat(code, containsString("case CONST_ABC:"));
|
||||
assertThat(code, containsString("return CONST_CDE;"));
|
||||
|
||||
cls.addInnerClass(getClassNode(TestCls.Inner.class));
|
||||
assertThat(code, containsString("case CONST_CDE_PRIVATE:"));
|
||||
assertThat(code, containsString(".CONST_ABC;"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user