From 890c0a9909a7ef59cf8bbd1536030188ddc99807 Mon Sep 17 00:00:00 2001 From: Skylot Date: Mon, 10 Mar 2014 23:00:14 +0400 Subject: [PATCH] refactor: remove deprecated methods --- .../java/jadx/core/codegen/AnnotationGen.java | 3 +- .../main/java/jadx/core/codegen/ClassGen.java | 145 +++++++-------- .../java/jadx/core/codegen/CodeWriter.java | 16 +- .../java/jadx/core/codegen/ConditionGen.java | 96 +++++++--- .../main/java/jadx/core/codegen/InsnGen.java | 167 +++++++++--------- .../java/jadx/core/codegen/MethodGen.java | 10 +- .../java/jadx/core/codegen/RegionGen.java | 23 ++- .../jadx/core/dex/visitors/ClassModifier.java | 35 ++++ .../tests/internal/TestRedundantBrackets.java | 11 +- .../tests/internal/TestReturnWrapping.java | 2 +- .../tests/internal/TestStaticFieldsInit.java | 41 +++++ .../internal/generics/TestGenerics2.java | 2 +- .../src/main/java/jadx/gui/JadxTextArea.java | 2 + 13 files changed, 332 insertions(+), 221 deletions(-) create mode 100644 jadx-core/src/test/java/jadx/tests/internal/TestStaticFieldsInit.java diff --git a/jadx-core/src/main/java/jadx/core/codegen/AnnotationGen.java b/jadx-core/src/main/java/jadx/core/codegen/AnnotationGen.java index 572f2df37..6ade80a07 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/AnnotationGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/AnnotationGen.java @@ -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); diff --git a/jadx-core/src/main/java/jadx/core/codegen/ClassGen.java b/jadx-core/src/main/java/jadx/core/codegen/ClassGen.java index 7afbfc68b..fa2175449 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/ClassGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/ClassGen.java @@ -43,6 +43,7 @@ public class ClassGen { private final boolean fallback; private final Set imports = new HashSet(); + 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> gmap) { + public boolean addGenericMap(CodeWriter code, Map> 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 mthList) { - CodeWriter code = new CodeWriter(clsCode.getIndent() + 1); - for (Iterator 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 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(','); diff --git a/jadx-core/src/main/java/jadx/core/codegen/CodeWriter.java b/jadx-core/src/main/java/jadx/core/codegen/CodeWriter.java index e47d0f067..76383db75 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/CodeWriter.java +++ b/jadx-core/src/main/java/jadx/core/codegen/CodeWriter.java @@ -95,21 +95,15 @@ public class CodeWriter { return this; } - @Deprecated - public CodeWriter add(CodeWriter code) { + CodeWriter add(CodeWriter code) { line--; for (Map.Entry 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; } diff --git a/jadx-core/src/main/java/jadx/core/codegen/ConditionGen.java b/jadx-core/src/main/java/jadx/core/codegen/ConditionGen.java index dc99a2a21..13b95a9fc 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/ConditionGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/ConditionGen.java @@ -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 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) { diff --git a/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java b/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java index ac4070fff..bd8f98edd 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java @@ -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 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 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); } } diff --git a/jadx-core/src/main/java/jadx/core/codegen/MethodGen.java b/jadx-core/src/main/java/jadx/core/codegen/MethodGen.java index e1f7926d1..6e098d303 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/MethodGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/MethodGen.java @@ -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 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) { diff --git a/jadx-core/src/main/java/jadx/core/codegen/RegionGen.java b/jadx-core/src/main/java/jadx/core/codegen/RegionGen.java index 2907d864e..4c3108c7c 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/RegionGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/RegionGen.java @@ -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('}'); } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/ClassModifier.java b/jadx-core/src/main/java/jadx/core/dex/visitors/ClassModifier.java index f93386a5b..b32f2149f 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/ClassModifier.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/ClassModifier.java @@ -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("()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 "" 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); + } + } + } + } diff --git a/jadx-core/src/test/java/jadx/tests/internal/TestRedundantBrackets.java b/jadx-core/src/test/java/jadx/tests/internal/TestRedundantBrackets.java index 3f6352959..5fb58efc8 100644 --- a/jadx-core/src/test/java/jadx/tests/internal/TestRedundantBrackets.java +++ b/jadx-core/src/test/java/jadx/tests/internal/TestRedundantBrackets.java @@ -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)")); diff --git a/jadx-core/src/test/java/jadx/tests/internal/TestReturnWrapping.java b/jadx-core/src/test/java/jadx/tests/internal/TestReturnWrapping.java index 54f559dfb..a6f128e55 100644 --- a/jadx-core/src/test/java/jadx/tests/internal/TestReturnWrapping.java +++ b/jadx-core/src/test/java/jadx/tests/internal/TestReturnWrapping.java @@ -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;")); } diff --git a/jadx-core/src/test/java/jadx/tests/internal/TestStaticFieldsInit.java b/jadx-core/src/test/java/jadx/tests/internal/TestStaticFieldsInit.java new file mode 100644 index 000000000..a63183401 --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/internal/TestStaticFieldsInit.java @@ -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;")); + } +} diff --git a/jadx-core/src/test/java/jadx/tests/internal/generics/TestGenerics2.java b/jadx-core/src/test/java/jadx/tests/internal/generics/TestGenerics2.java index 841a6e78c..0eaa5eec4 100644 --- a/jadx-core/src/test/java/jadx/tests/internal/generics/TestGenerics2.java +++ b/jadx-core/src/test/java/jadx/tests/internal/generics/TestGenerics2.java @@ -43,6 +43,6 @@ public class TestGenerics2 extends InternalJadxTest { assertThat(code, containsString("public ItemReference(V item, Object id, ReferenceQueue queue) {")); assertThat(code, containsString("public V get(Object id) {")); assertThat(code, containsString("WeakReference ref = ")); - assertThat(code, containsString("return (ref != null) ? ref.get() : null;")); + assertThat(code, containsString("return ref != null ? ref.get() : null;")); } } diff --git a/jadx-gui/src/main/java/jadx/gui/JadxTextArea.java b/jadx-gui/src/main/java/jadx/gui/JadxTextArea.java index 9557aa281..e6ddc8aa0 100644 --- a/jadx-gui/src/main/java/jadx/gui/JadxTextArea.java +++ b/jadx-gui/src/main/java/jadx/gui/JadxTextArea.java @@ -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);