View Javadoc

    1   /***
    2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
    3    */
    4   package net.sourceforge.pmd.typeresolution;
    5
    6   import net.sourceforge.pmd.ast.ASTClassOrInterfaceDeclaration;
    7   import net.sourceforge.pmd.ast.ASTClassOrInterfaceType;
    8   import net.sourceforge.pmd.ast.ASTCompilationUnit;
    9   import net.sourceforge.pmd.ast.ASTImportDeclaration;
    10  import net.sourceforge.pmd.ast.ASTName;
    11  import net.sourceforge.pmd.ast.ASTPackageDeclaration;
    12  import net.sourceforge.pmd.ast.JavaParserVisitorAdapter;
    13
    14  import java.util.Collections;
    15  import java.util.HashMap;
    16  import java.util.Iterator;
    17  import java.util.List;
    18  import java.util.Map;
    19
    20  public class ClassTypeResolver extends JavaParserVisitorAdapter {
    21
    22  	private static Map myPrimitiveTypes;
    23
    24  	private static PMDASMClassLoader pmdClassLoader = new PMDASMClassLoader();
    25
    26  	static {
    27  		Map thePrimitiveTypes = new HashMap();
    28  		thePrimitiveTypes.put("short", Short.TYPE);
    29  		thePrimitiveTypes.put("byte", Byte.TYPE);
    30  		thePrimitiveTypes.put("char", Character.TYPE);
    31  		thePrimitiveTypes.put("int", Integer.TYPE);
    32  		thePrimitiveTypes.put("long", Long.TYPE);
    33  		thePrimitiveTypes.put("float", Float.TYPE);
    34  		thePrimitiveTypes.put("double", Double.TYPE);
    35  		thePrimitiveTypes.put("boolean", Boolean.TYPE);
    36  		thePrimitiveTypes.put("void", Void.TYPE);
    37  		myPrimitiveTypes = Collections.unmodifiableMap(thePrimitiveTypes);
    38  	}
    39
    40  	private Map importedClasses;
    41
    42  	private String className;
    43
    44  	public Object visit(ASTCompilationUnit node, Object data) {
    45  		try {
    46  			populateClassName(node);
    47  		} catch (ClassNotFoundException e) {
    48  			populateImports(node);
    49  		}
    50  		return super.visit(node, data);
    51  	}
    52
    53  	/***
    54  	 * If the outer class wasn't found then we'll get in here
    55  	 *
    56  	 * @param node
    57  	 */
    58  	private void populateImports(ASTCompilationUnit node) {
    59  		List theImportDeclarations = node.findChildrenOfType(ASTImportDeclaration.class);
    60  		importedClasses = new HashMap();
    61
    62  		// go through the imports
    63  		for (Iterator anIterator = theImportDeclarations.iterator(); anIterator.hasNext();) {
    64  			ASTImportDeclaration anImportDeclaration = (ASTImportDeclaration) anIterator.next();
    65  			if (!anImportDeclaration.isImportOnDemand()) {
    66  				String strPackage = anImportDeclaration.getPackageName();
    67  				String strName = anImportDeclaration.getImportedName();
    68  				importedClasses.put(strName, strName);
    69  				importedClasses.put(strName.substring(strPackage.length() + 1), strName);
    70  			}
    71  		}
    72
    73  		importedClasses.put("String", "java.lang.String");
    74  		importedClasses.put("Object", "java.lang.Object");
    75  	}
    76
    77  	private void populateClassName(ASTCompilationUnit node) throws ClassNotFoundException {
    78  		ASTClassOrInterfaceDeclaration decl = (ASTClassOrInterfaceDeclaration) node
    79  				.getFirstChildOfType(ASTClassOrInterfaceDeclaration.class);
    80  		if (decl != null) {
    81  			ASTPackageDeclaration pkgDecl = (ASTPackageDeclaration) node
    82  					.getFirstChildOfType(ASTPackageDeclaration.class);
    83  			className = pkgDecl == null ? decl.getImage() : ((ASTName) pkgDecl.jjtGetChild(0)).getImage() + "."
    84  					+ decl.getImage();
    85  			pmdClassLoader.loadClass(className);
    86  			importedClasses = pmdClassLoader.getImportedClasses(className);
    87  		}
    88  	}
    89
    90  	public Object visit(ASTClassOrInterfaceType node, Object data) {
    91
    92  		String className = node.getImage();
    93  		String qualifiedName = className;
    94  		Class myType = (Class) myPrimitiveTypes.get(className);
    95  		if (myType == null && importedClasses != null) {
    96  			if (importedClasses.containsKey(className)) {
    97  				qualifiedName = (String) importedClasses.get(className);
    98  			} else if (importedClasses.containsValue(className)) {
    99  				qualifiedName = className;
    100 			}
    101 			if (qualifiedName != null) {
    102 				try {
    103 					/*
    104 					 * TODO - the map right now contains just class names. if we use a map of
    105 					 * classname/class then we don't have to hit the class loader for every type -
    106 					 * much faster
    107 					 */
    108 					myType = pmdClassLoader.loadClass(qualifiedName);
    109 				} catch (ClassNotFoundException e) {
    110 					//@TODO What should we do if it's not found?
    111 				}
    112 			}
    113 		}
    114 		if (myType != null) {
    115 			node.setType(myType);
    116 		}
    117 		return data;
    118 	}
    119 }