refactored type lookup functionality with a new TypeMap

git-svn-id: https://pmd.svn.sourceforge.net/svnroot/pmd/trunk@4703 51baf565-9d33-0410-a72c-fc3788e3496d
This commit is contained in:
Brian Remedios
2006-10-18 13:26:10 +00:00
parent f0e67f2dbc
commit ce424d73a2
4 changed files with 179 additions and 56 deletions

View File

@ -3,8 +3,6 @@
*/
package net.sourceforge.pmd.rules.design;
import java.util.Set;
import net.sourceforge.pmd.AbstractRule;
import net.sourceforge.pmd.ast.ASTClassOrInterfaceType;
import net.sourceforge.pmd.ast.ASTFieldDeclaration;
@ -16,12 +14,12 @@ import net.sourceforge.pmd.util.CollectionUtil;
public class LooseCoupling extends AbstractRule {
// TODO - these should be brought in via external properties
private static final Set implClassNames = CollectionUtil.asSet( new Object[] {
"ArrayList", "HashSet", "HashMap", "LinkedHashMap", "LinkedHashSet", "TreeSet", "TreeMap", "Vector",
"java.util.ArrayList", "java.util.HashSet", "java.util.HashMap",
"java.util.LinkedHashMap", "java.util.LinkedHashSet", "java.util.TreeSet",
"java.util.TreeMap", "java.util.Vector"
});
// private static final Set implClassNames = CollectionUtil.asSet( new Object[] {
// "ArrayList", "HashSet", "HashMap", "LinkedHashMap", "LinkedHashSet", "TreeSet", "TreeMap", "Vector",
// "java.util.ArrayList", "java.util.HashSet", "java.util.HashMap",
// "java.util.LinkedHashMap", "java.util.LinkedHashSet", "java.util.TreeSet",
// "java.util.TreeMap", "java.util.Vector"
// });
public LooseCoupling() {
super();
@ -29,8 +27,9 @@ public class LooseCoupling extends AbstractRule {
public Object visit(ASTClassOrInterfaceType node, Object data) {
Node parent = node.jjtGetParent().jjtGetParent().jjtGetParent();
if (implClassNames.contains(node.getImage()) && (parent instanceof ASTFieldDeclaration || parent instanceof ASTFormalParameter || parent instanceof ASTResultType)) {
addViolation(data, node, node.getImage());
String typeName = node.getImage();
if (CollectionUtil.isCollectionType(typeName, false) && (parent instanceof ASTFieldDeclaration || parent instanceof ASTFormalParameter || parent instanceof ASTResultType)) {
addViolation(data, node, typeName);
}
return data;
}

View File

@ -1,7 +1,6 @@
package net.sourceforge.pmd.util;
import java.math.BigDecimal;
import java.util.Map;
/**
@ -13,39 +12,40 @@ public class ClassUtil {
private ClassUtil() {};
private static final Map primitiveTypesByName = CollectionUtil.mapFrom( new Object[][] {
{"int", int.class },
{"byte", byte.class },
{"long", long.class },
{"short", short.class },
{"float", float.class },
{"double", double.class },
{"char", char.class },
{"boolean", boolean.class },
private static final TypeMap primitiveTypesByName = new TypeMap( new Class[] {
int.class,
byte.class,
long.class,
short.class,
float.class,
double.class,
char.class,
boolean.class,
});
private static final Map typesByShortName = CollectionUtil.mapFrom( new Object[][] {
{"Integer", Integer.class },
{"Byte", Byte.class },
{"Long", Long.class },
{"Short", Short.class },
{"Float", Float.class },
{"Double", Double.class },
{"Character", Character.class },
{"Boolean", Boolean.class },
{"BigDecimal", BigDecimal.class },
{"String", String.class },
{"Object", Object.class },
{"Object[]", Object[].class }
private static final TypeMap typesByNames = new TypeMap( new Class[] {
Integer.class,
Byte.class,
Long.class,
Short.class,
Float.class,
Double.class,
Character.class,
Boolean.class,
BigDecimal.class,
String.class,
Object.class,
});
/**
* Method getPrimitiveTypeFor.
* Returns the type(class) for the name specified
* or null if not found.
*
* @param name String
* @return Class
*/
public static Class getPrimitiveTypeFor(String name) {
return (Class)primitiveTypesByName.get(name);
return primitiveTypesByName.typeFor(name);
}
/**
@ -56,13 +56,28 @@ public class ClassUtil {
*/
public static Class getTypeFor(String shortName) {
Class cls = (Class)typesByShortName.get(shortName);
if (cls != null) return cls;
Class type = typesByNames.typeFor(shortName);
if (type != null) return type;
cls = (Class)primitiveTypesByName.get(shortName);
if (cls != null) return cls;
type = primitiveTypesByName.typeFor(shortName);
if (type != null) return type;
return CollectionUtil.getCollectionTypeFor(shortName);
}
/**
* Returns the abbreviated name of the type,
* without the package name
*
* @param fullTypeName
* @return String
*/
public static String withoutPackageName(String fullTypeName) {
int dotPos = fullTypeName.lastIndexOf('.');
return dotPos > 0 ?
fullTypeName.substring(dotPos+1) :
fullTypeName;
}
}

View File

@ -15,31 +15,56 @@ import java.util.Map.Entry;
*/
public class CollectionUtil {
public static final Map collectionTypesByShortName = mapFrom( new Object[][] {
{"List", java.util.List.class },
{"Collection", java.util.Collection.class },
{"Map", java.util.Map.class },
{"ArrayList", java.util.ArrayList.class },
{"LinkedList", java.util.LinkedList.class },
{"Vector", java.util.Vector.class },
{"HashMap", java.util.HashMap.class },
{"TreeMap", java.util.TreeMap.class },
{"Set", java.util.Set.class },
{"HashSet", java.util.HashSet.class }
});
public static final TypeMap collectionInterfacesByNames = new TypeMap( new Class[] {
java.util.List.class,
java.util.Collection.class,
java.util.Map.class,
java.util.Set.class,
});
public static final TypeMap collectionClassesByNames = new TypeMap( new Class[] {
java.util.ArrayList.class,
java.util.LinkedList.class,
java.util.Vector.class,
java.util.HashMap.class,
java.util.LinkedHashMap.class,
java.util.TreeMap.class,
java.util.TreeSet.class,
java.util.HashSet.class,
java.util.LinkedHashSet.class
});
private CollectionUtil() {};
/**
* Returns the collection type if we know it by its short name.
* Returns the collection type if we recognize it by its short name.
*
* @param name String
* @param shortName String
* @return Class
*/
public static Class getCollectionTypeFor(String name) {
return (Class)collectionTypesByShortName.get(name);
public static Class getCollectionTypeFor(String shortName) {
Class cls = collectionClassesByNames.typeFor(shortName);
if (cls != null) return cls;
return collectionInterfacesByNames.typeFor(shortName);
}
/**
* Return whether we can identify the typeName as a java.util collection class
* or interface as specified.
*
* @param typeName String
* @param includeInterfaces boolean
* @return boolean
*/
public static boolean isCollectionType(String typeName, boolean includeInterfaces) {
if (collectionClassesByNames.contains(typeName)) return true;
return includeInterfaces && collectionInterfacesByNames.contains(typeName);
}
/**
* Returns the items as a populated set.
*

View File

@ -0,0 +1,84 @@
package net.sourceforge.pmd.util;
import java.util.HashMap;
import java.util.Map;
/**
* A specialized map that stores classes by both their full and short names.
*
* @author Brian Remedios
*/
public class TypeMap {
private Map typesByName;
/**
* Constructor for TypeMap.
* @param initialSize int
*/
public TypeMap(int initialSize) {
typesByName = new HashMap(initialSize);
}
/**
* Constructor for TypeMap that takes in an initial set of types.
*
* @param types Class[]
*/
public TypeMap(Class[] types) {
this(types.length);
add(types);
}
/**
* Adds a type to the receiver and stores it keyed by both its full
* and short names.
*
* @param type Class
*/
public void add(Class type) {
typesByName.put(type.getName(), type);
typesByName.put(ClassUtil.withoutPackageName(type.getName()), type);
}
/**
* Returns whether the type is known to the receiver.
*
* @param type Class
* @return boolean
*/
public boolean contains(Class type) {
return typesByName.containsValue(type);
}
/**
* Returns whether the typeName is known to the receiver.
*
* @param typeName String
* @return boolean
*/
public boolean contains(String typeName) {
return typesByName.containsKey(typeName);
}
/**
* Returns the type for the typeName specified.
*
* @param typeName String
* @return Class
*/
public Class typeFor(String typeName) {
return (Class)typesByName.get(typeName);
}
/**
* Adds an array of types to the receiver at once.
*
* @param types Class[]
*/
public void add(Class[] types) {
for (int i=0; i<types.length; i++) {
add(types[i]);
}
}
}