AssignmentToNonFinalStaticRule.java
01 /*
02  * AssignmentToNonFinalStaticRule.java
03  *
04  * Created on October 24, 2004, 8:56 AM
05  */
06 
07 package net.sourceforge.pmd.lang.java.rule.design;
08 
09 import java.util.List;
10 import java.util.Map;
11 
12 import net.sourceforge.pmd.lang.ast.Node;
13 import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
14 import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
15 import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
16 import net.sourceforge.pmd.lang.java.symboltable.NameOccurrence;
17 import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration;
18 
19 
20 /**
21  @author Eric Olander
22  */
23 public class AssignmentToNonFinalStaticRule extends AbstractJavaRule {
24 
25     public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
26         Map<VariableNameDeclaration, List<NameOccurrence>> vars = node.getScope().getVariableDeclarations();
27         for (Map.Entry<VariableNameDeclaration, List<NameOccurrence>> entry: vars.entrySet()) {
28             VariableNameDeclaration decl = entry.getKey();
29             if (!decl.getAccessNodeParent().isStatic() || decl.getAccessNodeParent().isFinal()) {
30                 continue;
31             }
32 
33             if (initializedInConstructor(entry.getValue())) {
34                 addViolation(data, decl.getNode(), decl.getImage());
35             }
36         }
37         return super.visit(node, data);
38     }
39 
40     private boolean initializedInConstructor(List<NameOccurrence> usages) {
41         boolean initInConstructor = false;
42 
43         for (NameOccurrence occ: usages) {
44             if (occ.isOnLeftHandSide()) { // specifically omitting prefix and postfix operators as there are legitimate usages of these with static fields, e.g. typesafe enum pattern.
45           Node node = occ.getLocation();
46           Node constructor = node.getFirstParentOfType(ASTConstructorDeclaration.class);
47                 if (constructor != null) {
48                     initInConstructor = true;
49                 }
50             }
51         }
52 
53         return initInConstructor;
54     }
55 
56 }