001 /**
002 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
003 */
004 package net.sourceforge.pmd.lang.java.rule.naming;
005
006 import net.sourceforge.pmd.lang.ast.Node;
007 import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
008 import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
009 import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;
010 import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter;
011 import net.sourceforge.pmd.lang.java.ast.ASTFormalParameters;
012 import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration;
013 import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator;
014 import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
015 import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
016 import net.sourceforge.pmd.lang.rule.properties.BooleanProperty;
017 import net.sourceforge.pmd.lang.rule.properties.StringMultiProperty;
018
019 public class VariableNamingConventionsRule extends AbstractJavaRule {
020
021 private boolean checkMembers;
022 private boolean checkLocals;
023 private boolean checkParameters;
024 private String[] staticPrefixes;
025 private String[] staticSuffixes;
026 private String[] memberPrefixes;
027 private String[] memberSuffixes;
028 private String[] localPrefixes;
029 private String[] localSuffixes;
030 private String[] parameterPrefixes;
031 private String[] parameterSuffixes;
032
033 private static final BooleanProperty CHECK_MEMBERS_DESCRIPTOR = new BooleanProperty("checkMembers",
034 "Check member variables", true, 1.0f);
035
036 private static final BooleanProperty CHECK_LOCALS_DESCRIPTOR = new BooleanProperty("checkLocals",
037 "Check local variables", true, 2.0f);
038
039 private static final BooleanProperty CHECK_PARAMETERS_DESCRIPTOR = new BooleanProperty("checkParameters",
040 "Check constructor and method parameter variables", true, 3.0f);
041
042 private static final StringMultiProperty STATIC_PREFIXES_DESCRIPTOR = new StringMultiProperty("staticPrefix",
043 "Static variable prefixes", new String[] { "" }, 4.0f, ',');
044
045 private static final StringMultiProperty STATIC_SUFFIXES_DESCRIPTOR = new StringMultiProperty("staticSuffix",
046 "Static variable suffixes", new String[] { "" }, 5.0f, ',');
047
048 private static final StringMultiProperty MEMBER_PREFIXES_DESCRIPTOR = new StringMultiProperty("memberPrefix",
049 "Member variable prefixes", new String[] { "" }, 6.0f, ',');
050
051 private static final StringMultiProperty MEMBER_SUFFIXES_DESCRIPTOR = new StringMultiProperty("memberSuffix",
052 "Member variable suffixes", new String[] { "" }, 7.0f, ',');
053
054 private static final StringMultiProperty LOCAL_PREFIXES_DESCRIPTOR = new StringMultiProperty("localPrefix",
055 "Local variable prefixes", new String[] { "" }, 8.0f, ',');
056
057 private static final StringMultiProperty LOCAL_SUFFIXES_DESCRIPTOR = new StringMultiProperty("localSuffix",
058 "Local variable suffixes", new String[] { "" }, 9.0f, ',');
059
060 private static final StringMultiProperty PARAMETER_PREFIXES_DESCRIPTOR = new StringMultiProperty("parameterPrefix",
061 "Method parameter variable prefixes", new String[] { "" }, 10.0f, ',');
062
063 private static final StringMultiProperty PARAMETER_SUFFIXES_DESCRIPTOR = new StringMultiProperty("parameterSuffix",
064 "Method parameter variable suffixes", new String[] { "" }, 11.0f, ',');
065
066 public VariableNamingConventionsRule() {
067 definePropertyDescriptor(CHECK_MEMBERS_DESCRIPTOR);
068 definePropertyDescriptor(CHECK_LOCALS_DESCRIPTOR);
069 definePropertyDescriptor(CHECK_PARAMETERS_DESCRIPTOR);
070 definePropertyDescriptor(STATIC_PREFIXES_DESCRIPTOR);
071 definePropertyDescriptor(STATIC_SUFFIXES_DESCRIPTOR);
072 definePropertyDescriptor(MEMBER_PREFIXES_DESCRIPTOR);
073 definePropertyDescriptor(MEMBER_SUFFIXES_DESCRIPTOR);
074 definePropertyDescriptor(LOCAL_PREFIXES_DESCRIPTOR);
075 definePropertyDescriptor(LOCAL_SUFFIXES_DESCRIPTOR);
076 definePropertyDescriptor(PARAMETER_PREFIXES_DESCRIPTOR);
077 definePropertyDescriptor(PARAMETER_SUFFIXES_DESCRIPTOR);
078 }
079
080 public Object visit(ASTCompilationUnit node, Object data) {
081 init();
082 return super.visit(node, data);
083 }
084
085 protected void init() {
086 checkMembers = getProperty(CHECK_MEMBERS_DESCRIPTOR);
087 checkLocals = getProperty(CHECK_LOCALS_DESCRIPTOR);
088 checkParameters = getProperty(CHECK_PARAMETERS_DESCRIPTOR);
089 staticPrefixes = getProperty(STATIC_PREFIXES_DESCRIPTOR);
090 staticSuffixes = getProperty(STATIC_SUFFIXES_DESCRIPTOR);
091 memberPrefixes = getProperty(MEMBER_PREFIXES_DESCRIPTOR);
092 memberSuffixes = getProperty(MEMBER_SUFFIXES_DESCRIPTOR);
093 localPrefixes = getProperty(LOCAL_PREFIXES_DESCRIPTOR);
094 localSuffixes = getProperty(LOCAL_SUFFIXES_DESCRIPTOR);
095 parameterPrefixes = getProperty(PARAMETER_PREFIXES_DESCRIPTOR);
096 parameterSuffixes = getProperty(PARAMETER_SUFFIXES_DESCRIPTOR);
097 }
098
099 public Object visit(ASTFieldDeclaration node, Object data) {
100 if (!checkMembers) {
101 return data;
102 }
103 boolean isStatic = node.isStatic();
104 boolean isFinal = node.isFinal();
105 // Anything from an interface is necessarily static and final
106 if (node.jjtGetParent().jjtGetParent().jjtGetParent() instanceof ASTClassOrInterfaceDeclaration
107 && ((ASTClassOrInterfaceDeclaration) node.jjtGetParent().jjtGetParent().jjtGetParent()).isInterface()) {
108 isStatic = true;
109 isFinal = true;
110 }
111 return checkVariableDeclarators(node.isStatic() ? staticPrefixes : memberPrefixes, isStatic ? staticSuffixes
112 : memberSuffixes, node, isStatic, isFinal, data);
113 }
114
115 public Object visit(ASTLocalVariableDeclaration node, Object data) {
116 if (!checkLocals) {
117 return data;
118 }
119 return checkVariableDeclarators(localPrefixes, localSuffixes, node, false, node.isFinal(), data);
120 }
121
122 public Object visit(ASTFormalParameters node, Object data) {
123 if (!checkParameters) {
124 return data;
125 }
126 for (ASTFormalParameter formalParameter : node.findChildrenOfType(ASTFormalParameter.class)) {
127 for (ASTVariableDeclaratorId variableDeclaratorId : formalParameter
128 .findChildrenOfType(ASTVariableDeclaratorId.class)) {
129 checkVariableDeclaratorId(parameterPrefixes, parameterSuffixes, node, false, formalParameter.isFinal(),
130 variableDeclaratorId, data);
131 }
132 }
133 return data;
134 }
135
136 private Object checkVariableDeclarators(String[] prefixes, String[] suffixes, Node root, boolean isStatic,
137 boolean isFinal, Object data) {
138 for (ASTVariableDeclarator variableDeclarator : root.findChildrenOfType(ASTVariableDeclarator.class)) {
139 for (ASTVariableDeclaratorId variableDeclaratorId : variableDeclarator
140 .findChildrenOfType(ASTVariableDeclaratorId.class)) {
141 checkVariableDeclaratorId(prefixes, suffixes, root, isStatic, isFinal, variableDeclaratorId, data);
142 }
143 }
144 return data;
145 }
146
147 private Object checkVariableDeclaratorId(String[] prefixes, String[] suffixes, Node root, boolean isStatic,
148 boolean isFinal, ASTVariableDeclaratorId variableDeclaratorId, Object data) {
149
150 // Get the variable name
151 String varName = variableDeclaratorId.getImage();
152
153 // Skip serialVersionUID
154 if (varName.equals("serialVersionUID")) {
155 return data;
156 }
157
158 // Static finals should be uppercase
159 if (isStatic && isFinal) {
160 if (!varName.equals(varName.toUpperCase())) {
161 addViolationWithMessage(data, variableDeclaratorId,
162 "Variables that are final and static should be all capitals, ''{0}'' is not all capitals.",
163 new Object[] { varName });
164 }
165 return data;
166 } else if (!isFinal) {
167 String normalizedVarName = normalizeVariableName(varName, prefixes, suffixes);
168
169 if (normalizedVarName.indexOf('_') >= 0) {
170 addViolationWithMessage(
171 data,
172 variableDeclaratorId,
173 "Only variables that are final should contain underscores (except for underscores in standard prefix/suffix), ''{0}'' is not final.",
174 new Object[] { varName });
175 }
176 if (Character.isUpperCase(varName.charAt(0))) {
177 addViolationWithMessage(data, variableDeclaratorId,
178 "Variables should start with a lowercase character, ''{0}'' starts with uppercase character.",
179 new Object[] { varName });
180 }
181 }
182 return data;
183 }
184
185 private String normalizeVariableName(String varName, String[] prefixes, String[] suffixes) {
186 return stripSuffix(stripPrefix(varName, prefixes), suffixes);
187 }
188
189 private String stripSuffix(String varName, String[] suffixes) {
190 if (suffixes != null) {
191 for (int i = 0; i < suffixes.length; i++) {
192 if (varName.endsWith(suffixes[i])) {
193 varName = varName.substring(0, varName.length() - suffixes[i].length());
194 break;
195 }
196 }
197 }
198 return varName;
199 }
200
201 private String stripPrefix(String varName, String[] prefixes) {
202 if (prefixes != null) {
203 for (int i = 0; i < prefixes.length; i++) {
204 if (varName.startsWith(prefixes[i])) {
205 return varName.substring(prefixes[i].length());
206 }
207 }
208 }
209 return varName;
210 }
211 }
|