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 }