refactor: remove deprecated methods
This commit is contained in:
@@ -151,8 +151,7 @@ public class AnnotationGen {
|
||||
code.add(InsnGen.makeStaticFieldAccess(field, classGen));
|
||||
} else if (val instanceof List) {
|
||||
code.add('{');
|
||||
List list = (List) val;
|
||||
Iterator it = list.iterator();
|
||||
Iterator<?> it = ((List) val).iterator();
|
||||
while (it.hasNext()) {
|
||||
Object obj = it.next();
|
||||
encodeValue(code, obj);
|
||||
|
||||
@@ -43,6 +43,7 @@ public class ClassGen {
|
||||
private final boolean fallback;
|
||||
|
||||
private final Set<ClassInfo> imports = new HashSet<ClassInfo>();
|
||||
private int clsDeclLine = 0;
|
||||
|
||||
public ClassGen(ClassNode cls, ClassGen parentClsGen, boolean fallback) {
|
||||
this.cls = cls;
|
||||
@@ -95,12 +96,11 @@ public class ClassGen {
|
||||
if (cls.getAttributes().contains(AttributeFlag.INCONSISTENT_CODE)) {
|
||||
code.startLine("// jadx: inconsistent code");
|
||||
}
|
||||
makeClassDeclaration(code);
|
||||
makeClassBody(code);
|
||||
code.newLine();
|
||||
addClassDeclaration(code);
|
||||
addClassBody(code);
|
||||
}
|
||||
|
||||
public void makeClassDeclaration(CodeWriter clsCode) {
|
||||
public void addClassDeclaration(CodeWriter clsCode) {
|
||||
AccessInfo af = cls.getAccessFlags();
|
||||
if (af.isInterface()) {
|
||||
af = af.remove(AccessFlags.ACC_ABSTRACT);
|
||||
@@ -123,7 +123,7 @@ public class ClassGen {
|
||||
}
|
||||
clsCode.add(cls.getShortName());
|
||||
|
||||
makeGenericMap(clsCode, cls.getGenericMap());
|
||||
addGenericMap(clsCode, cls.getGenericMap());
|
||||
clsCode.add(' ');
|
||||
|
||||
ClassInfo sup = cls.getSuperClass();
|
||||
@@ -150,11 +150,10 @@ public class ClassGen {
|
||||
clsCode.add(' ');
|
||||
}
|
||||
}
|
||||
|
||||
clsCode.attachDefinition(cls);
|
||||
}
|
||||
|
||||
public boolean makeGenericMap(CodeWriter code, Map<ArgType, List<ArgType>> gmap) {
|
||||
public boolean addGenericMap(CodeWriter code, Map<ArgType, List<ArgType>> gmap) {
|
||||
if (gmap == null || gmap.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
@@ -183,91 +182,78 @@ public class ClassGen {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void makeClassBody(CodeWriter clsCode) throws CodegenException {
|
||||
public void addClassBody(CodeWriter clsCode) throws CodegenException {
|
||||
clsCode.add('{');
|
||||
CodeWriter mthsCode = makeMethods(clsCode, cls.getMethods());
|
||||
CodeWriter fieldsCode = makeFields(clsCode, cls, cls.getFields());
|
||||
clsCode.add(fieldsCode);
|
||||
if (fieldsCode.notEmpty() && mthsCode.notEmpty()) {
|
||||
clsCode.newLine();
|
||||
}
|
||||
// insert inner classes code
|
||||
if (cls.getInnerClasses().size() != 0) {
|
||||
clsCode.add(makeInnerClasses(cls, clsCode.getIndent()));
|
||||
if (mthsCode.notEmpty()) {
|
||||
clsCode.newLine();
|
||||
}
|
||||
}
|
||||
clsCode.add(mthsCode);
|
||||
clsDeclLine = clsCode.getLine();
|
||||
clsCode.incIndent();
|
||||
addFields(clsCode);
|
||||
addInnerClasses(clsCode, cls);
|
||||
addMethods(clsCode);
|
||||
clsCode.decIndent();
|
||||
clsCode.startLine('}');
|
||||
}
|
||||
|
||||
private CodeWriter makeInnerClasses(ClassNode cls, int indent) throws CodegenException {
|
||||
CodeWriter innerClsCode = new CodeWriter(indent + 1);
|
||||
for (ClassNode inCls : cls.getInnerClasses()) {
|
||||
if (!inCls.isAnonymous()) {
|
||||
ClassGen inClGen = new ClassGen(inCls, parentGen == null ? this : parentGen, fallback);
|
||||
inClGen.addClassCode(innerClsCode);
|
||||
private void addInnerClasses(CodeWriter code, ClassNode cls) throws CodegenException {
|
||||
for (ClassNode innerCls : cls.getInnerClasses()) {
|
||||
if (!innerCls.isAnonymous()) {
|
||||
ClassGen inClGen = new ClassGen(innerCls, getParentGen(), fallback);
|
||||
code.newLine();
|
||||
inClGen.addClassCode(code);
|
||||
imports.addAll(inClGen.getImports());
|
||||
}
|
||||
}
|
||||
return innerClsCode;
|
||||
}
|
||||
|
||||
private CodeWriter makeMethods(CodeWriter clsCode, List<MethodNode> mthList) {
|
||||
CodeWriter code = new CodeWriter(clsCode.getIndent() + 1);
|
||||
for (Iterator<MethodNode> it = mthList.iterator(); it.hasNext(); ) {
|
||||
MethodNode mth = it.next();
|
||||
if (mth.getAttributes().contains(AttributeFlag.DONT_GENERATE)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
if (mth.getAccessFlags().isAbstract() || mth.getAccessFlags().isNative()) {
|
||||
MethodGen mthGen = new MethodGen(this, mth);
|
||||
mthGen.addDefinition(code);
|
||||
if (cls.getAccessFlags().isAnnotation()) {
|
||||
Object def = annotationGen.getAnnotationDefaultValue(mth.getName());
|
||||
if (def != null) {
|
||||
code.add(" default ");
|
||||
annotationGen.encodeValue(code, def);
|
||||
}
|
||||
private void addMethods(CodeWriter code) {
|
||||
for (MethodNode mth : cls.getMethods()) {
|
||||
if (!mth.getAttributes().contains(AttributeFlag.DONT_GENERATE)) {
|
||||
try {
|
||||
if (code.getLine() != clsDeclLine) {
|
||||
code.newLine();
|
||||
}
|
||||
code.add(';');
|
||||
} else {
|
||||
MethodGen mthGen = new MethodGen(this, mth);
|
||||
boolean badCode = mth.getAttributes().contains(AttributeFlag.INCONSISTENT_CODE);
|
||||
if (badCode) {
|
||||
code.startLine("/* JADX WARNING: inconsistent code. */");
|
||||
code.startLine("/* Code decompiled incorrectly, please refer to instructions dump. */");
|
||||
LOG.error(ErrorsCounter.formatErrorMsg(mth, " Inconsistent code"));
|
||||
}
|
||||
if (mthGen.addDefinition(code)) {
|
||||
code.add(' ');
|
||||
}
|
||||
code.add('{');
|
||||
code.incIndent();
|
||||
insertSourceFileInfo(code, mth);
|
||||
mthGen.addInstructions(code);
|
||||
code.decIndent();
|
||||
code.startLine('}');
|
||||
addMethod(code, mth);
|
||||
} catch (Exception e) {
|
||||
String msg = ErrorsCounter.methodError(mth, "Method generation error", e);
|
||||
code.startLine("/* " + msg + CodeWriter.NL + Utils.getStackTrace(e) + " */");
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
String msg = ErrorsCounter.methodError(mth, "Method generation error", e);
|
||||
code.startLine("/* " + msg + CodeWriter.NL + Utils.getStackTrace(e) + " */");
|
||||
}
|
||||
if (it.hasNext()) {
|
||||
code.newLine();
|
||||
}
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
private CodeWriter makeFields(CodeWriter clsCode, ClassNode cls, List<FieldNode> fields) throws CodegenException {
|
||||
CodeWriter code = new CodeWriter(clsCode.getIndent() + 1);
|
||||
private void addMethod(CodeWriter code, MethodNode mth) throws CodegenException {
|
||||
MethodGen mthGen = new MethodGen(this, mth);
|
||||
if (mth.getAccessFlags().isAbstract() || mth.getAccessFlags().isNative()) {
|
||||
mthGen.addDefinition(code);
|
||||
if (cls.getAccessFlags().isAnnotation()) {
|
||||
Object def = annotationGen.getAnnotationDefaultValue(mth.getName());
|
||||
if (def != null) {
|
||||
code.add(" default ");
|
||||
annotationGen.encodeValue(code, def);
|
||||
}
|
||||
}
|
||||
code.add(';');
|
||||
} else {
|
||||
boolean badCode = mth.getAttributes().contains(AttributeFlag.INCONSISTENT_CODE);
|
||||
if (badCode) {
|
||||
code.startLine("/* JADX WARNING: inconsistent code. */");
|
||||
code.startLine("/* Code decompiled incorrectly, please refer to instructions dump. */");
|
||||
LOG.error(ErrorsCounter.formatErrorMsg(mth, " Inconsistent code"));
|
||||
}
|
||||
if (mthGen.addDefinition(code)) {
|
||||
code.add(' ');
|
||||
}
|
||||
code.add('{');
|
||||
code.incIndent();
|
||||
insertSourceFileInfo(code, mth);
|
||||
mthGen.addInstructions(code);
|
||||
code.decIndent();
|
||||
code.startLine('}');
|
||||
}
|
||||
}
|
||||
|
||||
addEnumFields(cls, code);
|
||||
|
||||
for (FieldNode f : fields) {
|
||||
private void addFields(CodeWriter code) throws CodegenException {
|
||||
addEnumFields(code);
|
||||
for (FieldNode f : cls.getFields()) {
|
||||
if (f.getAttributes().contains(AttributeFlag.DONT_GENERATE)) {
|
||||
continue;
|
||||
}
|
||||
@@ -288,10 +274,9 @@ public class ClassGen {
|
||||
code.add(';');
|
||||
code.attachDefinition(f);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
private void addEnumFields(ClassNode cls, CodeWriter code) throws CodegenException {
|
||||
private void addEnumFields(CodeWriter code) throws CodegenException {
|
||||
EnumClassAttr enumFields = (EnumClassAttr) cls.getAttributes().get(AttributeType.ENUM_CLASS);
|
||||
if (enumFields != null) {
|
||||
InsnGen igen = null;
|
||||
@@ -305,7 +290,7 @@ public class ClassGen {
|
||||
if (igen == null) {
|
||||
// don't init mth gen if this is simple enum
|
||||
MethodGen mthGen = new MethodGen(this, enumFields.getStaticMethod());
|
||||
igen = new InsnGen(mthGen, enumFields.getStaticMethod(), false);
|
||||
igen = new InsnGen(mthGen, false);
|
||||
}
|
||||
igen.addArg(code, arg);
|
||||
if (aIt.hasNext()) {
|
||||
@@ -315,7 +300,7 @@ public class ClassGen {
|
||||
code.add(')');
|
||||
}
|
||||
if (f.getCls() != null) {
|
||||
new ClassGen(f.getCls(), this, fallback).makeClassBody(code);
|
||||
new ClassGen(f.getCls(), this, fallback).addClassBody(code);
|
||||
}
|
||||
if (it.hasNext()) {
|
||||
code.add(',');
|
||||
|
||||
@@ -95,21 +95,15 @@ public class CodeWriter {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public CodeWriter add(CodeWriter code) {
|
||||
CodeWriter add(CodeWriter code) {
|
||||
line--;
|
||||
for (Map.Entry<CodePosition, Object> entry : code.annotations.entrySet()) {
|
||||
CodePosition pos = entry.getKey();
|
||||
attachAnnotation(entry.getValue(), new CodePosition(line + pos.getLine(), pos.getOffset()));
|
||||
}
|
||||
line += code.line;
|
||||
String str = code.toString();
|
||||
buf.append(str);
|
||||
if (str.contains(NL)) {
|
||||
offset = code.offset;
|
||||
} else {
|
||||
offset += code.offset;
|
||||
}
|
||||
offset = code.offset;
|
||||
buf.append(code);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -143,6 +137,10 @@ public class CodeWriter {
|
||||
}
|
||||
}
|
||||
|
||||
public int getLine() {
|
||||
return line;
|
||||
}
|
||||
|
||||
public int getIndent() {
|
||||
return indent;
|
||||
}
|
||||
|
||||
@@ -12,41 +12,52 @@ import jadx.core.dex.regions.Compare;
|
||||
import jadx.core.dex.regions.IfCondition;
|
||||
import jadx.core.utils.ErrorsCounter;
|
||||
import jadx.core.utils.exceptions.CodegenException;
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ConditionGen {
|
||||
public class ConditionGen extends InsnGen {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ConditionGen.class);
|
||||
|
||||
static String make(InsnGen insnGen, IfCondition condition) throws CodegenException {
|
||||
public ConditionGen(InsnGen insnGen) {
|
||||
super(insnGen.mgen, insnGen.fallback);
|
||||
}
|
||||
|
||||
void add(CodeWriter code, IfCondition condition) throws CodegenException {
|
||||
switch (condition.getMode()) {
|
||||
case COMPARE:
|
||||
return makeCompare(insnGen, condition.getCompare());
|
||||
addCompare(code, condition.getCompare());
|
||||
break;
|
||||
|
||||
case NOT:
|
||||
return "!(" + make(insnGen, condition.getArgs().get(0)) + ")";
|
||||
addNot(code, condition);
|
||||
break;
|
||||
|
||||
case AND:
|
||||
case OR:
|
||||
String mode = condition.getMode() == IfCondition.Mode.AND ? " && " : " || ";
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (IfCondition arg : condition.getArgs()) {
|
||||
if (sb.length() != 0) {
|
||||
sb.append(mode);
|
||||
}
|
||||
String s = make(insnGen, arg);
|
||||
if (arg.isCompare()) {
|
||||
sb.append(s);
|
||||
} else {
|
||||
sb.append('(').append(s).append(')');
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
addAndOr(code, condition);
|
||||
break;
|
||||
|
||||
default:
|
||||
return "??" + condition;
|
||||
throw new JadxRuntimeException("Unknown condition mode: " + condition);
|
||||
}
|
||||
}
|
||||
|
||||
private static String makeCompare(InsnGen insnGen, Compare compare) throws CodegenException {
|
||||
void wrap(CodeWriter code, IfCondition cond) throws CodegenException {
|
||||
boolean wrap = isWrapNeeded(cond);
|
||||
if (wrap) {
|
||||
code.add('(');
|
||||
}
|
||||
add(code, cond);
|
||||
if (wrap) {
|
||||
code.add(')');
|
||||
}
|
||||
}
|
||||
|
||||
private void addCompare(CodeWriter code, Compare compare) throws CodegenException {
|
||||
IfOp op = compare.getOp();
|
||||
InsnArg firstArg = compare.getA();
|
||||
InsnArg secondArg = compare.getB();
|
||||
@@ -59,20 +70,47 @@ public class ConditionGen {
|
||||
}
|
||||
if (op == IfOp.EQ) {
|
||||
// == true
|
||||
return insnGen.arg(firstArg, false).toString();
|
||||
addArg(code, firstArg, false);
|
||||
return;
|
||||
} else if (op == IfOp.NE) {
|
||||
// != true
|
||||
if (isWrapNeeded(firstArg)) {
|
||||
return "!(" + insnGen.arg(firstArg) + ")";
|
||||
} else {
|
||||
return "!" + insnGen.arg(firstArg);
|
||||
code.add('!');
|
||||
boolean wrap = isWrapNeeded(firstArg);
|
||||
if (wrap) {
|
||||
code.add('(');
|
||||
}
|
||||
addArg(code, firstArg, false);
|
||||
if (wrap) {
|
||||
code.add(')');
|
||||
}
|
||||
return;
|
||||
}
|
||||
LOG.warn(ErrorsCounter.formatErrorMsg(insnGen.mth, "Unsupported boolean condition " + op.getSymbol()));
|
||||
LOG.warn(ErrorsCounter.formatErrorMsg(mth, "Unsupported boolean condition " + op.getSymbol()));
|
||||
}
|
||||
return insnGen.arg(firstArg, isWrapNeeded(firstArg))
|
||||
+ " " + op.getSymbol() + " "
|
||||
+ insnGen.arg(secondArg, isWrapNeeded(secondArg));
|
||||
|
||||
addArg(code, firstArg, isWrapNeeded(firstArg));
|
||||
code.add(' ').add(op.getSymbol()).add(' ');
|
||||
addArg(code, secondArg, isWrapNeeded(secondArg));
|
||||
}
|
||||
|
||||
private void addNot(CodeWriter code, IfCondition condition) throws CodegenException {
|
||||
code.add('!');
|
||||
wrap(code, condition.getArgs().get(0));
|
||||
}
|
||||
|
||||
private void addAndOr(CodeWriter code, IfCondition condition) throws CodegenException {
|
||||
String mode = condition.getMode() == IfCondition.Mode.AND ? " && " : " || ";
|
||||
Iterator<IfCondition> it = condition.getArgs().iterator();
|
||||
while (it.hasNext()) {
|
||||
wrap(code, it.next());
|
||||
if (it.hasNext()) {
|
||||
code.add(mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isWrapNeeded(IfCondition condition) {
|
||||
return !condition.isCompare();
|
||||
}
|
||||
|
||||
private static boolean isWrapNeeded(InsnArg arg) {
|
||||
|
||||
@@ -57,16 +57,16 @@ public class InsnGen {
|
||||
protected final MethodGen mgen;
|
||||
protected final MethodNode mth;
|
||||
protected final RootNode root;
|
||||
private final boolean fallback;
|
||||
protected final boolean fallback;
|
||||
|
||||
private static enum Flags {
|
||||
BODY_ONLY,
|
||||
BODY_ONLY_NOWRAP,
|
||||
}
|
||||
|
||||
public InsnGen(MethodGen mgen, MethodNode mth, boolean fallback) {
|
||||
public InsnGen(MethodGen mgen, boolean fallback) {
|
||||
this.mgen = mgen;
|
||||
this.mth = mth;
|
||||
this.mth = mgen.getMethodNode();
|
||||
this.root = mth.dex().root();
|
||||
this.fallback = fallback;
|
||||
}
|
||||
@@ -75,23 +75,6 @@ public class InsnGen {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public CodeWriter arg(InsnNode insn, int arg) throws CodegenException {
|
||||
return arg(insn.getArg(arg));
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public CodeWriter arg(InsnArg arg) throws CodegenException {
|
||||
return arg(arg, true);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public CodeWriter arg(InsnArg arg, boolean wrap) throws CodegenException {
|
||||
CodeWriter code = new CodeWriter();
|
||||
addArg(code, arg, wrap);
|
||||
return code;
|
||||
}
|
||||
|
||||
public void addArgDot(CodeWriter code, InsnArg arg) throws CodegenException {
|
||||
int len = code.length();
|
||||
addArg(code, arg, true);
|
||||
@@ -128,17 +111,19 @@ public class InsnGen {
|
||||
}
|
||||
}
|
||||
|
||||
public String assignVar(InsnNode insn) throws CodegenException {
|
||||
public void assignVar(CodeWriter code, InsnNode insn) throws CodegenException {
|
||||
RegisterArg arg = insn.getResult();
|
||||
if (insn.getAttributes().contains(AttributeFlag.DECLARE_VAR)) {
|
||||
return declareVar(arg);
|
||||
declareVar(code, arg);
|
||||
} else {
|
||||
return arg(arg).toString();
|
||||
addArg(code, arg, false);
|
||||
}
|
||||
}
|
||||
|
||||
public String declareVar(RegisterArg arg) {
|
||||
return useType(arg.getType()) + " " + mgen.assignArg(arg);
|
||||
public void declareVar(CodeWriter code, RegisterArg arg) {
|
||||
code.add(useType(arg.getType()));
|
||||
code.add(' ');
|
||||
code.add(mgen.assignArg(arg));
|
||||
}
|
||||
|
||||
private static String lit(LiteralArg arg) {
|
||||
@@ -174,18 +159,6 @@ public class InsnGen {
|
||||
return clsGen.useClass(declClass) + '.' + field.getName();
|
||||
}
|
||||
|
||||
private void fieldPut(IndexInsnNode insn) {
|
||||
FieldInfo field = (FieldInfo) insn.getIndex();
|
||||
String thisClass = mth.getParentClass().getFullName();
|
||||
if (field.getDeclClass().getFullName().equals(thisClass)) {
|
||||
// if we generate this field - don't init if its final and used
|
||||
FieldNode fn = mth.getParentClass().searchField(field);
|
||||
if (fn != null && fn.getAccessFlags().isFinal()) {
|
||||
fn.getAttributes().remove(AttributeType.FIELD_VALUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected String staticField(FieldInfo field) {
|
||||
return makeStaticFieldAccess(field, mgen.getClassGen());
|
||||
}
|
||||
@@ -217,7 +190,8 @@ public class InsnGen {
|
||||
code.attachAnnotation(insn.getSourceLine());
|
||||
}
|
||||
if (insn.getResult() != null && insn.getType() != InsnType.ARITH_ONEARG) {
|
||||
code.add(assignVar(insn)).add(" = ");
|
||||
assignVar(code, insn);
|
||||
code.add(" = ");
|
||||
}
|
||||
makeInsnBody(code, insn, state);
|
||||
code.add(';');
|
||||
@@ -273,14 +247,18 @@ public class InsnGen {
|
||||
makeArithOneArg((ArithNode) insn, code, state);
|
||||
break;
|
||||
|
||||
case NEG:
|
||||
String base = "-" + arg(insn.getArg(0));
|
||||
if (state.contains(Flags.BODY_ONLY)) {
|
||||
code.add('(').add(base).add(')');
|
||||
} else {
|
||||
code.add(base);
|
||||
case NEG: {
|
||||
boolean wrap = state.contains(Flags.BODY_ONLY);
|
||||
if (wrap) {
|
||||
code.add('(');
|
||||
}
|
||||
code.add('-');
|
||||
addArg(code, insn.getArg(0));
|
||||
if (wrap) {
|
||||
code.add(')');
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case RETURN:
|
||||
if (insn.getArgsCount() != 0) {
|
||||
@@ -306,7 +284,15 @@ public class InsnGen {
|
||||
|
||||
case CMP_L:
|
||||
case CMP_G:
|
||||
code.add(String.format("(%1$s > %2$s ? 1 : (%1$s == %2$s ? 0 : -1))", arg(insn, 0), arg(insn, 1)));
|
||||
code.add('(');
|
||||
addArg(code, insn.getArg(0));
|
||||
code.add(" > ");
|
||||
addArg(code, insn.getArg(1));
|
||||
code.add(" ? 1 : (");
|
||||
addArg(code, insn.getArg(0));
|
||||
code.add(" == ");
|
||||
addArg(code, insn.getArg(1));
|
||||
code.add("? 0 : -1))");
|
||||
break;
|
||||
|
||||
case INSTANCE_OF: {
|
||||
@@ -314,7 +300,7 @@ public class InsnGen {
|
||||
if (wrap) {
|
||||
code.add('(');
|
||||
}
|
||||
code.add(arg(insn, 0));
|
||||
addArg(code, insn.getArg(0));
|
||||
code.add(" instanceof ");
|
||||
code.add(useType((ArgType) ((IndexInsnNode) insn).getIndex()));
|
||||
if (wrap) {
|
||||
@@ -332,8 +318,11 @@ public class InsnGen {
|
||||
|
||||
case NEW_ARRAY: {
|
||||
ArgType arrayType = insn.getResult().getType();
|
||||
code.add("new ").add(useType(arrayType.getArrayRootElement()));
|
||||
code.add('[');
|
||||
addArg(code, insn.getArg(0));
|
||||
code.add(']');
|
||||
int dim = arrayType.getArrayDimension();
|
||||
code.add("new ").add(useType(arrayType.getArrayRootElement())).add('[').add(arg(insn, 0)).add(']');
|
||||
for (int i = 0; i < dim - 1; i++) {
|
||||
code.add("[]");
|
||||
}
|
||||
@@ -341,7 +330,8 @@ public class InsnGen {
|
||||
}
|
||||
|
||||
case ARRAY_LENGTH:
|
||||
code.add(arg(insn, 0)).add(".length");
|
||||
addArg(code, insn.getArg(0));
|
||||
code.add(".length");
|
||||
break;
|
||||
|
||||
case FILL_ARRAY:
|
||||
@@ -384,37 +374,40 @@ public class InsnGen {
|
||||
code.add(staticField((FieldInfo) ((IndexInsnNode) insn).getIndex()));
|
||||
break;
|
||||
case SPUT:
|
||||
IndexInsnNode node = (IndexInsnNode) insn;
|
||||
fieldPut(node);
|
||||
code.add(staticField((FieldInfo) node.getIndex())).add(" = ");
|
||||
addArg(code, node.getArg(0), false);
|
||||
FieldInfo field = (FieldInfo) ((IndexInsnNode) insn).getIndex();
|
||||
code.add(staticField(field)).add(" = ");
|
||||
addArg(code, insn.getArg(0), false);
|
||||
break;
|
||||
|
||||
case STR_CONCAT:
|
||||
StringBuilder sb = new StringBuilder();
|
||||
boolean wrap = state.contains(Flags.BODY_ONLY);
|
||||
if (wrap) {
|
||||
code.add('(');
|
||||
}
|
||||
for (Iterator<InsnArg> it = insn.getArguments().iterator(); it.hasNext(); ) {
|
||||
sb.append(arg(it.next()));
|
||||
addArg(code, it.next());
|
||||
if (it.hasNext()) {
|
||||
sb.append(" + ");
|
||||
code.add(" + ");
|
||||
}
|
||||
}
|
||||
// TODO: wrap in braces only if necessary
|
||||
if (state.contains(Flags.BODY_ONLY)) {
|
||||
code.add('(').add(sb.toString()).add(')');
|
||||
} else {
|
||||
code.add(sb.toString());
|
||||
if (wrap) {
|
||||
code.add(')');
|
||||
}
|
||||
break;
|
||||
|
||||
case MONITOR_ENTER:
|
||||
if (isFallback()) {
|
||||
code.add("monitor-enter(").add(arg(insn.getArg(0))).add(')');
|
||||
code.add("monitor-enter(");
|
||||
addArg(code, insn.getArg(0));
|
||||
code.add(')');
|
||||
}
|
||||
break;
|
||||
|
||||
case MONITOR_EXIT:
|
||||
if (isFallback()) {
|
||||
code.add("monitor-exit(").add(arg(insn, 0)).add(')');
|
||||
code.add("monitor-exit(");
|
||||
addArg(code, insn.getArg(0));
|
||||
code.add(')');
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -422,7 +415,7 @@ public class InsnGen {
|
||||
if (isFallback()) {
|
||||
code.add("move-exception");
|
||||
} else {
|
||||
code.add(arg(insn, 0));
|
||||
addArg(code, insn.getArg(0));
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -431,7 +424,7 @@ public class InsnGen {
|
||||
break;
|
||||
|
||||
case ARGS:
|
||||
code.add(arg(insn, 0));
|
||||
addArg(code, insn.getArg(0));
|
||||
break;
|
||||
|
||||
/* fallback mode instructions */
|
||||
@@ -439,9 +432,10 @@ public class InsnGen {
|
||||
assert isFallback() : "if insn in not fallback mode";
|
||||
IfNode ifInsn = (IfNode) insn;
|
||||
code.add("if (");
|
||||
code.add(arg(insn.getArg(0))).add(' ');
|
||||
addArg(code, insn.getArg(0));
|
||||
code.add(' ');
|
||||
code.add(ifInsn.getOp().getSymbol()).add(' ');
|
||||
code.add(arg(insn.getArg(1)));
|
||||
addArg(code, insn.getArg(1));
|
||||
code.add(") goto ").add(MethodGen.getLabelName(ifInsn.getTarget()));
|
||||
break;
|
||||
|
||||
@@ -453,7 +447,9 @@ public class InsnGen {
|
||||
case SWITCH:
|
||||
assert isFallback();
|
||||
SwitchNode sw = (SwitchNode) insn;
|
||||
code.add("switch(").add(arg(insn, 0)).add(") {");
|
||||
code.add("switch(");
|
||||
addArg(code, insn.getArg(0));
|
||||
code.add(") {");
|
||||
code.incIndent();
|
||||
for (int i = 0; i < sw.getCasesCount(); i++) {
|
||||
code.startLine("case ").add(sw.getKeys()[i]).add(": goto ");
|
||||
@@ -481,7 +477,7 @@ public class InsnGen {
|
||||
code.add("new ").add(useType(insn.getResult().getType()));
|
||||
code.add('{');
|
||||
for (int i = 0; i < c; i++) {
|
||||
code.add(arg(insn, i));
|
||||
addArg(code, insn.getArg(i));
|
||||
if (i + 1 < c) {
|
||||
code.add(", ");
|
||||
}
|
||||
@@ -565,7 +561,7 @@ public class InsnGen {
|
||||
defCtr.getAttributes().add(AttributeFlag.DONT_GENERATE);
|
||||
}
|
||||
code.add("new ").add(parent == null ? "Object" : useClass(parent)).add("() ");
|
||||
new ClassGen(cls, mgen.getClassGen().getParentGen(), fallback).makeClassBody(code);
|
||||
new ClassGen(cls, mgen.getClassGen().getParentGen(), fallback).addClassBody(code);
|
||||
return;
|
||||
}
|
||||
if (insn.isSelf()) {
|
||||
@@ -705,17 +701,24 @@ public class InsnGen {
|
||||
}
|
||||
|
||||
private void makeTernary(TernaryInsn insn, CodeWriter code, EnumSet<Flags> state) throws CodegenException {
|
||||
String cond = ConditionGen.make(this, insn.getCondition());
|
||||
CodeWriter th = arg(insn.getArg(0), false);
|
||||
CodeWriter els = arg(insn.getArg(1), false);
|
||||
if (th.toString().equals("true") && els.toString().equals("false")) {
|
||||
code.add(cond);
|
||||
boolean wrap = state.contains(Flags.BODY_ONLY);
|
||||
if (wrap) {
|
||||
code.add('(');
|
||||
}
|
||||
InsnArg first = insn.getArg(0);
|
||||
InsnArg second = insn.getArg(1);
|
||||
ConditionGen condGen = new ConditionGen(this);
|
||||
if (first.equals(LiteralArg.TRUE) && second.equals(LiteralArg.FALSE)) {
|
||||
condGen.add(code, insn.getCondition());
|
||||
} else {
|
||||
if (state.contains(Flags.BODY_ONLY)) {
|
||||
code.add("((").add(cond).add(')').add(" ? ").add(th).add(" : ").add(els).add(')');
|
||||
} else {
|
||||
code.add('(').add(cond).add(')').add(" ? ").add(th).add(" : ").add(els);
|
||||
}
|
||||
condGen.wrap(code, insn.getCondition());
|
||||
code.add(" ? ");
|
||||
addArg(code, first, false);
|
||||
code.add(" : ");
|
||||
addArg(code, second, false);
|
||||
}
|
||||
if (wrap) {
|
||||
code.add(')');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -743,13 +746,15 @@ public class InsnGen {
|
||||
if (arg.isLiteral() && (op == ArithOp.ADD || op == ArithOp.SUB)) {
|
||||
LiteralArg lit = (LiteralArg) arg;
|
||||
if (lit.isInteger() && lit.getLiteral() == 1) {
|
||||
assignVar(code, insn);
|
||||
String opSymbol = op.getSymbol();
|
||||
code.add(assignVar(insn)).add(opSymbol).add(opSymbol);
|
||||
code.add(opSymbol).add(opSymbol);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// +=, -= ...
|
||||
code.add(assignVar(insn)).add(' ').add(op.getSymbol()).add("= ");
|
||||
assignVar(code, insn);
|
||||
code.add(' ').add(op.getSymbol()).add("= ");
|
||||
addArg(code, arg, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,10 @@ public class MethodGen {
|
||||
return classGen;
|
||||
}
|
||||
|
||||
public MethodNode getMethodNode() {
|
||||
return mth;
|
||||
}
|
||||
|
||||
public boolean addDefinition(CodeWriter code) {
|
||||
if (mth.getMethodInfo().isClassInit()) {
|
||||
code.startLine("static");
|
||||
@@ -84,7 +88,7 @@ public class MethodGen {
|
||||
}
|
||||
code.startLine(ai.makeString());
|
||||
|
||||
if (classGen.makeGenericMap(code, mth.getGenericMap())) {
|
||||
if (classGen.addGenericMap(code, mth.getGenericMap())) {
|
||||
code.add(' ');
|
||||
}
|
||||
if (mth.getAccessFlags().isConstructor()) {
|
||||
@@ -245,7 +249,7 @@ public class MethodGen {
|
||||
} else {
|
||||
Region startRegion = mth.getRegion();
|
||||
if (startRegion != null) {
|
||||
(new RegionGen(this, mth)).makeRegion(code, startRegion);
|
||||
(new RegionGen(this)).makeRegion(code, startRegion);
|
||||
} else {
|
||||
addFallbackMethodCode(code);
|
||||
}
|
||||
@@ -289,7 +293,7 @@ public class MethodGen {
|
||||
}
|
||||
|
||||
public static void addFallbackInsns(CodeWriter code, MethodNode mth, List<InsnNode> insns, boolean addLabels) {
|
||||
InsnGen insnGen = new InsnGen(getFallbackMethodGen(mth), mth, true);
|
||||
InsnGen insnGen = new InsnGen(getFallbackMethodGen(mth), true);
|
||||
for (InsnNode insn : insns) {
|
||||
AttributesList attrs = insn.getAttributes();
|
||||
if (addLabels) {
|
||||
|
||||
@@ -15,7 +15,6 @@ import jadx.core.dex.nodes.IBlock;
|
||||
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.IfCondition;
|
||||
import jadx.core.dex.regions.IfRegion;
|
||||
import jadx.core.dex.regions.LoopRegion;
|
||||
@@ -36,8 +35,8 @@ import org.slf4j.LoggerFactory;
|
||||
public class RegionGen extends InsnGen {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(RegionGen.class);
|
||||
|
||||
public RegionGen(MethodGen mgen, MethodNode mth) {
|
||||
super(mgen, mth, false);
|
||||
public RegionGen(MethodGen mgen) {
|
||||
super(mgen, false);
|
||||
}
|
||||
|
||||
public void makeRegion(CodeWriter code, IContainer cont) throws CodegenException {
|
||||
@@ -66,7 +65,9 @@ public class RegionGen extends InsnGen {
|
||||
(DeclareVariablesAttr) cont.getAttributes().get(AttributeType.DECLARE_VARIABLES);
|
||||
if (declVars != null) {
|
||||
for (RegisterArg v : declVars.getVars()) {
|
||||
code.startLine(declareVar(v)).add(';');
|
||||
code.startLine();
|
||||
declareVar(code, v);
|
||||
code.add(';');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -111,7 +112,9 @@ public class RegionGen extends InsnGen {
|
||||
if (newLine) {
|
||||
code.startLine();
|
||||
}
|
||||
code.add("if (").add(ConditionGen.make(this, region.getCondition())).add(") {");
|
||||
code.add("if (");
|
||||
new ConditionGen(this).add(code, region.getCondition());
|
||||
code.add(") {");
|
||||
makeRegionIndent(code, region.getThenRegion());
|
||||
code.startLine('}');
|
||||
|
||||
@@ -169,13 +172,17 @@ public class RegionGen extends InsnGen {
|
||||
return code;
|
||||
}
|
||||
|
||||
String condStr = ConditionGen.make(this, condition);
|
||||
ConditionGen conditionGen = new ConditionGen(this);
|
||||
if (region.isConditionAtEnd()) {
|
||||
code.startLine("do {");
|
||||
makeRegionIndent(code, region.getBody());
|
||||
code.startLine("} while (").add(condStr).add(");");
|
||||
code.startLine("} while (");
|
||||
conditionGen.add(code, condition);
|
||||
code.add(");");
|
||||
} else {
|
||||
code.startLine("while (").add(condStr).add(") {");
|
||||
code.startLine("while (");
|
||||
conditionGen.add(code, condition);
|
||||
code.add(") {");
|
||||
makeRegionIndent(code, region.getBody());
|
||||
code.startLine('}');
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package jadx.core.dex.visitors;
|
||||
|
||||
import jadx.core.dex.attributes.AttributeFlag;
|
||||
import jadx.core.dex.attributes.AttributeType;
|
||||
import jadx.core.dex.attributes.AttributesList;
|
||||
import jadx.core.dex.attributes.FieldReplaceAttr;
|
||||
import jadx.core.dex.info.AccessInfo;
|
||||
@@ -39,6 +40,8 @@ public class ClassModifier extends AbstractVisitor {
|
||||
removeSyntheticFields(cls);
|
||||
removeSyntheticMethods(cls);
|
||||
removeEmptyMethods(cls);
|
||||
|
||||
checkFieldsInit(cls);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -174,4 +177,36 @@ public class ClassModifier extends AbstractVisitor {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void checkFieldsInit(ClassNode cls) {
|
||||
MethodNode clinit = cls.searchMethodByName("<clinit>()V");
|
||||
if (clinit == null
|
||||
|| !clinit.getAccessFlags().isStatic()
|
||||
|| clinit.isNoCode()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (BlockNode block : clinit.getBasicBlocks()) {
|
||||
for (InsnNode insn : block.getInstructions()) {
|
||||
if (insn.getType() == InsnType.SPUT) {
|
||||
processStaticFieldAssign(cls, (IndexInsnNode) insn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove field initialization if it assign in "<clinit>" method
|
||||
*/
|
||||
private static void processStaticFieldAssign(ClassNode cls, IndexInsnNode insn) {
|
||||
FieldInfo field = (FieldInfo) insn.getIndex();
|
||||
String thisClass = cls.getFullName();
|
||||
if (field.getDeclClass().getFullName().equals(thisClass)) {
|
||||
FieldNode fn = cls.searchField(field);
|
||||
if (fn != null && fn.getAccessFlags().isFinal()) {
|
||||
fn.getAttributes().remove(AttributeType.FIELD_VALUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import jadx.core.dex.nodes.ClassNode;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.CoreMatchers.either;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
@@ -18,10 +17,7 @@ public class TestRedundantBrackets extends InternalJadxTest {
|
||||
}
|
||||
|
||||
public int method2(Object obj) {
|
||||
if (obj instanceof String) {
|
||||
return ((String) obj).length();
|
||||
}
|
||||
return 0;
|
||||
return obj instanceof String ? ((String) obj).length() : 0;
|
||||
}
|
||||
|
||||
public int method3(int a, int b) {
|
||||
@@ -50,11 +46,12 @@ public class TestRedundantBrackets extends InternalJadxTest {
|
||||
public void test() {
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
String code = cls.getCode().toString();
|
||||
System.out.println(code);
|
||||
|
||||
assertThat(code, not(containsString("(-1)")));
|
||||
assertThat(code, not(containsString("return;")));
|
||||
assertThat(code, either(containsString("if (obj instanceof String) {"))
|
||||
.or(containsString("return (obj instanceof String) ? ")));
|
||||
|
||||
assertThat(code, containsString("return obj instanceof String ? ((String) obj).length() : 0;"));
|
||||
assertThat(code, containsString("if (a + b < 10)"));
|
||||
assertThat(code, containsString("if ((a & b) != 0)"));
|
||||
assertThat(code, containsString("if (num == 4 || num == 6 || num == 8 || num == 10)"));
|
||||
|
||||
@@ -57,7 +57,7 @@ public class TestReturnWrapping extends InternalJadxTest {
|
||||
assertThat(code, containsString("return 255;"));
|
||||
assertThat(code, containsString("return arg0 + 1;"));
|
||||
//assertThat(code, containsString("return Integer.toHexString(i);"));
|
||||
assertThat(code, containsString("return (i > 128) ? arg0.toString() + ret.toString() : Integer.valueOf(i);"));
|
||||
assertThat(code, containsString("return i > 128 ? arg0.toString() + ret.toString() : Integer.valueOf(i);"));
|
||||
assertThat(code, containsString("return arg0 + 2;"));
|
||||
assertThat(code, containsString("arg0 -= 951;"));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
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 TestStaticFieldsInit extends InternalJadxTest {
|
||||
|
||||
public static class TestCls {
|
||||
public static final String s1 = "1";
|
||||
public static final String s2 = "12".substring(1);
|
||||
public static final String s3 = null;
|
||||
public static final String s4;
|
||||
public static final String s5 = "5";
|
||||
public static String s6 = "6";
|
||||
|
||||
static {
|
||||
if (s5.equals("?")) {
|
||||
s4 = "?";
|
||||
} else {
|
||||
s4 = "4";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
ClassNode cls = getClassNode(TestCls.class);
|
||||
String code = cls.getCode().toString();
|
||||
System.out.println(code);
|
||||
|
||||
assertThat(code, not(containsString("public static final String s2 = null;")));
|
||||
// TODO:
|
||||
// assertThat(code, containsString("public static final String s3 = null;"));
|
||||
}
|
||||
}
|
||||
@@ -43,6 +43,6 @@ public class TestGenerics2 extends InternalJadxTest {
|
||||
assertThat(code, containsString("public ItemReference(V item, Object id, ReferenceQueue<? super V> queue) {"));
|
||||
assertThat(code, containsString("public V get(Object id) {"));
|
||||
assertThat(code, containsString("WeakReference<V> ref = "));
|
||||
assertThat(code, containsString("return (ref != null) ? ref.get() : null;"));
|
||||
assertThat(code, containsString("return ref != null ? ref.get() : null;"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ import org.slf4j.LoggerFactory;
|
||||
public class JadxTextArea extends RSyntaxTextArea {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(JadxTextArea.class);
|
||||
|
||||
private static final long serialVersionUID = 6312736869579635796L;
|
||||
|
||||
private static final Color BACKGROUND = new Color(0xf7f7f7);
|
||||
private static final Color JUMP_FOREGROUND = new Color(0x785523);
|
||||
private static final Color JUMP_BACKGROUND = new Color(0xE6E6FF);
|
||||
|
||||
Reference in New Issue
Block a user