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