View Javadoc

    1   package net.sourceforge.pmd.rules.strings;
    2
    3   import net.sourceforge.pmd.AbstractRule;
    4   import net.sourceforge.pmd.ast.ASTEqualityExpression;
    5   import net.sourceforge.pmd.ast.ASTLiteral;
    6   import net.sourceforge.pmd.ast.ASTPrimitiveType;
    7   import net.sourceforge.pmd.ast.ASTVariableDeclaratorId;
    8   import net.sourceforge.pmd.ast.Node;
    9   import net.sourceforge.pmd.ast.SimpleNode;
    10  import net.sourceforge.pmd.symboltable.NameOccurrence;
    11
    12  import java.util.Iterator;
    13  import java.util.List;
    14
    15  /***
    16   * This rule finds code which inefficiently determines empty strings. This code
    17   * <p/>
    18   * <pre>
    19   *     if(str.trim().length()==0){....
    20   * </pre>
    21   * <p/>
    22   * is quite inefficient as trim() causes a new String to be created. Smarter
    23   * code to check for an empty string would be:
    24   * <p/>
    25   * <pre>
    26   * Character.isWhitespace(str.charAt(i));
    27   * </pre>
    28   *
    29   * @author acaplan
    30   */
    31  public class InefficientEmptyStringCheck extends AbstractRule {
    32
    33      public Object visit(ASTVariableDeclaratorId node, Object data) {
    34          SimpleNode nameNode = node.getTypeNameNode();
    35          if (nameNode instanceof ASTPrimitiveType) {
    36              return data;
    37          }
    38
    39          if (!"String".equals(node.getNameDeclaration().getTypeImage())) {
    40              return data;
    41          }
    42
    43          List declars = node.getUsages();
    44          for (Iterator i = declars.iterator(); i.hasNext();) {
    45              NameOccurrence occ = (NameOccurrence) i.next();
    46              if (!isStringLength(occ)) {
    47                  continue;
    48              }
    49              ASTEqualityExpression equality = (ASTEqualityExpression) occ
    50                      .getLocation().getFirstParentOfType(ASTEqualityExpression.class);
    51              if (equality != null && isCompareZero(equality)) {
    52                  addViolation(data, occ.getLocation());
    53              }
    54          }
    55          return data;
    56      }
    57
    58      /***
    59       * We only need to report if this is comparing against 0
    60       *
    61       * @param equality
    62       * @return true if this is comparing to 0 else false
    63       */
    64      private boolean isCompareZero(ASTEqualityExpression equality) {
    65          return (checkComparison(equality, 0) || checkComparison(equality, 1));
    66
    67      }
    68
    69      /***
    70       * Determine if we're dealing with String.length method
    71       *
    72       * @param occ The name occurance
    73       * @return true if it's String.length, else false
    74       */
    75      private boolean isStringLength(NameOccurrence occ) {
    76          if (occ.getNameForWhichThisIsAQualifier() != null
    77                  && occ.getNameForWhichThisIsAQualifier().getImage().indexOf("trim") != -1) {
    78              Node pExpression = occ.getLocation().jjtGetParent().jjtGetParent();
    79              if (pExpression.jjtGetNumChildren() >= 3
    80                      && "length"
    81                      .equals(((SimpleNode) pExpression.jjtGetChild(2))
    82                      .getImage())) {
    83                  return true;
    84              }
    85          }
    86          return false;
    87      }
    88
    89      /***
    90       * Checks if the equality expression passed in is of comparing against the
    91       * value passed in as i
    92       *
    93       * @param equality
    94       * @param i        The ordinal in the equality expression to check
    95       * @return true if the value in position i is 0, else false
    96       */
    97      private boolean checkComparison(ASTEqualityExpression equality, int i) {
    98          return (equality.jjtGetChild(i).jjtGetChild(0).jjtGetChild(0) instanceof ASTLiteral && "0"
    99                  .equals(((SimpleNode) equality.jjtGetChild(i).jjtGetChild(0)
    100                 .jjtGetChild(0)).getImage()));
    101     }
    102
    103 }