use of jadx.core.dex.nodes.InsnNode in project jadx by skylot.
the class ReSugarCode method getEnumMap.
private static EnumMapAttr.KeyValueMap getEnumMap(MethodNode mth, FieldNode field) {
ClassNode syntheticClass = field.getParentClass();
EnumMapAttr mapAttr = syntheticClass.get(AType.ENUM_MAP);
if (mapAttr != null) {
return mapAttr.getMap(field);
}
mapAttr = new EnumMapAttr();
syntheticClass.addAttr(mapAttr);
MethodNode clsInitMth = syntheticClass.searchMethodByName("<clinit>()V");
if (clsInitMth == null || clsInitMth.isNoCode()) {
return null;
}
if (clsInitMth.getBasicBlocks() == null) {
try {
clsInitMth.load();
} catch (DecodeException e) {
LOG.error("Load failed", e);
return null;
}
if (clsInitMth.getBasicBlocks() == null) {
// TODO:
return null;
}
}
for (BlockNode block : clsInitMth.getBasicBlocks()) {
for (InsnNode insn : block.getInstructions()) {
if (insn.getType() == InsnType.APUT) {
addToEnumMap(mth, mapAttr, insn);
}
}
}
return mapAttr.getMap(field);
}
use of jadx.core.dex.nodes.InsnNode in project jadx by skylot.
the class ReSugarCode method processEnumSwitch.
private static InsnNode processEnumSwitch(MethodNode mth, SwitchNode insn) {
InsnArg arg = insn.getArg(0);
if (!arg.isInsnWrap()) {
return null;
}
InsnNode wrapInsn = ((InsnWrapArg) arg).getWrapInsn();
if (wrapInsn.getType() != InsnType.AGET) {
return null;
}
EnumMapInfo enumMapInfo = checkEnumMapAccess(mth, wrapInsn);
if (enumMapInfo == null) {
return null;
}
FieldNode enumMapField = enumMapInfo.getMapField();
InsnArg invArg = enumMapInfo.getArg();
EnumMapAttr.KeyValueMap valueMap = getEnumMap(mth, enumMapField);
if (valueMap == null) {
return null;
}
Object[] keys = insn.getKeys();
for (Object key : keys) {
Object newKey = valueMap.get(key);
if (newKey == null) {
return null;
}
}
// replace confirmed
if (!insn.replaceArg(arg, invArg)) {
return null;
}
for (int i = 0; i < keys.length; i++) {
keys[i] = valueMap.get(keys[i]);
}
enumMapField.add(AFlag.DONT_GENERATE);
checkAndHideClass(enumMapField.getParentClass());
return null;
}
use of jadx.core.dex.nodes.InsnNode 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;
}
use of jadx.core.dex.nodes.InsnNode in project jadx by skylot.
the class ExtractFieldInit method moveCommonFieldsInit.
private static void moveCommonFieldsInit(ClassNode cls) {
List<MethodNode> constrList = getConstructorsList(cls);
if (constrList.isEmpty()) {
return;
}
List<InitInfo> infoList = new ArrayList<InitInfo>(constrList.size());
for (MethodNode constrMth : constrList) {
if (constrMth.isNoCode() || constrMth.getBasicBlocks().isEmpty()) {
return;
}
InitInfo info = new InitInfo(constrMth);
infoList.add(info);
// TODO: check not only first block
BlockNode blockNode = constrMth.getBasicBlocks().get(0);
for (InsnNode insn : blockNode.getInstructions()) {
if (insn.getType() == InsnType.IPUT && checkInsn(insn)) {
info.getPutInsns().add(insn);
} else if (!info.getPutInsns().isEmpty()) {
break;
}
}
}
// compare collected instructions
InitInfo common = null;
for (InitInfo info : infoList) {
if (common == null) {
common = info;
} else if (!compareInsns(common.getPutInsns(), info.getPutInsns())) {
return;
}
}
if (common == null) {
return;
}
Set<FieldInfo> fields = new HashSet<FieldInfo>();
for (InsnNode insn : common.getPutInsns()) {
FieldInfo fieldInfo = (FieldInfo) ((IndexInsnNode) insn).getIndex();
FieldNode field = cls.dex().resolveField(fieldInfo);
if (field == null) {
return;
}
if (!fields.add(fieldInfo)) {
return;
}
}
// all checks passed
for (InitInfo info : infoList) {
for (InsnNode putInsn : info.getPutInsns()) {
InstructionRemover.remove(info.getConstrMth(), putInsn);
}
}
for (InsnNode insn : common.getPutInsns()) {
FieldInfo fieldInfo = (FieldInfo) ((IndexInsnNode) insn).getIndex();
FieldNode field = cls.dex().resolveField(fieldInfo);
addFieldInitAttr(common.getConstrMth(), field, insn);
}
}
use of jadx.core.dex.nodes.InsnNode in project jadx by skylot.
the class ExtractFieldInit method checkInsn.
private static boolean checkInsn(InsnNode insn) {
InsnArg arg = insn.getArg(0);
if (arg.isInsnWrap()) {
InsnNode wrapInsn = ((InsnWrapArg) arg).getWrapInsn();
if (!wrapInsn.canReorderRecursive() && insn.contains(AType.CATCH_BLOCK)) {
return false;
}
} else {
return arg.isLiteral() || arg.isThis();
}
Set<RegisterArg> regs = new HashSet<RegisterArg>();
insn.getRegisterArgs(regs);
if (!regs.isEmpty()) {
for (RegisterArg reg : regs) {
if (!reg.isThis()) {
return false;
}
}
}
return true;
}
Aggregations