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