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 to
54   *         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          LOGGER.finest("buildDataFlowFor: node class " 
69                        + node.getClass().getCanonicalName() + " @ line " 
70                        + node.getBeginLine() 
71                        +", column " + node.getBeginColumn()
72                        + " --- " + new Throwable().getStackTrace()
73                  );
74          if (!(node instanceof ASTMethodDeclaration) 
75               && !(node instanceof ASTProgramUnit) 
76               && !(node instanceof ASTTypeMethod) 
77               && !(node instanceof ASTTriggerUnit)
78               && !(node instanceof ASTTriggerTimingPointSection)
79              ) {
80              throw new RuntimeException("Can't build a data flow for anything other than a Method or a Trigger");
81          }
82  
83          this.dataFlow = new Structure(dataFlowHandler);
84          this.dataFlow.createStartNode(node.getBeginLine());
85          this.dataFlow.createNewNode(node);
86  
87          node.jjtAccept(this, dataFlow);
88  
89          this.dataFlow.createEndNode(node.getEndLine());
90  
91          if (LOGGER.isLoggable(Level.FINE))
92          {
93            LOGGER.fine("DataFlow is " + this.dataFlow.dump() ); 
94          }
95          Linker linker = new Linker(dataFlowHandler, dataFlow.getBraceStack(), dataFlow.getContinueBreakReturnStack());
96          try {
97              linker.computePaths();
98          } catch (LinkerException e) {
99              LOGGER.severe("LinkerException");
100             e.printStackTrace();
101         } catch (SequenceException e) {
102             LOGGER.severe("SequenceException");
103             e.printStackTrace();
104         }
105         LOGGER.exiting(this.getClass().getCanonicalName(),"buildDataFlowFor");
106     }
107 
108     
109      public Object visit(ASTSqlStatement node, Object data) {
110         if (!(data instanceof Structure)) {
111             LOGGER.finest("immediate return ASTSqlStatement: line " + node.getBeginLine() +", column " + node.getBeginColumn());
112             return data;
113         }
114         Structure dataFlow = (Structure) data;
115         dataFlow.createNewNode(node);
116         LOGGER.finest("createNewNode ASTSqlStatement: line " + node.getBeginLine() +", column " + node.getBeginColumn());
117         return super.visit(node, data);
118     } 
119     
120      public Object visit(ASTEmbeddedSqlStatement node, Object data) {
121         if (!(data instanceof Structure)) {
122             LOGGER.finest("immediate return ASTEmbeddedSqlStatement: line " + node.getBeginLine() +", column " + node.getBeginColumn());
123             return data;
124         }
125         Structure dataFlow = (Structure) data;
126         dataFlow.createNewNode(node);
127         LOGGER.finest("createNewNode ASTEmbeddedSqlStatement: line " + node.getBeginLine() +", column " + node.getBeginColumn());
128         return super.visit(node, data);
129     } 
130     
131      public Object visit(ASTCloseStatement node, Object data) {
132         if (!(data instanceof Structure)) {
133             return data;
134         }
135         Structure dataFlow = (Structure) data;
136         dataFlow.createNewNode(node);
137         LOGGER.finest("createNewNode ASTCloseStatement: line " + node.getBeginLine() +", column " + node.getBeginColumn());
138         return super.visit(node, data);
139     } 
140     
141      public Object visit(ASTOpenStatement node, Object data) {
142         if (!(data instanceof Structure)) {
143             return data;
144         }
145         Structure dataFlow = (Structure) data;
146         dataFlow.createNewNode(node);
147         LOGGER.finest("createNewNode ASTOpenStatement: line " + node.getBeginLine() +", column " + node.getBeginColumn());
148         return super.visit(node, data);
149     } 
150     
151      public Object visit(ASTFetchStatement node, Object data) {
152         if (!(data instanceof Structure)) {
153             return data;
154         }
155         Structure dataFlow = (Structure) data;
156         dataFlow.createNewNode(node);
157         LOGGER.finest("createNewNode ASTFetchStatement: line " + node.getBeginLine() +", column " + node.getBeginColumn());
158         return super.visit(node, data);
159     } 
160     
161      public Object visit(ASTPipelineStatement node, Object data) {
162         if (!(data instanceof Structure)) {
163             return data;
164         }
165         Structure dataFlow = (Structure) data;
166         dataFlow.createNewNode(node);
167         LOGGER.finest("createNewNode ASTPipelineStatement: line " + node.getBeginLine() +", column " + node.getBeginColumn());
168         return super.visit(node, data);
169     } 
170     
171     /* */
172 
173     public Object visit(ASTVariableOrConstantDeclarator node, Object data) {
174         if (!(data instanceof Structure)) {
175             return data;
176         }
177         Structure dataFlow = (Structure) data;
178         dataFlow.createNewNode(node);
179         LOGGER.finest("createNewNode ASTVariableOrConstantDeclarator: line " + node.getBeginLine() +", column " + node.getBeginColumn());
180         return super.visit(node, data);
181     }
182 
183     public Object visit(ASTExpression node, Object data) {
184         LOGGER.finest("Entry ASTExpression: line " + node.getBeginLine() +", column " + node.getBeginColumn());
185         if (!(data instanceof Structure)) {
186             LOGGER.finest("immediate return ASTExpression: line " + node.getBeginLine() +", column " + node.getBeginColumn());
187             return data;
188         }
189         Structure dataFlow = (Structure) data;
190 
191         //The equivalent of an ASTExpression is an Expression whose parent is an UnLabelledStatement
192         if (node.jjtGetParent() instanceof ASTUnlabelledStatement) {
193             LOGGER.finest("createNewNode ASTSUnlabelledStatement: line " + node.getBeginLine() +", column " + node.getBeginColumn());
194             dataFlow.createNewNode(node);
195         } else 
196         // TODO what about throw stmts?
197         if (node.jjtGetParent() instanceof ASTIfStatement) {
198             dataFlow.createNewNode(node); // START IF
199             dataFlow.pushOnStack(NodeType.IF_EXPR, dataFlow.getLast());
200             LOGGER.finest("pushOnStack parent IF_EXPR: line " + node.getBeginLine() +", column " + node.getBeginColumn());
201         } else if (node.jjtGetParent() instanceof ASTElsifClause) {
202             LOGGER.finest("parent (Elsif) IF_EXPR at  " + node.getBeginLine() +", column " + node.getBeginColumn());
203             dataFlow.createNewNode(node); // START IF
204             dataFlow.pushOnStack(NodeType.IF_EXPR, dataFlow.getLast());
205             LOGGER.finest("pushOnStack parent (Elsif) IF_EXPR: line " + node.getBeginLine() +", column " + node.getBeginColumn());
206         } else if (node.jjtGetParent() instanceof ASTWhileStatement) {
207             dataFlow.createNewNode(node); // START WHILE
208             dataFlow.pushOnStack(NodeType.WHILE_EXPR, dataFlow.getLast());
209             LOGGER.finest("pushOnStack parent WHILE_EXPR: line " + node.getBeginLine() +", column " + node.getBeginColumn());
210         } else if (node.jjtGetParent() instanceof ASTCaseStatement) {
211             dataFlow.createNewNode(node); // START SWITCH
212             dataFlow.pushOnStack(NodeType.SWITCH_START, dataFlow.getLast());
213             LOGGER.finest("pushOnStack parent SWITCH_START: line " + node.getBeginLine() +", column " + node.getBeginColumn());
214         } else if (node.jjtGetParent() instanceof ASTForStatement) {
215             /* A PL/SQL loop control:
216              *  [<REVERSE>] Expression()[".."Expression()] 
217              * 
218              */
219             if (node.equals( node.jjtGetParent().getFirstChildOfType(ASTExpression.class) ) )
220             {
221               dataFlow.createNewNode(node); // FOR EXPR
222               dataFlow.pushOnStack(NodeType.FOR_EXPR, dataFlow.getLast());
223               LOGGER.finest("pushOnStack parent FOR_EXPR: line " + node.getBeginLine() +", column " + node.getBeginColumn());
224             }
225             LOGGER.finest("parent (ASTForStatement): line " + node.getBeginLine() +", column " + node.getBeginColumn());
226         } else if (node.jjtGetParent() instanceof ASTLoopStatement) {
227             dataFlow.createNewNode(node); // DO EXPR
228             dataFlow.pushOnStack(NodeType.DO_EXPR, dataFlow.getLast());
229             LOGGER.finest("pushOnStack parent DO_EXPR: line " + node.getBeginLine() +", column " + node.getBeginColumn());
230         }
231 
232         return super.visit(node, data);
233     }
234 
235     public Object visit(ASTLabelledStatement node, Object data) {
236         dataFlow.createNewNode(node);
237         dataFlow.pushOnStack(NodeType.LABEL_STATEMENT, dataFlow.getLast());
238         LOGGER.finest("pushOnStack LABEL_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
239         return super.visit(node, data);
240     } 
241 
242     /**
243      *  PL/SQL does not have a do/while statement or repeat/until statement: the equivalent is a LOOP statement.
244      *  A PL/SQL LOOP statement is exited using an explicit EXIT ( == break;) statement
245      * It does not have a test expression, so the Java control processing (on the expression) does not fire.
246      * The best way to cope it to push a DO_EXPR after the loop.
247      */
248     public Object visit(ASTLoopStatement node, Object data) {
249         LOGGER.finest("entry ASTLoopStatement: line " + node.getBeginLine() +", column " + node.getBeginColumn());
250         if (!(data instanceof Structure)) {
251             LOGGER.finest("immediate return ASTLoopStatement: line " + node.getBeginLine() +", column " + node.getBeginColumn());
252             return data;
253         }
254         Structure dataFlow = (Structure) data;
255 
256         //process the contents on the LOOP statement 
257         super.visit(node, data);
258 
259         dataFlow.createNewNode(node);
260         dataFlow.pushOnStack(NodeType.DO_EXPR, dataFlow.getLast());
261         LOGGER.finest("pushOnStack (ASTLoopStatement) DO_EXPR: line " + node.getBeginLine() +", column " + node.getBeginColumn());
262         return data;
263     } 
264 
265     /**
266      * A PL/SQL WHILE statement includes the LOOP statement and all Expressions within it:  
267      * it does not have a single test expression, so the Java control processing (on the Expression) fires for each 
268      * Expression in the LOOP.
269      * The best way to cope it to push a WHILE_LAST_STATEMENT after the WhileStatement has been processed.
270      */
271     public Object visit(ASTWhileStatement node, Object data) {
272         LOGGER.finest("entry ASTWhileStatement: line " + node.getBeginLine() +", column " + node.getBeginColumn());
273         if (!(data instanceof Structure)) {
274             LOGGER.finest("immediate return ASTWhileStatement: line " + node.getBeginLine() +", column " + node.getBeginColumn());
275             return data;
276         }
277 
278         //process the contents on the WHILE statement 
279         super.visit(node, data);
280 
281         return data;
282     } 
283 
284 
285 // 	----------------------------------------------------------------------------
286 //  BRANCH OUT
287 
288     public Object visit(ASTStatement node, Object data) {
289         LOGGER.finest("entry ASTStatement: line " + node.getBeginLine() +", column " + node.getBeginColumn() + " -> " + node.getClass().getCanonicalName());
290         if (!(data instanceof Structure)) {
291             LOGGER.finest("immediate return ASTStatement: line " + node.getBeginLine() +", column " + node.getBeginColumn());
292             return data;
293         }
294         Structure dataFlow = (Structure) data;
295 
296         if (node.jjtGetParent() instanceof ASTForStatement) {
297             ASTForStatement st = (ASTForStatement) node.jjtGetParent(); 
298             if (node.equals(st.getFirstChildOfType(ASTStatement.class)))
299             {
300               this.addForExpressionNode(node, dataFlow);
301               dataFlow.pushOnStack(NodeType.FOR_BEFORE_FIRST_STATEMENT, dataFlow.getLast());
302               LOGGER.finest("pushOnStack FOR_BEFORE_FIRST_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
303             }
304         } else if (node.jjtGetParent() instanceof ASTLoopStatement) {
305             ASTLoopStatement st = (ASTLoopStatement) node.jjtGetParent(); 
306             if (node.equals(st.getFirstChildOfType(ASTStatement.class)))
307             {
308               dataFlow.pushOnStack(NodeType.DO_BEFORE_FIRST_STATEMENT, dataFlow.getLast());
309               dataFlow.createNewNode(node.jjtGetParent());
310               LOGGER.finest("pushOnStack DO_BEFORE_FIRST_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
311             }
312         } 
313 
314 
315         super.visit(node, data);
316 
317         if (node.jjtGetParent() instanceof ASTElseClause) {
318             List<ASTStatement> allStatements = node.jjtGetParent().findChildrenOfType(ASTStatement.class) ;
319             LOGGER.finest("ElseClause has " + allStatements.size() + " Statements " );
320 
321            /*
322            //Restrict to the last Statement of the Else Clause
323            if (node == allStatements.get(allStatements.size()-1) )
324            {
325             if (node.jjtGetParent().jjtGetParent() instanceof ASTCaseStatement) {
326                 dataFlow.pushOnStack(NodeType.SWITCH_LAST_DEFAULT_STATEMENT, dataFlow.getLast());
327                 LOGGER.finest("pushOnStack (Else-Below Case) SWITCH_LAST_DEFAULT_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
328             } /*SRT else // if (node == node.jjtGetParent() instanceof ASTElseClause) { 
329             {
330               dataFlow.pushOnStack(NodeType.ELSE_LAST_STATEMENT, dataFlow.getLast());
331               LOGGER.finest("pushOnStack (Else-Below If) ELSE_LAST_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
332             } */
333            //}
334         } else if (node.jjtGetParent() instanceof ASTWhileStatement) {
335             ASTWhileStatement statement = (ASTWhileStatement) node.jjtGetParent();
336             List<ASTStatement> children = statement.findChildrenOfType(ASTStatement.class);
337             LOGGER.finest("(LastChildren): size " + children.size() );
338             ASTStatement lastChild = children.get(children.size()-1);
339 
340             // Push on stack if this Node is the LAST Statement associated with the FOR Statment
341             if ( node.equals(lastChild) )
342             {
343               dataFlow.pushOnStack(NodeType.WHILE_LAST_STATEMENT, dataFlow.getLast());
344               LOGGER.finest("pushOnStack WHILE_LAST_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
345             }
346         }  else if (node.jjtGetParent() instanceof ASTForStatement ) {
347             ASTForStatement statement = (ASTForStatement) node.jjtGetParent();
348             List<ASTStatement> children = statement.findChildrenOfType(ASTStatement.class);
349             LOGGER.finest("(LastChildren): size " + children.size() );
350             ASTStatement lastChild = children.get(children.size()-1);
351 
352             // Push on stack if this Node is the LAST Statement associated with the FOR Statment
353             if ( node.equals(lastChild) )
354             {
355             dataFlow.pushOnStack(NodeType.FOR_END, dataFlow.getLast());
356                 LOGGER.finest("pushOnStack (LastChildStatemnt) FOR_END: line " + node.getBeginLine() +", column " + node.getBeginColumn());
357             }
358         } else if (node.jjtGetParent() instanceof ASTLabelledStatement) {
359             dataFlow.pushOnStack(NodeType.LABEL_LAST_STATEMENT, dataFlow.getLast());
360             LOGGER.finest("pushOnStack LABEL_LAST_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
361         } 
362         LOGGER.finest("exit ASTStatement: line " + node.getBeginLine() +", column " + node.getBeginColumn() 
363                        + " -> " + node.getClass().getCanonicalName() 
364                        + " ->-> " + node.jjtGetParent().getClass().getCanonicalName() 
365                 );
366         return data;
367     }
368 
369     public Object visit(ASTUnlabelledStatement node, Object data) {
370         if (!(data instanceof Structure)) {
371             return data;
372         }
373         Structure dataFlow = (Structure) data;
374         super.visit(node, data);
375         if (node.jjtGetParent() instanceof ASTLabelledStatement) {
376             dataFlow.pushOnStack(NodeType.LABEL_LAST_STATEMENT, dataFlow.getLast());
377             LOGGER.finest("pushOnStack (ASTUnlabelledStatement) LABEL_LAST_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
378         } 
379         return data;
380     }
381 
382     public Object visit(ASTCaseStatement node, Object data) {
383         if (!(data instanceof Structure)) {
384             return data;
385         }
386         Structure dataFlow = (Structure) data;
387 
388         /*
389          * A PL/SQL CASE statement may be either:- 
390          * SIMPLE, e.g. CASE case_operand WHEN when_operand THEN statement ; ELSE statement ; END CASE
391          * SEARCHED, e.g. CASE WHEN boolean_expression THEN statement ; ELSE statement ; END CASE
392          * 
393          * A SIMPLE CASE statement may be treated as a normal Java SWITCH statement ( see visit(ASTExpression)), 
394          * but a SEARCHED CASE statement must have an atificial start node
395          */
396         if (null == node.getFirstChildOfType(ASTExpression.class) // CASE is "searched case statement"
397            )
398         {
399           dataFlow.createNewNode(node);
400           dataFlow.pushOnStack(NodeType.SWITCH_START, dataFlow.getLast());
401           LOGGER.finest("pushOnStack SWITCH_START: line " + node.getBeginLine() +", column " + node.getBeginColumn());
402         }
403 
404         super.visit(node, data);
405 
406         dataFlow.pushOnStack(NodeType.SWITCH_END, dataFlow.getLast());
407         LOGGER.finest("pushOnStack SWITCH_END: line " + node.getBeginLine() +", column " + node.getBeginColumn());
408         return data;
409     }
410 
411       public Object visit(ASTCaseWhenClause node, Object data) {
412         if (!(data instanceof Structure)) {
413             return data;
414         }
415         Structure dataFlow = (Structure) data;
416 
417 
418          //Java ASTSwitchLabel 
419         //SRT dataFlow.createNewNode(node);
420         dataFlow.pushOnStack(NodeType.CASE_LAST_STATEMENT, dataFlow.getLast());
421         LOGGER.finest("pushOnStack CASE_LAST_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
422 
423         super.visit(node, data);
424 
425         //dataFlow.createNewNode(node);
426         dataFlow.pushOnStack(NodeType.BREAK_STATEMENT, dataFlow.getLast());
427         LOGGER.finest("pushOnStack (ASTCaseWhenClause) BREAK_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
428         return data;
429     }
430      
431       public Object visit(ASTIfStatement node, Object data) {
432         if (!(data instanceof Structure)) {
433             return data;
434         }
435         Structure dataFlow = (Structure) data;
436         LOGGER.finest("ElsifClause) super.visit line" );
437         super.visit(node, data);
438 
439 
440         /*
441          * PLSQL AST now has explicit ELSIF and ELSE clauses
442          * All of the ELSE_END_STATEMENTS in an IF clause
443          * should point to the outer last clause because
444          * we have to convert a single PL/SQL IF/ELSIF/ELSE satement into the equivalent 
445          * set of nested Java if/else {if/else {if/else}} statements 
446          */
447           List<ASTElsifClause> elsifs = node.findChildrenOfType(ASTElsifClause.class);
448           ASTElseClause elseClause = node.getFirstChildOfType(ASTElseClause.class);
449           if (null == elseClause
450               && 
451               elsifs.isEmpty()
452              ) // The IF statements has no ELSE or ELSIF statements and this is the last Statement 
453           {
454               dataFlow.pushOnStack(NodeType.IF_LAST_STATEMENT_WITHOUT_ELSE, dataFlow.getLast());
455               LOGGER.finest("pushOnStack (ASTIfClause - no ELSIFs) IF_LAST_STATEMENT_WITHOUT_ELSE: line " + node.getBeginLine() +", column " + node.getBeginColumn());
456           } 
457           else 
458           {
459             if (elsifs.size() > 0 )
460             {
461 
462               ASTElsifClause lastElsifClause = elsifs.get(elsifs.size()-1);
463               for (ASTElsifClause elsifClause : elsifs )
464               {
465 
466                 /* If last ELSIF clause is not followed by a ELSE clause
467                  * then the last ELSIF is equivalent to an if statement without an else
468                  * Otherwise, it is equivalent to an if/else statement 
469                  */
470                 if (lastElsifClause == elsifClause && null == elseClause)
471                 {
472                   dataFlow.pushOnStack(NodeType.IF_LAST_STATEMENT_WITHOUT_ELSE, dataFlow.getLast());
473                   LOGGER.finest("pushOnStack (ASTIfClause - with ELSIFs) IF_LAST_STATEMENT_WITHOUT_ELSE: line " + node.getBeginLine() +", column " + node.getBeginColumn());
474                 }
475                 
476                 {
477                   dataFlow.pushOnStack(NodeType.ELSE_LAST_STATEMENT, dataFlow.getLast());
478                   LOGGER.finest("pushOnStack (ASTIfClause - with ELSIFs) ELSE_LAST_STATEMENT : line " + node.getBeginLine() +", column " + node.getBeginColumn());
479                 }
480               }
481             }
482 
483             if (null != elseClause)
484             {
485               //Output one terminating else
486               dataFlow.pushOnStack(NodeType.ELSE_LAST_STATEMENT, dataFlow.getLast());
487               LOGGER.finest("pushOnStack (ASTIfClause - with ELSE) ELSE_LAST_STATEMENT : line " + node.getBeginLine() +", column " + node.getBeginColumn());
488             }
489         } 
490         return data;
491     }
492 
493       public Object visit(ASTElseClause node, Object data) {
494         if (!(data instanceof Structure)) {
495             return data;
496         }
497         Structure dataFlow = (Structure) data;
498 
499         if (node.jjtGetParent() instanceof ASTIfStatement) {
500           dataFlow.pushOnStack(NodeType.IF_LAST_STATEMENT, dataFlow.getLast());
501           LOGGER.finest("pushOnStack (Visit ASTElseClause) IF_LAST_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
502           LOGGER.finest("ElseClause) super.visit line" );
503         }
504         else
505         {
506           //SRT dataFlow.createNewNode(node);
507           dataFlow.pushOnStack(NodeType.SWITCH_LAST_DEFAULT_STATEMENT, dataFlow.getLast());
508           LOGGER.finest("pushOnStack SWITCH_LAST_DEFAULT_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());          
509         }
510 
511         super.visit(node, data);
512 
513         return data;
514     }
515 
516       public Object visit(ASTElsifClause node, Object data) {
517         if (!(data instanceof Structure)) {
518             return data;
519         }
520         Structure dataFlow = (Structure) data;
521         dataFlow.pushOnStack(NodeType.IF_LAST_STATEMENT, dataFlow.getLast());
522         LOGGER.finest("pushOnStack (Visit ASTElsifClause) IF_LAST_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
523         LOGGER.finest("ElsifClause) super.visit line" );
524         super.visit(node, data);
525 
526         return data;
527     }
528 
529     /**
530      * Treat a PLSQL CONTINUE like a Java "continue"
531      * 
532      * @param node
533      * @param data
534      * @return 
535      */
536     public Object visit(ASTContinueStatement node, Object data) {
537         if (!(data instanceof Structure)) {
538             return data;
539         }
540         Structure dataFlow = (Structure) data;
541         dataFlow.createNewNode(node);
542         dataFlow.pushOnStack(NodeType.CONTINUE_STATEMENT, dataFlow.getLast());
543         LOGGER.finest("pushOnStack (ASTContinueStatement) CONTINUE_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
544         return super.visit(node, data);
545     }
546 
547     /**
548      * Treat a PLSQL EXIT like a Java "break"
549      * 
550      * @param node
551      * @param data
552      * @return 
553      */
554     public Object visit(ASTExitStatement node, Object data) {
555         if (!(data instanceof Structure)) {
556             return data;
557         }
558         Structure dataFlow = (Structure) data;
559         dataFlow.createNewNode(node);
560         dataFlow.pushOnStack(NodeType.BREAK_STATEMENT, dataFlow.getLast());
561         LOGGER.finest("pushOnStack (ASTExitStatement) BREAK_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
562         return super.visit(node, data);
563     }
564 	
565     /**
566      * Treat a PLSQL GOTO like a Java "continue"
567      * 
568      * @param node
569      * @param data
570      * @return 
571      */
572     public Object visit(ASTGotoStatement node, Object data) {
573         if (!(data instanceof Structure)) {
574             return data;
575         }
576         Structure dataFlow = (Structure) data;
577         dataFlow.createNewNode(node);
578         dataFlow.pushOnStack(NodeType.CONTINUE_STATEMENT, dataFlow.getLast());
579         LOGGER.finest("pushOnStack (ASTGotoStatement) CONTINUE_STATEMENT (GOTO): line " + node.getBeginLine() +", column " + node.getBeginColumn());
580         return super.visit(node, data);
581     }
582 
583     public Object visit(ASTReturnStatement node, Object data) {
584         if (!(data instanceof Structure)) {
585             return data;
586         }
587         Structure dataFlow = (Structure) data;
588         dataFlow.createNewNode(node);
589         dataFlow.pushOnStack(NodeType.RETURN_STATEMENT, dataFlow.getLast());
590         LOGGER.finest("pushOnStack RETURN_STATEMENT: line " + node.getBeginLine() +", column " + node.getBeginColumn());
591         return super.visit(node, data);
592     }
593 
594     public Object visit(ASTRaiseStatement node, Object data) {
595         if (!(data instanceof Structure)) {
596             return data;
597         }
598         Structure dataFlow = (Structure) data;
599         dataFlow.createNewNode(node);
600         dataFlow.pushOnStack(NodeType.THROW_STATEMENT, dataFlow.getLast());
601         LOGGER.finest("pushOnStack THROW: line " + node.getBeginLine() +", column " + node.getBeginColumn());
602         return super.visit(node, data);
603     }
604 
605     /*
606      * The method handles the special "for" loop. It creates always an
607      * expression node even if the loop looks like for(;;).
608      * */
609     private void addForExpressionNode(Node node, Structure dataFlow) {
610         ASTForStatement parent = (ASTForStatement) node.jjtGetParent();
611         boolean hasExpressionChild = false;
612 
613         for (int i = 0; i < parent.jjtGetNumChildren(); i++) {
614             if (parent.jjtGetChild(i) instanceof ASTExpression) {
615                 hasExpressionChild = true;
616             } 
617              
618         }
619         if (!hasExpressionChild) {
620             if (node instanceof ASTStatement) {
621                 /* if (!hasForInitNode && !hasForUpdateNode) {
622                     dataFlow.createNewNode(node);
623                     dataFlow.pushOnStack(NodeType.FOR_EXPR, dataFlow.getLast());
624                 } */
625             }
626         }
627     }
628 }