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.Opcodes;
13  import org.objectweb.asm.Type;
14  import org.objectweb.asm.signature.SignatureReader;
15  import org.objectweb.asm.signature.SignatureVisitor;
16  
17  import java.util.ArrayList;
18  import java.util.HashMap;
19  import java.util.List;
20  import java.util.Map;
21  
22  public class PMDASMVisitor extends ClassVisitor {
23  
24      public PMDASMVisitor() {
25          super(Opcodes.ASM4);
26      }
27  
28      private Map<String, String> packages = new HashMap<String, String>();
29  
30  	private AnnotationVisitor annotationVisitor = new PMDAnnotationVisitor(this);
31  
32  	private FieldVisitor fieldVisitor = new PMDFieldVisitor(this);
33  
34  	private SignatureVisitor sigVisitor = new PMDSignatureVisitor(this);
35  
36  	private MethodVisitor methodVisitor = new PMDMethodVisitor(this);
37  
38  	public List<String> innerClasses;
39  
40  	public Map<String, String> getPackages() {
41  		return packages;
42  	}
43  
44  	public List<String> getInnerClasses() {
45  		return innerClasses;
46  	}
47  
48  	private String parseClassName(String name) {
49  		if (name == null) {
50  			return null;
51  		}
52  
53  		String className = name;
54  		int n = name.lastIndexOf('/');
55  		if (n > -1) {
56  			className = name.substring(n + 1);
57  		}
58  		name = name.replace('/', '.');
59  		packages.put(className, name);
60  		n = className.indexOf('$');
61  		if (n > -1) {
62  			//TODO I don't think the first one, with Class$Inner is needed - come back and check
63  			packages.put(className.substring(n + 1), name);
64  			packages.put(className.replace('$', '.'), name);
65  		}
66  
67  		return name;
68  	}
69  
70  	private void parseClassName(String[] names) {
71  		if (names != null) {
72  			for (String s : names) {
73  				parseClassName(s);
74  			}
75  		}
76  	}
77  
78  	private void extractSignature(String sig) {
79  		if (sig != null) {
80  			new SignatureReader(sig).accept(sigVisitor);
81  		}
82  	}
83  
84  	/* Start ClassVisitor implementations */
85  
86  	public void visit(int version, int access, String name, String sig, String superName, String[] interfaces) {
87  		parseClassName(name);
88  		parseClassName(interfaces);
89  		if (sig != null) {
90  			extractSignature(sig);
91  		}
92  	}
93  
94  	public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
95  		addType(Type.getType(desc));
96  		return annotationVisitor;
97  	}
98  
99  	public FieldVisitor visitField(int access, String name, String desc, String sig, Object value) {
100 		if (sig != null) {
101 			extractSignature(sig);
102 		}
103 
104 		addType(Type.getType(desc));
105 		if (value instanceof Type) {
106 			addType((Type) value);
107 		}
108 		return fieldVisitor;
109 	}
110 
111 	public MethodVisitor visitMethod(int access, String name, String desc, String sig, String[] exceptions) {
112 		if (sig != null) {
113 			extractSignature(sig);
114 		}
115 		addMethodDesc(desc);
116 		parseClassName(exceptions);
117 		return methodVisitor;
118 	}
119 
120 	public void visitSource(String source, String debug) {
121 	}
122 
123 	public void visitInnerClass(String name, String outerName, String innerName, int access) {
124 		if (innerClasses == null) {
125 			innerClasses = new ArrayList<String>();
126 		}
127 		if (!innerClasses.contains(name.replace('/', '.'))) {
128 			innerClasses.add(name.replace('/', '.'));
129 		}
130 		packages.put(innerName, name.replace('/', '.'));
131 	}
132 
133 	public void visitOuterClass(String owner, String name, String desc) {
134 	}
135 
136 	public void visitEnd() {
137 	}
138 
139 	private void addMethodDesc(String desc) {
140 		addTypes(desc);
141 		addType(Type.getReturnType(desc));
142 	}
143 
144 	private void addTypes(String desc) {
145 		Type[] types = Type.getArgumentTypes(desc);
146 		for (Type type : types) {
147 			addType(type);
148 		}
149 	}
150 
151 	private void addType(Type t) {
152 		switch (t.getSort()) {
153 		case Type.ARRAY:
154 			addType(t.getElementType());
155 			break;
156 		case Type.OBJECT:
157 			parseClassName(t.getClassName().replace('.', '/'));
158 			break;
159 		default:
160 		    // Do nothing
161 		    break;
162 		}
163 	}
164 
165 	public void visitAttribute(Attribute attr) {
166 	}
167 
168 	/*
169 	 * Start visitors
170 	 */
171 
172 	private static class PMDFieldVisitor extends FieldVisitor {
173 
174 		private PMDASMVisitor parent;
175 
176 		public PMDFieldVisitor(PMDASMVisitor visitor) {
177 		    super(Opcodes.ASM4);
178 			parent = visitor;
179 		}
180 
181 		public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
182 			parent.addType(Type.getType(desc));
183 			return parent.annotationVisitor;
184 		}
185 
186 		public void visitAttribute(Attribute attr) {
187 		}
188 
189 		public void visitEnd() {
190 		}
191 	}
192 
193 	private static class PMDAnnotationVisitor extends AnnotationVisitor {
194 		private PMDASMVisitor parent;
195 
196 		public PMDAnnotationVisitor(PMDASMVisitor visitor) {
197             super(Opcodes.ASM4);
198 			parent = visitor;
199 		}
200 
201 		public AnnotationVisitor visitAnnotation(String name, String desc) {
202 			parent.addType(Type.getType(desc));
203 			return this;
204 		}
205 
206 		public void visitEnum(String name, String desc, String value) {
207 			parent.addType(Type.getType(desc));
208 		}
209 
210 		public AnnotationVisitor visitArray(String name) {
211 			return this;
212 		}
213 
214 		public void visitEnd() {
215 		}
216 
217 		public void visit(String name, Object value) {
218 			if (value instanceof Type) {
219 				parent.addType((Type) value);
220 			}
221 		}
222 	}
223 
224 	private static class PMDSignatureVisitor extends SignatureVisitor {
225 		private PMDASMVisitor parent;
226 
227 		public PMDSignatureVisitor(PMDASMVisitor visitor) {
228             super(Opcodes.ASM4);
229 			this.parent = visitor;
230 		}
231 
232 		public void visitFormalTypeParameter(String name) {
233 		}
234 
235 		public SignatureVisitor visitClassBound() {
236 			return this;
237 		}
238 
239 		public SignatureVisitor visitInterfaceBound() {
240 			return this;
241 		}
242 
243 		public SignatureVisitor visitSuperclass() {
244 			return this;
245 		}
246 
247 		public SignatureVisitor visitInterface() {
248 			return this;
249 		}
250 
251 		public SignatureVisitor visitParameterType() {
252 			return this;
253 		}
254 
255 		public SignatureVisitor visitReturnType() {
256 			return this;
257 		}
258 
259 		public SignatureVisitor visitExceptionType() {
260 			return this;
261 		}
262 
263 		public void visitBaseType(char descriptor) {
264 		}
265 
266 		public void visitTypeVariable(String name) {
267 		}
268 
269 		public SignatureVisitor visitArrayType() {
270 			return this;
271 		}
272 
273 		public void visitClassType(String name) {
274 			parent.parseClassName(name);
275 		}
276 
277 		public void visitInnerClassType(String name) {
278 			parent.parseClassName(name);
279 		}
280 
281 		public void visitTypeArgument() {
282 		}
283 
284 		public SignatureVisitor visitTypeArgument(char wildcard) {
285 			return this;
286 		}
287 
288 		public void visitEnd() {
289 		}
290 	}
291 
292 	private static class PMDMethodVisitor extends MethodVisitor {
293 		private PMDASMVisitor parent;
294 
295 		public PMDMethodVisitor(PMDASMVisitor visitor) {
296             super(Opcodes.ASM4);
297 			parent = visitor;
298 		}
299 
300 		public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {
301 			parent.addType(Type.getType(desc));
302 			return parent.annotationVisitor;
303 		}
304 
305 		public AnnotationVisitor visitAnnotation(String name, String desc) {
306 			parent.addType(Type.getType(desc));
307 			return parent.annotationVisitor;
308 		}
309 
310 		public void visitTypeInsn(int opcode, String desc) {
311 			if (desc.charAt(0) == '[') {
312 				parent.addType(Type.getType(desc));
313 			} else {
314 				parent.parseClassName(desc);
315 			}
316 		}
317 
318 		public void visitFieldInsn(int opcode, String owner, String name, String desc) {
319 			parent.parseClassName(owner);
320 			parent.addType(Type.getType(desc));
321 		}
322 
323 		public void visitMethodInsn(int opcode, String owner, String name, String desc) {
324 			parent.parseClassName(owner);
325 			parent.addMethodDesc(desc);
326 		}
327 
328 	    /**
329 	     * the constant to be loaded on the stack. This parameter must be a non null
330 	     * Integer, a Float, a Long, a Double a String (or a Type for .class
331 	     * constants, for classes whose version is 49.0 or more).
332 	     *
333 	     * @see org.objectweb.asm.MethodVisitor#visitLdcInsn(java.lang.Object)
334 	     */
335 	    public void visitLdcInsn(Object cst) {
336 	        if (cst instanceof Type) {
337 	        	parent.addType((Type) cst);
338 	        } else if (cst instanceof String) {
339 	            parent.parseClassName((String) cst);
340 	        }
341 	    }
342 		public void visitMultiANewArrayInsn(String desc, int dims) {
343 			parent.addType(Type.getType(desc));
344 		}
345 
346 		public void visitLocalVariable(String name, String desc, String sig, Label start, Label end, int index) {
347 			parent.extractSignature(sig);
348 		}
349 
350 		public void visitCode() {
351 		}
352 
353 		public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
354 		}
355 
356 		public void visitInsn(int opcode) {
357 		}
358 
359 		public void visitIntInsn(int opcode, int operand) {
360 		}
361 
362 		public void visitVarInsn(int opcode, int var) {
363 		}
364 
365 		public void visitJumpInsn(int opcode, Label label) {
366 		}
367 
368 		public void visitLabel(Label label) {
369 		}
370 
371 		public void visitIincInsn(int var, int increment) {
372 		}
373 
374 		public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels) {
375 		}
376 
377 		public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
378 		}
379 
380 		public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
381 			parent.parseClassName(type);
382 		}
383 
384 		public void visitLineNumber(int line, Label start) {
385 		}
386 
387 		public void visitMaxs(int maxStack, int maxLocals) {
388 		}
389 
390 		public AnnotationVisitor visitAnnotationDefault() {
391 			return parent.annotationVisitor;
392 		}
393 
394 		public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
395 			parent.addType(Type.getType(desc));
396 			return parent.annotationVisitor;
397 		}
398 
399 		public void visitEnd() {
400 		}
401 
402 		public void visitAttribute(Attribute attr) {
403 		}
404 
405 	}
406 }