KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sourceforge > pmd > rules > design > ImmutableField


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