1193326Sed//==- ProgramPoint.h - Program Points for Path-Sensitive Analysis --*- C++ -*-// 2193326Sed// 3193326Sed// The LLVM Compiler Infrastructure 4193326Sed// 5193326Sed// This file is distributed under the University of Illinois Open Source 6193326Sed// License. See LICENSE.TXT for details. 7193326Sed// 8193326Sed//===----------------------------------------------------------------------===// 9193326Sed// 10193326Sed// This file defines the interface ProgramPoint, which identifies a 11193326Sed// distinct location in a function. 12193326Sed// 13193326Sed//===----------------------------------------------------------------------===// 14193326Sed 15193326Sed#ifndef LLVM_CLANG_ANALYSIS_PROGRAM_POINT 16193326Sed#define LLVM_CLANG_ANALYSIS_PROGRAM_POINT 17193326Sed 18212904Sdim#include "clang/Analysis/AnalysisContext.h" 19198092Srdivacky#include "clang/Analysis/CFG.h" 20193326Sed#include "llvm/ADT/DenseMap.h" 21249423Sdim#include "llvm/ADT/FoldingSet.h" 22249423Sdim#include "llvm/ADT/Optional.h" 23234353Sdim#include "llvm/ADT/PointerIntPair.h" 24249423Sdim#include "llvm/ADT/StringRef.h" 25193326Sed#include "llvm/Support/Casting.h" 26249423Sdim#include "llvm/Support/DataTypes.h" 27193326Sed#include <cassert> 28249423Sdim#include <string> 29193326Sed#include <utility> 30193326Sed 31193326Sednamespace clang { 32198092Srdivacky 33234353Sdimclass AnalysisDeclContext; 34204643Srdivackyclass FunctionDecl; 35226633Sdimclass LocationContext; 36226633Sdimclass ProgramPointTag; 37226633Sdim 38193326Sedclass ProgramPoint { 39193326Sedpublic: 40198092Srdivacky enum Kind { BlockEdgeKind, 41198092Srdivacky BlockEntranceKind, 42198092Srdivacky BlockExitKind, 43198092Srdivacky PreStmtKind, 44239462Sdim PreStmtPurgeDeadSymbolsKind, 45239462Sdim PostStmtPurgeDeadSymbolsKind, 46198092Srdivacky PostStmtKind, 47199482Srdivacky PreLoadKind, 48198092Srdivacky PostLoadKind, 49199482Srdivacky PreStoreKind, 50198092Srdivacky PostStoreKind, 51221345Sdim PostConditionKind, 52198092Srdivacky PostLValueKind, 53239462Sdim MinPostStmtKind = PostStmtKind, 54239462Sdim MaxPostStmtKind = PostLValueKind, 55218893Sdim PostInitializerKind, 56204643Srdivacky CallEnterKind, 57239462Sdim CallExitBeginKind, 58239462Sdim CallExitEndKind, 59239462Sdim PreImplicitCallKind, 60239462Sdim PostImplicitCallKind, 61239462Sdim MinImplicitCallKind = PreImplicitCallKind, 62239462Sdim MaxImplicitCallKind = PostImplicitCallKind, 63234353Sdim EpsilonKind}; 64193326Sed 65193326Sedprivate: 66239462Sdim const void *Data1; 67234353Sdim llvm::PointerIntPair<const void *, 2, unsigned> Data2; 68198092Srdivacky 69198092Srdivacky // The LocationContext could be NULL to allow ProgramPoint to be used in 70198092Srdivacky // context insensitive analysis. 71234353Sdim llvm::PointerIntPair<const LocationContext *, 2, unsigned> L; 72234353Sdim 73239462Sdim llvm::PointerIntPair<const ProgramPointTag *, 2, unsigned> Tag; 74198092Srdivacky 75193326Sedprotected: 76249423Sdim ProgramPoint() {} 77234353Sdim ProgramPoint(const void *P, 78234353Sdim Kind k, 79234353Sdim const LocationContext *l, 80226633Sdim const ProgramPointTag *tag = 0) 81239462Sdim : Data1(P), 82239462Sdim Data2(0, (((unsigned) k) >> 0) & 0x3), 83239462Sdim L(l, (((unsigned) k) >> 2) & 0x3), 84239462Sdim Tag(tag, (((unsigned) k) >> 4) & 0x3) { 85234353Sdim assert(getKind() == k); 86234353Sdim assert(getLocationContext() == l); 87234353Sdim assert(getData1() == P); 88234353Sdim } 89234353Sdim 90234353Sdim ProgramPoint(const void *P1, 91234353Sdim const void *P2, 92234353Sdim Kind k, 93234353Sdim const LocationContext *l, 94226633Sdim const ProgramPointTag *tag = 0) 95239462Sdim : Data1(P1), 96239462Sdim Data2(P2, (((unsigned) k) >> 0) & 0x3), 97239462Sdim L(l, (((unsigned) k) >> 2) & 0x3), 98239462Sdim Tag(tag, (((unsigned) k) >> 4) & 0x3) {} 99193326Sed 100193326Sedprotected: 101239462Sdim const void *getData1() const { return Data1; } 102234353Sdim const void *getData2() const { return Data2.getPointer(); } 103234353Sdim void setData2(const void *d) { Data2.setPointer(d); } 104193326Sed 105198092Srdivackypublic: 106226633Sdim /// Create a new ProgramPoint object that is the same as the original 107226633Sdim /// except for using the specified tag value. 108226633Sdim ProgramPoint withTag(const ProgramPointTag *tag) const { 109234353Sdim return ProgramPoint(getData1(), getData2(), getKind(), 110234353Sdim getLocationContext(), tag); 111226633Sdim } 112226633Sdim 113249423Sdim /// \brief Convert to the specified ProgramPoint type, asserting that this 114249423Sdim /// ProgramPoint is of the desired type. 115249423Sdim template<typename T> 116249423Sdim T castAs() const { 117249423Sdim assert(T::isKind(*this)); 118249423Sdim T t; 119249423Sdim ProgramPoint& PP = t; 120249423Sdim PP = *this; 121249423Sdim return t; 122249423Sdim } 123249423Sdim 124249423Sdim /// \brief Convert to the specified ProgramPoint type, returning None if this 125249423Sdim /// ProgramPoint is not of the desired type. 126249423Sdim template<typename T> 127249423Sdim Optional<T> getAs() const { 128249423Sdim if (!T::isKind(*this)) 129249423Sdim return None; 130249423Sdim T t; 131249423Sdim ProgramPoint& PP = t; 132249423Sdim PP = *this; 133249423Sdim return t; 134249423Sdim } 135249423Sdim 136234353Sdim Kind getKind() const { 137239462Sdim unsigned x = Tag.getInt(); 138234353Sdim x <<= 2; 139239462Sdim x |= L.getInt(); 140239462Sdim x <<= 2; 141234353Sdim x |= Data2.getInt(); 142234353Sdim return (Kind) x; 143234353Sdim } 144198092Srdivacky 145239462Sdim /// \brief Is this a program point corresponding to purge/removal of dead 146239462Sdim /// symbols and bindings. 147239462Sdim bool isPurgeKind() { 148239462Sdim Kind K = getKind(); 149239462Sdim return (K == PostStmtPurgeDeadSymbolsKind || 150239462Sdim K == PreStmtPurgeDeadSymbolsKind); 151239462Sdim } 152218893Sdim 153239462Sdim const ProgramPointTag *getTag() const { return Tag.getPointer(); } 154239462Sdim 155234353Sdim const LocationContext *getLocationContext() const { 156234353Sdim return L.getPointer(); 157234353Sdim } 158198092Srdivacky 159193326Sed // For use with DenseMap. This hash is probably slow. 160193326Sed unsigned getHashValue() const { 161193326Sed llvm::FoldingSetNodeID ID; 162198092Srdivacky Profile(ID); 163193326Sed return ID.ComputeHash(); 164193326Sed } 165198092Srdivacky 166193326Sed bool operator==(const ProgramPoint & RHS) const { 167234982Sdim return Data1 == RHS.Data1 && 168234353Sdim Data2 == RHS.Data2 && 169234353Sdim L == RHS.L && 170234353Sdim Tag == RHS.Tag; 171193326Sed } 172193326Sed 173226633Sdim bool operator!=(const ProgramPoint &RHS) const { 174234353Sdim return Data1 != RHS.Data1 || 175234353Sdim Data2 != RHS.Data2 || 176234353Sdim L != RHS.L || 177234353Sdim Tag != RHS.Tag; 178193326Sed } 179198092Srdivacky 180193326Sed void Profile(llvm::FoldingSetNodeID& ID) const { 181234353Sdim ID.AddInteger((unsigned) getKind()); 182234353Sdim ID.AddPointer(getData1()); 183234353Sdim ID.AddPointer(getData2()); 184234353Sdim ID.AddPointer(getLocationContext()); 185239462Sdim ID.AddPointer(getTag()); 186193326Sed } 187226633Sdim 188226633Sdim static ProgramPoint getProgramPoint(const Stmt *S, ProgramPoint::Kind K, 189226633Sdim const LocationContext *LC, 190226633Sdim const ProgramPointTag *tag); 191193326Sed}; 192198092Srdivacky 193193326Sedclass BlockEntrance : public ProgramPoint { 194193326Sedpublic: 195226633Sdim BlockEntrance(const CFGBlock *B, const LocationContext *L, 196226633Sdim const ProgramPointTag *tag = 0) 197226633Sdim : ProgramPoint(B, BlockEntranceKind, L, tag) { 198226633Sdim assert(B && "BlockEntrance requires non-null block"); 199226633Sdim } 200198092Srdivacky 201226633Sdim const CFGBlock *getBlock() const { 202212904Sdim return reinterpret_cast<const CFGBlock*>(getData1()); 203193326Sed } 204198092Srdivacky 205249423Sdim Optional<CFGElement> getFirstElement() const { 206226633Sdim const CFGBlock *B = getBlock(); 207249423Sdim return B->empty() ? Optional<CFGElement>() : B->front(); 208193326Sed } 209201361Srdivacky 210249423Sdimprivate: 211249423Sdim friend class ProgramPoint; 212249423Sdim BlockEntrance() {} 213249423Sdim static bool isKind(const ProgramPoint &Location) { 214249423Sdim return Location.getKind() == BlockEntranceKind; 215193326Sed } 216193326Sed}; 217193326Sed 218193326Sedclass BlockExit : public ProgramPoint { 219193326Sedpublic: 220226633Sdim BlockExit(const CFGBlock *B, const LocationContext *L) 221198092Srdivacky : ProgramPoint(B, BlockExitKind, L) {} 222198092Srdivacky 223226633Sdim const CFGBlock *getBlock() const { 224212904Sdim return reinterpret_cast<const CFGBlock*>(getData1()); 225193326Sed } 226193326Sed 227226633Sdim const Stmt *getTerminator() const { 228193326Sed return getBlock()->getTerminator(); 229193326Sed } 230198092Srdivacky 231249423Sdimprivate: 232249423Sdim friend class ProgramPoint; 233249423Sdim BlockExit() {} 234249423Sdim static bool isKind(const ProgramPoint &Location) { 235249423Sdim return Location.getKind() == BlockExitKind; 236193326Sed } 237193326Sed}; 238193326Sed 239198092Srdivackyclass StmtPoint : public ProgramPoint { 240198092Srdivackypublic: 241198092Srdivacky StmtPoint(const Stmt *S, const void *p2, Kind k, const LocationContext *L, 242226633Sdim const ProgramPointTag *tag) 243243830Sdim : ProgramPoint(S, p2, k, L, tag) { 244243830Sdim assert(S); 245243830Sdim } 246193326Sed 247198092Srdivacky const Stmt *getStmt() const { return (const Stmt*) getData1(); } 248198092Srdivacky 249198092Srdivacky template <typename T> 250249423Sdim const T* getStmtAs() const { return dyn_cast<T>(getStmt()); } 251198092Srdivacky 252249423Sdimprotected: 253249423Sdim StmtPoint() {} 254249423Sdimprivate: 255249423Sdim friend class ProgramPoint; 256249423Sdim static bool isKind(const ProgramPoint &Location) { 257249423Sdim unsigned k = Location.getKind(); 258198092Srdivacky return k >= PreStmtKind && k <= MaxPostStmtKind; 259198092Srdivacky } 260198092Srdivacky}; 261198092Srdivacky 262198092Srdivacky 263198092Srdivackyclass PreStmt : public StmtPoint { 264193326Sedpublic: 265226633Sdim PreStmt(const Stmt *S, const LocationContext *L, const ProgramPointTag *tag, 266198092Srdivacky const Stmt *SubStmt = 0) 267198092Srdivacky : StmtPoint(S, SubStmt, PreStmtKind, L, tag) {} 268193326Sed 269198092Srdivacky const Stmt *getSubStmt() const { return (const Stmt*) getData2(); } 270193326Sed 271249423Sdimprivate: 272249423Sdim friend class ProgramPoint; 273249423Sdim PreStmt() {} 274249423Sdim static bool isKind(const ProgramPoint &Location) { 275249423Sdim return Location.getKind() == PreStmtKind; 276198092Srdivacky } 277198092Srdivacky}; 278198092Srdivacky 279198092Srdivackyclass PostStmt : public StmtPoint { 280198092Srdivackyprotected: 281249423Sdim PostStmt() {} 282226633Sdim PostStmt(const Stmt *S, const void *data, Kind k, const LocationContext *L, 283234353Sdim const ProgramPointTag *tag = 0) 284198092Srdivacky : StmtPoint(S, data, k, L, tag) {} 285198092Srdivacky 286198092Srdivackypublic: 287226633Sdim explicit PostStmt(const Stmt *S, Kind k, 288226633Sdim const LocationContext *L, const ProgramPointTag *tag = 0) 289218893Sdim : StmtPoint(S, NULL, k, L, tag) {} 290218893Sdim 291226633Sdim explicit PostStmt(const Stmt *S, const LocationContext *L, 292226633Sdim const ProgramPointTag *tag = 0) 293198092Srdivacky : StmtPoint(S, NULL, PostStmtKind, L, tag) {} 294198092Srdivacky 295249423Sdimprivate: 296249423Sdim friend class ProgramPoint; 297249423Sdim static bool isKind(const ProgramPoint &Location) { 298249423Sdim unsigned k = Location.getKind(); 299193326Sed return k >= MinPostStmtKind && k <= MaxPostStmtKind; 300193326Sed } 301193326Sed}; 302193326Sed 303221345Sdim// PostCondition represents the post program point of a branch condition. 304221345Sdimclass PostCondition : public PostStmt { 305221345Sdimpublic: 306226633Sdim PostCondition(const Stmt *S, const LocationContext *L, 307226633Sdim const ProgramPointTag *tag = 0) 308221345Sdim : PostStmt(S, PostConditionKind, L, tag) {} 309221345Sdim 310249423Sdimprivate: 311249423Sdim friend class ProgramPoint; 312249423Sdim PostCondition() {} 313249423Sdim static bool isKind(const ProgramPoint &Location) { 314249423Sdim return Location.getKind() == PostConditionKind; 315221345Sdim } 316221345Sdim}; 317221345Sdim 318199482Srdivackyclass LocationCheck : public StmtPoint { 319199482Srdivackyprotected: 320249423Sdim LocationCheck() {} 321199482Srdivacky LocationCheck(const Stmt *S, const LocationContext *L, 322226633Sdim ProgramPoint::Kind K, const ProgramPointTag *tag) 323199482Srdivacky : StmtPoint(S, NULL, K, L, tag) {} 324199482Srdivacky 325249423Sdimprivate: 326249423Sdim friend class ProgramPoint; 327249423Sdim static bool isKind(const ProgramPoint &location) { 328249423Sdim unsigned k = location.getKind(); 329199482Srdivacky return k == PreLoadKind || k == PreStoreKind; 330193326Sed } 331193326Sed}; 332199482Srdivacky 333199482Srdivackyclass PreLoad : public LocationCheck { 334193326Sedpublic: 335226633Sdim PreLoad(const Stmt *S, const LocationContext *L, 336226633Sdim const ProgramPointTag *tag = 0) 337199482Srdivacky : LocationCheck(S, L, PreLoadKind, tag) {} 338199482Srdivacky 339249423Sdimprivate: 340249423Sdim friend class ProgramPoint; 341249423Sdim PreLoad() {} 342249423Sdim static bool isKind(const ProgramPoint &location) { 343249423Sdim return location.getKind() == PreLoadKind; 344193326Sed } 345193326Sed}; 346198092Srdivacky 347199482Srdivackyclass PreStore : public LocationCheck { 348193326Sedpublic: 349226633Sdim PreStore(const Stmt *S, const LocationContext *L, 350226633Sdim const ProgramPointTag *tag = 0) 351199482Srdivacky : LocationCheck(S, L, PreStoreKind, tag) {} 352199482Srdivacky 353249423Sdimprivate: 354249423Sdim friend class ProgramPoint; 355249423Sdim PreStore() {} 356249423Sdim static bool isKind(const ProgramPoint &location) { 357249423Sdim return location.getKind() == PreStoreKind; 358193326Sed } 359193326Sed}; 360198092Srdivacky 361193326Sedclass PostLoad : public PostStmt { 362193326Sedpublic: 363226633Sdim PostLoad(const Stmt *S, const LocationContext *L, 364226633Sdim const ProgramPointTag *tag = 0) 365198092Srdivacky : PostStmt(S, PostLoadKind, L, tag) {} 366198092Srdivacky 367249423Sdimprivate: 368249423Sdim friend class ProgramPoint; 369249423Sdim PostLoad() {} 370249423Sdim static bool isKind(const ProgramPoint &Location) { 371249423Sdim return Location.getKind() == PostLoadKind; 372193326Sed } 373193326Sed}; 374198092Srdivacky 375239462Sdim/// \brief Represents a program point after a store evaluation. 376193326Sedclass PostStore : public PostStmt { 377193326Sedpublic: 378234353Sdim /// Construct the post store point. 379234353Sdim /// \param Loc can be used to store the information about the location 380234353Sdim /// used in the form it was uttered in the code. 381234353Sdim PostStore(const Stmt *S, const LocationContext *L, const void *Loc, 382226633Sdim const ProgramPointTag *tag = 0) 383234353Sdim : PostStmt(S, PostStoreKind, L, tag) { 384234353Sdim assert(getData2() == 0); 385234353Sdim setData2(Loc); 386234353Sdim } 387198092Srdivacky 388234353Sdim /// \brief Returns the information about the location used in the store, 389234353Sdim /// how it was uttered in the code. 390234353Sdim const void *getLocationValue() const { 391234353Sdim return getData2(); 392234353Sdim } 393234353Sdim 394249423Sdimprivate: 395249423Sdim friend class ProgramPoint; 396249423Sdim PostStore() {} 397249423Sdim static bool isKind(const ProgramPoint &Location) { 398249423Sdim return Location.getKind() == PostStoreKind; 399249423Sdim } 400193326Sed}; 401193326Sed 402193326Sedclass PostLValue : public PostStmt { 403193326Sedpublic: 404226633Sdim PostLValue(const Stmt *S, const LocationContext *L, 405226633Sdim const ProgramPointTag *tag = 0) 406198092Srdivacky : PostStmt(S, PostLValueKind, L, tag) {} 407198092Srdivacky 408249423Sdimprivate: 409249423Sdim friend class ProgramPoint; 410249423Sdim PostLValue() {} 411249423Sdim static bool isKind(const ProgramPoint &Location) { 412249423Sdim return Location.getKind() == PostLValueKind; 413193326Sed } 414198092Srdivacky}; 415198092Srdivacky 416239462Sdim/// Represents a point after we ran remove dead bindings BEFORE 417239462Sdim/// processing the given statement. 418239462Sdimclass PreStmtPurgeDeadSymbols : public StmtPoint { 419193326Sedpublic: 420239462Sdim PreStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L, 421226633Sdim const ProgramPointTag *tag = 0) 422239462Sdim : StmtPoint(S, 0, PreStmtPurgeDeadSymbolsKind, L, tag) { } 423198092Srdivacky 424249423Sdimprivate: 425249423Sdim friend class ProgramPoint; 426249423Sdim PreStmtPurgeDeadSymbols() {} 427249423Sdim static bool isKind(const ProgramPoint &Location) { 428249423Sdim return Location.getKind() == PreStmtPurgeDeadSymbolsKind; 429193326Sed } 430193326Sed}; 431198092Srdivacky 432239462Sdim/// Represents a point after we ran remove dead bindings AFTER 433239462Sdim/// processing the given statement. 434239462Sdimclass PostStmtPurgeDeadSymbols : public StmtPoint { 435239462Sdimpublic: 436239462Sdim PostStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L, 437239462Sdim const ProgramPointTag *tag = 0) 438239462Sdim : StmtPoint(S, 0, PostStmtPurgeDeadSymbolsKind, L, tag) { } 439239462Sdim 440249423Sdimprivate: 441249423Sdim friend class ProgramPoint; 442249423Sdim PostStmtPurgeDeadSymbols() {} 443249423Sdim static bool isKind(const ProgramPoint &Location) { 444249423Sdim return Location.getKind() == PostStmtPurgeDeadSymbolsKind; 445239462Sdim } 446239462Sdim}; 447239462Sdim 448193326Sedclass BlockEdge : public ProgramPoint { 449193326Sedpublic: 450226633Sdim BlockEdge(const CFGBlock *B1, const CFGBlock *B2, const LocationContext *L) 451226633Sdim : ProgramPoint(B1, B2, BlockEdgeKind, L) { 452226633Sdim assert(B1 && "BlockEdge: source block must be non-null"); 453226633Sdim assert(B2 && "BlockEdge: destination block must be non-null"); 454226633Sdim } 455198092Srdivacky 456226633Sdim const CFGBlock *getSrc() const { 457212904Sdim return static_cast<const CFGBlock*>(getData1()); 458193326Sed } 459198092Srdivacky 460226633Sdim const CFGBlock *getDst() const { 461212904Sdim return static_cast<const CFGBlock*>(getData2()); 462193326Sed } 463198092Srdivacky 464249423Sdimprivate: 465249423Sdim friend class ProgramPoint; 466249423Sdim BlockEdge() {} 467249423Sdim static bool isKind(const ProgramPoint &Location) { 468249423Sdim return Location.getKind() == BlockEdgeKind; 469193326Sed } 470193326Sed}; 471193326Sed 472218893Sdimclass PostInitializer : public ProgramPoint { 473218893Sdimpublic: 474249423Sdim /// \brief Construct a PostInitializer point that represents a location after 475249423Sdim /// CXXCtorInitializer expression evaluation. 476249423Sdim /// 477249423Sdim /// \param I The initializer. 478249423Sdim /// \param Loc The location of the field being initialized. 479249423Sdim PostInitializer(const CXXCtorInitializer *I, 480249423Sdim const void *Loc, 481218893Sdim const LocationContext *L) 482249423Sdim : ProgramPoint(I, Loc, PostInitializerKind, L) {} 483218893Sdim 484249423Sdim const CXXCtorInitializer *getInitializer() const { 485249423Sdim return static_cast<const CXXCtorInitializer *>(getData1()); 486218893Sdim } 487249423Sdim 488249423Sdim /// \brief Returns the location of the field. 489249423Sdim const void *getLocationValue() const { 490249423Sdim return getData2(); 491249423Sdim } 492249423Sdim 493249423Sdimprivate: 494249423Sdim friend class ProgramPoint; 495249423Sdim PostInitializer() {} 496249423Sdim static bool isKind(const ProgramPoint &Location) { 497249423Sdim return Location.getKind() == PostInitializerKind; 498249423Sdim } 499218893Sdim}; 500218893Sdim 501239462Sdim/// Represents an implicit call event. 502239462Sdim/// 503239462Sdim/// The nearest statement is provided for diagnostic purposes. 504239462Sdimclass ImplicitCallPoint : public ProgramPoint { 505204643Srdivackypublic: 506239462Sdim ImplicitCallPoint(const Decl *D, SourceLocation Loc, Kind K, 507239462Sdim const LocationContext *L, const ProgramPointTag *Tag) 508239462Sdim : ProgramPoint(Loc.getPtrEncoding(), D, K, L, Tag) {} 509239462Sdim 510239462Sdim const Decl *getDecl() const { return static_cast<const Decl *>(getData2()); } 511239462Sdim SourceLocation getLocation() const { 512239462Sdim return SourceLocation::getFromPtrEncoding(getData1()); 513239462Sdim } 514239462Sdim 515249423Sdimprotected: 516249423Sdim ImplicitCallPoint() {} 517249423Sdimprivate: 518249423Sdim friend class ProgramPoint; 519249423Sdim static bool isKind(const ProgramPoint &Location) { 520249423Sdim return Location.getKind() >= MinImplicitCallKind && 521249423Sdim Location.getKind() <= MaxImplicitCallKind; 522239462Sdim } 523239462Sdim}; 524239462Sdim 525239462Sdim/// Represents a program point just before an implicit call event. 526239462Sdim/// 527239462Sdim/// Explicit calls will appear as PreStmt program points. 528239462Sdimclass PreImplicitCall : public ImplicitCallPoint { 529239462Sdimpublic: 530239462Sdim PreImplicitCall(const Decl *D, SourceLocation Loc, 531239462Sdim const LocationContext *L, const ProgramPointTag *Tag = 0) 532239462Sdim : ImplicitCallPoint(D, Loc, PreImplicitCallKind, L, Tag) {} 533239462Sdim 534249423Sdimprivate: 535249423Sdim friend class ProgramPoint; 536249423Sdim PreImplicitCall() {} 537249423Sdim static bool isKind(const ProgramPoint &Location) { 538249423Sdim return Location.getKind() == PreImplicitCallKind; 539239462Sdim } 540239462Sdim}; 541239462Sdim 542239462Sdim/// Represents a program point just after an implicit call event. 543239462Sdim/// 544239462Sdim/// Explicit calls will appear as PostStmt program points. 545239462Sdimclass PostImplicitCall : public ImplicitCallPoint { 546239462Sdimpublic: 547239462Sdim PostImplicitCall(const Decl *D, SourceLocation Loc, 548239462Sdim const LocationContext *L, const ProgramPointTag *Tag = 0) 549239462Sdim : ImplicitCallPoint(D, Loc, PostImplicitCallKind, L, Tag) {} 550239462Sdim 551249423Sdimprivate: 552249423Sdim friend class ProgramPoint; 553249423Sdim PostImplicitCall() {} 554249423Sdim static bool isKind(const ProgramPoint &Location) { 555249423Sdim return Location.getKind() == PostImplicitCallKind; 556239462Sdim } 557239462Sdim}; 558239462Sdim 559239462Sdim/// Represents a point when we begin processing an inlined call. 560243830Sdim/// CallEnter uses the caller's location context. 561239462Sdimclass CallEnter : public ProgramPoint { 562239462Sdimpublic: 563218893Sdim CallEnter(const Stmt *stmt, const StackFrameContext *calleeCtx, 564218893Sdim const LocationContext *callerCtx) 565239462Sdim : ProgramPoint(stmt, calleeCtx, CallEnterKind, callerCtx, 0) {} 566198092Srdivacky 567204643Srdivacky const Stmt *getCallExpr() const { 568204643Srdivacky return static_cast<const Stmt *>(getData1()); 569204643Srdivacky } 570204643Srdivacky 571218893Sdim const StackFrameContext *getCalleeContext() const { 572218893Sdim return static_cast<const StackFrameContext *>(getData2()); 573204643Srdivacky } 574204643Srdivacky 575249423Sdimprivate: 576249423Sdim friend class ProgramPoint; 577249423Sdim CallEnter() {} 578249423Sdim static bool isKind(const ProgramPoint &Location) { 579249423Sdim return Location.getKind() == CallEnterKind; 580204643Srdivacky } 581204643Srdivacky}; 582204643Srdivacky 583239462Sdim/// Represents a point when we start the call exit sequence (for inlined call). 584239462Sdim/// 585239462Sdim/// The call exit is simulated with a sequence of nodes, which occur between 586239462Sdim/// CallExitBegin and CallExitEnd. The following operations occur between the 587239462Sdim/// two program points: 588239462Sdim/// - CallExitBegin 589239462Sdim/// - Bind the return value 590239462Sdim/// - Run Remove dead bindings (to clean up the dead symbols from the callee). 591239462Sdim/// - CallExitEnd 592239462Sdimclass CallExitBegin : public ProgramPoint { 593204643Srdivackypublic: 594239462Sdim // CallExitBegin uses the callee's location context. 595239462Sdim CallExitBegin(const StackFrameContext *L) 596239462Sdim : ProgramPoint(0, CallExitBeginKind, L, 0) {} 597204643Srdivacky 598249423Sdimprivate: 599249423Sdim friend class ProgramPoint; 600249423Sdim CallExitBegin() {} 601249423Sdim static bool isKind(const ProgramPoint &Location) { 602249423Sdim return Location.getKind() == CallExitBeginKind; 603204643Srdivacky } 604204643Srdivacky}; 605204643Srdivacky 606239462Sdim/// Represents a point when we finish the call exit sequence (for inlined call). 607239462Sdim/// \sa CallExitBegin 608239462Sdimclass CallExitEnd : public ProgramPoint { 609239462Sdimpublic: 610239462Sdim // CallExitEnd uses the caller's location context. 611239462Sdim CallExitEnd(const StackFrameContext *CalleeCtx, 612239462Sdim const LocationContext *CallerCtx) 613239462Sdim : ProgramPoint(CalleeCtx, CallExitEndKind, CallerCtx, 0) {} 614239462Sdim 615239462Sdim const StackFrameContext *getCalleeContext() const { 616239462Sdim return static_cast<const StackFrameContext *>(getData1()); 617239462Sdim } 618239462Sdim 619249423Sdimprivate: 620249423Sdim friend class ProgramPoint; 621249423Sdim CallExitEnd() {} 622249423Sdim static bool isKind(const ProgramPoint &Location) { 623249423Sdim return Location.getKind() == CallExitEndKind; 624239462Sdim } 625239462Sdim}; 626239462Sdim 627234353Sdim/// This is a meta program point, which should be skipped by all the diagnostic 628234353Sdim/// reasoning etc. 629234353Sdimclass EpsilonPoint : public ProgramPoint { 630234353Sdimpublic: 631234353Sdim EpsilonPoint(const LocationContext *L, const void *Data1, 632234353Sdim const void *Data2 = 0, const ProgramPointTag *tag = 0) 633234353Sdim : ProgramPoint(Data1, Data2, EpsilonKind, L, tag) {} 634234353Sdim 635234353Sdim const void *getData() const { return getData1(); } 636234353Sdim 637249423Sdimprivate: 638249423Sdim friend class ProgramPoint; 639249423Sdim EpsilonPoint() {} 640249423Sdim static bool isKind(const ProgramPoint &Location) { 641249423Sdim return Location.getKind() == EpsilonKind; 642234353Sdim } 643234353Sdim}; 644234353Sdim 645226633Sdim/// ProgramPoints can be "tagged" as representing points specific to a given 646226633Sdim/// analysis entity. Tags are abstract annotations, with an associated 647226633Sdim/// description and potentially other information. 648226633Sdimclass ProgramPointTag { 649226633Sdimpublic: 650226633Sdim ProgramPointTag(void *tagKind = 0) : TagKind(tagKind) {} 651226633Sdim virtual ~ProgramPointTag(); 652226633Sdim virtual StringRef getTagDescription() const = 0; 653204643Srdivacky 654226633Sdimprotected: 655249423Sdim /// Used to implement 'isKind' in subclasses. 656226633Sdim const void *getTagKind() { return TagKind; } 657226633Sdim 658226633Sdimprivate: 659226633Sdim const void *TagKind; 660226633Sdim}; 661226633Sdim 662226633Sdimclass SimpleProgramPointTag : public ProgramPointTag { 663226633Sdim std::string desc; 664226633Sdimpublic: 665226633Sdim SimpleProgramPointTag(StringRef description); 666226633Sdim StringRef getTagDescription() const; 667226633Sdim}; 668226633Sdim 669193326Sed} // end namespace clang 670193326Sed 671193326Sed 672198092Srdivackynamespace llvm { // Traits specialization for DenseMap 673198092Srdivacky 674193326Sedtemplate <> struct DenseMapInfo<clang::ProgramPoint> { 675193326Sed 676193326Sedstatic inline clang::ProgramPoint getEmptyKey() { 677193326Sed uintptr_t x = 678198092Srdivacky reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getEmptyKey()) & ~0x7; 679198092Srdivacky return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), 0); 680193326Sed} 681193326Sed 682193326Sedstatic inline clang::ProgramPoint getTombstoneKey() { 683193326Sed uintptr_t x = 684198092Srdivacky reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getTombstoneKey()) & ~0x7; 685198092Srdivacky return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), 0); 686193326Sed} 687193326Sed 688226633Sdimstatic unsigned getHashValue(const clang::ProgramPoint &Loc) { 689193326Sed return Loc.getHashValue(); 690193326Sed} 691193326Sed 692226633Sdimstatic bool isEqual(const clang::ProgramPoint &L, 693226633Sdim const clang::ProgramPoint &R) { 694193326Sed return L == R; 695193326Sed} 696193326Sed 697193326Sed}; 698200583Srdivacky 699200583Srdivackytemplate <> 700200583Srdivackystruct isPodLike<clang::ProgramPoint> { static const bool value = true; }; 701200583Srdivacky 702193326Sed} // end namespace llvm 703193326Sed 704193326Sed#endif 705