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 }