Home | History | Annotate | Download | only in Core
      1 //===--- CheckerManager.cpp - Static Analyzer Checker Manager -------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // Defines the Static Analyzer Checker Manager.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
     15 #include "clang/StaticAnalyzer/Core/Checker.h"
     16 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
     17 #include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
     18 #include "clang/Analysis/ProgramPoint.h"
     19 #include "clang/AST/DeclBase.h"
     20 
     21 using namespace clang;
     22 using namespace ento;
     23 
     24 bool CheckerManager::hasPathSensitiveCheckers() const {
     25   return !StmtCheckers.empty()              ||
     26          !PreObjCMessageCheckers.empty()    ||
     27          !PostObjCMessageCheckers.empty()   ||
     28          !LocationCheckers.empty()          ||
     29          !BindCheckers.empty()              ||
     30          !EndAnalysisCheckers.empty()       ||
     31          !EndPathCheckers.empty()           ||
     32          !BranchConditionCheckers.empty()   ||
     33          !LiveSymbolsCheckers.empty()       ||
     34          !DeadSymbolsCheckers.empty()       ||
     35          !RegionChangesCheckers.empty()     ||
     36          !EvalAssumeCheckers.empty()        ||
     37          !EvalCallCheckers.empty()          ||
     38          !InlineCallCheckers.empty();
     39 }
     40 
     41 void CheckerManager::finishedCheckerRegistration() {
     42 #ifndef NDEBUG
     43   // Make sure that for every event that has listeners, there is at least
     44   // one dispatcher registered for it.
     45   for (llvm::DenseMap<EventTag, EventInfo>::iterator
     46          I = Events.begin(), E = Events.end(); I != E; ++I)
     47     assert(I->second.HasDispatcher && "No dispatcher registered for an event");
     48 #endif
     49 }
     50 
     51 //===----------------------------------------------------------------------===//
     52 // Functions for running checkers for AST traversing..
     53 //===----------------------------------------------------------------------===//
     54 
     55 void CheckerManager::runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr,
     56                                           BugReporter &BR) {
     57   assert(D);
     58 
     59   unsigned DeclKind = D->getKind();
     60   CachedDeclCheckers *checkers = 0;
     61   CachedDeclCheckersMapTy::iterator CCI = CachedDeclCheckersMap.find(DeclKind);
     62   if (CCI != CachedDeclCheckersMap.end()) {
     63     checkers = &(CCI->second);
     64   } else {
     65     // Find the checkers that should run for this Decl and cache them.
     66     checkers = &CachedDeclCheckersMap[DeclKind];
     67     for (unsigned i = 0, e = DeclCheckers.size(); i != e; ++i) {
     68       DeclCheckerInfo &info = DeclCheckers[i];
     69       if (info.IsForDeclFn(D))
     70         checkers->push_back(info.CheckFn);
     71     }
     72   }
     73 
     74   assert(checkers);
     75   for (CachedDeclCheckers::iterator
     76          I = checkers->begin(), E = checkers->end(); I != E; ++I)
     77     (*I)(D, mgr, BR);
     78 }
     79 
     80 void CheckerManager::runCheckersOnASTBody(const Decl *D, AnalysisManager& mgr,
     81                                           BugReporter &BR) {
     82   assert(D && D->hasBody());
     83 
     84   for (unsigned i = 0, e = BodyCheckers.size(); i != e; ++i)
     85     BodyCheckers[i](D, mgr, BR);
     86 }
     87 
     88 //===----------------------------------------------------------------------===//
     89 // Functions for running checkers for path-sensitive checking.
     90 //===----------------------------------------------------------------------===//
     91 
     92 template <typename CHECK_CTX>
     93 static void expandGraphWithCheckers(CHECK_CTX checkCtx,
     94                                     ExplodedNodeSet &Dst,
     95                                     const ExplodedNodeSet &Src) {
     96 
     97   typename CHECK_CTX::CheckersTy::const_iterator
     98       I = checkCtx.checkers_begin(), E = checkCtx.checkers_end();
     99   if (I == E) {
    100     Dst.insert(Src);
    101     return;
    102   }
    103 
    104   ExplodedNodeSet Tmp1, Tmp2;
    105   const ExplodedNodeSet *PrevSet = &Src;
    106 
    107   for (; I != E; ++I) {
    108     ExplodedNodeSet *CurrSet = 0;
    109     if (I+1 == E)
    110       CurrSet = &Dst;
    111     else {
    112       CurrSet = (PrevSet == &Tmp1) ? &Tmp2 : &Tmp1;
    113       CurrSet->clear();
    114     }
    115 
    116     for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
    117          NI != NE; ++NI)
    118       checkCtx.runChecker(*I, *CurrSet, *NI);
    119 
    120     // Update which NodeSet is the current one.
    121     PrevSet = CurrSet;
    122   }
    123 }
    124 
    125 namespace {
    126   struct CheckStmtContext {
    127     typedef SmallVectorImpl<CheckerManager::CheckStmtFunc> CheckersTy;
    128     bool IsPreVisit;
    129     const CheckersTy &Checkers;
    130     const Stmt *S;
    131     ExprEngine &Eng;
    132 
    133     CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
    134     CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
    135 
    136     CheckStmtContext(bool isPreVisit, const CheckersTy &checkers,
    137                      const Stmt *s, ExprEngine &eng)
    138       : IsPreVisit(isPreVisit), Checkers(checkers), S(s), Eng(eng) { }
    139 
    140     void runChecker(CheckerManager::CheckStmtFunc checkFn,
    141                     ExplodedNodeSet &Dst, ExplodedNode *Pred) {
    142       // FIXME: Remove respondsToCallback from CheckerContext;
    143       ProgramPoint::Kind K =  IsPreVisit ? ProgramPoint::PreStmtKind :
    144                                            ProgramPoint::PostStmtKind;
    145       const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
    146                                 Pred->getLocationContext(), checkFn.Checker);
    147       CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0);
    148 
    149       checkFn(S, C);
    150     }
    151   };
    152 }
    153 
    154 /// \brief Run checkers for visiting Stmts.
    155 void CheckerManager::runCheckersForStmt(bool isPreVisit,
    156                                         ExplodedNodeSet &Dst,
    157                                         const ExplodedNodeSet &Src,
    158                                         const Stmt *S,
    159                                         ExprEngine &Eng) {
    160   CheckStmtContext C(isPreVisit, *getCachedStmtCheckersFor(S, isPreVisit),
    161                      S, Eng);
    162   expandGraphWithCheckers(C, Dst, Src);
    163 }
    164 
    165 namespace {
    166   struct CheckObjCMessageContext {
    167     typedef std::vector<CheckerManager::CheckObjCMessageFunc> CheckersTy;
    168     bool IsPreVisit;
    169     const CheckersTy &Checkers;
    170     const ObjCMessage &Msg;
    171     ExprEngine &Eng;
    172 
    173     CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
    174     CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
    175 
    176     CheckObjCMessageContext(bool isPreVisit, const CheckersTy &checkers,
    177                             const ObjCMessage &msg, ExprEngine &eng)
    178       : IsPreVisit(isPreVisit), Checkers(checkers), Msg(msg), Eng(eng) { }
    179 
    180     void runChecker(CheckerManager::CheckObjCMessageFunc checkFn,
    181                     ExplodedNodeSet &Dst, ExplodedNode *Pred) {
    182       ProgramPoint::Kind K =  IsPreVisit ? ProgramPoint::PreStmtKind :
    183                                            ProgramPoint::PostStmtKind;
    184       const ProgramPoint &L = ProgramPoint::getProgramPoint(Msg.getOriginExpr(),
    185                                 K, Pred->getLocationContext(), checkFn.Checker);
    186       CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0);
    187 
    188       checkFn(Msg, C);
    189     }
    190   };
    191 }
    192 
    193 /// \brief Run checkers for visiting obj-c messages.
    194 void CheckerManager::runCheckersForObjCMessage(bool isPreVisit,
    195                                                ExplodedNodeSet &Dst,
    196                                                const ExplodedNodeSet &Src,
    197                                                const ObjCMessage &msg,
    198                                                ExprEngine &Eng) {
    199   CheckObjCMessageContext C(isPreVisit,
    200                             isPreVisit ? PreObjCMessageCheckers
    201                                        : PostObjCMessageCheckers,
    202                             msg, Eng);
    203   expandGraphWithCheckers(C, Dst, Src);
    204 }
    205 
    206 namespace {
    207   struct CheckLocationContext {
    208     typedef std::vector<CheckerManager::CheckLocationFunc> CheckersTy;
    209     const CheckersTy &Checkers;
    210     SVal Loc;
    211     bool IsLoad;
    212     const Stmt *S;
    213     ExprEngine &Eng;
    214 
    215     CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
    216     CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
    217 
    218     CheckLocationContext(const CheckersTy &checkers,
    219                          SVal loc, bool isLoad, const Stmt *s, ExprEngine &eng)
    220       : Checkers(checkers), Loc(loc), IsLoad(isLoad), S(s), Eng(eng) { }
    221 
    222     void runChecker(CheckerManager::CheckLocationFunc checkFn,
    223                     ExplodedNodeSet &Dst, ExplodedNode *Pred) {
    224       ProgramPoint::Kind K =  IsLoad ? ProgramPoint::PreLoadKind :
    225                                        ProgramPoint::PreStoreKind;
    226       const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
    227                                 Pred->getLocationContext(), checkFn.Checker);
    228       CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0);
    229 
    230       checkFn(Loc, IsLoad, S, C);
    231     }
    232   };
    233 }
    234 
    235 /// \brief Run checkers for load/store of a location.
    236 void CheckerManager::runCheckersForLocation(ExplodedNodeSet &Dst,
    237                                             const ExplodedNodeSet &Src,
    238                                             SVal location, bool isLoad,
    239                                             const Stmt *S, ExprEngine &Eng) {
    240   CheckLocationContext C(LocationCheckers, location, isLoad, S, Eng);
    241   expandGraphWithCheckers(C, Dst, Src);
    242 }
    243 
    244 namespace {
    245   struct CheckBindContext {
    246     typedef std::vector<CheckerManager::CheckBindFunc> CheckersTy;
    247     const CheckersTy &Checkers;
    248     SVal Loc;
    249     SVal Val;
    250     const Stmt *S;
    251     ExprEngine &Eng;
    252 
    253     CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
    254     CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
    255 
    256     CheckBindContext(const CheckersTy &checkers,
    257                      SVal loc, SVal val, const Stmt *s, ExprEngine &eng)
    258       : Checkers(checkers), Loc(loc), Val(val), S(s), Eng(eng) { }
    259 
    260     void runChecker(CheckerManager::CheckBindFunc checkFn,
    261                     ExplodedNodeSet &Dst, ExplodedNode *Pred) {
    262       ProgramPoint::Kind K =  ProgramPoint::PreStmtKind;
    263       const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
    264                                 Pred->getLocationContext(), checkFn.Checker);
    265       CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0);
    266 
    267       checkFn(Loc, Val, S, C);
    268     }
    269   };
    270 }
    271 
    272 /// \brief Run checkers for binding of a value to a location.
    273 void CheckerManager::runCheckersForBind(ExplodedNodeSet &Dst,
    274                                         const ExplodedNodeSet &Src,
    275                                         SVal location, SVal val,
    276                                         const Stmt *S, ExprEngine &Eng) {
    277   CheckBindContext C(BindCheckers, location, val, S, Eng);
    278   expandGraphWithCheckers(C, Dst, Src);
    279 }
    280 
    281 void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G,
    282                                                BugReporter &BR,
    283                                                ExprEngine &Eng) {
    284   for (unsigned i = 0, e = EndAnalysisCheckers.size(); i != e; ++i)
    285     EndAnalysisCheckers[i](G, BR, Eng);
    286 }
    287 
    288 /// \brief Run checkers for end of path.
    289 void CheckerManager::runCheckersForEndPath(EndOfFunctionNodeBuilder &B,
    290                                            ExprEngine &Eng) {
    291   for (unsigned i = 0, e = EndPathCheckers.size(); i != e; ++i) {
    292     CheckEndPathFunc fn = EndPathCheckers[i];
    293     EndOfFunctionNodeBuilder specialB = B.withCheckerTag(fn.Checker);
    294     fn(specialB, Eng);
    295   }
    296 }
    297 
    298 /// \brief Run checkers for branch condition.
    299 void CheckerManager::runCheckersForBranchCondition(const Stmt *condition,
    300                                                    NodeBuilder &B,
    301                                                    ExplodedNode *Pred,
    302                                                    ExprEngine &Eng) {
    303   for (unsigned i = 0, e = BranchConditionCheckers.size(); i != e; ++i) {
    304     CheckBranchConditionFunc fn = BranchConditionCheckers[i];
    305     fn(condition, B, Pred, Eng);
    306   }
    307 }
    308 
    309 /// \brief Run checkers for live symbols.
    310 void CheckerManager::runCheckersForLiveSymbols(const ProgramState *state,
    311                                                SymbolReaper &SymReaper) {
    312   for (unsigned i = 0, e = LiveSymbolsCheckers.size(); i != e; ++i)
    313     LiveSymbolsCheckers[i](state, SymReaper);
    314 }
    315 
    316 namespace {
    317   struct CheckDeadSymbolsContext {
    318     typedef std::vector<CheckerManager::CheckDeadSymbolsFunc> CheckersTy;
    319     const CheckersTy &Checkers;
    320     SymbolReaper &SR;
    321     const Stmt *S;
    322     ExprEngine &Eng;
    323 
    324     CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
    325     CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
    326 
    327     CheckDeadSymbolsContext(const CheckersTy &checkers, SymbolReaper &sr,
    328                             const Stmt *s, ExprEngine &eng)
    329       : Checkers(checkers), SR(sr), S(s), Eng(eng) { }
    330 
    331     void runChecker(CheckerManager::CheckDeadSymbolsFunc checkFn,
    332                     ExplodedNodeSet &Dst, ExplodedNode *Pred) {
    333       ProgramPoint::Kind K = ProgramPoint::PostPurgeDeadSymbolsKind;
    334       const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
    335                                 Pred->getLocationContext(), checkFn.Checker);
    336       CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0);
    337 
    338       checkFn(SR, C);
    339     }
    340   };
    341 }
    342 
    343 /// \brief Run checkers for dead symbols.
    344 void CheckerManager::runCheckersForDeadSymbols(ExplodedNodeSet &Dst,
    345                                                const ExplodedNodeSet &Src,
    346                                                SymbolReaper &SymReaper,
    347                                                const Stmt *S,
    348                                                ExprEngine &Eng) {
    349   CheckDeadSymbolsContext C(DeadSymbolsCheckers, SymReaper, S, Eng);
    350   expandGraphWithCheckers(C, Dst, Src);
    351 }
    352 
    353 /// \brief True if at least one checker wants to check region changes.
    354 bool CheckerManager::wantsRegionChangeUpdate(const ProgramState *state) {
    355   for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i)
    356     if (RegionChangesCheckers[i].WantUpdateFn(state))
    357       return true;
    358 
    359   return false;
    360 }
    361 
    362 /// \brief Run checkers for region changes.
    363 const ProgramState *
    364 CheckerManager::runCheckersForRegionChanges(const ProgramState *state,
    365                             const StoreManager::InvalidatedSymbols *invalidated,
    366                                     ArrayRef<const MemRegion *> ExplicitRegions,
    367                                           ArrayRef<const MemRegion *> Regions) {
    368   for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i) {
    369     // If any checker declares the state infeasible (or if it starts that way),
    370     // bail out.
    371     if (!state)
    372       return NULL;
    373     state = RegionChangesCheckers[i].CheckFn(state, invalidated,
    374                                              ExplicitRegions, Regions);
    375   }
    376   return state;
    377 }
    378 
    379 /// \brief Run checkers for handling assumptions on symbolic values.
    380 const ProgramState *
    381 CheckerManager::runCheckersForEvalAssume(const ProgramState *state,
    382                                          SVal Cond, bool Assumption) {
    383   for (unsigned i = 0, e = EvalAssumeCheckers.size(); i != e; ++i) {
    384     // If any checker declares the state infeasible (or if it starts that way),
    385     // bail out.
    386     if (!state)
    387       return NULL;
    388     state = EvalAssumeCheckers[i](state, Cond, Assumption);
    389   }
    390   return state;
    391 }
    392 
    393 /// \brief Run checkers for evaluating a call.
    394 /// Only one checker will evaluate the call.
    395 void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
    396                                             const ExplodedNodeSet &Src,
    397                                             const CallExpr *CE,
    398                                             ExprEngine &Eng,
    399                                             GraphExpander *defaultEval) {
    400   if (EvalCallCheckers.empty()   &&
    401       InlineCallCheckers.empty() &&
    402       defaultEval == 0) {
    403     Dst.insert(Src);
    404     return;
    405   }
    406 
    407   for (ExplodedNodeSet::iterator
    408          NI = Src.begin(), NE = Src.end(); NI != NE; ++NI) {
    409 
    410     ExplodedNode *Pred = *NI;
    411     bool anyEvaluated = false;
    412 
    413     // First, check if any of the InlineCall callbacks can evaluate the call.
    414     assert(InlineCallCheckers.size() <= 1 &&
    415            "InlineCall is a special hacky callback to allow intrusive"
    416            "evaluation of the call (which simulates inlining). It is "
    417            "currently only used by OSAtomicChecker and should go away "
    418            "at some point.");
    419     for (std::vector<InlineCallFunc>::iterator
    420            EI = InlineCallCheckers.begin(), EE = InlineCallCheckers.end();
    421          EI != EE; ++EI) {
    422       ExplodedNodeSet checkDst;
    423       bool evaluated = (*EI)(CE, Eng, Pred, checkDst);
    424       assert(!(evaluated && anyEvaluated)
    425              && "There are more than one checkers evaluating the call");
    426       if (evaluated) {
    427         anyEvaluated = true;
    428         Dst.insert(checkDst);
    429 #ifdef NDEBUG
    430         break; // on release don't check that no other checker also evals.
    431 #endif
    432       }
    433     }
    434 
    435 #ifdef NDEBUG // on release don't check that no other checker also evals.
    436     if (anyEvaluated) {
    437       break;
    438     }
    439 #endif
    440 
    441     // Next, check if any of the EvalCall callbacks can evaluate the call.
    442     for (std::vector<EvalCallFunc>::iterator
    443            EI = EvalCallCheckers.begin(), EE = EvalCallCheckers.end();
    444          EI != EE; ++EI) {
    445       ExplodedNodeSet checkDst;
    446       ProgramPoint::Kind K = ProgramPoint::PostStmtKind;
    447       const ProgramPoint &L = ProgramPoint::getProgramPoint(CE, K,
    448                                 Pred->getLocationContext(), EI->Checker);
    449       bool evaluated = false;
    450       { // CheckerContext generates transitions(populates checkDest) on
    451         // destruction, so introduce the scope to make sure it gets properly
    452         // populated.
    453         CheckerContext C(checkDst, Eng.getBuilder(), Eng, Pred, L, 0);
    454         evaluated = (*EI)(CE, C);
    455       }
    456       assert(!(evaluated && anyEvaluated)
    457              && "There are more than one checkers evaluating the call");
    458       if (evaluated) {
    459         anyEvaluated = true;
    460         Dst.insert(checkDst);
    461 #ifdef NDEBUG
    462         break; // on release don't check that no other checker also evals.
    463 #endif
    464       }
    465     }
    466 
    467     // If none of the checkers evaluated the call, ask ExprEngine to handle it.
    468     if (!anyEvaluated) {
    469       if (defaultEval)
    470         defaultEval->expandGraph(Dst, Pred);
    471       else
    472         Dst.insert(Pred);
    473     }
    474   }
    475 }
    476 
    477 /// \brief Run checkers for the entire Translation Unit.
    478 void CheckerManager::runCheckersOnEndOfTranslationUnit(
    479                                                   const TranslationUnitDecl *TU,
    480                                                   AnalysisManager &mgr,
    481                                                   BugReporter &BR) {
    482   for (unsigned i = 0, e = EndOfTranslationUnitCheckers.size(); i != e; ++i)
    483     EndOfTranslationUnitCheckers[i](TU, mgr, BR);
    484 }
    485 
    486 void CheckerManager::runCheckersForPrintState(raw_ostream &Out,
    487                                               const ProgramState *State,
    488                                               const char *NL, const char *Sep) {
    489   for (llvm::DenseMap<CheckerTag, CheckerRef>::iterator
    490         I = CheckerTags.begin(), E = CheckerTags.end(); I != E; ++I)
    491     I->second->printState(Out, State, NL, Sep);
    492 }
    493 
    494 //===----------------------------------------------------------------------===//
    495 // Internal registration functions for AST traversing.
    496 //===----------------------------------------------------------------------===//
    497 
    498 void CheckerManager::_registerForDecl(CheckDeclFunc checkfn,
    499                                       HandlesDeclFunc isForDeclFn) {
    500   DeclCheckerInfo info = { checkfn, isForDeclFn };
    501   DeclCheckers.push_back(info);
    502 }
    503 
    504 void CheckerManager::_registerForBody(CheckDeclFunc checkfn) {
    505   BodyCheckers.push_back(checkfn);
    506 }
    507 
    508 //===----------------------------------------------------------------------===//
    509 // Internal registration functions for path-sensitive checking.
    510 //===----------------------------------------------------------------------===//
    511 
    512 void CheckerManager::_registerForPreStmt(CheckStmtFunc checkfn,
    513                                          HandlesStmtFunc isForStmtFn) {
    514   StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/true };
    515   StmtCheckers.push_back(info);
    516 }
    517 void CheckerManager::_registerForPostStmt(CheckStmtFunc checkfn,
    518                                           HandlesStmtFunc isForStmtFn) {
    519   StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/false };
    520   StmtCheckers.push_back(info);
    521 }
    522 
    523 void CheckerManager::_registerForPreObjCMessage(CheckObjCMessageFunc checkfn) {
    524   PreObjCMessageCheckers.push_back(checkfn);
    525 }
    526 void CheckerManager::_registerForPostObjCMessage(CheckObjCMessageFunc checkfn) {
    527   PostObjCMessageCheckers.push_back(checkfn);
    528 }
    529 
    530 void CheckerManager::_registerForLocation(CheckLocationFunc checkfn) {
    531   LocationCheckers.push_back(checkfn);
    532 }
    533 
    534 void CheckerManager::_registerForBind(CheckBindFunc checkfn) {
    535   BindCheckers.push_back(checkfn);
    536 }
    537 
    538 void CheckerManager::_registerForEndAnalysis(CheckEndAnalysisFunc checkfn) {
    539   EndAnalysisCheckers.push_back(checkfn);
    540 }
    541 
    542 void CheckerManager::_registerForEndPath(CheckEndPathFunc checkfn) {
    543   EndPathCheckers.push_back(checkfn);
    544 }
    545 
    546 void CheckerManager::_registerForBranchCondition(
    547                                              CheckBranchConditionFunc checkfn) {
    548   BranchConditionCheckers.push_back(checkfn);
    549 }
    550 
    551 void CheckerManager::_registerForLiveSymbols(CheckLiveSymbolsFunc checkfn) {
    552   LiveSymbolsCheckers.push_back(checkfn);
    553 }
    554 
    555 void CheckerManager::_registerForDeadSymbols(CheckDeadSymbolsFunc checkfn) {
    556   DeadSymbolsCheckers.push_back(checkfn);
    557 }
    558 
    559 void CheckerManager::_registerForRegionChanges(CheckRegionChangesFunc checkfn,
    560                                      WantsRegionChangeUpdateFunc wantUpdateFn) {
    561   RegionChangesCheckerInfo info = {checkfn, wantUpdateFn};
    562   RegionChangesCheckers.push_back(info);
    563 }
    564 
    565 void CheckerManager::_registerForEvalAssume(EvalAssumeFunc checkfn) {
    566   EvalAssumeCheckers.push_back(checkfn);
    567 }
    568 
    569 void CheckerManager::_registerForEvalCall(EvalCallFunc checkfn) {
    570   EvalCallCheckers.push_back(checkfn);
    571 }
    572 
    573 void CheckerManager::_registerForInlineCall(InlineCallFunc checkfn) {
    574   InlineCallCheckers.push_back(checkfn);
    575 }
    576 
    577 void CheckerManager::_registerForEndOfTranslationUnit(
    578                                             CheckEndOfTranslationUnit checkfn) {
    579   EndOfTranslationUnitCheckers.push_back(checkfn);
    580 }
    581 
    582 //===----------------------------------------------------------------------===//
    583 // Implementation details.
    584 //===----------------------------------------------------------------------===//
    585 
    586 CheckerManager::CachedStmtCheckers *
    587 CheckerManager::getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit) {
    588   assert(S);
    589 
    590   CachedStmtCheckersKey key(S->getStmtClass(), isPreVisit);
    591   CachedStmtCheckers *checkers = 0;
    592   CachedStmtCheckersMapTy::iterator CCI = CachedStmtCheckersMap.find(key);
    593   if (CCI != CachedStmtCheckersMap.end()) {
    594     checkers = &(CCI->second);
    595   } else {
    596     // Find the checkers that should run for this Stmt and cache them.
    597     checkers = &CachedStmtCheckersMap[key];
    598     for (unsigned i = 0, e = StmtCheckers.size(); i != e; ++i) {
    599       StmtCheckerInfo &info = StmtCheckers[i];
    600       if (info.IsPreVisit == isPreVisit && info.IsForStmtFn(S))
    601         checkers->push_back(info.CheckFn);
    602     }
    603   }
    604 
    605   assert(checkers);
    606   return checkers;
    607 }
    608 
    609 CheckerManager::~CheckerManager() {
    610   for (unsigned i = 0, e = CheckerDtors.size(); i != e; ++i)
    611     CheckerDtors[i]();
    612 }
    613 
    614 // Anchor for the vtable.
    615 GraphExpander::~GraphExpander() { }
    616