View Javadoc

    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              //Get the variable name
    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              // non static final class fields are OK
    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              // static finals (and interface fields, which are implicitly static and final) are
    74              // checked for uppercase
    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 }