From cb6ff606710143fd46f9c0930444caa6b514bbb8 Mon Sep 17 00:00:00 2001 From: Skylot Date: Sat, 15 Jun 2013 18:24:45 +0400 Subject: [PATCH] Fix small issues and improve code --- src/main/java/jadx/IJadxArgs.java | 2 - src/main/java/jadx/JadxArgs.java | 8 --- src/main/java/jadx/codegen/ClassGen.java | 39 +++++++---- src/main/java/jadx/codegen/CodeWriter.java | 5 +- src/main/java/jadx/dex/info/ClassInfo.java | 69 ++++++++++--------- .../jadx/dex/instructions/args/TypedVar.java | 6 +- src/main/java/jadx/dex/nodes/BlockNode.java | 3 +- src/main/java/jadx/dex/nodes/ClassNode.java | 4 +- src/main/java/jadx/dex/nodes/RootNode.java | 10 +-- .../jadx/dex/visitors/BlockMakerVisitor.java | 28 ++++---- .../dex/visitors/BlockProcessingHelper.java | 9 ++- .../java/jadx/dex/visitors/ClassModifier.java | 19 +++-- .../java/jadx/dex/visitors/CodeShrinker.java | 30 +++++--- .../java/jadx/dex/visitors/EnumVisitor.java | 26 +++++-- 14 files changed, 154 insertions(+), 104 deletions(-) diff --git a/src/main/java/jadx/IJadxArgs.java b/src/main/java/jadx/IJadxArgs.java index 58e11badf..4f2d6667f 100644 --- a/src/main/java/jadx/IJadxArgs.java +++ b/src/main/java/jadx/IJadxArgs.java @@ -18,8 +18,6 @@ public interface IJadxArgs { boolean isFallbackMode(); - boolean isNotObfuscated(); - boolean isVerbose(); boolean isPrintHelp(); diff --git a/src/main/java/jadx/JadxArgs.java b/src/main/java/jadx/JadxArgs.java index d38c725e0..90aa79d25 100644 --- a/src/main/java/jadx/JadxArgs.java +++ b/src/main/java/jadx/JadxArgs.java @@ -33,9 +33,6 @@ public class JadxArgs implements IJadxArgs { @Parameter(names = {"-f", "--fallback"}, description = "make simple dump (using goto instead of 'if', 'for', etc)", help = true) protected boolean fallbackMode = false; - @Parameter(names = {"--not-obfuscated"}, description = "set this flag if code not obfuscated") - protected boolean notObfuscated = false; - @Parameter(names = {"--cfg"}, description = "save methods control flow graph") protected boolean cfgOutput = false; @@ -177,11 +174,6 @@ public class JadxArgs implements IJadxArgs { return fallbackMode; } - @Override - public boolean isNotObfuscated() { - return notObfuscated; - } - @Override public boolean isVerbose() { return verbose; diff --git a/src/main/java/jadx/codegen/ClassGen.java b/src/main/java/jadx/codegen/ClassGen.java index e4c9717da..1507ed7db 100644 --- a/src/main/java/jadx/codegen/ClassGen.java +++ b/src/main/java/jadx/codegen/ClassGen.java @@ -82,6 +82,9 @@ public class ClassGen { if (cls.getAttributes().contains(AttributeFlag.DONT_GENERATE)) return; + if (cls.getAttributes().contains(AttributeFlag.INCONSISTENT_CODE)) + code.startLine("// jadx: inconsistent code"); + makeClassDeclaration(code); makeClassBody(code); code.endl(); @@ -124,7 +127,7 @@ public class ClassGen { else clsCode.add("implements "); - for (Iterator it = cls.getInterfaces().iterator(); it.hasNext();) { + for (Iterator it = cls.getInterfaces().iterator(); it.hasNext(); ) { ClassInfo interf = it.next(); clsCode.add(useClass(interf)); if (it.hasNext()) @@ -150,7 +153,7 @@ public class ClassGen { code.add(useClass(type)); if (list != null && !list.isEmpty()) { code.add(" extends "); - for (Iterator it = list.iterator(); it.hasNext();) { + for (Iterator it = list.iterator(); it.hasNext(); ) { ArgType g = it.next(); code.add(useClass(g)); if (it.hasNext()) { @@ -167,11 +170,16 @@ public class ClassGen { public void makeClassBody(CodeWriter clsCode) throws CodegenException { clsCode.add('{'); CodeWriter mthsCode = makeMethods(clsCode, cls.getMethods()); - clsCode.add(makeFields(clsCode, cls, cls.getFields())); + CodeWriter fieldsCode = makeFields(clsCode, cls, cls.getFields()); + clsCode.add(fieldsCode); + if (fieldsCode.notEmpty() && mthsCode.notEmpty()) + clsCode.endl(); // insert inner classes code if (cls.getInnerClasses().size() != 0) { clsCode.add(makeInnerClasses(cls, clsCode.getIndent())); + if (mthsCode.notEmpty()) + clsCode.endl(); } clsCode.add(mthsCode); clsCode.startLine('}'); @@ -192,7 +200,7 @@ public class ClassGen { private CodeWriter makeMethods(CodeWriter clsCode, List mthList) { CodeWriter code = new CodeWriter(clsCode.getIndent() + 1); - for (Iterator it = mthList.iterator(); it.hasNext();) { + for (Iterator it = mthList.iterator(); it.hasNext(); ) { MethodNode mth = it.next(); if (mth.getAttributes().contains(AttributeFlag.DONT_GENERATE)) continue; @@ -235,16 +243,19 @@ public class ClassGen { EnumClassAttr enumFields = (EnumClassAttr) cls.getAttributes().get(AttributeType.ENUM_CLASS); if (enumFields != null) { - MethodGen mthGen = new MethodGen(this, enumFields.getStaticMethod()); - InsnGen igen = new InsnGen(mthGen, enumFields.getStaticMethod(), false); - - for (Iterator it = enumFields.getFields().iterator(); it.hasNext();) { + InsnGen igen = null; + for (Iterator it = enumFields.getFields().iterator(); it.hasNext(); ) { EnumField f = it.next(); code.startLine(f.getName()); if (f.getArgs().size() != 0) { code.add('('); - for (Iterator aIt = f.getArgs().iterator(); aIt.hasNext();) { + for (Iterator aIt = f.getArgs().iterator(); aIt.hasNext(); ) { InsnArg arg = aIt.next(); + 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); + } code.add(igen.arg(arg)); if (aIt.hasNext()) code.add(", "); @@ -281,8 +292,6 @@ public class ClassGen { } code.add(';'); } - if (fields.size() != 0) - code.endl(); return code; } @@ -290,11 +299,11 @@ public class ClassGen { if (clsType.isGenericType()) { return clsType.getObject(); } - return useClass(ClassInfo.fromType(cls.dex(), clsType)); + return useClass(ClassInfo.fromType(clsType)); } public String useClass(ClassInfo classInfo) { - String baseClass = useClassInner(classInfo); + String baseClass = useClassInternal(classInfo); ArgType[] generics = classInfo.getType().getGenericTypes(); if (generics != null) { StringBuilder sb = new StringBuilder(); @@ -318,9 +327,9 @@ public class ClassGen { } } - private String useClassInner(ClassInfo classInfo) { + private String useClassInternal(ClassInfo classInfo) { if (parentGen != null) - return parentGen.useClassInner(classInfo); + return parentGen.useClassInternal(classInfo); String clsStr = classInfo.getFullName(); if (fallback) diff --git a/src/main/java/jadx/codegen/CodeWriter.java b/src/main/java/jadx/codegen/CodeWriter.java index 1802e4d18..b1abab90e 100644 --- a/src/main/java/jadx/codegen/CodeWriter.java +++ b/src/main/java/jadx/codegen/CodeWriter.java @@ -133,6 +133,10 @@ public class CodeWriter { } } + public boolean notEmpty() { + return buf.length() != 0; + } + @Override public String toString() { return buf.toString(); @@ -183,5 +187,4 @@ public class CodeWriter { throw new JadxRuntimeException("Can't create directory " + dir); } } - } diff --git a/src/main/java/jadx/dex/info/ClassInfo.java b/src/main/java/jadx/dex/info/ClassInfo.java index f4a2805aa..91712c2d7 100644 --- a/src/main/java/jadx/dex/info/ClassInfo.java +++ b/src/main/java/jadx/dex/info/ClassInfo.java @@ -13,13 +13,6 @@ public final class ClassInfo { private static final Map CLASSINFO_CACHE = new WeakHashMap(); private static final String DEFAULT_PACKAGE_NAME = "defpackage"; - private final String clsName; - private final String clsPackage; - private final ArgType type; - private final String fullName; - - private final ClassInfo parentClass; // not equals null if this is inner class - public static ClassInfo fromDex(DexNode dex, int clsIndex) { if (clsIndex == DexNode.NO_INDEX) return null; @@ -28,17 +21,17 @@ public final class ClassInfo { if (type.isArray()) type = ArgType.OBJECT; - return fromType(dex, type); + return fromType(type); } - public static ClassInfo fromName(DexNode dex, String clsName) { - return fromType(dex, ArgType.object(clsName)); + public static ClassInfo fromName(String clsName) { + return fromType(ArgType.object(clsName)); } - public static ClassInfo fromType(DexNode dex, ArgType type) { + public static ClassInfo fromType(ArgType type) { ClassInfo cls = CLASSINFO_CACHE.get(type); if (cls == null) { - cls = new ClassInfo(dex, type); + cls = new ClassInfo(type); CLASSINFO_CACHE.put(type, cls); } return cls; @@ -48,21 +41,28 @@ public final class ClassInfo { CLASSINFO_CACHE.clear(); } - private ClassInfo(DexNode dex, ArgType type) { + private final ArgType type; + private String pkg; + private String name; + private String fullName; + private ClassInfo parentClass; // not equals null if this is inner class + + private ClassInfo(ArgType type) { assert type.isObject() : "Not class type: " + type; this.type = type; + splitNames(true); + } + + private void splitNames(boolean canBeInner) { String fullObjectName = type.getObject(); assert fullObjectName.indexOf('/') == -1 : "Raw type: " + type; - boolean notObfuscated = dex.root().getJadxArgs().isNotObfuscated(); String name; - String pkg; - int dot = fullObjectName.lastIndexOf('.'); if (dot == -1) { // rename default package if it used from class with package (often for obfuscated apps), - pkg = (notObfuscated ? "" : DEFAULT_PACKAGE_NAME); + pkg = DEFAULT_PACKAGE_NAME; name = fullObjectName; } else { pkg = fullObjectName.substring(0, dot); @@ -70,27 +70,30 @@ public final class ClassInfo { } int sep = name.lastIndexOf('$'); - if (sep > 0 && sep != name.length() - 1) { + if (canBeInner && sep > 0 && sep != name.length() - 1) { String parClsName = pkg + '.' + name.substring(0, sep); - parentClass = fromName(dex, parClsName); + parentClass = fromName(parClsName); name = name.substring(sep + 1); } else { parentClass = null; } - if (Character.isDigit(name.charAt(0))) + char firstChar = name.charAt(0); + if (Character.isDigit(firstChar)) { name = "InnerClass_" + name; - - if (NameMapper.isReserved(name)) + } else if(firstChar == '$') { + name = "_" + name; + } + if (NameMapper.isReserved(name)) { name += "_"; - + } this.fullName = (parentClass != null ? parentClass.getFullName() : pkg) + "." + name; - this.clsName = name; - this.clsPackage = pkg; + this.name = name; } public String getFullPath() { - return clsPackage.replace('.', File.separatorChar) + File.separatorChar + return pkg.replace('.', File.separatorChar) + + File.separatorChar + getNameWithoutPackage().replace('.', '_'); } @@ -99,19 +102,19 @@ public final class ClassInfo { } public String getShortName() { - return clsName; + return name; } public String getPackage() { - return clsPackage; + return pkg; } public boolean isPackageDefault() { - return clsPackage.isEmpty() || clsPackage.equals(DEFAULT_PACKAGE_NAME); + return pkg.isEmpty() || pkg.equals(DEFAULT_PACKAGE_NAME); } public String getNameWithoutPackage() { - return (parentClass != null ? parentClass.getNameWithoutPackage() + "." : "") + clsName; + return (parentClass != null ? parentClass.getNameWithoutPackage() + "." : "") + name; } public ClassInfo getParentClass() { @@ -122,6 +125,10 @@ public final class ClassInfo { return parentClass != null; } + public void notInner() { + splitNames(false); + } + public ArgType getType() { return type; } @@ -133,7 +140,7 @@ public final class ClassInfo { @Override public int hashCode() { - return this.getFullName().hashCode(); + return type.hashCode(); } @Override diff --git a/src/main/java/jadx/dex/instructions/args/TypedVar.java b/src/main/java/jadx/dex/instructions/args/TypedVar.java index 76a5832c8..60e65c639 100644 --- a/src/main/java/jadx/dex/instructions/args/TypedVar.java +++ b/src/main/java/jadx/dex/instructions/args/TypedVar.java @@ -77,6 +77,10 @@ public class TypedVar { @Override public String toString() { - return (name != null ? "'" + name + "' " : "") + type.toString(); + StringBuilder sb = new StringBuilder(); + if(name != null) + sb.append('\'').append(name).append("' "); + sb.append(type); + return sb.toString(); } } diff --git a/src/main/java/jadx/dex/nodes/BlockNode.java b/src/main/java/jadx/dex/nodes/BlockNode.java index 24389d510..8943d8956 100644 --- a/src/main/java/jadx/dex/nodes/BlockNode.java +++ b/src/main/java/jadx/dex/nodes/BlockNode.java @@ -19,6 +19,7 @@ public class BlockNode extends AttrNode implements IBlock { private List predecessors = new ArrayList(1); private List successors = new ArrayList(1); + private List cleanSuccessors; private BitSet doms; // all dominators private BlockNode idom; // immediate dominator @@ -48,8 +49,6 @@ public class BlockNode extends AttrNode implements IBlock { return successors; } - private List cleanSuccessors; - public List getCleanSuccessors() { return cleanSuccessors; } diff --git a/src/main/java/jadx/dex/nodes/ClassNode.java b/src/main/java/jadx/dex/nodes/ClassNode.java index e6e81b4c2..d41f68f84 100644 --- a/src/main/java/jadx/dex/nodes/ClassNode.java +++ b/src/main/java/jadx/dex/nodes/ClassNode.java @@ -154,10 +154,10 @@ public class ClassNode extends AttrNode implements ILoadable { if (list != null && !list.isEmpty()) { try { ArgType st = list.remove(0); - this.superClass = ClassInfo.fromType(dex, st); + this.superClass = ClassInfo.fromType(st); int i = 0; for (ArgType it : list) { - ClassInfo interf = ClassInfo.fromType(dex, it); + ClassInfo interf = ClassInfo.fromType(it); interfaces.set(i, interf); i++; } diff --git a/src/main/java/jadx/dex/nodes/RootNode.java b/src/main/java/jadx/dex/nodes/RootNode.java index d853f2554..fe933e98e 100644 --- a/src/main/java/jadx/dex/nodes/RootNode.java +++ b/src/main/java/jadx/dex/nodes/RootNode.java @@ -56,16 +56,16 @@ public class RootNode { if (cls.getClassInfo().isInner()) inner.add(cls); } - getClasses().removeAll(inner); for (ClassNode cls : inner) { ClassNode parent = resolveClass(cls.getClassInfo().getParentClass()); - if (parent == null) - LOG.warn("Can't add inner class: {} to {}", cls, cls.getClassInfo().getParentClass()); - else + if (parent == null) { + cls.getClassInfo().notInner(); + } else { parent.addInnerClass(cls); + getClasses().remove(cls); + } } - inner.clear(); } public List getClasses() { diff --git a/src/main/java/jadx/dex/visitors/BlockMakerVisitor.java b/src/main/java/jadx/dex/visitors/BlockMakerVisitor.java index 40de71476..c0ae7f59c 100644 --- a/src/main/java/jadx/dex/visitors/BlockMakerVisitor.java +++ b/src/main/java/jadx/dex/visitors/BlockMakerVisitor.java @@ -159,7 +159,6 @@ public class BlockMakerVisitor extends AbstractVisitor { BlockNode destBlock = getBlock(h.getHandleOffset(), blocksMap); // skip self loop in handler if (connBlock != destBlock) - // && !connBlock.getPredecessors().contains(destBlock)) connect(connBlock, destBlock); } } @@ -208,9 +207,10 @@ public class BlockMakerVisitor extends AbstractVisitor { } private static void computeDominators(MethodNode mth) { - int nBlocks = mth.getBasicBlocks().size(); + List basicBlocks = mth.getBasicBlocks(); + int nBlocks = basicBlocks.size(); for (int i = 0; i < nBlocks; i++) { - BlockNode block = mth.getBasicBlocks().get(i); + BlockNode block = basicBlocks.get(i); block.setId(i); block.setDoms(new BitSet(nBlocks)); block.getDoms().set(0, nBlocks); @@ -224,7 +224,7 @@ public class BlockMakerVisitor extends AbstractVisitor { boolean changed; do { changed = false; - for (BlockNode block : mth.getBasicBlocks()) { + for (BlockNode block : basicBlocks) { if (block == entryBlock) continue; @@ -245,35 +245,36 @@ public class BlockMakerVisitor extends AbstractVisitor { markLoops(mth); // clear self dominance - for (BlockNode block : mth.getBasicBlocks()) { + for (BlockNode block : basicBlocks) { block.getDoms().clear(block.getId()); } // calculate immediate dominators - for (BlockNode block : mth.getBasicBlocks()) { + for (BlockNode block : basicBlocks) { if (block == entryBlock) continue; - if (block.getPredecessors().size() == 1) { - block.setIDom(block.getPredecessors().get(0)); + List preds = block.getPredecessors(); + if (preds.size() == 1) { + block.setIDom(preds.get(0)); } else { BitSet bs = new BitSet(block.getDoms().length()); bs.or(block.getDoms()); for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) { - BlockNode dom = mth.getBasicBlocks().get(i); + BlockNode dom = basicBlocks.get(i); bs.andNot(dom.getDoms()); } int c = bs.cardinality(); if (c == 1) { int id = bs.nextSetBit(0); - BlockNode idom = mth.getBasicBlocks().get(id); + BlockNode idom = basicBlocks.get(id); block.setIDom(idom); idom.getDominatesOn().add(block); } else { throw new JadxRuntimeException("Can't find immediate dominator for block " + block - + " in " + bs + " prec:" + block.getPredecessors()); + + " in " + bs + " preds:" + preds); } } } @@ -298,8 +299,9 @@ public class BlockMakerVisitor extends AbstractVisitor { private static void markReturnBlocks(MethodNode mth) { for (BlockNode block : mth.getBasicBlocks()) { - if (block.getInstructions().size() == 1) { - if (block.getInstructions().get(0).getType() == InsnType.RETURN) + List insns = block.getInstructions(); + if (insns.size() == 1) { + if (insns.get(0).getType() == InsnType.RETURN) block.getAttributes().add(AttributeFlag.RETURN); } } diff --git a/src/main/java/jadx/dex/visitors/BlockProcessingHelper.java b/src/main/java/jadx/dex/visitors/BlockProcessingHelper.java index cd583f0d7..ea7c4269b 100644 --- a/src/main/java/jadx/dex/visitors/BlockProcessingHelper.java +++ b/src/main/java/jadx/dex/visitors/BlockProcessingHelper.java @@ -10,6 +10,7 @@ import jadx.dex.nodes.MethodNode; import jadx.dex.trycatch.CatchAttr; import jadx.dex.trycatch.ExcHandlerAttr; import jadx.dex.trycatch.ExceptionHandler; +import jadx.dex.trycatch.TryCatchBlock; import jadx.utils.BlockUtils; public class BlockProcessingHelper { @@ -81,8 +82,12 @@ public class BlockProcessingHelper { if (insn.getType() == InsnType.THROW) { CatchAttr catchAttr = (CatchAttr) insn.getAttributes().get(AttributeType.CATCH_BLOCK); if (catchAttr != null) { - handlerAttr.getTryBlock().merge(mth, catchAttr.getTryBlock()); - catchAttr.getTryBlock().removeInsn(insn); + TryCatchBlock handlerBlock = handlerAttr.getTryBlock(); + TryCatchBlock catchBlock = catchAttr.getTryBlock(); + if (handlerBlock != catchBlock) { // TODO: why it can be? + handlerBlock.merge(mth, catchBlock); + catchBlock.removeInsn(insn); + } } } } diff --git a/src/main/java/jadx/dex/visitors/ClassModifier.java b/src/main/java/jadx/dex/visitors/ClassModifier.java index ef233125f..ca99edc3b 100644 --- a/src/main/java/jadx/dex/visitors/ClassModifier.java +++ b/src/main/java/jadx/dex/visitors/ClassModifier.java @@ -18,7 +18,7 @@ public class ClassModifier extends AbstractVisitor { visit(inner); } - for (Iterator it = cls.getMethods().iterator(); it.hasNext();) { + for (Iterator it = cls.getMethods().iterator(); it.hasNext(); ) { MethodNode mth = it.next(); AccessInfo af = mth.getAccessFlags(); @@ -34,17 +34,26 @@ public class ClassModifier extends AbstractVisitor { if (af.isConstructor() && af.isPublic() && mth.getArguments(false).isEmpty()) { - List bb = mth.getBasicBlocks(); - if (bb.isEmpty() || (bb.size() == 1 && bb.get(0).getInstructions().isEmpty())) { - if (mth.getSuperCall() == null) + if (mth.getSuperCall() == null) { + List bb = mth.getBasicBlocks(); + if (bb.isEmpty() || allBlocksEmpty(bb)) { it.remove(); + } } } } return false; } - private boolean isMethodUniq(ClassNode cls, MethodNode mth) { + private static boolean allBlocksEmpty(List blocks) { + for (BlockNode block : blocks) { + if (block.getInstructions().size() != 0) + return false; + } + return true; + } + + private static boolean isMethodUniq(ClassNode cls, MethodNode mth) { MethodInfo mi = mth.getMethodInfo(); for (MethodNode otherMth : cls.getMethods()) { MethodInfo omi = otherMth.getMethodInfo(); diff --git a/src/main/java/jadx/dex/visitors/CodeShrinker.java b/src/main/java/jadx/dex/visitors/CodeShrinker.java index fd3500933..c9b62ce78 100644 --- a/src/main/java/jadx/dex/visitors/CodeShrinker.java +++ b/src/main/java/jadx/dex/visitors/CodeShrinker.java @@ -36,24 +36,26 @@ public class CodeShrinker extends AbstractVisitor { private static void shrink(MethodNode mth) { for (BlockNode block : mth.getBasicBlocks()) { - InstructionRemover remover = new InstructionRemover(block.getInstructions()); - for (int i = 0; i < block.getInstructions().size(); i++) { - InsnNode insn = block.getInstructions().get(i); + List insnList = block.getInstructions(); + InstructionRemover remover = new InstructionRemover(insnList); + for (InsnNode insn : insnList) { // wrap instructions - if (insn.getResult() != null) { - List use = insn.getResult().getTypedVar().getUseList(); - if (use.size() == 1) { + RegisterArg result = insn.getResult(); + if (result != null) { + List useList = result.getTypedVar().getUseList(); + if (useList.size() == 1) { // variable is used only in this instruction // TODO not correct sometimes :( remover.add(insn); - } else if (use.size() == 2) { - InsnArg useInsnArg = use.get(1); + } else if (useList.size() == 2) { + InsnArg useInsnArg = selectOther(useList, result); InsnNode useInsn = useInsnArg.getParentInsn(); if (useInsn == null) { LOG.debug("parent insn null in " + useInsnArg + " from " + insn + " mth: " + mth); } else if (useInsn != insn) { boolean wrap = false; - if (false && insn.getResult().getTypedVar().getName() != null) { + // TODO + if (false && result.getTypedVar().getName() != null) { // don't wrap if result variable has name from debug info wrap = false; } else if (BlockUtils.blockContains(block, useInsn)) { @@ -181,10 +183,18 @@ public class CodeShrinker extends AbstractVisitor { list.removeAll(args); } i++; - if (i > 10000) + if (i > 1000) throw new JadxRuntimeException("Can't inline arguments for: " + arg + " insn: " + assignInsn); } while (!list.isEmpty()); return arg.wrapInstruction(assignInsn); } + + private static InsnArg selectOther(List list, RegisterArg insn) { + InsnArg first = list.get(0); + if (first == insn) + return list.get(1); + else + return first; + } } diff --git a/src/main/java/jadx/dex/visitors/EnumVisitor.java b/src/main/java/jadx/dex/visitors/EnumVisitor.java index 4f3386a76..8bd0868e2 100644 --- a/src/main/java/jadx/dex/visitors/EnumVisitor.java +++ b/src/main/java/jadx/dex/visitors/EnumVisitor.java @@ -22,7 +22,11 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public class EnumVisitor extends AbstractVisitor { + private static final Logger LOG = LoggerFactory.getLogger(EnumVisitor.class); @Override public boolean visit(ClassNode cls) throws JadxException { @@ -32,7 +36,7 @@ public class EnumVisitor extends AbstractVisitor { // collect enum fields, remove synthetic List enumFields = new ArrayList(); - for (Iterator it = cls.getFields().iterator(); it.hasNext();) { + for (Iterator it = cls.getFields().iterator(); it.hasNext(); ) { FieldNode f = it.next(); if (f.getAccessFlags().isEnum()) { enumFields.add(f); @@ -45,7 +49,7 @@ public class EnumVisitor extends AbstractVisitor { MethodNode staticMethod = null; // remove synthetic methods - for (Iterator it = cls.getMethods().iterator(); it.hasNext();) { + for (Iterator it = cls.getMethods().iterator(); it.hasNext(); ) { MethodNode mth = it.next(); MethodInfo mi = mth.getMethodInfo(); if (mi.isClassInit()) { @@ -60,11 +64,18 @@ public class EnumVisitor extends AbstractVisitor { } } - if (staticMethod == null) - throw new JadxException("Enum class init method not found"); - EnumClassAttr attr = new EnumClassAttr(enumFields.size()); cls.getAttributes().add(attr); + + if (staticMethod == null) { + LOG.warn("Enum class init method not found: {}", cls); + // for this broken enum puts found fields and mark as inconsistent + cls.getAttributes().add(AttributeFlag.INCONSISTENT_CODE); + for (FieldNode field : enumFields) { + attr.getFields().add(new EnumField(field.getName(), 0)); + } + return false; + } attr.setStaticMethod(staticMethod); // move enum specific instruction from static method to separate list @@ -117,7 +128,8 @@ public class EnumVisitor extends AbstractVisitor { constrArg = iArg; } else { constrArg = CodeShrinker.inlineArgument(staticMethod, (RegisterArg) iArg); - assert constrArg != null; + if (constrArg == null) + throw new JadxException("Can't inline constructor arg in enum: " + cls); } field.getArgs().add(constrArg); } @@ -127,7 +139,7 @@ public class EnumVisitor extends AbstractVisitor { for (ClassNode innerCls : cls.getInnerClasses()) { if (innerCls.getClassInfo().equals(co.getClassType())) { // remove constructor, because it is anonymous class - for (Iterator mit = innerCls.getMethods().iterator(); mit.hasNext();) { + for (Iterator mit = innerCls.getMethods().iterator(); mit.hasNext(); ) { MethodNode innerMth = (MethodNode) mit.next(); if (innerMth.getAccessFlags().isConstructor()) mit.remove();