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 }