View Javadoc
1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.lang.plsql.dfa;
5   
6   import java.util.List;
7   import java.util.logging.Level;
8   import java.util.logging.Logger;
9   
10  import net.sourceforge.pmd.lang.DataFlowHandler;
11  import net.sourceforge.pmd.lang.ast.Node;
12  import net.sourceforge.pmd.lang.dfa.Linker;
13  import net.sourceforge.pmd.lang.dfa.LinkerException;
14  import net.sourceforge.pmd.lang.dfa.NodeType;
15  import net.sourceforge.pmd.lang.dfa.SequenceException;
16  import net.sourceforge.pmd.lang.dfa.Structure;
17  import net.sourceforge.pmd.lang.plsql.ast.ASTCaseStatement;
18  import net.sourceforge.pmd.lang.plsql.ast.ASTCaseWhenClause;
19  import net.sourceforge.pmd.lang.plsql.ast.ASTCloseStatement;
20  import net.sourceforge.pmd.lang.plsql.ast.ASTContinueStatement;
21  import net.sourceforge.pmd.lang.plsql.ast.ASTElseClause;
22  import net.sourceforge.pmd.lang.plsql.ast.ASTElsifClause;
23  import net.sourceforge.pmd.lang.plsql.ast.ASTEmbeddedSqlStatement;
24  import net.sourceforge.pmd.lang.plsql.ast.ASTExitStatement;
25  import net.sourceforge.pmd.lang.plsql.ast.ASTExpression;
26  import net.sourceforge.pmd.lang.plsql.ast.ASTFetchStatement;
27  import net.sourceforge.pmd.lang.plsql.ast.ASTForStatement;
28  import net.sourceforge.pmd.lang.plsql.ast.ASTGotoStatement;
29  import net.sourceforge.pmd.lang.plsql.ast.ASTIfStatement;
30  import net.sourceforge.pmd.lang.plsql.ast.ASTLabelledStatement;
31  import net.sourceforge.pmd.lang.plsql.ast.ASTLoopStatement;
32  import net.sourceforge.pmd.lang.plsql.ast.ASTMethodDeclaration;
33  import net.sourceforge.pmd.lang.plsql.ast.ASTOpenStatement;
34  import net.sourceforge.pmd.lang.plsql.ast.ASTPipelineStatement;
35  import net.sourceforge.pmd.lang.plsql.ast.ASTProgramUnit;
36  import net.sourceforge.pmd.lang.plsql.ast.ASTRaiseStatement;
37  import net.sourceforge.pmd.lang.plsql.ast.ASTReturnStatement;
38  import net.sourceforge.pmd.lang.plsql.ast.ASTSqlStatement;
39  import net.sourceforge.pmd.lang.plsql.ast.ASTStatement;
40  import net.sourceforge.pmd.lang.plsql.ast.ASTTriggerTimingPointSection;
41  import net.sourceforge.pmd.lang.plsql.ast.ASTTriggerUnit;
42  import net.sourceforge.pmd.lang.plsql.ast.ASTTypeMethod;
43  import net.sourceforge.pmd.lang.plsql.ast.ASTUnlabelledStatement;
44  import net.sourceforge.pmd.lang.plsql.ast.ASTVariableOrConstantDeclarator;
45  import net.sourceforge.pmd.lang.plsql.ast.ASTWhileStatement;
46  import net.sourceforge.pmd.lang.plsql.ast.PLSQLNode;
47  import net.sourceforge.pmd.lang.plsql.ast.PLSQLParserVisitorAdapter;
48  
49  /**
50   * @author raik
51   *         <p/>
52   *         Sublayer of DataFlowFacade. Finds all data flow nodes and stores the
53   *         type information (@see StackObject). At last it uses this information
54   *         to link the nodes.
55   */
56  public class StatementAndBraceFinder extends PLSQLParserVisitorAdapter {
57      private final static Logger LOGGER = Logger.getLogger(StatementAndBraceFinder.class.getName());
58  
59      private final DataFlowHandler dataFlowHandler;
60      private Structure dataFlow;
61  
62      public StatementAndBraceFinder(DataFlowHandler dataFlowHandler) {
63          this.dataFlowHandler = dataFlowHandler;
64      }
65  
66      public void buildDataFlowFor(PLSQLNode node) {
67          LOGGER.entering(this.getClass().getCanonicalName(), "buildDataFlowFor");
68          if (LOGGER.isLoggable(Level.FINEST)) {
69              LOGGER.finest("buildDataFlowFor: node class " + node.getClass().getCanonicalName() + " @ line "
70                      + node.getBeginLine() + ", column " + node.getBeginColumn() + " --- "
71                      + new Throwable().getStackTrace());
72          }
73          if (!(node instanceof ASTMethodDeclaration) && !(node instanceof ASTProgramUnit)
74                  && !(node instanceof ASTTypeMethod) && !(node instanceof ASTTriggerUnit)
75                  && !(node instanceof ASTTriggerTimingPointSection)) {
76              throw new RuntimeException("Can't build a data flow for anything other than a Method or a Trigger");
77          }
78  
79          this.dataFlow = new Structure(dataFlowHandler);
80          this.dataFlow.createStartNode(node.getBeginLine());
81          this.dataFlow.createNewNode(node);
82  
83          node.jjtAccept(this, dataFlow);
84  
85          this.dataFlow.createEndNode(node.getEndLine());
86  
87          if (LOGGER.isLoggable(Level.FINE)) {
88              LOGGER.fine("DataFlow is " + this.dataFlow.dump());
89          }
90          Linker linker = new Linker(dataFlowHandler, dataFlow.getBraceStack(), dataFlow.getContinueBreakReturnStack());
91          try {
92              linker.computePaths();
93          } catch (LinkerException e) {
94              LOGGER.severe("LinkerException");
95              e.printStackTrace();
96          } catch (SequenceException e) {
97              LOGGER.severe("SequenceException");
98              e.printStackTrace();
99          }
100         LOGGER.exiting(this.getClass().getCanonicalName(), "buildDataFlowFor");
101     }
102 
103     public Object visit(ASTSqlStatement node, Object data) {
104         if (!(data instanceof Structure)) {
105             if (LOGGER.isLoggable(Level.FINEST)) {
106                 LOGGER.finest("immediate return ASTSqlStatement: line " + node.getBeginLine() + ", column "
107                         + node.getBeginColumn());
108             }
109             return data;
110         }
111         Structure dataFlow = (Structure) data;
112         dataFlow.createNewNode(node);
113         if (LOGGER.isLoggable(Level.FINEST)) {
114             LOGGER.finest("createNewNode ASTSqlStatement: line " + node.getBeginLine() + ", column "
115                     + node.getBeginColumn());
116         }
117         return super.visit(node, data);
118     }
119 
120     public Object visit(ASTEmbeddedSqlStatement node, Object data) {
121         if (!(data instanceof Structure)) {
122             if (LOGGER.isLoggable(Level.FINEST)) {
123                 LOGGER.finest("immediate return ASTEmbeddedSqlStatement: line " + node.getBeginLine() + ", column "
124                         + node.getBeginColumn());
125             }
126             return data;
127         }
128         Structure dataFlow = (Structure) data;
129         dataFlow.createNewNode(node);
130         if (LOGGER.isLoggable(Level.FINEST)) {
131             LOGGER.finest("createNewNode ASTEmbeddedSqlStatement: line " + node.getBeginLine() + ", column "
132                     + node.getBeginColumn());
133         }
134         return super.visit(node, data);
135     }
136 
137     public Object visit(ASTCloseStatement node, Object data) {
138         if (!(data instanceof Structure)) {
139             return data;
140         }
141         Structure dataFlow = (Structure) data;
142         dataFlow.createNewNode(node);
143         if (LOGGER.isLoggable(Level.FINEST)) {
144             LOGGER.finest("createNewNode ASTCloseStatement: line " + node.getBeginLine() + ", column "
145                     + node.getBeginColumn());
146         }
147         return super.visit(node, data);
148     }
149 
150     public Object visit(ASTOpenStatement node, Object data) {
151         if (!(data instanceof Structure)) {
152             return data;
153         }
154         Structure dataFlow = (Structure) data;
155         dataFlow.createNewNode(node);
156         if (LOGGER.isLoggable(Level.FINEST)) {
157             LOGGER.finest("createNewNode ASTOpenStatement: line " + node.getBeginLine() + ", column "
158                     + node.getBeginColumn());
159         }
160         return super.visit(node, data);
161     }
162 
163     public Object visit(ASTFetchStatement node, Object data) {
164         if (!(data instanceof Structure)) {
165             return data;
166         }
167         Structure dataFlow = (Structure) data;
168         dataFlow.createNewNode(node);
169         if (LOGGER.isLoggable(Level.FINEST)) {
170             LOGGER.finest("createNewNode ASTFetchStatement: line " + node.getBeginLine() + ", column "
171                     + node.getBeginColumn());
172         }
173         return super.visit(node, data);
174     }
175 
176     public Object visit(ASTPipelineStatement node, Object data) {
177         if (!(data instanceof Structure)) {
178             return data;
179         }
180         Structure dataFlow = (Structure) data;
181         dataFlow.createNewNode(node);
182         if (LOGGER.isLoggable(Level.FINEST)) {
183             LOGGER.finest("createNewNode ASTPipelineStatement: line " + node.getBeginLine() + ", column "
184                     + node.getBeginColumn());
185         }
186         return super.visit(node, data);
187     }
188 
189     /* */
190 
191     public Object visit(ASTVariableOrConstantDeclarator node, Object data) {
192         if (!(data instanceof Structure)) {
193             return data;
194         }
195         Structure dataFlow = (Structure) data;
196         dataFlow.createNewNode(node);
197         if (LOGGER.isLoggable(Level.FINEST)) {
198             LOGGER.finest("createNewNode ASTVariableOrConstantDeclarator: line " + node.getBeginLine() + ", column "
199                     + node.getBeginColumn());
200         }
201         return super.visit(node, data);
202     }
203 
204     public Object visit(ASTExpression node, Object data) {
205         if (LOGGER.isLoggable(Level.FINEST)) {
206             LOGGER.finest("Entry ASTExpression: line " + node.getBeginLine() + ", column " + node.getBeginColumn());
207         }
208         if (!(data instanceof Structure)) {
209             if (LOGGER.isLoggable(Level.FINEST)) {
210                 LOGGER.finest("immediate return ASTExpression: line " + node.getBeginLine() + ", column "
211                         + node.getBeginColumn());
212             }
213             return data;
214         }
215         Structure dataFlow = (Structure) data;
216 
217         // The equivalent of an ASTExpression is an Expression whose parent is
218         // an UnLabelledStatement
219         if (node.jjtGetParent() instanceof ASTUnlabelledStatement) {
220             if (LOGGER.isLoggable(Level.FINEST)) {
221                 LOGGER.finest("createNewNode ASTSUnlabelledStatement: line " + node.getBeginLine() + ", column "
222                         + node.getBeginColumn());
223             }
224             dataFlow.createNewNode(node);
225         } else
226         // TODO what about throw stmts?
227         if (node.jjtGetParent() instanceof ASTIfStatement) {
228             dataFlow.createNewNode(node); // START IF
229             dataFlow.pushOnStack(NodeType.IF_EXPR, dataFlow.getLast());
230             if (LOGGER.isLoggable(Level.FINEST)) {
231                 LOGGER.finest("pushOnStack parent IF_EXPR: line " + node.getBeginLine() + ", column "
232                         + node.getBeginColumn());
233             }
234         } else if (node.jjtGetParent() instanceof ASTElsifClause) {
235             if (LOGGER.isLoggable(Level.FINEST)) {
236                 LOGGER.finest("parent (Elsif) IF_EXPR at  " + node.getBeginLine() + ", column " + node.getBeginColumn());
237             }
238             dataFlow.createNewNode(node); // START IF
239             dataFlow.pushOnStack(NodeType.IF_EXPR, dataFlow.getLast());
240             if (LOGGER.isLoggable(Level.FINEST)) {
241                 LOGGER.finest("pushOnStack parent (Elsif) IF_EXPR: line " + node.getBeginLine() + ", column "
242                         + node.getBeginColumn());
243             }
244         } else if (node.jjtGetParent() instanceof ASTWhileStatement) {
245             dataFlow.createNewNode(node); // START WHILE
246             dataFlow.pushOnStack(NodeType.WHILE_EXPR, dataFlow.getLast());
247             if (LOGGER.isLoggable(Level.FINEST)) {
248                 LOGGER.finest("pushOnStack parent WHILE_EXPR: line " + node.getBeginLine() + ", column "
249                         + node.getBeginColumn());
250             }
251         } else if (node.jjtGetParent() instanceof ASTCaseStatement) {
252             dataFlow.createNewNode(node); // START SWITCH
253             dataFlow.pushOnStack(NodeType.SWITCH_START, dataFlow.getLast());
254             if (LOGGER.isLoggable(Level.FINEST)) {
255                 LOGGER.finest("pushOnStack parent SWITCH_START: line " + node.getBeginLine() + ", column "
256                         + node.getBeginColumn());
257             }
258         } else if (node.jjtGetParent() instanceof ASTForStatement) {
259             /*
260              * A PL/SQL loop control: [<REVERSE>] Expression()[".."Expression()]
261              */
262             if (node.equals(node.jjtGetParent().getFirstChildOfType(ASTExpression.class))) {
263                 dataFlow.createNewNode(node); // FOR EXPR
264                 dataFlow.pushOnStack(NodeType.FOR_EXPR, dataFlow.getLast());
265                 if (LOGGER.isLoggable(Level.FINEST)) {
266                     LOGGER.finest("pushOnStack parent FOR_EXPR: line " + node.getBeginLine() + ", column "
267                             + node.getBeginColumn());
268                 }
269             }
270             if (LOGGER.isLoggable(Level.FINEST)) {
271                 LOGGER.finest("parent (ASTForStatement): line " + node.getBeginLine() + ", column "
272                         + node.getBeginColumn());
273             }
274         } else if (node.jjtGetParent() instanceof ASTLoopStatement) {
275             dataFlow.createNewNode(node); // DO EXPR
276             dataFlow.pushOnStack(NodeType.DO_EXPR, dataFlow.getLast());
277             if (LOGGER.isLoggable(Level.FINEST)) {
278                 LOGGER.finest("pushOnStack parent DO_EXPR: line " + node.getBeginLine() + ", column "
279                         + node.getBeginColumn());
280             }
281         }
282 
283         return super.visit(node, data);
284     }
285 
286     public Object visit(ASTLabelledStatement node, Object data) {
287         dataFlow.createNewNode(node);
288         dataFlow.pushOnStack(NodeType.LABEL_STATEMENT, dataFlow.getLast());
289         if (LOGGER.isLoggable(Level.FINEST)) {
290             LOGGER.finest("pushOnStack LABEL_STATEMENT: line " + node.getBeginLine() + ", column "
291                     + node.getBeginColumn());
292         }
293         return super.visit(node, data);
294     }
295 
296     /**
297      * PL/SQL does not have a do/while statement or repeat/until statement: the
298      * equivalent is a LOOP statement. A PL/SQL LOOP statement is exited using
299      * an explicit EXIT ( == break;) statement It does not have a test
300      * expression, so the Java control processing (on the expression) does not
301      * fire. The best way to cope it to push a DO_EXPR after the loop.
302      */
303     public Object visit(ASTLoopStatement node, Object data) {
304         if (LOGGER.isLoggable(Level.FINEST)) {
305             LOGGER.finest("entry ASTLoopStatement: line " + node.getBeginLine() + ", column " + node.getBeginColumn());
306         }
307         if (!(data instanceof Structure)) {
308             if (LOGGER.isLoggable(Level.FINEST)) {
309                 LOGGER.finest("immediate return ASTLoopStatement: line " + node.getBeginLine() + ", column "
310                         + node.getBeginColumn());
311             }
312             return data;
313         }
314         Structure dataFlow = (Structure) data;
315 
316         // process the contents on the LOOP statement
317         super.visit(node, data);
318 
319         dataFlow.createNewNode(node);
320         dataFlow.pushOnStack(NodeType.DO_EXPR, dataFlow.getLast());
321         if (LOGGER.isLoggable(Level.FINEST)) {
322             LOGGER.finest("pushOnStack (ASTLoopStatement) DO_EXPR: line " + node.getBeginLine() + ", column "
323                     + node.getBeginColumn());
324         }
325         return data;
326     }
327 
328     /**
329      * A PL/SQL WHILE statement includes the LOOP statement and all Expressions
330      * within it: it does not have a single test expression, so the Java control
331      * processing (on the Expression) fires for each Expression in the LOOP. The
332      * best way to cope it to push a WHILE_LAST_STATEMENT after the
333      * WhileStatement has been processed.
334      */
335     public Object visit(ASTWhileStatement node, Object data) {
336         if (LOGGER.isLoggable(Level.FINEST)) {
337             LOGGER.finest("entry ASTWhileStatement: line " + node.getBeginLine() + ", column " + node.getBeginColumn());
338         }
339         if (!(data instanceof Structure)) {
340             if (LOGGER.isLoggable(Level.FINEST)) {
341                 LOGGER.finest("immediate return ASTWhileStatement: line " + node.getBeginLine() + ", column "
342                         + node.getBeginColumn());
343             }
344             return data;
345         }
346 
347         // process the contents on the WHILE statement
348         super.visit(node, data);
349 
350         return data;
351     }
352 
353     // ----------------------------------------------------------------------------
354     // BRANCH OUT
355 
356     public Object visit(ASTStatement node, Object data) {
357         if (LOGGER.isLoggable(Level.FINEST)) {
358             LOGGER.finest("entry ASTStatement: line " + node.getBeginLine() + ", column " + node.getBeginColumn()
359                     + " -> " + node.getClass().getCanonicalName());
360         }
361         if (!(data instanceof Structure)) {
362             if (LOGGER.isLoggable(Level.FINEST)) {
363                 LOGGER.finest("immediate return ASTStatement: line " + node.getBeginLine() + ", column "
364                         + node.getBeginColumn());
365             }
366             return data;
367         }
368         Structure dataFlow = (Structure) data;
369 
370         if (node.jjtGetParent() instanceof ASTForStatement) {
371             ASTForStatement st = (ASTForStatement) node.jjtGetParent();
372             if (node.equals(st.getFirstChildOfType(ASTStatement.class))) {
373                 addForExpressionNode(node, dataFlow);
374                 dataFlow.pushOnStack(NodeType.FOR_BEFORE_FIRST_STATEMENT, dataFlow.getLast());
375                 if (LOGGER.isLoggable(Level.FINEST)) {
376                     LOGGER.finest("pushOnStack FOR_BEFORE_FIRST_STATEMENT: line " + node.getBeginLine() + ", column "
377                             + node.getBeginColumn());
378                 }
379             }
380         } else if (node.jjtGetParent() instanceof ASTLoopStatement) {
381             ASTLoopStatement st = (ASTLoopStatement) node.jjtGetParent();
382             if (node.equals(st.getFirstChildOfType(ASTStatement.class))) {
383                 dataFlow.pushOnStack(NodeType.DO_BEFORE_FIRST_STATEMENT, dataFlow.getLast());
384                 dataFlow.createNewNode(node.jjtGetParent());
385                 if (LOGGER.isLoggable(Level.FINEST)) {
386                     LOGGER.finest("pushOnStack DO_BEFORE_FIRST_STATEMENT: line " + node.getBeginLine() + ", column "
387                             + node.getBeginColumn());
388                 }
389             }
390         }
391 
392         super.visit(node, data);
393 
394         if (node.jjtGetParent() instanceof ASTElseClause) {
395             List<ASTStatement> allStatements = node.jjtGetParent().findChildrenOfType(ASTStatement.class);
396             if (LOGGER.isLoggable(Level.FINEST)) {
397                 LOGGER.finest("ElseClause has " + allStatements.size() + " Statements ");
398             }
399 
400             /*
401              * //Restrict to the last Statement of the Else Clause if (node ==
402              * allStatements.get(allStatements.size()-1) ) { if
403              * (node.jjtGetParent().jjtGetParent() instanceof ASTCaseStatement)
404              * { dataFlow.pushOnStack(NodeType.SWITCH_LAST_DEFAULT_STATEMENT,
405              * dataFlow.getLast()); LOGGER.finest(
406              * "pushOnStack (Else-Below Case) SWITCH_LAST_DEFAULT_STATEMENT: line "
407              * + node.getBeginLine() +", column " + node.getBeginColumn()); }
408              * /*SRT else // if (node == node.jjtGetParent() instanceof
409              * ASTElseClause) { {
410              * dataFlow.pushOnStack(NodeType.ELSE_LAST_STATEMENT,
411              * dataFlow.getLast()); LOGGER.finest(
412              * "pushOnStack (Else-Below If) ELSE_LAST_STATEMENT: line " +
413              * node.getBeginLine() +", column " + node.getBeginColumn()); }
414              */
415             // }
416         } else if (node.jjtGetParent() instanceof ASTWhileStatement) {
417             ASTWhileStatement statement = (ASTWhileStatement) node.jjtGetParent();
418             List<ASTStatement> children = statement.findChildrenOfType(ASTStatement.class);
419             if (LOGGER.isLoggable(Level.FINEST)) {
420                 LOGGER.finest("(LastChildren): size " + children.size());
421             }
422             ASTStatement lastChild = children.get(children.size() - 1);
423 
424             // Push on stack if this Node is the LAST Statement associated with
425             // the FOR Statment
426             if (node.equals(lastChild)) {
427                 dataFlow.pushOnStack(NodeType.WHILE_LAST_STATEMENT, dataFlow.getLast());
428                 if (LOGGER.isLoggable(Level.FINEST)) {
429                     LOGGER.finest("pushOnStack WHILE_LAST_STATEMENT: line " + node.getBeginLine() + ", column "
430                             + node.getBeginColumn());
431                 }
432             }
433         } else if (node.jjtGetParent() instanceof ASTForStatement) {
434             ASTForStatement statement = (ASTForStatement) node.jjtGetParent();
435             List<ASTStatement> children = statement.findChildrenOfType(ASTStatement.class);
436             if (LOGGER.isLoggable(Level.FINEST)) {
437                 LOGGER.finest("(LastChildren): size " + children.size());
438             }
439             ASTStatement lastChild = children.get(children.size() - 1);
440 
441             // Push on stack if this Node is the LAST Statement associated with
442             // the FOR Statment
443             if (node.equals(lastChild)) {
444                 dataFlow.pushOnStack(NodeType.FOR_END, dataFlow.getLast());
445                 if (LOGGER.isLoggable(Level.FINEST)) {
446                     LOGGER.finest("pushOnStack (LastChildStatemnt) FOR_END: line " + node.getBeginLine() + ", column "
447                             + node.getBeginColumn());
448                 }
449             }
450         } else if (node.jjtGetParent() instanceof ASTLabelledStatement) {
451             dataFlow.pushOnStack(NodeType.LABEL_LAST_STATEMENT, dataFlow.getLast());
452             if (LOGGER.isLoggable(Level.FINEST)) {
453                 LOGGER.finest("pushOnStack LABEL_LAST_STATEMENT: line " + node.getBeginLine() + ", column "
454                         + node.getBeginColumn());
455             }
456         }
457         if (LOGGER.isLoggable(Level.FINEST)) {
458             LOGGER.finest("exit ASTStatement: line " + node.getBeginLine() + ", column " + node.getBeginColumn()
459                     + " -> " + node.getClass().getCanonicalName() + " ->-> "
460                     + node.jjtGetParent().getClass().getCanonicalName());
461         }
462         return data;
463     }
464 
465     public Object visit(ASTUnlabelledStatement node, Object data) {
466         if (!(data instanceof Structure)) {
467             return data;
468         }
469         Structure dataFlow = (Structure) data;
470         super.visit(node, data);
471         if (node.jjtGetParent() instanceof ASTLabelledStatement) {
472             dataFlow.pushOnStack(NodeType.LABEL_LAST_STATEMENT, dataFlow.getLast());
473             if (LOGGER.isLoggable(Level.FINEST)) {
474                 LOGGER.finest("pushOnStack (ASTUnlabelledStatement) LABEL_LAST_STATEMENT: line " + node.getBeginLine()
475                         + ", column " + node.getBeginColumn());
476             }
477         }
478         return data;
479     }
480 
481     public Object visit(ASTCaseStatement node, Object data) {
482         if (!(data instanceof Structure)) {
483             return data;
484         }
485         Structure dataFlow = (Structure) data;
486 
487         /*
488          * A PL/SQL CASE statement may be either:- SIMPLE, e.g. CASE
489          * case_operand WHEN when_operand THEN statement ; ELSE statement ; END
490          * CASE SEARCHED, e.g. CASE WHEN boolean_expression THEN statement ;
491          * ELSE statement ; END CASE
492          * 
493          * A SIMPLE CASE statement may be treated as a normal Java SWITCH
494          * statement ( see visit(ASTExpression)), but a SEARCHED CASE statement
495          * must have an atificial start node
496          */
497         if (null == node.getFirstChildOfType(ASTExpression.class) // CASE is
498                                                                   // "searched case statement"
499         ) {
500             dataFlow.createNewNode(node);
501             dataFlow.pushOnStack(NodeType.SWITCH_START, dataFlow.getLast());
502             if (LOGGER.isLoggable(Level.FINEST)) {
503                 LOGGER.finest("pushOnStack SWITCH_START: line " + node.getBeginLine() + ", column "
504                         + node.getBeginColumn());
505             }
506         }
507 
508         super.visit(node, data);
509 
510         dataFlow.pushOnStack(NodeType.SWITCH_END, dataFlow.getLast());
511         if (LOGGER.isLoggable(Level.FINEST)) {
512             LOGGER.finest("pushOnStack SWITCH_END: line " + node.getBeginLine() + ", column " + node.getBeginColumn());
513         }
514         return data;
515     }
516 
517     public Object visit(ASTCaseWhenClause node, Object data) {
518         if (!(data instanceof Structure)) {
519             return data;
520         }
521         Structure dataFlow = (Structure) data;
522 
523         // Java ASTSwitchLabel
524         // SRT dataFlow.createNewNode(node);
525         dataFlow.pushOnStack(NodeType.CASE_LAST_STATEMENT, dataFlow.getLast());
526         if (LOGGER.isLoggable(Level.FINEST)) {
527             LOGGER.finest("pushOnStack CASE_LAST_STATEMENT: line " + node.getBeginLine() + ", column "
528                     + node.getBeginColumn());
529         }
530 
531         super.visit(node, data);
532 
533         // dataFlow.createNewNode(node);
534         dataFlow.pushOnStack(NodeType.BREAK_STATEMENT, dataFlow.getLast());
535         if (LOGGER.isLoggable(Level.FINEST)) {
536             LOGGER.finest("pushOnStack (ASTCaseWhenClause) BREAK_STATEMENT: line " + node.getBeginLine() + ", column "
537                     + node.getBeginColumn());
538         }
539         return data;
540     }
541 
542     public Object visit(ASTIfStatement node, Object data) {
543         if (!(data instanceof Structure)) {
544             return data;
545         }
546         Structure dataFlow = (Structure) data;
547         LOGGER.finest("ElsifClause) super.visit line");
548         super.visit(node, data);
549 
550         /*
551          * PLSQL AST now has explicit ELSIF and ELSE clauses All of the
552          * ELSE_END_STATEMENTS in an IF clause should point to the outer last
553          * clause because we have to convert a single PL/SQL IF/ELSIF/ELSE
554          * satement into the equivalent set of nested Java if/else {if/else
555          * {if/else}} statements
556          */
557         List<ASTElsifClause> elsifs = node.findChildrenOfType(ASTElsifClause.class);
558         ASTElseClause elseClause = node.getFirstChildOfType(ASTElseClause.class);
559         if (null == elseClause && elsifs.isEmpty()) // The IF statements has no
560                                                     // ELSE or ELSIF statements
561                                                     // and this is the last
562                                                     // Statement
563         {
564             dataFlow.pushOnStack(NodeType.IF_LAST_STATEMENT_WITHOUT_ELSE, dataFlow.getLast());
565             if (LOGGER.isLoggable(Level.FINEST)) {
566                 LOGGER.finest("pushOnStack (ASTIfClause - no ELSIFs) IF_LAST_STATEMENT_WITHOUT_ELSE: line "
567                         + node.getBeginLine() + ", column " + node.getBeginColumn());
568             }
569         } else {
570             if (!elsifs.isEmpty()) {
571 
572                 ASTElsifClause lastElsifClause = elsifs.get(elsifs.size() - 1);
573                 for (ASTElsifClause elsifClause : elsifs) {
574 
575                     /*
576                      * If last ELSIF clause is not followed by a ELSE clause
577                      * then the last ELSIF is equivalent to an if statement
578                      * without an else Otherwise, it is equivalent to an if/else
579                      * statement
580                      */
581                     if (lastElsifClause.equals(elsifClause) && elseClause == null) {
582                         dataFlow.pushOnStack(NodeType.IF_LAST_STATEMENT_WITHOUT_ELSE, dataFlow.getLast());
583                         if (LOGGER.isLoggable(Level.FINEST)) {
584                             LOGGER.finest("pushOnStack (ASTIfClause - with ELSIFs) IF_LAST_STATEMENT_WITHOUT_ELSE: line "
585                                     + node.getBeginLine() + ", column " + node.getBeginColumn());
586                         }
587                     }
588 
589                     {
590                         dataFlow.pushOnStack(NodeType.ELSE_LAST_STATEMENT, dataFlow.getLast());
591                         if (LOGGER.isLoggable(Level.FINEST)) {
592                             LOGGER.finest("pushOnStack (ASTIfClause - with ELSIFs) ELSE_LAST_STATEMENT : line "
593                                     + node.getBeginLine() + ", column " + node.getBeginColumn());
594                         }
595                     }
596                 }
597             }
598 
599             if (null != elseClause) {
600                 // Output one terminating else
601                 dataFlow.pushOnStack(NodeType.ELSE_LAST_STATEMENT, dataFlow.getLast());
602                 if (LOGGER.isLoggable(Level.FINEST)) {
603                     LOGGER.finest("pushOnStack (ASTIfClause - with ELSE) ELSE_LAST_STATEMENT : line "
604                             + node.getBeginLine() + ", column " + node.getBeginColumn());
605                 }
606             }
607         }
608         return data;
609     }
610 
611     public Object visit(ASTElseClause node, Object data) {
612         if (!(data instanceof Structure)) {
613             return data;
614         }
615         Structure dataFlow = (Structure) data;
616 
617         if (node.jjtGetParent() instanceof ASTIfStatement) {
618             dataFlow.pushOnStack(NodeType.IF_LAST_STATEMENT, dataFlow.getLast());
619             if (LOGGER.isLoggable(Level.FINEST)) {
620                 LOGGER.finest("pushOnStack (Visit ASTElseClause) IF_LAST_STATEMENT: line " + node.getBeginLine()
621                         + ", column " + node.getBeginColumn());
622                 LOGGER.finest("ElseClause) super.visit line");
623             }
624         } else {
625             // SRT dataFlow.createNewNode(node);
626             dataFlow.pushOnStack(NodeType.SWITCH_LAST_DEFAULT_STATEMENT, dataFlow.getLast());
627             if (LOGGER.isLoggable(Level.FINEST)) {
628                 LOGGER.finest("pushOnStack SWITCH_LAST_DEFAULT_STATEMENT: line " + node.getBeginLine() + ", column "
629                         + node.getBeginColumn());
630             }
631         }
632 
633         super.visit(node, data);
634 
635         return data;
636     }
637 
638     public Object visit(ASTElsifClause node, Object data) {
639         if (!(data instanceof Structure)) {
640             return data;
641         }
642         Structure dataFlow = (Structure) data;
643         dataFlow.pushOnStack(NodeType.IF_LAST_STATEMENT, dataFlow.getLast());
644         if (LOGGER.isLoggable(Level.FINEST)) {
645             LOGGER.finest("pushOnStack (Visit ASTElsifClause) IF_LAST_STATEMENT: line " + node.getBeginLine()
646                     + ", column " + node.getBeginColumn());
647             LOGGER.finest("ElsifClause) super.visit line");
648         }
649         super.visit(node, data);
650 
651         return data;
652     }
653 
654     /**
655      * Treat a PLSQL CONTINUE like a Java "continue"
656      * 
657      * @param node
658      * @param data
659      * @return
660      */
661     public Object visit(ASTContinueStatement node, Object data) {
662         if (!(data instanceof Structure)) {
663             return data;
664         }
665         Structure dataFlow = (Structure) data;
666         dataFlow.createNewNode(node);
667         dataFlow.pushOnStack(NodeType.CONTINUE_STATEMENT, dataFlow.getLast());
668         if (LOGGER.isLoggable(Level.FINEST)) {
669             LOGGER.finest("pushOnStack (ASTContinueStatement) CONTINUE_STATEMENT: line " + node.getBeginLine()
670                     + ", column " + node.getBeginColumn());
671         }
672         return super.visit(node, data);
673     }
674 
675     /**
676      * Treat a PLSQL EXIT like a Java "break"
677      * 
678      * @param node
679      * @param data
680      * @return
681      */
682     public Object visit(ASTExitStatement node, Object data) {
683         if (!(data instanceof Structure)) {
684             return data;
685         }
686         Structure dataFlow = (Structure) data;
687         dataFlow.createNewNode(node);
688         dataFlow.pushOnStack(NodeType.BREAK_STATEMENT, dataFlow.getLast());
689         if (LOGGER.isLoggable(Level.FINEST)) {
690             LOGGER.finest("pushOnStack (ASTExitStatement) BREAK_STATEMENT: line " + node.getBeginLine() + ", column "
691                     + node.getBeginColumn());
692         }
693         return super.visit(node, data);
694     }
695 
696     /**
697      * Treat a PLSQL GOTO like a Java "continue"
698      * 
699      * @param node
700      * @param data
701      * @return
702      */
703     public Object visit(ASTGotoStatement node, Object data) {
704         if (!(data instanceof Structure)) {
705             return data;
706         }
707         Structure dataFlow = (Structure) data;
708         dataFlow.createNewNode(node);
709         dataFlow.pushOnStack(NodeType.CONTINUE_STATEMENT, dataFlow.getLast());
710         if (LOGGER.isLoggable(Level.FINEST)) {
711             LOGGER.finest("pushOnStack (ASTGotoStatement) CONTINUE_STATEMENT (GOTO): line " + node.getBeginLine()
712                     + ", column " + node.getBeginColumn());
713         }
714         return super.visit(node, data);
715     }
716 
717     public Object visit(ASTReturnStatement node, Object data) {
718         if (!(data instanceof Structure)) {
719             return data;
720         }
721         Structure dataFlow = (Structure) data;
722         dataFlow.createNewNode(node);
723         dataFlow.pushOnStack(NodeType.RETURN_STATEMENT, dataFlow.getLast());
724         if (LOGGER.isLoggable(Level.FINEST)) {
725             LOGGER.finest("pushOnStack RETURN_STATEMENT: line " + node.getBeginLine() + ", column "
726                     + node.getBeginColumn());
727         }
728         return super.visit(node, data);
729     }
730 
731     public Object visit(ASTRaiseStatement node, Object data) {
732         if (!(data instanceof Structure)) {
733             return data;
734         }
735         Structure dataFlow = (Structure) data;
736         dataFlow.createNewNode(node);
737         dataFlow.pushOnStack(NodeType.THROW_STATEMENT, dataFlow.getLast());
738         if (LOGGER.isLoggable(Level.FINEST)) {
739             LOGGER.finest("pushOnStack THROW: line " + node.getBeginLine() + ", column " + node.getBeginColumn());
740         }
741         return super.visit(node, data);
742     }
743 
744     /*
745      * The method handles the special "for" loop. It creates always an
746      * expression node even if the loop looks like for(;;).
747      */
748     private void addForExpressionNode(Node node, Structure dataFlow) {
749         ASTForStatement parent = (ASTForStatement) node.jjtGetParent();
750         boolean hasExpressionChild = false;
751 
752         for (int i = 0; i < parent.jjtGetNumChildren(); i++) {
753             if (parent.jjtGetChild(i) instanceof ASTExpression) {
754                 hasExpressionChild = true;
755             }
756 
757         }
758         if (!hasExpressionChild) {
759             if (node instanceof ASTStatement) {
760                 /*
761                  * if (!hasForInitNode && !hasForUpdateNode) {
762                  * dataFlow.createNewNode(node);
763                  * dataFlow.pushOnStack(NodeType.FOR_EXPR, dataFlow.getLast());
764                  * }
765                  */
766             }
767         }
768     }
769 }