1
2
3
4 package net.sourceforge.pmd.lang.java.rule.design;
5
6 import net.sourceforge.pmd.lang.ast.Node;
7 import net.sourceforge.pmd.lang.java.ast.ASTBlock;
8 import net.sourceforge.pmd.lang.java.ast.ASTBlockStatement;
9 import net.sourceforge.pmd.lang.java.ast.ASTBooleanLiteral;
10 import net.sourceforge.pmd.lang.java.ast.ASTIfStatement;
11 import net.sourceforge.pmd.lang.java.ast.ASTLiteral;
12 import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
13 import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
14 import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;
15 import net.sourceforge.pmd.lang.java.ast.ASTPrimitiveType;
16 import net.sourceforge.pmd.lang.java.ast.ASTResultType;
17 import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement;
18 import net.sourceforge.pmd.lang.java.ast.ASTStatement;
19 import net.sourceforge.pmd.lang.java.ast.ASTUnaryExpressionNotPlusMinus;
20 import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
21
22 public class SimplifyBooleanReturnsRule extends AbstractJavaRule {
23
24 public Object visit(ASTMethodDeclaration node, Object data) {
25
26 ASTResultType r = node.getResultType();
27
28 if (!r.isVoid()) {
29 Node t = r.jjtGetChild(0);
30 if (t.jjtGetNumChildren() == 1) {
31 t = t.jjtGetChild(0);
32 if ((t instanceof ASTPrimitiveType) && ((ASTPrimitiveType) t).isBoolean()) {
33 return super.visit(node, data);
34 }
35 }
36 }
37
38 return data;
39 }
40
41 public Object visit(ASTIfStatement node, Object data) {
42
43 if (node.jjtGetNumChildren() != 3) {
44 return super.visit(node, data);
45 }
46
47
48 if (node.jjtGetChild(1).jjtGetNumChildren() == 0 || node.jjtGetChild(2).jjtGetNumChildren() == 0) {
49 return super.visit(node, data);
50 }
51
52
53
54 if (false &&
55 node.jjtGetChild(0).jjtGetChild(0) instanceof ASTPrimaryExpression &&
56 node.jjtGetChild(0).jjtGetChild(0).jjtGetChild(0) instanceof ASTPrimaryPrefix &&
57 node.jjtGetChild(0).jjtGetChild(0).jjtGetChild(0).jjtGetChild(0) instanceof ASTLiteral &&
58 node.jjtGetChild(0).jjtGetChild(0).jjtGetChild(0).jjtGetChild(0).jjtGetChild(0) instanceof ASTBooleanLiteral) {
59 addViolation(data, node);
60 }
61 else {
62 Node returnStatement1 = node.jjtGetChild(1).jjtGetChild(0);
63 Node returnStatement2 = node.jjtGetChild(2).jjtGetChild(0);
64
65 if (returnStatement1 instanceof ASTReturnStatement && returnStatement2 instanceof ASTReturnStatement) {
66
67 if(isSimpleReturn(returnStatement1) && isSimpleReturn(returnStatement2)) {
68
69
70
71
72
73
74
75
76
77
78
79
80 addViolation(data, node);
81 }
82 else {
83 Node expression1 = returnStatement1.jjtGetChild(0).jjtGetChild(0);
84 Node expression2 = returnStatement2.jjtGetChild(0).jjtGetChild(0);
85 if(terminatesInBooleanLiteral(returnStatement1) && terminatesInBooleanLiteral(returnStatement2)) {
86 addViolation(data, node);
87 }
88 else if (expression1 instanceof ASTUnaryExpressionNotPlusMinus ^ expression2 instanceof ASTUnaryExpressionNotPlusMinus) {
89
90
91 if(isNodesEqualWithUnaryExpression(expression1, expression2)) {
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107 addViolation(data, node);
108 }
109 }
110 }
111 } else if (hasOneBlockStmt(node.jjtGetChild(1)) && hasOneBlockStmt(node.jjtGetChild(2))) {
112
113 returnStatement1 = returnStatement1.jjtGetChild(0).jjtGetChild(0).jjtGetChild(0);
114 returnStatement2 = returnStatement2.jjtGetChild(0).jjtGetChild(0).jjtGetChild(0);
115
116
117 if(isSimpleReturn(returnStatement1) && isSimpleReturn(returnStatement2)) {
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137 addViolation(data, node);
138 }
139 else {
140 Node expression1 = getDescendant(returnStatement1, 4);
141 Node expression2 = getDescendant(returnStatement2, 4);
142 if(terminatesInBooleanLiteral(node.jjtGetChild(1).jjtGetChild(0)) && terminatesInBooleanLiteral(node.jjtGetChild(2).jjtGetChild(0))) {
143 addViolation(data, node);
144 } else if (expression1 instanceof ASTUnaryExpressionNotPlusMinus ^ expression2 instanceof ASTUnaryExpressionNotPlusMinus) {
145
146
147 if(isNodesEqualWithUnaryExpression(expression1, expression2)) {
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170 addViolation(data, node);
171 }
172 }
173 }
174 }
175 }
176 return super.visit(node, data);
177 }
178
179 private boolean hasOneBlockStmt(Node node) {
180 return node.jjtGetChild(0) instanceof ASTBlock && node.jjtGetChild(0).jjtGetNumChildren() == 1 && node.jjtGetChild(0).jjtGetChild(0) instanceof ASTBlockStatement && node.jjtGetChild(0).jjtGetChild(0).jjtGetChild(0) instanceof ASTStatement && node.jjtGetChild(0).jjtGetChild(0).jjtGetChild(0).jjtGetChild(0) instanceof ASTReturnStatement;
181 }
182
183
184
185
186 private Node getDescendant(Node node, int level) {
187 Node n = node;
188 for(int i = 0; i < level; i++) {
189 if (n.jjtGetNumChildren() == 0) {
190 return null;
191 }
192 n = n.jjtGetChild(0);
193 }
194 return n;
195 }
196
197 private boolean terminatesInBooleanLiteral(Node node) {
198
199 return eachNodeHasOneChild(node) && (getLastChild(node) instanceof ASTBooleanLiteral);
200 }
201
202 private boolean eachNodeHasOneChild(Node node) {
203 if (node.jjtGetNumChildren() > 1) {
204 return false;
205 }
206 if (node.jjtGetNumChildren() == 0) {
207 return true;
208 }
209 return eachNodeHasOneChild(node.jjtGetChild(0));
210 }
211
212 private Node getLastChild(Node node) {
213 if (node.jjtGetNumChildren() == 0) {
214 return node;
215 }
216 return getLastChild(node.jjtGetChild(0));
217 }
218
219 private boolean isNodesEqualWithUnaryExpression(Node n1, Node n2) {
220 Node node1;
221 Node node2;
222 if(n1 instanceof ASTUnaryExpressionNotPlusMinus) {
223 node1 = n1.jjtGetChild(0);
224 } else {
225 node1 = n1;
226 }
227 if(n2 instanceof ASTUnaryExpressionNotPlusMinus) {
228 node2 = n2.jjtGetChild(0);
229 } else {
230 node2 = n2;
231 }
232 return isNodesEquals(node1, node2);
233 }
234
235 private boolean isNodesEquals(Node n1, Node n2) {
236 int numberChild1 = n1.jjtGetNumChildren();
237 int numberChild2 = n2.jjtGetNumChildren();
238 if(numberChild1 != numberChild2) {
239 return false;
240 }
241 if(!n1.getClass().equals(n2.getClass())) {
242 return false;
243 }
244 if(!n1.toString().equals(n2.toString())) {
245 return false;
246 }
247 for(int i = 0 ; i < numberChild1 ; i++) {
248 if( !isNodesEquals(n1.jjtGetChild(i), n2.jjtGetChild(i) ) ) {
249 return false;
250 }
251 }
252 return true;
253 }
254
255 private boolean isSimpleReturn(Node node) {
256 return node instanceof ASTReturnStatement && node.jjtGetNumChildren() == 0;
257 }
258
259 }