1
2
3
4 package net.sourceforge.pmd.lang.java.rule;
5
6 import java.util.Arrays;
7 import java.util.HashMap;
8 import java.util.List;
9 import java.util.Map;
10
11 import net.sourceforge.pmd.lang.ast.Node;
12 import net.sourceforge.pmd.lang.java.ast.ASTEqualityExpression;
13 import net.sourceforge.pmd.lang.java.ast.ASTLiteral;
14 import net.sourceforge.pmd.lang.java.ast.ASTPrimitiveType;
15 import net.sourceforge.pmd.lang.java.ast.ASTRelationalExpression;
16 import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
17 import net.sourceforge.pmd.lang.java.symboltable.JavaNameOccurrence;
18 import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
19
20
21
22
23
24
25
26
27 public abstract class AbstractInefficientZeroCheck extends AbstractJavaRule {
28
29 public abstract boolean appliesToClassName(String name);
30
31 public abstract boolean isTargetMethod(JavaNameOccurrence occ);
32
33
34
35
36
37 public Map<String, List<String>> getComparisonTargets() {
38 Map<String, List<String>> rules = new HashMap<String, List<String>>();
39 rules.put("==", Arrays.asList("0"));
40 rules.put("!=", Arrays.asList("0"));
41 rules.put(">", Arrays.asList("0"));
42 rules.put("<", Arrays.asList("0"));
43 return rules;
44 }
45
46 private static Map<String, String> inverse = new HashMap<String, String>();
47 static {
48 inverse.put("<", ">");
49 inverse.put(">", "<");
50 inverse.put("<=", ">=");
51 inverse.put(">=", "<=");
52 inverse.put("==", "==");
53 inverse.put("!=", "!=");
54 }
55
56 public Object visit(ASTVariableDeclaratorId node, Object data) {
57 Node nameNode = node.getTypeNameNode();
58 if (nameNode == null
59 || nameNode instanceof ASTPrimitiveType
60 || !appliesToClassName(node.getNameDeclaration().getTypeImage())) {
61 return data;
62 }
63
64 List<NameOccurrence> declars = node.getUsages();
65 for (NameOccurrence occ: declars) {
66 JavaNameOccurrence jocc = (JavaNameOccurrence)occ;
67 if (!isTargetMethod(jocc)) {
68 continue;
69 }
70 Node expr = jocc.getLocation().jjtGetParent().jjtGetParent().jjtGetParent();
71 checkNodeAndReport(data, jocc.getLocation(), expr);
72 }
73 return data;
74 }
75
76
77
78
79
80
81
82
83
84 protected void checkNodeAndReport(Object data, Node location, Node expr) {
85 if ((expr instanceof ASTEqualityExpression
86 || (expr instanceof ASTRelationalExpression
87 && (getComparisonTargets().containsKey(expr.getImage()))))
88 && isCompare(expr)) {
89 addViolation(data, location);
90 }
91 }
92
93
94
95
96
97
98
99
100 private boolean isCompare(Node equality) {
101 if (isLiteralLeftHand(equality)) {
102 return checkComparison(inverse.get(equality.getImage()), equality, 0);
103 } else {
104 return checkComparison(equality.getImage(), equality, 1);
105 }
106 }
107
108 private boolean isLiteralLeftHand(Node equality) {
109 return equality.jjtGetChild(0).jjtGetChild(0).jjtGetNumChildren() > 0
110 && equality.jjtGetChild(0).jjtGetChild(0).jjtGetChild(0) instanceof ASTLiteral;
111 }
112
113
114
115
116
117
118
119
120
121
122
123 private boolean checkComparison(String operator, Node equality, int i) {
124 Node target = equality.jjtGetChild(i).jjtGetChild(0).jjtGetChild(0);
125 return target instanceof ASTLiteral && getComparisonTargets().get(operator).contains(target.getImage());
126 }
127
128 }