View Javadoc

1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.lang.java.rule;
5   
6   import java.util.List;
7   
8   import net.sourceforge.pmd.lang.ast.Node;
9   import net.sourceforge.pmd.lang.java.ast.ASTEqualityExpression;
10  import net.sourceforge.pmd.lang.java.ast.ASTLiteral;
11  import net.sourceforge.pmd.lang.java.ast.ASTPrimitiveType;
12  import net.sourceforge.pmd.lang.java.ast.ASTRelationalExpression;
13  import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
14  import net.sourceforge.pmd.lang.java.symboltable.JavaNameOccurrence;
15  import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
16  
17  /**
18   * This is an abstract rule for patterns which compare a method invocation to 0.
19   * It could be further abstracted to find code that compares something to
20   * another definable pattern
21   * 
22   * @author acaplan
23   */
24  public abstract class AbstractInefficientZeroCheck extends AbstractJavaRule {
25  
26      public abstract boolean appliesToClassName(String name);
27  
28      public abstract boolean isTargetMethod(JavaNameOccurrence occ);
29  
30      public Object visit(ASTVariableDeclaratorId node, Object data) {
31          Node nameNode = node.getTypeNameNode();
32          if (nameNode == null
33              || nameNode instanceof ASTPrimitiveType
34              || !appliesToClassName(node.getNameDeclaration().getTypeImage())) {
35              return data;
36          }
37  
38          List<NameOccurrence> declars = node.getUsages();
39          for (NameOccurrence occ: declars) {
40              JavaNameOccurrence jocc = (JavaNameOccurrence)occ;
41              if (!isTargetMethod(jocc)) {
42                  continue;
43              }
44              Node expr = jocc.getLocation().jjtGetParent().jjtGetParent().jjtGetParent();
45              if ((expr instanceof ASTEqualityExpression ||
46                      (expr instanceof ASTRelationalExpression && ">".equals(expr.getImage())))
47                  && isCompareZero(expr)) {
48                  addViolation(data, jocc.getLocation());
49              }
50          }
51          return data;
52      }
53  
54      /**
55       * We only need to report if this is comparing against 0
56       * 
57       * @param equality
58       * @return true if this is comparing to 0 else false
59       */
60      private boolean isCompareZero(Node equality) {
61          return checkComparison(equality, 0) || checkComparison(equality, 1);
62  
63      }
64  
65      /**
66       * Checks if the equality expression passed in is of comparing against the
67       * value passed in as i
68       * 
69       * @param equality
70       * @param i
71       *            The ordinal in the equality expression to check
72       * @return true if the value in position i is 0, else false
73       */
74      private boolean checkComparison(Node equality, int i) {
75  	Node target = equality.jjtGetChild(i).jjtGetChild(0);
76          if (target.jjtGetNumChildren() == 0) {
77              return false;
78          }
79          target = target.jjtGetChild(0);
80          return target instanceof ASTLiteral && "0".equals(target.getImage());
81      }
82  
83  }