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 }