fix: additional patterns to restore enum classes (#830)
This commit is contained in:
@@ -5,26 +5,26 @@ import java.util.List;
|
||||
|
||||
import jadx.core.dex.attributes.AType;
|
||||
import jadx.core.dex.attributes.IAttribute;
|
||||
import jadx.core.dex.info.FieldInfo;
|
||||
import jadx.core.dex.instructions.mods.ConstructorInsn;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
import jadx.core.dex.nodes.FieldNode;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
|
||||
public class EnumClassAttr implements IAttribute {
|
||||
|
||||
public static class EnumField {
|
||||
private final FieldInfo field;
|
||||
private final FieldNode field;
|
||||
private final ConstructorInsn constrInsn;
|
||||
private final int startArg;
|
||||
private ClassNode cls;
|
||||
|
||||
public EnumField(FieldInfo field, ConstructorInsn co, int startArg) {
|
||||
public EnumField(FieldNode field, ConstructorInsn co, int startArg) {
|
||||
this.field = field;
|
||||
this.constrInsn = co;
|
||||
this.startArg = startArg;
|
||||
}
|
||||
|
||||
public FieldInfo getField() {
|
||||
public FieldNode getField() {
|
||||
return field;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
package jadx.core.dex.visitors;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -22,7 +26,9 @@ import jadx.core.dex.instructions.InsnType;
|
||||
import jadx.core.dex.instructions.args.ArgType;
|
||||
import jadx.core.dex.instructions.args.InsnArg;
|
||||
import jadx.core.dex.instructions.args.InsnWrapArg;
|
||||
import jadx.core.dex.instructions.args.LiteralArg;
|
||||
import jadx.core.dex.instructions.args.RegisterArg;
|
||||
import jadx.core.dex.instructions.args.SSAVar;
|
||||
import jadx.core.dex.instructions.mods.ConstructorInsn;
|
||||
import jadx.core.dex.nodes.BlockNode;
|
||||
import jadx.core.dex.nodes.ClassNode;
|
||||
@@ -31,7 +37,7 @@ import jadx.core.dex.nodes.FieldNode;
|
||||
import jadx.core.dex.nodes.InsnNode;
|
||||
import jadx.core.dex.nodes.MethodNode;
|
||||
import jadx.core.dex.visitors.shrink.CodeShrinkVisitor;
|
||||
import jadx.core.utils.ErrorsCounter;
|
||||
import jadx.core.utils.InsnRemover;
|
||||
import jadx.core.utils.InsnUtils;
|
||||
import jadx.core.utils.exceptions.JadxException;
|
||||
|
||||
@@ -48,7 +54,7 @@ public class EnumVisitor extends AbstractVisitor {
|
||||
AccessInfo accessFlags = cls.getAccessFlags();
|
||||
if (accessFlags.isEnum()) {
|
||||
cls.setAccessFlags(accessFlags.remove(AccessFlags.ACC_ENUM));
|
||||
cls.addAttr(AType.COMMENTS, "'enum' modifier removed");
|
||||
cls.addAttr(AType.COMMENTS, "JADX INFO: Failed to restore enum class, 'enum' modifier removed");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -58,37 +64,218 @@ public class EnumVisitor extends AbstractVisitor {
|
||||
if (!cls.isEnum()) {
|
||||
return false;
|
||||
}
|
||||
// search class init method
|
||||
MethodNode staticMethod = null;
|
||||
for (MethodNode mth : cls.getMethods()) {
|
||||
MethodInfo mi = mth.getMethodInfo();
|
||||
if (mi.isClassInit()) {
|
||||
staticMethod = mth;
|
||||
MethodNode classInitMth = cls.getClassInitMth();
|
||||
if (classInitMth == null) {
|
||||
cls.addAttr(AType.COMMENTS, "JADX INFO: Enum class init method not found");
|
||||
return false;
|
||||
}
|
||||
if (classInitMth.getBasicBlocks().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
BlockNode staticBlock = classInitMth.getBasicBlocks().get(0);
|
||||
|
||||
ArgType clsType = cls.getClassInfo().getType();
|
||||
|
||||
// search "$VALUES" field (holds all enum values)
|
||||
List<FieldNode> valuesCandidates = cls.getFields().stream()
|
||||
.filter(f -> f.getAccessFlags().isStatic())
|
||||
.filter(f -> f.getType().isArray())
|
||||
.filter(f -> Objects.equals(f.getType().getArrayRootElement(), clsType))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (valuesCandidates.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
if (valuesCandidates.size() > 1) {
|
||||
valuesCandidates.removeIf(f -> !f.getAccessFlags().isSynthetic());
|
||||
}
|
||||
if (valuesCandidates.size() > 1) {
|
||||
Optional<FieldNode> valuesOpt = valuesCandidates.stream().filter(f -> f.getName().equals("$VALUES")).findAny();
|
||||
if (valuesOpt.isPresent()) {
|
||||
valuesCandidates.clear();
|
||||
valuesCandidates.add(valuesOpt.get());
|
||||
}
|
||||
}
|
||||
if (valuesCandidates.size() != 1) {
|
||||
cls.addAttr(AType.COMMENTS, "JADX INFO: found several \"values\" enum fields: " + valuesCandidates);
|
||||
return false;
|
||||
}
|
||||
FieldNode valuesField = valuesCandidates.get(0);
|
||||
List<InsnNode> toRemove = new ArrayList<>();
|
||||
|
||||
// search "$VALUES" array init and collect enum fields
|
||||
List<EnumField> enumFields = null;
|
||||
for (InsnNode insn : staticBlock.getInstructions()) {
|
||||
if (insn.getType() != InsnType.SPUT) {
|
||||
continue;
|
||||
}
|
||||
FieldInfo f = (FieldInfo) ((IndexInsnNode) insn).getIndex();
|
||||
if (f.equals(valuesField.getFieldInfo())) {
|
||||
InsnArg arrArg = insn.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();
|
||||
}
|
||||
}
|
||||
}
|
||||
toRemove.add(insn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (staticMethod == null) {
|
||||
ErrorsCounter.classWarn(cls, "Enum class init method not found");
|
||||
if (enumFields == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ArgType clsType = cls.getClassInfo().getType();
|
||||
String enumConstructor = "<init>(Ljava/lang/String;I)V";
|
||||
// TODO: detect these methods by analyzing method instructions
|
||||
String valuesOfMethod = "valueOf(Ljava/lang/String;)" + TypeGen.signature(clsType);
|
||||
String valuesMethod = "values()" + TypeGen.signature(ArgType.array(clsType));
|
||||
// all checks complete, perform transform
|
||||
EnumClassAttr attr = new EnumClassAttr(enumFields.size());
|
||||
attr.setStaticMethod(classInitMth);
|
||||
attr.getFields().addAll(enumFields);
|
||||
cls.addAttr(attr);
|
||||
|
||||
// collect enum fields, remove synthetic
|
||||
List<FieldNode> enumFields = new ArrayList<>();
|
||||
for (FieldNode f : cls.getFields()) {
|
||||
if (f.getAccessFlags().isEnum()) {
|
||||
enumFields.add(f);
|
||||
f.add(AFlag.DONT_GENERATE);
|
||||
} else if (f.getAccessFlags().isSynthetic()) {
|
||||
f.add(AFlag.DONT_GENERATE);
|
||||
for (EnumField field : attr.getFields()) {
|
||||
ConstructorInsn co = field.getConstrInsn();
|
||||
FieldNode fieldNode = field.getField();
|
||||
|
||||
// use string arg from the constructor as enum field name
|
||||
String name = getConstString(cls.dex(), co.getArg(0));
|
||||
if (name != null
|
||||
&& !fieldNode.getAlias().equals(name)
|
||||
&& NameMapper.isValidAndPrintable(name)
|
||||
&& cls.root().getArgs().isRenameValid()) {
|
||||
fieldNode.getFieldInfo().setAlias(name);
|
||||
}
|
||||
if (!co.getClassType().equals(cls.getClassInfo())) {
|
||||
// enum contains additional methods
|
||||
for (ClassNode innerCls : cls.getInnerClasses()) {
|
||||
processEnumInnerCls(co, field, innerCls);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
valuesField.add(AFlag.DONT_GENERATE);
|
||||
enumFields.forEach(f -> f.getField().add(AFlag.DONT_GENERATE));
|
||||
InsnRemover.removeAllAndUnbind(classInitMth, staticBlock, toRemove);
|
||||
if (classInitMth.countInsns() == 0) {
|
||||
classInitMth.add(AFlag.DONT_GENERATE);
|
||||
}
|
||||
removeEnumMethods(cls, clsType);
|
||||
return true;
|
||||
}
|
||||
|
||||
private List<EnumField> extractEnumFields(ClassNode cls, InsnNode arrFillInsn, BlockNode staticBlock, List<InsnNode> toRemove) {
|
||||
List<EnumField> enumFields = new ArrayList<>();
|
||||
for (InsnArg arg : arrFillInsn.getArguments()) {
|
||||
EnumField field = null;
|
||||
if (arg.isInsnWrap()) {
|
||||
InsnNode wrappedInsn = ((InsnWrapArg) arg).getWrapInsn();
|
||||
field = processEnumFieldByField(cls, wrappedInsn, staticBlock, toRemove);
|
||||
} else if (arg.isRegister()) {
|
||||
field = processEnumFiledByRegister(cls, ((RegisterArg) arg), toRemove);
|
||||
}
|
||||
if (field == null) {
|
||||
return null;
|
||||
}
|
||||
enumFields.add(field);
|
||||
}
|
||||
return enumFields;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private EnumField processEnumFieldByField(ClassNode cls, InsnNode sgetInsn, BlockNode staticBlock, List<InsnNode> toRemove) {
|
||||
if (sgetInsn.getType() != InsnType.SGET) {
|
||||
return null;
|
||||
}
|
||||
FieldInfo fieldInfo = (FieldInfo) ((IndexInsnNode) sgetInsn).getIndex();
|
||||
FieldNode enumFieldNode = cls.searchField(fieldInfo);
|
||||
if (enumFieldNode == null) {
|
||||
return null;
|
||||
}
|
||||
InsnNode sputInsn = searchFieldPutInsn(cls, staticBlock, enumFieldNode);
|
||||
if (sputInsn == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ConstructorInsn co = getConstructorInsn(sputInsn);
|
||||
if (co == null) {
|
||||
return null;
|
||||
}
|
||||
toRemove.add(sgetInsn);
|
||||
toRemove.add(sputInsn);
|
||||
toRemove.add(co);
|
||||
return createEnumFieldByConstructor(cls, enumFieldNode, co);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private EnumField processEnumFiledByRegister(ClassNode cls, RegisterArg arg, List<InsnNode> toRemove) {
|
||||
SSAVar ssaVar = arg.getSVar();
|
||||
if (ssaVar.getUseCount() == 1) {
|
||||
return null;
|
||||
}
|
||||
final InsnNode sputInsn = ssaVar.getUseList().get(0).getParentInsn();
|
||||
if (sputInsn == null || sputInsn.getType() != InsnType.SPUT) {
|
||||
return null;
|
||||
}
|
||||
FieldInfo fieldInfo = (FieldInfo) ((IndexInsnNode) sputInsn).getIndex();
|
||||
FieldNode enumFieldNode = cls.searchField(fieldInfo);
|
||||
if (enumFieldNode == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
InsnNode constrInsn = ssaVar.getAssign().getParentInsn();
|
||||
if (constrInsn == null || constrInsn.getType() != InsnType.CONSTRUCTOR) {
|
||||
return null;
|
||||
}
|
||||
toRemove.add(sputInsn);
|
||||
toRemove.add(constrInsn);
|
||||
return createEnumFieldByConstructor(cls, enumFieldNode, (ConstructorInsn) constrInsn);
|
||||
}
|
||||
|
||||
private EnumField createEnumFieldByConstructor(ClassNode cls, FieldNode enumFieldNode, ConstructorInsn co) {
|
||||
// usually constructor signature is '<init>(Ljava/lang/String;I)V'.
|
||||
// sometimes for one field enum second arg can be omitted
|
||||
if (co.getArgsCount() < 1) {
|
||||
return null;
|
||||
}
|
||||
ClassInfo clsInfo = co.getClassType();
|
||||
ClassNode constrCls = cls.dex().resolveClass(clsInfo);
|
||||
if (constrCls == null) {
|
||||
return null;
|
||||
}
|
||||
if (!clsInfo.equals(cls.getClassInfo()) && !constrCls.getAccessFlags().isEnum()) {
|
||||
return null;
|
||||
}
|
||||
int startArg = co.getArgsCount() == 1 ? 1 : 2;
|
||||
return new EnumField(enumFieldNode, co, startArg);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private InsnNode searchFieldPutInsn(ClassNode cls, BlockNode staticBlock, FieldNode enumFieldNode) {
|
||||
for (InsnNode sputInsn : staticBlock.getInstructions()) {
|
||||
if (sputInsn != null && sputInsn.getType() == InsnType.SPUT) {
|
||||
FieldInfo f = (FieldInfo) ((IndexInsnNode) sputInsn).getIndex();
|
||||
FieldNode fieldNode = cls.searchField(f);
|
||||
if (Objects.equals(fieldNode, enumFieldNode)) {
|
||||
return sputInsn;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO: detect these methods by analyzing method instructions
|
||||
private void removeEnumMethods(ClassNode cls, ArgType clsType) {
|
||||
String enumConstructor = "<init>(Ljava/lang/String;I)V";
|
||||
String enumConstructorAlt = "<init>(Ljava/lang/String;)V";
|
||||
String valuesOfMethod = "valueOf(Ljava/lang/String;)" + TypeGen.signature(clsType);
|
||||
String valuesMethod = "values()" + TypeGen.signature(ArgType.array(clsType));
|
||||
|
||||
// remove synthetic methods
|
||||
for (MethodNode mth : cls.getMethods()) {
|
||||
MethodInfo mi = mth.getMethodInfo();
|
||||
@@ -98,7 +285,8 @@ public class EnumVisitor extends AbstractVisitor {
|
||||
String shortId = mi.getShortId();
|
||||
boolean isSynthetic = mth.getAccessFlags().isSynthetic();
|
||||
if (mi.isConstructor() && !isSynthetic) {
|
||||
if (shortId.equals(enumConstructor)) {
|
||||
if (shortId.equals(enumConstructor)
|
||||
|| shortId.equals(enumConstructorAlt)) {
|
||||
mth.add(AFlag.DONT_GENERATE);
|
||||
}
|
||||
} else if (isSynthetic
|
||||
@@ -107,73 +295,6 @@ public class EnumVisitor extends AbstractVisitor {
|
||||
mth.add(AFlag.DONT_GENERATE);
|
||||
}
|
||||
}
|
||||
|
||||
EnumClassAttr attr = new EnumClassAttr(enumFields.size());
|
||||
cls.addAttr(attr);
|
||||
|
||||
attr.setStaticMethod(staticMethod);
|
||||
ClassInfo classInfo = cls.getClassInfo();
|
||||
|
||||
// move enum specific instruction from static method to separate list
|
||||
BlockNode staticBlock = staticMethod.getBasicBlocks().get(0);
|
||||
List<InsnNode> enumPutInsns = new ArrayList<>();
|
||||
List<InsnNode> list = staticBlock.getInstructions();
|
||||
int size = list.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
InsnNode insn = list.get(i);
|
||||
if (insn.getType() != InsnType.SPUT) {
|
||||
continue;
|
||||
}
|
||||
FieldInfo f = (FieldInfo) ((IndexInsnNode) insn).getIndex();
|
||||
if (!f.getDeclClass().equals(classInfo)) {
|
||||
continue;
|
||||
}
|
||||
FieldNode fieldNode = cls.searchField(f);
|
||||
if (fieldNode != null && isEnumArrayField(classInfo, fieldNode)) {
|
||||
if (i == size - 1) {
|
||||
staticMethod.add(AFlag.DONT_GENERATE);
|
||||
} else {
|
||||
list.subList(0, i + 1).clear();
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
enumPutInsns.add(insn);
|
||||
}
|
||||
}
|
||||
|
||||
for (InsnNode putInsn : enumPutInsns) {
|
||||
ConstructorInsn co = getConstructorInsn(putInsn);
|
||||
if (co == null || co.getArgsCount() < 2) {
|
||||
continue;
|
||||
}
|
||||
ClassInfo clsInfo = co.getClassType();
|
||||
ClassNode constrCls = cls.dex().resolveClass(clsInfo);
|
||||
if (constrCls == null) {
|
||||
continue;
|
||||
}
|
||||
if (!clsInfo.equals(classInfo) && !constrCls.getAccessFlags().isEnum()) {
|
||||
continue;
|
||||
}
|
||||
FieldInfo fieldInfo = (FieldInfo) ((IndexInsnNode) putInsn).getIndex();
|
||||
String name = getConstString(cls.dex(), co.getArg(0));
|
||||
if (name != null
|
||||
&& !fieldInfo.getAlias().equals(name)
|
||||
&& NameMapper.isValidAndPrintable(name)
|
||||
&& cls.root().getArgs().isRenameValid()) {
|
||||
fieldInfo.setAlias(name);
|
||||
}
|
||||
|
||||
EnumField field = new EnumField(fieldInfo, co, 2);
|
||||
attr.getFields().add(field);
|
||||
|
||||
if (!co.getClassType().equals(classInfo)) {
|
||||
// enum contains additional methods
|
||||
for (ClassNode innerCls : cls.getInnerClasses()) {
|
||||
processEnumInnerCls(co, field, innerCls);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void processEnumInnerCls(ConstructorInsn co, EnumField field, ClassNode innerCls) {
|
||||
@@ -190,19 +311,11 @@ public class EnumVisitor extends AbstractVisitor {
|
||||
innerCls.add(AFlag.DONT_GENERATE);
|
||||
}
|
||||
|
||||
private boolean isEnumArrayField(ClassInfo classInfo, FieldNode fieldNode) {
|
||||
if (fieldNode.getAccessFlags().isSynthetic()) {
|
||||
ArgType fType = fieldNode.getType();
|
||||
return fType.isArray() && fType.getArrayRootElement().equals(classInfo.getType());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private ConstructorInsn getConstructorInsn(InsnNode putInsn) {
|
||||
if (putInsn.getArgsCount() != 1) {
|
||||
private ConstructorInsn getConstructorInsn(InsnNode insn) {
|
||||
if (insn.getArgsCount() != 1) {
|
||||
return null;
|
||||
}
|
||||
InsnArg arg = putInsn.getArg(0);
|
||||
InsnArg arg = insn.getArg(0);
|
||||
if (arg.isInsnWrap()) {
|
||||
return castConstructorInsn(((InsnWrapArg) arg).getWrapInsn());
|
||||
}
|
||||
|
||||
@@ -38,6 +38,11 @@ public abstract class SmaliTest extends IntegrationTest {
|
||||
return getClassNodeFromSmaliWithPkg(getTestPkg(), getTestName());
|
||||
}
|
||||
|
||||
protected ClassNode getClassNodeFromSmaliWithClsName(String fullClsName) {
|
||||
return getClassNodeFromSmali(getTestPkg() + File.separatorChar + getTestName(), fullClsName);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
protected ClassNode getClassNodeFromSmali(String clsName) {
|
||||
return getClassNodeFromSmali(clsName, clsName);
|
||||
}
|
||||
|
||||
@@ -42,14 +42,19 @@ public class JadxCodeAssertions extends AbstractStringAssert<JadxCodeAssertions>
|
||||
}
|
||||
String indent = TestUtils.indent(commonIndent);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
boolean first = true;
|
||||
for (String line : lines) {
|
||||
if (!line.isEmpty()) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
sb.append(CodeWriter.NL);
|
||||
}
|
||||
sb.append(indent);
|
||||
sb.append(line);
|
||||
}
|
||||
sb.append(CodeWriter.NL);
|
||||
}
|
||||
return countString(1, sb.toString());
|
||||
return containsOnlyOnce(sb.toString());
|
||||
}
|
||||
|
||||
public JadxCodeAssertions print() {
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package jadx.tests.integration.enums;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.tests.api.SmaliTest;
|
||||
|
||||
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
|
||||
|
||||
public class TestEnums5 extends SmaliTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
assertThat(getClassNodeFromSmaliWithClsName("kotlin.collections.State"))
|
||||
.code()
|
||||
.containsLines(
|
||||
"enum State {",
|
||||
indent() + "Ready,",
|
||||
indent() + "NotReady,",
|
||||
indent() + "Done,",
|
||||
indent() + "Failed",
|
||||
"}");
|
||||
}
|
||||
}
|
||||
@@ -14,11 +14,13 @@ public class TestEnumsInterface extends IntegrationTest {
|
||||
|
||||
public enum Operation implements IOperation {
|
||||
PLUS {
|
||||
@Override
|
||||
public int apply(int x, int y) {
|
||||
return x + y;
|
||||
}
|
||||
},
|
||||
MINUS {
|
||||
@Override
|
||||
public int apply(int x, int y) {
|
||||
return x - y;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package jadx.tests.integration.enums;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.tests.api.SmaliTest;
|
||||
|
||||
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
|
||||
|
||||
public class TestEnumsWithStaticFields extends SmaliTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
disableCompilation();
|
||||
assertThat(getClassNodeFromSmali())
|
||||
.code()
|
||||
.containsOnlyOnce("INSTANCE;")
|
||||
.containsOnlyOnce("private static c sB;")
|
||||
.doesNotContain(" sA")
|
||||
.doesNotContain(" sC")
|
||||
.doesNotContain("private TestEnumsWithStaticFields(String str) {");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
.class final enum Lkotlin/collections/State;
|
||||
.super Ljava/lang/Enum;
|
||||
|
||||
|
||||
# annotations
|
||||
.annotation system Ldalvik/annotation/Signature;
|
||||
value = {
|
||||
"Ljava/lang/Enum<",
|
||||
"Lkotlin/collections/State;",
|
||||
">;"
|
||||
}
|
||||
.end annotation
|
||||
|
||||
# static fields
|
||||
.field private static final synthetic $VALUES:[Lkotlin/collections/State;
|
||||
|
||||
.field public static final enum Done:Lkotlin/collections/State;
|
||||
|
||||
.field public static final enum Failed:Lkotlin/collections/State;
|
||||
|
||||
.field public static final enum NotReady:Lkotlin/collections/State;
|
||||
|
||||
.field public static final enum Ready:Lkotlin/collections/State;
|
||||
|
||||
|
||||
# direct methods
|
||||
.method static constructor <clinit>()V
|
||||
.registers 4
|
||||
|
||||
const/4 v0, 0x4
|
||||
|
||||
new-array v0, v0, [Lkotlin/collections/State;
|
||||
|
||||
new-instance v1, Lkotlin/collections/State;
|
||||
|
||||
const-string v2, "Ready"
|
||||
|
||||
const/4 v3, 0x0
|
||||
|
||||
invoke-direct {v1, v2, v3}, Lkotlin/collections/State;-><init>(Ljava/lang/String;I)V
|
||||
|
||||
sput-object v1, Lkotlin/collections/State;->Ready:Lkotlin/collections/State;
|
||||
|
||||
aput-object v1, v0, v3
|
||||
|
||||
new-instance v1, Lkotlin/collections/State;
|
||||
|
||||
const-string v2, "NotReady"
|
||||
|
||||
const/4 v3, 0x1
|
||||
|
||||
invoke-direct {v1, v2, v3}, Lkotlin/collections/State;-><init>(Ljava/lang/String;I)V
|
||||
|
||||
sput-object v1, Lkotlin/collections/State;->NotReady:Lkotlin/collections/State;
|
||||
|
||||
aput-object v1, v0, v3
|
||||
|
||||
new-instance v1, Lkotlin/collections/State;
|
||||
|
||||
const-string v2, "Done"
|
||||
|
||||
const/4 v3, 0x2
|
||||
|
||||
invoke-direct {v1, v2, v3}, Lkotlin/collections/State;-><init>(Ljava/lang/String;I)V
|
||||
|
||||
sput-object v1, Lkotlin/collections/State;->Done:Lkotlin/collections/State;
|
||||
|
||||
aput-object v1, v0, v3
|
||||
|
||||
new-instance v1, Lkotlin/collections/State;
|
||||
|
||||
const-string v2, "Failed"
|
||||
|
||||
const/4 v3, 0x3
|
||||
|
||||
invoke-direct {v1, v2, v3}, Lkotlin/collections/State;-><init>(Ljava/lang/String;I)V
|
||||
|
||||
sput-object v1, Lkotlin/collections/State;->Failed:Lkotlin/collections/State;
|
||||
|
||||
aput-object v1, v0, v3
|
||||
|
||||
sput-object v0, Lkotlin/collections/State;->$VALUES:[Lkotlin/collections/State;
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method protected constructor <init>(Ljava/lang/String;I)V
|
||||
.registers 3
|
||||
.param p1, "$enum_name_or_ordinal$0" # Ljava/lang/String;
|
||||
.param p2, "$enum_name_or_ordinal$1" # I
|
||||
.annotation system Ldalvik/annotation/Signature;
|
||||
value = {
|
||||
"()V"
|
||||
}
|
||||
.end annotation
|
||||
|
||||
.line 4
|
||||
invoke-direct {p0, p1, p2}, Ljava/lang/Enum;-><init>(Ljava/lang/String;I)V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method public static valueOf(Ljava/lang/String;)Lkotlin/collections/State;
|
||||
.registers 2
|
||||
|
||||
const-class v0, Lkotlin/collections/State;
|
||||
|
||||
invoke-static {v0, p0}, Ljava/lang/Enum;->valueOf(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
|
||||
|
||||
move-result-object p0
|
||||
|
||||
check-cast p0, Lkotlin/collections/State;
|
||||
|
||||
return-object p0
|
||||
.end method
|
||||
|
||||
.method public static values()[Lkotlin/collections/State;
|
||||
.registers 1
|
||||
|
||||
sget-object v0, Lkotlin/collections/State;->$VALUES:[Lkotlin/collections/State;
|
||||
|
||||
invoke-virtual {v0}, [Lkotlin/collections/State;->clone()Ljava/lang/Object;
|
||||
|
||||
move-result-object v0
|
||||
|
||||
check-cast v0, [Lkotlin/collections/State;
|
||||
|
||||
return-object v0
|
||||
.end method
|
||||
@@ -0,0 +1,174 @@
|
||||
.class public final enum Lenums/TestEnumsWithStaticFields;
|
||||
.super Ljava/lang/Enum;
|
||||
.source "SourceFile"
|
||||
|
||||
# interfaces
|
||||
.implements Lx/a/c;
|
||||
|
||||
|
||||
# annotations
|
||||
.annotation system Ldalvik/annotation/MemberClasses;
|
||||
value = {
|
||||
Lx/a/d$a;
|
||||
}
|
||||
.end annotation
|
||||
|
||||
.annotation system Ldalvik/annotation/Signature;
|
||||
value = {
|
||||
"Ljava/lang/Enum",
|
||||
"<",
|
||||
"Lenums/TestEnumsWithStaticFields;",
|
||||
">;",
|
||||
"Lx/a/c;"
|
||||
}
|
||||
.end annotation
|
||||
|
||||
|
||||
# static fields
|
||||
.field public static final enum sA:Lenums/TestEnumsWithStaticFields;
|
||||
|
||||
.field private static sB:Lx/a/c;
|
||||
|
||||
.field private static final synthetic sC:[Lenums/TestEnumsWithStaticFields;
|
||||
|
||||
|
||||
# direct methods
|
||||
.method static constructor <clinit>()V
|
||||
.registers 4
|
||||
|
||||
.prologue
|
||||
const v3, 0x23900
|
||||
|
||||
const/4 v2, 0x0
|
||||
|
||||
invoke-static {v3}, Lx/q;->i(I)V
|
||||
|
||||
.line 10
|
||||
new-instance v0, Lenums/TestEnumsWithStaticFields;
|
||||
|
||||
const-string/jumbo v1, "INSTANCE"
|
||||
|
||||
invoke-direct {v0, v1}, Lenums/TestEnumsWithStaticFields;-><init>(Ljava/lang/String;)V
|
||||
|
||||
sput-object v0, Lenums/TestEnumsWithStaticFields;->sA:Lenums/TestEnumsWithStaticFields;
|
||||
|
||||
.line 9
|
||||
const/4 v0, 0x1
|
||||
|
||||
new-array v0, v0, [Lenums/TestEnumsWithStaticFields;
|
||||
|
||||
sget-object v1, Lenums/TestEnumsWithStaticFields;->sA:Lenums/TestEnumsWithStaticFields;
|
||||
|
||||
aput-object v1, v0, v2
|
||||
|
||||
sput-object v0, Lenums/TestEnumsWithStaticFields;->sC:[Lenums/TestEnumsWithStaticFields;
|
||||
|
||||
.line 36
|
||||
new-instance v0, Lx/a/d$a;
|
||||
|
||||
invoke-direct {v0, v2}, Lx/a/d$a;-><init>(B)V
|
||||
|
||||
sput-object v0, Lenums/TestEnumsWithStaticFields;->sB:Lx/a/c;
|
||||
|
||||
invoke-static {v3}, Lx/q;->o(I)V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method private constructor <init>(Ljava/lang/String;)V
|
||||
.registers 3
|
||||
.annotation system Ldalvik/annotation/Signature;
|
||||
value = {
|
||||
"()V"
|
||||
}
|
||||
.end annotation
|
||||
|
||||
.prologue
|
||||
.line 9
|
||||
const/4 v0, 0x0
|
||||
|
||||
invoke-direct {p0, p1, v0}, Ljava/lang/Enum;-><init>(Ljava/lang/String;I)V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method public static a(Lx/a/c;)V
|
||||
.registers 1
|
||||
|
||||
.prologue
|
||||
.line 79
|
||||
if-eqz p0, :cond_4
|
||||
|
||||
.line 80
|
||||
sput-object p0, Lenums/TestEnumsWithStaticFields;->sB:Lx/a/c;
|
||||
|
||||
.line 82
|
||||
:cond_4
|
||||
return-void
|
||||
.end method
|
||||
|
||||
.method public static valueOf(Ljava/lang/String;)Lenums/TestEnumsWithStaticFields;
|
||||
.registers 3
|
||||
|
||||
.prologue
|
||||
const v1, 0x238f8
|
||||
|
||||
invoke-static {v1}, Lx/q;->i(I)V
|
||||
|
||||
.line 9
|
||||
const-class v0, Lenums/TestEnumsWithStaticFields;
|
||||
|
||||
invoke-static {v0, p0}, Ljava/lang/Enum;->valueOf(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
|
||||
|
||||
move-result-object v0
|
||||
|
||||
check-cast v0, Lenums/TestEnumsWithStaticFields;
|
||||
|
||||
invoke-static {v1}, Lx/q;->o(I)V
|
||||
|
||||
return-object v0
|
||||
.end method
|
||||
|
||||
.method public static values()[Lenums/TestEnumsWithStaticFields;
|
||||
.registers 2
|
||||
|
||||
.prologue
|
||||
const v1, 0x238f7
|
||||
|
||||
invoke-static {v1}, Lx/q;->i(I)V
|
||||
|
||||
.line 9
|
||||
sget-object v0, Lenums/TestEnumsWithStaticFields;->sC:[Lenums/TestEnumsWithStaticFields;
|
||||
|
||||
invoke-virtual {v0}, [Lenums/TestEnumsWithStaticFields;->clone()Ljava/lang/Object;
|
||||
|
||||
move-result-object v0
|
||||
|
||||
check-cast v0, [Lenums/TestEnumsWithStaticFields;
|
||||
|
||||
invoke-static {v1}, Lx/q;->o(I)V
|
||||
|
||||
return-object v0
|
||||
.end method
|
||||
|
||||
|
||||
# virtual methods
|
||||
.method public final FR(I)V
|
||||
.registers 4
|
||||
|
||||
.prologue
|
||||
const v1, 0x238fb
|
||||
|
||||
invoke-static {v1}, Lx/q;->i(I)V
|
||||
|
||||
.line 96
|
||||
sget-object v0, Lenums/TestEnumsWithStaticFields;->sB:Lx/a/c;
|
||||
|
||||
invoke-interface {v0, p1}, Lx/a/c;->FR(I)V
|
||||
|
||||
.line 97
|
||||
invoke-static {v1}, Lx/q;->o(I)V
|
||||
|
||||
return-void
|
||||
.end method
|
||||
|
||||
Reference in New Issue
Block a user