1
2
3
4 package net.sourceforge.pmd.dcd.graph;
5
6 import java.io.IOException;
7 import java.io.InputStream;
8 import java.util.ArrayList;
9 import java.util.Arrays;
10 import java.util.List;
11 import org.objectweb.asm.AnnotationVisitor;
12 import org.objectweb.asm.Attribute;
13 import org.objectweb.asm.ClassReader;
14 import org.objectweb.asm.ClassVisitor;
15 import org.objectweb.asm.FieldVisitor;
16 import org.objectweb.asm.Label;
17 import org.objectweb.asm.MethodVisitor;
18 import org.objectweb.asm.Opcodes;
19 import org.objectweb.asm.signature.SignatureReader;
20 import net.sourceforge.pmd.dcd.asm.PrintVisitor;
21 import net.sourceforge.pmd.dcd.asm.TypeSignatureVisitor;
22 import net.sourceforge.pmd.util.filter.Filter;
23
24
25
26
27 public class UsageGraphBuilder {
28
29
30
31
32
33 private static final boolean TRACE = false;
34 private static final boolean INDEX = true;
35
36 protected final UsageGraph usageGraph;
37 protected final Filter<String> classFilter;
38
39 public UsageGraphBuilder(Filter<String> classFilter) {
40 this.classFilter = classFilter;
41 this.usageGraph = new UsageGraph(classFilter);
42 }
43
44 public void index(String name) {
45 try {
46 String className = getClassName(name);
47 String classResourceName = getResourceName(name);
48 if (classFilter.filter(className)) {
49 if (!usageGraph.isClass(className)) {
50 usageGraph.defineClass(className);
51 InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(
52 classResourceName + ".class");
53 ClassReader classReader = new ClassReader(inputStream);
54 classReader.accept(getNewClassVisitor(), 0);
55 }
56 }
57 } catch (IOException e) {
58 throw new RuntimeException("For " + name + ": " + e.getMessage(), e);
59 }
60 }
61
62 public UsageGraph getUsageGraph() {
63 return usageGraph;
64 }
65
66 private ClassVisitor getNewClassVisitor() {
67 return new MyClassVisitor();
68 }
69
70
71 class MyClassVisitor extends ClassVisitor {
72 private final PrintVisitor p;
73
74 protected void println(String s) {
75 p.println(s);
76 }
77
78 protected void printlnIndent(String s) {
79 p.printlnIndent(s);
80 }
81
82 public MyClassVisitor() {
83 super(Opcodes.ASM5);
84 p = new PrintVisitor();
85 }
86
87 private String className;
88
89 public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
90 if (TRACE) {
91 println("visit:");
92 printlnIndent("version: " + version);
93 printlnIndent("access: " + access);
94 printlnIndent("name: " + name);
95 printlnIndent("signature: " + signature);
96 printlnIndent("superName: " + superName);
97 printlnIndent("interfaces: " + asList(interfaces));
98 }
99 this.className = getClassName(name);
100 }
101
102 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
103 if (TRACE) {
104 println("visitAnnotation:");
105 printlnIndent("desc: " + desc);
106 printlnIndent("visible: " + visible);
107 }
108 return null;
109 }
110
111 public void visitAttribute(Attribute attr) {
112 if (TRACE) {
113 println("visitAttribute:");
114 printlnIndent("attr: " + attr);
115 }
116 }
117
118 public void visitEnd() {
119 if (TRACE) {
120 println("visitEnd:");
121 }
122 }
123
124 public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
125 if (TRACE) {
126 println("visitField:");
127 printlnIndent("access: " + access);
128 printlnIndent("name: " + name);
129 printlnIndent("desc: " + desc);
130 printlnIndent("signature: " + signature);
131 printlnIndent("value: " + value);
132 }
133 if (INDEX) {
134 SignatureReader signatureReader = new SignatureReader(desc);
135 TypeSignatureVisitor visitor = new TypeSignatureVisitor(p);
136 signatureReader.acceptType(visitor);
137 if (TRACE) {
138 printlnIndent("fieldType: " + visitor.getFieldType());
139 }
140
141 usageGraph.defineField(className, name, desc);
142 }
143 return null;
144 }
145
146 public void visitInnerClass(String name, String outerName, String innerName, int access) {
147 if (TRACE) {
148 println("visitInnerClass:");
149 printlnIndent("name: " + name);
150 printlnIndent("outerName: " + outerName);
151 printlnIndent("innerName: " + innerName);
152 printlnIndent("access: " + access);
153 }
154 index(name);
155 }
156
157 public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
158 MemberNode memberNode = null;
159 if (TRACE) {
160 println("visitMethod:");
161 printlnIndent("access: " + access);
162 printlnIndent("name: " + name);
163 printlnIndent("desc: " + desc);
164 printlnIndent("signature: " + signature);
165 printlnIndent("exceptions: " + asList(exceptions));
166 }
167 if (INDEX) {
168 memberNode = usageGraph.defineMethod(className, name, desc);
169 }
170 return getNewMethodVisitor(p, memberNode);
171 }
172
173 public void visitOuterClass(String owner, String name, String desc) {
174 if (TRACE) {
175 println("visitOuterClass:");
176 printlnIndent("owner: " + owner);
177 printlnIndent("name: " + name);
178 printlnIndent("desc: " + desc);
179 }
180 }
181
182 public void visitSource(String source, String debug) {
183 if (TRACE) {
184 println("visitSource:");
185 printlnIndent("source: " + source);
186 printlnIndent("debug: " + debug);
187 }
188 }
189 }
190
191 protected MethodVisitor getNewMethodVisitor(PrintVisitor parent, MemberNode usingMemberNode) {
192 return new MyMethodVisitor(parent, usingMemberNode);
193 }
194
195 protected class MyMethodVisitor extends MethodVisitor {
196 private final PrintVisitor p;
197
198 protected void println(String s) {
199 p.println(s);
200 }
201
202 protected void printlnIndent(String s) {
203 p.printlnIndent(s);
204 }
205
206 private final MemberNode usingMemberNode;
207
208 public MyMethodVisitor(PrintVisitor parent, MemberNode usingMemberNode) {
209 super(Opcodes.ASM5);
210 p = parent;
211 this.usingMemberNode = usingMemberNode;
212 }
213
214 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
215 if (TRACE) {
216 println("visitAnnotation:");
217 printlnIndent("desc: " + desc);
218 printlnIndent("visible: " + visible);
219 }
220 return null;
221 }
222
223 public AnnotationVisitor visitAnnotationDefault() {
224 if (TRACE) {
225 println("visitAnnotationDefault:");
226 }
227 return null;
228 }
229
230 public void visitAttribute(Attribute attr) {
231 if (TRACE) {
232 println("visitAttribute:");
233 printlnIndent("attr: " + attr);
234 }
235 }
236
237 public void visitCode() {
238 if (TRACE) {
239 println("visitCode:");
240 }
241 }
242
243 public void visitEnd() {
244 if (TRACE) {
245 println("visitEnd:");
246 }
247 }
248
249 public void visitFieldInsn(int opcode, String owner, String name, String desc) {
250 if (TRACE) {
251 println("visitFieldInsn:");
252 printlnIndent("opcode: " + opcode);
253 printlnIndent("owner: " + owner);
254 printlnIndent("name: " + name);
255 printlnIndent("desc: " + desc);
256 }
257 if (INDEX) {
258 String className = getClassName(owner);
259 usageGraph.usageField(className, name, desc, usingMemberNode);
260 }
261 }
262
263 public void visitFrame(int type, int local, Object[] local2, int stack, Object[] stack2) {
264 if (TRACE) {
265 println("visitFrame:");
266 printlnIndent("type: " + type);
267 printlnIndent("local: " + local);
268 printlnIndent("local2: " + asList(local2));
269 printlnIndent("stack: " + stack);
270 printlnIndent("stack2: " + asList(stack2));
271 }
272 }
273
274 public void visitIincInsn(int var, int increment) {
275 if (TRACE) {
276 println("visitIincInsn:");
277 printlnIndent("var: " + var);
278 printlnIndent("increment: " + increment);
279 }
280 }
281
282 public void visitInsn(int opcode) {
283 if (TRACE) {
284 println("visitInsn:");
285 printlnIndent("opcode: " + opcode);
286 }
287 }
288
289 public void visitIntInsn(int opcode, int operand) {
290 if (TRACE) {
291 println("visitIntInsn:");
292 printlnIndent("opcode: " + opcode);
293 printlnIndent("operand: " + operand);
294 }
295 }
296
297 public void visitJumpInsn(int opcode, Label label) {
298 if (TRACE) {
299 println("visitJumpInsn:");
300 printlnIndent("opcode: " + opcode);
301 printlnIndent("label: " + label);
302 }
303 }
304
305 public void visitLabel(Label label) {
306 if (TRACE) {
307 println("visitLabel:");
308 printlnIndent("label: " + label);
309 }
310 }
311
312 public void visitLdcInsn(Object cst) {
313 if (TRACE) {
314 println("visitLdcInsn:");
315 printlnIndent("cst: " + cst);
316 }
317 }
318
319 public void visitLineNumber(int line, Label start) {
320 if (TRACE) {
321 println("visitLineNumber:");
322 printlnIndent("line: " + line);
323 printlnIndent("start: " + start);
324 }
325 }
326
327 public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
328 if (TRACE) {
329 println("visitLocalVariable:");
330 printlnIndent("name: " + name);
331 printlnIndent("desc: " + desc);
332 printlnIndent("signature: " + signature);
333 printlnIndent("start: " + start);
334 printlnIndent("end: " + end);
335 printlnIndent("index: " + index);
336 }
337 }
338
339 public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
340 if (TRACE) {
341 println("visitLookupSwitchInsn:");
342 printlnIndent("dflt: " + dflt);
343 printlnIndent("keys: " + asList(keys));
344 printlnIndent("labels: " + asList(labels));
345 }
346 }
347
348 public void visitMaxs(int maxStack, int maxLocals) {
349 if (TRACE) {
350 println("visitMaxs:");
351 printlnIndent("maxStack: " + maxStack);
352 printlnIndent("maxLocals: " + maxLocals);
353 }
354 }
355
356 public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
357 if (TRACE) {
358 println("visitMethodInsn:");
359 printlnIndent("opcode: " + opcode);
360 printlnIndent("owner: " + owner);
361 printlnIndent("name: " + name);
362 printlnIndent("desc: " + desc);
363 printlnIndent("itf: " + itf);
364 }
365 if (INDEX) {
366 String className = getClassName(owner);
367 usageGraph.usageMethod(className, name, desc, usingMemberNode);
368 }
369 }
370
371 public void visitMultiANewArrayInsn(String desc, int dims) {
372 if (TRACE) {
373 println("visitMultiANewArrayInsn:");
374 printlnIndent("desc: " + desc);
375 printlnIndent("dims: " + dims);
376 }
377 }
378
379 public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {
380 if (TRACE) {
381 println("visitParameterAnnotation:");
382 printlnIndent("parameter: " + parameter);
383 printlnIndent("desc: " + desc);
384 printlnIndent("visible: " + visible);
385 }
386 return null;
387 }
388
389 public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels) {
390 if (TRACE) {
391 println("visitTableSwitchInsn:");
392 printlnIndent("min: " + min);
393 printlnIndent("max: " + max);
394 printlnIndent("dflt: " + dflt);
395 printlnIndent("labels: " + asList(labels));
396 }
397 }
398
399 public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
400 if (TRACE) {
401 println("visitTryCatchBlock:");
402 printlnIndent("start: " + start);
403 printlnIndent("end: " + end);
404 printlnIndent("handler: " + handler);
405 printlnIndent("type: " + type);
406 }
407 }
408
409 public void visitTypeInsn(int opcode, String desc) {
410 if (TRACE) {
411 println("visitTypeInsn:");
412 printlnIndent("opcode: " + opcode);
413 printlnIndent("desc: " + desc);
414 }
415 }
416
417 public void visitVarInsn(int opcode, int var) {
418 if (TRACE) {
419 println("visitVarInsn:");
420 printlnIndent("opcode: " + opcode);
421 printlnIndent("var: " + var);
422 }
423 }
424 }
425
426 private static String getResourceName(String name) {
427 return name.replace('.', '/');
428 }
429
430 static String getClassName(String name) {
431 return name.replace('/', '.');
432 }
433
434 private static List<Integer> asList(int[] array) {
435 List<Integer> list = null;
436 if (array != null) {
437 list = new ArrayList<Integer>(array.length);
438 for (int i : array) {
439 list.add(i);
440 }
441 }
442 return list;
443 }
444
445 private static List<Object> asList(Object[] array) {
446 return array != null ? Arrays.asList(array) : null;
447 }
448 }