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