From 382699b766032efb6903ec149d3d25cf3c8ca6bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Thu, 13 Oct 2016 17:21:59 -0300 Subject: [PATCH 1/8] 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. --- .../pmd/lang/java/symboltable/TypeSet.java | 58 ++++++++++++++++--- 1 file changed, 50 insertions(+), 8 deletions(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/TypeSet.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/TypeSet.java index 6be744d5db..a4f4fac903 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/TypeSet.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/TypeSet.java @@ -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 + } } } From d8344b067202c648e624bcff4c72161aa22ecf04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Thu, 13 Oct 2016 17:47:27 -0300 Subject: [PATCH 2/8] Simplify varargs detection - Make use of our Java knowledge when analyzing Java code --- .../lang/java/symboltable/MethodNameDeclaration.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/MethodNameDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/MethodNameDeclaration.java index 2561bad214..b1d0a6e1c1 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/MethodNameDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/MethodNameDeclaration.java @@ -22,13 +22,13 @@ public class MethodNameDeclaration extends AbstractNameDeclaration { public boolean isVarargs() { ASTFormalParameters params = (ASTFormalParameters) node.jjtGetChild(0); - for (int i = 0; i < ((ASTMethodDeclarator) node).getParameterCount(); i++) { - ASTFormalParameter p = (ASTFormalParameter) params.jjtGetChild(i); - if (p.isVarargs()) { - return true; - } + if (params.getParameterCount() == 0) { + return false; } - return false; + + // If it's a varargs, it HAS to be the last parameter + ASTFormalParameter p = (ASTFormalParameter) params.jjtGetChild(params.getParameterCount() - 1); + return p.isVarargs(); } public ASTMethodDeclarator getMethodNameDeclaratorNode() { From 09ac963709948f3a37fd2dbf52423a11a8f57ba6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Thu, 13 Oct 2016 20:40:46 -0300 Subject: [PATCH 3/8] Improve SymbolTable times further - Expand hashCode calculation for `MethodNameDeclaration` to avoid collisions when overloading. - Also make sure `builtInMethodDeclaration` provides a complete syntax tree to avoid NPE when calling `hashCode` or `equals` --- .../pmd/lang/java/symboltable/ClassScope.java | 39 +++++++++++++++++-- .../symboltable/MethodNameDeclaration.java | 25 ++++++++++-- 2 files changed, 57 insertions(+), 7 deletions(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/ClassScope.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/ClassScope.java index 65299a3fce..f9e0a283c4 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/ClassScope.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/ClassScope.java @@ -28,6 +28,8 @@ import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator; import net.sourceforge.pmd.lang.java.ast.ASTName; import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix; +import net.sourceforge.pmd.lang.java.ast.ASTPrimitiveType; +import net.sourceforge.pmd.lang.java.ast.ASTReferenceType; import net.sourceforge.pmd.lang.java.ast.ASTType; import net.sourceforge.pmd.lang.java.ast.ASTTypeParameter; import net.sourceforge.pmd.lang.java.ast.ASTTypeParameters; @@ -43,6 +45,20 @@ import net.sourceforge.pmd.lang.symboltable.Scope; */ public class ClassScope extends AbstractJavaScope { + private static final Set PRIMITIVE_TYPES; + + static { + PRIMITIVE_TYPES = new HashSet<>(); + PRIMITIVE_TYPES.add("boolean"); + PRIMITIVE_TYPES.add("char"); + PRIMITIVE_TYPES.add("byte"); + PRIMITIVE_TYPES.add("short"); + PRIMITIVE_TYPES.add("int"); + PRIMITIVE_TYPES.add("long"); + PRIMITIVE_TYPES.add("float"); + PRIMITIVE_TYPES.add("double"); + } + // FIXME - this breaks given sufficiently nested code private static ThreadLocal anonymousInnerClassCounter = new ThreadLocal() { protected Integer initialValue() { @@ -206,7 +222,7 @@ public class ClassScope extends AbstractJavaScope { } } if (isEnum && "valueOf".equals(occurrence.getImage())) { - result.add(createBuiltInMethodDeclaration("valueOf", 1)); + result.add(createBuiltInMethodDeclaration("valueOf", "String")); } return result; } @@ -253,7 +269,7 @@ public class ClassScope extends AbstractJavaScope { * @param parameterCount the parameter count of the method * @return a method name declaration */ - private MethodNameDeclaration createBuiltInMethodDeclaration(final String methodName, final int parameterCount) { + private MethodNameDeclaration createBuiltInMethodDeclaration(final String methodName, final String... parameterTypes) { ASTMethodDeclaration methodDeclaration = new ASTMethodDeclaration(JavaParserTreeConstants.JJTMETHODDECLARATION); methodDeclaration.setPublic(true); methodDeclaration.setScope(this); @@ -270,7 +286,7 @@ public class ClassScope extends AbstractJavaScope { methodDeclarator.jjtAddChild(formalParameters, 0); formalParameters.jjtSetParent(methodDeclarator); - for (int i = 0; i < parameterCount; i++) { + for (int i = 0; i < parameterTypes.length; i++) { ASTFormalParameter formalParameter = new ASTFormalParameter(JavaParserTreeConstants.JJTFORMALPARAMETER); formalParameters.jjtAddChild(formalParameter, i); formalParameter.jjtSetParent(formalParameters); @@ -282,6 +298,23 @@ public class ClassScope extends AbstractJavaScope { variableDeclaratorId.setImage("arg" + i); formalParameter.jjtAddChild(variableDeclaratorId, 1); variableDeclaratorId.jjtSetParent(formalParameter); + + if (PRIMITIVE_TYPES.contains(parameterTypes[i])) { + ASTPrimitiveType primitiveType = new ASTPrimitiveType(JavaParserTreeConstants.JJTPRIMITIVETYPE); + primitiveType.setImage(parameterTypes[i]); + type.jjtAddChild(primitiveType, 0); + primitiveType.jjtSetParent(type); + } else { + ASTReferenceType referenceType = new ASTReferenceType(JavaParserTreeConstants.JJTREFERENCETYPE); + type.jjtAddChild(referenceType, 0); + referenceType.jjtSetParent(type); + + // TODO : this could actually be a primitive array... + ASTClassOrInterfaceType coiType = new ASTClassOrInterfaceType(JavaParserTreeConstants.JJTCLASSORINTERFACETYPE); + coiType.setImage(parameterTypes[i]); + referenceType.jjtAddChild(coiType, 0); + coiType.jjtSetParent(referenceType); + } } MethodNameDeclaration mnd = new MethodNameDeclaration(methodDeclarator); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/MethodNameDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/MethodNameDeclaration.java index b1d0a6e1c1..e5708081e7 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/MethodNameDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/MethodNameDeclaration.java @@ -36,7 +36,7 @@ public class MethodNameDeclaration extends AbstractNameDeclaration { } public String getParameterDisplaySignature() { - StringBuilder sb = new StringBuilder("("); + StringBuilder sb = new StringBuilder("("); ASTFormalParameters params = (ASTFormalParameters) node.jjtGetChild(0); // TODO - this can be optimized - add [0] then ,[n] in a loop. // no need to trim at the end @@ -44,7 +44,7 @@ public class MethodNameDeclaration extends AbstractNameDeclaration { ASTFormalParameter p = (ASTFormalParameter) params.jjtGetChild(i); sb.append(p.getTypeNode().getTypeImage()); if (p.isVarargs()) { - sb.append("..."); + sb.append("..."); } sb.append(','); } @@ -82,7 +82,7 @@ public class MethodNameDeclaration extends AbstractNameDeclaration { // Compare vararg if (myParam.isVarargs() != otherParam.isVarargs()) { - return false; + return false; } Node myTypeNode = myParam.getTypeNode().jjtGetChild(0); @@ -118,7 +118,24 @@ public class MethodNameDeclaration extends AbstractNameDeclaration { @Override public int hashCode() { - return node.getImage().hashCode() + ((ASTMethodDeclarator) node).getParameterCount(); + int hash = node.getImage().hashCode() * 31 + ((ASTMethodDeclarator) node).getParameterCount(); + + ASTFormalParameters myParams = (ASTFormalParameters) node.jjtGetChild(0); + for (int i = 0; i < ((ASTMethodDeclarator) node).getParameterCount(); i++) { + ASTFormalParameter myParam = (ASTFormalParameter) myParams.jjtGetChild(i); + Node myTypeNode = myParam.getTypeNode().jjtGetChild(0); + + String myTypeImg; + if (myTypeNode instanceof ASTPrimitiveType) { + myTypeImg = myTypeNode.getImage(); + } else { + myTypeImg = myTypeNode.jjtGetChild(0).getImage(); + } + + hash = hash * 31 + myTypeImg.hashCode(); + } + + return hash; } @Override From d350bcb49e4f07fb43b85304d6acc8293b320ca7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Fri, 14 Oct 2016 16:05:20 -0300 Subject: [PATCH 4/8] Make explicit imports orders of times faster - We can tell if a name can be resolved or not, and we can do so in constant time. --- .../pmd/lang/java/symboltable/TypeSet.java | 34 ++++++++++++++----- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/TypeSet.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/TypeSet.java index a4f4fac903..d54e5bb4c1 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/TypeSet.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/TypeSet.java @@ -108,7 +108,8 @@ public class TypeSet { * explicit import statements. */ public static class ExplicitImportResolver extends AbstractResolver { - private Set importStmts; + private Map importStmts; + /** * Creates a new {@link ExplicitImportResolver}. * @param pmdClassLoader the class loader to use. @@ -116,21 +117,36 @@ public class TypeSet { */ public ExplicitImportResolver(PMDASMClassLoader pmdClassLoader, Set importStmts) { super(pmdClassLoader); - this.importStmts = importStmts; + + // unfold imports, to store both FQ and unqualified names mapped to the FQ name + this.importStmts = new HashMap<>(); + for (final String stmt : importStmts) { + if (stmt.endsWith("*")) { + continue; + } + + this.importStmts.put(stmt, stmt); + final int lastDotItdx = stmt.lastIndexOf('.'); + if (lastDotItdx != -1) { + this.importStmts.put(stmt.substring(lastDotItdx + 1), stmt); + } + } } @Override public Class resolve(String name) throws ClassNotFoundException { - if (name == null) { - throw new ClassNotFoundException(); - } - for (String importStmt : importStmts) { - if (importStmt.endsWith(name)) { - return pmdClassLoader.loadClass(importStmt); - } + final String fqName = importStmts.get(name); + if (fqName != null) { + return pmdClassLoader.loadClass(fqName); } + throw new ClassNotFoundException("Type " + name + " not found"); } + + @Override + public boolean couldResolve(String name) { + return importStmts.containsKey(name); + } } /** From 565a9aa0d86ed2576b9937e7927c702b32ceb7ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Fri, 14 Oct 2016 18:59:52 -0300 Subject: [PATCH 5/8] Add a cache to ImplicitImportResolver - Classes in java.lang.* aren't that many, yet they hit a lot (String, all boxed primitives, Math, etc.), so it makes sense to cache them --- .../pmd/lang/java/symboltable/TypeSet.java | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/TypeSet.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/TypeSet.java index d54e5bb4c1..313337bb9e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/TypeSet.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/TypeSet.java @@ -9,6 +9,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import net.sourceforge.pmd.lang.java.typeresolution.PMDASMClassLoader; import net.sourceforge.pmd.util.ClasspathClassLoader; @@ -176,6 +177,13 @@ public class TypeSet { */ // TODO cite the JLS section on implicit imports public static class ImplicitImportResolver extends AbstractResolver { + /* + * They aren't so many to bother about memory, but are used all the time, + * so we worry about performance. On average, you can expect this cache to have ~90% hit ratio + * unless abusing star imports (import on demand) + */ + private final ConcurrentHashMap> CLASS_CACHE = new ConcurrentHashMap<>(); + /** * Creates a {@link ImplicitImportResolver} * @param pmdClassLoader the class loader @@ -183,9 +191,22 @@ public class TypeSet { public ImplicitImportResolver(PMDASMClassLoader pmdClassLoader) { super(pmdClassLoader); } + @Override public Class resolve(String name) throws ClassNotFoundException { - return pmdClassLoader.loadClass("java.lang." + name); + if (name == null) { + throw new ClassNotFoundException(); + } + + Class clazz = CLASS_CACHE.get(name); + if (clazz != null) { + return clazz; + } + + clazz = pmdClassLoader.loadClass("java.lang." + name); + CLASS_CACHE.putIfAbsent(name, clazz); + + return clazz; } } From 8c82dae34c9825b70be08c68d2016fa016beeaf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Fri, 14 Oct 2016 19:34:39 -0300 Subject: [PATCH 6/8] Fully implemente couldResolve --- .../pmd/lang/java/symboltable/TypeSet.java | 31 +++++++++++++++++-- .../typeresolution/PMDASMClassLoader.java | 14 ++++++++- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/TypeSet.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/TypeSet.java index 313337bb9e..7aaacbc8b0 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/TypeSet.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/TypeSet.java @@ -98,9 +98,9 @@ public class TypeSet { 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 + * the class loader, so ask him */ - return true; + return pmdClassLoader.couldResolve(name); } } @@ -170,6 +170,11 @@ public class TypeSet { public Class resolve(String name) throws ClassNotFoundException { return pmdClassLoader.loadClass(pkg + '.' + name); } + + @Override + public boolean couldResolve(String name) { + return super.couldResolve(pkg + '.' + name); + } } /** @@ -208,6 +213,11 @@ public class TypeSet { return clazz; } + + @Override + public boolean couldResolve(String name) { + return super.couldResolve("java.lang." + name); + } } /** @@ -245,6 +255,23 @@ public class TypeSet { } throw new ClassNotFoundException("Type " + name + " not found"); } + + @Override + public boolean couldResolve(String name) { + boolean couldResolve = false; + for (String importStmt : importStmts) { + if (importStmt.endsWith("*")) { + String fqClassName = new StringBuilder(importStmt.length() + name.length()) + .append(importStmt) + .replace(importStmt.length() - 1, importStmt.length(), name) + .toString(); + // can any class be resolved / was never attempted? + couldResolve |= super.couldResolve(fqClassName); + } + } + + return couldResolve; + } } /** diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/PMDASMClassLoader.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/PMDASMClassLoader.java index 344bef79a7..6760bb7c18 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/PMDASMClassLoader.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/PMDASMClassLoader.java @@ -47,7 +47,7 @@ public final class PMDASMClassLoader extends ClassLoader { private PMDASMClassLoader(ClassLoader parent) { super(parent); } - + /** * A new PMDASMClassLoader is created for each compilation unit, this method * allows to reuse the same PMDASMClassLoader across all the compilation @@ -80,6 +80,18 @@ public final class PMDASMClassLoader extends ClassLoader { throw new ClassNotFoundException(name, e); } } + + /** + * Checks if the class loader could resolve a given class name + * (ie: it doesn't know for sure it will fail). + * Notice, that the ability to resolve a class does not imply + * that the class will actually be found and resolved. + * @param name the name of the class + * @return whether the class can be resolved + */ + public boolean couldResolve(String name) { + return !dontBother.containsKey(name); + } public synchronized Map getImportedClasses(String name) throws ClassNotFoundException { if (dontBother.containsValue(name)) { From 9b7372eec0ef9cab1ae56013d198242230c0719f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Sat, 15 Oct 2016 02:55:02 -0300 Subject: [PATCH 7/8] Minor improvements - Typos, extra whitespace, a missing static, clearer loops.. --- .../pmd/lang/java/symboltable/TypeSet.java | 15 ++++++++------- .../java/typeresolution/PMDASMClassLoader.java | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/TypeSet.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/TypeSet.java index 7aaacbc8b0..4c9655810b 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/TypeSet.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/TypeSet.java @@ -127,9 +127,9 @@ public class TypeSet { } this.importStmts.put(stmt, stmt); - final int lastDotItdx = stmt.lastIndexOf('.'); - if (lastDotItdx != -1) { - this.importStmts.put(stmt.substring(lastDotItdx + 1), stmt); + final int lastDotIdx = stmt.lastIndexOf('.'); + if (lastDotIdx != -1) { + this.importStmts.put(stmt.substring(lastDotIdx + 1), stmt); } } } @@ -187,7 +187,7 @@ public class TypeSet { * so we worry about performance. On average, you can expect this cache to have ~90% hit ratio * unless abusing star imports (import on demand) */ - private final ConcurrentHashMap> CLASS_CACHE = new ConcurrentHashMap<>(); + private static final ConcurrentHashMap> CLASS_CACHE = new ConcurrentHashMap<>(); /** * Creates a {@link ImplicitImportResolver} @@ -258,7 +258,6 @@ public class TypeSet { @Override public boolean couldResolve(String name) { - boolean couldResolve = false; for (String importStmt : importStmts) { if (importStmt.endsWith("*")) { String fqClassName = new StringBuilder(importStmt.length() + name.length()) @@ -266,11 +265,13 @@ public class TypeSet { .replace(importStmt.length() - 1, importStmt.length(), name) .toString(); // can any class be resolved / was never attempted? - couldResolve |= super.couldResolve(fqClassName); + if (super.couldResolve(fqClassName)) { + return true; + } } } - return couldResolve; + return false; } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/PMDASMClassLoader.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/PMDASMClassLoader.java index 6760bb7c18..0ba95138c4 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/PMDASMClassLoader.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/PMDASMClassLoader.java @@ -80,7 +80,7 @@ public final class PMDASMClassLoader extends ClassLoader { throw new ClassNotFoundException(name, e); } } - + /** * Checks if the class loader could resolve a given class name * (ie: it doesn't know for sure it will fail). From 0ba362c4c0d186b776a879fa9a3829b6efb4c287 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sun, 30 Oct 2016 18:38:52 +0100 Subject: [PATCH 8/8] Update changelog --- src/site/markdown/overview/changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/site/markdown/overview/changelog.md b/src/site/markdown/overview/changelog.md index f3fb7c3c67..c927340850 100644 --- a/src/site/markdown/overview/changelog.md +++ b/src/site/markdown/overview/changelog.md @@ -21,6 +21,7 @@ * [#114](https://github.com/pmd/pmd/pull/114): \[core] Remove multihreading workaround for JRE5, as no PMD version supports running on JRE5 anymore * [#115](https://github.com/pmd/pmd/pull/115): \[java] Simplify lambda parsing * [#116](https://github.com/pmd/pmd/pull/116): \[core] \[java] Improve collection usage +* [#117](https://github.com/pmd/pmd/pull/117): \[java] Improve symboltable performance **Bugfixes:**