未验证 提交 5852da1e 编写于 作者: S Skylot

feat: support MethodParameters attribute (#1260)

上级 502fd069
......@@ -13,8 +13,8 @@ import jadx.api.plugins.input.data.annotations.EncodedValue;
import jadx.api.plugins.input.data.annotations.IAnnotation;
import jadx.api.plugins.input.data.attributes.JadxAttrType;
import jadx.api.plugins.input.data.attributes.types.AnnotationDefaultAttr;
import jadx.api.plugins.input.data.attributes.types.AnnotationMethodParamsAttr;
import jadx.api.plugins.input.data.attributes.types.AnnotationsAttr;
import jadx.api.plugins.input.data.attributes.types.MethodParamsAttr;
import jadx.core.Consts;
import jadx.core.dex.attributes.IAttributeNode;
import jadx.core.dex.info.FieldInfo;
......@@ -48,7 +48,7 @@ public class AnnotationGen {
add(field, code);
}
public void addForParameter(ICodeWriter code, MethodParamsAttr paramsAnnotations, int n) {
public void addForParameter(ICodeWriter code, AnnotationMethodParamsAttr paramsAnnotations, int n) {
List<AnnotationsAttr> paramList = paramsAnnotations.getParamList();
if (n >= paramList.size()) {
return;
......
......@@ -16,7 +16,7 @@ import jadx.api.data.annotations.VarDeclareRef;
import jadx.api.plugins.input.data.AccessFlags;
import jadx.api.plugins.input.data.annotations.EncodedValue;
import jadx.api.plugins.input.data.attributes.JadxAttrType;
import jadx.api.plugins.input.data.attributes.types.MethodParamsAttr;
import jadx.api.plugins.input.data.attributes.types.AnnotationMethodParamsAttr;
import jadx.core.Consts;
import jadx.core.Jadx;
import jadx.core.dex.attributes.AFlag;
......@@ -195,7 +195,7 @@ public class MethodGen {
}
private void addMethodArguments(ICodeWriter code, List<RegisterArg> args) {
MethodParamsAttr paramsAnnotation = mth.get(JadxAttrType.ANNOTATION_MTH_PARAMETERS);
AnnotationMethodParamsAttr paramsAnnotation = mth.get(JadxAttrType.ANNOTATION_MTH_PARAMETERS);
int i = 0;
Iterator<RegisterArg> it = args.iterator();
while (it.hasNext()) {
......
......@@ -9,7 +9,10 @@ import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jadx.api.plugins.input.data.AccessFlags;
import jadx.api.plugins.input.data.ILocalVar;
import jadx.api.plugins.input.data.attributes.JadxAttrType;
import jadx.api.plugins.input.data.attributes.types.MethodParametersAttr;
import jadx.core.Consts;
import jadx.core.deobf.NameMapper;
import jadx.core.dex.attributes.AFlag;
......@@ -18,6 +21,7 @@ import jadx.core.dex.attributes.nodes.LocalVarsDebugInfoAttr;
import jadx.core.dex.attributes.nodes.RegDebugInfoAttr;
import jadx.core.dex.instructions.PhiInsn;
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.instructions.args.CodeVar;
import jadx.core.dex.instructions.args.InsnArg;
import jadx.core.dex.instructions.args.Named;
import jadx.core.dex.instructions.args.RegisterArg;
......@@ -51,6 +55,7 @@ public class DebugInfoApplyVisitor extends AbstractVisitor {
applyDebugInfo(mth);
mth.remove(AType.LOCAL_VARS_DEBUG_INFO);
}
processMethodParametersAttribute(mth);
checkTypes(mth);
} catch (Exception e) {
mth.addWarnComment("Failed to apply debug info", e);
......@@ -221,4 +226,31 @@ public class DebugInfoApplyVisitor extends AbstractVisitor {
}
});
}
private void processMethodParametersAttribute(MethodNode mth) {
MethodParametersAttr parametersAttr = mth.get(JadxAttrType.METHOD_PARAMETERS);
if (parametersAttr == null) {
return;
}
try {
List<MethodParametersAttr.Info> params = parametersAttr.getList();
if (params.size() != mth.getMethodInfo().getArgsCount()) {
return;
}
int i = 0;
for (RegisterArg mthArg : mth.getArgRegs()) {
MethodParametersAttr.Info paramInfo = params.get(i++);
String name = paramInfo.getName();
if (NameMapper.isValidAndPrintable(name)) {
CodeVar codeVar = mthArg.getSVar().getCodeVar();
codeVar.setName(name);
if (AccessFlags.hasFlag(paramInfo.getAccFlags(), AccessFlags.FINAL)) {
codeVar.setFinal(true);
}
}
}
} catch (Exception e) {
mth.addWarnComment("Failed to process method parameters attribute: " + parametersAttr.getList(), e);
}
}
}
package jadx.tests.integration.others;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.stream.Collectors;
import jadx.tests.api.IntegrationTest;
import jadx.tests.api.extensions.profiles.TestProfile;
import jadx.tests.api.extensions.profiles.TestWithProfiles;
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
public class TestMethodParametersAttribute extends IntegrationTest {
public static class TestCls {
public String test(String paramStr, final int number) {
return paramStr + number;
}
public String paramNames() throws NoSuchMethodException {
Method testMethod = TestCls.class.getMethod("test", String.class, int.class);
return Arrays.stream(testMethod.getParameters())
.map(Parameter::getName)
.collect(Collectors.joining(", "));
}
public void check() throws NoSuchMethodException {
assertThat(paramNames()).isEqualTo("paramStr, number");
}
}
@TestWithProfiles({ TestProfile.JAVA8, TestProfile.D8_J11 })
public void test() {
getCompilerOptions().addArgument("-parameters");
noDebugInfo();
assertThat(getClassNode(TestCls.class))
.code()
.containsOne("public String test(String paramStr, final int number) {");
}
}
package jadx.plugins.input.dex.sections;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -17,6 +19,7 @@ import jadx.api.plugins.input.data.attributes.types.AnnotationsAttr;
import jadx.api.plugins.input.data.attributes.types.ExceptionsAttr;
import jadx.api.plugins.input.data.attributes.types.InnerClassesAttr;
import jadx.api.plugins.input.data.attributes.types.InnerClsInfo;
import jadx.api.plugins.input.data.attributes.types.MethodParametersAttr;
import jadx.api.plugins.input.data.attributes.types.SignatureAttr;
import jadx.api.plugins.utils.Utils;
import jadx.plugins.input.dex.sections.annotations.AnnotationsUtils;
......@@ -36,7 +39,7 @@ public class DexAnnotationsConvert {
appendAnnotations(null, list, annotationList);
}
private static void appendAnnotations(String cls, List<IJadxAttribute> attributes, List<IAnnotation> annotations) {
private static void appendAnnotations(@Nullable String cls, List<IJadxAttribute> attributes, List<IAnnotation> annotations) {
if (annotations.isEmpty()) {
return;
}
......@@ -49,7 +52,7 @@ public class DexAnnotationsConvert {
}
@SuppressWarnings("unchecked")
private static void convertSystemAnnotations(String cls, List<IJadxAttribute> attributes, IAnnotation annotation) {
private static void convertSystemAnnotations(@Nullable String cls, List<IJadxAttribute> attributes, IAnnotation annotation) {
switch (annotation.getAnnotationClass()) {
case "Ldalvik/annotation/Signature;":
attributes.add(new SignatureAttr(extractSignature(annotation)));
......@@ -90,6 +93,25 @@ public class DexAnnotationsConvert {
LOG.warn("Failed to convert dalvik throws annotation", e);
}
break;
case "Ldalvik/annotation/MethodParameters;":
try {
List<EncodedValue> names = AnnotationsUtils.getArray(annotation, "names");
List<EncodedValue> accFlags = AnnotationsUtils.getArray(annotation, "accessFlags");
if (!names.isEmpty() && names.size() == accFlags.size()) {
int size = names.size();
List<MethodParametersAttr.Info> list = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
String name = (String) names.get(i).getValue();
int accFlag = (int) accFlags.get(i).getValue();
list.add(new MethodParametersAttr.Info(accFlag, name));
}
attributes.add(new MethodParametersAttr(list));
}
} catch (Exception e) {
LOG.warn("Failed to parse annotation: " + annotation, e);
}
break;
}
}
......
......@@ -9,7 +9,7 @@ import jadx.api.plugins.input.data.ICodeReader;
import jadx.api.plugins.input.data.IMethodData;
import jadx.api.plugins.input.data.annotations.IAnnotation;
import jadx.api.plugins.input.data.attributes.IJadxAttribute;
import jadx.api.plugins.input.data.attributes.types.MethodParamsAttr;
import jadx.api.plugins.input.data.attributes.types.AnnotationMethodParamsAttr;
import jadx.api.plugins.utils.Utils;
import jadx.plugins.input.dex.sections.annotations.AnnotationsParser;
import jadx.plugins.input.dex.smali.SmaliPrinter;
......@@ -84,7 +84,7 @@ public class DexMethodData implements IMethodData {
public List<IJadxAttribute> getAttributes() {
List<IJadxAttribute> list = new ArrayList<>();
DexAnnotationsConvert.forMethod(list, getAnnotations());
Utils.addToList(list, MethodParamsAttr.pack(getParamsAnnotations()));
Utils.addToList(list, AnnotationMethodParamsAttr.pack(getParamsAnnotations()));
return list;
}
......
package jadx.plugins.input.dex.sections.annotations;
import java.util.Collections;
import java.util.List;
import org.jetbrains.annotations.Nullable;
import jadx.api.plugins.input.data.annotations.EncodedType;
import jadx.api.plugins.input.data.annotations.EncodedValue;
import jadx.api.plugins.input.data.annotations.IAnnotation;
......@@ -17,4 +22,28 @@ public class AnnotationsUtils {
}
return (T) encodedValue.getValue();
}
@Nullable
public static Object getValue(IAnnotation ann, String name, EncodedType type) {
if (ann == null || ann.getValues() == null || ann.getValues().isEmpty()) {
return null;
}
EncodedValue encodedValue = ann.getValues().get(name);
if (encodedValue == null || encodedValue.getType() != type) {
return null;
}
return encodedValue.getValue();
}
@SuppressWarnings("unchecked")
public static List<EncodedValue> getArray(IAnnotation ann, String name) {
if (ann == null || ann.getValues() == null || ann.getValues().isEmpty()) {
return Collections.emptyList();
}
EncodedValue encodedValue = ann.getValues().get(name);
if (encodedValue == null || encodedValue.getType() != EncodedType.ENCODED_ARRAY) {
return Collections.emptyList();
}
return (List<EncodedValue>) encodedValue.getValue();
}
}
......@@ -71,6 +71,7 @@ public class JavaMethodData implements IMethodData {
Utils.addToList(list, JavaAnnotationDefaultAttr.convert(attributes));
Utils.addToList(list, attributes.get(JavaAttrType.SIGNATURE));
Utils.addToList(list, attributes.get(JavaAttrType.EXCEPTIONS));
Utils.addToList(list, attributes.get(JavaAttrType.METHOD_PARAMETERS));
return list;
}
......
......@@ -17,6 +17,7 @@ import jadx.plugins.input.java.data.attributes.types.JavaAnnotationsAttr;
import jadx.plugins.input.java.data.attributes.types.JavaBootstrapMethodsAttr;
import jadx.plugins.input.java.data.attributes.types.JavaExceptionsAttr;
import jadx.plugins.input.java.data.attributes.types.JavaInnerClsAttr;
import jadx.plugins.input.java.data.attributes.types.JavaMethodParametersAttr;
import jadx.plugins.input.java.data.attributes.types.JavaParamAnnsAttr;
import jadx.plugins.input.java.data.attributes.types.JavaSignatureAttr;
import jadx.plugins.input.java.data.attributes.types.JavaSourceFileAttr;
......@@ -46,6 +47,7 @@ public final class JavaAttrType<T extends IJavaAttribute> {
public static final JavaAttrType<JavaSourceFileAttr> SOURCE_FILE;
public static final JavaAttrType<JavaSignatureAttr> SIGNATURE;
public static final JavaAttrType<JavaExceptionsAttr> EXCEPTIONS;
public static final JavaAttrType<JavaMethodParametersAttr> METHOD_PARAMETERS;
public static final JavaAttrType<IgnoredAttr> DEPRECATED;
public static final JavaAttrType<IgnoredAttr> SYNTHETIC;
......@@ -76,6 +78,7 @@ public final class JavaAttrType<T extends IJavaAttribute> {
SOURCE_FILE = bind("SourceFile", JavaSourceFileAttr.reader());
SIGNATURE = bind("Signature", JavaSignatureAttr.reader());
EXCEPTIONS = bind("Exceptions", JavaExceptionsAttr.reader());
METHOD_PARAMETERS = bind("MethodParameters", JavaMethodParametersAttr.reader());
// ignored
DEPRECATED = bind("Deprecated", null); // duplicated by annotation
......
package jadx.plugins.input.java.data.attributes.types;
import java.util.ArrayList;
import java.util.List;
import jadx.api.plugins.input.data.attributes.types.MethodParametersAttr;
import jadx.plugins.input.java.data.ConstPoolReader;
import jadx.plugins.input.java.data.attributes.IJavaAttribute;
import jadx.plugins.input.java.data.attributes.IJavaAttributeReader;
public class JavaMethodParametersAttr extends MethodParametersAttr implements IJavaAttribute {
public JavaMethodParametersAttr(List<Info> list) {
super(list);
}
public static IJavaAttributeReader reader() {
return (clsData, reader) -> {
ConstPoolReader constPool = clsData.getConstPoolReader();
int count = reader.readU1();
List<Info> params = new ArrayList<>(count);
for (int i = 0; i < count; i++) {
String name = constPool.getUtf8(reader.readU2());
int accessFlags = reader.readU2();
params.add(new Info(accessFlags, name));
}
return new JavaMethodParametersAttr(params);
};
}
}
......@@ -6,7 +6,7 @@ import java.util.List;
import jadx.api.plugins.input.data.annotations.AnnotationVisibility;
import jadx.api.plugins.input.data.annotations.IAnnotation;
import jadx.api.plugins.input.data.attributes.types.MethodParamsAttr;
import jadx.api.plugins.input.data.attributes.types.AnnotationMethodParamsAttr;
import jadx.api.plugins.utils.Utils;
import jadx.plugins.input.java.data.attributes.IJavaAttribute;
import jadx.plugins.input.java.data.attributes.IJavaAttributeReader;
......@@ -35,19 +35,19 @@ public class JavaParamAnnsAttr implements IJavaAttribute {
};
}
public static MethodParamsAttr merge(JavaAttrStorage storage) {
public static AnnotationMethodParamsAttr merge(JavaAttrStorage storage) {
JavaParamAnnsAttr runtimeAnnAttr = storage.get(JavaAttrType.RUNTIME_PARAMETER_ANNOTATIONS);
JavaParamAnnsAttr buildAnnAttr = storage.get(JavaAttrType.BUILD_PARAMETER_ANNOTATIONS);
if (runtimeAnnAttr == null && buildAnnAttr == null) {
return null;
}
if (buildAnnAttr == null) {
return MethodParamsAttr.pack(runtimeAnnAttr.getList());
return AnnotationMethodParamsAttr.pack(runtimeAnnAttr.getList());
}
if (runtimeAnnAttr == null) {
return MethodParamsAttr.pack(buildAnnAttr.getList());
return AnnotationMethodParamsAttr.pack(buildAnnAttr.getList());
}
return MethodParamsAttr.pack(mergeParamLists(runtimeAnnAttr.getList(), buildAnnAttr.getList()));
return AnnotationMethodParamsAttr.pack(mergeParamLists(runtimeAnnAttr.getList(), buildAnnAttr.getList()));
}
private static List<List<IAnnotation>> mergeParamLists(List<List<IAnnotation>> first, List<List<IAnnotation>> second) {
......
......@@ -3,10 +3,11 @@ package jadx.api.plugins.input.data.attributes;
import jadx.api.plugins.input.data.annotations.EncodedValue;
import jadx.api.plugins.input.data.attributes.types.AnnotationDefaultAttr;
import jadx.api.plugins.input.data.attributes.types.AnnotationDefaultClassAttr;
import jadx.api.plugins.input.data.attributes.types.AnnotationMethodParamsAttr;
import jadx.api.plugins.input.data.attributes.types.AnnotationsAttr;
import jadx.api.plugins.input.data.attributes.types.ExceptionsAttr;
import jadx.api.plugins.input.data.attributes.types.InnerClassesAttr;
import jadx.api.plugins.input.data.attributes.types.MethodParamsAttr;
import jadx.api.plugins.input.data.attributes.types.MethodParametersAttr;
import jadx.api.plugins.input.data.attributes.types.SignatureAttr;
import jadx.api.plugins.input.data.attributes.types.SourceFileAttr;
......@@ -25,9 +26,10 @@ public final class JadxAttrType<T extends IJadxAttribute> implements IJadxAttrTy
public static final JadxAttrType<EncodedValue> CONSTANT_VALUE = bind();
// method
public static final JadxAttrType<MethodParamsAttr> ANNOTATION_MTH_PARAMETERS = bind();
public static final JadxAttrType<AnnotationMethodParamsAttr> ANNOTATION_MTH_PARAMETERS = bind();
public static final JadxAttrType<AnnotationDefaultAttr> ANNOTATION_DEFAULT = bind();
public static final JadxAttrType<ExceptionsAttr> EXCEPTIONS = bind();
public static final JadxAttrType<MethodParametersAttr> METHOD_PARAMETERS = bind();
private static <T extends IJadxAttribute> JadxAttrType<T> bind() {
return new JadxAttrType<>();
......
......@@ -9,10 +9,10 @@ import jadx.api.plugins.input.data.annotations.IAnnotation;
import jadx.api.plugins.input.data.attributes.JadxAttrType;
import jadx.api.plugins.input.data.attributes.PinnedAttribute;
public class MethodParamsAttr extends PinnedAttribute {
public class AnnotationMethodParamsAttr extends PinnedAttribute {
@Nullable
public static MethodParamsAttr pack(List<List<IAnnotation>> annotationRefList) {
public static AnnotationMethodParamsAttr pack(List<List<IAnnotation>> annotationRefList) {
if (annotationRefList.isEmpty()) {
return null;
}
......@@ -20,12 +20,12 @@ public class MethodParamsAttr extends PinnedAttribute {
for (List<IAnnotation> annList : annotationRefList) {
list.add(AnnotationsAttr.pack(annList));
}
return new MethodParamsAttr(list);
return new AnnotationMethodParamsAttr(list);
}
private final List<AnnotationsAttr> paramList;
private MethodParamsAttr(List<AnnotationsAttr> paramsList) {
private AnnotationMethodParamsAttr(List<AnnotationsAttr> paramsList) {
this.paramList = paramsList;
}
......@@ -34,7 +34,7 @@ public class MethodParamsAttr extends PinnedAttribute {
}
@Override
public JadxAttrType<MethodParamsAttr> getAttrType() {
public JadxAttrType<AnnotationMethodParamsAttr> getAttrType() {
return JadxAttrType.ANNOTATION_MTH_PARAMETERS;
}
......
package jadx.api.plugins.input.data.attributes.types;
import java.util.List;
import jadx.api.plugins.input.data.AccessFlags;
import jadx.api.plugins.input.data.AccessFlagsScope;
import jadx.api.plugins.input.data.attributes.IJadxAttrType;
import jadx.api.plugins.input.data.attributes.JadxAttrType;
import jadx.api.plugins.input.data.attributes.PinnedAttribute;
public class MethodParametersAttr extends PinnedAttribute {
public static class Info {
private final int accFlags;
private final String name;
public Info(int accFlags, String name) {
this.accFlags = accFlags;
this.name = name;
}
public int getAccFlags() {
return accFlags;
}
public String getName() {
return name;
}
public String toString() {
return AccessFlags.format(accFlags, AccessFlagsScope.METHOD) + name;
}
}
private final List<Info> list;
public MethodParametersAttr(List<Info> list) {
this.list = list;
}
public List<Info> getList() {
return list;
}
@Override
public IJadxAttrType<MethodParametersAttr> getAttrType() {
return JadxAttrType.METHOD_PARAMETERS;
}
@Override
public String toString() {
return "METHOD_PARAMETERS: " + list;
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册