1 /** 2 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html 3 */ 4 package net.sourceforge.pmd.rules.design; 5 6 import java.util.HashMap; 7 import java.util.List; 8 import java.util.Map; 9 10 import net.sourceforge.pmd.AbstractRule; 11 import net.sourceforge.pmd.PropertyDescriptor; 12 import net.sourceforge.pmd.ast.ASTClassOrInterfaceDeclaration; 13 import net.sourceforge.pmd.ast.ASTCompilationUnit; 14 import net.sourceforge.pmd.ast.ASTFieldDeclaration; 15 import net.sourceforge.pmd.ast.SimpleNode; 16 import net.sourceforge.pmd.properties.IntegerProperty; 17 import net.sourceforge.pmd.util.NumericConstants; 18 19 20 public class TooManyFields extends AbstractRule { 21 22 private static final int DEFAULT_MAXFIELDS = 15; 23 24 private Map<String, Integer> stats; 25 private Map<String, ASTClassOrInterfaceDeclaration> nodes; 26 27 private static final PropertyDescriptor maxFieldsDescriptor = new IntegerProperty( 28 "maxfields", 29 "Maximum allowable fields per class", 30 DEFAULT_MAXFIELDS, 31 1.0f 32 ); 33 34 private static final Map<String, PropertyDescriptor> propertyDescriptorsByName = asFixedMap(maxFieldsDescriptor); 35 36 public Object visit(ASTCompilationUnit node, Object data) { 37 38 int maxFields = getIntProperty(maxFieldsDescriptor); 39 40 stats = new HashMap<String, Integer>(5); 41 nodes = new HashMap<String, ASTClassOrInterfaceDeclaration>(5); 42 43 List<ASTFieldDeclaration> l = node.findChildrenOfType(ASTFieldDeclaration.class); 44 45 for (ASTFieldDeclaration fd: l) { 46 if (fd.isFinal() && fd.isStatic()) { 47 continue; 48 } 49 ASTClassOrInterfaceDeclaration clazz = fd.getFirstParentOfType(ASTClassOrInterfaceDeclaration.class); 50 if (clazz != null && !clazz.isInterface()) { 51 bumpCounterFor(clazz); 52 } 53 } 54 for (String k : stats.keySet()) { 55 int val = stats.get(k); 56 SimpleNode n = nodes.get(k); 57 if (val > maxFields) { 58 addViolation(data, n); 59 } 60 } 61 return data; 62 } 63 64 private void bumpCounterFor(ASTClassOrInterfaceDeclaration clazz) { 65 String key = clazz.getImage(); 66 if (!stats.containsKey(key)) { 67 stats.put(key, NumericConstants.ZERO); 68 nodes.put(key, clazz); 69 } 70 Integer i = Integer.valueOf(stats.get(key) + 1); 71 stats.put(key, i); 72 } 73 74 /** 75 * @return Map 76 */ 77 protected Map<String, PropertyDescriptor> propertiesByName() { 78 return propertyDescriptorsByName; 79 } 80 }