ProgramPoint.h revision 7a95de68c093991047ed8d339479ccad51b88663
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 31namespace clang { 32 33class AnalysisDeclContext; 34class FunctionDecl; 35class LocationContext; 36class ProgramPointTag; 37 38class ProgramPoint { 39public: 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 65private: 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 75protected: 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 100protected: 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 105public: 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 TypeLoc type, asserting that this TypeLoc 114 /// 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 TypeLoc type, returning a null TypeLoc if 125 /// this TypeLoc 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 193class BlockEntrance : public ProgramPoint { 194public: 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 const CFGElement getFirstElement() const { 206 const CFGBlock *B = getBlock(); 207 return B->empty() ? CFGElement() : B->front(); 208 } 209 210private: 211 friend class ProgramPoint; 212 BlockEntrance() {} 213 static bool isKind(const ProgramPoint &Location) { 214 return Location.getKind() == BlockEntranceKind; 215 } 216}; 217 218class BlockExit : public ProgramPoint { 219public: 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 231private: 232 friend class ProgramPoint; 233 BlockExit() {} 234 static bool isKind(const ProgramPoint &Location) { 235 return Location.getKind() == BlockExitKind; 236 } 237}; 238 239class StmtPoint : public ProgramPoint { 240public: 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 252protected: 253 StmtPoint() {} 254private: 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 263class PreStmt : public StmtPoint { 264public: 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 271private: 272 friend class ProgramPoint; 273 PreStmt() {} 274 static bool isKind(const ProgramPoint &Location) { 275 return Location.getKind() == PreStmtKind; 276 } 277}; 278 279class PostStmt : public StmtPoint { 280protected: 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 286public: 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 295private: 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. 304class PostCondition : public PostStmt { 305public: 306 PostCondition(const Stmt *S, const LocationContext *L, 307 const ProgramPointTag *tag = 0) 308 : PostStmt(S, PostConditionKind, L, tag) {} 309 310private: 311 friend class ProgramPoint; 312 PostCondition() {} 313 static bool isKind(const ProgramPoint &Location) { 314 return Location.getKind() == PostConditionKind; 315 } 316}; 317 318class LocationCheck : public StmtPoint { 319protected: 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 325private: 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 333class PreLoad : public LocationCheck { 334public: 335 PreLoad(const Stmt *S, const LocationContext *L, 336 const ProgramPointTag *tag = 0) 337 : LocationCheck(S, L, PreLoadKind, tag) {} 338 339private: 340 friend class ProgramPoint; 341 PreLoad() {} 342 static bool isKind(const ProgramPoint &location) { 343 return location.getKind() == PreLoadKind; 344 } 345}; 346 347class PreStore : public LocationCheck { 348public: 349 PreStore(const Stmt *S, const LocationContext *L, 350 const ProgramPointTag *tag = 0) 351 : LocationCheck(S, L, PreStoreKind, tag) {} 352 353private: 354 friend class ProgramPoint; 355 PreStore() {} 356 static bool isKind(const ProgramPoint &location) { 357 return location.getKind() == PreStoreKind; 358 } 359}; 360 361class PostLoad : public PostStmt { 362public: 363 PostLoad(const Stmt *S, const LocationContext *L, 364 const ProgramPointTag *tag = 0) 365 : PostStmt(S, PostLoadKind, L, tag) {} 366 367private: 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. 376class PostStore : public PostStmt { 377public: 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 394private: 395 friend class ProgramPoint; 396 PostStore() {} 397 static bool isKind(const ProgramPoint &Location) { 398 return Location.getKind() == PostStoreKind; 399 } 400}; 401 402class PostLValue : public PostStmt { 403public: 404 PostLValue(const Stmt *S, const LocationContext *L, 405 const ProgramPointTag *tag = 0) 406 : PostStmt(S, PostLValueKind, L, tag) {} 407 408private: 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. 418class PreStmtPurgeDeadSymbols : public StmtPoint { 419public: 420 PreStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L, 421 const ProgramPointTag *tag = 0) 422 : StmtPoint(S, 0, PreStmtPurgeDeadSymbolsKind, L, tag) { } 423 424private: 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. 434class PostStmtPurgeDeadSymbols : public StmtPoint { 435public: 436 PostStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L, 437 const ProgramPointTag *tag = 0) 438 : StmtPoint(S, 0, PostStmtPurgeDeadSymbolsKind, L, tag) { } 439 440private: 441 friend class ProgramPoint; 442 PostStmtPurgeDeadSymbols() {} 443 static bool isKind(const ProgramPoint &Location) { 444 return Location.getKind() == PostStmtPurgeDeadSymbolsKind; 445 } 446}; 447 448class BlockEdge : public ProgramPoint { 449public: 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 464private: 465 friend class ProgramPoint; 466 BlockEdge() {} 467 static bool isKind(const ProgramPoint &Location) { 468 return Location.getKind() == BlockEdgeKind; 469 } 470}; 471 472class PostInitializer : public ProgramPoint { 473public: 474 PostInitializer(const CXXCtorInitializer *I, 475 const LocationContext *L) 476 : ProgramPoint(I, PostInitializerKind, L) {} 477 478private: 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. 489class ImplicitCallPoint : public ProgramPoint { 490public: 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 500protected: 501 ImplicitCallPoint() {} 502private: 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. 513class PreImplicitCall : public ImplicitCallPoint { 514public: 515 PreImplicitCall(const Decl *D, SourceLocation Loc, 516 const LocationContext *L, const ProgramPointTag *Tag = 0) 517 : ImplicitCallPoint(D, Loc, PreImplicitCallKind, L, Tag) {} 518 519private: 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. 530class PostImplicitCall : public ImplicitCallPoint { 531public: 532 PostImplicitCall(const Decl *D, SourceLocation Loc, 533 const LocationContext *L, const ProgramPointTag *Tag = 0) 534 : ImplicitCallPoint(D, Loc, PostImplicitCallKind, L, Tag) {} 535 536private: 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. 546class CallEnter : public ProgramPoint { 547public: 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 560private: 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 577class CallExitBegin : public ProgramPoint { 578public: 579 // CallExitBegin uses the callee's location context. 580 CallExitBegin(const StackFrameContext *L) 581 : ProgramPoint(0, CallExitBeginKind, L, 0) {} 582 583private: 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 593class CallExitEnd : public ProgramPoint { 594public: 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 604private: 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. 614class EpsilonPoint : public ProgramPoint { 615public: 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 622private: 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. 633class ProgramPointTag { 634public: 635 ProgramPointTag(void *tagKind = 0) : TagKind(tagKind) {} 636 virtual ~ProgramPointTag(); 637 virtual StringRef getTagDescription() const = 0; 638 639protected: 640 /// Used to implement 'isKind' in subclasses. 641 const void *getTagKind() { return TagKind; } 642 643private: 644 const void *TagKind; 645}; 646 647class SimpleProgramPointTag : public ProgramPointTag { 648 std::string desc; 649public: 650 SimpleProgramPointTag(StringRef description); 651 StringRef getTagDescription() const; 652}; 653 654} // end namespace clang 655 656 657namespace llvm { // Traits specialization for DenseMap 658 659template <> struct DenseMapInfo<clang::ProgramPoint> { 660 661static 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 667static 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 673static unsigned getHashValue(const clang::ProgramPoint &Loc) { 674 return Loc.getHashValue(); 675} 676 677static bool isEqual(const clang::ProgramPoint &L, 678 const clang::ProgramPoint &R) { 679 return L == R; 680} 681 682}; 683 684template <> 685struct isPodLike<clang::ProgramPoint> { static const bool value = true; }; 686 687} // end namespace llvm 688 689#endif 690