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/Support/DataTypes.h" 21 #include "llvm/ADT/DenseMap.h" 22 #include "llvm/ADT/FoldingSet.h" 23 #include "llvm/Support/Casting.h" 24 #include <cassert> 25 #include <utility> 26 27 namespace clang { 28 29 class LocationContext; 30 class AnalysisContext; 31 class FunctionDecl; 32 33 class ProgramPoint { 34 public: 35 enum Kind { BlockEdgeKind, 36 BlockEntranceKind, 37 BlockExitKind, 38 PreStmtKind, 39 PostStmtKind, 40 PreLoadKind, 41 PostLoadKind, 42 PreStoreKind, 43 PostStoreKind, 44 PostPurgeDeadSymbolsKind, 45 PostStmtCustomKind, 46 PostConditionKind, 47 PostLValueKind, 48 PostInitializerKind, 49 CallEnterKind, 50 CallExitKind, 51 MinPostStmtKind = PostStmtKind, 52 MaxPostStmtKind = CallExitKind }; 53 54 private: 55 std::pair<const void *, const void *> Data; 56 Kind K; 57 58 // The LocationContext could be NULL to allow ProgramPoint to be used in 59 // context insensitive analysis. 60 const LocationContext *L; 61 const void *Tag; 62 63 protected: 64 ProgramPoint(const void* P, Kind k, const LocationContext *l, 65 const void *tag = 0) Data(P,static_cast<const void * > (NULL))66 : Data(P, static_cast<const void*>(NULL)), K(k), L(l), Tag(tag) {} 67 68 ProgramPoint(const void* P1, const void* P2, Kind k, const LocationContext *l, 69 const void *tag = 0) Data(P1,P2)70 : Data(P1, P2), K(k), L(l), Tag(tag) {} 71 72 protected: getData1()73 const void* getData1() const { return Data.first; } getData2()74 const void* getData2() const { return Data.second; } 75 76 public: getKind()77 Kind getKind() const { return K; } 78 getTag()79 const void *getTag() const { return Tag; } 80 getLocationContext()81 const LocationContext *getLocationContext() const { return L; } 82 83 // For use with DenseMap. This hash is probably slow. getHashValue()84 unsigned getHashValue() const { 85 llvm::FoldingSetNodeID ID; 86 Profile(ID); 87 return ID.ComputeHash(); 88 } 89 classof(const ProgramPoint *)90 static bool classof(const ProgramPoint*) { return true; } 91 92 bool operator==(const ProgramPoint & RHS) const { 93 return K == RHS.K && Data == RHS.Data && L == RHS.L && Tag == RHS.Tag; 94 } 95 96 bool operator!=(const ProgramPoint& RHS) const { 97 return K != RHS.K || Data != RHS.Data || L != RHS.L || Tag != RHS.Tag; 98 } 99 Profile(llvm::FoldingSetNodeID & ID)100 void Profile(llvm::FoldingSetNodeID& ID) const { 101 ID.AddInteger((unsigned) K); 102 ID.AddPointer(Data.first); 103 ID.AddPointer(Data.second); 104 ID.AddPointer(L); 105 ID.AddPointer(Tag); 106 } 107 }; 108 109 class BlockEntrance : public ProgramPoint { 110 public: 111 BlockEntrance(const CFGBlock* B, const LocationContext *L, 112 const void *tag = 0) ProgramPoint(B,BlockEntranceKind,L,tag)113 : ProgramPoint(B, BlockEntranceKind, L, tag) {} 114 getBlock()115 const CFGBlock* getBlock() const { 116 return reinterpret_cast<const CFGBlock*>(getData1()); 117 } 118 getFirstElement()119 const CFGElement getFirstElement() const { 120 const CFGBlock* B = getBlock(); 121 return B->empty() ? CFGElement() : B->front(); 122 } 123 124 /// Create a new BlockEntrance object that is the same as the original 125 /// except for using the specified tag value. withTag(const void * tag)126 BlockEntrance withTag(const void *tag) { 127 return BlockEntrance(getBlock(), getLocationContext(), tag); 128 } 129 classof(const ProgramPoint * Location)130 static bool classof(const ProgramPoint* Location) { 131 return Location->getKind() == BlockEntranceKind; 132 } 133 }; 134 135 class BlockExit : public ProgramPoint { 136 public: BlockExit(const CFGBlock * B,const LocationContext * L)137 BlockExit(const CFGBlock* B, const LocationContext *L) 138 : ProgramPoint(B, BlockExitKind, L) {} 139 getBlock()140 const CFGBlock* getBlock() const { 141 return reinterpret_cast<const CFGBlock*>(getData1()); 142 } 143 getTerminator()144 const Stmt* getTerminator() const { 145 return getBlock()->getTerminator(); 146 } 147 classof(const ProgramPoint * Location)148 static bool classof(const ProgramPoint* Location) { 149 return Location->getKind() == BlockExitKind; 150 } 151 }; 152 153 class StmtPoint : public ProgramPoint { 154 public: StmtPoint(const Stmt * S,const void * p2,Kind k,const LocationContext * L,const void * tag)155 StmtPoint(const Stmt *S, const void *p2, Kind k, const LocationContext *L, 156 const void *tag) 157 : ProgramPoint(S, p2, k, L, tag) {} 158 getStmt()159 const Stmt *getStmt() const { return (const Stmt*) getData1(); } 160 161 template <typename T> getStmtAs()162 const T* getStmtAs() const { return llvm::dyn_cast<T>(getStmt()); } 163 classof(const ProgramPoint * Location)164 static bool classof(const ProgramPoint* Location) { 165 unsigned k = Location->getKind(); 166 return k >= PreStmtKind && k <= MaxPostStmtKind; 167 } 168 }; 169 170 171 class PreStmt : public StmtPoint { 172 public: 173 PreStmt(const Stmt *S, const LocationContext *L, const void *tag, 174 const Stmt *SubStmt = 0) StmtPoint(S,SubStmt,PreStmtKind,L,tag)175 : StmtPoint(S, SubStmt, PreStmtKind, L, tag) {} 176 getSubStmt()177 const Stmt *getSubStmt() const { return (const Stmt*) getData2(); } 178 classof(const ProgramPoint * Location)179 static bool classof(const ProgramPoint* Location) { 180 return Location->getKind() == PreStmtKind; 181 } 182 }; 183 184 class PostStmt : public StmtPoint { 185 protected: 186 PostStmt(const Stmt* S, const void* data, Kind k, const LocationContext *L, 187 const void *tag =0) StmtPoint(S,data,k,L,tag)188 : StmtPoint(S, data, k, L, tag) {} 189 190 public: 191 explicit PostStmt(const Stmt* S, Kind k, 192 const LocationContext *L, const void *tag = 0) StmtPoint(S,NULL,k,L,tag)193 : StmtPoint(S, NULL, k, L, tag) {} 194 195 explicit PostStmt(const Stmt* S, const LocationContext *L,const void *tag = 0) StmtPoint(S,NULL,PostStmtKind,L,tag)196 : StmtPoint(S, NULL, PostStmtKind, L, tag) {} 197 classof(const ProgramPoint * Location)198 static bool classof(const ProgramPoint* Location) { 199 unsigned k = Location->getKind(); 200 return k >= MinPostStmtKind && k <= MaxPostStmtKind; 201 } 202 }; 203 204 class PostStmtCustom : public PostStmt { 205 public: PostStmtCustom(const Stmt * S,const std::pair<const void *,const void * > * TaggedData,const LocationContext * L)206 PostStmtCustom(const Stmt* S, 207 const std::pair<const void*, const void*>* TaggedData,\ 208 const LocationContext *L) 209 : PostStmt(S, TaggedData, PostStmtCustomKind, L) {} 210 getTaggedPair()211 const std::pair<const void*, const void*>& getTaggedPair() const { 212 return 213 *reinterpret_cast<const std::pair<const void*, const void*>*>(getData2()); 214 } 215 getTag()216 const void* getTag() const { return getTaggedPair().first; } 217 getTaggedData()218 const void* getTaggedData() const { return getTaggedPair().second; } 219 classof(const ProgramPoint * Location)220 static bool classof(const ProgramPoint* Location) { 221 return Location->getKind() == PostStmtCustomKind; 222 } 223 }; 224 225 // PostCondition represents the post program point of a branch condition. 226 class PostCondition : public PostStmt { 227 public: 228 PostCondition(const Stmt* S, const LocationContext *L, const void *tag = 0) PostStmt(S,PostConditionKind,L,tag)229 : PostStmt(S, PostConditionKind, L, tag) {} 230 classof(const ProgramPoint * Location)231 static bool classof(const ProgramPoint* Location) { 232 return Location->getKind() == PostConditionKind; 233 } 234 }; 235 236 class LocationCheck : public StmtPoint { 237 protected: LocationCheck(const Stmt * S,const LocationContext * L,ProgramPoint::Kind K,const void * tag)238 LocationCheck(const Stmt *S, const LocationContext *L, 239 ProgramPoint::Kind K, const void *tag) 240 : StmtPoint(S, NULL, K, L, tag) {} 241 classof(const ProgramPoint * location)242 static bool classof(const ProgramPoint *location) { 243 unsigned k = location->getKind(); 244 return k == PreLoadKind || k == PreStoreKind; 245 } 246 }; 247 248 class PreLoad : public LocationCheck { 249 public: 250 PreLoad(const Stmt *S, const LocationContext *L, const void *tag = 0) LocationCheck(S,L,PreLoadKind,tag)251 : LocationCheck(S, L, PreLoadKind, tag) {} 252 classof(const ProgramPoint * location)253 static bool classof(const ProgramPoint *location) { 254 return location->getKind() == PreLoadKind; 255 } 256 }; 257 258 class PreStore : public LocationCheck { 259 public: 260 PreStore(const Stmt *S, const LocationContext *L, const void *tag = 0) LocationCheck(S,L,PreStoreKind,tag)261 : LocationCheck(S, L, PreStoreKind, tag) {} 262 classof(const ProgramPoint * location)263 static bool classof(const ProgramPoint *location) { 264 return location->getKind() == PreStoreKind; 265 } 266 }; 267 268 class PostLoad : public PostStmt { 269 public: 270 PostLoad(const Stmt* S, const LocationContext *L, const void *tag = 0) PostStmt(S,PostLoadKind,L,tag)271 : PostStmt(S, PostLoadKind, L, tag) {} 272 classof(const ProgramPoint * Location)273 static bool classof(const ProgramPoint* Location) { 274 return Location->getKind() == PostLoadKind; 275 } 276 }; 277 278 class PostStore : public PostStmt { 279 public: 280 PostStore(const Stmt* S, const LocationContext *L, const void *tag = 0) PostStmt(S,PostStoreKind,L,tag)281 : PostStmt(S, PostStoreKind, L, tag) {} 282 classof(const ProgramPoint * Location)283 static bool classof(const ProgramPoint* Location) { 284 return Location->getKind() == PostStoreKind; 285 } 286 }; 287 288 class PostLValue : public PostStmt { 289 public: 290 PostLValue(const Stmt* S, const LocationContext *L, const void *tag = 0) PostStmt(S,PostLValueKind,L,tag)291 : PostStmt(S, PostLValueKind, L, tag) {} 292 classof(const ProgramPoint * Location)293 static bool classof(const ProgramPoint* Location) { 294 return Location->getKind() == PostLValueKind; 295 } 296 }; 297 298 class PostPurgeDeadSymbols : public PostStmt { 299 public: 300 PostPurgeDeadSymbols(const Stmt* S, const LocationContext *L, 301 const void *tag = 0) PostStmt(S,PostPurgeDeadSymbolsKind,L,tag)302 : PostStmt(S, PostPurgeDeadSymbolsKind, L, tag) {} 303 classof(const ProgramPoint * Location)304 static bool classof(const ProgramPoint* Location) { 305 return Location->getKind() == PostPurgeDeadSymbolsKind; 306 } 307 }; 308 309 class BlockEdge : public ProgramPoint { 310 public: BlockEdge(const CFGBlock * B1,const CFGBlock * B2,const LocationContext * L)311 BlockEdge(const CFGBlock* B1, const CFGBlock* B2, const LocationContext *L) 312 : ProgramPoint(B1, B2, BlockEdgeKind, L) {} 313 getSrc()314 const CFGBlock* getSrc() const { 315 return static_cast<const CFGBlock*>(getData1()); 316 } 317 getDst()318 const CFGBlock* getDst() const { 319 return static_cast<const CFGBlock*>(getData2()); 320 } 321 classof(const ProgramPoint * Location)322 static bool classof(const ProgramPoint* Location) { 323 return Location->getKind() == BlockEdgeKind; 324 } 325 }; 326 327 class PostInitializer : public ProgramPoint { 328 public: PostInitializer(const CXXCtorInitializer * I,const LocationContext * L)329 PostInitializer(const CXXCtorInitializer *I, 330 const LocationContext *L) 331 : ProgramPoint(I, PostInitializerKind, L) {} 332 classof(const ProgramPoint * Location)333 static bool classof(const ProgramPoint *Location) { 334 return Location->getKind() == PostInitializerKind; 335 } 336 }; 337 338 class CallEnter : public StmtPoint { 339 public: CallEnter(const Stmt * stmt,const StackFrameContext * calleeCtx,const LocationContext * callerCtx)340 CallEnter(const Stmt *stmt, const StackFrameContext *calleeCtx, 341 const LocationContext *callerCtx) 342 : StmtPoint(stmt, calleeCtx, CallEnterKind, callerCtx, 0) {} 343 getCallExpr()344 const Stmt *getCallExpr() const { 345 return static_cast<const Stmt *>(getData1()); 346 } 347 getCalleeContext()348 const StackFrameContext *getCalleeContext() const { 349 return static_cast<const StackFrameContext *>(getData2()); 350 } 351 classof(const ProgramPoint * Location)352 static bool classof(const ProgramPoint *Location) { 353 return Location->getKind() == CallEnterKind; 354 } 355 }; 356 357 class CallExit : public StmtPoint { 358 public: 359 // CallExit uses the callee's location context. CallExit(const Stmt * S,const LocationContext * L)360 CallExit(const Stmt *S, const LocationContext *L) 361 : StmtPoint(S, 0, CallExitKind, L, 0) {} 362 classof(const ProgramPoint * Location)363 static bool classof(const ProgramPoint *Location) { 364 return Location->getKind() == CallExitKind; 365 } 366 }; 367 368 369 } // end namespace clang 370 371 372 namespace llvm { // Traits specialization for DenseMap 373 374 template <> struct DenseMapInfo<clang::ProgramPoint> { 375 376 static inline clang::ProgramPoint getEmptyKey() { 377 uintptr_t x = 378 reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getEmptyKey()) & ~0x7; 379 return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), 0); 380 } 381 382 static inline clang::ProgramPoint getTombstoneKey() { 383 uintptr_t x = 384 reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getTombstoneKey()) & ~0x7; 385 return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), 0); 386 } 387 388 static unsigned getHashValue(const clang::ProgramPoint& Loc) { 389 return Loc.getHashValue(); 390 } 391 392 static bool isEqual(const clang::ProgramPoint& L, 393 const clang::ProgramPoint& R) { 394 return L == R; 395 } 396 397 }; 398 399 template <> 400 struct isPodLike<clang::ProgramPoint> { static const bool value = true; }; 401 402 } // end namespace llvm 403 404 #endif 405