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
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
96
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 }