提交 62ca30bb 编写于 作者: S Skylot

fix: additional patterns to restore enum classes (#830)

上级 5e7388f6
......@@ -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;
}
......
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,122 +64,237 @@ 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;
break;
}
MethodNode classInitMth = cls.getClassInitMth();
if (classInitMth == null) {
cls.addAttr(AType.COMMENTS, "JADX INFO: Enum class init method not found");
return false;
}
if (staticMethod == null) {
ErrorsCounter.classWarn(cls, "Enum class init method not found");
if (classInitMth.getBasicBlocks().isEmpty()) {
return false;
}
BlockNode staticBlock = classInitMth.getBasicBlocks().get(0);
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));
// 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);
// 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<>();
// remove synthetic methods
for (MethodNode mth : cls.getMethods()) {
MethodInfo mi = mth.getMethodInfo();
if (mi.isClassInit()) {
// search "$VALUES" array init and collect enum fields
List<EnumField> enumFields = null;
for (InsnNode insn : staticBlock.getInstructions()) {
if (insn.getType() != InsnType.SPUT) {
continue;
}
String shortId = mi.getShortId();
boolean isSynthetic = mth.getAccessFlags().isSynthetic();
if (mi.isConstructor() && !isSynthetic) {
if (shortId.equals(enumConstructor)) {
mth.add(AFlag.DONT_GENERATE);
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();
}
}
}
} else if (isSynthetic
|| shortId.equals(valuesMethod)
|| shortId.equals(valuesOfMethod)) {
mth.add(AFlag.DONT_GENERATE);
toRemove.add(insn);
break;
}
}
if (enumFields == null) {
return false;
}
// all checks complete, perform transform
EnumClassAttr attr = new EnumClassAttr(enumFields.size());
attr.setStaticMethod(classInitMth);
attr.getFields().addAll(enumFields);
cls.addAttr(attr);
attr.setStaticMethod(staticMethod);
ClassInfo classInfo = cls.getClassInfo();
for (EnumField field : attr.getFields()) {
ConstructorInsn co = field.getConstrInsn();
FieldNode fieldNode = field.getField();
// 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;
// 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);
}
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();
if (!co.getClassType().equals(cls.getClassInfo())) {
// enum contains additional methods
for (ClassNode innerCls : cls.getInnerClasses()) {
processEnumInnerCls(co, field, innerCls);
}
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;
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 (!clsInfo.equals(classInfo) && !constrCls.getAccessFlags().isEnum()) {
continue;
if (field == null) {
return null;
}
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);
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;
}
EnumField field = new EnumField(fieldInfo, co, 2);
attr.getFields().add(field);
// 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));
if (!co.getClassType().equals(classInfo)) {
// enum contains additional methods
for (ClassNode innerCls : cls.getInnerClasses()) {
processEnumInnerCls(co, field, innerCls);
// remove synthetic methods
for (MethodNode mth : cls.getMethods()) {
MethodInfo mi = mth.getMethodInfo();
if (mi.isClassInit()) {
continue;
}
String shortId = mi.getShortId();
boolean isSynthetic = mth.getAccessFlags().isSynthetic();
if (mi.isConstructor() && !isSynthetic) {
if (shortId.equals(enumConstructor)
|| shortId.equals(enumConstructorAlt)) {
mth.add(AFlag.DONT_GENERATE);
}
} else if (isSynthetic
|| shortId.equals(valuesMethod)
|| shortId.equals(valuesOfMethod)) {
mth.add(AFlag.DONT_GENERATE);
}
}
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() {
......
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;
}
......
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) {");
}
}
.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
.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
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册