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