View Javadoc

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  			//TODO I don't think the first one, with Class$Inner is needed - come back and check
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  	/* Start ClassVisitor implementations */
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 	 * Start visitors
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 }