View Javadoc

1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.lang.java.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 		default:
155 		    // Do nothing
156 		    break;
157 		}
158 	}
159 
160 	public void visitAttribute(Attribute attr) {
161 	}
162 
163 	/*
164 	 * Start visitors
165 	 */
166 
167 	private static class PMDFieldVisitor implements FieldVisitor {
168 
169 		private PMDASMVisitor parent;
170 
171 		public PMDFieldVisitor(PMDASMVisitor visitor) {
172 			parent = visitor;
173 		}
174 
175 		public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
176 			parent.addType(Type.getType(desc));
177 			return parent.annotationVisitor;
178 		}
179 
180 		public void visitAttribute(Attribute attr) {
181 		}
182 
183 		public void visitEnd() {
184 		}
185 	}
186 
187 	private static class PMDAnnotationVisitor implements AnnotationVisitor {
188 		private PMDASMVisitor parent;
189 
190 		public PMDAnnotationVisitor(PMDASMVisitor visitor) {
191 			parent = visitor;
192 		}
193 
194 		public AnnotationVisitor visitAnnotation(String name, String desc) {
195 			parent.addType(Type.getType(desc));
196 			return this;
197 		}
198 
199 		public void visitEnum(String name, String desc, String value) {
200 			parent.addType(Type.getType(desc));
201 		}
202 
203 		public AnnotationVisitor visitArray(String name) {
204 			return this;
205 		}
206 
207 		public void visitEnd() {
208 		}
209 
210 		public void visit(String name, Object value) {
211 			if (value instanceof Type) {
212 				parent.addType((Type) value);
213 			}
214 		}
215 	}
216 
217 	private static class PMDSignatureVisitor implements SignatureVisitor {
218 		private PMDASMVisitor parent;
219 
220 		public PMDSignatureVisitor(PMDASMVisitor visitor) {
221 			this.parent = visitor;
222 		}
223 
224 		public void visitFormalTypeParameter(String name) {
225 		}
226 
227 		public SignatureVisitor visitClassBound() {
228 			return this;
229 		}
230 
231 		public SignatureVisitor visitInterfaceBound() {
232 			return this;
233 		}
234 
235 		public SignatureVisitor visitSuperclass() {
236 			return this;
237 		}
238 
239 		public SignatureVisitor visitInterface() {
240 			return this;
241 		}
242 
243 		public SignatureVisitor visitParameterType() {
244 			return this;
245 		}
246 
247 		public SignatureVisitor visitReturnType() {
248 			return this;
249 		}
250 
251 		public SignatureVisitor visitExceptionType() {
252 			return this;
253 		}
254 
255 		public void visitBaseType(char descriptor) {
256 		}
257 
258 		public void visitTypeVariable(String name) {
259 		}
260 
261 		public SignatureVisitor visitArrayType() {
262 			return this;
263 		}
264 
265 		public void visitClassType(String name) {
266 			parent.parseClassName(name);
267 		}
268 
269 		public void visitInnerClassType(String name) {
270 			parent.parseClassName(name);
271 		}
272 
273 		public void visitTypeArgument() {
274 		}
275 
276 		public SignatureVisitor visitTypeArgument(char wildcard) {
277 			return this;
278 		}
279 
280 		public void visitEnd() {
281 		}
282 	}
283 
284 	private static class PMDMethodVisitor implements MethodVisitor {
285 		private PMDASMVisitor parent;
286 
287 		public PMDMethodVisitor(PMDASMVisitor visitor) {
288 			parent = visitor;
289 		}
290 
291 		public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {
292 			parent.addType(Type.getType(desc));
293 			return parent.annotationVisitor;
294 		}
295 
296 		public AnnotationVisitor visitAnnotation(String name, String desc) {
297 			parent.addType(Type.getType(desc));
298 			return parent.annotationVisitor;
299 		}
300 
301 		public void visitTypeInsn(int opcode, String desc) {
302 			if (desc.charAt(0) == '[') {
303 				parent.addType(Type.getType(desc));
304 			} else {
305 				parent.parseClassName(desc);
306 			}
307 		}
308 
309 		public void visitFieldInsn(int opcode, String owner, String name, String desc) {
310 			parent.parseClassName(owner);
311 			parent.addType(Type.getType(desc));
312 		}
313 
314 		public void visitMethodInsn(int opcode, String owner, String name, String desc) {
315 			parent.parseClassName(owner);
316 			parent.addMethodDesc(desc);
317 		}
318 
319 	    /**
320 	     * the constant to be loaded on the stack. This parameter must be a non null
321 	     * Integer, a Float, a Long, a Double a String (or a Type for .class
322 	     * constants, for classes whose version is 49.0 or more).
323 	     *
324 	     * @see org.objectweb.asm.MethodVisitor#visitLdcInsn(java.lang.Object)
325 	     */
326 	    public void visitLdcInsn(Object cst) {
327 	        if (cst instanceof Type) {
328 	        	parent.addType((Type) cst);
329 	        } else if (cst instanceof String) {
330 	            parent.parseClassName((String) cst);
331 	        }
332 	    }
333 		public void visitMultiANewArrayInsn(String desc, int dims) {
334 			parent.addType(Type.getType(desc));
335 		}
336 
337 		public void visitLocalVariable(String name, String desc, String sig, Label start, Label end, int index) {
338 			parent.extractSignature(sig);
339 		}
340 
341 		public void visitCode() {
342 		}
343 
344 		public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
345 		}
346 
347 		public void visitInsn(int opcode) {
348 		}
349 
350 		public void visitIntInsn(int opcode, int operand) {
351 		}
352 
353 		public void visitVarInsn(int opcode, int var) {
354 		}
355 
356 		public void visitJumpInsn(int opcode, Label label) {
357 		}
358 
359 		public void visitLabel(Label label) {
360 		}
361 
362 		public void visitIincInsn(int var, int increment) {
363 		}
364 
365 		public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels) {
366 		}
367 
368 		public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
369 		}
370 
371 		public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
372 			parent.parseClassName(type);
373 		}
374 
375 		public void visitLineNumber(int line, Label start) {
376 		}
377 
378 		public void visitMaxs(int maxStack, int maxLocals) {
379 		}
380 
381 		public AnnotationVisitor visitAnnotationDefault() {
382 			return parent.annotationVisitor;
383 		}
384 
385 		public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
386 			parent.addType(Type.getType(desc));
387 			return parent.annotationVisitor;
388 		}
389 
390 		public void visitEnd() {
391 		}
392 
393 		public void visitAttribute(Attribute attr) {
394 		}
395 
396 	}
397 }