/** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ package net.sourceforge.pmd.lang.plsql.dfa; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import net.sourceforge.pmd.lang.DataFlowHandler; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.dfa.Linker; import net.sourceforge.pmd.lang.dfa.LinkerException; import net.sourceforge.pmd.lang.dfa.NodeType; import net.sourceforge.pmd.lang.dfa.SequenceException; import net.sourceforge.pmd.lang.dfa.Structure; import net.sourceforge.pmd.lang.plsql.ast.ASTCaseStatement; import net.sourceforge.pmd.lang.plsql.ast.ASTCaseWhenClause; import net.sourceforge.pmd.lang.plsql.ast.ASTCloseStatement; import net.sourceforge.pmd.lang.plsql.ast.ASTContinueStatement; import net.sourceforge.pmd.lang.plsql.ast.ASTElseClause; import net.sourceforge.pmd.lang.plsql.ast.ASTElsifClause; import net.sourceforge.pmd.lang.plsql.ast.ASTEmbeddedSqlStatement; import net.sourceforge.pmd.lang.plsql.ast.ASTExitStatement; import net.sourceforge.pmd.lang.plsql.ast.ASTExpression; import net.sourceforge.pmd.lang.plsql.ast.ASTFetchStatement; import net.sourceforge.pmd.lang.plsql.ast.ASTForStatement; import net.sourceforge.pmd.lang.plsql.ast.ASTGotoStatement; import net.sourceforge.pmd.lang.plsql.ast.ASTIfStatement; import net.sourceforge.pmd.lang.plsql.ast.ASTLabelledStatement; import net.sourceforge.pmd.lang.plsql.ast.ASTLoopStatement; import net.sourceforge.pmd.lang.plsql.ast.ASTMethodDeclaration; import net.sourceforge.pmd.lang.plsql.ast.ASTOpenStatement; import net.sourceforge.pmd.lang.plsql.ast.ASTPipelineStatement; import net.sourceforge.pmd.lang.plsql.ast.ASTProgramUnit; import net.sourceforge.pmd.lang.plsql.ast.ASTRaiseStatement; import net.sourceforge.pmd.lang.plsql.ast.ASTReturnStatement; import net.sourceforge.pmd.lang.plsql.ast.ASTSqlStatement; import net.sourceforge.pmd.lang.plsql.ast.ASTStatement; import net.sourceforge.pmd.lang.plsql.ast.ASTTriggerTimingPointSection; import net.sourceforge.pmd.lang.plsql.ast.ASTTriggerUnit; import net.sourceforge.pmd.lang.plsql.ast.ASTTypeMethod; import net.sourceforge.pmd.lang.plsql.ast.ASTUnlabelledStatement; import net.sourceforge.pmd.lang.plsql.ast.ASTVariableOrConstantDeclarator; import net.sourceforge.pmd.lang.plsql.ast.ASTWhileStatement; import net.sourceforge.pmd.lang.plsql.ast.PLSQLNode; import net.sourceforge.pmd.lang.plsql.ast.PLSQLParserVisitorAdapter; /** * Sublayer of DataFlowFacade. Finds all data flow nodes and stores the * type information (@see StackObject). At last it uses this information * to link the nodes. * * @author raik */ public class StatementAndBraceFinder extends PLSQLParserVisitorAdapter { private static final Logger LOGGER = Logger.getLogger(StatementAndBraceFinder.class.getName()); private final DataFlowHandler dataFlowHandler; private Structure dataFlow; public StatementAndBraceFinder(DataFlowHandler dataFlowHandler) { this.dataFlowHandler = dataFlowHandler; } public void buildDataFlowFor(PLSQLNode node) { LOGGER.entering(this.getClass().getCanonicalName(), "buildDataFlowFor"); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("buildDataFlowFor: node class " + node.getClass().getCanonicalName() + " @ line " + node.getBeginLine() + ", column " + node.getBeginColumn() + " --- " + new Throwable().getStackTrace()); } if (!(node instanceof ASTMethodDeclaration) && !(node instanceof ASTProgramUnit) && !(node instanceof ASTTypeMethod) && !(node instanceof ASTTriggerUnit) && !(node instanceof ASTTriggerTimingPointSection)) { throw new RuntimeException("Can't build a data flow for anything other than a Method or a Trigger"); } this.dataFlow = new Structure(dataFlowHandler); this.dataFlow.createStartNode(node.getBeginLine()); this.dataFlow.createNewNode(node); node.jjtAccept(this, dataFlow); this.dataFlow.createEndNode(node.getEndLine()); if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine("DataFlow is " + this.dataFlow.dump()); } Linker linker = new Linker(dataFlowHandler, dataFlow.getBraceStack(), dataFlow.getContinueBreakReturnStack()); try { linker.computePaths(); } catch (LinkerException e) { LOGGER.severe("LinkerException"); e.printStackTrace(); } catch (SequenceException e) { LOGGER.severe("SequenceException"); e.printStackTrace(); } LOGGER.exiting(this.getClass().getCanonicalName(), "buildDataFlowFor"); } @Override public Object visit(ASTSqlStatement node, Object data) { if (!(data instanceof Structure)) { if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("immediate return ASTSqlStatement: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } return data; } Structure dataFlow = (Structure) data; dataFlow.createNewNode(node); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest( "createNewNode ASTSqlStatement: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } return super.visit(node, data); } @Override public Object visit(ASTEmbeddedSqlStatement node, Object data) { if (!(data instanceof Structure)) { if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("immediate return ASTEmbeddedSqlStatement: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } return data; } Structure dataFlow = (Structure) data; dataFlow.createNewNode(node); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("createNewNode ASTEmbeddedSqlStatement: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } return super.visit(node, data); } @Override public Object visit(ASTCloseStatement node, Object data) { if (!(data instanceof Structure)) { return data; } Structure dataFlow = (Structure) data; dataFlow.createNewNode(node); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("createNewNode ASTCloseStatement: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } return super.visit(node, data); } @Override public Object visit(ASTOpenStatement node, Object data) { if (!(data instanceof Structure)) { return data; } Structure dataFlow = (Structure) data; dataFlow.createNewNode(node); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("createNewNode ASTOpenStatement: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } return super.visit(node, data); } @Override public Object visit(ASTFetchStatement node, Object data) { if (!(data instanceof Structure)) { return data; } Structure dataFlow = (Structure) data; dataFlow.createNewNode(node); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("createNewNode ASTFetchStatement: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } return super.visit(node, data); } @Override public Object visit(ASTPipelineStatement node, Object data) { if (!(data instanceof Structure)) { return data; } Structure dataFlow = (Structure) data; dataFlow.createNewNode(node); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("createNewNode ASTPipelineStatement: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } return super.visit(node, data); } /* */ @Override public Object visit(ASTVariableOrConstantDeclarator node, Object data) { if (!(data instanceof Structure)) { return data; } Structure dataFlow = (Structure) data; dataFlow.createNewNode(node); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("createNewNode ASTVariableOrConstantDeclarator: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } return super.visit(node, data); } @Override public Object visit(ASTExpression node, Object data) { if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("Entry ASTExpression: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } if (!(data instanceof Structure)) { if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("immediate return ASTExpression: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } return data; } Structure dataFlow = (Structure) data; // The equivalent of an ASTExpression is an Expression whose parent is // an UnLabelledStatement if (node.jjtGetParent() instanceof ASTUnlabelledStatement) { if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("createNewNode ASTSUnlabelledStatement: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } dataFlow.createNewNode(node); } else if (node.jjtGetParent() instanceof ASTIfStatement) { // TODO what about throw stmts? dataFlow.createNewNode(node); // START IF dataFlow.pushOnStack(NodeType.IF_EXPR, dataFlow.getLast()); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("pushOnStack parent IF_EXPR: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } } else if (node.jjtGetParent() instanceof ASTElsifClause) { if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest( "parent (Elsif) IF_EXPR at " + node.getBeginLine() + ", column " + node.getBeginColumn()); } dataFlow.createNewNode(node); // START IF dataFlow.pushOnStack(NodeType.IF_EXPR, dataFlow.getLast()); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("pushOnStack parent (Elsif) IF_EXPR: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } } else if (node.jjtGetParent() instanceof ASTWhileStatement) { dataFlow.createNewNode(node); // START WHILE dataFlow.pushOnStack(NodeType.WHILE_EXPR, dataFlow.getLast()); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("pushOnStack parent WHILE_EXPR: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } } else if (node.jjtGetParent() instanceof ASTCaseStatement) { dataFlow.createNewNode(node); // START SWITCH dataFlow.pushOnStack(NodeType.SWITCH_START, dataFlow.getLast()); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("pushOnStack parent SWITCH_START: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } } else if (node.jjtGetParent() instanceof ASTForStatement) { /* * A PL/SQL loop control: [<REVERSE>] Expression()[".."Expression()] */ if (node.equals(node.jjtGetParent().getFirstChildOfType(ASTExpression.class))) { dataFlow.createNewNode(node); // FOR EXPR dataFlow.pushOnStack(NodeType.FOR_EXPR, dataFlow.getLast()); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("pushOnStack parent FOR_EXPR: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } } if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest( "parent (ASTForStatement): line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } } else if (node.jjtGetParent() instanceof ASTLoopStatement) { dataFlow.createNewNode(node); // DO EXPR dataFlow.pushOnStack(NodeType.DO_EXPR, dataFlow.getLast()); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("pushOnStack parent DO_EXPR: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } } return super.visit(node, data); } @Override public Object visit(ASTLabelledStatement node, Object data) { dataFlow.createNewNode(node); dataFlow.pushOnStack(NodeType.LABEL_STATEMENT, dataFlow.getLast()); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest( "pushOnStack LABEL_STATEMENT: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } return super.visit(node, data); } /** * PL/SQL does not have a do/while statement or repeat/until statement: the * equivalent is a LOOP statement. A PL/SQL LOOP statement is exited using * an explicit EXIT ( == break;) statement It does not have a test * expression, so the Java control processing (on the expression) does not * fire. The best way to cope it to push a DO_EXPR after the loop. */ @Override public Object visit(ASTLoopStatement node, Object data) { if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("entry ASTLoopStatement: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } if (!(data instanceof Structure)) { if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("immediate return ASTLoopStatement: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } return data; } Structure dataFlow = (Structure) data; // process the contents on the LOOP statement super.visit(node, data); dataFlow.createNewNode(node); dataFlow.pushOnStack(NodeType.DO_EXPR, dataFlow.getLast()); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("pushOnStack (ASTLoopStatement) DO_EXPR: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } return data; } /** * A PL/SQL WHILE statement includes the LOOP statement and all Expressions * within it: it does not have a single test expression, so the Java control * processing (on the Expression) fires for each Expression in the LOOP. The * best way to cope it to push a WHILE_LAST_STATEMENT after the * WhileStatement has been processed. */ @Override public Object visit(ASTWhileStatement node, Object data) { if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("entry ASTWhileStatement: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } if (!(data instanceof Structure)) { if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("immediate return ASTWhileStatement: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } return data; } // process the contents on the WHILE statement super.visit(node, data); return data; } // ---------------------------------------------------------------------------- // BRANCH OUT @Override public Object visit(ASTStatement node, Object data) { if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("entry ASTStatement: line " + node.getBeginLine() + ", column " + node.getBeginColumn() + " -> " + node.getClass().getCanonicalName()); } if (!(data instanceof Structure)) { if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("immediate return ASTStatement: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } return data; } Structure dataFlow = (Structure) data; if (node.jjtGetParent() instanceof ASTForStatement) { ASTForStatement st = (ASTForStatement) node.jjtGetParent(); if (node.equals(st.getFirstChildOfType(ASTStatement.class))) { addForExpressionNode(node, dataFlow); dataFlow.pushOnStack(NodeType.FOR_BEFORE_FIRST_STATEMENT, dataFlow.getLast()); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("pushOnStack FOR_BEFORE_FIRST_STATEMENT: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } } } else if (node.jjtGetParent() instanceof ASTLoopStatement) { ASTLoopStatement st = (ASTLoopStatement) node.jjtGetParent(); if (node.equals(st.getFirstChildOfType(ASTStatement.class))) { dataFlow.pushOnStack(NodeType.DO_BEFORE_FIRST_STATEMENT, dataFlow.getLast()); dataFlow.createNewNode(node.jjtGetParent()); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("pushOnStack DO_BEFORE_FIRST_STATEMENT: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } } } super.visit(node, data); if (node.jjtGetParent() instanceof ASTElseClause) { List<ASTStatement> allStatements = node.jjtGetParent().findChildrenOfType(ASTStatement.class); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("ElseClause has " + allStatements.size() + " Statements "); } /* * //Restrict to the last Statement of the Else Clause if (node == * allStatements.get(allStatements.size()-1) ) { if * (node.jjtGetParent().jjtGetParent() instanceof ASTCaseStatement) * { dataFlow.pushOnStack(NodeType.SWITCH_LAST_DEFAULT_STATEMENT, * dataFlow.getLast()); LOGGER.finest( * "pushOnStack (Else-Below Case) SWITCH_LAST_DEFAULT_STATEMENT: line " * + node.getBeginLine() +", column " + node.getBeginColumn()); } * /*SRT else // if (node == node.jjtGetParent() instanceof * ASTElseClause) { { * dataFlow.pushOnStack(NodeType.ELSE_LAST_STATEMENT, * dataFlow.getLast()); LOGGER.finest( * "pushOnStack (Else-Below If) ELSE_LAST_STATEMENT: line " + * node.getBeginLine() +", column " + node.getBeginColumn()); } */ // } } else if (node.jjtGetParent() instanceof ASTWhileStatement) { ASTWhileStatement statement = (ASTWhileStatement) node.jjtGetParent(); List<ASTStatement> children = statement.findChildrenOfType(ASTStatement.class); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("(LastChildren): size " + children.size()); } ASTStatement lastChild = children.get(children.size() - 1); // Push on stack if this Node is the LAST Statement associated with // the FOR Statment if (node.equals(lastChild)) { dataFlow.pushOnStack(NodeType.WHILE_LAST_STATEMENT, dataFlow.getLast()); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("pushOnStack WHILE_LAST_STATEMENT: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } } } else if (node.jjtGetParent() instanceof ASTForStatement) { ASTForStatement statement = (ASTForStatement) node.jjtGetParent(); List<ASTStatement> children = statement.findChildrenOfType(ASTStatement.class); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("(LastChildren): size " + children.size()); } ASTStatement lastChild = children.get(children.size() - 1); // Push on stack if this Node is the LAST Statement associated with // the FOR Statment if (node.equals(lastChild)) { dataFlow.pushOnStack(NodeType.FOR_END, dataFlow.getLast()); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("pushOnStack (LastChildStatemnt) FOR_END: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } } } else if (node.jjtGetParent() instanceof ASTLabelledStatement) { dataFlow.pushOnStack(NodeType.LABEL_LAST_STATEMENT, dataFlow.getLast()); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("pushOnStack LABEL_LAST_STATEMENT: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } } if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("exit ASTStatement: line " + node.getBeginLine() + ", column " + node.getBeginColumn() + " -> " + node.getClass().getCanonicalName() + " ->-> " + node.jjtGetParent().getClass().getCanonicalName()); } return data; } @Override public Object visit(ASTUnlabelledStatement node, Object data) { if (!(data instanceof Structure)) { return data; } Structure dataFlow = (Structure) data; super.visit(node, data); if (node.jjtGetParent() instanceof ASTLabelledStatement) { dataFlow.pushOnStack(NodeType.LABEL_LAST_STATEMENT, dataFlow.getLast()); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("pushOnStack (ASTUnlabelledStatement) LABEL_LAST_STATEMENT: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } } return data; } @Override public Object visit(ASTCaseStatement node, Object data) { if (!(data instanceof Structure)) { return data; } Structure dataFlow = (Structure) data; /* * A PL/SQL CASE statement may be either:- SIMPLE, e.g. CASE * case_operand WHEN when_operand THEN statement ; ELSE statement ; END * CASE SEARCHED, e.g. CASE WHEN boolean_expression THEN statement ; * ELSE statement ; END CASE * * A SIMPLE CASE statement may be treated as a normal Java SWITCH * statement ( see visit(ASTExpression)), but a SEARCHED CASE statement * must have an atificial start node */ // CASE is "searched case statement" if (null == node.getFirstChildOfType(ASTExpression.class)) { dataFlow.createNewNode(node); dataFlow.pushOnStack(NodeType.SWITCH_START, dataFlow.getLast()); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest( "pushOnStack SWITCH_START: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } } super.visit(node, data); dataFlow.pushOnStack(NodeType.SWITCH_END, dataFlow.getLast()); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("pushOnStack SWITCH_END: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } return data; } @Override public Object visit(ASTCaseWhenClause node, Object data) { if (!(data instanceof Structure)) { return data; } Structure dataFlow = (Structure) data; // Java ASTSwitchLabel // SRT dataFlow.createNewNode(node); dataFlow.pushOnStack(NodeType.CASE_LAST_STATEMENT, dataFlow.getLast()); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("pushOnStack CASE_LAST_STATEMENT: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } super.visit(node, data); // dataFlow.createNewNode(node); dataFlow.pushOnStack(NodeType.BREAK_STATEMENT, dataFlow.getLast()); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("pushOnStack (ASTCaseWhenClause) BREAK_STATEMENT: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } return data; } @Override public Object visit(ASTIfStatement node, Object data) { if (!(data instanceof Structure)) { return data; } Structure dataFlow = (Structure) data; LOGGER.finest("ElsifClause) super.visit line"); super.visit(node, data); /* * PLSQL AST now has explicit ELSIF and ELSE clauses All of the * ELSE_END_STATEMENTS in an IF clause should point to the outer last * clause because we have to convert a single PL/SQL IF/ELSIF/ELSE * satement into the equivalent set of nested Java if/else {if/else * {if/else}} statements */ List<ASTElsifClause> elsifs = node.findChildrenOfType(ASTElsifClause.class); ASTElseClause elseClause = node.getFirstChildOfType(ASTElseClause.class); // The IF statements have no ELSE or ELSIF statements and this is the last // statement if (null == elseClause && elsifs.isEmpty()) { dataFlow.pushOnStack(NodeType.IF_LAST_STATEMENT_WITHOUT_ELSE, dataFlow.getLast()); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("pushOnStack (ASTIfClause - no ELSIFs) IF_LAST_STATEMENT_WITHOUT_ELSE: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } } else { if (!elsifs.isEmpty()) { ASTElsifClause lastElsifClause = elsifs.get(elsifs.size() - 1); for (ASTElsifClause elsifClause : elsifs) { /* * If last ELSIF clause is not followed by a ELSE clause * then the last ELSIF is equivalent to an if statement * without an else Otherwise, it is equivalent to an if/else * statement */ if (lastElsifClause.equals(elsifClause) && elseClause == null) { dataFlow.pushOnStack(NodeType.IF_LAST_STATEMENT_WITHOUT_ELSE, dataFlow.getLast()); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest( "pushOnStack (ASTIfClause - with ELSIFs) IF_LAST_STATEMENT_WITHOUT_ELSE: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } } { dataFlow.pushOnStack(NodeType.ELSE_LAST_STATEMENT, dataFlow.getLast()); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("pushOnStack (ASTIfClause - with ELSIFs) ELSE_LAST_STATEMENT : line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } } } } if (null != elseClause) { // Output one terminating else dataFlow.pushOnStack(NodeType.ELSE_LAST_STATEMENT, dataFlow.getLast()); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("pushOnStack (ASTIfClause - with ELSE) ELSE_LAST_STATEMENT : line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } } } return data; } @Override public Object visit(ASTElseClause node, Object data) { if (!(data instanceof Structure)) { return data; } Structure dataFlow = (Structure) data; if (node.jjtGetParent() instanceof ASTIfStatement) { dataFlow.pushOnStack(NodeType.IF_LAST_STATEMENT, dataFlow.getLast()); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("pushOnStack (Visit ASTElseClause) IF_LAST_STATEMENT: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); LOGGER.finest("ElseClause) super.visit line"); } } else { // SRT dataFlow.createNewNode(node); dataFlow.pushOnStack(NodeType.SWITCH_LAST_DEFAULT_STATEMENT, dataFlow.getLast()); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("pushOnStack SWITCH_LAST_DEFAULT_STATEMENT: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } } super.visit(node, data); return data; } @Override public Object visit(ASTElsifClause node, Object data) { if (!(data instanceof Structure)) { return data; } Structure dataFlow = (Structure) data; dataFlow.pushOnStack(NodeType.IF_LAST_STATEMENT, dataFlow.getLast()); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("pushOnStack (Visit ASTElsifClause) IF_LAST_STATEMENT: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); LOGGER.finest("ElsifClause) super.visit line"); } super.visit(node, data); return data; } /** * Treat a PLSQL CONTINUE like a Java "continue" * * @param node * @param data * @return */ @Override public Object visit(ASTContinueStatement node, Object data) { if (!(data instanceof Structure)) { return data; } Structure dataFlow = (Structure) data; dataFlow.createNewNode(node); dataFlow.pushOnStack(NodeType.CONTINUE_STATEMENT, dataFlow.getLast()); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("pushOnStack (ASTContinueStatement) CONTINUE_STATEMENT: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } return super.visit(node, data); } /** * Treat a PLSQL EXIT like a Java "break" * * @param node * @param data * @return */ @Override public Object visit(ASTExitStatement node, Object data) { if (!(data instanceof Structure)) { return data; } Structure dataFlow = (Structure) data; dataFlow.createNewNode(node); dataFlow.pushOnStack(NodeType.BREAK_STATEMENT, dataFlow.getLast()); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("pushOnStack (ASTExitStatement) BREAK_STATEMENT: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } return super.visit(node, data); } /** * Treat a PLSQL GOTO like a Java "continue" * * @param node * @param data * @return */ @Override public Object visit(ASTGotoStatement node, Object data) { if (!(data instanceof Structure)) { return data; } Structure dataFlow = (Structure) data; dataFlow.createNewNode(node); dataFlow.pushOnStack(NodeType.CONTINUE_STATEMENT, dataFlow.getLast()); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("pushOnStack (ASTGotoStatement) CONTINUE_STATEMENT (GOTO): line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } return super.visit(node, data); } @Override public Object visit(ASTReturnStatement node, Object data) { if (!(data instanceof Structure)) { return data; } Structure dataFlow = (Structure) data; dataFlow.createNewNode(node); dataFlow.pushOnStack(NodeType.RETURN_STATEMENT, dataFlow.getLast()); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest( "pushOnStack RETURN_STATEMENT: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } return super.visit(node, data); } @Override public Object visit(ASTRaiseStatement node, Object data) { if (!(data instanceof Structure)) { return data; } Structure dataFlow = (Structure) data; dataFlow.createNewNode(node); dataFlow.pushOnStack(NodeType.THROW_STATEMENT, dataFlow.getLast()); if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.finest("pushOnStack THROW: line " + node.getBeginLine() + ", column " + node.getBeginColumn()); } return super.visit(node, data); } /* * The method handles the special "for" loop. It creates always an * expression node even if the loop looks like for(;;). */ private void addForExpressionNode(Node node, Structure dataFlow) { ASTForStatement parent = (ASTForStatement) node.jjtGetParent(); boolean hasExpressionChild = false; for (int i = 0; i < parent.jjtGetNumChildren(); i++) { if (parent.jjtGetChild(i) instanceof ASTExpression) { hasExpressionChild = true; } } if (!hasExpressionChild) { if (node instanceof ASTStatement) { /* * if (!hasForInitNode && !hasForUpdateNode) { * dataFlow.createNewNode(node); * dataFlow.pushOnStack(NodeType.FOR_EXPR, dataFlow.getLast()); * } */ } } } }