CheckerManager.cpp revision 3f5e8d87dbf449d8b39fe96068415428594d370e
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
21using namespace clang;
22using namespace ento;
23
24bool 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
41void 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
55void 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
80void 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
92template <typename CHECK_CTX>
93static 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
125namespace {
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.
155void 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
165namespace {
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.
194void 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
206namespace {
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.
236void 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
244namespace {
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.
273void 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
281void 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.
289void 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.
299void CheckerManager::runCheckersForBranchCondition(const Stmt *condition,
300                                                   BranchNodeBuilder &B,
301                                                   ExprEngine &Eng) {
302  for (unsigned i = 0, e = BranchConditionCheckers.size(); i != e; ++i) {
303    CheckBranchConditionFunc fn = BranchConditionCheckers[i];
304    fn(condition, B, Eng);
305  }
306}
307
308/// \brief Run checkers for live symbols.
309void CheckerManager::runCheckersForLiveSymbols(const ProgramState *state,
310                                               SymbolReaper &SymReaper) {
311  for (unsigned i = 0, e = LiveSymbolsCheckers.size(); i != e; ++i)
312    LiveSymbolsCheckers[i](state, SymReaper);
313}
314
315namespace {
316  struct CheckDeadSymbolsContext {
317    typedef std::vector<CheckerManager::CheckDeadSymbolsFunc> CheckersTy;
318    const CheckersTy &Checkers;
319    SymbolReaper &SR;
320    const Stmt *S;
321    ExprEngine &Eng;
322
323    CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
324    CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
325
326    CheckDeadSymbolsContext(const CheckersTy &checkers, SymbolReaper &sr,
327                            const Stmt *s, ExprEngine &eng)
328      : Checkers(checkers), SR(sr), S(s), Eng(eng) { }
329
330    void runChecker(CheckerManager::CheckDeadSymbolsFunc checkFn,
331                    ExplodedNodeSet &Dst, ExplodedNode *Pred) {
332      ProgramPoint::Kind K = ProgramPoint::PostPurgeDeadSymbolsKind;
333      const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
334                                Pred->getLocationContext(), checkFn.Checker);
335      CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0);
336
337      checkFn(SR, C);
338    }
339  };
340}
341
342/// \brief Run checkers for dead symbols.
343void CheckerManager::runCheckersForDeadSymbols(ExplodedNodeSet &Dst,
344                                               const ExplodedNodeSet &Src,
345                                               SymbolReaper &SymReaper,
346                                               const Stmt *S,
347                                               ExprEngine &Eng) {
348  CheckDeadSymbolsContext C(DeadSymbolsCheckers, SymReaper, S, Eng);
349  expandGraphWithCheckers(C, Dst, Src);
350}
351
352/// \brief True if at least one checker wants to check region changes.
353bool CheckerManager::wantsRegionChangeUpdate(const ProgramState *state) {
354  for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i)
355    if (RegionChangesCheckers[i].WantUpdateFn(state))
356      return true;
357
358  return false;
359}
360
361/// \brief Run checkers for region changes.
362const ProgramState *
363CheckerManager::runCheckersForRegionChanges(const ProgramState *state,
364                            const StoreManager::InvalidatedSymbols *invalidated,
365                                    ArrayRef<const MemRegion *> ExplicitRegions,
366                                          ArrayRef<const MemRegion *> Regions) {
367  for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i) {
368    // If any checker declares the state infeasible (or if it starts that way),
369    // bail out.
370    if (!state)
371      return NULL;
372    state = RegionChangesCheckers[i].CheckFn(state, invalidated,
373                                             ExplicitRegions, Regions);
374  }
375  return state;
376}
377
378/// \brief Run checkers for handling assumptions on symbolic values.
379const ProgramState *
380CheckerManager::runCheckersForEvalAssume(const ProgramState *state,
381                                         SVal Cond, bool Assumption) {
382  for (unsigned i = 0, e = EvalAssumeCheckers.size(); i != e; ++i) {
383    // If any checker declares the state infeasible (or if it starts that way),
384    // bail out.
385    if (!state)
386      return NULL;
387    state = EvalAssumeCheckers[i](state, Cond, Assumption);
388  }
389  return state;
390}
391
392/// \brief Run checkers for evaluating a call.
393/// Only one checker will evaluate the call.
394void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
395                                            const ExplodedNodeSet &Src,
396                                            const CallExpr *CE,
397                                            ExprEngine &Eng,
398                                            GraphExpander *defaultEval) {
399  if (EvalCallCheckers.empty()   &&
400      InlineCallCheckers.empty() &&
401      defaultEval == 0) {
402    Dst.insert(Src);
403    return;
404  }
405
406  for (ExplodedNodeSet::iterator
407         NI = Src.begin(), NE = Src.end(); NI != NE; ++NI) {
408
409    ExplodedNode *Pred = *NI;
410    bool anyEvaluated = false;
411
412    // First, check if any of the InlineCall callbacks can evaluate the call.
413    assert(InlineCallCheckers.size() <= 1 &&
414           "InlineCall is a special hacky callback to allow intrusive"
415           "evaluation of the call (which simulates inlining). It is "
416           "currently only used by OSAtomicChecker and should go away "
417           "at some point.");
418    for (std::vector<InlineCallFunc>::iterator
419           EI = InlineCallCheckers.begin(), EE = InlineCallCheckers.end();
420         EI != EE; ++EI) {
421      ExplodedNodeSet checkDst;
422      bool evaluated = (*EI)(CE, Eng, Pred, checkDst);
423      assert(!(evaluated && anyEvaluated)
424             && "There are more than one checkers evaluating the call");
425      if (evaluated) {
426        anyEvaluated = true;
427        Dst.insert(checkDst);
428#ifdef NDEBUG
429        break; // on release don't check that no other checker also evals.
430#endif
431      }
432    }
433
434#ifdef NDEBUG // on release don't check that no other checker also evals.
435    if (anyEvaluated) {
436      break;
437    }
438#endif
439
440    // Next, check if any of the EvalCall callbacks can evaluate the call.
441    for (std::vector<EvalCallFunc>::iterator
442           EI = EvalCallCheckers.begin(), EE = EvalCallCheckers.end();
443         EI != EE; ++EI) {
444      ExplodedNodeSet checkDst;
445      ProgramPoint::Kind K = ProgramPoint::PostStmtKind;
446      const ProgramPoint &L = ProgramPoint::getProgramPoint(CE, K,
447                                Pred->getLocationContext(), EI->Checker);
448
449      CheckerContext C(checkDst, Eng.getBuilder(), Eng, Pred, L, 0);
450      bool evaluated = (*EI)(CE, C);
451      assert(!(evaluated && anyEvaluated)
452             && "There are more than one checkers evaluating the call");
453      if (evaluated) {
454        anyEvaluated = true;
455        Dst.insert(checkDst);
456#ifdef NDEBUG
457        break; // on release don't check that no other checker also evals.
458#endif
459      }
460    }
461
462    // If none of the checkers evaluated the call, ask ExprEngine to handle it.
463    if (!anyEvaluated) {
464      if (defaultEval)
465        defaultEval->expandGraph(Dst, Pred);
466      else
467        Dst.insert(Pred);
468    }
469  }
470}
471
472/// \brief Run checkers for the entire Translation Unit.
473void CheckerManager::runCheckersOnEndOfTranslationUnit(
474                                                  const TranslationUnitDecl *TU,
475                                                  AnalysisManager &mgr,
476                                                  BugReporter &BR) {
477  for (unsigned i = 0, e = EndOfTranslationUnitCheckers.size(); i != e; ++i)
478    EndOfTranslationUnitCheckers[i](TU, mgr, BR);
479}
480
481void CheckerManager::runCheckersForPrintState(raw_ostream &Out,
482                                              const ProgramState *State,
483                                              const char *NL, const char *Sep) {
484  for (llvm::DenseMap<CheckerTag, CheckerRef>::iterator
485        I = CheckerTags.begin(), E = CheckerTags.end(); I != E; ++I)
486    I->second->printState(Out, State, NL, Sep);
487}
488
489//===----------------------------------------------------------------------===//
490// Internal registration functions for AST traversing.
491//===----------------------------------------------------------------------===//
492
493void CheckerManager::_registerForDecl(CheckDeclFunc checkfn,
494                                      HandlesDeclFunc isForDeclFn) {
495  DeclCheckerInfo info = { checkfn, isForDeclFn };
496  DeclCheckers.push_back(info);
497}
498
499void CheckerManager::_registerForBody(CheckDeclFunc checkfn) {
500  BodyCheckers.push_back(checkfn);
501}
502
503//===----------------------------------------------------------------------===//
504// Internal registration functions for path-sensitive checking.
505//===----------------------------------------------------------------------===//
506
507void CheckerManager::_registerForPreStmt(CheckStmtFunc checkfn,
508                                         HandlesStmtFunc isForStmtFn) {
509  StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/true };
510  StmtCheckers.push_back(info);
511}
512void CheckerManager::_registerForPostStmt(CheckStmtFunc checkfn,
513                                          HandlesStmtFunc isForStmtFn) {
514  StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/false };
515  StmtCheckers.push_back(info);
516}
517
518void CheckerManager::_registerForPreObjCMessage(CheckObjCMessageFunc checkfn) {
519  PreObjCMessageCheckers.push_back(checkfn);
520}
521void CheckerManager::_registerForPostObjCMessage(CheckObjCMessageFunc checkfn) {
522  PostObjCMessageCheckers.push_back(checkfn);
523}
524
525void CheckerManager::_registerForLocation(CheckLocationFunc checkfn) {
526  LocationCheckers.push_back(checkfn);
527}
528
529void CheckerManager::_registerForBind(CheckBindFunc checkfn) {
530  BindCheckers.push_back(checkfn);
531}
532
533void CheckerManager::_registerForEndAnalysis(CheckEndAnalysisFunc checkfn) {
534  EndAnalysisCheckers.push_back(checkfn);
535}
536
537void CheckerManager::_registerForEndPath(CheckEndPathFunc checkfn) {
538  EndPathCheckers.push_back(checkfn);
539}
540
541void CheckerManager::_registerForBranchCondition(
542                                             CheckBranchConditionFunc checkfn) {
543  BranchConditionCheckers.push_back(checkfn);
544}
545
546void CheckerManager::_registerForLiveSymbols(CheckLiveSymbolsFunc checkfn) {
547  LiveSymbolsCheckers.push_back(checkfn);
548}
549
550void CheckerManager::_registerForDeadSymbols(CheckDeadSymbolsFunc checkfn) {
551  DeadSymbolsCheckers.push_back(checkfn);
552}
553
554void CheckerManager::_registerForRegionChanges(CheckRegionChangesFunc checkfn,
555                                     WantsRegionChangeUpdateFunc wantUpdateFn) {
556  RegionChangesCheckerInfo info = {checkfn, wantUpdateFn};
557  RegionChangesCheckers.push_back(info);
558}
559
560void CheckerManager::_registerForEvalAssume(EvalAssumeFunc checkfn) {
561  EvalAssumeCheckers.push_back(checkfn);
562}
563
564void CheckerManager::_registerForEvalCall(EvalCallFunc checkfn) {
565  EvalCallCheckers.push_back(checkfn);
566}
567
568void CheckerManager::_registerForInlineCall(InlineCallFunc checkfn) {
569  InlineCallCheckers.push_back(checkfn);
570}
571
572void CheckerManager::_registerForEndOfTranslationUnit(
573                                            CheckEndOfTranslationUnit checkfn) {
574  EndOfTranslationUnitCheckers.push_back(checkfn);
575}
576
577//===----------------------------------------------------------------------===//
578// Implementation details.
579//===----------------------------------------------------------------------===//
580
581CheckerManager::CachedStmtCheckers *
582CheckerManager::getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit) {
583  assert(S);
584
585  CachedStmtCheckersKey key(S->getStmtClass(), isPreVisit);
586  CachedStmtCheckers *checkers = 0;
587  CachedStmtCheckersMapTy::iterator CCI = CachedStmtCheckersMap.find(key);
588  if (CCI != CachedStmtCheckersMap.end()) {
589    checkers = &(CCI->second);
590  } else {
591    // Find the checkers that should run for this Stmt and cache them.
592    checkers = &CachedStmtCheckersMap[key];
593    for (unsigned i = 0, e = StmtCheckers.size(); i != e; ++i) {
594      StmtCheckerInfo &info = StmtCheckers[i];
595      if (info.IsPreVisit == isPreVisit && info.IsForStmtFn(S))
596        checkers->push_back(info.CheckFn);
597    }
598  }
599
600  assert(checkers);
601  return checkers;
602}
603
604CheckerManager::~CheckerManager() {
605  for (unsigned i = 0, e = CheckerDtors.size(); i != e; ++i)
606    CheckerDtors[i]();
607}
608
609// Anchor for the vtable.
610GraphExpander::~GraphExpander() { }
611