001: package net.sourceforge.pmd.dcd.graph;
002:
003: import java.io.IOException;
004: import java.io.InputStream;
005: import java.util.ArrayList;
006: import java.util.Arrays;
007: import java.util.List;
008:
009: import net.sourceforge.pmd.dcd.asm.PrintVisitor;
010: import net.sourceforge.pmd.dcd.asm.TypeSignatureVisitor;
011: import net.sourceforge.pmd.util.filter.Filter;
012:
013: import org.objectweb.asm.AnnotationVisitor;
014: import org.objectweb.asm.Attribute;
015: import org.objectweb.asm.ClassReader;
016: import org.objectweb.asm.ClassVisitor;
017: import org.objectweb.asm.FieldVisitor;
018: import org.objectweb.asm.Label;
019: import org.objectweb.asm.MethodVisitor;
020: import org.objectweb.asm.signature.SignatureReader;
021:
022: /**
023: * Utility class used to build a UsageGraph.
024: */
025: public class UsageGraphBuilder {
026:
027: /**
028: * Should trace level logging be enabled. This is a development debugging
029: * option.
030: */
031: private static final boolean TRACE = false;
032: private static final boolean INDEX = true;
033:
034: protected final UsageGraph usageGraph;
035: protected final Filter<String> classFilter;
036:
037: public UsageGraphBuilder(Filter<String> classFilter) {
038: this .classFilter = classFilter;
039: this .usageGraph = new UsageGraph(classFilter);
040: }
041:
042: public void index(String name) {
043: try {
044: String className = getClassName(name);
045: String classResourceName = getResourceName(name);
046: if (classFilter.filter(className)) {
047: if (!usageGraph.isClass(className)) {
048: ClassNode classNode = usageGraph
049: .defineClass(className);
050: InputStream inputStream = this .getClass()
051: .getClassLoader().getResourceAsStream(
052: classResourceName + ".class");
053: ClassReader classReader = new ClassReader(
054: inputStream);
055: classReader.accept(getNewClassVisitor(), 0);
056: }
057: }
058: } catch (IOException e) {
059: throw new RuntimeException("For " + name + ": "
060: + e.getMessage(), e);
061: }
062: }
063:
064: public UsageGraph getUsageGraph() {
065: return usageGraph;
066: }
067:
068: private ClassVisitor getNewClassVisitor() {
069: return new MyClassVisitor();
070: }
071:
072: // ASM visitor to on Class files to build a UsageGraph
073: class MyClassVisitor extends PrintVisitor implements ClassVisitor {
074: private String className;
075:
076: public void visit(int version, int access, String name,
077: String signature, String super Name, String[] interfaces) {
078: if (TRACE) {
079: println("visit:");
080: printlnIndent("version: " + version);
081: printlnIndent("access: " + access);
082: printlnIndent("name: " + name);
083: printlnIndent("signature: " + signature);
084: printlnIndent("superName: " + super Name);
085: printlnIndent("interfaces: " + asList(interfaces));
086: }
087: this .className = getClassName(name);
088: }
089:
090: public AnnotationVisitor visitAnnotation(String desc,
091: boolean visible) {
092: if (TRACE) {
093: println("visitAnnotation:");
094: printlnIndent("desc: " + desc);
095: printlnIndent("visible: " + visible);
096: }
097: return null;
098: }
099:
100: public void visitAttribute(Attribute attr) {
101: if (TRACE) {
102: println("visitAttribute:");
103: printlnIndent("attr: " + attr);
104: }
105: }
106:
107: public void visitEnd() {
108: if (TRACE) {
109: println("visitEnd:");
110: }
111: }
112:
113: public FieldVisitor visitField(int access, String name,
114: String desc, String signature, Object value) {
115: if (TRACE) {
116: println("visitField:");
117: printlnIndent("access: " + access);
118: printlnIndent("name: " + name);
119: printlnIndent("desc: " + desc);
120: printlnIndent("signature: " + signature);
121: printlnIndent("value: " + value);
122: }
123: if (INDEX) {
124: SignatureReader signatureReader = new SignatureReader(
125: desc);
126: TypeSignatureVisitor visitor = new TypeSignatureVisitor(
127: this );
128: signatureReader.acceptType(visitor);
129: if (TRACE) {
130: printlnIndent("fieldType: "
131: + visitor.getFieldType());
132: }
133:
134: usageGraph.defineField(className, name, desc);
135: }
136: return null;
137: }
138:
139: public void visitInnerClass(String name, String outerName,
140: String innerName, int access) {
141: if (TRACE) {
142: println("visitInnerClass:");
143: printlnIndent("name: " + name);
144: printlnIndent("outerName: " + outerName);
145: printlnIndent("innerName: " + innerName);
146: printlnIndent("access: " + access);
147: }
148: index(name);
149: }
150:
151: public MethodVisitor visitMethod(int access, String name,
152: String desc, String signature, String[] exceptions) {
153: MemberNode memberNode = null;
154: if (TRACE) {
155: println("visitMethod:");
156: printlnIndent("access: " + access);
157: printlnIndent("name: " + name);
158: printlnIndent("desc: " + desc);
159: printlnIndent("signature: " + signature);
160: printlnIndent("exceptions: " + asList(exceptions));
161: }
162: if (INDEX) {
163: memberNode = usageGraph.defineMethod(className, name,
164: desc);
165: }
166: return getNewMethodVisitor(this , memberNode);
167: }
168:
169: public void visitOuterClass(String owner, String name,
170: String desc) {
171: if (TRACE) {
172: println("visitOuterClass:");
173: printlnIndent("owner: " + owner);
174: printlnIndent("name: " + name);
175: printlnIndent("desc: " + desc);
176: }
177: }
178:
179: public void visitSource(String source, String debug) {
180: if (TRACE) {
181: println("visitSource:");
182: printlnIndent("source: " + source);
183: printlnIndent("debug: " + debug);
184: }
185: }
186: }
187:
188: protected MethodVisitor getNewMethodVisitor(PrintVisitor parent,
189: MemberNode usingMemberNode) {
190: return new MyMethodVisitor(parent, usingMemberNode);
191: }
192:
193: protected class MyMethodVisitor extends PrintVisitor implements
194: MethodVisitor {
195:
196: private final MemberNode usingMemberNode;
197:
198: public MyMethodVisitor(PrintVisitor parent,
199: MemberNode usingMemberNode) {
200: super (parent);
201: this .usingMemberNode = usingMemberNode;
202: }
203:
204: public AnnotationVisitor visitAnnotation(String desc,
205: boolean visible) {
206: if (TRACE) {
207: println("visitAnnotation:");
208: printlnIndent("desc: " + desc);
209: printlnIndent("visible: " + visible);
210: }
211: return null;
212: }
213:
214: public AnnotationVisitor visitAnnotationDefault() {
215: if (TRACE) {
216: println("visitAnnotationDefault:");
217: }
218: return null;
219: }
220:
221: public void visitAttribute(Attribute attr) {
222: if (TRACE) {
223: println("visitAttribute:");
224: printlnIndent("attr: " + attr);
225: }
226: }
227:
228: public void visitCode() {
229: if (TRACE) {
230: println("visitCode:");
231: }
232: }
233:
234: public void visitEnd() {
235: if (TRACE) {
236: println("visitEnd:");
237: }
238: }
239:
240: public void visitFieldInsn(int opcode, String owner,
241: String name, String desc) {
242: if (TRACE) {
243: println("visitFieldInsn:");
244: printlnIndent("opcode: " + opcode);
245: printlnIndent("owner: " + owner);
246: printlnIndent("name: " + name);
247: printlnIndent("desc: " + desc);
248: }
249: if (INDEX) {
250: String className = getClassName(owner);
251: usageGraph.usageField(className, name, desc,
252: usingMemberNode);
253: }
254: }
255:
256: public void visitFrame(int type, int local, Object[] local2,
257: int stack, Object[] stack2) {
258: if (TRACE) {
259: println("visitFrame:");
260: printlnIndent("type: " + type);
261: printlnIndent("local: " + local);
262: printlnIndent("local2: " + asList(local2));
263: printlnIndent("stack: " + stack);
264: printlnIndent("stack2: " + asList(stack2));
265: }
266: }
267:
268: public void visitIincInsn(int var, int increment) {
269: if (TRACE) {
270: println("visitIincInsn:");
271: printlnIndent("var: " + var);
272: printlnIndent("increment: " + increment);
273: }
274: }
275:
276: public void visitInsn(int opcode) {
277: if (TRACE) {
278: println("visitInsn:");
279: printlnIndent("opcode: " + opcode);
280: }
281: }
282:
283: public void visitIntInsn(int opcode, int operand) {
284: if (TRACE) {
285: println("visitIntInsn:");
286: printlnIndent("opcode: " + opcode);
287: printlnIndent("operand: " + operand);
288: }
289: }
290:
291: public void visitJumpInsn(int opcode, Label label) {
292: if (TRACE) {
293: println("visitJumpInsn:");
294: printlnIndent("opcode: " + opcode);
295: printlnIndent("label: " + label);
296: }
297: }
298:
299: public void visitLabel(Label label) {
300: if (TRACE) {
301: println("visitLabel:");
302: printlnIndent("label: " + label);
303: }
304: }
305:
306: public void visitLdcInsn(Object cst) {
307: if (TRACE) {
308: println("visitLdcInsn:");
309: printlnIndent("cst: " + cst);
310: }
311: }
312:
313: public void visitLineNumber(int line, Label start) {
314: if (TRACE) {
315: println("visitLineNumber:");
316: printlnIndent("line: " + line);
317: printlnIndent("start: " + start);
318: }
319: }
320:
321: public void visitLocalVariable(String name, String desc,
322: String signature, Label start, Label end, int index) {
323: if (TRACE) {
324: println("visitLocalVariable:");
325: printlnIndent("name: " + name);
326: printlnIndent("desc: " + desc);
327: printlnIndent("signature: " + signature);
328: printlnIndent("start: " + start);
329: printlnIndent("end: " + end);
330: printlnIndent("index: " + index);
331: }
332: }
333:
334: public void visitLookupSwitchInsn(Label dflt, int[] keys,
335: Label[] labels) {
336: if (TRACE) {
337: println("visitLookupSwitchInsn:");
338: printlnIndent("dflt: " + dflt);
339: printlnIndent("keys: " + asList(keys));
340: printlnIndent("labels: " + asList(labels));
341: }
342: }
343:
344: public void visitMaxs(int maxStack, int maxLocals) {
345: if (TRACE) {
346: println("visitMaxs:");
347: printlnIndent("maxStack: " + maxStack);
348: printlnIndent("maxLocals: " + maxLocals);
349: }
350: }
351:
352: public void visitMethodInsn(int opcode, String owner,
353: String name, String desc) {
354: if (TRACE) {
355: println("visitMethodInsn:");
356: printlnIndent("opcode: " + opcode);
357: printlnIndent("owner: " + owner);
358: printlnIndent("name: " + name);
359: printlnIndent("desc: " + desc);
360: }
361: if (INDEX) {
362: String className = getClassName(owner);
363: usageGraph.usageMethod(className, name, desc,
364: 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(
377: int parameter, String desc, boolean visible) {
378: if (TRACE) {
379: println("visitParameterAnnotation:");
380: printlnIndent("parameter: " + parameter);
381: printlnIndent("desc: " + desc);
382: printlnIndent("visible: " + visible);
383: }
384: return null;
385: }
386:
387: public void visitTableSwitchInsn(int min, int max, Label dflt,
388: Label[] labels) {
389: if (TRACE) {
390: println("visitTableSwitchInsn:");
391: printlnIndent("min: " + min);
392: printlnIndent("max: " + max);
393: printlnIndent("dflt: " + dflt);
394: printlnIndent("labels: " + asList(labels));
395: }
396: }
397:
398: public void visitTryCatchBlock(Label start, Label end,
399: 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: }
|