Java, typeres: fix PR comments, optimize by caching single class JavaTypeDefinitions

This commit is contained in:
Bendegúz Nagy
2017-06-20 00:18:21 +02:00
parent 4175460d35
commit 46daa878b0
5 changed files with 66 additions and 57 deletions

View File

@ -47,4 +47,8 @@ public class ASTClassOrInterfaceType extends AbstractJavaTypeNode {
}
return false;
}
public boolean isAnonymousClass() {
return jjtGetParent().hasDescendantOfType(ASTClassOrInterfaceBody.class);
}
}

View File

@ -28,7 +28,6 @@ import net.sourceforge.pmd.lang.java.ast.ASTArguments;
import net.sourceforge.pmd.lang.java.ast.ASTArrayDimsAndInits;
import net.sourceforge.pmd.lang.java.ast.ASTBooleanLiteral;
import net.sourceforge.pmd.lang.java.ast.ASTCastExpression;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBody;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
@ -58,7 +57,6 @@ import net.sourceforge.pmd.lang.java.ast.ASTPreDecrementExpression;
import net.sourceforge.pmd.lang.java.ast.ASTPreIncrementExpression;
import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;
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.ASTRelationalExpression;
@ -158,6 +156,12 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter {
private List<String> importedOnDemand;
private int anonymousClassCounter = 0;
/**
* Contains Class -> JavaTypeDefinitions map for raw Class types. Also helps to avoid infinite recursion
* when determining default upper bounds.
*/
private Map<Class<?>, JavaTypeDefinition> classToDefaultUpperBounds = new HashMap<>();
public ClassTypeResolver() {
this(ClassTypeResolver.class.getClassLoader());
}
@ -232,8 +236,8 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter {
super.visit(node, data);
String typeName = node.getImage();
// branch deals with anonymous classes
if (node.jjtGetParent().hasDescendantOfType(ASTClassOrInterfaceBody.class)) {
if (node.isAnonymousClass()) {
anonymousClassCounter++;
AbstractNode parent = node.getFirstParentOfType(ASTClassOrInterfaceDeclaration.class);
if (parent == null) {
@ -261,13 +265,6 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter {
return data;
}
@Override
public Object visit(ASTExtendsList node, Object data) {
super.visit(node, data);
return data;
}
@Override
public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
populateType(node, node.getImage());
@ -288,18 +285,18 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter {
@Override
public Object visit(ASTName node, Object data) {
Class accessingClass = getEnclosingTypeDeclaration(node);
Class<?> accessingClass = getEnclosingTypeDeclaration(node);
String[] dotSplitImage = node.getImage().split("\\.");
JavaTypeDefinition previousType
= getTypeDefinitionOfVariableFromScope(node.getScope(), dotSplitImage[0], accessingClass);
if (node.getNameDeclaration() != null //
if (node.getNameDeclaration() != null
&& previousType == null // if it's not null, then let other code handle things
&& node.getNameDeclaration().getNode() instanceof TypeNode) {
// Carry over the type from the declaration
Class nodeType = ((TypeNode) node.getNameDeclaration().getNode()).getType();
Class<?> nodeType = ((TypeNode) node.getNameDeclaration().getNode()).getType();
// generic classes and class with generic super types could have the wrong type assigned here
if (nodeType != null && !isGeneric(nodeType) && !isGeneric(nodeType.getSuperclass())) {
node.setType(nodeType);
@ -342,7 +339,7 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter {
* @param accessingClass The class that is trying to access the field, some Class declared in the current ACU.
* @return JavaTypeDefinition of the resolved field or null if it could not be found.
*/
private JavaTypeDefinition getFieldType(JavaTypeDefinition typeToSearch, String fieldImage, Class accessingClass) {
private JavaTypeDefinition getFieldType(JavaTypeDefinition typeToSearch, String fieldImage, Class<?> accessingClass) {
while (typeToSearch != null) {
try {
Field field = typeToSearch.getType().getDeclaredField(fieldImage);
@ -367,7 +364,7 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter {
* @param accessingClass The Class (which is defined in the current ACU) that is trying to access the field.
* @return Type def. of the field, or null if it could not be resolved.
*/
private JavaTypeDefinition getTypeDefinitionOfVariableFromScope(Scope scope, String image, Class accessingClass) {
private JavaTypeDefinition getTypeDefinitionOfVariableFromScope(Scope scope, String image, Class<?> accessingClass) {
if (accessingClass == null) {
return null;
}
@ -463,7 +460,7 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter {
* @param parameterName The name of the type parameter.
* @return The ordinal of the type parameter.
*/
private int getTypeParameterOrdinal(Class clazz, String parameterName) {
private int getTypeParameterOrdinal(Class<?> clazz, String parameterName) {
TypeVariable[] classTypeParameters = clazz.getTypeParameters();
for (int index = 0; index < classTypeParameters.length; ++index) {
@ -481,7 +478,7 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter {
* @param clazz The Class to examine.
* @return True if the Class is generic.
*/
private boolean isGeneric(Class clazz) {
private boolean isGeneric(Class<?> clazz) {
if (clazz != null) {
return clazz.getTypeParameters().length != 0;
}
@ -489,11 +486,6 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter {
return false;
}
/**
* Contains Class -> JavaTypeDefinitions map for raw Class types. Also helps to avoid infinite recursion.
*/
private Map<Class, JavaTypeDefinition> classToDefaultUpperBounds = new HashMap<>();
/**
* Given a Class, returns the type def. for when the Class stands without type arguments, meaning it
* is a raw type. Determines the generic types by looking at the upper bounds of it's generic parameters.
@ -502,7 +494,7 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter {
* @param clazzWithDefBounds The raw Class type.
* @return The type def. of the raw Class.
*/
private JavaTypeDefinition getDefaultUpperBounds(JavaTypeDefinition context, Class clazzWithDefBounds) {
private JavaTypeDefinition getDefaultUpperBounds(JavaTypeDefinition context, Class<?> clazzWithDefBounds) {
JavaTypeDefinitionBuilder typeDef = JavaTypeDefinition.builder(clazzWithDefBounds);
// helps avoid infinite recursion with Something<.... E extends Something (<- same raw type)... >
@ -765,7 +757,7 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter {
JavaTypeDefinition primaryNodeType = null;
AbstractJavaTypeNode previousChild = null;
Class accessingClass = getEnclosingTypeDeclaration(primaryNode);
Class<?> accessingClass = getEnclosingTypeDeclaration(primaryNode);
for (int childIndex = 0; childIndex < primaryNode.jjtGetNumChildren(); ++childIndex) {
AbstractJavaTypeNode currentChild = (AbstractJavaTypeNode) primaryNode.jjtGetChild(childIndex);
@ -832,7 +824,7 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter {
* @param node The node with the enclosing Class declaration.
* @return The JavaTypeDefinition of the enclosing Class declaration.
*/
private Class getEnclosingTypeDeclaration(Node node) {
private Class<?> getEnclosingTypeDeclaration(Node node) {
Node previousNode = null;
while (node != null) {
if (node instanceof ASTClassOrInterfaceDeclaration) {
@ -863,7 +855,7 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter {
* @param clazz The type of the enclosing class.
* @return The TypeDefinition of the superclass.
*/
private JavaTypeDefinition getSuperClassTypeDefinition(Node node, Class clazz) {
private JavaTypeDefinition getSuperClassTypeDefinition(Node node, Class<?> clazz) {
Node previousNode = null;
for (; node != null; previousNode = node, node = node.jjtGetParent()) {
if (node instanceof ASTClassOrInterfaceDeclaration // class declaration
@ -898,18 +890,6 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter {
return data;
}
@Override
public Object visit(ASTPrimarySuffix node, Object data) {
super.visit(node, data);
return data;
}
@Override
public Object visit(ASTTypeArguments node, Object data) {
super.visit(node, data);
return data;
}
@Override
public Object visit(ASTTypeArgument node, Object data) {
super.visit(node, data);

View File

@ -6,43 +6,68 @@ package net.sourceforge.pmd.lang.java.typeresolution.typedefinition;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class JavaTypeDefinition implements TypeDefinition {
private final Class clazz;
private final List<JavaTypeDefinition> genericArgs;
private final Class<?> clazz;
private List<JavaTypeDefinition> genericArgs;
// contains TypeDefs where only the clazz field is used
private static Map<Class<?>, JavaTypeDefinition> onlyClassTypeDef = new HashMap<>();
public Class getType() {
public Class<?> getType() {
return clazz;
}
public List<JavaTypeDefinition> getGenericArgs() {
if (genericArgs == null) {
genericArgs = Collections.unmodifiableList(new ArrayList<JavaTypeDefinition>());
}
return genericArgs;
}
JavaTypeDefinition(Class clazz, List<JavaTypeDefinition> genericArgs) {
private JavaTypeDefinition(Class<?> clazz, List<JavaTypeDefinition> genericArgs) {
this.clazz = clazz;
if (genericArgs == null) {
genericArgs = new ArrayList<>();
if (genericArgs != null) {
this.genericArgs = Collections.unmodifiableList(genericArgs);
}
this.genericArgs = Collections.unmodifiableList(genericArgs);
}
// builder part of the class
// TODO: possibly add some sort of caching (with like a map or something)
public static JavaTypeDefinition build(Class clazz) {
return new JavaTypeDefinition(clazz, null);
public static JavaTypeDefinition build(Class<?> clazz) {
if (onlyClassTypeDef.containsKey(clazz)) {
return onlyClassTypeDef.get(clazz);
}
JavaTypeDefinition typeDef = new JavaTypeDefinition(clazz, null);
onlyClassTypeDef.put(clazz, typeDef);
return typeDef;
}
public static JavaTypeDefinitionBuilder builder(Class clazz) {
/**
* @param genericArgs This package private method expects that the genericArgs list has not been leaked,
* meaning the other references have been discarded to ensure immutability.
*/
/* default */ static JavaTypeDefinition build(Class<?> clazz, List<JavaTypeDefinition> genericArgs) {
if (genericArgs == null) {
return build(clazz);
}
return new JavaTypeDefinition(clazz, genericArgs);
}
public static JavaTypeDefinitionBuilder builder(Class<?> clazz) {
return new JavaTypeDefinitionBuilder().setType(clazz);
}
public static JavaTypeDefinitionBuilder builder() {
return new JavaTypeDefinitionBuilder();
}

View File

@ -9,10 +9,10 @@ import java.util.Collections;
import java.util.List;
public class JavaTypeDefinitionBuilder {
private Class clazz = null;
private Class<?> clazz = null;
private List<JavaTypeDefinition> genericArgs = new ArrayList<>();
JavaTypeDefinitionBuilder() {}
/* default */ JavaTypeDefinitionBuilder() {}
public JavaTypeDefinitionBuilder addTypeArg(JavaTypeDefinition arg) {
genericArgs.add(arg);
@ -28,12 +28,12 @@ public class JavaTypeDefinitionBuilder {
return this;
}
public JavaTypeDefinitionBuilder setType(Class clazz) {
public JavaTypeDefinitionBuilder setType(Class<?> clazz) {
this.clazz = clazz;
return this;
}
public JavaTypeDefinition build() {
return new JavaTypeDefinition(clazz, genericArgs);
return JavaTypeDefinition.build(clazz, genericArgs);
}
}

View File

@ -12,7 +12,7 @@ public interface TypeDefinition {
*
* @return Raw Class type.
*/
Class getType();
Class<?> getType();
/**
* Get the list of type arguments for this TypeDefinition.