//===--- CFGStmtVisitor.h - Visitor for Stmts in a CFG ----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file defines the CFGStmtVisitor interface, which extends // StmtVisitor. This interface is useful for visiting statements in a CFG // where some statements have implicit control-flow and thus should // be treated specially. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_ANALYSIS_CFGSTMTVISITOR_H #define LLVM_CLANG_ANALYSIS_CFGSTMTVISITOR_H #include "clang/AST/StmtVisitor.h" #include "clang/Analysis/CFG.h" namespace clang { #define DISPATCH_CASE(CLASS) \ case Stmt::CLASS ## Class: return \ static_cast(this)->BlockStmt_Visit ## CLASS(static_cast(S)); #define DEFAULT_BLOCKSTMT_VISIT(CLASS) RetTy BlockStmt_Visit ## CLASS(CLASS *S)\ { return\ static_cast(this)->BlockStmt_VisitImplicitControlFlowExpr(\ cast(S)); } template class CFGStmtVisitor : public StmtVisitor { Stmt *CurrentBlkStmt; struct NullifyStmt { Stmt*& S; NullifyStmt(Stmt*& s) : S(s) {} ~NullifyStmt() { S = NULL; } }; public: CFGStmtVisitor() : CurrentBlkStmt(NULL) {} Stmt *getCurrentBlkStmt() const { return CurrentBlkStmt; } RetTy Visit(Stmt *S) { if (S == CurrentBlkStmt || !static_cast(this)->getCFG().isBlkExpr(S)) return StmtVisitor::Visit(S); else return RetTy(); } /// VisitConditionVariableInit - Handle the initialization of condition /// variables at branches. Valid statements include IfStmt, ForStmt, /// WhileStmt, and SwitchStmt. RetTy VisitConditionVariableInit(Stmt *S) { return RetTy(); } /// BlockVisit_XXX - Visitor methods for visiting the "root" statements in /// CFGBlocks. Root statements are the statements that appear explicitly in /// the list of statements in a CFGBlock. For substatements, or when there /// is no implementation provided for a BlockStmt_XXX method, we default /// to using StmtVisitor's Visit method. RetTy BlockStmt_Visit(Stmt *S) { CurrentBlkStmt = S; NullifyStmt cleanup(CurrentBlkStmt); switch (S->getStmtClass()) { case Stmt::IfStmtClass: case Stmt::ForStmtClass: case Stmt::WhileStmtClass: case Stmt::SwitchStmtClass: return static_cast(this)->VisitConditionVariableInit(S); DISPATCH_CASE(StmtExpr) DISPATCH_CASE(ConditionalOperator) DISPATCH_CASE(BinaryConditionalOperator) DISPATCH_CASE(ObjCForCollectionStmt) DISPATCH_CASE(CXXForRangeStmt) case Stmt::BinaryOperatorClass: { BinaryOperator* B = cast(S); if (B->isLogicalOp()) return static_cast(this)->BlockStmt_VisitLogicalOp(B); else if (B->getOpcode() == BO_Comma) return static_cast(this)->BlockStmt_VisitComma(B); // Fall through. } default: if (isa(S)) return static_cast(this)->BlockStmt_VisitExpr(cast(S)); else return static_cast(this)->BlockStmt_VisitStmt(S); } } DEFAULT_BLOCKSTMT_VISIT(StmtExpr) DEFAULT_BLOCKSTMT_VISIT(ConditionalOperator) DEFAULT_BLOCKSTMT_VISIT(BinaryConditionalOperator) RetTy BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) { return static_cast(this)->BlockStmt_VisitStmt(S); } RetTy BlockStmt_VisitCXXForRangeStmt(CXXForRangeStmt *S) { return static_cast(this)->BlockStmt_VisitStmt(S); } RetTy BlockStmt_VisitImplicitControlFlowExpr(Expr *E) { return static_cast(this)->BlockStmt_VisitExpr(E); } RetTy BlockStmt_VisitExpr(Expr *E) { return static_cast(this)->BlockStmt_VisitStmt(E); } RetTy BlockStmt_VisitStmt(Stmt *S) { return static_cast(this)->Visit(S); } RetTy BlockStmt_VisitLogicalOp(BinaryOperator* B) { return static_cast(this)->BlockStmt_VisitImplicitControlFlowExpr(B); } RetTy BlockStmt_VisitComma(BinaryOperator* B) { return static_cast(this)->BlockStmt_VisitImplicitControlFlowExpr(B); } //===--------------------------------------------------------------------===// // Utility methods. Not called by default (but subclasses may use them). //===--------------------------------------------------------------------===// /// VisitChildren: Call "Visit" on each child of S. void VisitChildren(Stmt *S) { switch (S->getStmtClass()) { default: break; case Stmt::StmtExprClass: { CompoundStmt *CS = cast(S)->getSubStmt(); if (CS->body_empty()) return; static_cast(this)->Visit(CS->body_back()); return; } case Stmt::BinaryOperatorClass: { BinaryOperator* B = cast(S); if (B->getOpcode() != BO_Comma) break; static_cast(this)->Visit(B->getRHS()); return; } } for (Stmt::child_range I = S->children(); I; ++I) if (*I) static_cast(this)->Visit(*I); } }; #undef DEFAULT_BLOCKSTMT_VISIT #undef DISPATCH_CASE } // end namespace clang #endif