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$
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