From 408201b69bda073d3c180c909500ea004b4fdd66 Mon Sep 17 00:00:00 2001 From: Skylot Date: Thu, 17 Sep 2020 20:10:59 +0300 Subject: [PATCH] fix: restore enum for java 15 --- .../jadx/core/dex/visitors/EnumVisitor.java | 64 +++++++++++++++---- 1 file changed, 51 insertions(+), 13 deletions(-) diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/EnumVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/EnumVisitor.java index 7b9b2ca1f..4e56ae09f 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/EnumVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/EnumVisitor.java @@ -41,8 +41,10 @@ import jadx.core.dex.nodes.MethodNode; import jadx.core.dex.nodes.RootNode; import jadx.core.dex.visitors.shrink.CodeShrinkVisitor; import jadx.core.utils.BlockInsnPair; +import jadx.core.utils.BlockUtils; import jadx.core.utils.InsnRemover; import jadx.core.utils.InsnUtils; +import jadx.core.utils.Utils; import jadx.core.utils.exceptions.JadxException; import static jadx.core.utils.InsnUtils.checkInsnType; @@ -133,17 +135,8 @@ public class EnumVisitor extends AbstractVisitor { List enumFields = null; InsnArg arrArg = valuesInitInsn.getArg(0); if (arrArg.isInsnWrap()) { - InsnNode arrFillInsn = ((InsnWrapArg) arrArg).getWrapInsn(); - InsnType insnType = arrFillInsn.getType(); - if (insnType == InsnType.FILLED_NEW_ARRAY) { - enumFields = extractEnumFields(cls, arrFillInsn, staticBlock, toRemove); - } else if (insnType == InsnType.NEW_ARRAY) { - // empty enum - InsnArg arg = arrFillInsn.getArg(0); - if (arg.isLiteral() && ((LiteralArg) arg).getLiteral() == 0) { - enumFields = Collections.emptyList(); - } - } + InsnNode wrappedInsn = ((InsnWrapArg) arrArg).getWrapInsn(); + enumFields = extractEnumFieldsFromInsn(cls, staticBlock, wrappedInsn, toRemove); } if (enumFields == null) { return false; @@ -201,6 +194,50 @@ public class EnumVisitor extends AbstractVisitor { InsnRemover.removeWithoutUnbind(classInitMth, staticBlock, co); } + @Nullable + private List extractEnumFieldsFromInsn(ClassNode cls, BlockNode staticBlock, + InsnNode wrappedInsn, List toRemove) { + switch (wrappedInsn.getType()) { + case FILLED_NEW_ARRAY: + return extractEnumFieldsFromFilledArray(cls, wrappedInsn, staticBlock, toRemove); + + case INVOKE: + // handle redirection of values array fill (added in java 15) + return extractEnumFieldsFromInvoke(cls, staticBlock, (InvokeNode) wrappedInsn, toRemove); + + case NEW_ARRAY: + InsnArg arg = wrappedInsn.getArg(0); + if (arg.isLiteral() && ((LiteralArg) arg).getLiteral() == 0) { + // empty enum + return Collections.emptyList(); + } + return null; + + default: + return null; + } + } + + private List extractEnumFieldsFromInvoke(ClassNode cls, BlockNode staticBlock, + InvokeNode invokeNode, List toRemove) { + MethodInfo callMth = invokeNode.getCallMth(); + MethodNode valuesMth = cls.root().resolveMethod(callMth); + if (valuesMth == null || valuesMth.isVoidReturn()) { + return null; + } + BlockNode returnBlock = Utils.getOne(valuesMth.getExitBlocks()); + InsnNode returnInsn = BlockUtils.getLastInsn(returnBlock); + InsnNode wrappedInsn = getWrappedInsn(getSingleArg(returnInsn)); + if (wrappedInsn == null) { + return null; + } + List enumFields = extractEnumFieldsFromInsn(cls, staticBlock, wrappedInsn, toRemove); + if (enumFields != null) { + valuesMth.add(AFlag.DONT_GENERATE); + } + return enumFields; + } + private BlockInsnPair getValuesInitInsn(MethodNode classInitMth, FieldNode valuesField) { FieldInfo searchField = valuesField.getFieldInfo(); for (BlockNode blockNode : classInitMth.getBasicBlocks()) { @@ -217,7 +254,8 @@ public class EnumVisitor extends AbstractVisitor { return null; } - private List extractEnumFields(ClassNode cls, InsnNode arrFillInsn, BlockNode staticBlock, List toRemove) { + private List extractEnumFieldsFromFilledArray(ClassNode cls, InsnNode arrFillInsn, BlockNode staticBlock, + List toRemove) { List enumFields = new ArrayList<>(); for (InsnArg arg : arrFillInsn.getArguments()) { EnumField field = null; @@ -225,7 +263,7 @@ public class EnumVisitor extends AbstractVisitor { InsnNode wrappedInsn = ((InsnWrapArg) arg).getWrapInsn(); field = processEnumFieldByField(cls, wrappedInsn, staticBlock, toRemove); } else if (arg.isRegister()) { - field = processEnumFiledByRegister(cls, ((RegisterArg) arg), toRemove); + field = processEnumFiledByRegister(cls, (RegisterArg) arg, toRemove); } if (field == null) { return null;