1 /**
2 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3 */
4 package net.sourceforge.pmd.typeresolution.visitors;
5
6 import org.objectweb.asm.AnnotationVisitor;
7 import org.objectweb.asm.Attribute;
8 import org.objectweb.asm.ClassVisitor;
9 import org.objectweb.asm.FieldVisitor;
10 import org.objectweb.asm.Label;
11 import org.objectweb.asm.MethodVisitor;
12 import org.objectweb.asm.Type;
13 import org.objectweb.asm.signature.SignatureReader;
14 import org.objectweb.asm.signature.SignatureVisitor;
15
16 import java.util.ArrayList;
17 import java.util.HashMap;
18 import java.util.List;
19 import java.util.Map;
20
21 public class PMDASMVisitor implements ClassVisitor {
22
23 private Map<String, String> packages = new HashMap<String, String>();
24
25 private AnnotationVisitor annotationVisitor = new PMDAnnotationVisitor(this);
26
27 private FieldVisitor fieldVisitor = new PMDFieldVisitor(this);
28
29 private SignatureVisitor sigVisitor = new PMDSignatureVisitor(this);
30
31 private MethodVisitor methodVisitor = new PMDMethodVisitor(this);
32
33 public List<String> innerClasses;
34
35 public Map<String, String> getPackages() {
36 return packages;
37 }
38
39 public List<String> getInnerClasses() {
40 return innerClasses;
41 }
42
43 private String parseClassName(String name) {
44 if (name == null) {
45 return null;
46 }
47
48 String className = name;
49 int n = name.lastIndexOf('/');
50 if (n > -1) {
51 className = name.substring(n + 1);
52 }
53 name = name.replace('/', '.');
54 packages.put(className, name);
55 n = className.indexOf('$');
56 if (n > -1) {
57
58 packages.put(className.substring(n + 1), name);
59 packages.put(className.replace('$', '.'), name);
60 }
61
62 return name;
63 }
64
65 private void parseClassName(String[] names) {
66 if (names != null) {
67 for (String s : names) {
68 parseClassName(s);
69 }
70 }
71 }
72
73 private void extractSignature(String sig) {
74 if (sig != null) {
75 new SignatureReader(sig).accept(sigVisitor);
76 }
77 }
78
79
80
81 public void visit(int version, int access, String name, String sig, String superName, String[] interfaces) {
82 parseClassName(name);
83 parseClassName(interfaces);
84 if (sig != null) {
85 extractSignature(sig);
86 }
87 }
88
89 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
90 addType(Type.getType(desc));
91 return annotationVisitor;
92 }
93
94 public FieldVisitor visitField(int access, String name, String desc, String sig, Object value) {
95 if (sig != null) {
96 extractSignature(sig);
97 }
98
99 addType(Type.getType(desc));
100 if (value instanceof Type) {
101 addType((Type) value);
102 }
103 return fieldVisitor;
104 }
105
106 public MethodVisitor visitMethod(int access, String name, String desc, String sig, String[] exceptions) {
107 if (sig != null) {
108 extractSignature(sig);
109 }
110 addMethodDesc(desc);
111 parseClassName(exceptions);
112 return methodVisitor;
113 }
114
115 public void visitSource(String source, String debug) {
116 }
117
118 public void visitInnerClass(String name, String outerName, String innerName, int access) {
119 if (innerClasses == null) {
120 innerClasses = new ArrayList<String>();
121 }
122 if (!innerClasses.contains(name.replace('/', '.'))) {
123 innerClasses.add(name.replace('/', '.'));
124 }
125 packages.put(innerName, name.replace('/', '.'));
126 }
127
128 public void visitOuterClass(String owner, String name, String desc) {
129 }
130
131 public void visitEnd() {
132 }
133
134 private void addMethodDesc(String desc) {
135 addTypes(desc);
136 addType(Type.getReturnType(desc));
137 }
138
139 private void addTypes(String desc) {
140 Type[] types = Type.getArgumentTypes(desc);
141 for (Type type : types) {
142 addType(type);
143 }
144 }
145
146 private void addType(Type t) {
147 switch (t.getSort()) {
148 case Type.ARRAY:
149 addType(t.getElementType());
150 break;
151 case Type.OBJECT:
152 parseClassName(t.getClassName().replace('.', '/'));
153 break;
154 }
155 }
156
157 public void visitAttribute(Attribute attr) {
158 }
159
160
161
162
163
164 private static class PMDFieldVisitor implements FieldVisitor {
165
166 private PMDASMVisitor parent;
167
168 public PMDFieldVisitor(PMDASMVisitor visitor) {
169 parent = visitor;
170 }
171
172 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
173 parent.addType(Type.getType(desc));
174 return parent.annotationVisitor;
175 }
176
177 public void visitAttribute(Attribute attr) {
178 }
179
180 public void visitEnd() {
181 }
182 }
183
184 private static class PMDAnnotationVisitor implements AnnotationVisitor {
185 private PMDASMVisitor parent;
186
187 public PMDAnnotationVisitor(PMDASMVisitor visitor) {
188 parent = visitor;
189 }
190
191 public AnnotationVisitor visitAnnotation(String name, String desc) {
192 parent.addType(Type.getType(desc));
193 return this;
194 }
195
196 public void visitEnum(String name, String desc, String value) {
197 parent.addType(Type.getType(desc));
198 }
199
200 public AnnotationVisitor visitArray(String name) {
201 return this;
202 }
203
204 public void visitEnd() {
205 }
206
207 public void visit(String name, Object value) {
208 if (value instanceof Type) {
209 parent.addType((Type) value);
210 }
211 }
212 }
213
214 private static class PMDSignatureVisitor implements SignatureVisitor {
215 private PMDASMVisitor parent;
216
217 public PMDSignatureVisitor(PMDASMVisitor visitor) {
218 this.parent = visitor;
219 }
220
221 public void visitFormalTypeParameter(String name) {
222 }
223
224 public SignatureVisitor visitClassBound() {
225 return this;
226 }
227
228 public SignatureVisitor visitInterfaceBound() {
229 return this;
230 }
231
232 public SignatureVisitor visitSuperclass() {
233 return this;
234 }
235
236 public SignatureVisitor visitInterface() {
237 return this;
238 }
239
240 public SignatureVisitor visitParameterType() {
241 return this;
242 }
243
244 public SignatureVisitor visitReturnType() {
245 return this;
246 }
247
248 public SignatureVisitor visitExceptionType() {
249 return this;
250 }
251
252 public void visitBaseType(char descriptor) {
253 }
254
255 public void visitTypeVariable(String name) {
256 }
257
258 public SignatureVisitor visitArrayType() {
259 return this;
260 }
261
262 public void visitClassType(String name) {
263 parent.parseClassName(name);
264 }
265
266 public void visitInnerClassType(String name) {
267 parent.parseClassName(name);
268 }
269
270 public void visitTypeArgument() {
271 }
272
273 public SignatureVisitor visitTypeArgument(char wildcard) {
274 return this;
275 }
276
277 public void visitEnd() {
278 }
279 }
280
281 private static class PMDMethodVisitor implements MethodVisitor {
282 private PMDASMVisitor parent;
283
284 public PMDMethodVisitor(PMDASMVisitor visitor) {
285 parent = visitor;
286 }
287
288 public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {
289 parent.addType(Type.getType(desc));
290 return parent.annotationVisitor;
291 }
292
293 public AnnotationVisitor visitAnnotation(String name, String desc) {
294 parent.addType(Type.getType(desc));
295 return parent.annotationVisitor;
296 }
297
298 public void visitTypeInsn(int opcode, String desc) {
299 if (desc.charAt(0) == '[') {
300 parent.addType(Type.getType(desc));
301 } else {
302 parent.parseClassName(desc);
303 }
304 }
305
306 public void visitFieldInsn(int opcode, String owner, String name, String desc) {
307 parent.parseClassName(owner);
308 parent.addType(Type.getType(desc));
309 }
310
311 public void visitMethodInsn(int opcode, String owner, String name, String desc) {
312 parent.parseClassName(owner);
313 parent.addMethodDesc(desc);
314 }
315
316 /**
317 * the constant to be loaded on the stack. This parameter must be a non null
318 * Integer, a Float, a Long, a Double a String (or a Type for .class
319 * constants, for classes whose version is 49.0 or more).
320 *
321 * @see org.objectweb.asm.MethodVisitor#visitLdcInsn(java.lang.Object)
322 */
323 public void visitLdcInsn(Object cst) {
324 if (cst instanceof Type) {
325 parent.addType((Type) cst);
326 } else if (cst instanceof String) {
327 parent.parseClassName((String) cst);
328 }
329 }
330 public void visitMultiANewArrayInsn(String desc, int dims) {
331 parent.addType(Type.getType(desc));
332 }
333
334 public void visitLocalVariable(String name, String desc, String sig, Label start, Label end, int index) {
335 parent.extractSignature(sig);
336 }
337
338 public void visitCode() {
339 }
340
341 public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
342 }
343
344 public void visitInsn(int opcode) {
345 }
346
347 public void visitIntInsn(int opcode, int operand) {
348 }
349
350 public void visitVarInsn(int opcode, int var) {
351 }
352
353 public void visitJumpInsn(int opcode, Label label) {
354 }
355
356 public void visitLabel(Label label) {
357 }
358
359 public void visitIincInsn(int var, int increment) {
360 }
361
362 public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels) {
363 }
364
365 public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
366 }
367
368 public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
369 parent.parseClassName(type);
370 }
371
372 public void visitLineNumber(int line, Label start) {
373 }
374
375 public void visitMaxs(int maxStack, int maxLocals) {
376 }
377
378 public AnnotationVisitor visitAnnotationDefault() {
379 return parent.annotationVisitor;
380 }
381
382 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
383 parent.addType(Type.getType(desc));
384 return parent.annotationVisitor;
385 }
386
387 public void visitEnd() {
388 }
389
390 public void visitAttribute(Attribute attr) {
391 }
392
393 }
394 }