View Javadoc

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