1218887Sdim//===--- CheckerManager.cpp - Static Analyzer Checker Manager -------------===//
2218887Sdim//
3218887Sdim//                     The LLVM Compiler Infrastructure
4218887Sdim//
5218887Sdim// This file is distributed under the University of Illinois Open Source
6218887Sdim// License. See LICENSE.TXT for details.
7218887Sdim//
8218887Sdim//===----------------------------------------------------------------------===//
9218887Sdim//
10218887Sdim// Defines the Static Analyzer Checker Manager.
11218887Sdim//
12218887Sdim//===----------------------------------------------------------------------===//
13218887Sdim
14218887Sdim#include "clang/StaticAnalyzer/Core/CheckerManager.h"
15249423Sdim#include "clang/AST/DeclBase.h"
16249423Sdim#include "clang/Analysis/ProgramPoint.h"
17226633Sdim#include "clang/StaticAnalyzer/Core/Checker.h"
18249423Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
19219077Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
20218887Sdim
21218887Sdimusing namespace clang;
22218887Sdimusing namespace ento;
23218887Sdim
24221345Sdimbool CheckerManager::hasPathSensitiveCheckers() const {
25221345Sdim  return !StmtCheckers.empty()              ||
26221345Sdim         !PreObjCMessageCheckers.empty()    ||
27221345Sdim         !PostObjCMessageCheckers.empty()   ||
28239462Sdim         !PreCallCheckers.empty()    ||
29239462Sdim         !PostCallCheckers.empty()   ||
30221345Sdim         !LocationCheckers.empty()          ||
31221345Sdim         !BindCheckers.empty()              ||
32221345Sdim         !EndAnalysisCheckers.empty()       ||
33249423Sdim         !EndFunctionCheckers.empty()           ||
34221345Sdim         !BranchConditionCheckers.empty()   ||
35221345Sdim         !LiveSymbolsCheckers.empty()       ||
36221345Sdim         !DeadSymbolsCheckers.empty()       ||
37221345Sdim         !RegionChangesCheckers.empty()     ||
38221345Sdim         !EvalAssumeCheckers.empty()        ||
39243830Sdim         !EvalCallCheckers.empty();
40221345Sdim}
41221345Sdim
42221345Sdimvoid CheckerManager::finishedCheckerRegistration() {
43221345Sdim#ifndef NDEBUG
44221345Sdim  // Make sure that for every event that has listeners, there is at least
45221345Sdim  // one dispatcher registered for it.
46221345Sdim  for (llvm::DenseMap<EventTag, EventInfo>::iterator
47221345Sdim         I = Events.begin(), E = Events.end(); I != E; ++I)
48221345Sdim    assert(I->second.HasDispatcher && "No dispatcher registered for an event");
49221345Sdim#endif
50221345Sdim}
51221345Sdim
52219077Sdim//===----------------------------------------------------------------------===//
53219077Sdim// Functions for running checkers for AST traversing..
54219077Sdim//===----------------------------------------------------------------------===//
55219077Sdim
56218887Sdimvoid CheckerManager::runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr,
57218887Sdim                                          BugReporter &BR) {
58218887Sdim  assert(D);
59218887Sdim
60218887Sdim  unsigned DeclKind = D->getKind();
61218887Sdim  CachedDeclCheckers *checkers = 0;
62218887Sdim  CachedDeclCheckersMapTy::iterator CCI = CachedDeclCheckersMap.find(DeclKind);
63218887Sdim  if (CCI != CachedDeclCheckersMap.end()) {
64218887Sdim    checkers = &(CCI->second);
65218887Sdim  } else {
66218887Sdim    // Find the checkers that should run for this Decl and cache them.
67218887Sdim    checkers = &CachedDeclCheckersMap[DeclKind];
68218887Sdim    for (unsigned i = 0, e = DeclCheckers.size(); i != e; ++i) {
69218887Sdim      DeclCheckerInfo &info = DeclCheckers[i];
70218887Sdim      if (info.IsForDeclFn(D))
71219077Sdim        checkers->push_back(info.CheckFn);
72218887Sdim    }
73218887Sdim  }
74218887Sdim
75218887Sdim  assert(checkers);
76218887Sdim  for (CachedDeclCheckers::iterator
77219077Sdim         I = checkers->begin(), E = checkers->end(); I != E; ++I)
78219077Sdim    (*I)(D, mgr, BR);
79218887Sdim}
80218887Sdim
81218887Sdimvoid CheckerManager::runCheckersOnASTBody(const Decl *D, AnalysisManager& mgr,
82218887Sdim                                          BugReporter &BR) {
83218887Sdim  assert(D && D->hasBody());
84218887Sdim
85219077Sdim  for (unsigned i = 0, e = BodyCheckers.size(); i != e; ++i)
86219077Sdim    BodyCheckers[i](D, mgr, BR);
87219077Sdim}
88219077Sdim
89219077Sdim//===----------------------------------------------------------------------===//
90219077Sdim// Functions for running checkers for path-sensitive checking.
91219077Sdim//===----------------------------------------------------------------------===//
92219077Sdim
93219077Sdimtemplate <typename CHECK_CTX>
94219077Sdimstatic void expandGraphWithCheckers(CHECK_CTX checkCtx,
95219077Sdim                                    ExplodedNodeSet &Dst,
96219077Sdim                                    const ExplodedNodeSet &Src) {
97234353Sdim  const NodeBuilderContext &BldrCtx = checkCtx.Eng.getBuilderContext();
98234353Sdim  if (Src.empty())
99234353Sdim    return;
100219077Sdim
101219077Sdim  typename CHECK_CTX::CheckersTy::const_iterator
102219077Sdim      I = checkCtx.checkers_begin(), E = checkCtx.checkers_end();
103219077Sdim  if (I == E) {
104219077Sdim    Dst.insert(Src);
105219077Sdim    return;
106218887Sdim  }
107219077Sdim
108219077Sdim  ExplodedNodeSet Tmp1, Tmp2;
109219077Sdim  const ExplodedNodeSet *PrevSet = &Src;
110219077Sdim
111219077Sdim  for (; I != E; ++I) {
112219077Sdim    ExplodedNodeSet *CurrSet = 0;
113219077Sdim    if (I+1 == E)
114219077Sdim      CurrSet = &Dst;
115219077Sdim    else {
116219077Sdim      CurrSet = (PrevSet == &Tmp1) ? &Tmp2 : &Tmp1;
117219077Sdim      CurrSet->clear();
118219077Sdim    }
119219077Sdim
120234353Sdim    NodeBuilder B(*PrevSet, *CurrSet, BldrCtx);
121219077Sdim    for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
122234353Sdim         NI != NE; ++NI) {
123234353Sdim      checkCtx.runChecker(*I, B, *NI);
124234353Sdim    }
125219077Sdim
126234353Sdim    // If all the produced transitions are sinks, stop.
127234353Sdim    if (CurrSet->empty())
128234353Sdim      return;
129234353Sdim
130219077Sdim    // Update which NodeSet is the current one.
131219077Sdim    PrevSet = CurrSet;
132219077Sdim  }
133218887Sdim}
134218887Sdim
135219077Sdimnamespace {
136219077Sdim  struct CheckStmtContext {
137226633Sdim    typedef SmallVectorImpl<CheckerManager::CheckStmtFunc> CheckersTy;
138219077Sdim    bool IsPreVisit;
139219077Sdim    const CheckersTy &Checkers;
140219077Sdim    const Stmt *S;
141219077Sdim    ExprEngine &Eng;
142239462Sdim    bool WasInlined;
143219077Sdim
144219077Sdim    CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
145219077Sdim    CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
146219077Sdim
147219077Sdim    CheckStmtContext(bool isPreVisit, const CheckersTy &checkers,
148234353Sdim                     const Stmt *s, ExprEngine &eng, bool wasInlined = false)
149234353Sdim      : IsPreVisit(isPreVisit), Checkers(checkers), S(s), Eng(eng),
150239462Sdim        WasInlined(wasInlined) {}
151219077Sdim
152219077Sdim    void runChecker(CheckerManager::CheckStmtFunc checkFn,
153234353Sdim                    NodeBuilder &Bldr, ExplodedNode *Pred) {
154219077Sdim      // FIXME: Remove respondsToCallback from CheckerContext;
155226633Sdim      ProgramPoint::Kind K =  IsPreVisit ? ProgramPoint::PreStmtKind :
156226633Sdim                                           ProgramPoint::PostStmtKind;
157226633Sdim      const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
158226633Sdim                                Pred->getLocationContext(), checkFn.Checker);
159239462Sdim      CheckerContext C(Bldr, Eng, Pred, L, WasInlined);
160219077Sdim      checkFn(S, C);
161219077Sdim    }
162219077Sdim  };
163219077Sdim}
164219077Sdim
165219077Sdim/// \brief Run checkers for visiting Stmts.
166219077Sdimvoid CheckerManager::runCheckersForStmt(bool isPreVisit,
167219077Sdim                                        ExplodedNodeSet &Dst,
168219077Sdim                                        const ExplodedNodeSet &Src,
169219077Sdim                                        const Stmt *S,
170234353Sdim                                        ExprEngine &Eng,
171239462Sdim                                        bool WasInlined) {
172263508Sdim  CheckStmtContext C(isPreVisit, getCachedStmtCheckersFor(S, isPreVisit),
173239462Sdim                     S, Eng, WasInlined);
174219077Sdim  expandGraphWithCheckers(C, Dst, Src);
175219077Sdim}
176219077Sdim
177219077Sdimnamespace {
178219077Sdim  struct CheckObjCMessageContext {
179219077Sdim    typedef std::vector<CheckerManager::CheckObjCMessageFunc> CheckersTy;
180239462Sdim    bool IsPreVisit, WasInlined;
181219077Sdim    const CheckersTy &Checkers;
182239462Sdim    const ObjCMethodCall &Msg;
183219077Sdim    ExprEngine &Eng;
184219077Sdim
185219077Sdim    CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
186219077Sdim    CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
187219077Sdim
188219077Sdim    CheckObjCMessageContext(bool isPreVisit, const CheckersTy &checkers,
189239462Sdim                            const ObjCMethodCall &msg, ExprEngine &eng,
190239462Sdim                            bool wasInlined)
191239462Sdim      : IsPreVisit(isPreVisit), WasInlined(wasInlined), Checkers(checkers),
192239462Sdim        Msg(msg), Eng(eng) { }
193219077Sdim
194219077Sdim    void runChecker(CheckerManager::CheckObjCMessageFunc checkFn,
195234353Sdim                    NodeBuilder &Bldr, ExplodedNode *Pred) {
196239462Sdim      const ProgramPoint &L = Msg.getProgramPoint(IsPreVisit,checkFn.Checker);
197239462Sdim      CheckerContext C(Bldr, Eng, Pred, L, WasInlined);
198226633Sdim
199239462Sdim      checkFn(*Msg.cloneWithState<ObjCMethodCall>(Pred->getState()), C);
200219077Sdim    }
201219077Sdim  };
202219077Sdim}
203219077Sdim
204219077Sdim/// \brief Run checkers for visiting obj-c messages.
205219077Sdimvoid CheckerManager::runCheckersForObjCMessage(bool isPreVisit,
206219077Sdim                                               ExplodedNodeSet &Dst,
207219077Sdim                                               const ExplodedNodeSet &Src,
208239462Sdim                                               const ObjCMethodCall &msg,
209239462Sdim                                               ExprEngine &Eng,
210239462Sdim                                               bool WasInlined) {
211219077Sdim  CheckObjCMessageContext C(isPreVisit,
212219077Sdim                            isPreVisit ? PreObjCMessageCheckers
213219077Sdim                                       : PostObjCMessageCheckers,
214239462Sdim                            msg, Eng, WasInlined);
215219077Sdim  expandGraphWithCheckers(C, Dst, Src);
216219077Sdim}
217219077Sdim
218219077Sdimnamespace {
219239462Sdim  // FIXME: This has all the same signatures as CheckObjCMessageContext.
220239462Sdim  // Is there a way we can merge the two?
221239462Sdim  struct CheckCallContext {
222239462Sdim    typedef std::vector<CheckerManager::CheckCallFunc> CheckersTy;
223239462Sdim    bool IsPreVisit, WasInlined;
224239462Sdim    const CheckersTy &Checkers;
225239462Sdim    const CallEvent &Call;
226239462Sdim    ExprEngine &Eng;
227239462Sdim
228239462Sdim    CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
229239462Sdim    CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
230239462Sdim
231239462Sdim    CheckCallContext(bool isPreVisit, const CheckersTy &checkers,
232239462Sdim                     const CallEvent &call, ExprEngine &eng,
233239462Sdim                     bool wasInlined)
234239462Sdim    : IsPreVisit(isPreVisit), WasInlined(wasInlined), Checkers(checkers),
235239462Sdim      Call(call), Eng(eng) { }
236239462Sdim
237239462Sdim    void runChecker(CheckerManager::CheckCallFunc checkFn,
238239462Sdim                    NodeBuilder &Bldr, ExplodedNode *Pred) {
239239462Sdim      const ProgramPoint &L = Call.getProgramPoint(IsPreVisit,checkFn.Checker);
240239462Sdim      CheckerContext C(Bldr, Eng, Pred, L, WasInlined);
241239462Sdim
242239462Sdim      checkFn(*Call.cloneWithState(Pred->getState()), C);
243239462Sdim    }
244239462Sdim  };
245239462Sdim}
246239462Sdim
247239462Sdim/// \brief Run checkers for visiting an abstract call event.
248239462Sdimvoid CheckerManager::runCheckersForCallEvent(bool isPreVisit,
249239462Sdim                                             ExplodedNodeSet &Dst,
250239462Sdim                                             const ExplodedNodeSet &Src,
251239462Sdim                                             const CallEvent &Call,
252239462Sdim                                             ExprEngine &Eng,
253239462Sdim                                             bool WasInlined) {
254239462Sdim  CheckCallContext C(isPreVisit,
255239462Sdim                     isPreVisit ? PreCallCheckers
256239462Sdim                                : PostCallCheckers,
257239462Sdim                     Call, Eng, WasInlined);
258239462Sdim  expandGraphWithCheckers(C, Dst, Src);
259239462Sdim}
260239462Sdim
261239462Sdimnamespace {
262219077Sdim  struct CheckLocationContext {
263219077Sdim    typedef std::vector<CheckerManager::CheckLocationFunc> CheckersTy;
264219077Sdim    const CheckersTy &Checkers;
265219077Sdim    SVal Loc;
266219077Sdim    bool IsLoad;
267234353Sdim    const Stmt *NodeEx; /* Will become a CFGStmt */
268234353Sdim    const Stmt *BoundEx;
269219077Sdim    ExprEngine &Eng;
270219077Sdim
271219077Sdim    CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
272219077Sdim    CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
273219077Sdim
274219077Sdim    CheckLocationContext(const CheckersTy &checkers,
275234353Sdim                         SVal loc, bool isLoad, const Stmt *NodeEx,
276234353Sdim                         const Stmt *BoundEx,
277234353Sdim                         ExprEngine &eng)
278234353Sdim      : Checkers(checkers), Loc(loc), IsLoad(isLoad), NodeEx(NodeEx),
279234353Sdim        BoundEx(BoundEx), Eng(eng) {}
280219077Sdim
281219077Sdim    void runChecker(CheckerManager::CheckLocationFunc checkFn,
282234353Sdim                    NodeBuilder &Bldr, ExplodedNode *Pred) {
283226633Sdim      ProgramPoint::Kind K =  IsLoad ? ProgramPoint::PreLoadKind :
284226633Sdim                                       ProgramPoint::PreStoreKind;
285234353Sdim      const ProgramPoint &L =
286234353Sdim        ProgramPoint::getProgramPoint(NodeEx, K,
287234353Sdim                                      Pred->getLocationContext(),
288234353Sdim                                      checkFn.Checker);
289234353Sdim      CheckerContext C(Bldr, Eng, Pred, L);
290234353Sdim      checkFn(Loc, IsLoad, BoundEx, C);
291219077Sdim    }
292219077Sdim  };
293219077Sdim}
294219077Sdim
295219077Sdim/// \brief Run checkers for load/store of a location.
296234353Sdim
297219077Sdimvoid CheckerManager::runCheckersForLocation(ExplodedNodeSet &Dst,
298219077Sdim                                            const ExplodedNodeSet &Src,
299219077Sdim                                            SVal location, bool isLoad,
300234353Sdim                                            const Stmt *NodeEx,
301234353Sdim                                            const Stmt *BoundEx,
302234353Sdim                                            ExprEngine &Eng) {
303234353Sdim  CheckLocationContext C(LocationCheckers, location, isLoad, NodeEx,
304234353Sdim                         BoundEx, Eng);
305219077Sdim  expandGraphWithCheckers(C, Dst, Src);
306219077Sdim}
307219077Sdim
308221345Sdimnamespace {
309221345Sdim  struct CheckBindContext {
310221345Sdim    typedef std::vector<CheckerManager::CheckBindFunc> CheckersTy;
311221345Sdim    const CheckersTy &Checkers;
312221345Sdim    SVal Loc;
313221345Sdim    SVal Val;
314221345Sdim    const Stmt *S;
315221345Sdim    ExprEngine &Eng;
316243830Sdim    const ProgramPoint &PP;
317221345Sdim
318221345Sdim    CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
319221345Sdim    CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
320221345Sdim
321221345Sdim    CheckBindContext(const CheckersTy &checkers,
322234353Sdim                     SVal loc, SVal val, const Stmt *s, ExprEngine &eng,
323243830Sdim                     const ProgramPoint &pp)
324243830Sdim      : Checkers(checkers), Loc(loc), Val(val), S(s), Eng(eng), PP(pp) {}
325221345Sdim
326221345Sdim    void runChecker(CheckerManager::CheckBindFunc checkFn,
327234353Sdim                    NodeBuilder &Bldr, ExplodedNode *Pred) {
328243830Sdim      const ProgramPoint &L = PP.withTag(checkFn.Checker);
329234353Sdim      CheckerContext C(Bldr, Eng, Pred, L);
330226633Sdim
331226633Sdim      checkFn(Loc, Val, S, C);
332221345Sdim    }
333221345Sdim  };
334221345Sdim}
335221345Sdim
336221345Sdim/// \brief Run checkers for binding of a value to a location.
337221345Sdimvoid CheckerManager::runCheckersForBind(ExplodedNodeSet &Dst,
338221345Sdim                                        const ExplodedNodeSet &Src,
339221345Sdim                                        SVal location, SVal val,
340234353Sdim                                        const Stmt *S, ExprEngine &Eng,
341243830Sdim                                        const ProgramPoint &PP) {
342243830Sdim  CheckBindContext C(BindCheckers, location, val, S, Eng, PP);
343221345Sdim  expandGraphWithCheckers(C, Dst, Src);
344221345Sdim}
345221345Sdim
346219077Sdimvoid CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G,
347219077Sdim                                               BugReporter &BR,
348219077Sdim                                               ExprEngine &Eng) {
349219077Sdim  for (unsigned i = 0, e = EndAnalysisCheckers.size(); i != e; ++i)
350219077Sdim    EndAnalysisCheckers[i](G, BR, Eng);
351219077Sdim}
352219077Sdim
353219077Sdim/// \brief Run checkers for end of path.
354234353Sdim// Note, We do not chain the checker output (like in expandGraphWithCheckers)
355234353Sdim// for this callback since end of path nodes are expected to be final.
356249423Sdimvoid CheckerManager::runCheckersForEndFunction(NodeBuilderContext &BC,
357249423Sdim                                               ExplodedNodeSet &Dst,
358249423Sdim                                               ExplodedNode *Pred,
359249423Sdim                                               ExprEngine &Eng) {
360234353Sdim
361234353Sdim  // We define the builder outside of the loop bacause if at least one checkers
362234353Sdim  // creates a sucsessor for Pred, we do not need to generate an
363234353Sdim  // autotransition for it.
364234353Sdim  NodeBuilder Bldr(Pred, Dst, BC);
365249423Sdim  for (unsigned i = 0, e = EndFunctionCheckers.size(); i != e; ++i) {
366249423Sdim    CheckEndFunctionFunc checkFn = EndFunctionCheckers[i];
367234353Sdim
368234353Sdim    const ProgramPoint &L = BlockEntrance(BC.Block,
369234353Sdim                                          Pred->getLocationContext(),
370234353Sdim                                          checkFn.Checker);
371234353Sdim    CheckerContext C(Bldr, Eng, Pred, L);
372234353Sdim    checkFn(C);
373219077Sdim  }
374219077Sdim}
375219077Sdim
376234353Sdimnamespace {
377234353Sdim  struct CheckBranchConditionContext {
378234353Sdim    typedef std::vector<CheckerManager::CheckBranchConditionFunc> CheckersTy;
379234353Sdim    const CheckersTy &Checkers;
380234353Sdim    const Stmt *Condition;
381234353Sdim    ExprEngine &Eng;
382234353Sdim
383234353Sdim    CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
384234353Sdim    CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
385234353Sdim
386234353Sdim    CheckBranchConditionContext(const CheckersTy &checkers,
387234353Sdim                                const Stmt *Cond, ExprEngine &eng)
388234353Sdim      : Checkers(checkers), Condition(Cond), Eng(eng) {}
389234353Sdim
390234353Sdim    void runChecker(CheckerManager::CheckBranchConditionFunc checkFn,
391234353Sdim                    NodeBuilder &Bldr, ExplodedNode *Pred) {
392234353Sdim      ProgramPoint L = PostCondition(Condition, Pred->getLocationContext(),
393234353Sdim                                     checkFn.Checker);
394234353Sdim      CheckerContext C(Bldr, Eng, Pred, L);
395234353Sdim      checkFn(Condition, C);
396234353Sdim    }
397234353Sdim  };
398234353Sdim}
399234353Sdim
400221345Sdim/// \brief Run checkers for branch condition.
401234353Sdimvoid CheckerManager::runCheckersForBranchCondition(const Stmt *Condition,
402234353Sdim                                                   ExplodedNodeSet &Dst,
403234353Sdim                                                   ExplodedNode *Pred,
404221345Sdim                                                   ExprEngine &Eng) {
405234353Sdim  ExplodedNodeSet Src;
406234353Sdim  Src.insert(Pred);
407234353Sdim  CheckBranchConditionContext C(BranchConditionCheckers, Condition, Eng);
408234353Sdim  expandGraphWithCheckers(C, Dst, Src);
409221345Sdim}
410221345Sdim
411219077Sdim/// \brief Run checkers for live symbols.
412234353Sdimvoid CheckerManager::runCheckersForLiveSymbols(ProgramStateRef state,
413219077Sdim                                               SymbolReaper &SymReaper) {
414219077Sdim  for (unsigned i = 0, e = LiveSymbolsCheckers.size(); i != e; ++i)
415219077Sdim    LiveSymbolsCheckers[i](state, SymReaper);
416219077Sdim}
417219077Sdim
418219077Sdimnamespace {
419219077Sdim  struct CheckDeadSymbolsContext {
420219077Sdim    typedef std::vector<CheckerManager::CheckDeadSymbolsFunc> CheckersTy;
421219077Sdim    const CheckersTy &Checkers;
422219077Sdim    SymbolReaper &SR;
423219077Sdim    const Stmt *S;
424219077Sdim    ExprEngine &Eng;
425239462Sdim    ProgramPoint::Kind ProgarmPointKind;
426219077Sdim
427219077Sdim    CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
428219077Sdim    CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
429219077Sdim
430219077Sdim    CheckDeadSymbolsContext(const CheckersTy &checkers, SymbolReaper &sr,
431239462Sdim                            const Stmt *s, ExprEngine &eng,
432239462Sdim                            ProgramPoint::Kind K)
433239462Sdim      : Checkers(checkers), SR(sr), S(s), Eng(eng), ProgarmPointKind(K) { }
434219077Sdim
435219077Sdim    void runChecker(CheckerManager::CheckDeadSymbolsFunc checkFn,
436234353Sdim                    NodeBuilder &Bldr, ExplodedNode *Pred) {
437239462Sdim      const ProgramPoint &L = ProgramPoint::getProgramPoint(S, ProgarmPointKind,
438226633Sdim                                Pred->getLocationContext(), checkFn.Checker);
439234353Sdim      CheckerContext C(Bldr, Eng, Pred, L);
440226633Sdim
441239462Sdim      // Note, do not pass the statement to the checkers without letting them
442239462Sdim      // differentiate if we ran remove dead bindings before or after the
443239462Sdim      // statement.
444219077Sdim      checkFn(SR, C);
445219077Sdim    }
446219077Sdim  };
447219077Sdim}
448219077Sdim
449219077Sdim/// \brief Run checkers for dead symbols.
450219077Sdimvoid CheckerManager::runCheckersForDeadSymbols(ExplodedNodeSet &Dst,
451219077Sdim                                               const ExplodedNodeSet &Src,
452219077Sdim                                               SymbolReaper &SymReaper,
453219077Sdim                                               const Stmt *S,
454239462Sdim                                               ExprEngine &Eng,
455239462Sdim                                               ProgramPoint::Kind K) {
456239462Sdim  CheckDeadSymbolsContext C(DeadSymbolsCheckers, SymReaper, S, Eng, K);
457219077Sdim  expandGraphWithCheckers(C, Dst, Src);
458219077Sdim}
459219077Sdim
460219077Sdim/// \brief True if at least one checker wants to check region changes.
461234353Sdimbool CheckerManager::wantsRegionChangeUpdate(ProgramStateRef state) {
462219077Sdim  for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i)
463219077Sdim    if (RegionChangesCheckers[i].WantUpdateFn(state))
464219077Sdim      return true;
465219077Sdim
466219077Sdim  return false;
467219077Sdim}
468219077Sdim
469219077Sdim/// \brief Run checkers for region changes.
470234353SdimProgramStateRef
471234353SdimCheckerManager::runCheckersForRegionChanges(ProgramStateRef state,
472249423Sdim                                    const InvalidatedSymbols *invalidated,
473226633Sdim                                    ArrayRef<const MemRegion *> ExplicitRegions,
474249423Sdim                                    ArrayRef<const MemRegion *> Regions,
475249423Sdim                                    const CallEvent *Call) {
476219077Sdim  for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i) {
477219077Sdim    // If any checker declares the state infeasible (or if it starts that way),
478219077Sdim    // bail out.
479219077Sdim    if (!state)
480219077Sdim      return NULL;
481226633Sdim    state = RegionChangesCheckers[i].CheckFn(state, invalidated,
482234353Sdim                                             ExplicitRegions, Regions, Call);
483219077Sdim  }
484219077Sdim  return state;
485219077Sdim}
486219077Sdim
487249423Sdim/// \brief Run checkers to process symbol escape event.
488249423SdimProgramStateRef
489249423SdimCheckerManager::runCheckersForPointerEscape(ProgramStateRef State,
490263508Sdim                                   const InvalidatedSymbols &Escaped,
491263508Sdim                                   const CallEvent *Call,
492263508Sdim                                   PointerEscapeKind Kind,
493263508Sdim                                   RegionAndSymbolInvalidationTraits *ETraits) {
494249423Sdim  assert((Call != NULL ||
495249423Sdim          (Kind != PSK_DirectEscapeOnCall &&
496249423Sdim           Kind != PSK_IndirectEscapeOnCall)) &&
497249423Sdim         "Call must not be NULL when escaping on call");
498249423Sdim    for (unsigned i = 0, e = PointerEscapeCheckers.size(); i != e; ++i) {
499249423Sdim      // If any checker declares the state infeasible (or if it starts that
500249423Sdim      //  way), bail out.
501249423Sdim      if (!State)
502249423Sdim        return NULL;
503263508Sdim      State = PointerEscapeCheckers[i](State, Escaped, Call, Kind, ETraits);
504249423Sdim    }
505249423Sdim  return State;
506249423Sdim}
507249423Sdim
508221345Sdim/// \brief Run checkers for handling assumptions on symbolic values.
509234353SdimProgramStateRef
510234353SdimCheckerManager::runCheckersForEvalAssume(ProgramStateRef state,
511221345Sdim                                         SVal Cond, bool Assumption) {
512221345Sdim  for (unsigned i = 0, e = EvalAssumeCheckers.size(); i != e; ++i) {
513221345Sdim    // If any checker declares the state infeasible (or if it starts that way),
514221345Sdim    // bail out.
515221345Sdim    if (!state)
516221345Sdim      return NULL;
517221345Sdim    state = EvalAssumeCheckers[i](state, Cond, Assumption);
518221345Sdim  }
519221345Sdim  return state;
520221345Sdim}
521221345Sdim
522219077Sdim/// \brief Run checkers for evaluating a call.
523219077Sdim/// Only one checker will evaluate the call.
524219077Sdimvoid CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
525219077Sdim                                            const ExplodedNodeSet &Src,
526239462Sdim                                            const CallEvent &Call,
527239462Sdim                                            ExprEngine &Eng) {
528239462Sdim  const CallExpr *CE = cast<CallExpr>(Call.getOriginExpr());
529219077Sdim  for (ExplodedNodeSet::iterator
530219077Sdim         NI = Src.begin(), NE = Src.end(); NI != NE; ++NI) {
531219077Sdim    ExplodedNode *Pred = *NI;
532219077Sdim    bool anyEvaluated = false;
533226633Sdim
534234353Sdim    ExplodedNodeSet checkDst;
535234353Sdim    NodeBuilder B(Pred, checkDst, Eng.getBuilderContext());
536243830Sdim
537243830Sdim    // Check if any of the EvalCall callbacks can evaluate the call.
538219077Sdim    for (std::vector<EvalCallFunc>::iterator
539219077Sdim           EI = EvalCallCheckers.begin(), EE = EvalCallCheckers.end();
540219077Sdim         EI != EE; ++EI) {
541226633Sdim      ProgramPoint::Kind K = ProgramPoint::PostStmtKind;
542226633Sdim      const ProgramPoint &L = ProgramPoint::getProgramPoint(CE, K,
543226633Sdim                                Pred->getLocationContext(), EI->Checker);
544226633Sdim      bool evaluated = false;
545226633Sdim      { // CheckerContext generates transitions(populates checkDest) on
546226633Sdim        // destruction, so introduce the scope to make sure it gets properly
547226633Sdim        // populated.
548234353Sdim        CheckerContext C(B, Eng, Pred, L);
549226633Sdim        evaluated = (*EI)(CE, C);
550226633Sdim      }
551219077Sdim      assert(!(evaluated && anyEvaluated)
552219077Sdim             && "There are more than one checkers evaluating the call");
553219077Sdim      if (evaluated) {
554219077Sdim        anyEvaluated = true;
555219077Sdim        Dst.insert(checkDst);
556219077Sdim#ifdef NDEBUG
557219077Sdim        break; // on release don't check that no other checker also evals.
558219077Sdim#endif
559219077Sdim      }
560219077Sdim    }
561219077Sdim
562226633Sdim    // If none of the checkers evaluated the call, ask ExprEngine to handle it.
563219077Sdim    if (!anyEvaluated) {
564239462Sdim      NodeBuilder B(Pred, Dst, Eng.getBuilderContext());
565239462Sdim      Eng.defaultEvalCall(B, Pred, Call);
566219077Sdim    }
567219077Sdim  }
568219077Sdim}
569219077Sdim
570223017Sdim/// \brief Run checkers for the entire Translation Unit.
571223017Sdimvoid CheckerManager::runCheckersOnEndOfTranslationUnit(
572223017Sdim                                                  const TranslationUnitDecl *TU,
573223017Sdim                                                  AnalysisManager &mgr,
574223017Sdim                                                  BugReporter &BR) {
575223017Sdim  for (unsigned i = 0, e = EndOfTranslationUnitCheckers.size(); i != e; ++i)
576223017Sdim    EndOfTranslationUnitCheckers[i](TU, mgr, BR);
577223017Sdim}
578223017Sdim
579226633Sdimvoid CheckerManager::runCheckersForPrintState(raw_ostream &Out,
580234353Sdim                                              ProgramStateRef State,
581226633Sdim                                              const char *NL, const char *Sep) {
582226633Sdim  for (llvm::DenseMap<CheckerTag, CheckerRef>::iterator
583226633Sdim        I = CheckerTags.begin(), E = CheckerTags.end(); I != E; ++I)
584226633Sdim    I->second->printState(Out, State, NL, Sep);
585226633Sdim}
586226633Sdim
587219077Sdim//===----------------------------------------------------------------------===//
588219077Sdim// Internal registration functions for AST traversing.
589219077Sdim//===----------------------------------------------------------------------===//
590219077Sdim
591219077Sdimvoid CheckerManager::_registerForDecl(CheckDeclFunc checkfn,
592218887Sdim                                      HandlesDeclFunc isForDeclFn) {
593219077Sdim  DeclCheckerInfo info = { checkfn, isForDeclFn };
594218887Sdim  DeclCheckers.push_back(info);
595218887Sdim}
596218887Sdim
597219077Sdimvoid CheckerManager::_registerForBody(CheckDeclFunc checkfn) {
598219077Sdim  BodyCheckers.push_back(checkfn);
599218887Sdim}
600218887Sdim
601219077Sdim//===----------------------------------------------------------------------===//
602219077Sdim// Internal registration functions for path-sensitive checking.
603219077Sdim//===----------------------------------------------------------------------===//
604219077Sdim
605219077Sdimvoid CheckerManager::_registerForPreStmt(CheckStmtFunc checkfn,
606219077Sdim                                         HandlesStmtFunc isForStmtFn) {
607219077Sdim  StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/true };
608219077Sdim  StmtCheckers.push_back(info);
609218887Sdim}
610219077Sdimvoid CheckerManager::_registerForPostStmt(CheckStmtFunc checkfn,
611219077Sdim                                          HandlesStmtFunc isForStmtFn) {
612219077Sdim  StmtCheckerInfo info = { checkfn, isForStmtFn, /*IsPreVisit*/false };
613219077Sdim  StmtCheckers.push_back(info);
614219077Sdim}
615218887Sdim
616219077Sdimvoid CheckerManager::_registerForPreObjCMessage(CheckObjCMessageFunc checkfn) {
617219077Sdim  PreObjCMessageCheckers.push_back(checkfn);
618219077Sdim}
619219077Sdimvoid CheckerManager::_registerForPostObjCMessage(CheckObjCMessageFunc checkfn) {
620219077Sdim  PostObjCMessageCheckers.push_back(checkfn);
621219077Sdim}
622219077Sdim
623239462Sdimvoid CheckerManager::_registerForPreCall(CheckCallFunc checkfn) {
624239462Sdim  PreCallCheckers.push_back(checkfn);
625239462Sdim}
626239462Sdimvoid CheckerManager::_registerForPostCall(CheckCallFunc checkfn) {
627239462Sdim  PostCallCheckers.push_back(checkfn);
628239462Sdim}
629239462Sdim
630219077Sdimvoid CheckerManager::_registerForLocation(CheckLocationFunc checkfn) {
631219077Sdim  LocationCheckers.push_back(checkfn);
632219077Sdim}
633219077Sdim
634221345Sdimvoid CheckerManager::_registerForBind(CheckBindFunc checkfn) {
635221345Sdim  BindCheckers.push_back(checkfn);
636221345Sdim}
637221345Sdim
638219077Sdimvoid CheckerManager::_registerForEndAnalysis(CheckEndAnalysisFunc checkfn) {
639219077Sdim  EndAnalysisCheckers.push_back(checkfn);
640219077Sdim}
641219077Sdim
642249423Sdimvoid CheckerManager::_registerForEndFunction(CheckEndFunctionFunc checkfn) {
643249423Sdim  EndFunctionCheckers.push_back(checkfn);
644219077Sdim}
645219077Sdim
646221345Sdimvoid CheckerManager::_registerForBranchCondition(
647221345Sdim                                             CheckBranchConditionFunc checkfn) {
648221345Sdim  BranchConditionCheckers.push_back(checkfn);
649221345Sdim}
650221345Sdim
651219077Sdimvoid CheckerManager::_registerForLiveSymbols(CheckLiveSymbolsFunc checkfn) {
652219077Sdim  LiveSymbolsCheckers.push_back(checkfn);
653219077Sdim}
654219077Sdim
655219077Sdimvoid CheckerManager::_registerForDeadSymbols(CheckDeadSymbolsFunc checkfn) {
656219077Sdim  DeadSymbolsCheckers.push_back(checkfn);
657219077Sdim}
658219077Sdim
659219077Sdimvoid CheckerManager::_registerForRegionChanges(CheckRegionChangesFunc checkfn,
660219077Sdim                                     WantsRegionChangeUpdateFunc wantUpdateFn) {
661219077Sdim  RegionChangesCheckerInfo info = {checkfn, wantUpdateFn};
662219077Sdim  RegionChangesCheckers.push_back(info);
663219077Sdim}
664219077Sdim
665249423Sdimvoid CheckerManager::_registerForPointerEscape(CheckPointerEscapeFunc checkfn){
666249423Sdim  PointerEscapeCheckers.push_back(checkfn);
667249423Sdim}
668249423Sdim
669249423Sdimvoid CheckerManager::_registerForConstPointerEscape(
670249423Sdim                                          CheckPointerEscapeFunc checkfn) {
671249423Sdim  PointerEscapeCheckers.push_back(checkfn);
672249423Sdim}
673249423Sdim
674221345Sdimvoid CheckerManager::_registerForEvalAssume(EvalAssumeFunc checkfn) {
675221345Sdim  EvalAssumeCheckers.push_back(checkfn);
676221345Sdim}
677221345Sdim
678219077Sdimvoid CheckerManager::_registerForEvalCall(EvalCallFunc checkfn) {
679219077Sdim  EvalCallCheckers.push_back(checkfn);
680219077Sdim}
681219077Sdim
682223017Sdimvoid CheckerManager::_registerForEndOfTranslationUnit(
683223017Sdim                                            CheckEndOfTranslationUnit checkfn) {
684223017Sdim  EndOfTranslationUnitCheckers.push_back(checkfn);
685223017Sdim}
686223017Sdim
687219077Sdim//===----------------------------------------------------------------------===//
688219077Sdim// Implementation details.
689219077Sdim//===----------------------------------------------------------------------===//
690219077Sdim
691263508Sdimconst CheckerManager::CachedStmtCheckers &
692219077SdimCheckerManager::getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit) {
693219077Sdim  assert(S);
694219077Sdim
695263508Sdim  unsigned Key = (S->getStmtClass() << 1) | unsigned(isPreVisit);
696263508Sdim  CachedStmtCheckersMapTy::iterator CCI = CachedStmtCheckersMap.find(Key);
697263508Sdim  if (CCI != CachedStmtCheckersMap.end())
698263508Sdim    return CCI->second;
699263508Sdim
700263508Sdim  // Find the checkers that should run for this Stmt and cache them.
701263508Sdim  CachedStmtCheckers &Checkers = CachedStmtCheckersMap[Key];
702263508Sdim  for (unsigned i = 0, e = StmtCheckers.size(); i != e; ++i) {
703263508Sdim    StmtCheckerInfo &Info = StmtCheckers[i];
704263508Sdim    if (Info.IsPreVisit == isPreVisit && Info.IsForStmtFn(S))
705263508Sdim      Checkers.push_back(Info.CheckFn);
706218887Sdim  }
707263508Sdim  return Checkers;
708218887Sdim}
709218887Sdim
710219077SdimCheckerManager::~CheckerManager() {
711219077Sdim  for (unsigned i = 0, e = CheckerDtors.size(); i != e; ++i)
712219077Sdim    CheckerDtors[i]();
713219077Sdim}
714