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