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