Index: clang/include/clang/StaticAnalyzer/Core/Checker.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/Checker.h +++ clang/include/clang/StaticAnalyzer/Core/Checker.h @@ -223,6 +223,20 @@ } }; +class BeginAnalysis { + template + static void _checkBeginAnalysis(void *checker, CheckerContext &C) { + ((const CHECKER *)checker)->checkBeginAnalysis(C); + } + +public: + template + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForBeginAnalysis(CheckerManager::CheckBeginAnalysisFunc( + checker, _checkBeginAnalysis)); + } +}; + class EndAnalysis { template static void _checkEndAnalysis(void *checker, ExplodedGraph &G, Index: clang/include/clang/StaticAnalyzer/Core/CheckerManager.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ clang/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -299,6 +299,10 @@ const Stmt *S, ExprEngine &Eng, const ProgramPoint &PP); + /// Run checkers for begin of analysis. + void runCheckersForBeginAnalysis(ExplodedNodeSet &Dst, const BlockEdge &L, + ExplodedNode *Pred, ExprEngine &Eng); + /// Run checkers for end of analysis. void runCheckersForEndAnalysis(ExplodedGraph &G, BugReporter &BR, ExprEngine &Eng); @@ -455,6 +459,8 @@ CheckerFn; + using CheckBeginAnalysisFunc = CheckerFn; + using CheckEndAnalysisFunc = CheckerFn; @@ -517,6 +523,7 @@ void _registerForBind(CheckBindFunc checkfn); + void _registerForBeginAnalysis(CheckBeginAnalysisFunc checkfn); void _registerForEndAnalysis(CheckEndAnalysisFunc checkfn); void _registerForBeginFunction(CheckBeginFunctionFunc checkfn); @@ -628,6 +635,7 @@ std::vector BindCheckers; + std::vector BeginAnalysisCheckers; std::vector EndAnalysisCheckers; std::vector BeginFunctionCheckers; Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h +++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h @@ -56,6 +56,8 @@ return Eng.getAnalysisManager(); } + CheckerManager &getCheckerManager() { return Eng.getCheckerManager(); } + ConstraintManager &getConstraintManager() { return Eng.getConstraintManager(); } Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -358,6 +358,10 @@ /// visit for CallExpr. void processCallExit(ExplodedNode *Pred) override; + /// Called by CoreEngine when the analysis worklist starts. + void processBeginWorklist(NodeBuilderContext &NBC, ExplodedNode *Pred, + ExplodedNodeSet &Dst, const BlockEdge &L) override; + /// Called by CoreEngine when the analysis worklist has terminated. void processEndWorklist() override; Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h +++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h @@ -163,8 +163,13 @@ const LocationContext *LCtx, const char *NL, unsigned int Space, bool IsDot) const = 0; + /// Called by CoreEngine when the analysis worklist starts. + virtual void processBeginWorklist(NodeBuilderContext &NBC, ExplodedNode *Pred, + ExplodedNodeSet &Dst, + const BlockEdge &L) = 0; + /// Called by CoreEngine when the analysis worklist is either empty or the - // maximum number of analysis steps have been reached. + /// maximum number of analysis steps have been reached. virtual void processEndWorklist() = 0; }; Index: clang/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp +++ clang/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp @@ -47,6 +47,7 @@ check::DeadSymbols, check::BeginFunction, check::EndFunction, + check::BeginAnalysis, check::EndAnalysis, check::EndOfTranslationUnit, eval::Call, @@ -193,6 +194,13 @@ /// check::EndFunction void checkEndFunction(const ReturnStmt *RS, CheckerContext &Ctx) const {} + /// Called when the analysis starts. + /// + /// This callback should be used to construct the checker's fields. + /// + /// check::BeginAnalysis + void checkBeginAnalysis(const Decl *D, BugReporter &BR); + /// Called after all the paths in the ExplodedGraph reach end of path /// - the symbolic execution graph is fully explored. /// Index: clang/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp @@ -23,10 +23,14 @@ using namespace ento; namespace { -class TraversalDumper : public Checker< check::BranchCondition, - check::BeginFunction, - check::EndFunction > { +class TraversalDumper + : public Checker { public: + void checkBeginAnalysis(CheckerContext &C) const; + void checkEndAnalysis(ExplodedGraph &G, BugReporter &BR, + ExprEngine &Eng) const; void checkBranchCondition(const Stmt *Condition, CheckerContext &C) const; void checkBeginFunction(CheckerContext &C) const; void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const; @@ -51,6 +55,15 @@ << Parent->getStmtClassName() << "\n"; } +void TraversalDumper::checkBeginAnalysis(CheckerContext &) const { + llvm::outs() << "--BEGIN ANALYSIS--\n"; +} + +void TraversalDumper::checkEndAnalysis(ExplodedGraph &G, BugReporter &BR, + ExprEngine &Eng) const { + llvm::outs() << "--END ANALYSIS--\n"; +} + void TraversalDumper::checkBeginFunction(CheckerContext &C) const { llvm::outs() << "--BEGIN FUNCTION--\n"; } Index: clang/lib/StaticAnalyzer/Core/CheckerManager.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ clang/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -399,6 +399,41 @@ expandGraphWithCheckers(C, Dst, Src); } +namespace { +struct CheckBeginAnalysisContext { + using CheckersTy = std::vector; + + const CheckersTy &Checkers; + ExprEngine &Eng; + const ProgramPoint &PP; + + CheckBeginAnalysisContext(const CheckersTy &Checkers, ExprEngine &Eng, + const ProgramPoint &PP) + : Checkers(Checkers), Eng(Eng), PP(PP) {} + + CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } + CheckersTy::const_iterator checkers_end() { return Checkers.end(); } + + void runChecker(CheckerManager::CheckBeginAnalysisFunc checkFn, + NodeBuilder &Bldr, ExplodedNode *Pred) { + const ProgramPoint &L = PP.withTag(checkFn.Checker); + CheckerContext C(Bldr, Eng, Pred, L); + + checkFn(C); + } +}; +} // namespace + +void CheckerManager::runCheckersForBeginAnalysis(ExplodedNodeSet &Dst, + const BlockEdge &L, + ExplodedNode *Pred, + ExprEngine &Eng) { + ExplodedNodeSet Src; + Src.insert(Pred); + CheckBeginAnalysisContext C(BeginAnalysisCheckers, Eng, L); + expandGraphWithCheckers(C, Dst, Src); +} + void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G, BugReporter &BR, ExprEngine &Eng) { @@ -827,6 +862,10 @@ BindCheckers.push_back(checkfn); } +void CheckerManager::_registerForBeginAnalysis(CheckBeginAnalysisFunc checkfn) { + BeginAnalysisCheckers.push_back(checkfn); +} + void CheckerManager::_registerForEndAnalysis(CheckEndAnalysisFunc checkfn) { EndAnalysisCheckers.push_back(checkfn); } Index: clang/lib/StaticAnalyzer/Core/CoreEngine.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/CoreEngine.cpp +++ clang/lib/StaticAnalyzer/Core/CoreEngine.cpp @@ -113,6 +113,8 @@ NodeBuilderContext BuilderCtx(*this, StartLoc.getDst(), Node); ExplodedNodeSet DstBegin; + + SubEng.processBeginWorklist(BuilderCtx, Node, DstBegin, StartLoc); SubEng.processBeginOfFunction(BuilderCtx, Node, DstBegin, StartLoc); enqueue(DstBegin); Index: clang/lib/StaticAnalyzer/Core/ExprEngine.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -620,6 +620,13 @@ IsDot); } +void ExprEngine::processBeginWorklist(NodeBuilderContext &NBC, + ExplodedNode *Pred, ExplodedNodeSet &Dst, + const BlockEdge &L) { + SaveAndRestore NodeContextRAII(currBldrCtx, &NBC); + getCheckerManager().runCheckersForBeginAnalysis(Dst, L, Pred, *this); +} + void ExprEngine::processEndWorklist() { getCheckerManager().runCheckersForEndAnalysis(G, BR, *this); } Index: clang/test/Analysis/traversal-begin-end-function.c =================================================================== --- clang/test/Analysis/traversal-begin-end-function.c +++ clang/test/Analysis/traversal-begin-end-function.c @@ -2,17 +2,9 @@ void inline_callee(int i); -// CHECK: --BEGIN FUNCTION-- void inline_caller() { - // CHECK: --BEGIN FUNCTION-- - // CHECK: --BEGIN FUNCTION-- - // CHECK: --BEGIN FUNCTION-- inline_callee(3); - // CHECK: --END FUNCTION-- - // CHECK: --END FUNCTION-- - // CHECK: --END FUNCTION-- } -// CHECK: --END FUNCTION-- void inline_callee(int i) { if (i <= 1) @@ -20,3 +12,17 @@ inline_callee(i - 1); } + +// CHECK: --BEGIN ANALYSIS-- +// CHECK-NEXT: --BEGIN FUNCTION-- +// CHECK-NEXT: --BEGIN FUNCTION-- +// CHECK-NEXT: IfStmt +// CHECK-NEXT: --BEGIN FUNCTION-- +// CHECK-NEXT: IfStmt +// CHECK-NEXT: --BEGIN FUNCTION-- +// CHECK-NEXT: IfStmt +// CHECK-NEXT: --END FUNCTION-- +// CHECK-NEXT: --END FUNCTION-- +// CHECK-NEXT: --END FUNCTION-- +// CHECK-NEXT: --END FUNCTION-- +// CHECK-NEXT: --END ANALYSIS--