View Javadoc

1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
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   * Utility class used to build a UsageGraph.
28   */
29  public class UsageGraphBuilder {
30  
31  	/**
32  	 * Should trace level logging be enabled.  This is a development debugging
33  	 * option.
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  	// ASM visitor to on Class files to build a UsageGraph
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 }