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