|
8 | 8 |
|
9 | 9 | import jadx.api.plugins.input.data.ICallSite;
|
10 | 10 | import jadx.api.plugins.input.data.ICodeReader;
|
| 11 | +import jadx.api.plugins.input.data.IFieldRef; |
11 | 12 | import jadx.api.plugins.input.data.IMethodHandle;
|
12 | 13 | import jadx.api.plugins.input.data.IMethodRef;
|
| 14 | +import jadx.api.plugins.input.data.annotations.EncodedValue; |
| 15 | +import jadx.api.plugins.input.data.annotations.IAnnotation; |
| 16 | +import jadx.api.plugins.input.data.attributes.JadxAttrType; |
| 17 | +import jadx.api.plugins.input.data.attributes.types.AnnotationMethodParamsAttr; |
| 18 | +import jadx.api.plugins.input.data.attributes.types.AnnotationsAttr; |
13 | 19 | import jadx.api.plugins.input.insns.InsnData;
|
14 | 20 | import jadx.api.plugins.input.insns.Opcode;
|
15 | 21 | import jadx.api.plugins.input.insns.custom.ICustomPayload;
|
|
20 | 26 | import jadx.core.dex.instructions.args.ArgType;
|
21 | 27 | import jadx.core.dex.nodes.ClassNode;
|
22 | 28 | import jadx.core.dex.nodes.FieldNode;
|
| 29 | +import jadx.core.dex.nodes.ICodeNode; |
23 | 30 | import jadx.core.dex.nodes.MethodNode;
|
24 | 31 | import jadx.core.dex.nodes.RootNode;
|
25 | 32 | import jadx.core.dex.visitors.AbstractVisitor;
|
26 | 33 | import jadx.core.dex.visitors.JadxVisitor;
|
27 | 34 | import jadx.core.dex.visitors.OverrideMethodVisitor;
|
| 35 | +import jadx.core.dex.visitors.SignatureProcessor; |
28 | 36 | import jadx.core.dex.visitors.rename.RenameVisitor;
|
29 | 37 | import jadx.core.utils.ListUtils;
|
| 38 | +import jadx.core.utils.exceptions.JadxRuntimeException; |
30 | 39 | import jadx.core.utils.input.InsnDataUtils;
|
31 | 40 |
|
32 | 41 | @JadxVisitor(
|
33 | 42 | name = "UsageInfoVisitor",
|
34 | 43 | desc = "Scan class and methods to collect usage info and class dependencies",
|
35 | 44 | runAfter = {
|
| 45 | + SignatureProcessor.class, // use types with generics |
36 | 46 | OverrideMethodVisitor.class, // add method override as use
|
37 | 47 | RenameVisitor.class // sort by alias name
|
38 | 48 | }
|
@@ -80,19 +90,23 @@ private static void processClass(ClassNode cls, UsageInfo usageInfo) {
|
80 | 90 | }
|
81 | 91 | for (FieldNode fieldNode : cls.getFields()) {
|
82 | 92 | usageInfo.clsUse(cls, fieldNode.getType());
|
| 93 | + processAnnotations(fieldNode, usageInfo); |
| 94 | + // TODO: process types from field 'constant value' |
83 | 95 | }
|
84 |
| - // TODO: process annotations and generics |
| 96 | + // TODO: process generics |
| 97 | + processAnnotations(cls, usageInfo); |
85 | 98 | for (MethodNode methodNode : cls.getMethods()) {
|
86 | 99 | processMethod(methodNode, usageInfo);
|
87 | 100 | }
|
88 | 101 | }
|
89 | 102 |
|
90 | 103 | private static void processMethod(MethodNode mth, UsageInfo usageInfo) {
|
91 |
| - ClassNode cls = mth.getParentClass(); |
92 |
| - usageInfo.clsUse(cls, mth.getReturnType()); |
93 |
| - for (ArgType argType : mth.getMethodInfo().getArgumentsTypes()) { |
94 |
| - usageInfo.clsUse(cls, argType); |
| 104 | + processMethodAnnotations(mth, usageInfo); |
| 105 | + usageInfo.clsUse(mth, mth.getReturnType()); |
| 106 | + for (ArgType argType : mth.getArgTypes()) { |
| 107 | + usageInfo.clsUse(mth, argType); |
95 | 108 | }
|
| 109 | + // TODO: process exception classes from 'throws' |
96 | 110 | try {
|
97 | 111 | processInstructions(mth, usageInfo);
|
98 | 112 | } catch (Exception e) {
|
@@ -169,6 +183,65 @@ private static void processInsn(RootNode root, MethodNode mth, InsnData insnData
|
169 | 183 | }
|
170 | 184 | }
|
171 | 185 |
|
| 186 | + private static void processAnnotations(ICodeNode node, UsageInfo usageInfo) { |
| 187 | + AnnotationsAttr annAttr = node.get(JadxAttrType.ANNOTATION_LIST); |
| 188 | + processAnnotationAttr(node, annAttr, usageInfo); |
| 189 | + } |
| 190 | + |
| 191 | + private static void processMethodAnnotations(MethodNode mth, UsageInfo usageInfo) { |
| 192 | + processAnnotations(mth, usageInfo); |
| 193 | + AnnotationMethodParamsAttr paramsAttr = mth.get(JadxAttrType.ANNOTATION_MTH_PARAMETERS); |
| 194 | + if (paramsAttr != null) { |
| 195 | + for (AnnotationsAttr annAttr : paramsAttr.getParamList()) { |
| 196 | + processAnnotationAttr(mth, annAttr, usageInfo); |
| 197 | + } |
| 198 | + } |
| 199 | + } |
| 200 | + |
| 201 | + private static void processAnnotationAttr(ICodeNode node, AnnotationsAttr annAttr, UsageInfo usageInfo) { |
| 202 | + if (annAttr == null || annAttr.isEmpty()) { |
| 203 | + return; |
| 204 | + } |
| 205 | + for (IAnnotation ann : annAttr.getList()) { |
| 206 | + processAnnotation(node, ann, usageInfo); |
| 207 | + } |
| 208 | + } |
| 209 | + |
| 210 | + private static void processAnnotation(ICodeNode node, IAnnotation ann, UsageInfo usageInfo) { |
| 211 | + usageInfo.clsUse(node, ArgType.parse(ann.getAnnotationClass())); |
| 212 | + for (EncodedValue value : ann.getValues().values()) { |
| 213 | + processAnnotationValue(node, value, usageInfo); |
| 214 | + } |
| 215 | + } |
| 216 | + |
| 217 | + @SuppressWarnings("unchecked") |
| 218 | + private static void processAnnotationValue(ICodeNode node, EncodedValue value, UsageInfo usageInfo) { |
| 219 | + Object obj = value.getValue(); |
| 220 | + switch (value.getType()) { |
| 221 | + case ENCODED_TYPE: |
| 222 | + usageInfo.clsUse(node, ArgType.parse((String) obj)); |
| 223 | + break; |
| 224 | + case ENCODED_ENUM: |
| 225 | + case ENCODED_FIELD: |
| 226 | + if (obj instanceof IFieldRef) { |
| 227 | + usageInfo.fieldUse(node, FieldInfo.fromRef(node.root(), (IFieldRef) obj)); |
| 228 | + } else if (obj instanceof FieldInfo) { |
| 229 | + usageInfo.fieldUse(node, (FieldInfo) obj); |
| 230 | + } else { |
| 231 | + throw new JadxRuntimeException("Unexpected field type class: " + value.getClass()); |
| 232 | + } |
| 233 | + break; |
| 234 | + case ENCODED_ARRAY: |
| 235 | + for (EncodedValue encodedValue : (List<EncodedValue>) obj) { |
| 236 | + processAnnotationValue(node, encodedValue, usageInfo); |
| 237 | + } |
| 238 | + break; |
| 239 | + case ENCODED_ANNOTATION: |
| 240 | + processAnnotation(node, (IAnnotation) obj, usageInfo); |
| 241 | + break; |
| 242 | + } |
| 243 | + } |
| 244 | + |
172 | 245 | public static void replaceMethodUsage(MethodNode mergeIntoMth, MethodNode sourceMth) {
|
173 | 246 | List<MethodNode> mergedUsage = ListUtils.distinctMergeSortedLists(mergeIntoMth.getUseIn(), sourceMth.getUseIn());
|
174 | 247 | mergedUsage.remove(sourceMth);
|
|
0 commit comments