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