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] 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