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_PROGRAM_POINT 16 #define LLVM_CLANG_ANALYSIS_PROGRAM_POINT 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 = 0) 81 : Data1(P), 82 Data2(0, (((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 = 0) 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 = 0) 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 = 0) 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 = 0) 284 : StmtPoint(S, data, k, L, tag) {} 285 286 public: 287 explicit PostStmt(const Stmt *S, Kind k, 288 const LocationContext *L, const ProgramPointTag *tag = 0) 289 : StmtPoint(S, NULL, k, L, tag) {} 290 291 explicit PostStmt(const Stmt *S, const LocationContext *L, 292 const ProgramPointTag *tag = 0) 293 : StmtPoint(S, NULL, 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 = 0) 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, NULL, 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 = 0) 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 = 0) 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 = 0) 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 = 0) 383 : PostStmt(S, PostStoreKind, L, tag) { 384 assert(getData2() == 0); 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 = 0) 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 = 0) 422 : StmtPoint(S, 0, 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 = 0) 438 : StmtPoint(S, 0, 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 PostInitializer(const CXXCtorInitializer *I, 475 const LocationContext *L) 476 : ProgramPoint(I, PostInitializerKind, L) {} 477 478 private: 479 friend class ProgramPoint; 480 PostInitializer() {} 481 static bool isKind(const ProgramPoint &Location) { 482 return Location.getKind() == PostInitializerKind; 483 } 484 }; 485 486 /// Represents an implicit call event. 487 /// 488 /// The nearest statement is provided for diagnostic purposes. 489 class ImplicitCallPoint : public ProgramPoint { 490 public: 491 ImplicitCallPoint(const Decl *D, SourceLocation Loc, Kind K, 492 const LocationContext *L, const ProgramPointTag *Tag) 493 : ProgramPoint(Loc.getPtrEncoding(), D, K, L, Tag) {} 494 495 const Decl *getDecl() const { return static_cast<const Decl *>(getData2()); } 496 SourceLocation getLocation() const { 497 return SourceLocation::getFromPtrEncoding(getData1()); 498 } 499 500 protected: 501 ImplicitCallPoint() {} 502 private: 503 friend class ProgramPoint; 504 static bool isKind(const ProgramPoint &Location) { 505 return Location.getKind() >= MinImplicitCallKind && 506 Location.getKind() <= MaxImplicitCallKind; 507 } 508 }; 509 510 /// Represents a program point just before an implicit call event. 511 /// 512 /// Explicit calls will appear as PreStmt program points. 513 class PreImplicitCall : public ImplicitCallPoint { 514 public: 515 PreImplicitCall(const Decl *D, SourceLocation Loc, 516 const LocationContext *L, const ProgramPointTag *Tag = 0) 517 : ImplicitCallPoint(D, Loc, PreImplicitCallKind, L, Tag) {} 518 519 private: 520 friend class ProgramPoint; 521 PreImplicitCall() {} 522 static bool isKind(const ProgramPoint &Location) { 523 return Location.getKind() == PreImplicitCallKind; 524 } 525 }; 526 527 /// Represents a program point just after an implicit call event. 528 /// 529 /// Explicit calls will appear as PostStmt program points. 530 class PostImplicitCall : public ImplicitCallPoint { 531 public: 532 PostImplicitCall(const Decl *D, SourceLocation Loc, 533 const LocationContext *L, const ProgramPointTag *Tag = 0) 534 : ImplicitCallPoint(D, Loc, PostImplicitCallKind, L, Tag) {} 535 536 private: 537 friend class ProgramPoint; 538 PostImplicitCall() {} 539 static bool isKind(const ProgramPoint &Location) { 540 return Location.getKind() == PostImplicitCallKind; 541 } 542 }; 543 544 /// Represents a point when we begin processing an inlined call. 545 /// CallEnter uses the caller's location context. 546 class CallEnter : public ProgramPoint { 547 public: 548 CallEnter(const Stmt *stmt, const StackFrameContext *calleeCtx, 549 const LocationContext *callerCtx) 550 : ProgramPoint(stmt, calleeCtx, CallEnterKind, callerCtx, 0) {} 551 552 const Stmt *getCallExpr() const { 553 return static_cast<const Stmt *>(getData1()); 554 } 555 556 const StackFrameContext *getCalleeContext() const { 557 return static_cast<const StackFrameContext *>(getData2()); 558 } 559 560 private: 561 friend class ProgramPoint; 562 CallEnter() {} 563 static bool isKind(const ProgramPoint &Location) { 564 return Location.getKind() == CallEnterKind; 565 } 566 }; 567 568 /// Represents a point when we start the call exit sequence (for inlined call). 569 /// 570 /// The call exit is simulated with a sequence of nodes, which occur between 571 /// CallExitBegin and CallExitEnd. The following operations occur between the 572 /// two program points: 573 /// - CallExitBegin 574 /// - Bind the return value 575 /// - Run Remove dead bindings (to clean up the dead symbols from the callee). 576 /// - CallExitEnd 577 class CallExitBegin : public ProgramPoint { 578 public: 579 // CallExitBegin uses the callee's location context. 580 CallExitBegin(const StackFrameContext *L) 581 : ProgramPoint(0, CallExitBeginKind, L, 0) {} 582 583 private: 584 friend class ProgramPoint; 585 CallExitBegin() {} 586 static bool isKind(const ProgramPoint &Location) { 587 return Location.getKind() == CallExitBeginKind; 588 } 589 }; 590 591 /// Represents a point when we finish the call exit sequence (for inlined call). 592 /// \sa CallExitBegin 593 class CallExitEnd : public ProgramPoint { 594 public: 595 // CallExitEnd uses the caller's location context. 596 CallExitEnd(const StackFrameContext *CalleeCtx, 597 const LocationContext *CallerCtx) 598 : ProgramPoint(CalleeCtx, CallExitEndKind, CallerCtx, 0) {} 599 600 const StackFrameContext *getCalleeContext() const { 601 return static_cast<const StackFrameContext *>(getData1()); 602 } 603 604 private: 605 friend class ProgramPoint; 606 CallExitEnd() {} 607 static bool isKind(const ProgramPoint &Location) { 608 return Location.getKind() == CallExitEndKind; 609 } 610 }; 611 612 /// This is a meta program point, which should be skipped by all the diagnostic 613 /// reasoning etc. 614 class EpsilonPoint : public ProgramPoint { 615 public: 616 EpsilonPoint(const LocationContext *L, const void *Data1, 617 const void *Data2 = 0, const ProgramPointTag *tag = 0) 618 : ProgramPoint(Data1, Data2, EpsilonKind, L, tag) {} 619 620 const void *getData() const { return getData1(); } 621 622 private: 623 friend class ProgramPoint; 624 EpsilonPoint() {} 625 static bool isKind(const ProgramPoint &Location) { 626 return Location.getKind() == EpsilonKind; 627 } 628 }; 629 630 /// ProgramPoints can be "tagged" as representing points specific to a given 631 /// analysis entity. Tags are abstract annotations, with an associated 632 /// description and potentially other information. 633 class ProgramPointTag { 634 public: 635 ProgramPointTag(void *tagKind = 0) : TagKind(tagKind) {} 636 virtual ~ProgramPointTag(); 637 virtual StringRef getTagDescription() const = 0; 638 639 protected: 640 /// Used to implement 'isKind' in subclasses. 641 const void *getTagKind() { return TagKind; } 642 643 private: 644 const void *TagKind; 645 }; 646 647 class SimpleProgramPointTag : public ProgramPointTag { 648 std::string desc; 649 public: 650 SimpleProgramPointTag(StringRef description); 651 StringRef getTagDescription() const; 652 }; 653 654 } // end namespace clang 655 656 657 namespace llvm { // Traits specialization for DenseMap 658 659 template <> struct DenseMapInfo<clang::ProgramPoint> { 660 661 static inline clang::ProgramPoint getEmptyKey() { 662 uintptr_t x = 663 reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getEmptyKey()) & ~0x7; 664 return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), 0); 665 } 666 667 static inline clang::ProgramPoint getTombstoneKey() { 668 uintptr_t x = 669 reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getTombstoneKey()) & ~0x7; 670 return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), 0); 671 } 672 673 static unsigned getHashValue(const clang::ProgramPoint &Loc) { 674 return Loc.getHashValue(); 675 } 676 677 static bool isEqual(const clang::ProgramPoint &L, 678 const clang::ProgramPoint &R) { 679 return L == R; 680 } 681 682 }; 683 684 template <> 685 struct isPodLike<clang::ProgramPoint> { static const bool value = true; }; 686 687 } // end namespace llvm 688 689 #endif 690