Search in sources :

Example 1 with BlockInsnPair

use of jadx.core.utils.BlockInsnPair in project jadx by skylot.

the class EnumVisitor method convertToEnum.

private boolean convertToEnum(ClassNode cls) {
    if (!cls.isEnum()) {
        return false;
    }
    MethodNode classInitMth = cls.getClassInitMth();
    if (classInitMth == null) {
        cls.addWarnComment("Enum class init method not found");
        return false;
    }
    if (classInitMth.getBasicBlocks().isEmpty()) {
        return false;
    }
    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.addWarnComment("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
    BlockInsnPair valuesInitPair = getValuesInitInsn(classInitMth, valuesField);
    if (valuesInitPair == null) {
        return false;
    }
    BlockNode staticBlock = valuesInitPair.getBlock();
    InsnNode valuesInitInsn = valuesInitPair.getInsn();
    List<EnumField> enumFields = null;
    InsnArg arrArg = valuesInitInsn.getArg(0);
    if (arrArg.isInsnWrap()) {
        InsnNode wrappedInsn = ((InsnWrapArg) arrArg).getWrapInsn();
        enumFields = extractEnumFieldsFromInsn(cls, staticBlock, wrappedInsn, toRemove);
    }
    if (enumFields == null) {
        return false;
    }
    toRemove.add(valuesInitInsn);
    // all checks complete, perform transform
    EnumClassAttr attr = new EnumClassAttr(enumFields);
    attr.setStaticMethod(classInitMth);
    cls.addAttr(attr);
    for (EnumField enumField : attr.getFields()) {
        ConstructorInsn co = enumField.getConstrInsn();
        FieldNode fieldNode = enumField.getField();
        // use string arg from the constructor as enum field name
        String name = getConstString(cls.root(), co.getArg(0));
        if (name != null && !fieldNode.getAlias().equals(name) && NameMapper.isValidAndPrintable(name) && cls.root().getArgs().isRenameValid()) {
            fieldNode.getFieldInfo().setAlias(name);
        }
        fieldNode.add(AFlag.DONT_GENERATE);
        processConstructorInsn(cls, enumField, classInitMth, staticBlock, toRemove);
    }
    valuesField.add(AFlag.DONT_GENERATE);
    InsnRemover.removeAllAndUnbind(classInitMth, staticBlock, toRemove);
    if (classInitMth.countInsns() == 0) {
        classInitMth.add(AFlag.DONT_GENERATE);
    } else if (!toRemove.isEmpty()) {
        CodeShrinkVisitor.shrinkMethod(classInitMth);
    }
    removeEnumMethods(cls, clsType, valuesField);
    return true;
}
Also used : ArgType(jadx.core.dex.instructions.args.ArgType) ArgType(jadx.core.dex.instructions.args.ArgType) Arrays(java.util.Arrays) MethodNode(jadx.core.dex.nodes.MethodNode) AType(jadx.core.dex.attributes.AType) EnumClassAttr(jadx.core.dex.attributes.nodes.EnumClassAttr) AFlag(jadx.core.dex.attributes.AFlag) IndexInsnNode(jadx.core.dex.instructions.IndexInsnNode) InsnUtils.checkInsnType(jadx.core.utils.InsnUtils.checkInsnType) InsnType(jadx.core.dex.instructions.InsnType) RootNode(jadx.core.dex.nodes.RootNode) JadxException(jadx.core.utils.exceptions.JadxException) ClassInfo(jadx.core.dex.info.ClassInfo) FieldInfo(jadx.core.dex.info.FieldInfo) BlockUtils(jadx.core.utils.BlockUtils) AccessInfo(jadx.core.dex.info.AccessInfo) ArrayList(java.util.ArrayList) InsnUtils(jadx.core.utils.InsnUtils) TypeGen(jadx.core.codegen.TypeGen) NameMapper(jadx.core.deobf.NameMapper) ClassNode(jadx.core.dex.nodes.ClassNode) InsnUtils.getWrappedInsn(jadx.core.utils.InsnUtils.getWrappedInsn) ConstructorInsn(jadx.core.dex.instructions.mods.ConstructorInsn) BlockInsnPair(jadx.core.utils.BlockInsnPair) InsnNode(jadx.core.dex.nodes.InsnNode) SSAVar(jadx.core.dex.instructions.args.SSAVar) FieldNode(jadx.core.dex.nodes.FieldNode) CodeShrinkVisitor(jadx.core.dex.visitors.shrink.CodeShrinkVisitor) EnumField(jadx.core.dex.attributes.nodes.EnumClassAttr.EnumField) InsnArg(jadx.core.dex.instructions.args.InsnArg) InsnWrapArg(jadx.core.dex.instructions.args.InsnWrapArg) RegisterArg(jadx.core.dex.instructions.args.RegisterArg) Predicate(java.util.function.Predicate) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) MethodInfo(jadx.core.dex.info.MethodInfo) Nullable(org.jetbrains.annotations.Nullable) SkipMethodArgsAttr(jadx.core.dex.attributes.nodes.SkipMethodArgsAttr) List(java.util.List) BlockNode(jadx.core.dex.nodes.BlockNode) InvokeNode(jadx.core.dex.instructions.InvokeNode) InsnUtils.getSingleArg(jadx.core.utils.InsnUtils.getSingleArg) Optional(java.util.Optional) AccessFlags(jadx.api.plugins.input.data.AccessFlags) InsnRemover(jadx.core.utils.InsnRemover) Collections(java.util.Collections) Utils(jadx.core.utils.Utils) BlockNode(jadx.core.dex.nodes.BlockNode) 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) InsnArg(jadx.core.dex.instructions.args.InsnArg) InsnWrapArg(jadx.core.dex.instructions.args.InsnWrapArg) ConstructorInsn(jadx.core.dex.instructions.mods.ConstructorInsn) BlockInsnPair(jadx.core.utils.BlockInsnPair)

