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;
}
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;
}
Aggregations