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