001: /**
002: * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
003: */package net.sourceforge.pmd.rules;
004:
005: import java.util.Map;
006:
007: import net.sourceforge.pmd.AbstractRule;
008: import net.sourceforge.pmd.PropertyDescriptor;
009: import net.sourceforge.pmd.ast.ASTClassOrInterfaceDeclaration;
010: import net.sourceforge.pmd.ast.ASTCompilationUnit;
011: import net.sourceforge.pmd.ast.ASTFieldDeclaration;
012: import net.sourceforge.pmd.ast.ASTName;
013: import net.sourceforge.pmd.ast.ASTPrimitiveType;
014: import net.sourceforge.pmd.ast.ASTType;
015: import net.sourceforge.pmd.ast.ASTVariableDeclarator;
016: import net.sourceforge.pmd.ast.ASTVariableDeclaratorId;
017: import net.sourceforge.pmd.properties.StringProperty;
018:
019: public class VariableNamingConventions extends AbstractRule {
020:
021: private String[] staticPrefixes;
022: private String[] staticSuffixes;
023: private String[] memberPrefixes;
024: private String[] memberSuffixes;
025:
026: private static final PropertyDescriptor staticPrefixesDescriptor = new StringProperty(
027: "staticPrefix", "Static prefixes", new String[] { "" },
028: 1.0f, ',');
029:
030: private static final PropertyDescriptor staticSuffixesDescriptor = new StringProperty(
031: "staticSuffix", "Static suffixes", new String[] { "" },
032: 2.0f, ',');
033:
034: private static final PropertyDescriptor memberPrefixesDescriptor = new StringProperty(
035: "memberPrefix", "Member prefixes", new String[] { "" },
036: 3.0f, ',');
037:
038: private static final PropertyDescriptor memberSuffixesDescriptor = new StringProperty(
039: "memberSuffix", "Member suffixes", new String[] { "" },
040: 4.0f, ',');
041:
042: private static final Map<String, PropertyDescriptor> propertyDescriptorsByName = asFixedMap(new PropertyDescriptor[] {
043: staticPrefixesDescriptor, staticSuffixesDescriptor,
044: memberPrefixesDescriptor, memberSuffixesDescriptor });
045:
046: /**
047: * @return Map
048: */
049: protected Map<String, PropertyDescriptor> propertiesByName() {
050: return propertyDescriptorsByName;
051: }
052:
053: public Object visit(ASTCompilationUnit node, Object data) {
054: init();
055: return super .visit(node, data);
056: }
057:
058: protected void init() {
059: staticPrefixes = getStringProperties(staticPrefixesDescriptor);
060: staticSuffixes = getStringProperties(staticSuffixesDescriptor);
061: memberPrefixes = getStringProperties(memberPrefixesDescriptor);
062: memberSuffixes = getStringProperties(memberSuffixesDescriptor);
063: }
064:
065: public Object visit(ASTFieldDeclaration node, Object data) {
066: return checkNames(node, data);
067: }
068:
069: private Object checkNames(ASTFieldDeclaration node, Object data) {
070: ASTType childNodeType = (ASTType) node.jjtGetChild(0);
071: String varType = "";
072: if (childNodeType.jjtGetChild(0) instanceof ASTName) {
073: varType = ((ASTName) childNodeType.jjtGetChild(0))
074: .getImage();
075: } else if (childNodeType.jjtGetChild(0) instanceof ASTPrimitiveType) {
076: varType = ((ASTPrimitiveType) childNodeType.jjtGetChild(0))
077: .getImage();
078: }
079: if (varType != null && varType.length() > 0) {
080: //Get the variable name
081: ASTVariableDeclarator childNodeName = (ASTVariableDeclarator) node
082: .jjtGetChild(1);
083: ASTVariableDeclaratorId childNodeId = (ASTVariableDeclaratorId) childNodeName
084: .jjtGetChild(0);
085: String varName = childNodeId.getImage();
086:
087: if (varName.equals("serialVersionUID")
088: || (node.isFinal() && !node.isStatic() && !node
089: .isInterfaceMember())) {
090: return data;
091: }
092:
093: // static finals (and interface fields, which are implicitly static and final) are
094: // checked for uppercase
095: if ((node.isStatic() && node.isFinal())
096: || (node.jjtGetParent().jjtGetParent()
097: .jjtGetParent() instanceof ASTClassOrInterfaceDeclaration && ((ASTClassOrInterfaceDeclaration) node
098: .jjtGetParent().jjtGetParent()
099: .jjtGetParent()).isInterface())) {
100: if (!varName.equals(varName.toUpperCase())) {
101: addViolationWithMessage(data, childNodeName,
102: "Variables that are final and static should be in all caps.");
103: }
104: return data;
105: }
106:
107: String strippedVarName = null;
108: if (node.isStatic()) {
109: strippedVarName = normalizeStaticVariableName(varName);
110: } else {
111: strippedVarName = normalizeMemberVariableName(varName);
112: }
113:
114: if (strippedVarName.indexOf('_') >= 0) {
115: addViolationWithMessage(
116: data,
117: childNodeName,
118: "Variables that are not final should not contain underscores (except for underscores in standard prefix/suffix).");
119: }
120: if (Character.isUpperCase(varName.charAt(0))) {
121: addViolationWithMessage(data, childNodeName,
122: "Variables should start with a lowercase character");
123: }
124: }
125: return data;
126: }
127:
128: private String normalizeMemberVariableName(String varName) {
129: return stripSuffix(stripPrefix(varName, memberPrefixes),
130: memberSuffixes);
131: }
132:
133: private String normalizeStaticVariableName(String varName) {
134: return stripSuffix(stripPrefix(varName, staticPrefixes),
135: staticSuffixes);
136: }
137:
138: private String stripSuffix(String varName, String[] suffix) {
139: if (suffix != null) {
140: for (int i = 0; i < suffix.length; i++) {
141: if (varName.endsWith(suffix[i])) {
142: varName = varName.substring(0, varName.length()
143: - suffix[i].length());
144: break;
145: }
146: }
147: }
148: return varName;
149: }
150:
151: private String stripPrefix(String varName, String[] prefix) {
152: if (prefix == null) {
153: return varName;
154: }
155: for (int i = 0; i < prefix.length; i++) {
156: if (varName.startsWith(prefix[i])) {
157: return varName.substring(prefix[i].length());
158: }
159: }
160: return varName;
161: }
162: }
|