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 }