Improve type resolution

- Notice the `couldResolve` doesn't guarantee a positive resolution, but still
     manages to kill early some resolver checks
 - `PrimiiveTypeResolver.resolve()` and `VoidTypeResolver.resolve()`
     were the 2nd and 5th most time consuming methods on several profiles
     I ran. This change fixes it.
This commit is contained in:
Juan Martín Sotuyo Dodero
2016-10-13 17:21:59 -03:00
parent b773da1441
commit 382699b766

View File

@@ -67,6 +67,15 @@ public class TypeSet {
* @throws ClassNotFoundException if the class couldn't be found
*/
Class<?> resolve(String name) throws ClassNotFoundException;
/**
* Checks if the given class could be resolved by this resolver.
* Notice, that a resolver's ability to resolve a class does not imply
* that the class will actually be found and resolved.
* @param name the name of the class, might be fully classified or not.
* @return whether the class can be resolved
*/
boolean couldResolve(String name);
}
/**
@@ -76,13 +85,22 @@ public class TypeSet {
public abstract static class AbstractResolver implements Resolver {
/** the class loader. */
protected final PMDASMClassLoader pmdClassLoader;
/**
* Creates a new AbstractResolver that uses the given class loader.
* @param pmdClassLoader the class loader to use
*/
public AbstractResolver(PMDASMClassLoader pmdClassLoader) {
public AbstractResolver(final PMDASMClassLoader pmdClassLoader) {
this.pmdClassLoader = pmdClassLoader;
}
public boolean couldResolve(final String name) {
/*
* Resolvers based on this one, will attempt to load the class from
* the class loader yields no real gain
*/
return true;
}
}
/**
@@ -100,6 +118,7 @@ public class TypeSet {
super(pmdClassLoader);
this.importStmts = importStmts;
}
@Override
public Class<?> resolve(String name) throws ClassNotFoundException {
if (name == null) {
@@ -119,6 +138,7 @@ public class TypeSet {
*/
public static class CurrentPackageResolver extends AbstractResolver {
private String pkg;
/**
* Creates a new {@link CurrentPackageResolver}
* @param pmdClassLoader the class loader to use
@@ -128,6 +148,7 @@ public class TypeSet {
super(pmdClassLoader);
this.pkg = pkg;
}
@Override
public Class<?> resolve(String name) throws ClassNotFoundException {
return pmdClassLoader.loadClass(pkg + '.' + name);
@@ -168,11 +189,18 @@ public class TypeSet {
}
@Override
public Class<?> resolve(String name) throws ClassNotFoundException {
if (name == null) {
throw new ClassNotFoundException();
}
for (String importStmt : importStmts) {
if (importStmt.endsWith("*")) {
try {
String importPkg = importStmt.substring(0, importStmt.indexOf('*') - 1);
return pmdClassLoader.loadClass(importPkg + '.' + name);
String fqClassName = new StringBuilder(importStmt.length() + name.length())
.append(importStmt)
.replace(importStmt.length() - 1, importStmt.length(), name)
.toString();
return pmdClassLoader.loadClass(fqClassName);
} catch (ClassNotFoundException cnfe) {
// ignored as the class could be imported with the next on demand import...
}
@@ -201,6 +229,7 @@ public class TypeSet {
primitiveTypes.put("short", short.class);
primitiveTypes.put("char", char.class);
}
@Override
public Class<?> resolve(String name) throws ClassNotFoundException {
if (!primitiveTypes.containsKey(name)) {
@@ -208,6 +237,11 @@ public class TypeSet {
}
return primitiveTypes.get(name);
}
@Override
public boolean couldResolve(String name) {
return primitiveTypes.containsKey(name);
}
}
/**
@@ -221,6 +255,11 @@ public class TypeSet {
}
throw new ClassNotFoundException(name);
}
@Override
public boolean couldResolve(String name) {
return "void".equals(name);
}
}
/**
@@ -235,6 +274,7 @@ public class TypeSet {
public FullyQualifiedNameResolver(PMDASMClassLoader pmdClassLoader) {
super(pmdClassLoader);
}
@Override
public Class<?> resolve(String name) throws ClassNotFoundException {
if (name == null) {
@@ -281,11 +321,13 @@ public class TypeSet {
buildResolvers();
}
for (Resolver resolver : resolvers) {
try {
return resolver.resolve(name);
} catch (ClassNotFoundException cnfe) {
// ignored, maybe another resolver will find the class
for (final Resolver resolver : resolvers) {
if (resolver.couldResolve(name)) {
try {
return resolver.resolve(name);
} catch (ClassNotFoundException cnfe) {
// ignored, maybe another resolver will find the class
}
}
}