1
2
3
4 package net.sourceforge.pmd.lang.java.dfa;
5
6 import java.util.logging.Level;
7 import java.util.logging.Logger;
8
9 import net.sourceforge.pmd.lang.DataFlowHandler;
10 import net.sourceforge.pmd.lang.ast.Node;
11 import net.sourceforge.pmd.lang.dfa.Linker;
12 import net.sourceforge.pmd.lang.dfa.LinkerException;
13 import net.sourceforge.pmd.lang.dfa.NodeType;
14 import net.sourceforge.pmd.lang.dfa.SequenceException;
15 import net.sourceforge.pmd.lang.dfa.Structure;
16 import net.sourceforge.pmd.lang.java.ast.ASTBreakStatement;
17 import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
18 import net.sourceforge.pmd.lang.java.ast.ASTContinueStatement;
19 import net.sourceforge.pmd.lang.java.ast.ASTDoStatement;
20 import net.sourceforge.pmd.lang.java.ast.ASTExpression;
21 import net.sourceforge.pmd.lang.java.ast.ASTForInit;
22 import net.sourceforge.pmd.lang.java.ast.ASTForStatement;
23 import net.sourceforge.pmd.lang.java.ast.ASTForUpdate;
24 import net.sourceforge.pmd.lang.java.ast.ASTIfStatement;
25 import net.sourceforge.pmd.lang.java.ast.ASTLabeledStatement;
26 import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
27 import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement;
28 import net.sourceforge.pmd.lang.java.ast.ASTStatement;
29 import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression;
30 import net.sourceforge.pmd.lang.java.ast.ASTSwitchLabel;
31 import net.sourceforge.pmd.lang.java.ast.ASTSwitchStatement;
32 import net.sourceforge.pmd.lang.java.ast.ASTThrowStatement;
33 import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator;
34 import net.sourceforge.pmd.lang.java.ast.ASTWhileStatement;
35 import net.sourceforge.pmd.lang.java.ast.JavaNode;
36 import net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter;
37
38
39
40
41
42
43
44
45 public class StatementAndBraceFinder extends JavaParserVisitorAdapter {
46 private final static Logger LOGGER = Logger.getLogger(StatementAndBraceFinder.class.getName());
47
48 private final DataFlowHandler dataFlowHandler;
49 private Structure dataFlow;
50
51 public StatementAndBraceFinder(DataFlowHandler dataFlowHandler) {
52 this.dataFlowHandler = dataFlowHandler;
53 }
54
55 public void buildDataFlowFor(JavaNode node) {
56 if (!(node instanceof ASTMethodDeclaration) && !(node instanceof ASTConstructorDeclaration)) {
57 throw new RuntimeException("Can't build a data flow for anything other than a method or a constructor");
58 }
59
60 this.dataFlow = new Structure(dataFlowHandler);
61 this.dataFlow.createStartNode(node.getBeginLine());
62 this.dataFlow.createNewNode(node);
63
64 node.jjtAccept(this, dataFlow);
65
66 this.dataFlow.createEndNode(node.getEndLine());
67 if (LOGGER.isLoggable(Level.FINE)) {
68 LOGGER.fine("DataFlow is " + this.dataFlow.dump() );
69 }
70 Linker linker = new Linker(dataFlowHandler, dataFlow.getBraceStack(), dataFlow.getContinueBreakReturnStack());
71 try {
72 linker.computePaths();
73 } catch (LinkerException e) {
74 e.printStackTrace();
75 } catch (SequenceException e) {
76 e.printStackTrace();
77 }
78 }
79
80 public Object visit(ASTStatementExpression node, Object data) {
81 if (!(data instanceof Structure)) {
82 return data;
83 }
84 Structure dataFlow = (Structure) data;
85 if (LOGGER.isLoggable(Level.FINEST)) {
86 LOGGER.finest("createNewNode ASTStatementExpression: line " + node.getBeginLine() +", column " + node.getBeginColumn());
87 }
88 dataFlow.createNewNode(node);
89 return super.visit(node, data);
90 }
91
92 public Object visit(ASTVariableDeclarator node, Object data) {
93 if (!(data instanceof Structure)) {
94 return data;
95 }
96 Structure dataFlow = (Structure) data;
97 if (LOGGER.isLoggable(Level.FINEST)) {
98 LOGGER.finest("createNewNode ASTVariableDeclarator: line " + node.getBeginLine() +", column " + node.getBeginColumn());
99 }
100 dataFlow.createNewNode(node);
101 return super.visit(node, data);
102 }
103
104 public Object visit(ASTExpression node, Object data) {
105 if (!(data instanceof Structure)) {
106 return data;
107 }
108 Structure dataFlow = (Structure) data;
109
110
111 if (node.jjtGetParent() instanceof ASTIfStatement) {
112 dataFlow.createNewNode(node);
113 dataFlow.pushOnStack(NodeType.IF_EXPR, dataFlow.getLast());
114 if (LOGGER.isLoggable(Level.FINEST)) {
115 LOGGER.finest("pushOnStack parent IF_EXPR: line " + node.getBeginLine() +", column " + node.getBeginColumn());
116 }
117 } else if (node.jjtGetParent() instanceof ASTWhileStatement) {
118 dataFlow.createNewNode(node);
119 dataFlow.pushOnStack(NodeType.WHILE_EXPR, dataFlow.getLast());
120 if (LOGGER.isLoggable(Level.FINEST)) {
121 LOGGER.finest("pushOnStack parent WHILE_EXPR: line " + node.getBeginLine() +", column " + node.getBeginColumn());
122 }
123 } else if (node.jjtGetParent() instanceof ASTSwitchStatement) {
124 dataFlow.createNewNode(node);
125 dataFlow.pushOnStack(NodeType.SWITCH_START, dataFlow.getLast());
126 if (LOGGER.isLoggable(Level.FINEST)) {
127 LOGGER.finest("pushOnStack parent SWITCH_START: line " + node.getBeginLine() +", column " + node.getBeginColumn());
128 }
129 } else if (node.jjtGetParent() instanceof ASTForStatement) {
130 dataFlow.createNewNode(node);
131 dataFlow.pushOnStack(NodeType.FOR_EXPR, dataFlow.getLast());
132 if (LOGGER.isLoggable(Level.FINEST)) {
133 LOGGER.finest("pushOnStack parent FOR_EXPR: line " + node.getBeginLine() +", column " + node.getBeginColumn());
134 }
135 } else if (node.jjtGetParent() instanceof ASTDoStatement) {
136 dataFlow.createNewNode(node);
137 dataFlow.pushOnStack(NodeType.DO_EXPR, dataFlow.getLast());
138 if (LOGGER.isLoggable(Level.FINEST)) {
139 LOGGER.finest("pushOnStack parent DO_EXPR: line " + node.getBeginLine() +", column " + node.getBeginColumn());
140 }
141 }
142
143 return super.visit(node, data);
144 }
145
146 public Object visit(ASTForInit node, Object data) {
147 if (!(data instanceof Structure)) {
148 return data;
149 }
150 Structure dataFlow = (Structure) data;
151 super.visit(node, data);
152 dataFlow.pushOnStack(NodeType.FOR_INIT, dataFlow.getLast());
153 if (LOGGER.isLoggable(Level.FINEST)) {
154 LOGGER.finest("pushOnStack FOR_INIT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
155 }
156 this.addForExpressionNode(node, dataFlow);
157 return data;
158 }
159
160 public Object visit(ASTLabeledStatement node, Object data) {
161 dataFlow.createNewNode(node);
162 dataFlow.pushOnStack(NodeType.LABEL_STATEMENT, dataFlow.getLast());
163 if (LOGGER.isLoggable(Level.FINEST)) {
164 LOGGER.finest("pushOnStack LABEL_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
165 }
166 return super.visit(node, data);
167 }
168
169 public Object visit(ASTForUpdate node, Object data) {
170 if (!(data instanceof Structure)) {
171 return data;
172 }
173 Structure dataFlow = (Structure) data;
174 this.addForExpressionNode(node, dataFlow);
175 super.visit(node, data);
176 dataFlow.pushOnStack(NodeType.FOR_UPDATE, dataFlow.getLast());
177 if (LOGGER.isLoggable(Level.FINEST)) {
178 LOGGER.finest("pushOnStack FOR_UPDATE: line " + node.getBeginLine() +", column " + node.getBeginColumn());
179 }
180 return data;
181 }
182
183
184
185
186 public Object visit(ASTStatement node, Object data) {
187 if (!(data instanceof Structure)) {
188 return data;
189 }
190 Structure dataFlow = (Structure) data;
191
192 if (node.jjtGetParent() instanceof ASTForStatement) {
193 this.addForExpressionNode(node, dataFlow);
194 dataFlow.pushOnStack(NodeType.FOR_BEFORE_FIRST_STATEMENT, dataFlow.getLast());
195 if (LOGGER.isLoggable(Level.FINEST)) {
196 LOGGER.finest("pushOnStack FOR_BEFORE_FIRST_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
197 }
198 } else if (node.jjtGetParent() instanceof ASTDoStatement) {
199 dataFlow.pushOnStack(NodeType.DO_BEFORE_FIRST_STATEMENT, dataFlow.getLast());
200 dataFlow.createNewNode(node.jjtGetParent());
201 if (LOGGER.isLoggable(Level.FINEST)) {
202 LOGGER.finest("pushOnStack DO_BEFORE_FIRST_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
203 }
204 }
205
206 super.visit(node, data);
207
208 if (node.jjtGetParent() instanceof ASTIfStatement) {
209 ASTIfStatement st = (ASTIfStatement) node.jjtGetParent();
210 if (!st.hasElse()) {
211 dataFlow.pushOnStack(NodeType.IF_LAST_STATEMENT_WITHOUT_ELSE, dataFlow.getLast());
212 if (LOGGER.isLoggable(Level.FINEST)) {
213 LOGGER.finest("pushOnStack IF_LAST_STATEMENT_WITHOUT_ELSE: line " + node.getBeginLine() +", column " + node.getBeginColumn());
214 }
215 } else if (st.hasElse() && !st.jjtGetChild(1).equals(node)) {
216 dataFlow.pushOnStack(NodeType.ELSE_LAST_STATEMENT, dataFlow.getLast());
217 if (LOGGER.isLoggable(Level.FINEST)) {
218 LOGGER.finest("pushOnStack ELSE_LAST_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
219 }
220 } else {
221 dataFlow.pushOnStack(NodeType.IF_LAST_STATEMENT, dataFlow.getLast());
222 if (LOGGER.isLoggable(Level.FINEST)) {
223 LOGGER.finest("pushOnStack IF_LAST_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
224 }
225 }
226 } else if (node.jjtGetParent() instanceof ASTWhileStatement) {
227 dataFlow.pushOnStack(NodeType.WHILE_LAST_STATEMENT, dataFlow.getLast());
228 if (LOGGER.isLoggable(Level.FINEST)) {
229 LOGGER.finest("pushOnStack WHILE_LAST_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
230 }
231 } else if (node.jjtGetParent() instanceof ASTForStatement) {
232 dataFlow.pushOnStack(NodeType.FOR_END, dataFlow.getLast());
233 if (LOGGER.isLoggable(Level.FINEST)) {
234 LOGGER.finest("pushOnStack FOR_END: line " + node.getBeginLine() +", column " + node.getBeginColumn());
235 }
236 } else if (node.jjtGetParent() instanceof ASTLabeledStatement) {
237 dataFlow.pushOnStack(NodeType.LABEL_LAST_STATEMENT, dataFlow.getLast());
238 if (LOGGER.isLoggable(Level.FINEST)) {
239 LOGGER.finest("pushOnStack LABEL_LAST_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
240 }
241 }
242 return data;
243 }
244
245 public Object visit(ASTSwitchStatement node, Object data) {
246 if (!(data instanceof Structure)) {
247 return data;
248 }
249 Structure dataFlow = (Structure) data;
250 super.visit(node, data);
251 dataFlow.pushOnStack(NodeType.SWITCH_END, dataFlow.getLast());
252 if (LOGGER.isLoggable(Level.FINEST)) {
253 LOGGER.finest("pushOnStack SWITCH_END: line " + node.getBeginLine() +", column " + node.getBeginColumn());
254 }
255 return data;
256 }
257
258 public Object visit(ASTSwitchLabel node, Object data) {
259 if (!(data instanceof Structure)) {
260 return data;
261 }
262 Structure dataFlow = (Structure) data;
263
264 if (node.jjtGetNumChildren() == 0) {
265 dataFlow.pushOnStack(NodeType.SWITCH_LAST_DEFAULT_STATEMENT, dataFlow.getLast());
266 if (LOGGER.isLoggable(Level.FINEST)) {
267 LOGGER.finest("pushOnStack SWITCH_LAST_DEFAULT_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
268 }
269 } else {
270 dataFlow.pushOnStack(NodeType.CASE_LAST_STATEMENT, dataFlow.getLast());
271 if (LOGGER.isLoggable(Level.FINEST)) {
272 LOGGER.finest("pushOnStack CASE_LAST_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
273 }
274 }
275 return data;
276 }
277
278 public Object visit(ASTBreakStatement node, Object data) {
279 if (!(data instanceof Structure)) {
280 return data;
281 }
282 Structure dataFlow = (Structure) data;
283 dataFlow.createNewNode(node);
284 dataFlow.pushOnStack(NodeType.BREAK_STATEMENT, dataFlow.getLast());
285 if (LOGGER.isLoggable(Level.FINEST)) {
286 LOGGER.finest("pushOnStack BREAK_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
287 }
288 return super.visit(node, data);
289 }
290
291
292 public Object visit(ASTContinueStatement node, Object data) {
293 if (!(data instanceof Structure)) {
294 return data;
295 }
296 Structure dataFlow = (Structure) data;
297 dataFlow.createNewNode(node);
298 dataFlow.pushOnStack(NodeType.CONTINUE_STATEMENT, dataFlow.getLast());
299 if (LOGGER.isLoggable(Level.FINEST)) {
300 LOGGER.finest("pushOnStack CONTINUE_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
301 }
302 return super.visit(node, data);
303 }
304
305 public Object visit(ASTReturnStatement node, Object data) {
306 if (!(data instanceof Structure)) {
307 return data;
308 }
309 Structure dataFlow = (Structure) data;
310 dataFlow.createNewNode(node);
311 dataFlow.pushOnStack(NodeType.RETURN_STATEMENT, dataFlow.getLast());
312 if (LOGGER.isLoggable(Level.FINEST)) {
313 LOGGER.finest("pushOnStack RETURN_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
314 }
315 return super.visit(node, data);
316 }
317
318 public Object visit(ASTThrowStatement node, Object data) {
319 if (!(data instanceof Structure)) {
320 return data;
321 }
322 Structure dataFlow = (Structure) data;
323 dataFlow.createNewNode(node);
324 dataFlow.pushOnStack(NodeType.THROW_STATEMENT, dataFlow.getLast());
325 if (LOGGER.isLoggable(Level.FINEST)) {
326 LOGGER.finest("pushOnStack THROW_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
327 }
328 return super.visit(node, data);
329 }
330
331
332
333
334
335 private void addForExpressionNode(Node node, Structure dataFlow) {
336 ASTForStatement parent = (ASTForStatement) node.jjtGetParent();
337 boolean hasExpressionChild = false;
338 boolean hasForInitNode = false;
339 boolean hasForUpdateNode = false;
340
341 for (int i = 0; i < parent.jjtGetNumChildren(); i++) {
342 if (parent.jjtGetChild(i) instanceof ASTExpression) {
343 hasExpressionChild = true;
344 } else if (parent.jjtGetChild(i) instanceof ASTForUpdate) {
345 hasForUpdateNode = true;
346 } else if (parent.jjtGetChild(i) instanceof ASTForInit) {
347 hasForInitNode = true;
348 }
349 }
350 if (!hasExpressionChild) {
351 if (node instanceof ASTForInit) {
352 dataFlow.createNewNode(node);
353 dataFlow.pushOnStack(NodeType.FOR_EXPR, dataFlow.getLast());
354 if (LOGGER.isLoggable(Level.FINEST)) {
355 LOGGER.finest("pushOnStack FOR_EXPR: line " + node.getBeginLine() +", column " + node.getBeginColumn());
356 }
357 } else if (node instanceof ASTForUpdate) {
358 if (!hasForInitNode) {
359 dataFlow.createNewNode(node);
360 dataFlow.pushOnStack(NodeType.FOR_EXPR, dataFlow.getLast());
361 if (LOGGER.isLoggable(Level.FINEST)) {
362 LOGGER.finest("pushOnStack FOR_EXPR: line " + node.getBeginLine() +", column " + node.getBeginColumn());
363 }
364 }
365 } else if (node instanceof ASTStatement) {
366 if (!hasForInitNode && !hasForUpdateNode) {
367 dataFlow.createNewNode(node);
368 dataFlow.pushOnStack(NodeType.FOR_EXPR, dataFlow.getLast());
369 if (LOGGER.isLoggable(Level.FINEST)) {
370 LOGGER.finest("pushOnStack FOR_EXPR: line " + node.getBeginLine() +", column " + node.getBeginColumn());
371 }
372 }
373 }
374 }
375 }
376 }