use of jadx.core.dex.attributes.nodes.EnumClassAttr.EnumField in project jadx by skylot.
the class ClassGen method addEnumFields.
private void addEnumFields(CodeWriter code) throws CodegenException {
EnumClassAttr enumFields = cls.get(AType.ENUM_CLASS);
if (enumFields == null) {
return;
}
InsnGen igen = null;
for (Iterator<EnumField> it = enumFields.getFields().iterator(); it.hasNext(); ) {
EnumField f = it.next();
code.startLine(f.getField().getAlias());
ConstructorInsn constrInsn = f.getConstrInsn();
if (constrInsn.getArgsCount() > f.getStartArg()) {
if (igen == null) {
igen = makeInsnGen(enumFields.getStaticMethod());
}
MethodNode callMth = cls.dex().resolveMethod(constrInsn.getCallMth());
igen.generateMethodArguments(code, constrInsn, f.getStartArg(), callMth);
}
if (f.getCls() != null) {
code.add(' ');
new ClassGen(f.getCls(), this).addClassBody(code);
}
if (it.hasNext()) {
code.add(',');
}
}
if (isMethodsPresents() || isFieldsPresents() || isInnerClassesPresents()) {
if (enumFields.getFields().isEmpty()) {
code.startLine();
}
code.add(';');
if (isFieldsPresents()) {
code.startLine();
}
}
}
use of jadx.core.dex.attributes.nodes.EnumClassAttr.EnumField in project jadx by skylot.
the class EnumVisitor method visit.
@Override
public boolean visit(ClassNode cls) throws JadxException {
if (!cls.isEnum()) {
return true;
}
// search class init method
MethodNode staticMethod = null;
for (MethodNode mth : cls.getMethods()) {
MethodInfo mi = mth.getMethodInfo();
if (mi.isClassInit()) {
staticMethod = mth;
break;
}
}
if (staticMethod == null) {
ErrorsCounter.classError(cls, "Enum class init method not found");
return true;
}
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<FieldNode>();
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);
}
}
// 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)) {
mth.add(AFlag.DONT_GENERATE);
}
} else if (isSynthetic || shortId.equals(valuesMethod) || shortId.equals(valuesOfMethod)) {
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<InsnNode>();
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.isValidIdentifier(name)) {
// LOG.debug("Rename enum field: '{}' to '{}' in {}", fieldInfo.getName(), name, cls);
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 false;
}
Aggregations