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