Clover coverage report - PMD - 3.7
Coverage timestamp: Wed May 31 2006 09:25:59 EDT

file stats: | LOC: | 112 |  | Methods: | 6
| NCLOC: | 95 |  | Classes: | 1

Source file | Conditionals | Statements | Methods | TOTAL

ImmutableField.java

91.7%

100%

100%

97.1%

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.HashSet;
21 |  | import java.util.Iterator;
22 |  | import java.util.List;
23 |  | import java.util.Map;
24 |  | import java.util.Set;
25 |  | import java.util.ArrayList;
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.keySet().iterator(); i.hasNext();) {
40 | 18 | VariableNameDeclaration field = (VariableNameDeclaration) i.next();
41 | 18 | if (field.getAccessNodeParent().isStatic() || !field.getAccessNodeParent().isPrivate() || field.getAccessNodeParent().isFinal()) {
42 | 2 | continue;
43 |  | }
44 |  |
45 | 16 | int result = initializedInConstructor((List) vars.get(field), new HashSet(constructors));
46 | 16 | if (result == MUTABLE) {
47 | 12 | continue;
48 |  | }
49 | 4 | if (result == IMMUTABLE || (result == CHECKDECL && initializedWhenDeclared(field))) {
50 | 2 | addViolation(data, field.getNode(), field.getImage());
51 |  | }
52 |  | }
53 | 16 | return super.visit(node, data);
54 |  | }
55 |  |
56 | 3 | private boolean initializedWhenDeclared(VariableNameDeclaration field) {
57 | 3 | return !field.getAccessNodeParent().findChildrenOfType(ASTVariableInitializer.class).isEmpty();
58 |  | }
59 |  |
60 | 16 | private int initializedInConstructor(List usages, Set allConstructors) {
61 | 16 | int result = MUTABLE, methodInitCount = 0;
62 | 16 | Set consSet = new HashSet();
63 | 16 | for (Iterator j = usages.iterator(); j.hasNext();) {
64 | 18 | NameOccurrence occ = (NameOccurrence) j.next();
65 | 18 | if (occ.isOnLeftHandSide() || occ.isSelfAssignment()) {
66 | 18 | SimpleNode node = occ.getLocation();
67 | 18 | SimpleNode constructor = (SimpleNode) node.getFirstParentOfType(ASTConstructorDeclaration.class);
68 | 18 | if (constructor != null) {
69 | 6 | if (inLoopOrTry(node)) {
70 | 2 | continue;
71 |  | }
72 | 4 | if (inAnonymousInnerClass(node)) {
73 | 1 | methodInitCount++;
74 |  | } else {
75 | 3 | consSet.add(constructor);
76 |  | }
77 |  | } else {
78 | 12 | if (node.getFirstParentOfType(ASTMethodDeclaration.class) != null) {
79 | 12 | methodInitCount++;
80 |  | }
81 |  | }
82 |  | }
83 |  | }
84 | 16 | if (usages.isEmpty() || ((methodInitCount == 0) && consSet.isEmpty())) {
85 | 3 | result = CHECKDECL;
86 |  | } else {
87 | 13 | allConstructors.removeAll(consSet);
88 | 13 | if (allConstructors.isEmpty() && (methodInitCount == 0)) {
89 | 1 | result = IMMUTABLE;
90 |  | }
91 |  | }
92 | 16 | return result;
93 |  | }
94 |  |
95 | 6 | private boolean inLoopOrTry(SimpleNode node) {
96 | 6 | return (SimpleNode) node.getFirstParentOfType(ASTTryStatement.class) != null ||
97 |  | (SimpleNode) node.getFirstParentOfType(ASTForStatement.class) != null ||
98 |  | (SimpleNode) node.getFirstParentOfType(ASTWhileStatement.class) != null ||
99 |  | (SimpleNode) node.getFirstParentOfType(ASTDoStatement.class) != null;
100 |  | }
101 |  |
102 | 4 | private boolean inAnonymousInnerClass(SimpleNode node) {
103 | 4 | ASTClassOrInterfaceBodyDeclaration parent = (ASTClassOrInterfaceBodyDeclaration) node.getFirstParentOfType(ASTClassOrInterfaceBodyDeclaration.class);
104 | 4 | return parent != null && parent.isAnonymousInnerClass();
105 |  | }
106 |  |
107 | 16 | private List findAllConstructors(ASTClassOrInterfaceDeclaration node) {
108 | 16 | List cons = new ArrayList();
109 | 16 | node.findChildrenOfType(ASTConstructorDeclaration.class, cons, false);
110 | 16 | return cons;
111 |  | }
112 |  | }