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 FunctionDecl; 34 class 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. 39 class ProgramPointTag { 40 public: 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 48 private: 49 const void *const TagKind; 50 }; 51 52 class SimpleProgramPointTag : public ProgramPointTag { 53 std::string Desc; 54 public: 55 SimpleProgramPointTag(StringRef MsgProvider, StringRef Msg); 56 StringRef getTagDescription() const override; 57 }; 58 59 class ProgramPoint { 60 public: 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 89 private: 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 99 protected: 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 124 protected: 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 129 public: 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 225 class BlockEntrance : public ProgramPoint { 226 public: 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 242 private: 243 friend class ProgramPoint; 244 BlockEntrance() = default; 245 static bool isKind(const ProgramPoint &Location) { 246 return Location.getKind() == BlockEntranceKind; 247 } 248 }; 249 250 class BlockExit : public ProgramPoint { 251 public: 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 263 private: 264 friend class ProgramPoint; 265 BlockExit() = default; 266 static bool isKind(const ProgramPoint &Location) { 267 return Location.getKind() == BlockExitKind; 268 } 269 }; 270 271 class StmtPoint : public ProgramPoint { 272 public: 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 284 protected: 285 StmtPoint() = default; 286 private: 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 295 class PreStmt : public StmtPoint { 296 public: 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 303 private: 304 friend class ProgramPoint; 305 PreStmt() = default; 306 static bool isKind(const ProgramPoint &Location) { 307 return Location.getKind() == PreStmtKind; 308 } 309 }; 310 311 class PostStmt : public StmtPoint { 312 protected: 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 318 public: 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 327 private: 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 335 class FunctionExitPoint : public ProgramPoint { 336 public: 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 350 private: 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. 359 class PostCondition : public PostStmt { 360 public: 361 PostCondition(const Stmt *S, const LocationContext *L, 362 const ProgramPointTag *tag = nullptr) 363 : PostStmt(S, PostConditionKind, L, tag) {} 364 365 private: 366 friend class ProgramPoint; 367 PostCondition() = default; 368 static bool isKind(const ProgramPoint &Location) { 369 return Location.getKind() == PostConditionKind; 370 } 371 }; 372 373 class LocationCheck : public StmtPoint { 374 protected: 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 380 private: 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 388 class PreLoad : public LocationCheck { 389 public: 390 PreLoad(const Stmt *S, const LocationContext *L, 391 const ProgramPointTag *tag = nullptr) 392 : LocationCheck(S, L, PreLoadKind, tag) {} 393 394 private: 395 friend class ProgramPoint; 396 PreLoad() = default; 397 static bool isKind(const ProgramPoint &location) { 398 return location.getKind() == PreLoadKind; 399 } 400 }; 401 402 class PreStore : public LocationCheck { 403 public: 404 PreStore(const Stmt *S, const LocationContext *L, 405 const ProgramPointTag *tag = nullptr) 406 : LocationCheck(S, L, PreStoreKind, tag) {} 407 408 private: 409 friend class ProgramPoint; 410 PreStore() = default; 411 static bool isKind(const ProgramPoint &location) { 412 return location.getKind() == PreStoreKind; 413 } 414 }; 415 416 class PostLoad : public PostStmt { 417 public: 418 PostLoad(const Stmt *S, const LocationContext *L, 419 const ProgramPointTag *tag = nullptr) 420 : PostStmt(S, PostLoadKind, L, tag) {} 421 422 private: 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. 431 class PostStore : public PostStmt { 432 public: 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 449 private: 450 friend class ProgramPoint; 451 PostStore() = default; 452 static bool isKind(const ProgramPoint &Location) { 453 return Location.getKind() == PostStoreKind; 454 } 455 }; 456 457 class PostLValue : public PostStmt { 458 public: 459 PostLValue(const Stmt *S, const LocationContext *L, 460 const ProgramPointTag *tag = nullptr) 461 : PostStmt(S, PostLValueKind, L, tag) {} 462 463 private: 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. 473 class PreStmtPurgeDeadSymbols : public StmtPoint { 474 public: 475 PreStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L, 476 const ProgramPointTag *tag = nullptr) 477 : StmtPoint(S, nullptr, PreStmtPurgeDeadSymbolsKind, L, tag) { } 478 479 private: 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. 489 class PostStmtPurgeDeadSymbols : public StmtPoint { 490 public: 491 PostStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L, 492 const ProgramPointTag *tag = nullptr) 493 : StmtPoint(S, nullptr, PostStmtPurgeDeadSymbolsKind, L, tag) { } 494 495 private: 496 friend class ProgramPoint; 497 PostStmtPurgeDeadSymbols() = default; 498 static bool isKind(const ProgramPoint &Location) { 499 return Location.getKind() == PostStmtPurgeDeadSymbolsKind; 500 } 501 }; 502 503 class BlockEdge : public ProgramPoint { 504 public: 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 519 private: 520 friend class ProgramPoint; 521 BlockEdge() = default; 522 static bool isKind(const ProgramPoint &Location) { 523 return Location.getKind() == BlockEdgeKind; 524 } 525 }; 526 527 class PostInitializer : public ProgramPoint { 528 public: 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 548 private: 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. 559 class ImplicitCallPoint : public ProgramPoint { 560 public: 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 570 protected: 571 ImplicitCallPoint() = default; 572 private: 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. 583 class PreImplicitCall : public ImplicitCallPoint { 584 public: 585 PreImplicitCall(const Decl *D, SourceLocation Loc, const LocationContext *L, 586 const ProgramPointTag *Tag = nullptr) 587 : ImplicitCallPoint(D, Loc, PreImplicitCallKind, L, Tag) {} 588 589 private: 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. 600 class PostImplicitCall : public ImplicitCallPoint { 601 public: 602 PostImplicitCall(const Decl *D, SourceLocation Loc, const LocationContext *L, 603 const ProgramPointTag *Tag = nullptr) 604 : ImplicitCallPoint(D, Loc, PostImplicitCallKind, L, Tag) {} 605 606 private: 607 friend class ProgramPoint; 608 PostImplicitCall() = default; 609 static bool isKind(const ProgramPoint &Location) { 610 return Location.getKind() == PostImplicitCallKind; 611 } 612 }; 613 614 class PostAllocatorCall : public StmtPoint { 615 public: 616 PostAllocatorCall(const Stmt *S, const LocationContext *L, 617 const ProgramPointTag *Tag = nullptr) 618 : StmtPoint(S, nullptr, PostAllocatorCallKind, L, Tag) {} 619 620 private: 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. 630 class CallEnter : public ProgramPoint { 631 public: 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 651 private: 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 668 class CallExitBegin : public ProgramPoint { 669 public: 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 678 private: 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 688 class CallExitEnd : public ProgramPoint { 689 public: 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 699 private: 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. 713 class LoopExit : public ProgramPoint { 714 public: 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 722 private: 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. 732 class EpsilonPoint : public ProgramPoint { 733 public: 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 741 private: 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 752 namespace llvm { // Traits specialization for DenseMap 753 754 template <> struct DenseMapInfo<clang::ProgramPoint> { 755 756 static 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 762 static 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 768 static unsigned getHashValue(const clang::ProgramPoint &Loc) { 769 return Loc.getHashValue(); 770 } 771 772 static 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