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