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
12 import net.sourceforge.pmd.dcd.asm.PrintVisitor;
13 import net.sourceforge.pmd.dcd.asm.TypeSignatureVisitor;
14 import net.sourceforge.pmd.util.filter.Filter;
15
16 import org.objectweb.asm.AnnotationVisitor;
17 import org.objectweb.asm.Attribute;
18 import org.objectweb.asm.ClassReader;
19 import org.objectweb.asm.ClassVisitor;
20 import org.objectweb.asm.FieldVisitor;
21 import org.objectweb.asm.Label;
22 import org.objectweb.asm.MethodVisitor;
23 import org.objectweb.asm.Opcodes;
24 import org.objectweb.asm.signature.SignatureReader;
25
26
27
28
29 public class UsageGraphBuilder {
30
31
32
33
34
35 private static final boolean TRACE = false;
36 private static final boolean INDEX = true;
37
38 protected final UsageGraph usageGraph;
39 protected final Filter<String> classFilter;
40
41 public UsageGraphBuilder(Filter<String> classFilter) {
42 this.classFilter = classFilter;
43 this.usageGraph = new UsageGraph(classFilter);
44 }
45
46 public void index(String name) {
47 try {
48 String className = getClassName(name);
49 String classResourceName = getResourceName(name);
50 if (classFilter.filter(className)) {
51 if (!usageGraph.isClass(className)) {
52 usageGraph.defineClass(className);
53 InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(
54 classResourceName + ".class");
55 ClassReader classReader = new ClassReader(inputStream);
56 classReader.accept(getNewClassVisitor(), 0);
57 }
58 }
59 } catch (IOException e) {
60 throw new RuntimeException("For " + name + ": " + e.getMessage(), e);
61 }
62 }
63
64 public UsageGraph getUsageGraph() {
65 return usageGraph;
66 }
67
68 private ClassVisitor getNewClassVisitor() {
69 return new MyClassVisitor();
70 }
71
72
73 class MyClassVisitor extends ClassVisitor {
74 private final PrintVisitor p;
75 protected void println(String s) {
76 p.println(s);
77 }
78 protected void printlnIndent(String s) {
79 p.printlnIndent(s);
80 }
81
82 public MyClassVisitor() {
83 super(Opcodes.ASM4);
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 protected void println(String s) {
198 p.println(s);
199 }
200 protected void printlnIndent(String s) {
201 p.printlnIndent(s);
202 }
203
204 private final MemberNode usingMemberNode;
205
206 public MyMethodVisitor(PrintVisitor parent, MemberNode usingMemberNode) {
207 super(Opcodes.ASM4);
208 p = parent;
209 this.usingMemberNode = usingMemberNode;
210 }
211
212 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
213 if (TRACE) {
214 println("visitAnnotation:");
215 printlnIndent("desc: " + desc);
216 printlnIndent("visible: " + visible);
217 }
218 return null;
219 }
220
221 public AnnotationVisitor visitAnnotationDefault() {
222 if (TRACE) {
223 println("visitAnnotationDefault:");
224 }
225 return null;
226 }
227
228 public void visitAttribute(Attribute attr) {
229 if (TRACE) {
230 println("visitAttribute:");
231 printlnIndent("attr: " + attr);
232 }
233 }
234
235 public void visitCode() {
236 if (TRACE) {
237 println("visitCode:");
238 }
239 }
240
241 public void visitEnd() {
242 if (TRACE) {
243 println("visitEnd:");
244 }
245 }
246
247 public void visitFieldInsn(int opcode, String owner, String name, String desc) {
248 if (TRACE) {
249 println("visitFieldInsn:");
250 printlnIndent("opcode: " + opcode);
251 printlnIndent("owner: " + owner);
252 printlnIndent("name: " + name);
253 printlnIndent("desc: " + desc);
254 }
255 if (INDEX) {
256 String className = getClassName(owner);
257 usageGraph.usageField(className, name, desc, usingMemberNode);
258 }
259 }
260
261 public void visitFrame(int type, int local, Object[] local2, int stack, Object[] stack2) {
262 if (TRACE) {
263 println("visitFrame:");
264 printlnIndent("type: " + type);
265 printlnIndent("local: " + local);
266 printlnIndent("local2: " + asList(local2));
267 printlnIndent("stack: " + stack);
268 printlnIndent("stack2: " + asList(stack2));
269 }
270 }
271
272 public void visitIincInsn(int var, int increment) {
273 if (TRACE) {
274 println("visitIincInsn:");
275 printlnIndent("var: " + var);
276 printlnIndent("increment: " + increment);
277 }
278 }
279
280 public void visitInsn(int opcode) {
281 if (TRACE) {
282 println("visitInsn:");
283 printlnIndent("opcode: " + opcode);
284 }
285 }
286
287 public void visitIntInsn(int opcode, int operand) {
288 if (TRACE) {
289 println("visitIntInsn:");
290 printlnIndent("opcode: " + opcode);
291 printlnIndent("operand: " + operand);
292 }
293 }
294
295 public void visitJumpInsn(int opcode, Label label) {
296 if (TRACE) {
297 println("visitJumpInsn:");
298 printlnIndent("opcode: " + opcode);
299 printlnIndent("label: " + label);
300 }
301 }
302
303 public void visitLabel(Label label) {
304 if (TRACE) {
305 println("visitLabel:");
306 printlnIndent("label: " + label);
307 }
308 }
309
310 public void visitLdcInsn(Object cst) {
311 if (TRACE) {
312 println("visitLdcInsn:");
313 printlnIndent("cst: " + cst);
314 }
315 }
316
317 public void visitLineNumber(int line, Label start) {
318 if (TRACE) {
319 println("visitLineNumber:");
320 printlnIndent("line: " + line);
321 printlnIndent("start: " + start);
322 }
323 }
324
325 public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
326 if (TRACE) {
327 println("visitLocalVariable:");
328 printlnIndent("name: " + name);
329 printlnIndent("desc: " + desc);
330 printlnIndent("signature: " + signature);
331 printlnIndent("start: " + start);
332 printlnIndent("end: " + end);
333 printlnIndent("index: " + index);
334 }
335 }
336
337 public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
338 if (TRACE) {
339 println("visitLookupSwitchInsn:");
340 printlnIndent("dflt: " + dflt);
341 printlnIndent("keys: " + asList(keys));
342 printlnIndent("labels: " + asList(labels));
343 }
344 }
345
346 public void visitMaxs(int maxStack, int maxLocals) {
347 if (TRACE) {
348 println("visitMaxs:");
349 printlnIndent("maxStack: " + maxStack);
350 printlnIndent("maxLocals: " + maxLocals);
351 }
352 }
353
354 public void visitMethodInsn(int opcode, String owner, String name, String desc) {
355 if (TRACE) {
356 println("visitMethodInsn:");
357 printlnIndent("opcode: " + opcode);
358 printlnIndent("owner: " + owner);
359 printlnIndent("name: " + name);
360 printlnIndent("desc: " + desc);
361 }
362 if (INDEX) {
363 String className = getClassName(owner);
364 usageGraph.usageMethod(className, name, desc, usingMemberNode);
365 }
366 }
367
368 public void visitMultiANewArrayInsn(String desc, int dims) {
369 if (TRACE) {
370 println("visitMultiANewArrayInsn:");
371 printlnIndent("desc: " + desc);
372 printlnIndent("dims: " + dims);
373 }
374 }
375
376 public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {
377 if (TRACE) {
378 println("visitParameterAnnotation:");
379 printlnIndent("parameter: " + parameter);
380 printlnIndent("desc: " + desc);
381 printlnIndent("visible: " + visible);
382 }
383 return null;
384 }
385
386 public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels) {
387 if (TRACE) {
388 println("visitTableSwitchInsn:");
389 printlnIndent("min: " + min);
390 printlnIndent("max: " + max);
391 printlnIndent("dflt: " + dflt);
392 printlnIndent("labels: " + asList(labels));
393 }
394 }
395
396 public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
397 if (TRACE) {
398 println("visitTryCatchBlock:");
399 printlnIndent("start: " + start);
400 printlnIndent("end: " + end);
401 printlnIndent("handler: " + handler);
402 printlnIndent("type: " + type);
403 }
404 }
405
406 public void visitTypeInsn(int opcode, String desc) {
407 if (TRACE) {
408 println("visitTypeInsn:");
409 printlnIndent("opcode: " + opcode);
410 printlnIndent("desc: " + desc);
411 }
412 }
413
414 public void visitVarInsn(int opcode, int var) {
415 if (TRACE) {
416 println("visitVarInsn:");
417 printlnIndent("opcode: " + opcode);
418 printlnIndent("var: " + var);
419 }
420 }
421 }
422
423 private static String getResourceName(String name) {
424 return name.replace('.', '/');
425 }
426
427 static String getClassName(String name) {
428 return name.replace('/', '.');
429 }
430
431 private static List<Integer> asList(int[] array) {
432 List<Integer> list = null;
433 if (array != null) {
434 list = new ArrayList<Integer>(array.length);
435 for (int i : array) {
436 list.add(i);
437 }
438 }
439 return list;
440 }
441
442 private static List<Object> asList(Object[] array) {
443 return array != null ? Arrays.asList(array) : null;
444 }
445 }