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 30namespace clang { 31 32class AnalysisDeclContext; 33class 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. 38class ProgramPointTag { 39public: 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 47private: 48 const void *const TagKind; 49}; 50 51class SimpleProgramPointTag : public ProgramPointTag { 52 std::string Desc; 53public: 54 SimpleProgramPointTag(StringRef MsgProvider, StringRef Msg); 55 StringRef getTagDescription() const override; 56}; 57 58class ProgramPoint { 59public: 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 88private: 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 CFGBlock::ConstCFGElementRef ElemRef = {nullptr, 0}; 99 100protected: 101 ProgramPoint() = default; 102 ProgramPoint(const void *P, Kind k, const LocationContext *l, 103 const ProgramPointTag *tag = nullptr, 104 CFGBlock::ConstCFGElementRef ElemRef = {nullptr, 0}) 105 : Data1(P), Data2(nullptr, (((unsigned)k) >> 0) & 0x3), 106 L(l, (((unsigned)k) >> 2) & 0x3), Tag(tag, (((unsigned)k) >> 4) & 0x3), 107 ElemRef(ElemRef) { 108 assert(getKind() == k); 109 assert(getLocationContext() == l); 110 assert(getData1() == P); 111 } 112 113 ProgramPoint(const void *P1, const void *P2, Kind k, const LocationContext *l, 114 const ProgramPointTag *tag = nullptr, 115 CFGBlock::ConstCFGElementRef ElemRef = {nullptr, 0}) 116 : Data1(P1), Data2(P2, (((unsigned)k) >> 0) & 0x3), 117 L(l, (((unsigned)k) >> 2) & 0x3), Tag(tag, (((unsigned)k) >> 4) & 0x3), 118 ElemRef(ElemRef) {} 119 120protected: 121 const void *getData1() const { return Data1; } 122 const void *getData2() const { return Data2.getPointer(); } 123 void setData2(const void *d) { Data2.setPointer(d); } 124 CFGBlock::ConstCFGElementRef getElementRef() const { return ElemRef; } 125 126public: 127 /// Create a new ProgramPoint object that is the same as the original 128 /// except for using the specified tag value. 129 ProgramPoint withTag(const ProgramPointTag *tag) const { 130 return ProgramPoint(getData1(), getData2(), getKind(), 131 getLocationContext(), tag); 132 } 133 134 /// Convert to the specified ProgramPoint type, asserting that this 135 /// ProgramPoint is of the desired type. 136 template<typename T> 137 T castAs() const { 138 assert(T::isKind(*this)); 139 T t; 140 ProgramPoint& PP = t; 141 PP = *this; 142 return t; 143 } 144 145 /// Convert to the specified ProgramPoint type, returning std::nullopt if this 146 /// ProgramPoint is not of the desired type. 147 template <typename T> std::optional<T> getAs() const { 148 if (!T::isKind(*this)) 149 return std::nullopt; 150 T t; 151 ProgramPoint& PP = t; 152 PP = *this; 153 return t; 154 } 155 156 Kind getKind() const { 157 unsigned x = Tag.getInt(); 158 x <<= 2; 159 x |= L.getInt(); 160 x <<= 2; 161 x |= Data2.getInt(); 162 return (Kind) x; 163 } 164 165 /// Is this a program point corresponding to purge/removal of dead 166 /// symbols and bindings. 167 bool isPurgeKind() { 168 Kind K = getKind(); 169 return (K == PostStmtPurgeDeadSymbolsKind || 170 K == PreStmtPurgeDeadSymbolsKind); 171 } 172 173 const ProgramPointTag *getTag() const { return Tag.getPointer(); } 174 175 const LocationContext *getLocationContext() const { 176 return L.getPointer(); 177 } 178 179 const StackFrameContext *getStackFrame() const { 180 return getLocationContext()->getStackFrame(); 181 } 182 183 // For use with DenseMap. This hash is probably slow. 184 unsigned getHashValue() const { 185 llvm::FoldingSetNodeID ID; 186 Profile(ID); 187 return ID.ComputeHash(); 188 } 189 190 bool operator==(const ProgramPoint & RHS) const { 191 return Data1 == RHS.Data1 && Data2 == RHS.Data2 && L == RHS.L && 192 Tag == RHS.Tag && ElemRef == RHS.ElemRef; 193 } 194 195 bool operator!=(const ProgramPoint &RHS) const { 196 return Data1 != RHS.Data1 || Data2 != RHS.Data2 || L != RHS.L || 197 Tag != RHS.Tag || ElemRef != RHS.ElemRef; 198 } 199 200 void Profile(llvm::FoldingSetNodeID& ID) const { 201 ID.AddInteger((unsigned) getKind()); 202 ID.AddPointer(getData1()); 203 ID.AddPointer(getData2()); 204 ID.AddPointer(getLocationContext()); 205 ID.AddPointer(getTag()); 206 ID.AddPointer(ElemRef.getParent()); 207 ID.AddInteger(ElemRef.getIndexInBlock()); 208 } 209 210 void printJson(llvm::raw_ostream &Out, const char *NL = "\n") const; 211 212 LLVM_DUMP_METHOD void dump() const; 213 214 static ProgramPoint getProgramPoint(const Stmt *S, ProgramPoint::Kind K, 215 const LocationContext *LC, 216 const ProgramPointTag *tag); 217}; 218 219class BlockEntrance : public ProgramPoint { 220public: 221 BlockEntrance(const CFGBlock *B, const LocationContext *L, 222 const ProgramPointTag *tag = nullptr) 223 : ProgramPoint(B, BlockEntranceKind, L, tag) { 224 assert(B && "BlockEntrance requires non-null block"); 225 } 226 227 const CFGBlock *getBlock() const { 228 return reinterpret_cast<const CFGBlock*>(getData1()); 229 } 230 231 std::optional<CFGElement> getFirstElement() const { 232 const CFGBlock *B = getBlock(); 233 return B->empty() ? std::optional<CFGElement>() : B->front(); 234 } 235 236private: 237 friend class ProgramPoint; 238 BlockEntrance() = default; 239 static bool isKind(const ProgramPoint &Location) { 240 return Location.getKind() == BlockEntranceKind; 241 } 242}; 243 244class BlockExit : public ProgramPoint { 245public: 246 BlockExit(const CFGBlock *B, const LocationContext *L) 247 : ProgramPoint(B, BlockExitKind, L) {} 248 249 const CFGBlock *getBlock() const { 250 return reinterpret_cast<const CFGBlock*>(getData1()); 251 } 252 253 const Stmt *getTerminator() const { 254 return getBlock()->getTerminatorStmt(); 255 } 256 257private: 258 friend class ProgramPoint; 259 BlockExit() = default; 260 static bool isKind(const ProgramPoint &Location) { 261 return Location.getKind() == BlockExitKind; 262 } 263}; 264 265// FIXME: Eventually we want to take a CFGElementRef as parameter here too. 266class StmtPoint : public ProgramPoint { 267public: 268 StmtPoint(const Stmt *S, const void *p2, Kind k, const LocationContext *L, 269 const ProgramPointTag *tag) 270 : ProgramPoint(S, p2, k, L, tag) { 271 assert(S); 272 } 273 274 const Stmt *getStmt() const { return (const Stmt*) getData1(); } 275 276 template <typename T> 277 const T* getStmtAs() const { return dyn_cast<T>(getStmt()); } 278 279protected: 280 StmtPoint() = default; 281private: 282 friend class ProgramPoint; 283 static bool isKind(const ProgramPoint &Location) { 284 unsigned k = Location.getKind(); 285 return k >= PreStmtKind && k <= MaxPostStmtKind; 286 } 287}; 288 289 290class PreStmt : public StmtPoint { 291public: 292 PreStmt(const Stmt *S, const LocationContext *L, const ProgramPointTag *tag, 293 const Stmt *SubStmt = nullptr) 294 : StmtPoint(S, SubStmt, PreStmtKind, L, tag) {} 295 296 const Stmt *getSubStmt() const { return (const Stmt*) getData2(); } 297 298private: 299 friend class ProgramPoint; 300 PreStmt() = default; 301 static bool isKind(const ProgramPoint &Location) { 302 return Location.getKind() == PreStmtKind; 303 } 304}; 305 306class PostStmt : public StmtPoint { 307protected: 308 PostStmt() = default; 309 PostStmt(const Stmt *S, const void *data, Kind k, const LocationContext *L, 310 const ProgramPointTag *tag = nullptr) 311 : StmtPoint(S, data, k, L, tag) {} 312 313public: 314 explicit PostStmt(const Stmt *S, Kind k, const LocationContext *L, 315 const ProgramPointTag *tag = nullptr) 316 : StmtPoint(S, nullptr, k, L, tag) {} 317 318 explicit PostStmt(const Stmt *S, const LocationContext *L, 319 const ProgramPointTag *tag = nullptr) 320 : StmtPoint(S, nullptr, PostStmtKind, L, tag) {} 321 322private: 323 friend class ProgramPoint; 324 static bool isKind(const ProgramPoint &Location) { 325 unsigned k = Location.getKind(); 326 return k >= MinPostStmtKind && k <= MaxPostStmtKind; 327 } 328}; 329 330class FunctionExitPoint : public ProgramPoint { 331public: 332 explicit FunctionExitPoint(const ReturnStmt *S, 333 const LocationContext *LC, 334 const ProgramPointTag *tag = nullptr) 335 : ProgramPoint(S, FunctionExitKind, LC, tag) {} 336 337 const CFGBlock *getBlock() const { 338 return &getLocationContext()->getCFG()->getExit(); 339 } 340 341 const ReturnStmt *getStmt() const { 342 return reinterpret_cast<const ReturnStmt *>(getData1()); 343 } 344 345private: 346 friend class ProgramPoint; 347 FunctionExitPoint() = default; 348 static bool isKind(const ProgramPoint &Location) { 349 return Location.getKind() == FunctionExitKind; 350 } 351}; 352 353// PostCondition represents the post program point of a branch condition. 354class PostCondition : public PostStmt { 355public: 356 PostCondition(const Stmt *S, const LocationContext *L, 357 const ProgramPointTag *tag = nullptr) 358 : PostStmt(S, PostConditionKind, L, tag) {} 359 360private: 361 friend class ProgramPoint; 362 PostCondition() = default; 363 static bool isKind(const ProgramPoint &Location) { 364 return Location.getKind() == PostConditionKind; 365 } 366}; 367 368class LocationCheck : public StmtPoint { 369protected: 370 LocationCheck() = default; 371 LocationCheck(const Stmt *S, const LocationContext *L, 372 ProgramPoint::Kind K, const ProgramPointTag *tag) 373 : StmtPoint(S, nullptr, K, L, tag) {} 374 375private: 376 friend class ProgramPoint; 377 static bool isKind(const ProgramPoint &location) { 378 unsigned k = location.getKind(); 379 return k == PreLoadKind || k == PreStoreKind; 380 } 381}; 382 383class PreLoad : public LocationCheck { 384public: 385 PreLoad(const Stmt *S, const LocationContext *L, 386 const ProgramPointTag *tag = nullptr) 387 : LocationCheck(S, L, PreLoadKind, tag) {} 388 389private: 390 friend class ProgramPoint; 391 PreLoad() = default; 392 static bool isKind(const ProgramPoint &location) { 393 return location.getKind() == PreLoadKind; 394 } 395}; 396 397class PreStore : public LocationCheck { 398public: 399 PreStore(const Stmt *S, const LocationContext *L, 400 const ProgramPointTag *tag = nullptr) 401 : LocationCheck(S, L, PreStoreKind, tag) {} 402 403private: 404 friend class ProgramPoint; 405 PreStore() = default; 406 static bool isKind(const ProgramPoint &location) { 407 return location.getKind() == PreStoreKind; 408 } 409}; 410 411class PostLoad : public PostStmt { 412public: 413 PostLoad(const Stmt *S, const LocationContext *L, 414 const ProgramPointTag *tag = nullptr) 415 : PostStmt(S, PostLoadKind, L, tag) {} 416 417private: 418 friend class ProgramPoint; 419 PostLoad() = default; 420 static bool isKind(const ProgramPoint &Location) { 421 return Location.getKind() == PostLoadKind; 422 } 423}; 424 425/// Represents a program point after a store evaluation. 426class PostStore : public PostStmt { 427public: 428 /// Construct the post store point. 429 /// \param Loc can be used to store the information about the location 430 /// used in the form it was uttered in the code. 431 PostStore(const Stmt *S, const LocationContext *L, const void *Loc, 432 const ProgramPointTag *tag = nullptr) 433 : PostStmt(S, PostStoreKind, L, tag) { 434 assert(getData2() == nullptr); 435 setData2(Loc); 436 } 437 438 /// Returns the information about the location used in the store, 439 /// how it was uttered in the code. 440 const void *getLocationValue() const { 441 return getData2(); 442 } 443 444private: 445 friend class ProgramPoint; 446 PostStore() = default; 447 static bool isKind(const ProgramPoint &Location) { 448 return Location.getKind() == PostStoreKind; 449 } 450}; 451 452class PostLValue : public PostStmt { 453public: 454 PostLValue(const Stmt *S, const LocationContext *L, 455 const ProgramPointTag *tag = nullptr) 456 : PostStmt(S, PostLValueKind, L, tag) {} 457 458private: 459 friend class ProgramPoint; 460 PostLValue() = default; 461 static bool isKind(const ProgramPoint &Location) { 462 return Location.getKind() == PostLValueKind; 463 } 464}; 465 466/// Represents a point after we ran remove dead bindings BEFORE 467/// processing the given statement. 468class PreStmtPurgeDeadSymbols : public StmtPoint { 469public: 470 PreStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L, 471 const ProgramPointTag *tag = nullptr) 472 : StmtPoint(S, nullptr, PreStmtPurgeDeadSymbolsKind, L, tag) { } 473 474private: 475 friend class ProgramPoint; 476 PreStmtPurgeDeadSymbols() = default; 477 static bool isKind(const ProgramPoint &Location) { 478 return Location.getKind() == PreStmtPurgeDeadSymbolsKind; 479 } 480}; 481 482/// Represents a point after we ran remove dead bindings AFTER 483/// processing the given statement. 484class PostStmtPurgeDeadSymbols : public StmtPoint { 485public: 486 PostStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L, 487 const ProgramPointTag *tag = nullptr) 488 : StmtPoint(S, nullptr, PostStmtPurgeDeadSymbolsKind, L, tag) { } 489 490private: 491 friend class ProgramPoint; 492 PostStmtPurgeDeadSymbols() = default; 493 static bool isKind(const ProgramPoint &Location) { 494 return Location.getKind() == PostStmtPurgeDeadSymbolsKind; 495 } 496}; 497 498class BlockEdge : public ProgramPoint { 499public: 500 BlockEdge(const CFGBlock *B1, const CFGBlock *B2, const LocationContext *L) 501 : ProgramPoint(B1, B2, BlockEdgeKind, L) { 502 assert(B1 && "BlockEdge: source block must be non-null"); 503 assert(B2 && "BlockEdge: destination block must be non-null"); 504 } 505 506 const CFGBlock *getSrc() const { 507 return static_cast<const CFGBlock*>(getData1()); 508 } 509 510 const CFGBlock *getDst() const { 511 return static_cast<const CFGBlock*>(getData2()); 512 } 513 514private: 515 friend class ProgramPoint; 516 BlockEdge() = default; 517 static bool isKind(const ProgramPoint &Location) { 518 return Location.getKind() == BlockEdgeKind; 519 } 520}; 521 522class PostInitializer : public ProgramPoint { 523public: 524 /// Construct a PostInitializer point that represents a location after 525 /// CXXCtorInitializer expression evaluation. 526 /// 527 /// \param I The initializer. 528 /// \param Loc The location of the field being initialized. 529 PostInitializer(const CXXCtorInitializer *I, 530 const void *Loc, 531 const LocationContext *L) 532 : ProgramPoint(I, Loc, PostInitializerKind, L) {} 533 534 const CXXCtorInitializer *getInitializer() const { 535 return static_cast<const CXXCtorInitializer *>(getData1()); 536 } 537 538 /// Returns the location of the field. 539 const void *getLocationValue() const { 540 return getData2(); 541 } 542 543private: 544 friend class ProgramPoint; 545 PostInitializer() = default; 546 static bool isKind(const ProgramPoint &Location) { 547 return Location.getKind() == PostInitializerKind; 548 } 549}; 550 551/// Represents an implicit call event. 552/// 553/// The nearest statement is provided for diagnostic purposes. 554class ImplicitCallPoint : public ProgramPoint { 555public: 556 ImplicitCallPoint(const Decl *D, SourceLocation Loc, Kind K, 557 const LocationContext *L, const ProgramPointTag *Tag, 558 CFGBlock::ConstCFGElementRef ElemRef) 559 : ProgramPoint(Loc.getPtrEncoding(), D, K, L, Tag, ElemRef) {} 560 561 const Decl *getDecl() const { return static_cast<const Decl *>(getData2()); } 562 SourceLocation getLocation() const { 563 return SourceLocation::getFromPtrEncoding(getData1()); 564 } 565 566protected: 567 ImplicitCallPoint() = default; 568private: 569 friend class ProgramPoint; 570 static bool isKind(const ProgramPoint &Location) { 571 return Location.getKind() >= MinImplicitCallKind && 572 Location.getKind() <= MaxImplicitCallKind; 573 } 574}; 575 576/// Represents a program point just before an implicit call event. 577/// 578/// Explicit calls will appear as PreStmt program points. 579class PreImplicitCall : public ImplicitCallPoint { 580public: 581 PreImplicitCall(const Decl *D, SourceLocation Loc, const LocationContext *L, 582 CFGBlock::ConstCFGElementRef ElemRef, 583 const ProgramPointTag *Tag = nullptr) 584 : ImplicitCallPoint(D, Loc, PreImplicitCallKind, L, Tag, ElemRef) {} 585 586private: 587 friend class ProgramPoint; 588 PreImplicitCall() = default; 589 static bool isKind(const ProgramPoint &Location) { 590 return Location.getKind() == PreImplicitCallKind; 591 } 592}; 593 594/// Represents a program point just after an implicit call event. 595/// 596/// Explicit calls will appear as PostStmt program points. 597class PostImplicitCall : public ImplicitCallPoint { 598public: 599 PostImplicitCall(const Decl *D, SourceLocation Loc, const LocationContext *L, 600 CFGBlock::ConstCFGElementRef ElemRef, 601 const ProgramPointTag *Tag = nullptr) 602 : ImplicitCallPoint(D, Loc, PostImplicitCallKind, L, Tag, ElemRef) {} 603 604private: 605 friend class ProgramPoint; 606 PostImplicitCall() = default; 607 static bool isKind(const ProgramPoint &Location) { 608 return Location.getKind() == PostImplicitCallKind; 609 } 610}; 611 612class PostAllocatorCall : public StmtPoint { 613public: 614 PostAllocatorCall(const Stmt *S, const LocationContext *L, 615 const ProgramPointTag *Tag = nullptr) 616 : StmtPoint(S, nullptr, PostAllocatorCallKind, L, Tag) {} 617 618private: 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. 628class CallEnter : public ProgramPoint { 629public: 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 649private: 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 666class CallExitBegin : public ProgramPoint { 667public: 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 676private: 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 686class CallExitEnd : public ProgramPoint { 687public: 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 697private: 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. 711class LoopExit : public ProgramPoint { 712public: 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 720private: 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. 730class EpsilonPoint : public ProgramPoint { 731public: 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 739private: 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 750namespace llvm { // Traits specialization for DenseMap 751 752template <> struct DenseMapInfo<clang::ProgramPoint> { 753 754static 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 760static 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 766static unsigned getHashValue(const clang::ProgramPoint &Loc) { 767 return Loc.getHashValue(); 768} 769 770static 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