1//==- ProgramPoint.h - Program Points for Path-Sensitive Analysis --*- C++ -*-// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8// 9// This file defines the interface ProgramPoint, which identifies a 10// distinct location in a function. 11// 12//===----------------------------------------------------------------------===// 13 14#ifndef LLVM_CLANG_ANALYSIS_PROGRAMPOINT_H 15#define LLVM_CLANG_ANALYSIS_PROGRAMPOINT_H 16 17#include "clang/Analysis/AnalysisDeclContext.h" 18#include "clang/Analysis/CFG.h" 19#include "llvm/ADT/DenseMap.h" 20#include "llvm/ADT/FoldingSet.h" 21#include "llvm/ADT/Optional.h" 22#include "llvm/ADT/PointerIntPair.h" 23#include "llvm/ADT/StringRef.h" 24#include "llvm/Support/Casting.h" 25#include "llvm/Support/DataTypes.h" 26#include <cassert> 27#include <string> 28#include <utility> 29 30namespace clang { 31 32class AnalysisDeclContext; 33class FunctionDecl; 34class LocationContext; 35 36/// ProgramPoints can be "tagged" as representing points specific to a given 37/// analysis entity. Tags are abstract annotations, with an associated 38/// description and potentially other information. 39class ProgramPointTag { 40public: 41 ProgramPointTag(void *tagKind = nullptr) : TagKind(tagKind) {} 42 virtual ~ProgramPointTag(); 43 virtual StringRef getTagDescription() const = 0; 44 45 /// Used to implement 'isKind' in subclasses. 46 const void *getTagKind() const { return TagKind; } 47 48private: 49 const void *const TagKind; 50}; 51 52class SimpleProgramPointTag : public ProgramPointTag { 53 std::string Desc; 54public: 55 SimpleProgramPointTag(StringRef MsgProvider, StringRef Msg); 56 StringRef getTagDescription() const override; 57}; 58 59class ProgramPoint { 60public: 61 enum Kind { BlockEdgeKind, 62 BlockEntranceKind, 63 BlockExitKind, 64 PreStmtKind, 65 PreStmtPurgeDeadSymbolsKind, 66 PostStmtPurgeDeadSymbolsKind, 67 PostStmtKind, 68 PreLoadKind, 69 PostLoadKind, 70 PreStoreKind, 71 PostStoreKind, 72 PostConditionKind, 73 PostLValueKind, 74 PostAllocatorCallKind, 75 MinPostStmtKind = PostStmtKind, 76 MaxPostStmtKind = PostAllocatorCallKind, 77 PostInitializerKind, 78 CallEnterKind, 79 CallExitBeginKind, 80 CallExitEndKind, 81 FunctionExitKind, 82 PreImplicitCallKind, 83 PostImplicitCallKind, 84 MinImplicitCallKind = PreImplicitCallKind, 85 MaxImplicitCallKind = PostImplicitCallKind, 86 LoopExitKind, 87 EpsilonKind}; 88 89private: 90 const void *Data1; 91 llvm::PointerIntPair<const void *, 2, unsigned> Data2; 92 93 // The LocationContext could be NULL to allow ProgramPoint to be used in 94 // context insensitive analysis. 95 llvm::PointerIntPair<const LocationContext *, 2, unsigned> L; 96 97 llvm::PointerIntPair<const ProgramPointTag *, 2, unsigned> Tag; 98 99protected: 100 ProgramPoint() = default; 101 ProgramPoint(const void *P, 102 Kind k, 103 const LocationContext *l, 104 const ProgramPointTag *tag = nullptr) 105 : Data1(P), 106 Data2(nullptr, (((unsigned) k) >> 0) & 0x3), 107 L(l, (((unsigned) k) >> 2) & 0x3), 108 Tag(tag, (((unsigned) k) >> 4) & 0x3) { 109 assert(getKind() == k); 110 assert(getLocationContext() == l); 111 assert(getData1() == P); 112 } 113 114 ProgramPoint(const void *P1, 115 const void *P2, 116 Kind k, 117 const LocationContext *l, 118 const ProgramPointTag *tag = nullptr) 119 : Data1(P1), 120 Data2(P2, (((unsigned) k) >> 0) & 0x3), 121 L(l, (((unsigned) k) >> 2) & 0x3), 122 Tag(tag, (((unsigned) k) >> 4) & 0x3) {} 123 124protected: 125 const void *getData1() const { return Data1; } 126 const void *getData2() const { return Data2.getPointer(); } 127 void setData2(const void *d) { Data2.setPointer(d); } 128 129public: 130 /// Create a new ProgramPoint object that is the same as the original 131 /// except for using the specified tag value. 132 ProgramPoint withTag(const ProgramPointTag *tag) const { 133 return ProgramPoint(getData1(), getData2(), getKind(), 134 getLocationContext(), tag); 135 } 136 137 /// Convert to the specified ProgramPoint type, asserting that this 138 /// ProgramPoint is of the desired type. 139 template<typename T> 140 T castAs() const { 141 assert(T::isKind(*this)); 142 T t; 143 ProgramPoint& PP = t; 144 PP = *this; 145 return t; 146 } 147 148 /// Convert to the specified ProgramPoint type, returning None if this 149 /// ProgramPoint is not of the desired type. 150 template<typename T> 151 Optional<T> getAs() const { 152 if (!T::isKind(*this)) 153 return None; 154 T t; 155 ProgramPoint& PP = t; 156 PP = *this; 157 return t; 158 } 159 160 Kind getKind() const { 161 unsigned x = Tag.getInt(); 162 x <<= 2; 163 x |= L.getInt(); 164 x <<= 2; 165 x |= Data2.getInt(); 166 return (Kind) x; 167 } 168 169 /// Is this a program point corresponding to purge/removal of dead 170 /// symbols and bindings. 171 bool isPurgeKind() { 172 Kind K = getKind(); 173 return (K == PostStmtPurgeDeadSymbolsKind || 174 K == PreStmtPurgeDeadSymbolsKind); 175 } 176 177 const ProgramPointTag *getTag() const { return Tag.getPointer(); } 178 179 const LocationContext *getLocationContext() const { 180 return L.getPointer(); 181 } 182 183 const StackFrameContext *getStackFrame() const { 184 return getLocationContext()->getStackFrame(); 185 } 186 187 // For use with DenseMap. This hash is probably slow. 188 unsigned getHashValue() const { 189 llvm::FoldingSetNodeID ID; 190 Profile(ID); 191 return ID.ComputeHash(); 192 } 193 194 bool operator==(const ProgramPoint & RHS) const { 195 return Data1 == RHS.Data1 && 196 Data2 == RHS.Data2 && 197 L == RHS.L && 198 Tag == RHS.Tag; 199 } 200 201 bool operator!=(const ProgramPoint &RHS) const { 202 return Data1 != RHS.Data1 || 203 Data2 != RHS.Data2 || 204 L != RHS.L || 205 Tag != RHS.Tag; 206 } 207 208 void Profile(llvm::FoldingSetNodeID& ID) const { 209 ID.AddInteger((unsigned) getKind()); 210 ID.AddPointer(getData1()); 211 ID.AddPointer(getData2()); 212 ID.AddPointer(getLocationContext()); 213 ID.AddPointer(getTag()); 214 } 215 216 void printJson(llvm::raw_ostream &Out, const char *NL = "\n") const; 217 218 LLVM_DUMP_METHOD void dump() const; 219 220 static ProgramPoint getProgramPoint(const Stmt *S, ProgramPoint::Kind K, 221 const LocationContext *LC, 222 const ProgramPointTag *tag); 223}; 224 225class BlockEntrance : public ProgramPoint { 226public: 227 BlockEntrance(const CFGBlock *B, const LocationContext *L, 228 const ProgramPointTag *tag = nullptr) 229 : ProgramPoint(B, BlockEntranceKind, L, tag) { 230 assert(B && "BlockEntrance requires non-null block"); 231 } 232 233 const CFGBlock *getBlock() const { 234 return reinterpret_cast<const CFGBlock*>(getData1()); 235 } 236 237 Optional<CFGElement> getFirstElement() const { 238 const CFGBlock *B = getBlock(); 239 return B->empty() ? Optional<CFGElement>() : B->front(); 240 } 241 242private: 243 friend class ProgramPoint; 244 BlockEntrance() = default; 245 static bool isKind(const ProgramPoint &Location) { 246 return Location.getKind() == BlockEntranceKind; 247 } 248}; 249 250class BlockExit : public ProgramPoint { 251public: 252 BlockExit(const CFGBlock *B, const LocationContext *L) 253 : ProgramPoint(B, BlockExitKind, L) {} 254 255 const CFGBlock *getBlock() const { 256 return reinterpret_cast<const CFGBlock*>(getData1()); 257 } 258 259 const Stmt *getTerminator() const { 260 return getBlock()->getTerminatorStmt(); 261 } 262 263private: 264 friend class ProgramPoint; 265 BlockExit() = default; 266 static bool isKind(const ProgramPoint &Location) { 267 return Location.getKind() == BlockExitKind; 268 } 269}; 270 271class StmtPoint : public ProgramPoint { 272public: 273 StmtPoint(const Stmt *S, const void *p2, Kind k, const LocationContext *L, 274 const ProgramPointTag *tag) 275 : ProgramPoint(S, p2, k, L, tag) { 276 assert(S); 277 } 278 279 const Stmt *getStmt() const { return (const Stmt*) getData1(); } 280 281 template <typename T> 282 const T* getStmtAs() const { return dyn_cast<T>(getStmt()); } 283 284protected: 285 StmtPoint() = default; 286private: 287 friend class ProgramPoint; 288 static bool isKind(const ProgramPoint &Location) { 289 unsigned k = Location.getKind(); 290 return k >= PreStmtKind && k <= MaxPostStmtKind; 291 } 292}; 293 294 295class PreStmt : public StmtPoint { 296public: 297 PreStmt(const Stmt *S, const LocationContext *L, const ProgramPointTag *tag, 298 const Stmt *SubStmt = nullptr) 299 : StmtPoint(S, SubStmt, PreStmtKind, L, tag) {} 300 301 const Stmt *getSubStmt() const { return (const Stmt*) getData2(); } 302 303private: 304 friend class ProgramPoint; 305 PreStmt() = default; 306 static bool isKind(const ProgramPoint &Location) { 307 return Location.getKind() == PreStmtKind; 308 } 309}; 310 311class PostStmt : public StmtPoint { 312protected: 313 PostStmt() = default; 314 PostStmt(const Stmt *S, const void *data, Kind k, const LocationContext *L, 315 const ProgramPointTag *tag = nullptr) 316 : StmtPoint(S, data, k, L, tag) {} 317 318public: 319 explicit PostStmt(const Stmt *S, Kind k, const LocationContext *L, 320 const ProgramPointTag *tag = nullptr) 321 : StmtPoint(S, nullptr, k, L, tag) {} 322 323 explicit PostStmt(const Stmt *S, const LocationContext *L, 324 const ProgramPointTag *tag = nullptr) 325 : StmtPoint(S, nullptr, PostStmtKind, L, tag) {} 326 327private: 328 friend class ProgramPoint; 329 static bool isKind(const ProgramPoint &Location) { 330 unsigned k = Location.getKind(); 331 return k >= MinPostStmtKind && k <= MaxPostStmtKind; 332 } 333}; 334 335class FunctionExitPoint : public ProgramPoint { 336public: 337 explicit FunctionExitPoint(const ReturnStmt *S, 338 const LocationContext *LC, 339 const ProgramPointTag *tag = nullptr) 340 : ProgramPoint(S, FunctionExitKind, LC, tag) {} 341 342 const CFGBlock *getBlock() const { 343 return &getLocationContext()->getCFG()->getExit(); 344 } 345 346 const ReturnStmt *getStmt() const { 347 return reinterpret_cast<const ReturnStmt *>(getData1()); 348 } 349 350private: 351 friend class ProgramPoint; 352 FunctionExitPoint() = default; 353 static bool isKind(const ProgramPoint &Location) { 354 return Location.getKind() == FunctionExitKind; 355 } 356}; 357 358// PostCondition represents the post program point of a branch condition. 359class PostCondition : public PostStmt { 360public: 361 PostCondition(const Stmt *S, const LocationContext *L, 362 const ProgramPointTag *tag = nullptr) 363 : PostStmt(S, PostConditionKind, L, tag) {} 364 365private: 366 friend class ProgramPoint; 367 PostCondition() = default; 368 static bool isKind(const ProgramPoint &Location) { 369 return Location.getKind() == PostConditionKind; 370 } 371}; 372 373class LocationCheck : public StmtPoint { 374protected: 375 LocationCheck() = default; 376 LocationCheck(const Stmt *S, const LocationContext *L, 377 ProgramPoint::Kind K, const ProgramPointTag *tag) 378 : StmtPoint(S, nullptr, K, L, tag) {} 379 380private: 381 friend class ProgramPoint; 382 static bool isKind(const ProgramPoint &location) { 383 unsigned k = location.getKind(); 384 return k == PreLoadKind || k == PreStoreKind; 385 } 386}; 387 388class PreLoad : public LocationCheck { 389public: 390 PreLoad(const Stmt *S, const LocationContext *L, 391 const ProgramPointTag *tag = nullptr) 392 : LocationCheck(S, L, PreLoadKind, tag) {} 393 394private: 395 friend class ProgramPoint; 396 PreLoad() = default; 397 static bool isKind(const ProgramPoint &location) { 398 return location.getKind() == PreLoadKind; 399 } 400}; 401 402class PreStore : public LocationCheck { 403public: 404 PreStore(const Stmt *S, const LocationContext *L, 405 const ProgramPointTag *tag = nullptr) 406 : LocationCheck(S, L, PreStoreKind, tag) {} 407 408private: 409 friend class ProgramPoint; 410 PreStore() = default; 411 static bool isKind(const ProgramPoint &location) { 412 return location.getKind() == PreStoreKind; 413 } 414}; 415 416class PostLoad : public PostStmt { 417public: 418 PostLoad(const Stmt *S, const LocationContext *L, 419 const ProgramPointTag *tag = nullptr) 420 : PostStmt(S, PostLoadKind, L, tag) {} 421 422private: 423 friend class ProgramPoint; 424 PostLoad() = default; 425 static bool isKind(const ProgramPoint &Location) { 426 return Location.getKind() == PostLoadKind; 427 } 428}; 429 430/// Represents a program point after a store evaluation. 431class PostStore : public PostStmt { 432public: 433 /// Construct the post store point. 434 /// \param Loc can be used to store the information about the location 435 /// used in the form it was uttered in the code. 436 PostStore(const Stmt *S, const LocationContext *L, const void *Loc, 437 const ProgramPointTag *tag = nullptr) 438 : PostStmt(S, PostStoreKind, L, tag) { 439 assert(getData2() == nullptr); 440 setData2(Loc); 441 } 442 443 /// Returns the information about the location used in the store, 444 /// how it was uttered in the code. 445 const void *getLocationValue() const { 446 return getData2(); 447 } 448 449private: 450 friend class ProgramPoint; 451 PostStore() = default; 452 static bool isKind(const ProgramPoint &Location) { 453 return Location.getKind() == PostStoreKind; 454 } 455}; 456 457class PostLValue : public PostStmt { 458public: 459 PostLValue(const Stmt *S, const LocationContext *L, 460 const ProgramPointTag *tag = nullptr) 461 : PostStmt(S, PostLValueKind, L, tag) {} 462 463private: 464 friend class ProgramPoint; 465 PostLValue() = default; 466 static bool isKind(const ProgramPoint &Location) { 467 return Location.getKind() == PostLValueKind; 468 } 469}; 470 471/// Represents a point after we ran remove dead bindings BEFORE 472/// processing the given statement. 473class PreStmtPurgeDeadSymbols : public StmtPoint { 474public: 475 PreStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L, 476 const ProgramPointTag *tag = nullptr) 477 : StmtPoint(S, nullptr, PreStmtPurgeDeadSymbolsKind, L, tag) { } 478 479private: 480 friend class ProgramPoint; 481 PreStmtPurgeDeadSymbols() = default; 482 static bool isKind(const ProgramPoint &Location) { 483 return Location.getKind() == PreStmtPurgeDeadSymbolsKind; 484 } 485}; 486 487/// Represents a point after we ran remove dead bindings AFTER 488/// processing the given statement. 489class PostStmtPurgeDeadSymbols : public StmtPoint { 490public: 491 PostStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L, 492 const ProgramPointTag *tag = nullptr) 493 : StmtPoint(S, nullptr, PostStmtPurgeDeadSymbolsKind, L, tag) { } 494 495private: 496 friend class ProgramPoint; 497 PostStmtPurgeDeadSymbols() = default; 498 static bool isKind(const ProgramPoint &Location) { 499 return Location.getKind() == PostStmtPurgeDeadSymbolsKind; 500 } 501}; 502 503class BlockEdge : public ProgramPoint { 504public: 505 BlockEdge(const CFGBlock *B1, const CFGBlock *B2, const LocationContext *L) 506 : ProgramPoint(B1, B2, BlockEdgeKind, L) { 507 assert(B1 && "BlockEdge: source block must be non-null"); 508 assert(B2 && "BlockEdge: destination block must be non-null"); 509 } 510 511 const CFGBlock *getSrc() const { 512 return static_cast<const CFGBlock*>(getData1()); 513 } 514 515 const CFGBlock *getDst() const { 516 return static_cast<const CFGBlock*>(getData2()); 517 } 518 519private: 520 friend class ProgramPoint; 521 BlockEdge() = default; 522 static bool isKind(const ProgramPoint &Location) { 523 return Location.getKind() == BlockEdgeKind; 524 } 525}; 526 527class PostInitializer : public ProgramPoint { 528public: 529 /// Construct a PostInitializer point that represents a location after 530 /// CXXCtorInitializer expression evaluation. 531 /// 532 /// \param I The initializer. 533 /// \param Loc The location of the field being initialized. 534 PostInitializer(const CXXCtorInitializer *I, 535 const void *Loc, 536 const LocationContext *L) 537 : ProgramPoint(I, Loc, PostInitializerKind, L) {} 538 539 const CXXCtorInitializer *getInitializer() const { 540 return static_cast<const CXXCtorInitializer *>(getData1()); 541 } 542 543 /// Returns the location of the field. 544 const void *getLocationValue() const { 545 return getData2(); 546 } 547 548private: 549 friend class ProgramPoint; 550 PostInitializer() = default; 551 static bool isKind(const ProgramPoint &Location) { 552 return Location.getKind() == PostInitializerKind; 553 } 554}; 555 556/// Represents an implicit call event. 557/// 558/// The nearest statement is provided for diagnostic purposes. 559class ImplicitCallPoint : public ProgramPoint { 560public: 561 ImplicitCallPoint(const Decl *D, SourceLocation Loc, Kind K, 562 const LocationContext *L, const ProgramPointTag *Tag) 563 : ProgramPoint(Loc.getPtrEncoding(), D, K, L, Tag) {} 564 565 const Decl *getDecl() const { return static_cast<const Decl *>(getData2()); } 566 SourceLocation getLocation() const { 567 return SourceLocation::getFromPtrEncoding(getData1()); 568 } 569 570protected: 571 ImplicitCallPoint() = default; 572private: 573 friend class ProgramPoint; 574 static bool isKind(const ProgramPoint &Location) { 575 return Location.getKind() >= MinImplicitCallKind && 576 Location.getKind() <= MaxImplicitCallKind; 577 } 578}; 579 580/// Represents a program point just before an implicit call event. 581/// 582/// Explicit calls will appear as PreStmt program points. 583class PreImplicitCall : public ImplicitCallPoint { 584public: 585 PreImplicitCall(const Decl *D, SourceLocation Loc, const LocationContext *L, 586 const ProgramPointTag *Tag = nullptr) 587 : ImplicitCallPoint(D, Loc, PreImplicitCallKind, L, Tag) {} 588 589private: 590 friend class ProgramPoint; 591 PreImplicitCall() = default; 592 static bool isKind(const ProgramPoint &Location) { 593 return Location.getKind() == PreImplicitCallKind; 594 } 595}; 596 597/// Represents a program point just after an implicit call event. 598/// 599/// Explicit calls will appear as PostStmt program points. 600class PostImplicitCall : public ImplicitCallPoint { 601public: 602 PostImplicitCall(const Decl *D, SourceLocation Loc, const LocationContext *L, 603 const ProgramPointTag *Tag = nullptr) 604 : ImplicitCallPoint(D, Loc, PostImplicitCallKind, L, Tag) {} 605 606private: 607 friend class ProgramPoint; 608 PostImplicitCall() = default; 609 static bool isKind(const ProgramPoint &Location) { 610 return Location.getKind() == PostImplicitCallKind; 611 } 612}; 613 614class PostAllocatorCall : public StmtPoint { 615public: 616 PostAllocatorCall(const Stmt *S, const LocationContext *L, 617 const ProgramPointTag *Tag = nullptr) 618 : StmtPoint(S, nullptr, PostAllocatorCallKind, L, Tag) {} 619 620private: 621 friend class ProgramPoint; 622 PostAllocatorCall() = default; 623 static bool isKind(const ProgramPoint &Location) { 624 return Location.getKind() == PostAllocatorCallKind; 625 } 626}; 627 628/// Represents a point when we begin processing an inlined call. 629/// CallEnter uses the caller's location context. 630class CallEnter : public ProgramPoint { 631public: 632 CallEnter(const Stmt *stmt, const StackFrameContext *calleeCtx, 633 const LocationContext *callerCtx) 634 : ProgramPoint(stmt, calleeCtx, CallEnterKind, callerCtx, nullptr) {} 635 636 const Stmt *getCallExpr() const { 637 return static_cast<const Stmt *>(getData1()); 638 } 639 640 const StackFrameContext *getCalleeContext() const { 641 return static_cast<const StackFrameContext *>(getData2()); 642 } 643 644 /// Returns the entry block in the CFG for the entered function. 645 const CFGBlock *getEntry() const { 646 const StackFrameContext *CalleeCtx = getCalleeContext(); 647 const CFG *CalleeCFG = CalleeCtx->getCFG(); 648 return &(CalleeCFG->getEntry()); 649 } 650 651private: 652 friend class ProgramPoint; 653 CallEnter() = default; 654 static bool isKind(const ProgramPoint &Location) { 655 return Location.getKind() == CallEnterKind; 656 } 657}; 658 659/// Represents a point when we start the call exit sequence (for inlined call). 660/// 661/// The call exit is simulated with a sequence of nodes, which occur between 662/// CallExitBegin and CallExitEnd. The following operations occur between the 663/// two program points: 664/// - CallExitBegin 665/// - Bind the return value 666/// - Run Remove dead bindings (to clean up the dead symbols from the callee). 667/// - CallExitEnd 668class CallExitBegin : public ProgramPoint { 669public: 670 // CallExitBegin uses the callee's location context. 671 CallExitBegin(const StackFrameContext *L, const ReturnStmt *RS) 672 : ProgramPoint(RS, CallExitBeginKind, L, nullptr) { } 673 674 const ReturnStmt *getReturnStmt() const { 675 return static_cast<const ReturnStmt *>(getData1()); 676 } 677 678private: 679 friend class ProgramPoint; 680 CallExitBegin() = default; 681 static bool isKind(const ProgramPoint &Location) { 682 return Location.getKind() == CallExitBeginKind; 683 } 684}; 685 686/// Represents a point when we finish the call exit sequence (for inlined call). 687/// \sa CallExitBegin 688class CallExitEnd : public ProgramPoint { 689public: 690 // CallExitEnd uses the caller's location context. 691 CallExitEnd(const StackFrameContext *CalleeCtx, 692 const LocationContext *CallerCtx) 693 : ProgramPoint(CalleeCtx, CallExitEndKind, CallerCtx, nullptr) {} 694 695 const StackFrameContext *getCalleeContext() const { 696 return static_cast<const StackFrameContext *>(getData1()); 697 } 698 699private: 700 friend class ProgramPoint; 701 CallExitEnd() = default; 702 static bool isKind(const ProgramPoint &Location) { 703 return Location.getKind() == CallExitEndKind; 704 } 705}; 706 707/// Represents a point when we exit a loop. 708/// When this ProgramPoint is encountered we can be sure that the symbolic 709/// execution of the corresponding LoopStmt is finished on the given path. 710/// Note: It is possible to encounter a LoopExit element when we haven't even 711/// encountered the loop itself. At the current state not all loop exits will 712/// result in a LoopExit program point. 713class LoopExit : public ProgramPoint { 714public: 715 LoopExit(const Stmt *LoopStmt, const LocationContext *LC) 716 : ProgramPoint(LoopStmt, nullptr, LoopExitKind, LC) {} 717 718 const Stmt *getLoopStmt() const { 719 return static_cast<const Stmt *>(getData1()); 720 } 721 722private: 723 friend class ProgramPoint; 724 LoopExit() = default; 725 static bool isKind(const ProgramPoint &Location) { 726 return Location.getKind() == LoopExitKind; 727 } 728}; 729 730/// This is a meta program point, which should be skipped by all the diagnostic 731/// reasoning etc. 732class EpsilonPoint : public ProgramPoint { 733public: 734 EpsilonPoint(const LocationContext *L, const void *Data1, 735 const void *Data2 = nullptr, 736 const ProgramPointTag *tag = nullptr) 737 : ProgramPoint(Data1, Data2, EpsilonKind, L, tag) {} 738 739 const void *getData() const { return getData1(); } 740 741private: 742 friend class ProgramPoint; 743 EpsilonPoint() = default; 744 static bool isKind(const ProgramPoint &Location) { 745 return Location.getKind() == EpsilonKind; 746 } 747}; 748 749} // end namespace clang 750 751 752namespace llvm { // Traits specialization for DenseMap 753 754template <> struct DenseMapInfo<clang::ProgramPoint> { 755 756static inline clang::ProgramPoint getEmptyKey() { 757 uintptr_t x = 758 reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getEmptyKey()) & ~0x7; 759 return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), nullptr); 760} 761 762static inline clang::ProgramPoint getTombstoneKey() { 763 uintptr_t x = 764 reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getTombstoneKey()) & ~0x7; 765 return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), nullptr); 766} 767 768static unsigned getHashValue(const clang::ProgramPoint &Loc) { 769 return Loc.getHashValue(); 770} 771 772static bool isEqual(const clang::ProgramPoint &L, 773 const clang::ProgramPoint &R) { 774 return L == R; 775} 776 777}; 778 779} // end namespace llvm 780 781#endif 782