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 }