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