View Javadoc

1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.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      /**
20       * TODO should Resolver provide a canResolve() and a resolve()?
21       * Requiring 2 calls seems clunky... but so does this
22       * throwing an exception for flow control...
23       */
24      public interface Resolver {
25          Class resolve(String name) throws ClassNotFoundException;
26      }
27  
28      public static class ExplicitImportResolver implements Resolver {
29          private Set<String> importStmts;
30  
31          public ExplicitImportResolver(Set<String> importStmts) {
32              this.importStmts = importStmts;
33          }
34  
35          public Class resolve(String name) throws ClassNotFoundException {
36              for (String importStmt: importStmts) {
37                  if (importStmt.endsWith(name)) {
38                      return Class.forName(importStmt);
39                  }
40              }
41              throw new ClassNotFoundException("Type " + name + " not found");
42          }
43      }
44  
45      public static class CurrentPackageResolver implements Resolver {
46          private String pkg;
47  
48          public CurrentPackageResolver(String pkg) {
49              this.pkg = pkg;
50          }
51  
52          public Class resolve(String name) throws ClassNotFoundException {
53              return Class.forName(pkg + name);
54          }
55      }
56  
57      // TODO cite the JLS section on implicit imports
58      public static class ImplicitImportResolver implements Resolver {
59          public Class resolve(String name) throws ClassNotFoundException {
60              return Class.forName("java.lang." + name);
61          }
62      }
63  
64      public static class ImportOnDemandResolver implements Resolver {
65          private Set<String> importStmts;
66  
67          public ImportOnDemandResolver(Set<String> importStmts) {
68              this.importStmts = importStmts;
69          }
70  
71          public Class resolve(String name) throws ClassNotFoundException {
72              for (String importStmt: importStmts) {
73                  if (importStmt.endsWith("*")) {
74                      try {
75                          String importPkg = importStmt.substring(0, importStmt.indexOf('*') - 1);
76                          return Class.forName(importPkg + '.' + name);
77                      } catch (ClassNotFoundException cnfe) {
78                      }
79                  }
80              }
81              throw new ClassNotFoundException("Type " + name + " not found");
82          }
83      }
84  
85      public static class PrimitiveTypeResolver implements Resolver {
86          private Map<String, Class> primitiveTypes = new HashMap<String, Class>();
87  
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 }