/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.symboltable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Keeps track of the types encountered in a ASTCompilationUnit
*/
public class TypeSet {
/**
* TODO should Resolver provide a canResolve() and a resolve()?
* Requiring 2 calls seems clunky... but so does this
* throwing an exception for flow control...
*/
public interface Resolver {
Class resolve(String name) throws ClassNotFoundException;
}
public static class ExplicitImportResolver implements Resolver {
private Set importStmts;
public ExplicitImportResolver(Set importStmts) {
this.importStmts = importStmts;
}
public Class resolve(String name) throws ClassNotFoundException {
for (Iterator i = importStmts.iterator(); i.hasNext();) {
String importStmt = (String) i.next();
if (importStmt.endsWith(name)) {
return Class.forName(importStmt);
}
}
throw new ClassNotFoundException("Type " + name + " not found");
}
}
public static class CurrentPackageResolver implements Resolver {
private String pkg;
public CurrentPackageResolver(String pkg) {
this.pkg = pkg;
}
public Class resolve(String name) throws ClassNotFoundException {
return Class.forName(pkg + name);
}
}
// TODO cite the JLS section on implicit imports
public static class ImplicitImportResolver implements Resolver {
public Class resolve(String name) throws ClassNotFoundException {
return Class.forName("java.lang." + name);
}
}
public static class ImportOnDemandResolver implements Resolver {
private Set importStmts;
public ImportOnDemandResolver(Set importStmts) {
this.importStmts = importStmts;
}
public Class resolve(String name) throws ClassNotFoundException {
for (Iterator i = importStmts.iterator(); i.hasNext();) {
String importStmt = (String) i.next();
if (importStmt.endsWith("*")) {
try {
String importPkg = importStmt.substring(0, importStmt.indexOf("*") - 1);
return Class.forName(importPkg + "." + name);
} catch (ClassNotFoundException cnfe) {
}
}
}
throw new ClassNotFoundException("Type " + name + " not found");
}
}
public static class PrimitiveTypeResolver implements Resolver {
private Map primitiveTypes = new HashMap();
public PrimitiveTypeResolver() {
primitiveTypes.put("int", int.class);
primitiveTypes.put("float", float.class);
primitiveTypes.put("double", double.class);
primitiveTypes.put("long", long.class);
primitiveTypes.put("boolean", boolean.class);
primitiveTypes.put("byte", byte.class);
primitiveTypes.put("short", short.class);
primitiveTypes.put("char", char.class);
}
public Class resolve(String name) throws ClassNotFoundException {
if (!primitiveTypes.containsKey(name)) {
throw new ClassNotFoundException();
}
return (Class) primitiveTypes.get(name);
}
}
public static class VoidResolver implements Resolver {
public Class resolve(String name) throws ClassNotFoundException {
if (name.equals("void")) {
return void.class;
}
throw new ClassNotFoundException();
}
}
public static class FullyQualifiedNameResolver implements Resolver {
public Class resolve(String name) throws ClassNotFoundException {
return Class.forName(name);
}
}
private String pkg;
private Set imports = new HashSet();
private List resolvers = new ArrayList();
public void setASTCompilationUnitPackage(String pkg) {
this.pkg = pkg;
}
public String getASTCompilationUnitPackage() {
return pkg;
}
public void addImport(String importString) {
imports.add(importString);
}
public int getImportsCount() {
return imports.size();
}
public Class findClass(String name) throws ClassNotFoundException {
// we don't build the resolvers until now since we first want to get all the imports
if (resolvers.isEmpty()) {
buildResolvers();
}
for (Iterator i = resolvers.iterator(); i.hasNext();) {
Resolver resolver = (Resolver) i.next();
try {
return resolver.resolve(name);
} catch (ClassNotFoundException cnfe) {
}
}
throw new ClassNotFoundException("Type " + name + " not found");
}
private void buildResolvers() {
resolvers.add(new PrimitiveTypeResolver());
resolvers.add(new VoidResolver());
resolvers.add(new ExplicitImportResolver(imports));
resolvers.add(new CurrentPackageResolver(pkg));
resolvers.add(new ImplicitImportResolver());
resolvers.add(new ImportOnDemandResolver(imports));
resolvers.add(new FullyQualifiedNameResolver());
}
}