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.symboltable;
5   
6   import java.util.ArrayList;
7   import java.util.HashMap;
8   import java.util.HashSet;
9   import java.util.List;
10  import java.util.Map;
11  import java.util.Set;
12  
13  /**
14   * Keeps track of the types encountered in a ASTCompilationUnit
15   */
16  public class TypeSet {
17  
18      /**
19       * TODO should Resolver provide a canResolve() and a resolve()?
20       * Requiring 2 calls seems clunky... but so does this
21       * throwing an exception for flow control...
22       */
23      public interface Resolver {
24  	Class<?> resolve(String name) throws ClassNotFoundException;
25      }
26  
27      public static class ExplicitImportResolver implements Resolver {
28  	private Set<String> importStmts;
29  
30  	public ExplicitImportResolver(Set<String> importStmts) {
31  	    this.importStmts = importStmts;
32  	}
33  
34  	public Class<?> resolve(String name) throws ClassNotFoundException {
35  	    for (String importStmt : importStmts) {
36  		if (importStmt.endsWith(name)) {
37  		    return Class.forName(importStmt);
38  		}
39  	    }
40  	    throw new ClassNotFoundException("Type " + name + " not found");
41  	}
42      }
43  
44      public static class CurrentPackageResolver implements Resolver {
45  	private String pkg;
46  
47  	public CurrentPackageResolver(String pkg) {
48  	    this.pkg = pkg;
49  	}
50  
51  	public Class<?> resolve(String name) throws ClassNotFoundException {
52  	    return Class.forName(pkg + name);
53  	}
54      }
55  
56      // TODO cite the JLS section on implicit imports
57      public static class ImplicitImportResolver implements Resolver {
58  	public Class<?> resolve(String name) throws ClassNotFoundException {
59  	    return Class.forName("java.lang." + name);
60  	}
61      }
62  
63      public static class ImportOnDemandResolver implements Resolver {
64  	private Set<String> importStmts;
65  
66  	public ImportOnDemandResolver(Set<String> importStmts) {
67  	    this.importStmts = importStmts;
68  	}
69  
70  	public Class<?> resolve(String name) throws ClassNotFoundException {
71  	    for (String importStmt : importStmts) {
72  		if (importStmt.endsWith("*")) {
73  		    try {
74  			String importPkg = importStmt.substring(0, importStmt.indexOf('*') - 1);
75  			return Class.forName(importPkg + '.' + name);
76  		    } catch (ClassNotFoundException cnfe) {
77  		    }
78  		}
79  	    }
80  	    throw new ClassNotFoundException("Type " + name + " not found");
81  	}
82      }
83  
84      public static class PrimitiveTypeResolver implements Resolver {
85  	private Map<String, Class<?>> primitiveTypes = new HashMap<String, Class<?>>();
86  
87  	@SuppressWarnings("PMD.AvoidUsingShortType")
88  	public PrimitiveTypeResolver() {
89  	    primitiveTypes.put("int", int.class);
90  	    primitiveTypes.put("float", float.class);
91  	    primitiveTypes.put("double", double.class);
92  	    primitiveTypes.put("long", long.class);
93  	    primitiveTypes.put("boolean", boolean.class);
94  	    primitiveTypes.put("byte", byte.class);
95  	    primitiveTypes.put("short", short.class);
96  	    primitiveTypes.put("char", char.class);
97  	}
98  
99  	public Class<?> resolve(String name) throws ClassNotFoundException {
100 	    if (!primitiveTypes.containsKey(name)) {
101 		throw new ClassNotFoundException();
102 	    }
103 	    return primitiveTypes.get(name);
104 	}
105     }
106 
107     public static class VoidResolver implements Resolver {
108 	public Class<?> resolve(String name) throws ClassNotFoundException {
109 	    if (name.equals("void")) {
110 		return void.class;
111 	    }
112 	    throw new ClassNotFoundException();
113 	}
114     }
115 
116     public static class FullyQualifiedNameResolver implements Resolver {
117 	public Class<?> resolve(String name) throws ClassNotFoundException {
118 	    return Class.forName(name);
119 	}
120     }
121 
122     private String pkg;
123     private Set<String> imports = new HashSet<String>();
124     private List<Resolver> resolvers = new ArrayList<Resolver>();
125 
126     public void setASTCompilationUnitPackage(String pkg) {
127 	this.pkg = pkg;
128     }
129 
130     public String getASTCompilationUnitPackage() {
131 	return pkg;
132     }
133 
134     public void addImport(String importString) {
135 	imports.add(importString);
136     }
137 
138     public int getImportsCount() {
139 	return imports.size();
140     }
141 
142     public Class<?> findClass(String name) throws ClassNotFoundException {
143 	// we don't build the resolvers until now since we first want to get all the imports
144 	if (resolvers.isEmpty()) {
145 	    buildResolvers();
146 	}
147 
148 	for (Resolver resolver : resolvers) {
149 	    try {
150 		return resolver.resolve(name);
151 	    } catch (ClassNotFoundException cnfe) {
152 	    }
153 	}
154 
155 	throw new ClassNotFoundException("Type " + name + " not found");
156     }
157 
158     private void buildResolvers() {
159 	resolvers.add(new PrimitiveTypeResolver());
160 	resolvers.add(new VoidResolver());
161 	resolvers.add(new ExplicitImportResolver(imports));
162 	resolvers.add(new CurrentPackageResolver(pkg));
163 	resolvers.add(new ImplicitImportResolver());
164 	resolvers.add(new ImportOnDemandResolver(imports));
165 	resolvers.add(new FullyQualifiedNameResolver());
166     }
167 
168 }