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