fix: check enum constructor content before removing (#922)
This commit is contained in:
@@ -9,6 +9,8 @@ import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.android.dx.rop.code.AccessFlags;
|
||||
import com.google.common.collect.Streams;
|
||||
|
||||
@@ -21,6 +23,7 @@ import jadx.core.dex.attributes.nodes.EnumClassAttr;
|
||||
import jadx.core.dex.attributes.nodes.EnumClassAttr.EnumField;
|
||||
import jadx.core.dex.attributes.nodes.JadxError;
|
||||
import jadx.core.dex.attributes.nodes.LineAttrNode;
|
||||
import jadx.core.dex.attributes.nodes.SkipMethodArgsAttr;
|
||||
import jadx.core.dex.info.AccessInfo;
|
||||
import jadx.core.dex.info.ClassInfo;
|
||||
import jadx.core.dex.instructions.args.ArgType;
|
||||
@@ -420,12 +423,13 @@ public class ClassGen {
|
||||
EnumField f = it.next();
|
||||
code.startLine(f.getField().getAlias());
|
||||
ConstructorInsn constrInsn = f.getConstrInsn();
|
||||
if (constrInsn.getArgsCount() > f.getStartArg()) {
|
||||
MethodNode callMth = cls.dex().resolveMethod(constrInsn.getCallMth());
|
||||
int skipCount = getEnumCtrSkipArgsCount(callMth);
|
||||
if (constrInsn.getArgsCount() > skipCount) {
|
||||
if (igen == null) {
|
||||
igen = makeInsnGen(enumFields.getStaticMethod());
|
||||
}
|
||||
MethodNode callMth = cls.dex().resolveMethod(constrInsn.getCallMth());
|
||||
igen.generateMethodArguments(code, constrInsn, f.getStartArg(), callMth);
|
||||
igen.generateMethodArguments(code, constrInsn, 0, callMth);
|
||||
}
|
||||
if (f.getCls() != null) {
|
||||
code.add(' ');
|
||||
@@ -446,6 +450,16 @@ public class ClassGen {
|
||||
}
|
||||
}
|
||||
|
||||
private int getEnumCtrSkipArgsCount(@Nullable MethodNode callMth) {
|
||||
if (callMth != null) {
|
||||
SkipMethodArgsAttr skipArgsAttr = callMth.get(AType.SKIP_MTH_ARGS);
|
||||
if (skipArgsAttr != null) {
|
||||
return skipArgsAttr.getSkipCount();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private InsnGen makeInsnGen(MethodNode mth) {
|
||||
MethodGen mthGen = new MethodGen(this, mth);
|
||||
return new InsnGen(mthGen, false);
|
||||
|
||||
@@ -14,13 +14,11 @@ public class EnumClassAttr implements IAttribute {
|
||||
public static class EnumField {
|
||||
private final FieldNode field;
|
||||
private final ConstructorInsn constrInsn;
|
||||
private final int startArg;
|
||||
private ClassNode cls;
|
||||
|
||||
public EnumField(FieldNode field, ConstructorInsn co, int startArg) {
|
||||
public EnumField(FieldNode field, ConstructorInsn co) {
|
||||
this.field = field;
|
||||
this.constrInsn = co;
|
||||
this.startArg = startArg;
|
||||
}
|
||||
|
||||
public FieldNode getField() {
|
||||
@@ -31,10 +29,6 @@ public class EnumClassAttr implements IAttribute {
|
||||
return constrInsn;
|
||||
}
|
||||
|
||||
public int getStartArg() {
|
||||
return startArg;
|
||||
}
|
||||
|
||||
public ClassNode getCls() {
|
||||
return cls;
|
||||
}
|
||||
|
||||
@@ -55,6 +55,10 @@ public class SkipMethodArgsAttr implements IAttribute {
|
||||
return skipArgs.get(argNum);
|
||||
}
|
||||
|
||||
public int getSkipCount() {
|
||||
return skipArgs.cardinality();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AType<SkipMethodArgsAttr> getType() {
|
||||
return AType.SKIP_MTH_ARGS;
|
||||
|
||||
@@ -19,6 +19,7 @@ import jadx.core.dex.attributes.AFlag;
|
||||
import jadx.core.dex.attributes.AType;
|
||||
import jadx.core.dex.attributes.nodes.EnumClassAttr;
|
||||
import jadx.core.dex.attributes.nodes.EnumClassAttr.EnumField;
|
||||
import jadx.core.dex.attributes.nodes.SkipMethodArgsAttr;
|
||||
import jadx.core.dex.info.AccessInfo;
|
||||
import jadx.core.dex.info.ClassInfo;
|
||||
import jadx.core.dex.info.FieldInfo;
|
||||
@@ -287,8 +288,13 @@ public class EnumVisitor extends AbstractVisitor {
|
||||
if (!clsInfo.equals(cls.getClassInfo()) && !constrCls.getAccessFlags().isEnum()) {
|
||||
return null;
|
||||
}
|
||||
int startArg = co.getArgsCount() == 1 ? 1 : 2;
|
||||
return new EnumField(enumFieldNode, co, startArg);
|
||||
MethodInfo callMth = co.getCallMth();
|
||||
MethodNode mth = cls.dex().resolveMethod(callMth);
|
||||
if (mth == null) {
|
||||
return null;
|
||||
}
|
||||
markArgsForSkip(mth);
|
||||
return new EnumField(enumFieldNode, co);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -306,10 +312,7 @@ public class EnumVisitor extends AbstractVisitor {
|
||||
}
|
||||
|
||||
private void removeEnumMethods(ClassNode cls, ArgType clsType, FieldNode valuesField) {
|
||||
String enumConstructor = "<init>(Ljava/lang/String;I)V";
|
||||
String enumConstructorAlt = "<init>(Ljava/lang/String;)V";
|
||||
String valuesMethod = "values()" + TypeGen.signature(ArgType.array(clsType));
|
||||
|
||||
FieldInfo valuesFieldInfo = valuesField.getFieldInfo();
|
||||
|
||||
// remove compiler generated methods
|
||||
@@ -319,12 +322,11 @@ public class EnumVisitor extends AbstractVisitor {
|
||||
continue;
|
||||
}
|
||||
String shortId = mi.getShortId();
|
||||
boolean isSynthetic = mth.getAccessFlags().isSynthetic();
|
||||
if (mi.isConstructor() && !isSynthetic) {
|
||||
if (shortId.equals(enumConstructor)
|
||||
|| shortId.equals(enumConstructorAlt)) {
|
||||
if (mi.isConstructor()) {
|
||||
if (isDefaultConstructor(mth, shortId)) {
|
||||
mth.add(AFlag.DONT_GENERATE);
|
||||
}
|
||||
markArgsForSkip(mth);
|
||||
} else if (shortId.equals(valuesMethod)
|
||||
|| usesValuesField(mth, valuesFieldInfo)
|
||||
|| simpleValueOfMth(mth, clsType)) {
|
||||
@@ -333,6 +335,24 @@ public class EnumVisitor extends AbstractVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
private void markArgsForSkip(MethodNode mth) {
|
||||
// skip first and second args
|
||||
SkipMethodArgsAttr.skipArg(mth, 0);
|
||||
if (mth.getMethodInfo().getArgsCount() > 1) {
|
||||
SkipMethodArgsAttr.skipArg(mth, 1);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isDefaultConstructor(MethodNode mth, String shortId) {
|
||||
boolean defaultId = shortId.equals("<init>(Ljava/lang/String;I)V")
|
||||
|| shortId.equals("<init>(Ljava/lang/String;)V");
|
||||
if (defaultId) {
|
||||
// check content
|
||||
return mth.countInsns() == 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean simpleValueOfMth(MethodNode mth, ArgType clsType) {
|
||||
InsnNode returnInsn = InsnUtils.searchSingleReturnInsn(mth, insn -> insn.getArgsCount() == 1);
|
||||
if (returnInsn == null) {
|
||||
|
||||
Reference in New Issue
Block a user