core: make better variables naming
This commit is contained in:
+6
-8
@@ -9,16 +9,14 @@ subprojects {
|
||||
apply plugin: 'jacoco'
|
||||
apply plugin: 'coveralls'
|
||||
|
||||
sourceCompatibility = 1.6
|
||||
targetCompatibility = 1.6
|
||||
|
||||
version = jadxVersion
|
||||
|
||||
gradle.projectsEvaluated {
|
||||
tasks.withType(Compile) {
|
||||
if (!"$it".contains(':jadx-samples:')) {
|
||||
options.compilerArgs << '-Xlint' << '-Xlint:unchecked' << '-Xlint:deprecation'
|
||||
}
|
||||
tasks.withType(JavaCompile) {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_6
|
||||
targetCompatibility = JavaVersion.VERSION_1_6
|
||||
|
||||
if (!"$it".contains(':jadx-samples:')) {
|
||||
options.compilerArgs << '-Xlint' << '-Xlint:unchecked' << '-Xlint:deprecation'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import jadx.core.dex.visitors.BlockMakerVisitor;
|
||||
import jadx.core.dex.visitors.ClassModifier;
|
||||
import jadx.core.dex.visitors.CodeShrinker;
|
||||
import jadx.core.dex.visitors.ConstInlinerVisitor;
|
||||
import jadx.core.dex.visitors.DebugInfoVisitor;
|
||||
import jadx.core.dex.visitors.DotGraphVisitor;
|
||||
import jadx.core.dex.visitors.EnumVisitor;
|
||||
import jadx.core.dex.visitors.FallbackModeVisitor;
|
||||
@@ -54,6 +55,7 @@ public class Jadx {
|
||||
} else {
|
||||
passes.add(new BlockMakerVisitor());
|
||||
passes.add(new SSATransform());
|
||||
passes.add(new DebugInfoVisitor());
|
||||
passes.add(new TypeInference());
|
||||
|
||||
passes.add(new ConstInlinerVisitor());
|
||||
|
||||
@@ -88,7 +88,7 @@ public class InsnGen {
|
||||
|
||||
public void addArg(CodeWriter code, InsnArg arg, boolean wrap) throws CodegenException {
|
||||
if (arg.isRegister()) {
|
||||
code.add(mgen.makeArgName((RegisterArg) arg));
|
||||
code.add(mgen.getNameGen().useArg((RegisterArg) arg));
|
||||
} else if (arg.isLiteral()) {
|
||||
code.add(lit((LiteralArg) arg));
|
||||
} else if (arg.isInsnWrap()) {
|
||||
@@ -120,7 +120,7 @@ public class InsnGen {
|
||||
public void declareVar(CodeWriter code, RegisterArg arg) {
|
||||
useType(code, arg.getType());
|
||||
code.add(' ');
|
||||
code.add(mgen.assignArg(arg));
|
||||
code.add(mgen.getNameGen().assignArg(arg));
|
||||
}
|
||||
|
||||
private static String lit(LiteralArg arg) {
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
package jadx.core.codegen;
|
||||
|
||||
import jadx.core.Consts;
|
||||
import jadx.core.dex.attributes.AFlag;
|
||||
import jadx.core.dex.attributes.AType;
|
||||
import jadx.core.dex.attributes.annotations.MethodParameters;
|
||||
import jadx.core.dex.attributes.nodes.JadxErrorAttr;
|
||||
import jadx.core.dex.info.AccessInfo;
|
||||
import jadx.core.dex.instructions.args.ArgType;
|
||||
import jadx.core.dex.instructions.args.NamedArg;
|
||||
import jadx.core.dex.instructions.args.RegisterArg;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
@@ -21,10 +19,8 @@ import jadx.core.utils.Utils;
|
||||
import jadx.core.utils.exceptions.CodegenException;
|
||||
import jadx.core.utils.exceptions.DecodeException;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -36,27 +32,24 @@ public class MethodGen {
|
||||
|
||||
private final MethodNode mth;
|
||||
private final ClassGen classGen;
|
||||
private final boolean fallback;
|
||||
private final AnnotationGen annotationGen;
|
||||
|
||||
private final Set<String> varNames = new HashSet<String>();
|
||||
private final NameGen nameGen;
|
||||
|
||||
public MethodGen(ClassGen classGen, MethodNode mth) {
|
||||
this.mth = mth;
|
||||
this.classGen = classGen;
|
||||
this.fallback = classGen.isFallbackMode();
|
||||
this.annotationGen = classGen.getAnnotationGen();
|
||||
|
||||
List<RegisterArg> args = mth.getArguments(true);
|
||||
for (RegisterArg arg : args) {
|
||||
varNames.add(makeArgName(arg));
|
||||
}
|
||||
this.nameGen = new NameGen(classGen.isFallbackMode());
|
||||
}
|
||||
|
||||
public ClassGen getClassGen() {
|
||||
return classGen;
|
||||
}
|
||||
|
||||
public NameGen getNameGen() {
|
||||
return nameGen;
|
||||
}
|
||||
|
||||
public MethodNode getMethodNode() {
|
||||
return mth;
|
||||
}
|
||||
@@ -124,9 +117,7 @@ public class MethodGen {
|
||||
}
|
||||
|
||||
private void addMethodArguments(CodeWriter argsCode, List<RegisterArg> args) {
|
||||
MethodParameters paramsAnnotation =
|
||||
mth.get(AType.ANNOTATION_MTH_PARAMETERS);
|
||||
|
||||
MethodParameters paramsAnnotation = mth.get(AType.ANNOTATION_MTH_PARAMETERS);
|
||||
int i = 0;
|
||||
for (Iterator<RegisterArg> it = args.iterator(); it.hasNext(); ) {
|
||||
RegisterArg arg = it.next();
|
||||
@@ -150,7 +141,7 @@ public class MethodGen {
|
||||
classGen.useType(argsCode, arg.getType());
|
||||
}
|
||||
argsCode.add(' ');
|
||||
argsCode.add(makeArgName(arg));
|
||||
argsCode.add(nameGen.assignArg(arg));
|
||||
|
||||
i++;
|
||||
if (it.hasNext()) {
|
||||
@@ -159,74 +150,6 @@ public class MethodGen {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make variable name for register,
|
||||
* Name contains register number and
|
||||
* variable type or name (if debug info available)
|
||||
*/
|
||||
public String makeArgName(RegisterArg arg) {
|
||||
String name = arg.getName();
|
||||
String base = "r" + arg.getRegNum();
|
||||
if (fallback) {
|
||||
if (name != null) {
|
||||
return base + "_" + name;
|
||||
}
|
||||
return base;
|
||||
} else {
|
||||
if (name != null) {
|
||||
if (Consts.DEBUG) {
|
||||
return base + "_" + name;
|
||||
}
|
||||
return name;
|
||||
} else {
|
||||
ArgType type = arg.getType();
|
||||
if (type.isPrimitive()) {
|
||||
return base + type.getPrimitiveType().getShortName().toLowerCase();
|
||||
} else {
|
||||
// TODO: prettify variable name
|
||||
return base + "_" + Utils.escape(type.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Put variable declaration and return variable name (used for assignments)
|
||||
*
|
||||
* @param arg register variable
|
||||
* @return variable name
|
||||
*/
|
||||
public String assignArg(RegisterArg arg) {
|
||||
String name = makeArgName(arg);
|
||||
if (varNames.add(name) || fallback) {
|
||||
return name;
|
||||
}
|
||||
name = getUniqVarName(name);
|
||||
arg.getSVar().setVariableName(name);
|
||||
return name;
|
||||
}
|
||||
|
||||
public String assignNamedArg(NamedArg arg) {
|
||||
String name = arg.getName();
|
||||
if (varNames.add(name) || fallback) {
|
||||
return name;
|
||||
}
|
||||
name = getUniqVarName(name);
|
||||
arg.setName(name);
|
||||
return name;
|
||||
}
|
||||
|
||||
private String getUniqVarName(String name) {
|
||||
String r;
|
||||
int i = 2;
|
||||
do {
|
||||
r = name + "_" + i;
|
||||
i++;
|
||||
} while (varNames.contains(r));
|
||||
varNames.add(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
public void addInstructions(CodeWriter code) throws CodegenException {
|
||||
if (mth.contains(AType.JADX_ERROR)) {
|
||||
code.startLine("throw new UnsupportedOperationException(\"Method not decompiled: ");
|
||||
@@ -283,20 +206,23 @@ public class MethodGen {
|
||||
return;
|
||||
}
|
||||
}
|
||||
List<InsnNode> insns = mth.getInstructions();
|
||||
if (insns == null) {
|
||||
InsnNode[] insnArr = mth.getInstructions();
|
||||
if (insnArr == null) {
|
||||
code.startLine("// Can't load method instructions.");
|
||||
return;
|
||||
}
|
||||
if (mth.getThisArg() != null) {
|
||||
code.startLine(getFallbackMethodGen(mth).makeArgName(mth.getThisArg())).add(" = this;");
|
||||
code.startLine(getFallbackMethodGen(mth).nameGen.useArg(mth.getThisArg())).add(" = this;");
|
||||
}
|
||||
addFallbackInsns(code, mth, insns, true);
|
||||
addFallbackInsns(code, mth, insnArr, true);
|
||||
}
|
||||
|
||||
public static void addFallbackInsns(CodeWriter code, MethodNode mth, List<InsnNode> insns, boolean addLabels) {
|
||||
public static void addFallbackInsns(CodeWriter code, MethodNode mth, InsnNode[] insnArr, boolean addLabels) {
|
||||
InsnGen insnGen = new InsnGen(getFallbackMethodGen(mth), true);
|
||||
for (InsnNode insn : insns) {
|
||||
for (InsnNode insn : insnArr) {
|
||||
if (insn == null) {
|
||||
continue;
|
||||
}
|
||||
if (addLabels) {
|
||||
if (insn.contains(AType.JUMP)
|
||||
|| insn.contains(AType.EXC_HANDLER)) {
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
package jadx.core.codegen;
|
||||
|
||||
import jadx.core.Consts;
|
||||
import jadx.core.deobf.NameMapper;
|
||||
import jadx.core.dex.info.ClassInfo;
|
||||
import jadx.core.dex.instructions.args.ArgType;
|
||||
import jadx.core.dex.instructions.args.NamedArg;
|
||||
import jadx.core.dex.instructions.args.RegisterArg;
|
||||
import jadx.core.dex.instructions.args.SSAVar;
|
||||
import jadx.core.utils.Utils;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class NameGen {
|
||||
|
||||
private final Set<String> varNames = new HashSet<String>();
|
||||
private final boolean fallback;
|
||||
|
||||
public NameGen(boolean fallback) {
|
||||
this.fallback = fallback;
|
||||
}
|
||||
|
||||
public String assignArg(RegisterArg arg) {
|
||||
String name = makeArgName(arg);
|
||||
if (fallback) {
|
||||
return name;
|
||||
}
|
||||
name = getUniqueVarName(name);
|
||||
SSAVar sVar = arg.getSVar();
|
||||
if (sVar != null) {
|
||||
sVar.setName(name);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
public String assignNamedArg(NamedArg arg) {
|
||||
String name = arg.getName();
|
||||
if (fallback) {
|
||||
return name;
|
||||
}
|
||||
name = getUniqueVarName(name);
|
||||
arg.setName(name);
|
||||
return name;
|
||||
}
|
||||
|
||||
public String useArg(RegisterArg arg) {
|
||||
String name = makeArgName(arg);
|
||||
varNames.add(name);
|
||||
return name;
|
||||
}
|
||||
|
||||
private String getUniqueVarName(String name) {
|
||||
String r = name;
|
||||
int i = 2;
|
||||
while (varNames.contains(r)) {
|
||||
r = name + i;
|
||||
i++;
|
||||
}
|
||||
varNames.add(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
private String makeArgName(RegisterArg arg) {
|
||||
String name = arg.getName();
|
||||
if (fallback) {
|
||||
String base = "r" + arg.getRegNum();
|
||||
if (name != null) {
|
||||
return base + "_" + name;
|
||||
}
|
||||
return base;
|
||||
}
|
||||
String varName;
|
||||
if (name != null) {
|
||||
if (name.equals("this")) {
|
||||
return name;
|
||||
}
|
||||
varName = name;
|
||||
} else {
|
||||
varName = makeNameForType(arg.getType());
|
||||
}
|
||||
if (NameMapper.isReserved(varName)) {
|
||||
return varName + "R";
|
||||
}
|
||||
return varName;
|
||||
}
|
||||
|
||||
private static String makeNameForType(ArgType type) {
|
||||
if (type.isPrimitive()) {
|
||||
return makeNameForPrimitive(type);
|
||||
} else if (type.isArray()) {
|
||||
return makeNameForType(type.getArrayRootElement()) + "Arr";
|
||||
} else {
|
||||
return makeNameForObject(type);
|
||||
}
|
||||
}
|
||||
|
||||
private static String makeNameForPrimitive(ArgType type) {
|
||||
return type.getPrimitiveType().getShortName().toLowerCase();
|
||||
}
|
||||
|
||||
private static String makeNameForObject(ArgType type) {
|
||||
if (type.isObject()) {
|
||||
String obj = type.getObject();
|
||||
if (obj.startsWith("java.lang.")) {
|
||||
if (obj.equals(Consts.CLASS_STRING)) {
|
||||
return "str";
|
||||
}
|
||||
if (obj.equals(Consts.CLASS_OBJECT)) {
|
||||
return "obj";
|
||||
}
|
||||
if (obj.equals(Consts.CLASS_CLASS)) {
|
||||
return "cls";
|
||||
}
|
||||
if (obj.equals(Consts.CLASS_THROWABLE)) {
|
||||
return "th";
|
||||
}
|
||||
}
|
||||
ClassInfo clsInfo = ClassInfo.fromType(type);
|
||||
String shortName = clsInfo.getShortName();
|
||||
if (shortName.toUpperCase().equals(shortName)) {
|
||||
// all characters are upper case
|
||||
return shortName.toLowerCase();
|
||||
}
|
||||
if (!shortName.isEmpty()) {
|
||||
String v1 = Character.toLowerCase(shortName.charAt(0)) + shortName.substring(1);
|
||||
if (!v1.equals(shortName)) {
|
||||
return v1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Utils.escape(type.toString());
|
||||
}
|
||||
}
|
||||
@@ -277,7 +277,7 @@ public class RegionGen extends InsnGen {
|
||||
useClass(code, handler.getCatchType());
|
||||
}
|
||||
code.add(' ');
|
||||
code.add(mgen.assignNamedArg(handler.getArg()));
|
||||
code.add(mgen.getNameGen().assignNamedArg(handler.getArg()));
|
||||
code.add(") {");
|
||||
makeRegionIndent(code, region);
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ public abstract class InsnArg extends Typed {
|
||||
return reg(InsnUtils.getArg(insn, argNum), type);
|
||||
}
|
||||
|
||||
public static RegisterArg parameterReg(int regNum, ArgType type) {
|
||||
public static MthParameterArg parameterReg(int regNum, ArgType type) {
|
||||
return new MthParameterArg(regNum, type);
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ public abstract class InsnArg extends Typed {
|
||||
}
|
||||
|
||||
public boolean isThis() {
|
||||
// must be implemented in RegisterArg
|
||||
// must be implemented in RegisterArg and MthParameterArg
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package jadx.core.dex.instructions.args;
|
||||
|
||||
public class MthParameterArg extends RegisterArg {
|
||||
|
||||
private boolean isThis = false;
|
||||
|
||||
public MthParameterArg(int rn, ArgType type) {
|
||||
super(rn, type);
|
||||
}
|
||||
@@ -14,4 +16,29 @@ public class MthParameterArg extends RegisterArg {
|
||||
@Override
|
||||
public void setType(ArgType type) {
|
||||
}
|
||||
|
||||
public void markAsThis() {
|
||||
this.isThis = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isThis() {
|
||||
return isThis;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
if (isThis) {
|
||||
return "this";
|
||||
}
|
||||
return super.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
void setSVar(SSAVar sVar) {
|
||||
if (isThis) {
|
||||
sVar.setName("this");
|
||||
}
|
||||
super.setSVar(sVar);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ import jadx.core.dex.nodes.DexNode;
|
||||
import jadx.core.dex.nodes.FieldNode;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.dex.nodes.parser.FieldValueAttr;
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -21,7 +20,6 @@ public class RegisterArg extends InsnArg implements Named {
|
||||
|
||||
protected final int regNum;
|
||||
protected SSAVar sVar;
|
||||
protected String name;
|
||||
|
||||
public RegisterArg(int rn) {
|
||||
this.regNum = rn;
|
||||
@@ -49,34 +47,43 @@ public class RegisterArg extends InsnArg implements Named {
|
||||
this.sVar = sVar;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
if (sVar == null) {
|
||||
return null;
|
||||
}
|
||||
return sVar.getName();
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
if (sVar != null) {
|
||||
sVar.setName(name);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isNameEquals(InsnArg arg) {
|
||||
String n = getName();
|
||||
if (n == null || !(arg instanceof Named)) {
|
||||
return false;
|
||||
}
|
||||
return n.equals(((Named) arg).getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setType(ArgType type) {
|
||||
if (sVar != null) {
|
||||
sVar.setType(type);
|
||||
} else {
|
||||
throw new JadxRuntimeException("SSA variable equals null");
|
||||
}
|
||||
}
|
||||
|
||||
public void mergeDebugInfo(ArgType type, String name) {
|
||||
setType(type);
|
||||
setName(name);
|
||||
}
|
||||
|
||||
public void forceType(ArgType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public boolean isNameEquals(InsnArg arg) {
|
||||
if (name == null || !(arg instanceof Named)) {
|
||||
return false;
|
||||
}
|
||||
return name.equals(((Named) arg).getName());
|
||||
}
|
||||
|
||||
public void setName(String newName) {
|
||||
this.name = newName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return constant value from register assign or null if not constant
|
||||
*
|
||||
@@ -113,17 +120,15 @@ public class RegisterArg extends InsnArg implements Named {
|
||||
|
||||
@Override
|
||||
public boolean isThis() {
|
||||
if ("this".equals(name)) {
|
||||
if ("this".equals(getName())) {
|
||||
return true;
|
||||
}
|
||||
// maybe it was moved from 'this' register
|
||||
InsnNode ai = getAssignInsn();
|
||||
if (ai != null && ai.getType() == InsnType.MOVE) {
|
||||
InsnArg arg = ai.getArg(0);
|
||||
if (arg != this
|
||||
&& arg.isRegister()
|
||||
&& "this".equals(((RegisterArg) arg).getName())) {
|
||||
return true;
|
||||
if (arg != this) {
|
||||
return arg.isThis();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -196,8 +201,8 @@ public class RegisterArg extends InsnArg implements Named {
|
||||
if (sVar != null) {
|
||||
sb.append("_").append(sVar.getVersion());
|
||||
}
|
||||
if (name != null) {
|
||||
sb.append(" '").append(name).append("'");
|
||||
if (getName() != null) {
|
||||
sb.append(" '").append(getName()).append("'");
|
||||
}
|
||||
sb.append(" ");
|
||||
sb.append(type);
|
||||
|
||||
@@ -9,6 +9,7 @@ public class SSAVar {
|
||||
|
||||
private final int regNum;
|
||||
private final int version;
|
||||
private VarName varName;
|
||||
|
||||
private RegisterArg assign;
|
||||
private final List<RegisterArg> useList = new ArrayList<RegisterArg>(2);
|
||||
@@ -22,7 +23,6 @@ public class SSAVar {
|
||||
this.assign = assign;
|
||||
|
||||
if (assign != null) {
|
||||
mergeName(assign);
|
||||
assign.setSVar(this);
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,6 @@ public class SSAVar {
|
||||
}
|
||||
|
||||
public void use(RegisterArg arg) {
|
||||
mergeName(arg);
|
||||
if (arg.getSVar() != null) {
|
||||
arg.getSVar().removeUse(arg);
|
||||
}
|
||||
@@ -103,35 +102,27 @@ public class SSAVar {
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
if (assign != null) {
|
||||
assign.setName(name);
|
||||
}
|
||||
for (int i = 0, useListSize = useList.size(); i < useListSize; i++) {
|
||||
useList.get(i).setName(name);
|
||||
}
|
||||
}
|
||||
|
||||
public void setVariableName(String name) {
|
||||
setName(name);
|
||||
if (isUsedInPhi()) {
|
||||
PhiInsn phi = getUsedInPhi();
|
||||
phi.getResult().getSVar().setVariableName(name);
|
||||
for (InsnArg arg : phi.getArguments()) {
|
||||
if (arg.isRegister()) {
|
||||
RegisterArg reg = (RegisterArg) arg;
|
||||
SSAVar sVar = reg.getSVar();
|
||||
if (sVar != this && !name.equals(reg.getName())) {
|
||||
sVar.setVariableName(name);
|
||||
}
|
||||
}
|
||||
if (name != null) {
|
||||
if (varName == null) {
|
||||
varName = new VarName();
|
||||
}
|
||||
varName.setName(name);
|
||||
}
|
||||
}
|
||||
|
||||
public void mergeName(RegisterArg arg) {
|
||||
if (arg.getName() != null) {
|
||||
setName(arg.getName());
|
||||
public String getName() {
|
||||
if (varName == null) {
|
||||
return null;
|
||||
}
|
||||
return varName.getName();
|
||||
}
|
||||
|
||||
public VarName getVarName() {
|
||||
return varName;
|
||||
}
|
||||
|
||||
public void setVarName(VarName varName) {
|
||||
this.varName = varName;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -28,12 +28,4 @@ public abstract class Typed {
|
||||
public boolean merge(InsnArg arg) {
|
||||
return merge(arg.getType());
|
||||
}
|
||||
|
||||
public void mergeDebugInfo(RegisterArg arg) {
|
||||
this.type = arg.getType();
|
||||
if (this instanceof Named) {
|
||||
Named n = (Named) this;
|
||||
n.setName(arg.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package jadx.core.dex.instructions.args;
|
||||
|
||||
public class VarName {
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -15,9 +15,9 @@ import jadx.core.dex.instructions.InsnDecoder;
|
||||
import jadx.core.dex.instructions.SwitchNode;
|
||||
import jadx.core.dex.instructions.args.ArgType;
|
||||
import jadx.core.dex.instructions.args.InsnArg;
|
||||
import jadx.core.dex.instructions.args.MthParameterArg;
|
||||
import jadx.core.dex.instructions.args.RegisterArg;
|
||||
import jadx.core.dex.instructions.args.SSAVar;
|
||||
import jadx.core.dex.nodes.parser.DebugInfoParser;
|
||||
import jadx.core.dex.nodes.parser.SignatureParser;
|
||||
import jadx.core.dex.regions.Region;
|
||||
import jadx.core.dex.trycatch.ExcHandlerAttr;
|
||||
@@ -51,7 +51,8 @@ public class MethodNode extends LineAttrNode implements ILoadable {
|
||||
|
||||
private final Method methodData;
|
||||
private int regsCount;
|
||||
private List<InsnNode> instructions;
|
||||
private InsnNode[] instructions;
|
||||
private int debugInfoOffset;
|
||||
private boolean noCode;
|
||||
|
||||
private ArgType retType;
|
||||
@@ -92,30 +93,12 @@ public class MethodNode extends LineAttrNode implements ILoadable {
|
||||
|
||||
InsnDecoder decoder = new InsnDecoder(this);
|
||||
decoder.decodeInsns(mthCode);
|
||||
InsnNode[] insnByOffset = decoder.process();
|
||||
instructions = new ArrayList<InsnNode>();
|
||||
for (InsnNode insn : insnByOffset) {
|
||||
if (insn != null) {
|
||||
instructions.add(insn);
|
||||
}
|
||||
}
|
||||
((ArrayList<InsnNode>) instructions).trimToSize();
|
||||
instructions = decoder.process();
|
||||
|
||||
initTryCatches(mthCode, insnByOffset);
|
||||
initJumps(insnByOffset);
|
||||
initTryCatches(mthCode);
|
||||
initJumps();
|
||||
|
||||
int debugInfoOffset = mthCode.getDebugInfoOffset();
|
||||
if (debugInfoOffset > 0) {
|
||||
DebugInfoParser debugInfoParser = new DebugInfoParser(this, debugInfoOffset, insnByOffset);
|
||||
debugInfoParser.process();
|
||||
|
||||
if (instructions.size() != 0) {
|
||||
int line = instructions.get(0).getSourceLine();
|
||||
if (line != 0) {
|
||||
this.setSourceLine(line - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.debugInfoOffset = mthCode.getDebugInfoOffset();
|
||||
} catch (Exception e) {
|
||||
if (!noCode) {
|
||||
noCode = true;
|
||||
@@ -139,9 +122,7 @@ public class MethodNode extends LineAttrNode implements ILoadable {
|
||||
if (noCode) {
|
||||
return;
|
||||
}
|
||||
if (instructions != null) {
|
||||
instructions.clear();
|
||||
}
|
||||
instructions = null;
|
||||
blocks = null;
|
||||
exitBlocks = null;
|
||||
exceptionHandlers.clear();
|
||||
@@ -199,8 +180,9 @@ public class MethodNode extends LineAttrNode implements ILoadable {
|
||||
if (accFlags.isStatic()) {
|
||||
thisArg = null;
|
||||
} else {
|
||||
thisArg = InsnArg.parameterReg(pos - 1, parentClass.getClassInfo().getType());
|
||||
thisArg.setName("this");
|
||||
MthParameterArg arg = InsnArg.parameterReg(pos - 1, parentClass.getClassInfo().getType());
|
||||
arg.markAsThis();
|
||||
thisArg = arg;
|
||||
}
|
||||
if (args.isEmpty()) {
|
||||
argsList = Collections.emptyList();
|
||||
@@ -241,7 +223,8 @@ public class MethodNode extends LineAttrNode implements ILoadable {
|
||||
return genericMap;
|
||||
}
|
||||
|
||||
private void initTryCatches(Code mthCode, InsnNode[] insnByOffset) {
|
||||
private void initTryCatches(Code mthCode) {
|
||||
InsnNode[] insnByOffset = instructions;
|
||||
CatchHandler[] catchBlocks = mthCode.getCatchHandlers();
|
||||
Try[] tries = mthCode.getTries();
|
||||
|
||||
@@ -311,9 +294,13 @@ public class MethodNode extends LineAttrNode implements ILoadable {
|
||||
}
|
||||
}
|
||||
|
||||
private void initJumps(InsnNode[] insnByOffset) {
|
||||
for (InsnNode insn : getInstructions()) {
|
||||
int offset = insn.getOffset();
|
||||
private void initJumps() {
|
||||
InsnNode[] insnByOffset = instructions;
|
||||
for (int offset = 0; offset < insnByOffset.length; offset++) {
|
||||
InsnNode insn = insnByOffset[offset];
|
||||
if (insn == null) {
|
||||
continue;
|
||||
}
|
||||
switch (insn.getType()) {
|
||||
case SWITCH: {
|
||||
SwitchNode sw = (SwitchNode) insn;
|
||||
@@ -367,20 +354,20 @@ public class MethodNode extends LineAttrNode implements ILoadable {
|
||||
return noCode;
|
||||
}
|
||||
|
||||
public List<InsnNode> getInstructions() {
|
||||
public InsnNode[] getInstructions() {
|
||||
return instructions;
|
||||
}
|
||||
|
||||
public void unloadInsnArr() {
|
||||
this.instructions = null;
|
||||
}
|
||||
|
||||
public void initBasicBlocks() {
|
||||
blocks = new ArrayList<BlockNode>();
|
||||
exitBlocks = new ArrayList<BlockNode>(1);
|
||||
}
|
||||
|
||||
public void finishBasicBlocks() {
|
||||
// after filling basic blocks we don't need instructions list anymore
|
||||
instructions.clear();
|
||||
instructions = null;
|
||||
|
||||
((ArrayList<BlockNode>) blocks).trimToSize();
|
||||
((ArrayList<BlockNode>) exitBlocks).trimToSize();
|
||||
|
||||
@@ -479,6 +466,10 @@ public class MethodNode extends LineAttrNode implements ILoadable {
|
||||
return regsCount;
|
||||
}
|
||||
|
||||
public int getDebugInfoOffset() {
|
||||
return debugInfoOffset;
|
||||
}
|
||||
|
||||
public SSAVar makeNewSVar(int regNum, int[] versions, RegisterArg arg) {
|
||||
SSAVar var = new SSAVar(regNum, versions[regNum], arg);
|
||||
versions[regNum]++;
|
||||
|
||||
@@ -226,19 +226,18 @@ public class DebugInfoParser {
|
||||
}
|
||||
|
||||
private static void fillLocals(InsnNode insn, LocalVar var) {
|
||||
if (insn.getResult() != null) {
|
||||
merge(insn.getResult(), var);
|
||||
}
|
||||
merge(insn.getResult(), var);
|
||||
for (InsnArg arg : insn.getArguments()) {
|
||||
merge(arg, var);
|
||||
}
|
||||
}
|
||||
|
||||
private static void merge(InsnArg arg, LocalVar var) {
|
||||
if (arg != null
|
||||
&& arg.isRegister()
|
||||
&& var.getRegNum() == ((RegisterArg) arg).getRegNum()) {
|
||||
arg.mergeDebugInfo(var);
|
||||
if (arg != null && arg.isRegister()) {
|
||||
RegisterArg reg = (RegisterArg) arg;
|
||||
if (var.getRegNum() == reg.getRegNum()) {
|
||||
reg.mergeDebugInfo(var.getType(), var.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,17 +8,19 @@ import jadx.core.utils.InsnUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
final class LocalVar extends RegisterArg {
|
||||
|
||||
final class LocalVar {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(LocalVar.class);
|
||||
|
||||
private boolean isEnd;
|
||||
private int regNum;
|
||||
private String name;
|
||||
private ArgType type;
|
||||
|
||||
private boolean isEnd;
|
||||
private int startAddr;
|
||||
private int endAddr;
|
||||
|
||||
public LocalVar(DexNode dex, int rn, int nameId, int typeId, int signId) {
|
||||
super(rn, ArgType.UNKNOWN);
|
||||
this.regNum = rn;
|
||||
String name = (nameId == DexNode.NO_INDEX ? null : dex.getString(nameId));
|
||||
ArgType type = (typeId == DexNode.NO_INDEX ? null : dex.getType(typeId));
|
||||
String sign = (signId == DexNode.NO_INDEX ? null : dex.getString(signId));
|
||||
@@ -27,7 +29,7 @@ final class LocalVar extends RegisterArg {
|
||||
}
|
||||
|
||||
public LocalVar(RegisterArg arg) {
|
||||
super(arg.getRegNum(), arg.getType());
|
||||
this.regNum = arg.getRegNum();
|
||||
init(arg.getName(), arg.getType(), null);
|
||||
}
|
||||
|
||||
@@ -42,8 +44,8 @@ final class LocalVar extends RegisterArg {
|
||||
LOG.error("Can't parse signature for local variable: " + sign, e);
|
||||
}
|
||||
}
|
||||
setName(name);
|
||||
forceType(type);
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
private boolean checkSignature(ArgType type, String sign, ArgType gType) {
|
||||
@@ -72,6 +74,18 @@ final class LocalVar extends RegisterArg {
|
||||
this.endAddr = addr;
|
||||
}
|
||||
|
||||
public int getRegNum() {
|
||||
return regNum;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public ArgType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public boolean isEnd() {
|
||||
return isEnd;
|
||||
}
|
||||
|
||||
@@ -60,6 +60,9 @@ public class BlockMakerVisitor extends AbstractVisitor {
|
||||
|
||||
// split into blocks
|
||||
for (InsnNode insn : mth.getInstructions()) {
|
||||
if (insn == null) {
|
||||
continue;
|
||||
}
|
||||
boolean startNew = false;
|
||||
if (prevInsn != null) {
|
||||
InsnType type = prevInsn.getType();
|
||||
@@ -443,10 +446,18 @@ public class BlockMakerVisitor extends AbstractVisitor {
|
||||
if (returnInsn.getArgsCount() != 0 && !isReturnArgAssignInPred(preds, returnInsn)) {
|
||||
return false;
|
||||
}
|
||||
boolean first = true;
|
||||
for (BlockNode pred : preds) {
|
||||
BlockNode newRetBlock = startNewBlock(mth, exitBlock.getStartOffset());
|
||||
newRetBlock.add(AFlag.SYNTHETIC);
|
||||
newRetBlock.getInstructions().add(duplicateReturnInsn(returnInsn));
|
||||
InsnNode newRetInsn;
|
||||
if (first) {
|
||||
newRetInsn = returnInsn;
|
||||
first = false;
|
||||
} else {
|
||||
newRetInsn = duplicateReturnInsn(returnInsn);
|
||||
}
|
||||
newRetBlock.getInstructions().add(newRetInsn);
|
||||
removeConnection(pred, exitBlock);
|
||||
connect(pred, newRetBlock);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package jadx.core.dex.visitors;
|
||||
|
||||
import jadx.core.dex.instructions.args.ArgType;
|
||||
import jadx.core.dex.instructions.args.RegisterArg;
|
||||
import jadx.core.dex.nodes.BlockNode;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
import jadx.core.dex.nodes.parser.DebugInfoParser;
|
||||
import jadx.core.utils.exceptions.JadxException;
|
||||
|
||||
public class DebugInfoVisitor extends AbstractVisitor {
|
||||
@Override
|
||||
public void visit(MethodNode mth) throws JadxException {
|
||||
int debugOffset = mth.getDebugInfoOffset();
|
||||
if (debugOffset > 0) {
|
||||
InsnNode[] insnArr = mth.getInstructions();
|
||||
DebugInfoParser debugInfoParser = new DebugInfoParser(mth, debugOffset, insnArr);
|
||||
debugInfoParser.process();
|
||||
|
||||
if (insnArr.length != 0) {
|
||||
int line = insnArr[0].getSourceLine();
|
||||
if (line != 0) {
|
||||
mth.setSourceLine(line - 1);
|
||||
}
|
||||
}
|
||||
if (!mth.getReturnType().equals(ArgType.VOID)
|
||||
&& mth.getExitBlocks().size() > 1) {
|
||||
// fix debug for splitter 'return' instructions
|
||||
for (BlockNode exit : mth.getExitBlocks()) {
|
||||
InsnNode ret = exit.getInstructions().get(0);
|
||||
InsnNode oldRet = insnArr[ret.getOffset()];
|
||||
if (oldRet != ret) {
|
||||
RegisterArg oldArg = (RegisterArg) oldRet.getArg(0);
|
||||
RegisterArg newArg = (RegisterArg) ret.getArg(0);
|
||||
newArg.mergeDebugInfo(oldArg.getType(), oldArg.getName());
|
||||
ret.setSourceLine(oldRet.getSourceLine());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mth.unloadInsnArr();
|
||||
}
|
||||
}
|
||||
@@ -211,7 +211,9 @@ public class DotGraphVisitor extends AbstractVisitor {
|
||||
return str.toString();
|
||||
} else {
|
||||
CodeWriter code = new CodeWriter();
|
||||
MethodGen.addFallbackInsns(code, mth, block.getInstructions(), false);
|
||||
List<InsnNode> instructions = block.getInstructions();
|
||||
MethodGen.addFallbackInsns(code, mth,
|
||||
instructions.toArray(new InsnNode[instructions.size()]), false);
|
||||
String str = escape(code.newLine().toString());
|
||||
if (str.startsWith(NL)) {
|
||||
str = str.substring(NL.length());
|
||||
|
||||
@@ -14,6 +14,9 @@ public class FallbackModeVisitor extends AbstractVisitor {
|
||||
return;
|
||||
}
|
||||
for (InsnNode insn : mth.getInstructions()) {
|
||||
if (insn == null) {
|
||||
continue;
|
||||
}
|
||||
// remove 'exception catch' for instruction which don't throw any exceptions
|
||||
CatchAttr catchAttr = insn.get(AType.CATCH_BLOCK);
|
||||
if (catchAttr != null) {
|
||||
|
||||
@@ -5,6 +5,7 @@ import jadx.core.dex.attributes.AType;
|
||||
import jadx.core.dex.attributes.nodes.DeclareVariablesAttr;
|
||||
import jadx.core.dex.instructions.args.ArgType;
|
||||
import jadx.core.dex.instructions.args.RegisterArg;
|
||||
import jadx.core.dex.instructions.args.VarName;
|
||||
import jadx.core.dex.nodes.IBlock;
|
||||
import jadx.core.dex.nodes.IContainer;
|
||||
import jadx.core.dex.nodes.IRegion;
|
||||
@@ -66,6 +67,7 @@ public class ProcessVariables extends AbstractVisitor {
|
||||
|
||||
private static class Usage {
|
||||
private RegisterArg arg;
|
||||
private VarName varName;
|
||||
private IRegion argRegion;
|
||||
private final Set<IRegion> usage = new HashSet<IRegion>(2);
|
||||
private final Set<IRegion> assigns = new HashSet<IRegion>(2);
|
||||
@@ -78,6 +80,14 @@ public class ProcessVariables extends AbstractVisitor {
|
||||
return arg;
|
||||
}
|
||||
|
||||
public VarName getVarName() {
|
||||
return varName;
|
||||
}
|
||||
|
||||
public void setVarName(VarName varName) {
|
||||
this.varName = varName;
|
||||
}
|
||||
|
||||
public void setArgRegion(IRegion argRegion) {
|
||||
this.argRegion = argRegion;
|
||||
}
|
||||
@@ -102,7 +112,14 @@ public class ProcessVariables extends AbstractVisitor {
|
||||
|
||||
@Override
|
||||
public void visit(MethodNode mth) throws JadxException {
|
||||
if (mth.isNoCode()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Map<Variable, Usage> usageMap = new LinkedHashMap<Variable, Usage>();
|
||||
for (RegisterArg arg : mth.getArguments(true)) {
|
||||
addToUsageMap(arg, usageMap);
|
||||
}
|
||||
|
||||
// collect all variables usage
|
||||
IRegionVisitor collect = new TracedRegionVisitor() {
|
||||
@@ -210,6 +227,17 @@ public class ProcessVariables extends AbstractVisitor {
|
||||
usage = new Usage();
|
||||
usageMap.put(varId, usage);
|
||||
}
|
||||
// merge variables names
|
||||
if (usage.getVarName() == null) {
|
||||
VarName argVN = arg.getSVar().getVarName();
|
||||
if (argVN == null) {
|
||||
argVN = new VarName();
|
||||
arg.getSVar().setVarName(argVN);
|
||||
}
|
||||
usage.setVarName(argVN);
|
||||
} else {
|
||||
arg.getSVar().setVarName(usage.getVarName());
|
||||
}
|
||||
return usage;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package jadx.core.dex.visitors.ssa;
|
||||
import jadx.core.dex.attributes.AType;
|
||||
import jadx.core.dex.attributes.nodes.PhiListAttr;
|
||||
import jadx.core.dex.instructions.PhiInsn;
|
||||
import jadx.core.dex.instructions.args.SSAVar;
|
||||
import jadx.core.dex.nodes.BlockNode;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
@@ -19,56 +18,9 @@ public class EliminatePhiNodes extends AbstractVisitor {
|
||||
if (mth.isNoCode()) {
|
||||
return;
|
||||
}
|
||||
enumerateSVars(mth);
|
||||
removePhiInstructions(mth);
|
||||
}
|
||||
|
||||
public static void enumerateSVars(MethodNode mth) {
|
||||
for (SSAVar sVar : mth.getSVars()) {
|
||||
if (sVar.isUsedInPhi()) {
|
||||
sVar.mergeName(sVar.getUsedInPhi().getResult());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// public static void enumerateSVars(MethodNode mth) {
|
||||
// List<SSAVar> vars = mth.getSVars();
|
||||
// int varsSize = vars.size();
|
||||
// Deque<SSAVar> workList = new LinkedList<SSAVar>();
|
||||
// for (int i = 0; i < varsSize; i++) {
|
||||
// SSAVar ssaVar = vars.get(i);
|
||||
// ssaVar.setVarId(i);
|
||||
// if (ssaVar.isUsedInPhi()) {
|
||||
// workList.add(ssaVar);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// int k = 0;
|
||||
// while (!workList.isEmpty()) {
|
||||
// SSAVar var = workList.pop();
|
||||
// RegisterArg assignVar = var.getUsedInPhi().getResult();
|
||||
// // set same name and variable ID
|
||||
// var.mergeName(assignVar);
|
||||
// SSAVar assignSVar = assignVar.getSVar();
|
||||
// int varId = assignSVar.getVarId();
|
||||
// var.setVarId(varId);
|
||||
//
|
||||
// if (assignSVar.isUsedInPhi()) {
|
||||
// PhiInsn assignPhi = assignSVar.getUsedInPhi();
|
||||
// SSAVar asVar = assignPhi.getResult().getSVar();
|
||||
// if (asVar.getVarId() != varId) {
|
||||
// asVar.setVarId(varId);
|
||||
// for (int i = 0; i < assignPhi.getArgsCount(); i++) {
|
||||
// workList.push(assignPhi.getArg(i).getSVar());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if (k++ > 1000) {
|
||||
// throw new JadxRuntimeException("Can't calculate variable id");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
private static void removePhiInstructions(MethodNode mth) {
|
||||
for (BlockNode block : mth.getBasicBlocks()) {
|
||||
PhiListAttr phiList = block.get(AType.PHI_LIST);
|
||||
|
||||
@@ -32,7 +32,7 @@ public class SSATransform extends AbstractVisitor {
|
||||
process(mth);
|
||||
}
|
||||
|
||||
public void process(MethodNode mth) {
|
||||
private void process(MethodNode mth) {
|
||||
LiveVarAnalysis la = new LiveVarAnalysis(mth);
|
||||
la.runAnalysis();
|
||||
for (int i = 0; i < mth.getRegsCount(); i++) {
|
||||
|
||||
@@ -82,7 +82,7 @@ public class TypeInference extends AbstractVisitor {
|
||||
for (int i = 0; i < phi.getArgsCount(); i++) {
|
||||
RegisterArg arg = phi.getArg(i);
|
||||
arg.setType(type);
|
||||
arg.getSVar().mergeName(phi.getResult());
|
||||
arg.getSVar().setName(phi.getResult().getName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,8 +31,8 @@ public class TestInline2 extends InternalJadxTest {
|
||||
System.out.println(code);
|
||||
|
||||
assertThat(code, containsString("i < a.length"));
|
||||
assertThat(code, containsString("long i_2 ="));
|
||||
assertThat(code, containsString("+ i_2"));
|
||||
assertThat(code, containsString("i_2--;"));
|
||||
assertThat(code, containsString("long i2 ="));
|
||||
assertThat(code, containsString("+ i2"));
|
||||
assertThat(code, containsString("i2--;"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,8 +36,9 @@ public abstract class AbstractTest {
|
||||
|
||||
public static void assertEquals(Object a1, Object a2) {
|
||||
if (a1 == null) {
|
||||
if (a2 != null)
|
||||
if (a2 != null) {
|
||||
throw new AssertionError(a1 + " != " + a2);
|
||||
}
|
||||
} else if (!a1.equals(a2)) {
|
||||
throw new AssertionError(a1 + " != " + a2);
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ public class TestAnnotations extends AbstractTest {
|
||||
@MyAnnotation(name = "b",
|
||||
num = 7,
|
||||
cls = Exception.class,
|
||||
doubles = { 0.0, 1.1 },
|
||||
doubles = {0.0, 1.1},
|
||||
value = 9.87f,
|
||||
simple = @SimpleAnnotation(false))
|
||||
public static Object test(String[] a) {
|
||||
|
||||
@@ -22,10 +22,11 @@ public class TestCF extends AbstractTest {
|
||||
|
||||
public int test1b(int a) {
|
||||
if (a > 0) {
|
||||
if (a < 5)
|
||||
if (a < 5) {
|
||||
a++;
|
||||
else
|
||||
} else {
|
||||
a -= 2;
|
||||
}
|
||||
}
|
||||
a *= 2;
|
||||
return a + 3;
|
||||
@@ -134,16 +135,17 @@ public class TestCF extends AbstractTest {
|
||||
|
||||
public int testIfElse(String str) {
|
||||
int r;
|
||||
if (str.equals("a"))
|
||||
if (str.equals("a")) {
|
||||
r = 1;
|
||||
else if (str.equals("b"))
|
||||
} else if (str.equals("b")) {
|
||||
r = 2;
|
||||
else if (str.equals("3"))
|
||||
} else if (str.equals("3")) {
|
||||
r = 3;
|
||||
else if (str.equals("$"))
|
||||
} else if (str.equals("$")) {
|
||||
r = 4;
|
||||
else
|
||||
} else {
|
||||
r = -1;
|
||||
}
|
||||
|
||||
r = r * 10;
|
||||
return Math.abs(r);
|
||||
|
||||
@@ -5,7 +5,7 @@ public class TestCF2 extends AbstractTest {
|
||||
private boolean ready = false;
|
||||
|
||||
public int simple_loops() throws InterruptedException {
|
||||
int[] a = new int[] { 1, 2, 4, 6, 8 };
|
||||
int[] a = new int[]{1, 2, 4, 6, 8};
|
||||
int b = 0;
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
b += a[i];
|
||||
@@ -21,8 +21,9 @@ public class TestCF2 extends AbstractTest {
|
||||
*/
|
||||
public void run() throws InterruptedException {
|
||||
while (true) {
|
||||
if (!ready)
|
||||
if (!ready) {
|
||||
ready_mutex.wait();
|
||||
}
|
||||
ready = false;
|
||||
func();
|
||||
}
|
||||
@@ -88,8 +89,9 @@ public class TestCF2 extends AbstractTest {
|
||||
public void do_while_return2(boolean k) throws InterruptedException {
|
||||
int i = 3;
|
||||
do {
|
||||
if (k)
|
||||
if (k) {
|
||||
return;
|
||||
}
|
||||
i++;
|
||||
} while (i < 5);
|
||||
}
|
||||
|
||||
@@ -3,8 +3,9 @@ package jadx.samples;
|
||||
public class TestDeadCode extends AbstractTest {
|
||||
|
||||
private void test1(int i) {
|
||||
if (i == 0)
|
||||
if (i == 0) {
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ public class TestGenerics extends AbstractTest {
|
||||
public static boolean use() {
|
||||
Pair<Integer, String> p1 = new OrderedPair<Integer, String>(1, "str1");
|
||||
Pair<Integer, String> p2 = new OrderedPair<Integer, String>(2, "str2");
|
||||
boolean same = Util.<Integer, String> compare(p1, p2);
|
||||
boolean same = Util.<Integer, String>compare(p1, p2);
|
||||
return same;
|
||||
}
|
||||
|
||||
@@ -107,9 +107,11 @@ public class TestGenerics extends AbstractTest {
|
||||
|
||||
public static <T extends Comparable<T>> int countGreaterThan(T[] anArray, T elem) {
|
||||
int count = 0;
|
||||
for (T e : anArray)
|
||||
if (e.compareTo(elem) > 0)
|
||||
for (T e : anArray) {
|
||||
if (e.compareTo(elem) > 0) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
@@ -117,8 +119,9 @@ public class TestGenerics extends AbstractTest {
|
||||
}
|
||||
|
||||
public static void printList(List<?> list) {
|
||||
for (Object elem : list)
|
||||
for (Object elem : list) {
|
||||
System.out.print(elem + " ");
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@ public class TestInner extends AbstractTest {
|
||||
{
|
||||
count += 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
count += 6;
|
||||
@@ -68,6 +69,7 @@ public class TestInner extends AbstractTest {
|
||||
{
|
||||
count += 7;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
count += 8;
|
||||
|
||||
@@ -73,7 +73,7 @@ public class TestInner2 extends AbstractTest {
|
||||
|
||||
Method[] mths = TestInner2.class.getDeclaredMethods();
|
||||
for (Method mth : mths) {
|
||||
if(mth.getName().startsWith("access$")) {
|
||||
if (mth.getName().startsWith("access$")) {
|
||||
int modifiers = mth.getModifiers();
|
||||
assertTrue((modifiers & SYNTHETIC) != 0, "Synthetic methods must be removed");
|
||||
}
|
||||
|
||||
@@ -14,10 +14,11 @@ public class TestInvoke extends AbstractTest {
|
||||
}
|
||||
|
||||
private void parse(String[] args) {
|
||||
if (args.length > 0)
|
||||
if (args.length > 0) {
|
||||
f = Integer.parseInt(args[0]);
|
||||
else
|
||||
} else {
|
||||
f = 20;
|
||||
}
|
||||
}
|
||||
|
||||
public int getF() {
|
||||
@@ -37,18 +38,26 @@ public class TestInvoke extends AbstractTest {
|
||||
return s;
|
||||
}
|
||||
|
||||
private String testSameArgTypes(String s1, String s2) {
|
||||
if (s1.equals(s2)) {
|
||||
return null;
|
||||
}
|
||||
return s1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean testRun() throws Exception {
|
||||
TestInvoke inv = new TestInvoke();
|
||||
|
||||
inv.parse(new String[] { "12", "35" });
|
||||
inv.parse(new String[]{"12", "35"});
|
||||
assertTrue(inv.getF() == 12);
|
||||
inv.parse(new String[0]);
|
||||
assertTrue(inv.getF() == 20);
|
||||
|
||||
assertTrue(inv.testVarArgs("a", "2", "III"));
|
||||
assertTrue(inv.testVarArgs2("a".toCharArray(), new char[] { '1', '2' }).equals("a12"));
|
||||
assertTrue(inv.testVarArgs2("a".toCharArray(), new char[]{'1', '2'}).equals("a12"));
|
||||
|
||||
assertEquals(testSameArgTypes("a", "b"), "a");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,10 +43,11 @@ public class TestSwitch extends AbstractTest {
|
||||
int k = i;
|
||||
switch (k) {
|
||||
case 1:
|
||||
if (j == 0)
|
||||
if (j == 0) {
|
||||
return 0;
|
||||
else
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
case 2:
|
||||
return 1;
|
||||
}
|
||||
@@ -69,8 +70,9 @@ public class TestSwitch extends AbstractTest {
|
||||
int k = i;
|
||||
switch (k) {
|
||||
case 1:
|
||||
if (b == 0)
|
||||
if (b == 0) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
case 2:
|
||||
b++;
|
||||
|
||||
@@ -5,14 +5,16 @@ import java.io.IOException;
|
||||
public class TestTryCatch extends AbstractTest {
|
||||
|
||||
private static boolean exc(Object obj) throws Exception {
|
||||
if (obj == null)
|
||||
if (obj == null) {
|
||||
throw new Exception("test");
|
||||
}
|
||||
return (obj instanceof Object);
|
||||
}
|
||||
|
||||
private static boolean exc2(Object obj) throws IOException {
|
||||
if (obj == null)
|
||||
if (obj == null) {
|
||||
throw new IOException();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -41,10 +43,11 @@ public class TestTryCatch extends AbstractTest {
|
||||
try {
|
||||
return exc(obj);
|
||||
} catch (Exception e) {
|
||||
if (obj != null)
|
||||
if (obj != null) {
|
||||
return true;
|
||||
else
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,8 +81,9 @@ public class TestTryCatch extends AbstractTest {
|
||||
try {
|
||||
res = "" + exc(obj);
|
||||
boolean f = exc2("a");
|
||||
if (!f)
|
||||
if (!f) {
|
||||
res = "f == false";
|
||||
}
|
||||
} catch (Exception e) {
|
||||
res = "exc";
|
||||
}
|
||||
@@ -95,8 +99,9 @@ public class TestTryCatch extends AbstractTest {
|
||||
} catch (IOException e) {
|
||||
res = true;
|
||||
} catch (Throwable e) {
|
||||
if (obj == null)
|
||||
if (obj == null) {
|
||||
obj = new Object();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,8 +117,9 @@ public class TestTryCatch extends AbstractTest {
|
||||
res = true;
|
||||
obj = new Object();
|
||||
} catch (Throwable e) {
|
||||
if (obj == null)
|
||||
if (obj == null) {
|
||||
res = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -137,16 +143,18 @@ public class TestTryCatch extends AbstractTest {
|
||||
} catch (Exception e) {
|
||||
e.toString();
|
||||
} finally {
|
||||
if (!mDiscovering)
|
||||
if (!mDiscovering) {
|
||||
mDiscovering = true;
|
||||
}
|
||||
}
|
||||
return mDiscovering;
|
||||
}
|
||||
|
||||
private static boolean testSynchronize(Object obj) throws InterruptedException {
|
||||
synchronized (obj) {
|
||||
if (obj instanceof String)
|
||||
if (obj instanceof String) {
|
||||
return false;
|
||||
}
|
||||
obj.wait(5);
|
||||
}
|
||||
return true;
|
||||
@@ -171,8 +179,9 @@ public class TestTryCatch extends AbstractTest {
|
||||
public int catchInLoop(int i, int j) {
|
||||
while (true) {
|
||||
try {
|
||||
while (i < j)
|
||||
while (i < j) {
|
||||
i = j++ / i;
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
i = 10;
|
||||
continue;
|
||||
|
||||
@@ -7,7 +7,7 @@ package jadx.samples;
|
||||
*/
|
||||
public class TestTypeResolver2 extends AbstractTest {
|
||||
|
||||
private static String result = "";
|
||||
private static String result = "";
|
||||
|
||||
public void testOverloadedMethods() {
|
||||
Object s1 = "The";
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
rootProject.name = 'jadx'
|
||||
|
||||
include 'jadx-core', 'jadx-samples', 'jadx-cli', 'jadx-gui'
|
||||
|
||||
Reference in New Issue
Block a user