From 9f9141cd46b87cefd74625d92634a5aa93d2c9c6 Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Tue, 20 Nov 2007 03:01:58 +0000 Subject: [PATCH] Updated CFGStmtVisitor and CFGRecStmtVisitor to have a notion of "block-expressions" when visiting arbitrary expressions (via calls to "Visit()"). This results in a refactoring where a dataflow analysis no longer needs to always special case when handling block-expressions versus non-block expressions. Updated LiveVariables and UninitializedValues to conform to the slightly altered interface of these visitor classes. Thanks to Nuno Lopes for providing a test case that illustrated some fundamental problems in the current design of the CFGXXXStmtVisitor classes and how they were used. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@44246 91177308-0d34-0410-b5e6-96231b3b80d8 --- Analysis/LiveVariables.cpp | 19 +++----------- Analysis/UninitializedValues.cpp | 2 ++ .../Analysis/Visitors/CFGRecStmtVisitor.h | 12 ++------- .../clang/Analysis/Visitors/CFGStmtVisitor.h | 26 +++++++++++++++++-- 4 files changed, 31 insertions(+), 28 deletions(-) diff --git a/Analysis/LiveVariables.cpp b/Analysis/LiveVariables.cpp index 3118a30d1f..eba1a77941 100644 --- a/Analysis/LiveVariables.cpp +++ b/Analysis/LiveVariables.cpp @@ -35,6 +35,7 @@ class RegisterDecls : public CFGRecStmtDeclVisitor { public: RegisterDecls(LiveVariables::AnalysisDataTy& ad) : AD(ad) {} void VisitVarDecl(VarDecl* VD) { AD.Register(VD); } + CFG& getCFG() { return AD.getCFG(); } }; } // end anonymous namespace @@ -52,34 +53,25 @@ namespace { static const bool Alive = true; static const bool Dead = false; -class TransferFuncs : public CFGStmtVisitor { +class TransferFuncs : public CFGRecStmtVisitor { LiveVariables::AnalysisDataTy& AD; LiveVariables::ValTy LiveState; public: TransferFuncs(LiveVariables::AnalysisDataTy& ad) : AD(ad) {} LiveVariables::ValTy& getVal() { return LiveState; } + CFG& getCFG() { return AD.getCFG(); } void VisitDeclRefExpr(DeclRefExpr* DR); void VisitBinaryOperator(BinaryOperator* B); void VisitAssign(BinaryOperator* B); void VisitDeclStmt(DeclStmt* DS); void VisitUnaryOperator(UnaryOperator* U); - void VisitStmt(Stmt* S); - void VisitExpr(Expr* E); - void BlockStmt_VisitExpr(Expr *E); void Visit(Stmt *S); DeclRefExpr* FindDeclRef(Stmt *S); }; - -void TransferFuncs::VisitExpr(Expr * E) { - if (AD.getCFG().isBlkExpr(E)) return; - else VisitStmt(E); -} -void TransferFuncs::VisitStmt(Stmt* S) { VisitChildren(S); } - void TransferFuncs::Visit(Stmt *S) { if (AD.Observer) AD.Observer->ObserveStmt(S,AD,LiveState); @@ -160,11 +152,6 @@ void TransferFuncs::VisitDeclStmt(DeclStmt* DS) { LiveState(D,AD) = Dead; } -void TransferFuncs::BlockStmt_VisitExpr(Expr* E) { - assert (AD.getCFG().isBlkExpr(E)); - VisitChildren(E); -} - } // end anonymous namespace //===----------------------------------------------------------------------===// diff --git a/Analysis/UninitializedValues.cpp b/Analysis/UninitializedValues.cpp index 6f24872cd2..0a496595f6 100644 --- a/Analysis/UninitializedValues.cpp +++ b/Analysis/UninitializedValues.cpp @@ -34,6 +34,7 @@ public: RegisterDecls(UninitializedValues::AnalysisDataTy& ad) : AD(ad) {} void VisitBlockVarDecl(BlockVarDecl* VD) { AD.Register(VD); } + CFG& getCFG() { return AD.getCFG(); } }; } // end anonymous namespace @@ -58,6 +59,7 @@ public: } UninitializedValues::ValTy& getVal() { return V; } + CFG& getCFG() { return AD.getCFG(); } bool VisitDeclRefExpr(DeclRefExpr* DR); bool VisitBinaryOperator(BinaryOperator* B); diff --git a/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h b/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h index 002c2f0546..bfe998bf9d 100644 --- a/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h +++ b/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h @@ -22,18 +22,10 @@ template class CFGRecStmtVisitor : public CFGStmtVisitor { public: - void Visit(Stmt* S) { - static_cast< CFGStmtVisitor* >(this)->Visit(S); + void VisitStmt(Stmt* S) { static_cast< ImplClass* >(this)->VisitChildren(S); } - - void BlockStmt_Visit(Stmt* S) { - assert (S); - - static_cast< CFGStmtVisitor* >(this)->BlockStmt_Visit(S); - static_cast< ImplClass* >(this)->VisitChildren(S); - } - + // Defining operator() allows the visitor to be used as a C++ style functor. void operator()(Stmt* S) { static_cast(this)->BlockStmt_Visit(S);} }; diff --git a/include/clang/Analysis/Visitors/CFGStmtVisitor.h b/include/clang/Analysis/Visitors/CFGStmtVisitor.h index afc9873093..8ece7d0acb 100644 --- a/include/clang/Analysis/Visitors/CFGStmtVisitor.h +++ b/include/clang/Analysis/Visitors/CFGStmtVisitor.h @@ -33,14 +33,36 @@ static_cast(this)->BlockStmt_Visit ## CLASS(static_cast(S)); template class CFGStmtVisitor : public StmtVisitor { -public: + Stmt* CurrentBlkExpr; + + struct NullifyStmt { + Stmt*& S; + + NullifyStmt(Stmt*& s) : S(s) {} + ~NullifyStmt() { S = NULL; } + }; + +public: + CFGStmtVisitor() : CurrentBlkExpr(NULL) {} + + RetTy Visit(Stmt* S) { + if (S == CurrentBlkExpr || + !static_cast(this)->getCFG().isBlkExpr(S)) + return StmtVisitor::Visit(S); + else + 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) { - switch (S->getStmtClass()) { + CurrentBlkExpr = S; + NullifyStmt cleanup(CurrentBlkExpr); + + switch (S->getStmtClass()) { DISPATCH_CASE(CallExpr) DISPATCH_CASE(StmtExpr) DISPATCH_CASE(ConditionalOperator) -- 2.40.0