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" 21252723Sdim#include "llvm/ADT/FoldingSet.h" 22252723Sdim#include "llvm/ADT/Optional.h" 23235633Sdim#include "llvm/ADT/PointerIntPair.h" 24252723Sdim#include "llvm/ADT/StringRef.h" 25193326Sed#include "llvm/Support/Casting.h" 26252723Sdim#include "llvm/Support/DataTypes.h" 27193326Sed#include <cassert> 28252723Sdim#include <string> 29193326Sed#include <utility> 30193326Sed 31193326Sednamespace clang { 32198092Srdivacky 33235633Sdimclass AnalysisDeclContext; 34204643Srdivackyclass FunctionDecl; 35226890Sdimclass LocationContext; 36226890Sdimclass ProgramPointTag; 37226890Sdim 38193326Sedclass ProgramPoint { 39193326Sedpublic: 40198092Srdivacky enum Kind { BlockEdgeKind, 41198092Srdivacky BlockEntranceKind, 42198092Srdivacky BlockExitKind, 43198092Srdivacky PreStmtKind, 44245431Sdim PreStmtPurgeDeadSymbolsKind, 45245431Sdim PostStmtPurgeDeadSymbolsKind, 46198092Srdivacky PostStmtKind, 47199482Srdivacky PreLoadKind, 48198092Srdivacky PostLoadKind, 49199482Srdivacky PreStoreKind, 50198092Srdivacky PostStoreKind, 51221345Sdim PostConditionKind, 52198092Srdivacky PostLValueKind, 53245431Sdim MinPostStmtKind = PostStmtKind, 54245431Sdim MaxPostStmtKind = PostLValueKind, 55218893Sdim PostInitializerKind, 56204643Srdivacky CallEnterKind, 57245431Sdim CallExitBeginKind, 58245431Sdim CallExitEndKind, 59245431Sdim PreImplicitCallKind, 60245431Sdim PostImplicitCallKind, 61245431Sdim MinImplicitCallKind = PreImplicitCallKind, 62245431Sdim MaxImplicitCallKind = PostImplicitCallKind, 63235633Sdim EpsilonKind}; 64193326Sed 65193326Sedprivate: 66245431Sdim const void *Data1; 67235633Sdim 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. 71235633Sdim llvm::PointerIntPair<const LocationContext *, 2, unsigned> L; 72235633Sdim 73245431Sdim llvm::PointerIntPair<const ProgramPointTag *, 2, unsigned> Tag; 74198092Srdivacky 75193326Sedprotected: 76252723Sdim ProgramPoint() {} 77235633Sdim ProgramPoint(const void *P, 78235633Sdim Kind k, 79235633Sdim const LocationContext *l, 80226890Sdim const ProgramPointTag *tag = 0) 81245431Sdim : Data1(P), 82245431Sdim Data2(0, (((unsigned) k) >> 0) & 0x3), 83245431Sdim L(l, (((unsigned) k) >> 2) & 0x3), 84245431Sdim Tag(tag, (((unsigned) k) >> 4) & 0x3) { 85235633Sdim assert(getKind() == k); 86235633Sdim assert(getLocationContext() == l); 87235633Sdim assert(getData1() == P); 88235633Sdim } 89235633Sdim 90235633Sdim ProgramPoint(const void *P1, 91235633Sdim const void *P2, 92235633Sdim Kind k, 93235633Sdim const LocationContext *l, 94226890Sdim const ProgramPointTag *tag = 0) 95245431Sdim : Data1(P1), 96245431Sdim Data2(P2, (((unsigned) k) >> 0) & 0x3), 97245431Sdim L(l, (((unsigned) k) >> 2) & 0x3), 98245431Sdim Tag(tag, (((unsigned) k) >> 4) & 0x3) {} 99193326Sed 100193326Sedprotected: 101245431Sdim const void *getData1() const { return Data1; } 102235633Sdim const void *getData2() const { return Data2.getPointer(); } 103235633Sdim void setData2(const void *d) { Data2.setPointer(d); } 104193326Sed 105198092Srdivackypublic: 106226890Sdim /// Create a new ProgramPoint object that is the same as the original 107226890Sdim /// except for using the specified tag value. 108226890Sdim ProgramPoint withTag(const ProgramPointTag *tag) const { 109235633Sdim return ProgramPoint(getData1(), getData2(), getKind(), 110235633Sdim getLocationContext(), tag); 111226890Sdim } 112226890Sdim 113252723Sdim /// \brief Convert to the specified ProgramPoint type, asserting that this 114252723Sdim /// ProgramPoint is of the desired type. 115252723Sdim template<typename T> 116252723Sdim T castAs() const { 117252723Sdim assert(T::isKind(*this)); 118252723Sdim T t; 119252723Sdim ProgramPoint& PP = t; 120252723Sdim PP = *this; 121252723Sdim return t; 122252723Sdim } 123252723Sdim 124252723Sdim /// \brief Convert to the specified ProgramPoint type, returning None if this 125252723Sdim /// ProgramPoint is not of the desired type. 126252723Sdim template<typename T> 127252723Sdim Optional<T> getAs() const { 128252723Sdim if (!T::isKind(*this)) 129252723Sdim return None; 130252723Sdim T t; 131252723Sdim ProgramPoint& PP = t; 132252723Sdim PP = *this; 133252723Sdim return t; 134252723Sdim } 135252723Sdim 136235633Sdim Kind getKind() const { 137245431Sdim unsigned x = Tag.getInt(); 138235633Sdim x <<= 2; 139245431Sdim x |= L.getInt(); 140245431Sdim x <<= 2; 141235633Sdim x |= Data2.getInt(); 142235633Sdim return (Kind) x; 143235633Sdim } 144198092Srdivacky 145245431Sdim /// \brief Is this a program point corresponding to purge/removal of dead 146245431Sdim /// symbols and bindings. 147245431Sdim bool isPurgeKind() { 148245431Sdim Kind K = getKind(); 149245431Sdim return (K == PostStmtPurgeDeadSymbolsKind || 150245431Sdim K == PreStmtPurgeDeadSymbolsKind); 151245431Sdim } 152218893Sdim 153245431Sdim const ProgramPointTag *getTag() const { return Tag.getPointer(); } 154245431Sdim 155235633Sdim const LocationContext *getLocationContext() const { 156235633Sdim return L.getPointer(); 157235633Sdim } 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 { 167235633Sdim return Data1 == RHS.Data1 && 168235633Sdim Data2 == RHS.Data2 && 169235633Sdim L == RHS.L && 170235633Sdim Tag == RHS.Tag; 171193326Sed } 172193326Sed 173226890Sdim bool operator!=(const ProgramPoint &RHS) const { 174235633Sdim return Data1 != RHS.Data1 || 175235633Sdim Data2 != RHS.Data2 || 176235633Sdim L != RHS.L || 177235633Sdim Tag != RHS.Tag; 178193326Sed } 179198092Srdivacky 180193326Sed void Profile(llvm::FoldingSetNodeID& ID) const { 181235633Sdim ID.AddInteger((unsigned) getKind()); 182235633Sdim ID.AddPointer(getData1()); 183235633Sdim ID.AddPointer(getData2()); 184235633Sdim ID.AddPointer(getLocationContext()); 185245431Sdim ID.AddPointer(getTag()); 186193326Sed } 187226890Sdim 188226890Sdim static ProgramPoint getProgramPoint(const Stmt *S, ProgramPoint::Kind K, 189226890Sdim const LocationContext *LC, 190226890Sdim const ProgramPointTag *tag); 191193326Sed}; 192198092Srdivacky 193193326Sedclass BlockEntrance : public ProgramPoint { 194193326Sedpublic: 195226890Sdim BlockEntrance(const CFGBlock *B, const LocationContext *L, 196226890Sdim const ProgramPointTag *tag = 0) 197226890Sdim : ProgramPoint(B, BlockEntranceKind, L, tag) { 198226890Sdim assert(B && "BlockEntrance requires non-null block"); 199226890Sdim } 200198092Srdivacky 201226890Sdim const CFGBlock *getBlock() const { 202212904Sdim return reinterpret_cast<const CFGBlock*>(getData1()); 203193326Sed } 204198092Srdivacky 205252723Sdim Optional<CFGElement> getFirstElement() const { 206226890Sdim const CFGBlock *B = getBlock(); 207252723Sdim return B->empty() ? Optional<CFGElement>() : B->front(); 208193326Sed } 209201361Srdivacky 210252723Sdimprivate: 211252723Sdim friend class ProgramPoint; 212252723Sdim BlockEntrance() {} 213252723Sdim static bool isKind(const ProgramPoint &Location) { 214252723Sdim return Location.getKind() == BlockEntranceKind; 215193326Sed } 216193326Sed}; 217193326Sed 218193326Sedclass BlockExit : public ProgramPoint { 219193326Sedpublic: 220226890Sdim BlockExit(const CFGBlock *B, const LocationContext *L) 221198092Srdivacky : ProgramPoint(B, BlockExitKind, L) {} 222198092Srdivacky 223226890Sdim const CFGBlock *getBlock() const { 224212904Sdim return reinterpret_cast<const CFGBlock*>(getData1()); 225193326Sed } 226193326Sed 227226890Sdim const Stmt *getTerminator() const { 228193326Sed return getBlock()->getTerminator(); 229193326Sed } 230198092Srdivacky 231252723Sdimprivate: 232252723Sdim friend class ProgramPoint; 233252723Sdim BlockExit() {} 234252723Sdim static bool isKind(const ProgramPoint &Location) { 235252723Sdim 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, 242226890Sdim const ProgramPointTag *tag) 243245431Sdim : ProgramPoint(S, p2, k, L, tag) { 244245431Sdim assert(S); 245245431Sdim } 246193326Sed 247198092Srdivacky const Stmt *getStmt() const { return (const Stmt*) getData1(); } 248198092Srdivacky 249198092Srdivacky template <typename T> 250252723Sdim const T* getStmtAs() const { return dyn_cast<T>(getStmt()); } 251198092Srdivacky 252252723Sdimprotected: 253252723Sdim StmtPoint() {} 254252723Sdimprivate: 255252723Sdim friend class ProgramPoint; 256252723Sdim static bool isKind(const ProgramPoint &Location) { 257252723Sdim unsigned k = Location.getKind(); 258198092Srdivacky return k >= PreStmtKind && k <= MaxPostStmtKind; 259198092Srdivacky } 260198092Srdivacky}; 261198092Srdivacky 262198092Srdivacky 263198092Srdivackyclass PreStmt : public StmtPoint { 264193326Sedpublic: 265226890Sdim 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 271252723Sdimprivate: 272252723Sdim friend class ProgramPoint; 273252723Sdim PreStmt() {} 274252723Sdim static bool isKind(const ProgramPoint &Location) { 275252723Sdim return Location.getKind() == PreStmtKind; 276198092Srdivacky } 277198092Srdivacky}; 278198092Srdivacky 279198092Srdivackyclass PostStmt : public StmtPoint { 280198092Srdivackyprotected: 281252723Sdim PostStmt() {} 282226890Sdim PostStmt(const Stmt *S, const void *data, Kind k, const LocationContext *L, 283235633Sdim const ProgramPointTag *tag = 0) 284198092Srdivacky : StmtPoint(S, data, k, L, tag) {} 285198092Srdivacky 286198092Srdivackypublic: 287226890Sdim explicit PostStmt(const Stmt *S, Kind k, 288226890Sdim const LocationContext *L, const ProgramPointTag *tag = 0) 289218893Sdim : StmtPoint(S, NULL, k, L, tag) {} 290218893Sdim 291226890Sdim explicit PostStmt(const Stmt *S, const LocationContext *L, 292226890Sdim const ProgramPointTag *tag = 0) 293198092Srdivacky : StmtPoint(S, NULL, PostStmtKind, L, tag) {} 294198092Srdivacky 295252723Sdimprivate: 296252723Sdim friend class ProgramPoint; 297252723Sdim static bool isKind(const ProgramPoint &Location) { 298252723Sdim 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: 306226890Sdim PostCondition(const Stmt *S, const LocationContext *L, 307226890Sdim const ProgramPointTag *tag = 0) 308221345Sdim : PostStmt(S, PostConditionKind, L, tag) {} 309221345Sdim 310252723Sdimprivate: 311252723Sdim friend class ProgramPoint; 312252723Sdim PostCondition() {} 313252723Sdim static bool isKind(const ProgramPoint &Location) { 314252723Sdim return Location.getKind() == PostConditionKind; 315221345Sdim } 316221345Sdim}; 317221345Sdim 318199482Srdivackyclass LocationCheck : public StmtPoint { 319199482Srdivackyprotected: 320252723Sdim LocationCheck() {} 321199482Srdivacky LocationCheck(const Stmt *S, const LocationContext *L, 322226890Sdim ProgramPoint::Kind K, const ProgramPointTag *tag) 323199482Srdivacky : StmtPoint(S, NULL, K, L, tag) {} 324199482Srdivacky 325252723Sdimprivate: 326252723Sdim friend class ProgramPoint; 327252723Sdim static bool isKind(const ProgramPoint &location) { 328252723Sdim unsigned k = location.getKind(); 329199482Srdivacky return k == PreLoadKind || k == PreStoreKind; 330193326Sed } 331193326Sed}; 332199482Srdivacky 333199482Srdivackyclass PreLoad : public LocationCheck { 334193326Sedpublic: 335226890Sdim PreLoad(const Stmt *S, const LocationContext *L, 336226890Sdim const ProgramPointTag *tag = 0) 337199482Srdivacky : LocationCheck(S, L, PreLoadKind, tag) {} 338199482Srdivacky 339252723Sdimprivate: 340252723Sdim friend class ProgramPoint; 341252723Sdim PreLoad() {} 342252723Sdim static bool isKind(const ProgramPoint &location) { 343252723Sdim return location.getKind() == PreLoadKind; 344193326Sed } 345193326Sed}; 346198092Srdivacky 347199482Srdivackyclass PreStore : public LocationCheck { 348193326Sedpublic: 349226890Sdim PreStore(const Stmt *S, const LocationContext *L, 350226890Sdim const ProgramPointTag *tag = 0) 351199482Srdivacky : LocationCheck(S, L, PreStoreKind, tag) {} 352199482Srdivacky 353252723Sdimprivate: 354252723Sdim friend class ProgramPoint; 355252723Sdim PreStore() {} 356252723Sdim static bool isKind(const ProgramPoint &location) { 357252723Sdim return location.getKind() == PreStoreKind; 358193326Sed } 359193326Sed}; 360198092Srdivacky 361193326Sedclass PostLoad : public PostStmt { 362193326Sedpublic: 363226890Sdim PostLoad(const Stmt *S, const LocationContext *L, 364226890Sdim const ProgramPointTag *tag = 0) 365198092Srdivacky : PostStmt(S, PostLoadKind, L, tag) {} 366198092Srdivacky 367252723Sdimprivate: 368252723Sdim friend class ProgramPoint; 369252723Sdim PostLoad() {} 370252723Sdim static bool isKind(const ProgramPoint &Location) { 371252723Sdim return Location.getKind() == PostLoadKind; 372193326Sed } 373193326Sed}; 374198092Srdivacky 375245431Sdim/// \brief Represents a program point after a store evaluation. 376193326Sedclass PostStore : public PostStmt { 377193326Sedpublic: 378235633Sdim /// Construct the post store point. 379235633Sdim /// \param Loc can be used to store the information about the location 380235633Sdim /// used in the form it was uttered in the code. 381235633Sdim PostStore(const Stmt *S, const LocationContext *L, const void *Loc, 382226890Sdim const ProgramPointTag *tag = 0) 383235633Sdim : PostStmt(S, PostStoreKind, L, tag) { 384235633Sdim assert(getData2() == 0); 385235633Sdim setData2(Loc); 386235633Sdim } 387198092Srdivacky 388235633Sdim /// \brief Returns the information about the location used in the store, 389235633Sdim /// how it was uttered in the code. 390235633Sdim const void *getLocationValue() const { 391235633Sdim return getData2(); 392235633Sdim } 393235633Sdim 394252723Sdimprivate: 395252723Sdim friend class ProgramPoint; 396252723Sdim PostStore() {} 397252723Sdim static bool isKind(const ProgramPoint &Location) { 398252723Sdim return Location.getKind() == PostStoreKind; 399252723Sdim } 400193326Sed}; 401193326Sed 402193326Sedclass PostLValue : public PostStmt { 403193326Sedpublic: 404226890Sdim PostLValue(const Stmt *S, const LocationContext *L, 405226890Sdim const ProgramPointTag *tag = 0) 406198092Srdivacky : PostStmt(S, PostLValueKind, L, tag) {} 407198092Srdivacky 408252723Sdimprivate: 409252723Sdim friend class ProgramPoint; 410252723Sdim PostLValue() {} 411252723Sdim static bool isKind(const ProgramPoint &Location) { 412252723Sdim return Location.getKind() == PostLValueKind; 413193326Sed } 414198092Srdivacky}; 415198092Srdivacky 416245431Sdim/// Represents a point after we ran remove dead bindings BEFORE 417245431Sdim/// processing the given statement. 418245431Sdimclass PreStmtPurgeDeadSymbols : public StmtPoint { 419193326Sedpublic: 420245431Sdim PreStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L, 421226890Sdim const ProgramPointTag *tag = 0) 422245431Sdim : StmtPoint(S, 0, PreStmtPurgeDeadSymbolsKind, L, tag) { } 423198092Srdivacky 424252723Sdimprivate: 425252723Sdim friend class ProgramPoint; 426252723Sdim PreStmtPurgeDeadSymbols() {} 427252723Sdim static bool isKind(const ProgramPoint &Location) { 428252723Sdim return Location.getKind() == PreStmtPurgeDeadSymbolsKind; 429193326Sed } 430193326Sed}; 431198092Srdivacky 432245431Sdim/// Represents a point after we ran remove dead bindings AFTER 433245431Sdim/// processing the given statement. 434245431Sdimclass PostStmtPurgeDeadSymbols : public StmtPoint { 435245431Sdimpublic: 436245431Sdim PostStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L, 437245431Sdim const ProgramPointTag *tag = 0) 438245431Sdim : StmtPoint(S, 0, PostStmtPurgeDeadSymbolsKind, L, tag) { } 439245431Sdim 440252723Sdimprivate: 441252723Sdim friend class ProgramPoint; 442252723Sdim PostStmtPurgeDeadSymbols() {} 443252723Sdim static bool isKind(const ProgramPoint &Location) { 444252723Sdim return Location.getKind() == PostStmtPurgeDeadSymbolsKind; 445245431Sdim } 446245431Sdim}; 447245431Sdim 448193326Sedclass BlockEdge : public ProgramPoint { 449193326Sedpublic: 450226890Sdim BlockEdge(const CFGBlock *B1, const CFGBlock *B2, const LocationContext *L) 451226890Sdim : ProgramPoint(B1, B2, BlockEdgeKind, L) { 452226890Sdim assert(B1 && "BlockEdge: source block must be non-null"); 453226890Sdim assert(B2 && "BlockEdge: destination block must be non-null"); 454226890Sdim } 455198092Srdivacky 456226890Sdim const CFGBlock *getSrc() const { 457212904Sdim return static_cast<const CFGBlock*>(getData1()); 458193326Sed } 459198092Srdivacky 460226890Sdim const CFGBlock *getDst() const { 461212904Sdim return static_cast<const CFGBlock*>(getData2()); 462193326Sed } 463198092Srdivacky 464252723Sdimprivate: 465252723Sdim friend class ProgramPoint; 466252723Sdim BlockEdge() {} 467252723Sdim static bool isKind(const ProgramPoint &Location) { 468252723Sdim return Location.getKind() == BlockEdgeKind; 469193326Sed } 470193326Sed}; 471193326Sed 472218893Sdimclass PostInitializer : public ProgramPoint { 473218893Sdimpublic: 474252723Sdim /// \brief Construct a PostInitializer point that represents a location after 475252723Sdim /// CXXCtorInitializer expression evaluation. 476252723Sdim /// 477252723Sdim /// \param I The initializer. 478252723Sdim /// \param Loc The location of the field being initialized. 479252723Sdim PostInitializer(const CXXCtorInitializer *I, 480252723Sdim const void *Loc, 481218893Sdim const LocationContext *L) 482252723Sdim : ProgramPoint(I, Loc, PostInitializerKind, L) {} 483218893Sdim 484252723Sdim const CXXCtorInitializer *getInitializer() const { 485252723Sdim return static_cast<const CXXCtorInitializer *>(getData1()); 486218893Sdim } 487252723Sdim 488252723Sdim /// \brief Returns the location of the field. 489252723Sdim const void *getLocationValue() const { 490252723Sdim return getData2(); 491252723Sdim } 492252723Sdim 493252723Sdimprivate: 494252723Sdim friend class ProgramPoint; 495252723Sdim PostInitializer() {} 496252723Sdim static bool isKind(const ProgramPoint &Location) { 497252723Sdim return Location.getKind() == PostInitializerKind; 498252723Sdim } 499218893Sdim}; 500218893Sdim 501245431Sdim/// Represents an implicit call event. 502245431Sdim/// 503245431Sdim/// The nearest statement is provided for diagnostic purposes. 504245431Sdimclass ImplicitCallPoint : public ProgramPoint { 505204643Srdivackypublic: 506245431Sdim ImplicitCallPoint(const Decl *D, SourceLocation Loc, Kind K, 507245431Sdim const LocationContext *L, const ProgramPointTag *Tag) 508245431Sdim : ProgramPoint(Loc.getPtrEncoding(), D, K, L, Tag) {} 509245431Sdim 510245431Sdim const Decl *getDecl() const { return static_cast<const Decl *>(getData2()); } 511245431Sdim SourceLocation getLocation() const { 512245431Sdim return SourceLocation::getFromPtrEncoding(getData1()); 513245431Sdim } 514245431Sdim 515252723Sdimprotected: 516252723Sdim ImplicitCallPoint() {} 517252723Sdimprivate: 518252723Sdim friend class ProgramPoint; 519252723Sdim static bool isKind(const ProgramPoint &Location) { 520252723Sdim return Location.getKind() >= MinImplicitCallKind && 521252723Sdim Location.getKind() <= MaxImplicitCallKind; 522245431Sdim } 523245431Sdim}; 524245431Sdim 525245431Sdim/// Represents a program point just before an implicit call event. 526245431Sdim/// 527245431Sdim/// Explicit calls will appear as PreStmt program points. 528245431Sdimclass PreImplicitCall : public ImplicitCallPoint { 529245431Sdimpublic: 530245431Sdim PreImplicitCall(const Decl *D, SourceLocation Loc, 531245431Sdim const LocationContext *L, const ProgramPointTag *Tag = 0) 532245431Sdim : ImplicitCallPoint(D, Loc, PreImplicitCallKind, L, Tag) {} 533245431Sdim 534252723Sdimprivate: 535252723Sdim friend class ProgramPoint; 536252723Sdim PreImplicitCall() {} 537252723Sdim static bool isKind(const ProgramPoint &Location) { 538252723Sdim return Location.getKind() == PreImplicitCallKind; 539245431Sdim } 540245431Sdim}; 541245431Sdim 542245431Sdim/// Represents a program point just after an implicit call event. 543245431Sdim/// 544245431Sdim/// Explicit calls will appear as PostStmt program points. 545245431Sdimclass PostImplicitCall : public ImplicitCallPoint { 546245431Sdimpublic: 547245431Sdim PostImplicitCall(const Decl *D, SourceLocation Loc, 548245431Sdim const LocationContext *L, const ProgramPointTag *Tag = 0) 549245431Sdim : ImplicitCallPoint(D, Loc, PostImplicitCallKind, L, Tag) {} 550245431Sdim 551252723Sdimprivate: 552252723Sdim friend class ProgramPoint; 553252723Sdim PostImplicitCall() {} 554252723Sdim static bool isKind(const ProgramPoint &Location) { 555252723Sdim return Location.getKind() == PostImplicitCallKind; 556245431Sdim } 557245431Sdim}; 558245431Sdim 559245431Sdim/// Represents a point when we begin processing an inlined call. 560245431Sdim/// CallEnter uses the caller's location context. 561245431Sdimclass CallEnter : public ProgramPoint { 562245431Sdimpublic: 563218893Sdim CallEnter(const Stmt *stmt, const StackFrameContext *calleeCtx, 564218893Sdim const LocationContext *callerCtx) 565245431Sdim : 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 575252723Sdimprivate: 576252723Sdim friend class ProgramPoint; 577252723Sdim CallEnter() {} 578252723Sdim static bool isKind(const ProgramPoint &Location) { 579252723Sdim return Location.getKind() == CallEnterKind; 580204643Srdivacky } 581204643Srdivacky}; 582204643Srdivacky 583245431Sdim/// Represents a point when we start the call exit sequence (for inlined call). 584245431Sdim/// 585245431Sdim/// The call exit is simulated with a sequence of nodes, which occur between 586245431Sdim/// CallExitBegin and CallExitEnd. The following operations occur between the 587245431Sdim/// two program points: 588245431Sdim/// - CallExitBegin 589245431Sdim/// - Bind the return value 590245431Sdim/// - Run Remove dead bindings (to clean up the dead symbols from the callee). 591245431Sdim/// - CallExitEnd 592245431Sdimclass CallExitBegin : public ProgramPoint { 593204643Srdivackypublic: 594245431Sdim // CallExitBegin uses the callee's location context. 595245431Sdim CallExitBegin(const StackFrameContext *L) 596245431Sdim : ProgramPoint(0, CallExitBeginKind, L, 0) {} 597204643Srdivacky 598252723Sdimprivate: 599252723Sdim friend class ProgramPoint; 600252723Sdim CallExitBegin() {} 601252723Sdim static bool isKind(const ProgramPoint &Location) { 602252723Sdim return Location.getKind() == CallExitBeginKind; 603204643Srdivacky } 604204643Srdivacky}; 605204643Srdivacky 606245431Sdim/// Represents a point when we finish the call exit sequence (for inlined call). 607245431Sdim/// \sa CallExitBegin 608245431Sdimclass CallExitEnd : public ProgramPoint { 609245431Sdimpublic: 610245431Sdim // CallExitEnd uses the caller's location context. 611245431Sdim CallExitEnd(const StackFrameContext *CalleeCtx, 612245431Sdim const LocationContext *CallerCtx) 613245431Sdim : ProgramPoint(CalleeCtx, CallExitEndKind, CallerCtx, 0) {} 614245431Sdim 615245431Sdim const StackFrameContext *getCalleeContext() const { 616245431Sdim return static_cast<const StackFrameContext *>(getData1()); 617245431Sdim } 618245431Sdim 619252723Sdimprivate: 620252723Sdim friend class ProgramPoint; 621252723Sdim CallExitEnd() {} 622252723Sdim static bool isKind(const ProgramPoint &Location) { 623252723Sdim return Location.getKind() == CallExitEndKind; 624245431Sdim } 625245431Sdim}; 626245431Sdim 627235633Sdim/// This is a meta program point, which should be skipped by all the diagnostic 628235633Sdim/// reasoning etc. 629235633Sdimclass EpsilonPoint : public ProgramPoint { 630235633Sdimpublic: 631235633Sdim EpsilonPoint(const LocationContext *L, const void *Data1, 632235633Sdim const void *Data2 = 0, const ProgramPointTag *tag = 0) 633235633Sdim : ProgramPoint(Data1, Data2, EpsilonKind, L, tag) {} 634235633Sdim 635235633Sdim const void *getData() const { return getData1(); } 636235633Sdim 637252723Sdimprivate: 638252723Sdim friend class ProgramPoint; 639252723Sdim EpsilonPoint() {} 640252723Sdim static bool isKind(const ProgramPoint &Location) { 641252723Sdim return Location.getKind() == EpsilonKind; 642235633Sdim } 643235633Sdim}; 644235633Sdim 645226890Sdim/// ProgramPoints can be "tagged" as representing points specific to a given 646226890Sdim/// analysis entity. Tags are abstract annotations, with an associated 647226890Sdim/// description and potentially other information. 648226890Sdimclass ProgramPointTag { 649226890Sdimpublic: 650226890Sdim ProgramPointTag(void *tagKind = 0) : TagKind(tagKind) {} 651226890Sdim virtual ~ProgramPointTag(); 652226890Sdim virtual StringRef getTagDescription() const = 0; 653204643Srdivacky 654226890Sdimprotected: 655252723Sdim /// Used to implement 'isKind' in subclasses. 656226890Sdim const void *getTagKind() { return TagKind; } 657226890Sdim 658226890Sdimprivate: 659226890Sdim const void *TagKind; 660226890Sdim}; 661226890Sdim 662226890Sdimclass SimpleProgramPointTag : public ProgramPointTag { 663226890Sdim std::string desc; 664226890Sdimpublic: 665226890Sdim SimpleProgramPointTag(StringRef description); 666226890Sdim StringRef getTagDescription() const; 667226890Sdim}; 668226890Sdim 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 688226890Sdimstatic unsigned getHashValue(const clang::ProgramPoint &Loc) { 689193326Sed return Loc.getHashValue(); 690193326Sed} 691193326Sed 692226890Sdimstatic bool isEqual(const clang::ProgramPoint &L, 693226890Sdim 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