View Javadoc

1   /***
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.rules;
5   
6   import net.sourceforge.pmd.AbstractRule;
7   import net.sourceforge.pmd.ast.ASTClassOrInterfaceDeclaration;
8   import net.sourceforge.pmd.ast.ASTCompilationUnit;
9   import net.sourceforge.pmd.ast.ASTFieldDeclaration;
10  import net.sourceforge.pmd.ast.ASTName;
11  import net.sourceforge.pmd.ast.ASTPrimitiveType;
12  import net.sourceforge.pmd.ast.ASTType;
13  import net.sourceforge.pmd.ast.ASTVariableDeclarator;
14  import net.sourceforge.pmd.ast.ASTVariableDeclaratorId;
15  import net.sourceforge.pmd.ast.AccessNode;
16  
17  import java.util.ArrayList;
18  import java.util.List;
19  
20  public class VariableNamingConventions extends AbstractRule {
21  
22      public static final String SEPARATOR = ",";
23  
24      private String[] staticPrefix;
25      private String[] staticSuffix;
26      private String[] memberPrefix;
27      private String[] memberSuffix;
28  
29      public Object visit(ASTCompilationUnit node, Object data) {
30          init();
31          return super.visit(node, data);
32      }
33  
34      protected void init() {
35          staticPrefix = split(getStringProperty("staticPrefix"));
36          staticSuffix = split(getStringProperty("staticSuffix"));
37          memberPrefix = split(getStringProperty("memberPrefix"));
38          memberSuffix = split(getStringProperty("memberSuffix"));
39      }
40  
41      public Object visit(ASTFieldDeclaration node, Object data) {
42          return checkNames(node, data);
43      }
44  
45      public Object checkNames(AccessNode node, Object data) {
46          ASTType childNodeType = (ASTType) node.jjtGetChild(0);
47          String varType = "";
48          if (childNodeType.jjtGetChild(0) instanceof ASTName) {
49              varType = ((ASTName) childNodeType.jjtGetChild(0)).getImage();
50          } else if (childNodeType.jjtGetChild(0) instanceof ASTPrimitiveType) {
51              varType = ((ASTPrimitiveType) childNodeType.jjtGetChild(0)).getImage();
52          }
53          if (varType != null && varType.length() > 0) {
54              //Get the variable name
55              ASTVariableDeclarator childNodeName = (ASTVariableDeclarator) node.jjtGetChild(1);
56              ASTVariableDeclaratorId childNodeId = (ASTVariableDeclaratorId) childNodeName.jjtGetChild(0);
57              String varName = childNodeId.getImage();
58  
59              if (varName.equals("serialVersionUID")) {
60                  return data;
61              }
62  
63              // non static final class fields are OK
64              if (node.isFinal() && !node.isStatic()) {
65                  if (node.jjtGetParent().jjtGetParent().jjtGetParent() instanceof ASTClassOrInterfaceDeclaration) {
66                      ASTClassOrInterfaceDeclaration c = (ASTClassOrInterfaceDeclaration) node.jjtGetParent().jjtGetParent().jjtGetParent();
67                      if (!c.isInterface()) {
68                          return data;
69                      }
70                  }
71              }
72  
73              // static finals (and interface fields, which are implicitly static and final) are
74              // checked for uppercase
75              if ((node.isStatic() && node.isFinal()) || (node.jjtGetParent().jjtGetParent().jjtGetParent() instanceof ASTClassOrInterfaceDeclaration && ((ASTClassOrInterfaceDeclaration) node.jjtGetParent().jjtGetParent().jjtGetParent()).isInterface())) {
76                  if (!varName.equals(varName.toUpperCase())) {
77                      addViolation(data, childNodeName, "Variables that are final and static should be in all caps.");
78                  }
79                  return data;
80              }
81  
82              String strippedVarName = null;
83              if (node.isStatic()) {
84                  strippedVarName = normalizeStaticVariableName(varName);
85              } else {
86                  strippedVarName = normalizeMemberVariableName(varName);
87              }
88  
89              if (strippedVarName.indexOf("_") >= 0) {
90                  addViolation(data, childNodeName, "Variables that are not final should not contain underscores (except for underscores in standard prefix/suffix).");
91              }
92              if (Character.isUpperCase(varName.charAt(0))) {
93                  addViolation(data, childNodeName, "Variables should start with a lowercase character");
94              }
95          }
96          return data;
97      }
98  
99      private String normalizeMemberVariableName(String varName) {
100         return stripSuffix(stripPrefix(varName, memberPrefix), memberSuffix);
101     }
102 
103     private String normalizeStaticVariableName(String varName) {
104         return stripSuffix(stripPrefix(varName, staticPrefix), staticSuffix);
105     }
106 
107     private String stripSuffix(String varName, String[] suffix) {
108         if (suffix != null) {
109             for (int i = 0; i < suffix.length; i++) {
110                 if (varName.endsWith(suffix[i])) {
111                     varName = varName.substring(0, varName.length() - suffix[i].length());
112                     break;
113                 }
114             }
115         }
116         return varName;
117     }
118 
119     private String stripPrefix(String varName, String[] prefix) {
120         if (prefix == null) {
121             return varName;
122         }
123         for (int i = 0; i < prefix.length; i++) {
124             if (varName.startsWith(prefix[i])) {
125                 return varName.substring(prefix[i].length());
126             }
127         }
128         return varName;
129     }
130 
131     protected String[] split(String str) {
132         if (str == null || str.length() == 0) {
133             return null;
134         }
135 
136         int index = str.indexOf(SEPARATOR);
137         if (index == -1) {
138             return new String[]{str};
139         }
140 
141         List list = new ArrayList();
142         int currPos = 0;
143         int len = SEPARATOR.length();
144         while (index != -1) {
145             list.add(str.substring(currPos, index));
146             currPos = index + len;
147             index = str.indexOf(SEPARATOR, currPos);
148         }
149         list.add(str.substring(currPos));
150         return (String[]) list.toArray(new String[list.size()]);
151     }
152 }