Search in sources :

Example 1 with EnumClassAttr

use of jadx.core.dex.attributes.nodes.EnumClassAttr 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();
        }
    }
}
Also used : EnumField(jadx.core.dex.attributes.nodes.EnumClassAttr.EnumField) MethodNode(jadx.core.dex.nodes.MethodNode) ConstructorInsn(jadx.core.dex.instructions.mods.ConstructorInsn) EnumClassAttr(jadx.core.dex.attributes.nodes.EnumClassAttr)

Example 2 with EnumClassAttr

use of jadx.core.dex.attributes.nodes.EnumClassAttr 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;
}
Also used : ArgType(jadx.core.dex.instructions.args.ArgType) BlockNode(jadx.core.dex.nodes.BlockNode) ClassNode(jadx.core.dex.nodes.ClassNode) EnumField(jadx.core.dex.attributes.nodes.EnumClassAttr.EnumField) FieldNode(jadx.core.dex.nodes.FieldNode) ArrayList(java.util.ArrayList) EnumClassAttr(jadx.core.dex.attributes.nodes.EnumClassAttr) IndexInsnNode(jadx.core.dex.instructions.IndexInsnNode) InsnNode(jadx.core.dex.nodes.InsnNode) MethodNode(jadx.core.dex.nodes.MethodNode) MethodInfo(jadx.core.dex.info.MethodInfo) ConstructorInsn(jadx.core.dex.instructions.mods.ConstructorInsn) FieldInfo(jadx.core.dex.info.FieldInfo) ClassInfo(jadx.core.dex.info.ClassInfo)

Aggregations

EnumClassAttr (jadx.core.dex.attributes.nodes.EnumClassAttr)2 EnumField (jadx.core.dex.attributes.nodes.EnumClassAttr.EnumField)2 ConstructorInsn (jadx.core.dex.instructions.mods.ConstructorInsn)2 MethodNode (jadx.core.dex.nodes.MethodNode)2 ClassInfo (jadx.core.dex.info.ClassInfo)1 FieldInfo (jadx.core.dex.info.FieldInfo)1 MethodInfo (jadx.core.dex.info.MethodInfo)1 IndexInsnNode (jadx.core.dex.instructions.IndexInsnNode)1 ArgType (jadx.core.dex.instructions.args.ArgType)1 BlockNode (jadx.core.dex.nodes.BlockNode)1 ClassNode (jadx.core.dex.nodes.ClassNode)1 FieldNode (jadx.core.dex.nodes.FieldNode)1 InsnNode (jadx.core.dex.nodes.InsnNode)1 ArrayList (java.util.ArrayList)1