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   const NodeBuilderContext &BldrCtx = checkCtx.Eng.getBuilderContext();
97   if (Src.empty())
98     return;
99 
100   typename CHECK_CTX::CheckersTy::const_iterator
101       I = checkCtx.checkers_begin(), E = checkCtx.checkers_end();
102   if (I == E) {
103     Dst.insert(Src);
104     return;
105   }
106 
107   ExplodedNodeSet Tmp1, Tmp2;
108   const ExplodedNodeSet *PrevSet = &Src;
109 
110   for (; I != E; ++I) {
111     ExplodedNodeSet *CurrSet = 0;
112     if (I+1 == E)
113       CurrSet = &Dst;
114     else {
115       CurrSet = (PrevSet == &Tmp1) ? &Tmp2 : &Tmp1;
116       CurrSet->clear();
117     }
118 
119     NodeBuilder B(*PrevSet, *CurrSet, BldrCtx);
120     for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
121          NI != NE; ++NI) {
122       checkCtx.runChecker(*I, B, *NI);
123     }
124 
125     // If all the produced transitions are sinks, stop.
126     if (CurrSet->empty())
127       return;
128 
129     // Update which NodeSet is the current one.
130     PrevSet = CurrSet;
131   }
132 }
133 
134 namespace {
135   struct CheckStmtContext {
136     typedef SmallVectorImpl<CheckerManager::CheckStmtFunc> CheckersTy;
137     bool IsPreVisit;
138     const CheckersTy &Checkers;
139     const Stmt *S;
140     ExprEngine &Eng;
141 
142     CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
143     CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
144 
145     CheckStmtContext(bool isPreVisit, const CheckersTy &checkers,
146                      const Stmt *s, ExprEngine &eng)
147       : IsPreVisit(isPreVisit), Checkers(checkers), S(s), Eng(eng) { }
148 
149     void runChecker(CheckerManager::CheckStmtFunc checkFn,
150                     NodeBuilder &Bldr, ExplodedNode *Pred) {
151       // FIXME: Remove respondsToCallback from CheckerContext;
152       ProgramPoint::Kind K =  IsPreVisit ? ProgramPoint::PreStmtKind :
153                                            ProgramPoint::PostStmtKind;
154       const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
155                                 Pred->getLocationContext(), checkFn.Checker);
156       CheckerContext C(Bldr, Eng, Pred, L);
157 
158       checkFn(S, C);
159     }
160   };
161 }
162 
163 /// \brief Run checkers for visiting Stmts.
164 void CheckerManager::runCheckersForStmt(bool isPreVisit,
165                                         ExplodedNodeSet &Dst,
166                                         const ExplodedNodeSet &Src,
167                                         const Stmt *S,
168                                         ExprEngine &Eng) {
169   CheckStmtContext C(isPreVisit, *getCachedStmtCheckersFor(S, isPreVisit),
170                      S, Eng);
171   expandGraphWithCheckers(C, Dst, Src);
172 }
173 
174 namespace {
175   struct CheckObjCMessageContext {
176     typedef std::vector<CheckerManager::CheckObjCMessageFunc> CheckersTy;
177     bool IsPreVisit;
178     const CheckersTy &Checkers;
179     const ObjCMessage &Msg;
180     ExprEngine &Eng;
181 
182     CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
183     CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
184 
185     CheckObjCMessageContext(bool isPreVisit, const CheckersTy &checkers,
186                             const ObjCMessage &msg, ExprEngine &eng)
187       : IsPreVisit(isPreVisit), Checkers(checkers), Msg(msg), Eng(eng) { }
188 
189     void runChecker(CheckerManager::CheckObjCMessageFunc checkFn,
190                     NodeBuilder &Bldr, ExplodedNode *Pred) {
191       ProgramPoint::Kind K =  IsPreVisit ? ProgramPoint::PreStmtKind :
192                                            ProgramPoint::PostStmtKind;
193       const ProgramPoint &L =
194         ProgramPoint::getProgramPoint(Msg.getMessageExpr(),
195                                       K, Pred->getLocationContext(),
196                                       checkFn.Checker);
197       CheckerContext C(Bldr, Eng, Pred, L);
198 
199       checkFn(Msg, C);
200     }
201   };
202 }
203 
204 /// \brief Run checkers for visiting obj-c messages.
205 void CheckerManager::runCheckersForObjCMessage(bool isPreVisit,
206                                                ExplodedNodeSet &Dst,
207                                                const ExplodedNodeSet &Src,
208                                                const ObjCMessage &msg,
209                                                ExprEngine &Eng) {
210   CheckObjCMessageContext C(isPreVisit,
211                             isPreVisit ? PreObjCMessageCheckers
212                                        : PostObjCMessageCheckers,
213                             msg, Eng);
214   expandGraphWithCheckers(C, Dst, Src);
215 }
216 
217 namespace {
218   struct CheckLocationContext {
219     typedef std::vector<CheckerManager::CheckLocationFunc> CheckersTy;
220     const CheckersTy &Checkers;
221     SVal Loc;
222     bool IsLoad;
223     const Stmt *S;
224     ExprEngine &Eng;
225 
226     CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
227     CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
228 
229     CheckLocationContext(const CheckersTy &checkers,
230                          SVal loc, bool isLoad, const Stmt *s, ExprEngine &eng)
231       : Checkers(checkers), Loc(loc), IsLoad(isLoad), S(s), Eng(eng) { }
232 
233     void runChecker(CheckerManager::CheckLocationFunc checkFn,
234                     NodeBuilder &Bldr, ExplodedNode *Pred) {
235       ProgramPoint::Kind K =  IsLoad ? ProgramPoint::PreLoadKind :
236                                        ProgramPoint::PreStoreKind;
237       const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
238                                 Pred->getLocationContext(), checkFn.Checker);
239       CheckerContext C(Bldr, Eng, Pred, L);
240 
241       checkFn(Loc, IsLoad, S, C);
242     }
243   };
244 }
245 
246 /// \brief Run checkers for load/store of a location.
247 
248 void CheckerManager::runCheckersForLocation(ExplodedNodeSet &Dst,
249                                             const ExplodedNodeSet &Src,
250                                             SVal location, bool isLoad,
251                                             const Stmt *S, ExprEngine &Eng) {
252   CheckLocationContext C(LocationCheckers, location, isLoad, S, Eng);
253   expandGraphWithCheckers(C, Dst, Src);
254 }
255 
256 namespace {
257   struct CheckBindContext {
258     typedef std::vector<CheckerManager::CheckBindFunc> CheckersTy;
259     const CheckersTy &Checkers;
260     SVal Loc;
261     SVal Val;
262     const Stmt *S;
263     ExprEngine &Eng;
264     ProgramPoint::Kind PointKind;
265 
266     CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
267     CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
268 
269     CheckBindContext(const CheckersTy &checkers,
270                      SVal loc, SVal val, const Stmt *s, ExprEngine &eng,
271                      ProgramPoint::Kind PK)
272       : Checkers(checkers), Loc(loc), Val(val), S(s), Eng(eng), PointKind(PK) {}
273 
274     void runChecker(CheckerManager::CheckBindFunc checkFn,
275                     NodeBuilder &Bldr, ExplodedNode *Pred) {
276       const ProgramPoint &L = ProgramPoint::getProgramPoint(S, PointKind,
277                                 Pred->getLocationContext(), checkFn.Checker);
278       CheckerContext C(Bldr, Eng, Pred, L);
279 
280       checkFn(Loc, Val, S, C);
281     }
282   };
283 }
284 
285 /// \brief Run checkers for binding of a value to a location.
286 void CheckerManager::runCheckersForBind(ExplodedNodeSet &Dst,
287                                         const ExplodedNodeSet &Src,
288                                         SVal location, SVal val,
289                                         const Stmt *S, ExprEngine &Eng,
290                                         ProgramPoint::Kind PointKind) {
291   CheckBindContext C(BindCheckers, location, val, S, Eng, PointKind);
292   expandGraphWithCheckers(C, Dst, Src);
293 }
294 
295 void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G,
296                                                BugReporter &BR,
297                                                ExprEngine &Eng) {
298   for (unsigned i = 0, e = EndAnalysisCheckers.size(); i != e; ++i)
299     EndAnalysisCheckers[i](G, BR, Eng);
300 }
301 
302 /// \brief Run checkers for end of path.
303 // Note, We do not chain the checker output (like in expandGraphWithCheckers)
304 // for this callback since end of path nodes are expected to be final.
305 void CheckerManager::runCheckersForEndPath(NodeBuilderContext &BC,
306                                            ExplodedNodeSet &Dst,
307                                            ExprEngine &Eng) {
308   ExplodedNode *Pred = BC.Pred;
309 
310   // We define the builder outside of the loop bacause if at least one checkers
311   // creates a sucsessor for Pred, we do not need to generate an
312   // autotransition for it.
313   NodeBuilder Bldr(Pred, Dst, BC);
314   for (unsigned i = 0, e = EndPathCheckers.size(); i != e; ++i) {
315     CheckEndPathFunc checkFn = EndPathCheckers[i];
316 
317     const ProgramPoint &L = BlockEntrance(BC.Block,
318                                           Pred->getLocationContext(),
319                                           checkFn.Checker);
320     CheckerContext C(Bldr, Eng, Pred, L);
321     checkFn(C);
322   }
323 }
324 
325 namespace {
326   struct CheckBranchConditionContext {
327     typedef std::vector<CheckerManager::CheckBranchConditionFunc> CheckersTy;
328     const CheckersTy &Checkers;
329     const Stmt *Condition;
330     ExprEngine &Eng;
331 
332     CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
333     CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
334 
335     CheckBranchConditionContext(const CheckersTy &checkers,
336                                 const Stmt *Cond, ExprEngine &eng)
337       : Checkers(checkers), Condition(Cond), Eng(eng) {}
338 
339     void runChecker(CheckerManager::CheckBranchConditionFunc checkFn,
340                     NodeBuilder &Bldr, ExplodedNode *Pred) {
341       ProgramPoint L = PostCondition(Condition, Pred->getLocationContext(),
342                                      checkFn.Checker);
343       CheckerContext C(Bldr, Eng, Pred, L);
344       checkFn(Condition, C);
345     }
346   };
347 }
348 
349 /// \brief Run checkers for branch condition.
350 void CheckerManager::runCheckersForBranchCondition(const Stmt *Condition,
351                                                    ExplodedNodeSet &Dst,
352                                                    ExplodedNode *Pred,
353                                                    ExprEngine &Eng) {
354   ExplodedNodeSet Src;
355   Src.insert(Pred);
356   CheckBranchConditionContext C(BranchConditionCheckers, Condition, Eng);
357   expandGraphWithCheckers(C, Dst, Src);
358 }
359 
360 /// \brief Run checkers for live symbols.
361 void CheckerManager::runCheckersForLiveSymbols(ProgramStateRef state,
362                                                SymbolReaper &SymReaper) {
363   for (unsigned i = 0, e = LiveSymbolsCheckers.size(); i != e; ++i)
364     LiveSymbolsCheckers[i](state, SymReaper);
365 }
366 
367 namespace {
368   struct CheckDeadSymbolsContext {
369     typedef std::vector<CheckerManager::CheckDeadSymbolsFunc> CheckersTy;
370     const CheckersTy &Checkers;
371     SymbolReaper &SR;
372     const Stmt *S;
373     ExprEngine &Eng;
374 
375     CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
376     CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
377 
378     CheckDeadSymbolsContext(const CheckersTy &checkers, SymbolReaper &sr,
379                             const Stmt *s, ExprEngine &eng)
380       : Checkers(checkers), SR(sr), S(s), Eng(eng) { }
381 
382     void runChecker(CheckerManager::CheckDeadSymbolsFunc checkFn,
383                     NodeBuilder &Bldr, ExplodedNode *Pred) {
384       ProgramPoint::Kind K = ProgramPoint::PostPurgeDeadSymbolsKind;
385       const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
386                                 Pred->getLocationContext(), checkFn.Checker);
387       CheckerContext C(Bldr, Eng, Pred, L);
388 
389       checkFn(SR, C);
390     }
391   };
392 }
393 
394 /// \brief Run checkers for dead symbols.
395 void CheckerManager::runCheckersForDeadSymbols(ExplodedNodeSet &Dst,
396                                                const ExplodedNodeSet &Src,
397                                                SymbolReaper &SymReaper,
398                                                const Stmt *S,
399                                                ExprEngine &Eng) {
400   CheckDeadSymbolsContext C(DeadSymbolsCheckers, SymReaper, S, Eng);
401   expandGraphWithCheckers(C, Dst, Src);
402 }
403 
404 /// \brief True if at least one checker wants to check region changes.
405 bool CheckerManager::wantsRegionChangeUpdate(ProgramStateRef state) {
406   for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i)
407     if (RegionChangesCheckers[i].WantUpdateFn(state))
408       return true;
409 
410   return false;
411 }
412 
413 /// \brief Run checkers for region changes.
414 ProgramStateRef
415 CheckerManager::runCheckersForRegionChanges(ProgramStateRef state,
416                             const StoreManager::InvalidatedSymbols *invalidated,
417                                     ArrayRef<const MemRegion *> ExplicitRegions,
418                                           ArrayRef<const MemRegion *> Regions,
419                                           const CallOrObjCMessage *Call) {
420   for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i) {
421     // If any checker declares the state infeasible (or if it starts that way),
422     // bail out.
423     if (!state)
424       return NULL;
425     state = RegionChangesCheckers[i].CheckFn(state, invalidated,
426                                              ExplicitRegions, Regions, Call);
427   }
428   return state;
429 }
430 
431 /// \brief Run checkers for handling assumptions on symbolic values.
432 ProgramStateRef
433 CheckerManager::runCheckersForEvalAssume(ProgramStateRef state,
434                                          SVal Cond, bool Assumption) {
435   for (unsigned i = 0, e = EvalAssumeCheckers.size(); i != e; ++i) {
436     // If any checker declares the state infeasible (or if it starts that way),
437     // bail out.
438     if (!state)
439       return NULL;
440     state = EvalAssumeCheckers[i](state, Cond, Assumption);
441   }
442   return state;
443 }
444 
445 /// \brief Run checkers for evaluating a call.
446 /// Only one checker will evaluate the call.
447 void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
448                                             const ExplodedNodeSet &Src,
449                                             const CallExpr *CE,
450                                             ExprEngine &Eng,
451                                             GraphExpander *defaultEval) {
452   if (EvalCallCheckers.empty()   &&
453       InlineCallCheckers.empty() &&
454       defaultEval == 0) {
455     Dst.insert(Src);
456     return;
457   }
458 
459   for (ExplodedNodeSet::iterator
460          NI = Src.begin(), NE = Src.end(); NI != NE; ++NI) {
461 
462     ExplodedNode *Pred = *NI;
463     bool anyEvaluated = false;
464 
465     // First, check if any of the InlineCall callbacks can evaluate the call.
466     assert(InlineCallCheckers.size() <= 1 &&
467            "InlineCall is a special hacky callback to allow intrusive"
468            "evaluation of the call (which simulates inlining). It is "
469            "currently only used by OSAtomicChecker and should go away "
470            "at some point.");
471     for (std::vector<InlineCallFunc>::iterator
472            EI = InlineCallCheckers.begin(), EE = InlineCallCheckers.end();
473          EI != EE; ++EI) {
474       ExplodedNodeSet checkDst;
475       bool evaluated = (*EI)(CE, Eng, Pred, checkDst);
476       assert(!(evaluated && anyEvaluated)
477              && "There are more than one checkers evaluating the call");
478       if (evaluated) {
479         anyEvaluated = true;
480         Dst.insert(checkDst);
481 #ifdef NDEBUG
482         break; // on release don't check that no other checker also evals.
483 #endif
484       }
485     }
486 
487 #ifdef NDEBUG // on release don't check that no other checker also evals.
488     if (anyEvaluated) {
489       break;
490     }
491 #endif
492 
493     ExplodedNodeSet checkDst;
494     NodeBuilder B(Pred, checkDst, Eng.getBuilderContext());
495     // Next, check if any of the EvalCall callbacks can evaluate the call.
496     for (std::vector<EvalCallFunc>::iterator
497            EI = EvalCallCheckers.begin(), EE = EvalCallCheckers.end();
498          EI != EE; ++EI) {
499       ProgramPoint::Kind K = ProgramPoint::PostStmtKind;
500       const ProgramPoint &L = ProgramPoint::getProgramPoint(CE, K,
501                                 Pred->getLocationContext(), EI->Checker);
502       bool evaluated = false;
503       { // CheckerContext generates transitions(populates checkDest) on
504         // destruction, so introduce the scope to make sure it gets properly
505         // populated.
506         CheckerContext C(B, Eng, Pred, L);
507         evaluated = (*EI)(CE, C);
508       }
509       assert(!(evaluated && anyEvaluated)
510              && "There are more than one checkers evaluating the call");
511       if (evaluated) {
512         anyEvaluated = true;
513         Dst.insert(checkDst);
514 #ifdef NDEBUG
515         break; // on release don't check that no other checker also evals.
516 #endif
517       }
518     }
519 
520     // If none of the checkers evaluated the call, ask ExprEngine to handle it.
521     if (!anyEvaluated) {
522       if (defaultEval)
523         defaultEval->expandGraph(Dst, Pred);
524       else
525         Dst.insert(Pred);
526     }
527   }
528 }
529 
530 /// \brief Run checkers for the entire Translation Unit.
531 void CheckerManager::runCheckersOnEndOfTranslationUnit(
532                                                   const TranslationUnitDecl *TU,
533                                                   AnalysisManager &mgr,
534                                                   BugReporter &BR) {
535   for (unsigned i = 0, e = EndOfTranslationUnitCheckers.size(); i != e; ++i)
536     EndOfTranslationUnitCheckers[i](TU, mgr, BR);
537 }
538 
539 void CheckerManager::runCheckersForPrintState(raw_ostream &Out,
540                                               ProgramStateRef State,
541                                               const char *NL, const char *Sep) {
542   for (llvm::DenseMap<CheckerTag, CheckerRef>::iterator
543         I = CheckerTags.begin(), E = CheckerTags.end(); I != E; ++I)
544     I->second->printState(Out, State, NL, Sep);
545 }
546 
547 //===----------------------------------------------------------------------===//
548 // Internal registration functions for AST traversing.
549 //===----------------------------------------------------------------------===//
550 
551 void CheckerManager::_registerForDecl(CheckDeclFunc checkfn,
552                                       HandlesDeclFunc isForDeclFn) {
553   DeclCheckerInfo info = { checkfn, isForDeclFn };
554   DeclCheckers.push_back(info);
555 }
556 
557 void CheckerManager::_registerForBody(CheckDeclFunc checkfn) {
558   BodyCheckers.push_back(checkfn);
559 }
560 
561 //===----------------------------------------------------------------------===//
562 // Internal registration functions for path-sensitive checking.
563 //===----------------------------------------------------------------------===//
564 
565 void CheckerManager::_registerForPreStmt(CheckStmtFunc checkfn,
566                                          HandlesStmtFunc isForStmtFn) {
567   StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/true };
568   StmtCheckers.push_back(info);
569 }
570 void CheckerManager::_registerForPostStmt(CheckStmtFunc checkfn,
571                                           HandlesStmtFunc isForStmtFn) {
572   StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/false };
573   StmtCheckers.push_back(info);
574 }
575 
576 void CheckerManager::_registerForPreObjCMessage(CheckObjCMessageFunc checkfn) {
577   PreObjCMessageCheckers.push_back(checkfn);
578 }
579 void CheckerManager::_registerForPostObjCMessage(CheckObjCMessageFunc checkfn) {
580   PostObjCMessageCheckers.push_back(checkfn);
581 }
582 
583 void CheckerManager::_registerForLocation(CheckLocationFunc checkfn) {
584   LocationCheckers.push_back(checkfn);
585 }
586 
587 void CheckerManager::_registerForBind(CheckBindFunc checkfn) {
588   BindCheckers.push_back(checkfn);
589 }
590 
591 void CheckerManager::_registerForEndAnalysis(CheckEndAnalysisFunc checkfn) {
592   EndAnalysisCheckers.push_back(checkfn);
593 }
594 
595 void CheckerManager::_registerForEndPath(CheckEndPathFunc checkfn) {
596   EndPathCheckers.push_back(checkfn);
597 }
598 
599 void CheckerManager::_registerForBranchCondition(
600                                              CheckBranchConditionFunc checkfn) {
601   BranchConditionCheckers.push_back(checkfn);
602 }
603 
604 void CheckerManager::_registerForLiveSymbols(CheckLiveSymbolsFunc checkfn) {
605   LiveSymbolsCheckers.push_back(checkfn);
606 }
607 
608 void CheckerManager::_registerForDeadSymbols(CheckDeadSymbolsFunc checkfn) {
609   DeadSymbolsCheckers.push_back(checkfn);
610 }
611 
612 void CheckerManager::_registerForRegionChanges(CheckRegionChangesFunc checkfn,
613                                      WantsRegionChangeUpdateFunc wantUpdateFn) {
614   RegionChangesCheckerInfo info = {checkfn, wantUpdateFn};
615   RegionChangesCheckers.push_back(info);
616 }
617 
618 void CheckerManager::_registerForEvalAssume(EvalAssumeFunc checkfn) {
619   EvalAssumeCheckers.push_back(checkfn);
620 }
621 
622 void CheckerManager::_registerForEvalCall(EvalCallFunc checkfn) {
623   EvalCallCheckers.push_back(checkfn);
624 }
625 
626 void CheckerManager::_registerForInlineCall(InlineCallFunc checkfn) {
627   InlineCallCheckers.push_back(checkfn);
628 }
629 
630 void CheckerManager::_registerForEndOfTranslationUnit(
631                                             CheckEndOfTranslationUnit checkfn) {
632   EndOfTranslationUnitCheckers.push_back(checkfn);
633 }
634 
635 //===----------------------------------------------------------------------===//
636 // Implementation details.
637 //===----------------------------------------------------------------------===//
638 
639 CheckerManager::CachedStmtCheckers *
640 CheckerManager::getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit) {
641   assert(S);
642 
643   CachedStmtCheckersKey key(S->getStmtClass(), isPreVisit);
644   CachedStmtCheckers *checkers = 0;
645   CachedStmtCheckersMapTy::iterator CCI = CachedStmtCheckersMap.find(key);
646   if (CCI != CachedStmtCheckersMap.end()) {
647     checkers = &(CCI->second);
648   } else {
649     // Find the checkers that should run for this Stmt and cache them.
650     checkers = &CachedStmtCheckersMap[key];
651     for (unsigned i = 0, e = StmtCheckers.size(); i != e; ++i) {
652       StmtCheckerInfo &info = StmtCheckers[i];
653       if (info.IsPreVisit == isPreVisit && info.IsForStmtFn(S))
654         checkers->push_back(info.CheckFn);
655     }
656   }
657 
658   assert(checkers);
659   return checkers;
660 }
661 
662 CheckerManager::~CheckerManager() {
663   for (unsigned i = 0, e = CheckerDtors.size(); i != e; ++i)
664     CheckerDtors[i]();
665 }
666 
667 // Anchor for the vtable.
668 GraphExpander::~GraphExpander() { }
669