Clover coverage report - PMD - 3.9 Coverage timestamp: Tue Dec 19 2006 09:38:44 EST FRAMES NO FRAMES |
file stats: | LOC: | 113 |  | Methods: | 6
| NCLOC: | 96 |  | Classes: | 1
Source file | Conditionals | Statements | Methods | TOTAL
ImmutableField.java | 91.7% | 100% | 100% | 97.2% |

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 net.sourceforge.pmd.AbstractRule;
7 |  | import net.sourceforge.pmd.ast.ASTClassOrInterfaceBodyDeclaration;
8 |  | import net.sourceforge.pmd.ast.ASTClassOrInterfaceDeclaration;
9 |  | import net.sourceforge.pmd.ast.ASTConstructorDeclaration;
10 |  | import net.sourceforge.pmd.ast.ASTDoStatement;
11 |  | import net.sourceforge.pmd.ast.ASTForStatement;
12 |  | import net.sourceforge.pmd.ast.ASTMethodDeclaration;
13 |  | import net.sourceforge.pmd.ast.ASTTryStatement;
14 |  | import net.sourceforge.pmd.ast.ASTVariableInitializer;
15 |  | import net.sourceforge.pmd.ast.ASTWhileStatement;
16 |  | import net.sourceforge.pmd.ast.SimpleNode;
17 |  | import net.sourceforge.pmd.symboltable.NameOccurrence;
18 |  | import net.sourceforge.pmd.symboltable.VariableNameDeclaration;
19 |  |
20 |  | import java.util.ArrayList;
21 |  | import java.util.HashSet;
22 |  | import java.util.Iterator;
23 |  | import java.util.List;
24 |  | import java.util.Map;
25 |  | import java.util.Set;
26 |  |
27 |  | /**
28 |  | * @author Olander
29 |  | */
30 |  | public class ImmutableField extends AbstractRule {
31 |  |
32 |  | private static final int MUTABLE = 0;
33 |  | private static final int IMMUTABLE = 1;
34 |  | private static final int CHECKDECL = 2;
35 |  |
36 | 16 | public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
37 | 16 | Map vars = node.getScope().getVariableDeclarations();
38 | 16 | List constructors = findAllConstructors(node);
39 | 16 | for (Iterator i = vars.entrySet().iterator(); i.hasNext();) {
40 | 18 | Map.Entry entry = (Map.Entry) i.next();
41 | 18 | VariableNameDeclaration field = (VariableNameDeclaration) entry.getKey();
42 | 18 | if (field.getAccessNodeParent().isStatic() || !field.getAccessNodeParent().isPrivate() || field.getAccessNodeParent().isFinal()) {
43 | 2 | continue;
44 |  | }
45 |  |
46 | 16 | int result = initializedInConstructor((List) entry.getValue(), new HashSet(constructors));
47 | 16 | if (result == MUTABLE) {
48 | 12 | continue;
49 |  | }
50 | 4 | if (result == IMMUTABLE || (result == CHECKDECL && initializedWhenDeclared(field))) {
51 | 2 | addViolation(data, field.getNode(), field.getImage());
52 |  | }
53 |  | }
54 | 16 | return super.visit(node, data);
55 |  | }
56 |  |
57 | 3 | private boolean initializedWhenDeclared(VariableNameDeclaration field) {
58 | 3 | return !field.getAccessNodeParent().findChildrenOfType(ASTVariableInitializer.class).isEmpty();
59 |  | }
60 |  |
61 | 16 | private int initializedInConstructor(List usages, Set allConstructors) {
62 | 16 | int result = MUTABLE, methodInitCount = 0;
63 | 16 | Set consSet = new HashSet();
64 | 16 | for (Iterator j = usages.iterator(); j.hasNext();) {
65 | 18 | NameOccurrence occ = (NameOccurrence) j.next();
66 | 18 | if (occ.isOnLeftHandSide() || occ.isSelfAssignment()) {
67 | 18 | SimpleNode node = occ.getLocation();
68 | 18 | SimpleNode constructor = (SimpleNode) node.getFirstParentOfType(ASTConstructorDeclaration.class);
69 | 18 | if (constructor != null) {
70 | 6 | if (inLoopOrTry(node)) {
71 | 2 | continue;
72 |  | }
73 | 4 | if (inAnonymousInnerClass(node)) {
74 | 1 | methodInitCount++;
75 |  | } else {
76 | 3 | consSet.add(constructor);
77 |  | }
78 |  | } else {
79 | 12 | if (node.getFirstParentOfType(ASTMethodDeclaration.class) != null) {
80 | 12 | methodInitCount++;
81 |  | }
82 |  | }
83 |  | }
84 |  | }
85 | 16 | if (usages.isEmpty() || ((methodInitCount == 0) && consSet.isEmpty())) {
86 | 3 | result = CHECKDECL;
87 |  | } else {
88 | 13 | allConstructors.removeAll(consSet);
89 | 13 | if (allConstructors.isEmpty() && (methodInitCount == 0)) {
90 | 1 | result = IMMUTABLE;
91 |  | }
92 |  | }
93 | 16 | return result;
94 |  | }
95 |  |
96 | 6 | private boolean inLoopOrTry(SimpleNode node) {
97 | 6 | return (SimpleNode) node.getFirstParentOfType(ASTTryStatement.class) != null ||
98 |  | (SimpleNode) node.getFirstParentOfType(ASTForStatement.class) != null ||
99 |  | (SimpleNode) node.getFirstParentOfType(ASTWhileStatement.class) != null ||
100 |  | (SimpleNode) node.getFirstParentOfType(ASTDoStatement.class) != null;
101 |  | }
102 |  |
103 | 4 | private boolean inAnonymousInnerClass(SimpleNode node) {
104 | 4 | ASTClassOrInterfaceBodyDeclaration parent = (ASTClassOrInterfaceBodyDeclaration) node.getFirstParentOfType(ASTClassOrInterfaceBodyDeclaration.class);
105 | 4 | return parent != null && parent.isAnonymousInnerClass();
106 |  | }
107 |  |
108 | 16 | private List findAllConstructors(ASTClassOrInterfaceDeclaration node) {
109 | 16 | List cons = new ArrayList();
110 | 16 | node.findChildrenOfType(ASTConstructorDeclaration.class, cons, false);
111 | 16 | return cons;
112 |  | }
113 |  | }