Example 2 with BlockInsnPair

use of jadx.core.utils.BlockInsnPair in project jadx by skylot.

the class EnumVisitor method getValuesInitInsn.

private BlockInsnPair getValuesInitInsn(MethodNode classInitMth, FieldNode valuesField) {
    FieldInfo searchField = valuesField.getFieldInfo();
    for (BlockNode blockNode : classInitMth.getBasicBlocks()) {
        for (InsnNode insn : blockNode.getInstructions()) {
            if (insn.getType() == InsnType.SPUT) {
                IndexInsnNode indexInsnNode = (IndexInsnNode) insn;
                FieldInfo f = (FieldInfo) indexInsnNode.getIndex();
                if (f.equals(searchField)) {
                    return new BlockInsnPair(blockNode, indexInsnNode);
                }
            }
        }
    }
    return null;
}
Also used : BlockNode(jadx.core.dex.nodes.BlockNode) IndexInsnNode(jadx.core.dex.instructions.IndexInsnNode) InsnNode(jadx.core.dex.nodes.InsnNode) IndexInsnNode(jadx.core.dex.instructions.IndexInsnNode) FieldInfo(jadx.core.dex.info.FieldInfo) BlockInsnPair(jadx.core.utils.BlockInsnPair)

Aggregations

FieldInfo (jadx.core.dex.info.FieldInfo)2 IndexInsnNode (jadx.core.dex.instructions.IndexInsnNode)2 BlockNode (jadx.core.dex.nodes.BlockNode)2 InsnNode (jadx.core.dex.nodes.InsnNode)2 BlockInsnPair (jadx.core.utils.BlockInsnPair)2 AccessFlags (jadx.api.plugins.input.data.AccessFlags)1 TypeGen (jadx.core.codegen.TypeGen)1 NameMapper (jadx.core.deobf.NameMapper)1 AFlag (jadx.core.dex.attributes.AFlag)1 AType (jadx.core.dex.attributes.AType)1 EnumClassAttr (jadx.core.dex.attributes.nodes.EnumClassAttr)1 EnumField (jadx.core.dex.attributes.nodes.EnumClassAttr.EnumField)1 SkipMethodArgsAttr (jadx.core.dex.attributes.nodes.SkipMethodArgsAttr)1 AccessInfo (jadx.core.dex.info.AccessInfo)1 ClassInfo (jadx.core.dex.info.ClassInfo)1 MethodInfo (jadx.core.dex.info.MethodInfo)1 InsnType (jadx.core.dex.instructions.InsnType)1 InvokeNode (jadx.core.dex.instructions.InvokeNode)1 ArgType (jadx.core.dex.instructions.args.ArgType)1 InsnArg (jadx.core.dex.instructions.args.InsnArg)1