diff --git a/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/EnumMapAttr.java b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/EnumMapAttr.java index 9221da8aa..5bdd8f1a4 100644 --- a/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/EnumMapAttr.java +++ b/jadx-core/src/main/java/jadx/core/dex/attributes/nodes/EnumMapAttr.java @@ -1,12 +1,14 @@ package jadx.core.dex.attributes.nodes; +import java.util.HashMap; +import java.util.Map; + +import org.jetbrains.annotations.Nullable; + import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.IAttribute; import jadx.core.dex.nodes.FieldNode; -import java.util.HashMap; -import java.util.Map; - public class EnumMapAttr implements IAttribute { public static class KeyValueMap { @@ -21,9 +23,14 @@ public class EnumMapAttr implements IAttribute { } } - private final Map fieldsMap = new HashMap<>(); + @Nullable + private Map fieldsMap; + @Nullable public KeyValueMap getMap(FieldNode field) { + if (fieldsMap == null) { + return null; + } return fieldsMap.get(field); } @@ -31,11 +38,18 @@ public class EnumMapAttr implements IAttribute { KeyValueMap map = getMap(field); if (map == null) { map = new KeyValueMap(); + if (fieldsMap == null) { + fieldsMap = new HashMap<>(); + } fieldsMap.put(field, map); } map.put(key, value); } + public boolean isEmpty() { + return fieldsMap == null || fieldsMap.isEmpty(); + } + @Override public AType getType() { return AType.ENUM_MAP; @@ -45,5 +59,4 @@ public class EnumMapAttr implements IAttribute { public String toString() { return "Enum fields map: " + fieldsMap; } - } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/ReSugarCode.java b/jadx-core/src/main/java/jadx/core/dex/visitors/ReSugarCode.java index eabebe155..134375919 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/ReSugarCode.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/ReSugarCode.java @@ -1,6 +1,11 @@ package jadx.core.dex.visitors; -import jadx.core.ProcessClass; +import java.util.List; + +import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import jadx.core.dex.attributes.AFlag; import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.nodes.EnumMapAttr; @@ -18,18 +23,13 @@ import jadx.core.dex.instructions.args.InsnWrapArg; import jadx.core.dex.instructions.args.LiteralArg; import jadx.core.dex.nodes.BlockNode; import jadx.core.dex.nodes.ClassNode; +import jadx.core.dex.nodes.DexNode; import jadx.core.dex.nodes.FieldNode; import jadx.core.dex.nodes.InsnNode; import jadx.core.dex.nodes.MethodNode; import jadx.core.utils.InstructionRemover; -import jadx.core.utils.exceptions.DecodeException; import jadx.core.utils.exceptions.JadxException; -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - @JadxVisitor( name = "ReSugarCode", desc = "Simplify synthetic or verbose code", @@ -39,6 +39,12 @@ public class ReSugarCode extends AbstractVisitor { private static final Logger LOG = LoggerFactory.getLogger(ReSugarCode.class); + @Override + public boolean visit(ClassNode cls) throws JadxException { + initClsEnumMap(cls); + return true; + } + @Override public void visit(MethodNode mth) throws JadxException { if (mth.isNoCode()) { @@ -78,7 +84,7 @@ public class ReSugarCode extends AbstractVisitor { * Replace new array and sequence of array-put to new filled-array instruction. */ private static InsnNode processNewArray(MethodNode mth, List instructions, int i, - InstructionRemover remover) { + InstructionRemover remover) { NewArrayNode newArrayInsn = (NewArrayNode) instructions.get(i); InsnArg arg = newArrayInsn.getArg(0); if (!arg.isLiteral()) { @@ -115,7 +121,7 @@ public class ReSugarCode extends AbstractVisitor { if (wrapInsn.getType() != InsnType.AGET) { return; } - EnumMapInfo enumMapInfo = checkEnumMapAccess(mth, wrapInsn); + EnumMapInfo enumMapInfo = checkEnumMapAccess(mth.dex(), wrapInsn); if (enumMapInfo == null) { return; } @@ -144,49 +150,40 @@ public class ReSugarCode extends AbstractVisitor { checkAndHideClass(enumMapField.getParentClass()); } - private static EnumMapAttr.KeyValueMap getEnumMap(MethodNode mth, FieldNode field) { - ClassNode syntheticClass = field.getParentClass(); - EnumMapAttr mapAttr = syntheticClass.get(AType.ENUM_MAP); - if (mapAttr != null) { - return mapAttr.getMap(field); + private static void initClsEnumMap(ClassNode enumCls) { + MethodNode clsInitMth = enumCls.getClassInitMth(); + if (clsInitMth == null || clsInitMth.isNoCode()) { + return; } - synchronized (ProcessClass.getSyncObj(syntheticClass)) { - mapAttr = new EnumMapAttr(); - syntheticClass.addAttr(mapAttr); - - MethodNode clsInitMth = syntheticClass.searchMethodByName("()V"); - if (clsInitMth == null || clsInitMth.isNoCode()) { - return null; - } - if (clsInitMth.getBasicBlocks() == null) { - try { - clsInitMth.load(); - } catch (DecodeException e) { - LOG.error("Load failed", e); - return null; - } - if (clsInitMth.getBasicBlocks() == null) { - // TODO: - return null; + EnumMapAttr mapAttr = new EnumMapAttr(); + for (BlockNode block : clsInitMth.getBasicBlocks()) { + for (InsnNode insn : block.getInstructions()) { + if (insn.getType() == InsnType.APUT) { + addToEnumMap(enumCls.dex(), mapAttr, insn); } } - for (BlockNode block : clsInitMth.getBasicBlocks()) { - for (InsnNode insn : block.getInstructions()) { - if (insn.getType() == InsnType.APUT) { - addToEnumMap(mth, mapAttr, insn); - } - } - } - return mapAttr.getMap(field); + } + if (!mapAttr.isEmpty()) { + enumCls.addAttr(mapAttr); } } - private static void addToEnumMap(MethodNode mth, EnumMapAttr mapAttr, InsnNode aputInsn) { + @Nullable + private static EnumMapAttr.KeyValueMap getEnumMap(MethodNode mth, FieldNode field) { + ClassNode syntheticClass = field.getParentClass(); + EnumMapAttr mapAttr = syntheticClass.get(AType.ENUM_MAP); + if (mapAttr == null) { + return null; + } + return mapAttr.getMap(field); + } + + private static void addToEnumMap(DexNode dex, EnumMapAttr mapAttr, InsnNode aputInsn) { InsnArg litArg = aputInsn.getArg(2); if (!litArg.isLiteral()) { return; } - EnumMapInfo mapInfo = checkEnumMapAccess(mth, aputInsn); + EnumMapInfo mapInfo = checkEnumMapAccess(dex, aputInsn); if (mapInfo == null) { return; } @@ -203,7 +200,7 @@ public class ReSugarCode extends AbstractVisitor { if (!(index instanceof FieldInfo)) { return; } - FieldNode fieldNode = mth.dex().resolveField((FieldInfo) index); + FieldNode fieldNode = dex.resolveField((FieldInfo) index); if (fieldNode == null) { return; } @@ -211,7 +208,7 @@ public class ReSugarCode extends AbstractVisitor { mapAttr.add(field, literal, fieldNode); } - public static EnumMapInfo checkEnumMapAccess(MethodNode mth, InsnNode checkInsn) { + public static EnumMapInfo checkEnumMapAccess(DexNode dex, InsnNode checkInsn) { InsnArg sgetArg = checkInsn.getArg(0); InsnArg invArg = checkInsn.getArg(1); if (!sgetArg.isInsnWrap() || !invArg.isInsnWrap()) { @@ -226,7 +223,7 @@ public class ReSugarCode extends AbstractVisitor { if (!inv.getCallMth().getShortId().equals("ordinal()I")) { return null; } - ClassNode enumCls = mth.dex().resolveClass(inv.getCallMth().getDeclClass()); + ClassNode enumCls = dex.resolveClass(inv.getCallMth().getDeclClass()); if (enumCls == null || !enumCls.isEnum()) { return null; } @@ -234,7 +231,7 @@ public class ReSugarCode extends AbstractVisitor { if (!(index instanceof FieldInfo)) { return null; } - FieldNode enumMapField = mth.dex().resolveField((FieldInfo) index); + FieldNode enumMapField = dex.resolveField((FieldInfo) index); if (enumMapField == null || !enumMapField.getAccessFlags().isSynthetic()) { return null; }