CheckerManager.h revision 96479da6ad9d921d875e7be29fe1bfa127be8069
1//===--- CheckerManager.h - Static Analyzer Checker Manager -----*- C++ -*-===// 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#ifndef LLVM_CLANG_SA_CORE_CHECKERMANAGER_H 15#define LLVM_CLANG_SA_CORE_CHECKERMANAGER_H 16 17#include "clang/Basic/LangOptions.h" 18#include "llvm/ADT/SmallVector.h" 19#include "llvm/ADT/DenseMap.h" 20#include "llvm/ADT/FoldingSet.h" 21#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" 22#include "clang/Analysis/ProgramPoint.h" 23#include <vector> 24 25namespace clang { 26 class Decl; 27 class Stmt; 28 class CallExpr; 29 30namespace ento { 31 class CheckerBase; 32 class ExprEngine; 33 class AnalysisManager; 34 class BugReporter; 35 class CheckerContext; 36 class SimpleCall; 37 class ObjCMethodCall; 38 class SVal; 39 class ExplodedNode; 40 class ExplodedNodeSet; 41 class ExplodedGraph; 42 class ProgramState; 43 class NodeBuilder; 44 struct NodeBuilderContext; 45 class MemRegion; 46 class SymbolReaper; 47 48template <typename T> class CheckerFn; 49 50template <typename RET, typename P1, typename P2, typename P3, typename P4, 51 typename P5> 52class CheckerFn<RET(P1, P2, P3, P4, P5)> { 53 typedef RET (*Func)(void *, P1, P2, P3, P4, P5); 54 Func Fn; 55public: 56 CheckerBase *Checker; 57 CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { } 58 RET operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) const { 59 return Fn(Checker, p1, p2, p3, p4, p5); 60 } 61}; 62 63template <typename RET, typename P1, typename P2, typename P3, typename P4> 64class CheckerFn<RET(P1, P2, P3, P4)> { 65 typedef RET (*Func)(void *, P1, P2, P3, P4); 66 Func Fn; 67public: 68 CheckerBase *Checker; 69 CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { } 70 RET operator()(P1 p1, P2 p2, P3 p3, P4 p4) const { 71 return Fn(Checker, p1, p2, p3, p4); 72 } 73}; 74 75template <typename RET, typename P1, typename P2, typename P3> 76class CheckerFn<RET(P1, P2, P3)> { 77 typedef RET (*Func)(void *, P1, P2, P3); 78 Func Fn; 79public: 80 CheckerBase *Checker; 81 CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { } 82 RET operator()(P1 p1, P2 p2, P3 p3) const { return Fn(Checker, p1, p2, p3); } 83}; 84 85template <typename RET, typename P1, typename P2> 86class CheckerFn<RET(P1, P2)> { 87 typedef RET (*Func)(void *, P1, P2); 88 Func Fn; 89public: 90 CheckerBase *Checker; 91 CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { } 92 RET operator()(P1 p1, P2 p2) const { return Fn(Checker, p1, p2); } 93}; 94 95template <typename RET, typename P1> 96class CheckerFn<RET(P1)> { 97 typedef RET (*Func)(void *, P1); 98 Func Fn; 99public: 100 CheckerBase *Checker; 101 CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { } 102 RET operator()(P1 p1) const { return Fn(Checker, p1); } 103}; 104 105template <typename RET> 106class CheckerFn<RET()> { 107 typedef RET (*Func)(void *); 108 Func Fn; 109public: 110 CheckerBase *Checker; 111 CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { } 112 RET operator()() const { return Fn(Checker); } 113}; 114 115class CheckerManager { 116 const LangOptions LangOpts; 117 118public: 119 CheckerManager(const LangOptions &langOpts) : LangOpts(langOpts) { } 120 ~CheckerManager(); 121 122 bool hasPathSensitiveCheckers() const; 123 124 void finishedCheckerRegistration(); 125 126 const LangOptions &getLangOpts() const { return LangOpts; } 127 128 typedef CheckerBase *CheckerRef; 129 typedef const void *CheckerTag; 130 typedef CheckerFn<void ()> CheckerDtor; 131 132//===----------------------------------------------------------------------===// 133// registerChecker 134//===----------------------------------------------------------------------===// 135 136 /// \brief Used to register checkers. 137 /// 138 /// \returns a pointer to the checker object. 139 template <typename CHECKER> 140 CHECKER *registerChecker() { 141 CheckerTag tag = getTag<CHECKER>(); 142 CheckerRef &ref = CheckerTags[tag]; 143 if (ref) 144 return static_cast<CHECKER *>(ref); // already registered. 145 146 CHECKER *checker = new CHECKER(); 147 CheckerDtors.push_back(CheckerDtor(checker, destruct<CHECKER>)); 148 CHECKER::_register(checker, *this); 149 ref = checker; 150 return checker; 151 } 152 153//===----------------------------------------------------------------------===// 154// Functions for running checkers for AST traversing.. 155//===----------------------------------------------------------------------===// 156 157 /// \brief Run checkers handling Decls. 158 void runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr, 159 BugReporter &BR); 160 161 /// \brief Run checkers handling Decls containing a Stmt body. 162 void runCheckersOnASTBody(const Decl *D, AnalysisManager& mgr, 163 BugReporter &BR); 164 165//===----------------------------------------------------------------------===// 166// Functions for running checkers for path-sensitive checking. 167//===----------------------------------------------------------------------===// 168 169 /// \brief Run checkers for pre-visiting Stmts. 170 /// 171 /// The notification is performed for every explored CFGElement, which does 172 /// not include the control flow statements such as IfStmt. 173 /// 174 /// \sa runCheckersForBranchCondition, runCheckersForPostStmt 175 void runCheckersForPreStmt(ExplodedNodeSet &Dst, 176 const ExplodedNodeSet &Src, 177 const Stmt *S, 178 ExprEngine &Eng) { 179 runCheckersForStmt(/*isPreVisit=*/true, Dst, Src, S, Eng); 180 } 181 182 /// \brief Run checkers for post-visiting Stmts. 183 /// 184 /// The notification is performed for every explored CFGElement, which does 185 /// not include the control flow statements such as IfStmt. 186 /// 187 /// \sa runCheckersForBranchCondition, runCheckersForPreStmt 188 void runCheckersForPostStmt(ExplodedNodeSet &Dst, 189 const ExplodedNodeSet &Src, 190 const Stmt *S, 191 ExprEngine &Eng, 192 bool wasInlined = false) { 193 runCheckersForStmt(/*isPreVisit=*/false, Dst, Src, S, Eng, wasInlined); 194 } 195 196 /// \brief Run checkers for visiting Stmts. 197 void runCheckersForStmt(bool isPreVisit, 198 ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, 199 const Stmt *S, ExprEngine &Eng, 200 bool wasInlined = false); 201 202 /// \brief Run checkers for pre-visiting obj-c messages. 203 void runCheckersForPreObjCMessage(ExplodedNodeSet &Dst, 204 const ExplodedNodeSet &Src, 205 const ObjCMethodCall &msg, 206 ExprEngine &Eng) { 207 runCheckersForObjCMessage(/*isPreVisit=*/true, Dst, Src, msg, Eng); 208 } 209 210 /// \brief Run checkers for post-visiting obj-c messages. 211 void runCheckersForPostObjCMessage(ExplodedNodeSet &Dst, 212 const ExplodedNodeSet &Src, 213 const ObjCMethodCall &msg, 214 ExprEngine &Eng) { 215 runCheckersForObjCMessage(/*isPreVisit=*/false, Dst, Src, msg, Eng); 216 } 217 218 /// \brief Run checkers for visiting obj-c messages. 219 void runCheckersForObjCMessage(bool isPreVisit, 220 ExplodedNodeSet &Dst, 221 const ExplodedNodeSet &Src, 222 const ObjCMethodCall &msg, ExprEngine &Eng); 223 224 /// \brief Run checkers for pre-visiting obj-c messages. 225 void runCheckersForPreCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, 226 const CallEvent &Call, ExprEngine &Eng) { 227 runCheckersForCallEvent(/*isPreVisit=*/true, Dst, Src, Call, Eng); 228 } 229 230 /// \brief Run checkers for post-visiting obj-c messages. 231 void runCheckersForPostCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, 232 const CallEvent &Call, ExprEngine &Eng) { 233 runCheckersForCallEvent(/*isPreVisit=*/false, Dst, Src, Call, Eng); 234 } 235 236 /// \brief Run checkers for visiting obj-c messages. 237 void runCheckersForCallEvent(bool isPreVisit, ExplodedNodeSet &Dst, 238 const ExplodedNodeSet &Src, 239 const CallEvent &Call, ExprEngine &Eng); 240 241 /// \brief Run checkers for load/store of a location. 242 void runCheckersForLocation(ExplodedNodeSet &Dst, 243 const ExplodedNodeSet &Src, 244 SVal location, 245 bool isLoad, 246 const Stmt *NodeEx, 247 const Stmt *BoundEx, 248 ExprEngine &Eng); 249 250 /// \brief Run checkers for binding of a value to a location. 251 void runCheckersForBind(ExplodedNodeSet &Dst, 252 const ExplodedNodeSet &Src, 253 SVal location, SVal val, 254 const Stmt *S, ExprEngine &Eng, 255 ProgramPoint::Kind PointKind); 256 257 /// \brief Run checkers for end of analysis. 258 void runCheckersForEndAnalysis(ExplodedGraph &G, BugReporter &BR, 259 ExprEngine &Eng); 260 261 /// \brief Run checkers for end of path. 262 void runCheckersForEndPath(NodeBuilderContext &BC, 263 ExplodedNodeSet &Dst, 264 ExprEngine &Eng); 265 266 /// \brief Run checkers for branch condition. 267 void runCheckersForBranchCondition(const Stmt *condition, 268 ExplodedNodeSet &Dst, ExplodedNode *Pred, 269 ExprEngine &Eng); 270 271 /// \brief Run checkers for live symbols. 272 /// 273 /// Allows modifying SymbolReaper object. For example, checkers can explicitly 274 /// register symbols of interest as live. These symbols will not be marked 275 /// dead and removed. 276 void runCheckersForLiveSymbols(ProgramStateRef state, 277 SymbolReaper &SymReaper); 278 279 /// \brief Run checkers for dead symbols. 280 /// 281 /// Notifies checkers when symbols become dead. For example, this allows 282 /// checkers to aggressively clean up/reduce the checker state and produce 283 /// precise diagnostics. 284 void runCheckersForDeadSymbols(ExplodedNodeSet &Dst, 285 const ExplodedNodeSet &Src, 286 SymbolReaper &SymReaper, const Stmt *S, 287 ExprEngine &Eng, 288 ProgramPoint::Kind K); 289 290 /// \brief True if at least one checker wants to check region changes. 291 bool wantsRegionChangeUpdate(ProgramStateRef state); 292 293 /// \brief Run checkers for region changes. 294 /// 295 /// This corresponds to the check::RegionChanges callback. 296 /// \param state The current program state. 297 /// \param invalidated A set of all symbols potentially touched by the change. 298 /// \param ExplicitRegions The regions explicitly requested for invalidation. 299 /// For example, in the case of a function call, these would be arguments. 300 /// \param Regions The transitive closure of accessible regions, 301 /// i.e. all regions that may have been touched by this change. 302 /// \param Call The call expression wrapper if the regions are invalidated 303 /// by a call. 304 ProgramStateRef 305 runCheckersForRegionChanges(ProgramStateRef state, 306 const StoreManager::InvalidatedSymbols *invalidated, 307 ArrayRef<const MemRegion *> ExplicitRegions, 308 ArrayRef<const MemRegion *> Regions, 309 const CallEvent *Call); 310 311 /// \brief Run checkers for handling assumptions on symbolic values. 312 ProgramStateRef runCheckersForEvalAssume(ProgramStateRef state, 313 SVal Cond, bool Assumption); 314 315 /// \brief Run checkers for evaluating a call. 316 void runCheckersForEvalCall(ExplodedNodeSet &Dst, 317 const ExplodedNodeSet &Src, 318 const SimpleCall &CE, ExprEngine &Eng); 319 320 /// \brief Run checkers for the entire Translation Unit. 321 void runCheckersOnEndOfTranslationUnit(const TranslationUnitDecl *TU, 322 AnalysisManager &mgr, 323 BugReporter &BR); 324 325 /// \brief Run checkers for debug-printing a ProgramState. 326 /// 327 /// Unlike most other callbacks, any checker can simply implement the virtual 328 /// method CheckerBase::printState if it has custom data to print. 329 /// \param Out The output stream 330 /// \param State The state being printed 331 /// \param NL The preferred representation of a newline. 332 /// \param Sep The preferred separator between different kinds of data. 333 void runCheckersForPrintState(raw_ostream &Out, ProgramStateRef State, 334 const char *NL, const char *Sep); 335 336//===----------------------------------------------------------------------===// 337// Internal registration functions for AST traversing. 338//===----------------------------------------------------------------------===// 339 340 // Functions used by the registration mechanism, checkers should not touch 341 // these directly. 342 343 typedef CheckerFn<void (const Decl *, AnalysisManager&, BugReporter &)> 344 CheckDeclFunc; 345 346 typedef bool (*HandlesDeclFunc)(const Decl *D); 347 void _registerForDecl(CheckDeclFunc checkfn, HandlesDeclFunc isForDeclFn); 348 349 void _registerForBody(CheckDeclFunc checkfn); 350 351//===----------------------------------------------------------------------===// 352// Internal registration functions for path-sensitive checking. 353//===----------------------------------------------------------------------===// 354 355 typedef CheckerFn<void (const Stmt *, CheckerContext &)> CheckStmtFunc; 356 357 typedef CheckerFn<void (const ObjCMethodCall &, CheckerContext &)> 358 CheckObjCMessageFunc; 359 360 typedef CheckerFn<void (const CallEvent &, CheckerContext &)> 361 CheckCallFunc; 362 363 typedef CheckerFn<void (const SVal &location, bool isLoad, 364 const Stmt *S, 365 CheckerContext &)> 366 CheckLocationFunc; 367 368 typedef CheckerFn<void (const SVal &location, const SVal &val, 369 const Stmt *S, CheckerContext &)> 370 CheckBindFunc; 371 372 typedef CheckerFn<void (ExplodedGraph &, BugReporter &, ExprEngine &)> 373 CheckEndAnalysisFunc; 374 375 typedef CheckerFn<void (CheckerContext &)> 376 CheckEndPathFunc; 377 378 typedef CheckerFn<void (const Stmt *, CheckerContext &)> 379 CheckBranchConditionFunc; 380 381 typedef CheckerFn<void (SymbolReaper &, CheckerContext &)> 382 CheckDeadSymbolsFunc; 383 384 typedef CheckerFn<void (ProgramStateRef,SymbolReaper &)> CheckLiveSymbolsFunc; 385 386 typedef CheckerFn<ProgramStateRef (ProgramStateRef, 387 const StoreManager::InvalidatedSymbols *symbols, 388 ArrayRef<const MemRegion *> ExplicitRegions, 389 ArrayRef<const MemRegion *> Regions, 390 const CallEvent *Call)> 391 CheckRegionChangesFunc; 392 393 typedef CheckerFn<bool (ProgramStateRef)> WantsRegionChangeUpdateFunc; 394 395 typedef CheckerFn<ProgramStateRef (ProgramStateRef, 396 const SVal &cond, bool assumption)> 397 EvalAssumeFunc; 398 399 typedef CheckerFn<bool (const CallExpr *, CheckerContext &)> 400 EvalCallFunc; 401 402 typedef CheckerFn<bool (const CallExpr *, ExprEngine &Eng, 403 ExplodedNode *Pred, 404 ExplodedNodeSet &Dst)> 405 InlineCallFunc; 406 407 typedef CheckerFn<void (const TranslationUnitDecl *, 408 AnalysisManager&, BugReporter &)> 409 CheckEndOfTranslationUnit; 410 411 typedef bool (*HandlesStmtFunc)(const Stmt *D); 412 void _registerForPreStmt(CheckStmtFunc checkfn, 413 HandlesStmtFunc isForStmtFn); 414 void _registerForPostStmt(CheckStmtFunc checkfn, 415 HandlesStmtFunc isForStmtFn); 416 417 void _registerForPreObjCMessage(CheckObjCMessageFunc checkfn); 418 void _registerForPostObjCMessage(CheckObjCMessageFunc checkfn); 419 420 void _registerForPreCall(CheckCallFunc checkfn); 421 void _registerForPostCall(CheckCallFunc checkfn); 422 423 void _registerForLocation(CheckLocationFunc checkfn); 424 425 void _registerForBind(CheckBindFunc checkfn); 426 427 void _registerForEndAnalysis(CheckEndAnalysisFunc checkfn); 428 429 void _registerForEndPath(CheckEndPathFunc checkfn); 430 431 void _registerForBranchCondition(CheckBranchConditionFunc checkfn); 432 433 void _registerForLiveSymbols(CheckLiveSymbolsFunc checkfn); 434 435 void _registerForDeadSymbols(CheckDeadSymbolsFunc checkfn); 436 437 void _registerForRegionChanges(CheckRegionChangesFunc checkfn, 438 WantsRegionChangeUpdateFunc wantUpdateFn); 439 440 void _registerForEvalAssume(EvalAssumeFunc checkfn); 441 442 void _registerForEvalCall(EvalCallFunc checkfn); 443 444 void _registerForInlineCall(InlineCallFunc checkfn); 445 446 void _registerForEndOfTranslationUnit(CheckEndOfTranslationUnit checkfn); 447 448//===----------------------------------------------------------------------===// 449// Internal registration functions for events. 450//===----------------------------------------------------------------------===// 451 452 typedef void *EventTag; 453 typedef CheckerFn<void (const void *event)> CheckEventFunc; 454 455 template <typename EVENT> 456 void _registerListenerForEvent(CheckEventFunc checkfn) { 457 EventInfo &info = Events[getTag<EVENT>()]; 458 info.Checkers.push_back(checkfn); 459 } 460 461 template <typename EVENT> 462 void _registerDispatcherForEvent() { 463 EventInfo &info = Events[getTag<EVENT>()]; 464 info.HasDispatcher = true; 465 } 466 467 template <typename EVENT> 468 void _dispatchEvent(const EVENT &event) const { 469 EventsTy::const_iterator I = Events.find(getTag<EVENT>()); 470 if (I == Events.end()) 471 return; 472 const EventInfo &info = I->second; 473 for (unsigned i = 0, e = info.Checkers.size(); i != e; ++i) 474 info.Checkers[i](&event); 475 } 476 477//===----------------------------------------------------------------------===// 478// Implementation details. 479//===----------------------------------------------------------------------===// 480 481private: 482 template <typename CHECKER> 483 static void destruct(void *obj) { delete static_cast<CHECKER *>(obj); } 484 485 template <typename T> 486 static void *getTag() { static int tag; return &tag; } 487 488 llvm::DenseMap<CheckerTag, CheckerRef> CheckerTags; 489 490 std::vector<CheckerDtor> CheckerDtors; 491 492 struct DeclCheckerInfo { 493 CheckDeclFunc CheckFn; 494 HandlesDeclFunc IsForDeclFn; 495 }; 496 std::vector<DeclCheckerInfo> DeclCheckers; 497 498 std::vector<CheckDeclFunc> BodyCheckers; 499 500 typedef SmallVector<CheckDeclFunc, 4> CachedDeclCheckers; 501 typedef llvm::DenseMap<unsigned, CachedDeclCheckers> CachedDeclCheckersMapTy; 502 CachedDeclCheckersMapTy CachedDeclCheckersMap; 503 504 struct StmtCheckerInfo { 505 CheckStmtFunc CheckFn; 506 HandlesStmtFunc IsForStmtFn; 507 bool IsPreVisit; 508 }; 509 std::vector<StmtCheckerInfo> StmtCheckers; 510 511 struct CachedStmtCheckersKey { 512 unsigned StmtKind; 513 bool IsPreVisit; 514 515 CachedStmtCheckersKey() : StmtKind(0), IsPreVisit(0) { } 516 CachedStmtCheckersKey(unsigned stmtKind, bool isPreVisit) 517 : StmtKind(stmtKind), IsPreVisit(isPreVisit) { } 518 519 static CachedStmtCheckersKey getSentinel() { 520 return CachedStmtCheckersKey(~0U, 0); 521 } 522 unsigned getHashValue() const { 523 llvm::FoldingSetNodeID ID; 524 ID.AddInteger(StmtKind); 525 ID.AddBoolean(IsPreVisit); 526 return ID.ComputeHash(); 527 } 528 bool operator==(const CachedStmtCheckersKey &RHS) const { 529 return StmtKind == RHS.StmtKind && IsPreVisit == RHS.IsPreVisit; 530 } 531 }; 532 friend struct llvm::DenseMapInfo<CachedStmtCheckersKey>; 533 534 typedef SmallVector<CheckStmtFunc, 4> CachedStmtCheckers; 535 typedef llvm::DenseMap<CachedStmtCheckersKey, CachedStmtCheckers> 536 CachedStmtCheckersMapTy; 537 CachedStmtCheckersMapTy CachedStmtCheckersMap; 538 539 CachedStmtCheckers *getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit); 540 541 std::vector<CheckObjCMessageFunc> PreObjCMessageCheckers; 542 std::vector<CheckObjCMessageFunc> PostObjCMessageCheckers; 543 544 std::vector<CheckCallFunc> PreCallCheckers; 545 std::vector<CheckCallFunc> PostCallCheckers; 546 547 std::vector<CheckLocationFunc> LocationCheckers; 548 549 std::vector<CheckBindFunc> BindCheckers; 550 551 std::vector<CheckEndAnalysisFunc> EndAnalysisCheckers; 552 553 std::vector<CheckEndPathFunc> EndPathCheckers; 554 555 std::vector<CheckBranchConditionFunc> BranchConditionCheckers; 556 557 std::vector<CheckLiveSymbolsFunc> LiveSymbolsCheckers; 558 559 std::vector<CheckDeadSymbolsFunc> DeadSymbolsCheckers; 560 561 struct RegionChangesCheckerInfo { 562 CheckRegionChangesFunc CheckFn; 563 WantsRegionChangeUpdateFunc WantUpdateFn; 564 }; 565 std::vector<RegionChangesCheckerInfo> RegionChangesCheckers; 566 567 std::vector<EvalAssumeFunc> EvalAssumeCheckers; 568 569 std::vector<EvalCallFunc> EvalCallCheckers; 570 571 std::vector<InlineCallFunc> InlineCallCheckers; 572 573 std::vector<CheckEndOfTranslationUnit> EndOfTranslationUnitCheckers; 574 575 struct EventInfo { 576 SmallVector<CheckEventFunc, 4> Checkers; 577 bool HasDispatcher; 578 EventInfo() : HasDispatcher(false) { } 579 }; 580 581 typedef llvm::DenseMap<EventTag, EventInfo> EventsTy; 582 EventsTy Events; 583}; 584 585} // end ento namespace 586 587} // end clang namespace 588 589namespace llvm { 590 /// Define DenseMapInfo so that CachedStmtCheckersKey can be used as key 591 /// in DenseMap and DenseSets. 592 template <> 593 struct DenseMapInfo<clang::ento::CheckerManager::CachedStmtCheckersKey> { 594 static inline clang::ento::CheckerManager::CachedStmtCheckersKey 595 getEmptyKey() { 596 return clang::ento::CheckerManager::CachedStmtCheckersKey(); 597 } 598 static inline clang::ento::CheckerManager::CachedStmtCheckersKey 599 getTombstoneKey() { 600 return clang::ento::CheckerManager::CachedStmtCheckersKey::getSentinel(); 601 } 602 603 static unsigned 604 getHashValue(clang::ento::CheckerManager::CachedStmtCheckersKey S) { 605 return S.getHashValue(); 606 } 607 608 static bool isEqual(clang::ento::CheckerManager::CachedStmtCheckersKey LHS, 609 clang::ento::CheckerManager::CachedStmtCheckersKey RHS) { 610 return LHS == RHS; 611 } 612 }; 613} // end namespace llvm 614 615#endif 616