View Javadoc

    1   package net.sourceforge.pmd.rules;
    2
    3   import net.sourceforge.pmd.AbstractRule;
    4   import net.sourceforge.pmd.ast.ASTAdditiveExpression;
    5   import net.sourceforge.pmd.ast.ASTLiteral;
    6   import net.sourceforge.pmd.ast.ASTPrimaryExpression;
    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.List;
    13
    14  /**
    15   * Detects and flags the occurrences of specific method calls against an instance of
    16   * a designated class. I.e. String.indexOf. The goal is to be able to suggest more
    17   * efficient/modern ways of implementing the same function.
    18   *
    19   * Concrete subclasses are expected to provide the name of the target class and an
    20   * array of method names that we are looking for. We then pass judgment on any literal
    21   * arguments we find in the subclass as well.
    22   *
    23   * @author Brian Remedios
    24   * @version $Revision: 6422 $
    25   */
    26  public abstract class AbstractPoorMethodCall extends AbstractRule {
    27
    28
    29      /**
    30       * The name of the type the method will be invoked against.
    31       * @return String
    32       */
    33      protected abstract String targetTypename();
    34
    35      /**
    36       * Return the names of all the methods we are scanning for, no brackets or
    37       * argument types.
    38       *
    39       * @return String[]
    40       */
    41      protected abstract String[] methodNames();
    42
    43      /**
    44       * Returns whether the node being sent to the method is OK or not. Return
    45       * true if you want to record the method call as a violation.
    46       *
    47       * @param arg the node to inspect
    48       * @return boolean
    49       */
    50      protected abstract boolean isViolationArgument(Node arg);
    51
    52      /**
    53       * Returns whether the name occurrence is one of the method calls
    54       * we are interested in.
    55       *
    56       * @param occurrence NameOccurrence
    57       * @return boolean
    58       */
    59      private boolean isNotedMethod(NameOccurrence occurrence) {
    60
    61          if (occurrence == null) return false;
    62
    63          String methodCall = occurrence.getImage();
    64          String[] methodNames = methodNames();
    65
    66          for (int i=0; i<methodNames.length; i++) {
    67              if (methodCall.indexOf(methodNames[i]) != -1) return true;
    68          }
    69          return false;
    70      }
    71
    72      /**
    73       * Method visit.
    74       * @param node ASTVariableDeclaratorId
    75       * @param data Object
    76       * @return Object
    77       * @see net.sourceforge.pmd.ast.JavaParserVisitor#visit(ASTVariableDeclaratorId, Object)
    78       */
    79      public Object visit(ASTVariableDeclaratorId node, Object data) {
    80
    81          if (!node.getNameDeclaration().getTypeImage().equals(targetTypename())) {
    82              return data;
    83          }
    84
    85          for (NameOccurrence occ: node.getUsages()) {
    86              if (isNotedMethod(occ.getNameForWhichThisIsAQualifier())) {
    87                  SimpleNode parent = (SimpleNode)occ.getLocation().jjtGetParent().jjtGetParent();
    88                  if (parent instanceof ASTPrimaryExpression) {
    89                      // bail out if it's something like indexOf("a" + "b")
    90                      List additives = parent.findChildrenOfType(ASTAdditiveExpression.class);
    91                      if (!additives.isEmpty()) {
    92                          return data;
    93                      }
    94                      List literals = parent.findChildrenOfType(ASTLiteral.class);
    95                      for (int l=0; l<literals.size(); l++) {
    96                          ASTLiteral literal = (ASTLiteral)literals.get(l);
    97                          if (isViolationArgument(literal)) {
    98                              addViolation(data, occ.getLocation());
    99                          }
    100                     }
    101                 }
    102             }
    103         }
    104         return data;
    105     }
    106 }
    107