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