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`
This commit is contained in:
Juan Martín Sotuyo Dodero
2016-10-13 20:40:46 -03:00
parent d8344b0672
commit 09ac963709
2 changed files with 57 additions and 7 deletions

View File

@ -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<String> 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<Integer> anonymousInnerClassCounter = new ThreadLocal<Integer>() {
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);

View File

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