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