diff options
Diffstat (limited to 'clang/lib/StaticAnalyzer/Core/CheckerManager.cpp')
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/CheckerManager.cpp | 678 |
1 files changed, 678 insertions, 0 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp new file mode 100644 index 0000000..0bcc343 --- /dev/null +++ b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -0,0 +1,678 @@ +//===--- CheckerManager.cpp - Static Analyzer Checker Manager -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Defines the Static Analyzer Checker Manager. +// +//===----------------------------------------------------------------------===// + +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h" +#include "clang/Analysis/ProgramPoint.h" +#include "clang/AST/DeclBase.h" + +using namespace clang; +using namespace ento; + +bool CheckerManager::hasPathSensitiveCheckers() const { + return !StmtCheckers.empty() || + !PreObjCMessageCheckers.empty() || + !PostObjCMessageCheckers.empty() || + !LocationCheckers.empty() || + !BindCheckers.empty() || + !EndAnalysisCheckers.empty() || + !EndPathCheckers.empty() || + !BranchConditionCheckers.empty() || + !LiveSymbolsCheckers.empty() || + !DeadSymbolsCheckers.empty() || + !RegionChangesCheckers.empty() || + !EvalAssumeCheckers.empty() || + !EvalCallCheckers.empty() || + !InlineCallCheckers.empty(); +} + +void CheckerManager::finishedCheckerRegistration() { +#ifndef NDEBUG + // Make sure that for every event that has listeners, there is at least + // one dispatcher registered for it. + for (llvm::DenseMap<EventTag, EventInfo>::iterator + I = Events.begin(), E = Events.end(); I != E; ++I) + assert(I->second.HasDispatcher && "No dispatcher registered for an event"); +#endif +} + +//===----------------------------------------------------------------------===// +// Functions for running checkers for AST traversing.. +//===----------------------------------------------------------------------===// + +void CheckerManager::runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr, + BugReporter &BR) { + assert(D); + + unsigned DeclKind = D->getKind(); + CachedDeclCheckers *checkers = 0; + CachedDeclCheckersMapTy::iterator CCI = CachedDeclCheckersMap.find(DeclKind); + if (CCI != CachedDeclCheckersMap.end()) { + checkers = &(CCI->second); + } else { + // Find the checkers that should run for this Decl and cache them. + checkers = &CachedDeclCheckersMap[DeclKind]; + for (unsigned i = 0, e = DeclCheckers.size(); i != e; ++i) { + DeclCheckerInfo &info = DeclCheckers[i]; + if (info.IsForDeclFn(D)) + checkers->push_back(info.CheckFn); + } + } + + assert(checkers); + for (CachedDeclCheckers::iterator + I = checkers->begin(), E = checkers->end(); I != E; ++I) + (*I)(D, mgr, BR); +} + +void CheckerManager::runCheckersOnASTBody(const Decl *D, AnalysisManager& mgr, + BugReporter &BR) { + assert(D && D->hasBody()); + + for (unsigned i = 0, e = BodyCheckers.size(); i != e; ++i) + BodyCheckers[i](D, mgr, BR); +} + +//===----------------------------------------------------------------------===// +// Functions for running checkers for path-sensitive checking. +//===----------------------------------------------------------------------===// + +template <typename CHECK_CTX> +static void expandGraphWithCheckers(CHECK_CTX checkCtx, + ExplodedNodeSet &Dst, + const ExplodedNodeSet &Src) { + const NodeBuilderContext &BldrCtx = checkCtx.Eng.getBuilderContext(); + if (Src.empty()) + return; + + typename CHECK_CTX::CheckersTy::const_iterator + I = checkCtx.checkers_begin(), E = checkCtx.checkers_end(); + if (I == E) { + Dst.insert(Src); + return; + } + + ExplodedNodeSet Tmp1, Tmp2; + const ExplodedNodeSet *PrevSet = &Src; + + for (; I != E; ++I) { + ExplodedNodeSet *CurrSet = 0; + if (I+1 == E) + CurrSet = &Dst; + else { + CurrSet = (PrevSet == &Tmp1) ? &Tmp2 : &Tmp1; + CurrSet->clear(); + } + + NodeBuilder B(*PrevSet, *CurrSet, BldrCtx); + for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); + NI != NE; ++NI) { + checkCtx.runChecker(*I, B, *NI); + } + + // If all the produced transitions are sinks, stop. + if (CurrSet->empty()) + return; + + // Update which NodeSet is the current one. + PrevSet = CurrSet; + } +} + +namespace { + struct CheckStmtContext { + typedef SmallVectorImpl<CheckerManager::CheckStmtFunc> CheckersTy; + bool IsPreVisit; + const CheckersTy &Checkers; + const Stmt *S; + ExprEngine &Eng; + bool wasInlined; + + CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } + CheckersTy::const_iterator checkers_end() { return Checkers.end(); } + + CheckStmtContext(bool isPreVisit, const CheckersTy &checkers, + const Stmt *s, ExprEngine &eng, bool wasInlined = false) + : IsPreVisit(isPreVisit), Checkers(checkers), S(s), Eng(eng), + wasInlined(wasInlined) {} + + void runChecker(CheckerManager::CheckStmtFunc checkFn, + NodeBuilder &Bldr, ExplodedNode *Pred) { + // FIXME: Remove respondsToCallback from CheckerContext; + ProgramPoint::Kind K = IsPreVisit ? ProgramPoint::PreStmtKind : + ProgramPoint::PostStmtKind; + const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, + Pred->getLocationContext(), checkFn.Checker); + CheckerContext C(Bldr, Eng, Pred, L, wasInlined); + checkFn(S, C); + } + }; +} + +/// \brief Run checkers for visiting Stmts. +void CheckerManager::runCheckersForStmt(bool isPreVisit, + ExplodedNodeSet &Dst, + const ExplodedNodeSet &Src, + const Stmt *S, + ExprEngine &Eng, + bool wasInlined) { + CheckStmtContext C(isPreVisit, *getCachedStmtCheckersFor(S, isPreVisit), + S, Eng, wasInlined); + expandGraphWithCheckers(C, Dst, Src); +} + +namespace { + struct CheckObjCMessageContext { + typedef std::vector<CheckerManager::CheckObjCMessageFunc> CheckersTy; + bool IsPreVisit; + const CheckersTy &Checkers; + const ObjCMessage &Msg; + ExprEngine &Eng; + + CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } + CheckersTy::const_iterator checkers_end() { return Checkers.end(); } + + CheckObjCMessageContext(bool isPreVisit, const CheckersTy &checkers, + const ObjCMessage &msg, ExprEngine &eng) + : IsPreVisit(isPreVisit), Checkers(checkers), Msg(msg), Eng(eng) { } + + void runChecker(CheckerManager::CheckObjCMessageFunc checkFn, + NodeBuilder &Bldr, ExplodedNode *Pred) { + ProgramPoint::Kind K = IsPreVisit ? ProgramPoint::PreStmtKind : + ProgramPoint::PostStmtKind; + const ProgramPoint &L = + ProgramPoint::getProgramPoint(Msg.getMessageExpr(), + K, Pred->getLocationContext(), + checkFn.Checker); + CheckerContext C(Bldr, Eng, Pred, L); + + checkFn(Msg, C); + } + }; +} + +/// \brief Run checkers for visiting obj-c messages. +void CheckerManager::runCheckersForObjCMessage(bool isPreVisit, + ExplodedNodeSet &Dst, + const ExplodedNodeSet &Src, + const ObjCMessage &msg, + ExprEngine &Eng) { + CheckObjCMessageContext C(isPreVisit, + isPreVisit ? PreObjCMessageCheckers + : PostObjCMessageCheckers, + msg, Eng); + expandGraphWithCheckers(C, Dst, Src); +} + +namespace { + struct CheckLocationContext { + typedef std::vector<CheckerManager::CheckLocationFunc> CheckersTy; + const CheckersTy &Checkers; + SVal Loc; + bool IsLoad; + const Stmt *NodeEx; /* Will become a CFGStmt */ + const Stmt *BoundEx; + ExprEngine &Eng; + + CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } + CheckersTy::const_iterator checkers_end() { return Checkers.end(); } + + CheckLocationContext(const CheckersTy &checkers, + SVal loc, bool isLoad, const Stmt *NodeEx, + const Stmt *BoundEx, + ExprEngine &eng) + : Checkers(checkers), Loc(loc), IsLoad(isLoad), NodeEx(NodeEx), + BoundEx(BoundEx), Eng(eng) {} + + void runChecker(CheckerManager::CheckLocationFunc checkFn, + NodeBuilder &Bldr, ExplodedNode *Pred) { + ProgramPoint::Kind K = IsLoad ? ProgramPoint::PreLoadKind : + ProgramPoint::PreStoreKind; + const ProgramPoint &L = + ProgramPoint::getProgramPoint(NodeEx, K, + Pred->getLocationContext(), + checkFn.Checker); + CheckerContext C(Bldr, Eng, Pred, L); + checkFn(Loc, IsLoad, BoundEx, C); + } + }; +} + +/// \brief Run checkers for load/store of a location. + +void CheckerManager::runCheckersForLocation(ExplodedNodeSet &Dst, + const ExplodedNodeSet &Src, + SVal location, bool isLoad, + const Stmt *NodeEx, + const Stmt *BoundEx, + ExprEngine &Eng) { + CheckLocationContext C(LocationCheckers, location, isLoad, NodeEx, + BoundEx, Eng); + expandGraphWithCheckers(C, Dst, Src); +} + +namespace { + struct CheckBindContext { + typedef std::vector<CheckerManager::CheckBindFunc> CheckersTy; + const CheckersTy &Checkers; + SVal Loc; + SVal Val; + const Stmt *S; + ExprEngine &Eng; + ProgramPoint::Kind PointKind; + + CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } + CheckersTy::const_iterator checkers_end() { return Checkers.end(); } + + CheckBindContext(const CheckersTy &checkers, + SVal loc, SVal val, const Stmt *s, ExprEngine &eng, + ProgramPoint::Kind PK) + : Checkers(checkers), Loc(loc), Val(val), S(s), Eng(eng), PointKind(PK) {} + + void runChecker(CheckerManager::CheckBindFunc checkFn, + NodeBuilder &Bldr, ExplodedNode *Pred) { + const ProgramPoint &L = ProgramPoint::getProgramPoint(S, PointKind, + Pred->getLocationContext(), checkFn.Checker); + CheckerContext C(Bldr, Eng, Pred, L); + + checkFn(Loc, Val, S, C); + } + }; +} + +/// \brief Run checkers for binding of a value to a location. +void CheckerManager::runCheckersForBind(ExplodedNodeSet &Dst, + const ExplodedNodeSet &Src, + SVal location, SVal val, + const Stmt *S, ExprEngine &Eng, + ProgramPoint::Kind PointKind) { + CheckBindContext C(BindCheckers, location, val, S, Eng, PointKind); + expandGraphWithCheckers(C, Dst, Src); +} + +void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G, + BugReporter &BR, + ExprEngine &Eng) { + for (unsigned i = 0, e = EndAnalysisCheckers.size(); i != e; ++i) + EndAnalysisCheckers[i](G, BR, Eng); +} + +/// \brief Run checkers for end of path. +// Note, We do not chain the checker output (like in expandGraphWithCheckers) +// for this callback since end of path nodes are expected to be final. +void CheckerManager::runCheckersForEndPath(NodeBuilderContext &BC, + ExplodedNodeSet &Dst, + ExprEngine &Eng) { + ExplodedNode *Pred = BC.Pred; + + // We define the builder outside of the loop bacause if at least one checkers + // creates a sucsessor for Pred, we do not need to generate an + // autotransition for it. + NodeBuilder Bldr(Pred, Dst, BC); + for (unsigned i = 0, e = EndPathCheckers.size(); i != e; ++i) { + CheckEndPathFunc checkFn = EndPathCheckers[i]; + + const ProgramPoint &L = BlockEntrance(BC.Block, + Pred->getLocationContext(), + checkFn.Checker); + CheckerContext C(Bldr, Eng, Pred, L); + checkFn(C); + } +} + +namespace { + struct CheckBranchConditionContext { + typedef std::vector<CheckerManager::CheckBranchConditionFunc> CheckersTy; + const CheckersTy &Checkers; + const Stmt *Condition; + ExprEngine &Eng; + + CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } + CheckersTy::const_iterator checkers_end() { return Checkers.end(); } + + CheckBranchConditionContext(const CheckersTy &checkers, + const Stmt *Cond, ExprEngine &eng) + : Checkers(checkers), Condition(Cond), Eng(eng) {} + + void runChecker(CheckerManager::CheckBranchConditionFunc checkFn, + NodeBuilder &Bldr, ExplodedNode *Pred) { + ProgramPoint L = PostCondition(Condition, Pred->getLocationContext(), + checkFn.Checker); + CheckerContext C(Bldr, Eng, Pred, L); + checkFn(Condition, C); + } + }; +} + +/// \brief Run checkers for branch condition. +void CheckerManager::runCheckersForBranchCondition(const Stmt *Condition, + ExplodedNodeSet &Dst, + ExplodedNode *Pred, + ExprEngine &Eng) { + ExplodedNodeSet Src; + Src.insert(Pred); + CheckBranchConditionContext C(BranchConditionCheckers, Condition, Eng); + expandGraphWithCheckers(C, Dst, Src); +} + +/// \brief Run checkers for live symbols. +void CheckerManager::runCheckersForLiveSymbols(ProgramStateRef state, + SymbolReaper &SymReaper) { + for (unsigned i = 0, e = LiveSymbolsCheckers.size(); i != e; ++i) + LiveSymbolsCheckers[i](state, SymReaper); +} + +namespace { + struct CheckDeadSymbolsContext { + typedef std::vector<CheckerManager::CheckDeadSymbolsFunc> CheckersTy; + const CheckersTy &Checkers; + SymbolReaper &SR; + const Stmt *S; + ExprEngine &Eng; + + CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } + CheckersTy::const_iterator checkers_end() { return Checkers.end(); } + + CheckDeadSymbolsContext(const CheckersTy &checkers, SymbolReaper &sr, + const Stmt *s, ExprEngine &eng) + : Checkers(checkers), SR(sr), S(s), Eng(eng) { } + + void runChecker(CheckerManager::CheckDeadSymbolsFunc checkFn, + NodeBuilder &Bldr, ExplodedNode *Pred) { + ProgramPoint::Kind K = ProgramPoint::PostPurgeDeadSymbolsKind; + const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, + Pred->getLocationContext(), checkFn.Checker); + CheckerContext C(Bldr, Eng, Pred, L); + + checkFn(SR, C); + } + }; +} + +/// \brief Run checkers for dead symbols. +void CheckerManager::runCheckersForDeadSymbols(ExplodedNodeSet &Dst, + const ExplodedNodeSet &Src, + SymbolReaper &SymReaper, + const Stmt *S, + ExprEngine &Eng) { + CheckDeadSymbolsContext C(DeadSymbolsCheckers, SymReaper, S, Eng); + expandGraphWithCheckers(C, Dst, Src); +} + +/// \brief True if at least one checker wants to check region changes. +bool CheckerManager::wantsRegionChangeUpdate(ProgramStateRef state) { + for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i) + if (RegionChangesCheckers[i].WantUpdateFn(state)) + return true; + + return false; +} + +/// \brief Run checkers for region changes. +ProgramStateRef +CheckerManager::runCheckersForRegionChanges(ProgramStateRef state, + const StoreManager::InvalidatedSymbols *invalidated, + ArrayRef<const MemRegion *> ExplicitRegions, + ArrayRef<const MemRegion *> Regions, + const CallOrObjCMessage *Call) { + for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i) { + // If any checker declares the state infeasible (or if it starts that way), + // bail out. + if (!state) + return NULL; + state = RegionChangesCheckers[i].CheckFn(state, invalidated, + ExplicitRegions, Regions, Call); + } + return state; +} + +/// \brief Run checkers for handling assumptions on symbolic values. +ProgramStateRef +CheckerManager::runCheckersForEvalAssume(ProgramStateRef state, + SVal Cond, bool Assumption) { + for (unsigned i = 0, e = EvalAssumeCheckers.size(); i != e; ++i) { + // If any checker declares the state infeasible (or if it starts that way), + // bail out. + if (!state) + return NULL; + state = EvalAssumeCheckers[i](state, Cond, Assumption); + } + return state; +} + +/// \brief Run checkers for evaluating a call. +/// Only one checker will evaluate the call. +void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst, + const ExplodedNodeSet &Src, + const CallExpr *CE, + ExprEngine &Eng, + GraphExpander *defaultEval) { + if (EvalCallCheckers.empty() && + InlineCallCheckers.empty() && + defaultEval == 0) { + Dst.insert(Src); + return; + } + + for (ExplodedNodeSet::iterator + NI = Src.begin(), NE = Src.end(); NI != NE; ++NI) { + + ExplodedNode *Pred = *NI; + bool anyEvaluated = false; + + // First, check if any of the InlineCall callbacks can evaluate the call. + assert(InlineCallCheckers.size() <= 1 && + "InlineCall is a special hacky callback to allow intrusive" + "evaluation of the call (which simulates inlining). It is " + "currently only used by OSAtomicChecker and should go away " + "at some point."); + for (std::vector<InlineCallFunc>::iterator + EI = InlineCallCheckers.begin(), EE = InlineCallCheckers.end(); + EI != EE; ++EI) { + ExplodedNodeSet checkDst; + bool evaluated = (*EI)(CE, Eng, Pred, checkDst); + assert(!(evaluated && anyEvaluated) + && "There are more than one checkers evaluating the call"); + if (evaluated) { + anyEvaluated = true; + Dst.insert(checkDst); +#ifdef NDEBUG + break; // on release don't check that no other checker also evals. +#endif + } + } + +#ifdef NDEBUG // on release don't check that no other checker also evals. + if (anyEvaluated) { + break; + } +#endif + + ExplodedNodeSet checkDst; + NodeBuilder B(Pred, checkDst, Eng.getBuilderContext()); + // Next, check if any of the EvalCall callbacks can evaluate the call. + for (std::vector<EvalCallFunc>::iterator + EI = EvalCallCheckers.begin(), EE = EvalCallCheckers.end(); + EI != EE; ++EI) { + ProgramPoint::Kind K = ProgramPoint::PostStmtKind; + const ProgramPoint &L = ProgramPoint::getProgramPoint(CE, K, + Pred->getLocationContext(), EI->Checker); + bool evaluated = false; + { // CheckerContext generates transitions(populates checkDest) on + // destruction, so introduce the scope to make sure it gets properly + // populated. + CheckerContext C(B, Eng, Pred, L); + evaluated = (*EI)(CE, C); + } + assert(!(evaluated && anyEvaluated) + && "There are more than one checkers evaluating the call"); + if (evaluated) { + anyEvaluated = true; + Dst.insert(checkDst); +#ifdef NDEBUG + break; // on release don't check that no other checker also evals. +#endif + } + } + + // If none of the checkers evaluated the call, ask ExprEngine to handle it. + if (!anyEvaluated) { + if (defaultEval) + defaultEval->expandGraph(Dst, Pred); + else + Dst.insert(Pred); + } + } +} + +/// \brief Run checkers for the entire Translation Unit. +void CheckerManager::runCheckersOnEndOfTranslationUnit( + const TranslationUnitDecl *TU, + AnalysisManager &mgr, + BugReporter &BR) { + for (unsigned i = 0, e = EndOfTranslationUnitCheckers.size(); i != e; ++i) + EndOfTranslationUnitCheckers[i](TU, mgr, BR); +} + +void CheckerManager::runCheckersForPrintState(raw_ostream &Out, + ProgramStateRef State, + const char *NL, const char *Sep) { + for (llvm::DenseMap<CheckerTag, CheckerRef>::iterator + I = CheckerTags.begin(), E = CheckerTags.end(); I != E; ++I) + I->second->printState(Out, State, NL, Sep); +} + +//===----------------------------------------------------------------------===// +// Internal registration functions for AST traversing. +//===----------------------------------------------------------------------===// + +void CheckerManager::_registerForDecl(CheckDeclFunc checkfn, + HandlesDeclFunc isForDeclFn) { + DeclCheckerInfo info = { checkfn, isForDeclFn }; + DeclCheckers.push_back(info); +} + +void CheckerManager::_registerForBody(CheckDeclFunc checkfn) { + BodyCheckers.push_back(checkfn); +} + +//===----------------------------------------------------------------------===// +// Internal registration functions for path-sensitive checking. +//===----------------------------------------------------------------------===// + +void CheckerManager::_registerForPreStmt(CheckStmtFunc checkfn, + HandlesStmtFunc isForStmtFn) { + StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/true }; + StmtCheckers.push_back(info); +} +void CheckerManager::_registerForPostStmt(CheckStmtFunc checkfn, + HandlesStmtFunc isForStmtFn) { + StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/false }; + StmtCheckers.push_back(info); +} + +void CheckerManager::_registerForPreObjCMessage(CheckObjCMessageFunc checkfn) { + PreObjCMessageCheckers.push_back(checkfn); +} +void CheckerManager::_registerForPostObjCMessage(CheckObjCMessageFunc checkfn) { + PostObjCMessageCheckers.push_back(checkfn); +} + +void CheckerManager::_registerForLocation(CheckLocationFunc checkfn) { + LocationCheckers.push_back(checkfn); +} + +void CheckerManager::_registerForBind(CheckBindFunc checkfn) { + BindCheckers.push_back(checkfn); +} + +void CheckerManager::_registerForEndAnalysis(CheckEndAnalysisFunc checkfn) { + EndAnalysisCheckers.push_back(checkfn); +} + +void CheckerManager::_registerForEndPath(CheckEndPathFunc checkfn) { + EndPathCheckers.push_back(checkfn); +} + +void CheckerManager::_registerForBranchCondition( + CheckBranchConditionFunc checkfn) { + BranchConditionCheckers.push_back(checkfn); +} + +void CheckerManager::_registerForLiveSymbols(CheckLiveSymbolsFunc checkfn) { + LiveSymbolsCheckers.push_back(checkfn); +} + +void CheckerManager::_registerForDeadSymbols(CheckDeadSymbolsFunc checkfn) { + DeadSymbolsCheckers.push_back(checkfn); +} + +void CheckerManager::_registerForRegionChanges(CheckRegionChangesFunc checkfn, + WantsRegionChangeUpdateFunc wantUpdateFn) { + RegionChangesCheckerInfo info = {checkfn, wantUpdateFn}; + RegionChangesCheckers.push_back(info); +} + +void CheckerManager::_registerForEvalAssume(EvalAssumeFunc checkfn) { + EvalAssumeCheckers.push_back(checkfn); +} + +void CheckerManager::_registerForEvalCall(EvalCallFunc checkfn) { + EvalCallCheckers.push_back(checkfn); +} + +void CheckerManager::_registerForInlineCall(InlineCallFunc checkfn) { + InlineCallCheckers.push_back(checkfn); +} + +void CheckerManager::_registerForEndOfTranslationUnit( + CheckEndOfTranslationUnit checkfn) { + EndOfTranslationUnitCheckers.push_back(checkfn); +} + +//===----------------------------------------------------------------------===// +// Implementation details. +//===----------------------------------------------------------------------===// + +CheckerManager::CachedStmtCheckers * +CheckerManager::getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit) { + assert(S); + + CachedStmtCheckersKey key(S->getStmtClass(), isPreVisit); + CachedStmtCheckers *checkers = 0; + CachedStmtCheckersMapTy::iterator CCI = CachedStmtCheckersMap.find(key); + if (CCI != CachedStmtCheckersMap.end()) { + checkers = &(CCI->second); + } else { + // Find the checkers that should run for this Stmt and cache them. + checkers = &CachedStmtCheckersMap[key]; + for (unsigned i = 0, e = StmtCheckers.size(); i != e; ++i) { + StmtCheckerInfo &info = StmtCheckers[i]; + if (info.IsPreVisit == isPreVisit && info.IsForStmtFn(S)) + checkers->push_back(info.CheckFn); + } + } + + assert(checkers); + return checkers; +} + +CheckerManager::~CheckerManager() { + for (unsigned i = 0, e = CheckerDtors.size(); i != e; ++i) + CheckerDtors[i](); +} + +// Anchor for the vtable. +GraphExpander::~GraphExpander() { } |