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