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
38 public Map<String, List<String>> getComparisonTargets() {
39 Map<String, List<String>> rules = new HashMap<String, List<String>>();
40 rules.put("==", Arrays.asList("0"));
41 rules.put("!=", Arrays.asList("0"));
42 rules.put(">", Arrays.asList("0"));
43 rules.put("<", Arrays.asList("0"));
44 return rules;
45 }
46
47 private static Map<String, String> inverse = new HashMap<String, String>();
48 static {
49 inverse.put("<", ">");
50 inverse.put(">", "<");
51 inverse.put("<=", ">=");
52 inverse.put(">=", "<=");
53 inverse.put("==", "==");
54 inverse.put("!=", "!=");
55 }
56
57 public Object visit(ASTVariableDeclaratorId node, Object data) {
58 Node nameNode = node.getTypeNameNode();
59 if (nameNode == null || 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
85
86
87 protected void checkNodeAndReport(Object data, Node location, Node expr) {
88 if ((expr instanceof ASTEqualityExpression || expr instanceof ASTRelationalExpression
89 && getComparisonTargets().containsKey(expr.getImage()))
90 && isCompare(expr)) {
91 addViolation(data, location);
92 }
93 }
94
95
96
97
98
99
100
101
102
103
104 private boolean isCompare(Node equality) {
105 if (isLiteralLeftHand(equality)) {
106 return checkComparison(inverse.get(equality.getImage()), equality, 0);
107 } else if (isLiteralRightHand(equality)) {
108 return checkComparison(equality.getImage(), equality, 1);
109 }
110 return false;
111 }
112
113 private boolean isLiteralLeftHand(Node equality) {
114 return isLiteral(equality, 0);
115 }
116
117 private boolean isLiteralRightHand(Node equality) {
118 return isLiteral(equality, 1);
119 }
120
121 private boolean isLiteral(Node equality, int child) {
122 Node target = equality.jjtGetChild(child);
123 target = getFirstChildOrThis(target);
124 target = getFirstChildOrThis(target);
125 return target instanceof ASTLiteral;
126 }
127
128 private Node getFirstChildOrThis(Node node) {
129 if (node.jjtGetNumChildren() > 0) {
130 return node.jjtGetChild(0);
131 }
132 return node;
133 }
134
135
136
137
138
139
140
141
142
143
144
145
146 private boolean checkComparison(String operator, Node equality, int i) {
147 Node target = equality
148 .jjtGetChild(i)
149 .jjtGetChild(0)
150 .jjtGetChild(0);
151 return target instanceof ASTLiteral && getComparisonTargets().get(operator).contains(target.getImage());
152 }
153
154 }