clang API Documentation
00001 //==- ProgramPoint.h - Program Points for Path-Sensitive Analysis --*- C++ -*-// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file defines the interface ProgramPoint, which identifies a 00011 // distinct location in a function. 00012 // 00013 //===----------------------------------------------------------------------===// 00014 00015 #ifndef LLVM_CLANG_ANALYSIS_PROGRAMPOINT_H 00016 #define LLVM_CLANG_ANALYSIS_PROGRAMPOINT_H 00017 00018 #include "clang/Analysis/AnalysisContext.h" 00019 #include "clang/Analysis/CFG.h" 00020 #include "llvm/ADT/DenseMap.h" 00021 #include "llvm/ADT/FoldingSet.h" 00022 #include "llvm/ADT/Optional.h" 00023 #include "llvm/ADT/PointerIntPair.h" 00024 #include "llvm/ADT/StringRef.h" 00025 #include "llvm/Support/Casting.h" 00026 #include "llvm/Support/DataTypes.h" 00027 #include <cassert> 00028 #include <string> 00029 #include <utility> 00030 00031 namespace clang { 00032 00033 class AnalysisDeclContext; 00034 class FunctionDecl; 00035 class LocationContext; 00036 class ProgramPointTag; 00037 00038 class ProgramPoint { 00039 public: 00040 enum Kind { BlockEdgeKind, 00041 BlockEntranceKind, 00042 BlockExitKind, 00043 PreStmtKind, 00044 PreStmtPurgeDeadSymbolsKind, 00045 PostStmtPurgeDeadSymbolsKind, 00046 PostStmtKind, 00047 PreLoadKind, 00048 PostLoadKind, 00049 PreStoreKind, 00050 PostStoreKind, 00051 PostConditionKind, 00052 PostLValueKind, 00053 MinPostStmtKind = PostStmtKind, 00054 MaxPostStmtKind = PostLValueKind, 00055 PostInitializerKind, 00056 CallEnterKind, 00057 CallExitBeginKind, 00058 CallExitEndKind, 00059 PreImplicitCallKind, 00060 PostImplicitCallKind, 00061 MinImplicitCallKind = PreImplicitCallKind, 00062 MaxImplicitCallKind = PostImplicitCallKind, 00063 EpsilonKind}; 00064 00065 private: 00066 const void *Data1; 00067 llvm::PointerIntPair<const void *, 2, unsigned> Data2; 00068 00069 // The LocationContext could be NULL to allow ProgramPoint to be used in 00070 // context insensitive analysis. 00071 llvm::PointerIntPair<const LocationContext *, 2, unsigned> L; 00072 00073 llvm::PointerIntPair<const ProgramPointTag *, 2, unsigned> Tag; 00074 00075 protected: 00076 ProgramPoint() {} 00077 ProgramPoint(const void *P, 00078 Kind k, 00079 const LocationContext *l, 00080 const ProgramPointTag *tag = nullptr) 00081 : Data1(P), 00082 Data2(nullptr, (((unsigned) k) >> 0) & 0x3), 00083 L(l, (((unsigned) k) >> 2) & 0x3), 00084 Tag(tag, (((unsigned) k) >> 4) & 0x3) { 00085 assert(getKind() == k); 00086 assert(getLocationContext() == l); 00087 assert(getData1() == P); 00088 } 00089 00090 ProgramPoint(const void *P1, 00091 const void *P2, 00092 Kind k, 00093 const LocationContext *l, 00094 const ProgramPointTag *tag = nullptr) 00095 : Data1(P1), 00096 Data2(P2, (((unsigned) k) >> 0) & 0x3), 00097 L(l, (((unsigned) k) >> 2) & 0x3), 00098 Tag(tag, (((unsigned) k) >> 4) & 0x3) {} 00099 00100 protected: 00101 const void *getData1() const { return Data1; } 00102 const void *getData2() const { return Data2.getPointer(); } 00103 void setData2(const void *d) { Data2.setPointer(d); } 00104 00105 public: 00106 /// Create a new ProgramPoint object that is the same as the original 00107 /// except for using the specified tag value. 00108 ProgramPoint withTag(const ProgramPointTag *tag) const { 00109 return ProgramPoint(getData1(), getData2(), getKind(), 00110 getLocationContext(), tag); 00111 } 00112 00113 /// \brief Convert to the specified ProgramPoint type, asserting that this 00114 /// ProgramPoint is of the desired type. 00115 template<typename T> 00116 T castAs() const { 00117 assert(T::isKind(*this)); 00118 T t; 00119 ProgramPoint& PP = t; 00120 PP = *this; 00121 return t; 00122 } 00123 00124 /// \brief Convert to the specified ProgramPoint type, returning None if this 00125 /// ProgramPoint is not of the desired type. 00126 template<typename T> 00127 Optional<T> getAs() const { 00128 if (!T::isKind(*this)) 00129 return None; 00130 T t; 00131 ProgramPoint& PP = t; 00132 PP = *this; 00133 return t; 00134 } 00135 00136 Kind getKind() const { 00137 unsigned x = Tag.getInt(); 00138 x <<= 2; 00139 x |= L.getInt(); 00140 x <<= 2; 00141 x |= Data2.getInt(); 00142 return (Kind) x; 00143 } 00144 00145 /// \brief Is this a program point corresponding to purge/removal of dead 00146 /// symbols and bindings. 00147 bool isPurgeKind() { 00148 Kind K = getKind(); 00149 return (K == PostStmtPurgeDeadSymbolsKind || 00150 K == PreStmtPurgeDeadSymbolsKind); 00151 } 00152 00153 const ProgramPointTag *getTag() const { return Tag.getPointer(); } 00154 00155 const LocationContext *getLocationContext() const { 00156 return L.getPointer(); 00157 } 00158 00159 // For use with DenseMap. This hash is probably slow. 00160 unsigned getHashValue() const { 00161 llvm::FoldingSetNodeID ID; 00162 Profile(ID); 00163 return ID.ComputeHash(); 00164 } 00165 00166 bool operator==(const ProgramPoint & RHS) const { 00167 return Data1 == RHS.Data1 && 00168 Data2 == RHS.Data2 && 00169 L == RHS.L && 00170 Tag == RHS.Tag; 00171 } 00172 00173 bool operator!=(const ProgramPoint &RHS) const { 00174 return Data1 != RHS.Data1 || 00175 Data2 != RHS.Data2 || 00176 L != RHS.L || 00177 Tag != RHS.Tag; 00178 } 00179 00180 void Profile(llvm::FoldingSetNodeID& ID) const { 00181 ID.AddInteger((unsigned) getKind()); 00182 ID.AddPointer(getData1()); 00183 ID.AddPointer(getData2()); 00184 ID.AddPointer(getLocationContext()); 00185 ID.AddPointer(getTag()); 00186 } 00187 00188 static ProgramPoint getProgramPoint(const Stmt *S, ProgramPoint::Kind K, 00189 const LocationContext *LC, 00190 const ProgramPointTag *tag); 00191 }; 00192 00193 class BlockEntrance : public ProgramPoint { 00194 public: 00195 BlockEntrance(const CFGBlock *B, const LocationContext *L, 00196 const ProgramPointTag *tag = nullptr) 00197 : ProgramPoint(B, BlockEntranceKind, L, tag) { 00198 assert(B && "BlockEntrance requires non-null block"); 00199 } 00200 00201 const CFGBlock *getBlock() const { 00202 return reinterpret_cast<const CFGBlock*>(getData1()); 00203 } 00204 00205 Optional<CFGElement> getFirstElement() const { 00206 const CFGBlock *B = getBlock(); 00207 return B->empty() ? Optional<CFGElement>() : B->front(); 00208 } 00209 00210 private: 00211 friend class ProgramPoint; 00212 BlockEntrance() {} 00213 static bool isKind(const ProgramPoint &Location) { 00214 return Location.getKind() == BlockEntranceKind; 00215 } 00216 }; 00217 00218 class BlockExit : public ProgramPoint { 00219 public: 00220 BlockExit(const CFGBlock *B, const LocationContext *L) 00221 : ProgramPoint(B, BlockExitKind, L) {} 00222 00223 const CFGBlock *getBlock() const { 00224 return reinterpret_cast<const CFGBlock*>(getData1()); 00225 } 00226 00227 const Stmt *getTerminator() const { 00228 return getBlock()->getTerminator(); 00229 } 00230 00231 private: 00232 friend class ProgramPoint; 00233 BlockExit() {} 00234 static bool isKind(const ProgramPoint &Location) { 00235 return Location.getKind() == BlockExitKind; 00236 } 00237 }; 00238 00239 class StmtPoint : public ProgramPoint { 00240 public: 00241 StmtPoint(const Stmt *S, const void *p2, Kind k, const LocationContext *L, 00242 const ProgramPointTag *tag) 00243 : ProgramPoint(S, p2, k, L, tag) { 00244 assert(S); 00245 } 00246 00247 const Stmt *getStmt() const { return (const Stmt*) getData1(); } 00248 00249 template <typename T> 00250 const T* getStmtAs() const { return dyn_cast<T>(getStmt()); } 00251 00252 protected: 00253 StmtPoint() {} 00254 private: 00255 friend class ProgramPoint; 00256 static bool isKind(const ProgramPoint &Location) { 00257 unsigned k = Location.getKind(); 00258 return k >= PreStmtKind && k <= MaxPostStmtKind; 00259 } 00260 }; 00261 00262 00263 class PreStmt : public StmtPoint { 00264 public: 00265 PreStmt(const Stmt *S, const LocationContext *L, const ProgramPointTag *tag, 00266 const Stmt *SubStmt = nullptr) 00267 : StmtPoint(S, SubStmt, PreStmtKind, L, tag) {} 00268 00269 const Stmt *getSubStmt() const { return (const Stmt*) getData2(); } 00270 00271 private: 00272 friend class ProgramPoint; 00273 PreStmt() {} 00274 static bool isKind(const ProgramPoint &Location) { 00275 return Location.getKind() == PreStmtKind; 00276 } 00277 }; 00278 00279 class PostStmt : public StmtPoint { 00280 protected: 00281 PostStmt() {} 00282 PostStmt(const Stmt *S, const void *data, Kind k, const LocationContext *L, 00283 const ProgramPointTag *tag = nullptr) 00284 : StmtPoint(S, data, k, L, tag) {} 00285 00286 public: 00287 explicit PostStmt(const Stmt *S, Kind k, const LocationContext *L, 00288 const ProgramPointTag *tag = nullptr) 00289 : StmtPoint(S, nullptr, k, L, tag) {} 00290 00291 explicit PostStmt(const Stmt *S, const LocationContext *L, 00292 const ProgramPointTag *tag = nullptr) 00293 : StmtPoint(S, nullptr, PostStmtKind, L, tag) {} 00294 00295 private: 00296 friend class ProgramPoint; 00297 static bool isKind(const ProgramPoint &Location) { 00298 unsigned k = Location.getKind(); 00299 return k >= MinPostStmtKind && k <= MaxPostStmtKind; 00300 } 00301 }; 00302 00303 // PostCondition represents the post program point of a branch condition. 00304 class PostCondition : public PostStmt { 00305 public: 00306 PostCondition(const Stmt *S, const LocationContext *L, 00307 const ProgramPointTag *tag = nullptr) 00308 : PostStmt(S, PostConditionKind, L, tag) {} 00309 00310 private: 00311 friend class ProgramPoint; 00312 PostCondition() {} 00313 static bool isKind(const ProgramPoint &Location) { 00314 return Location.getKind() == PostConditionKind; 00315 } 00316 }; 00317 00318 class LocationCheck : public StmtPoint { 00319 protected: 00320 LocationCheck() {} 00321 LocationCheck(const Stmt *S, const LocationContext *L, 00322 ProgramPoint::Kind K, const ProgramPointTag *tag) 00323 : StmtPoint(S, nullptr, K, L, tag) {} 00324 00325 private: 00326 friend class ProgramPoint; 00327 static bool isKind(const ProgramPoint &location) { 00328 unsigned k = location.getKind(); 00329 return k == PreLoadKind || k == PreStoreKind; 00330 } 00331 }; 00332 00333 class PreLoad : public LocationCheck { 00334 public: 00335 PreLoad(const Stmt *S, const LocationContext *L, 00336 const ProgramPointTag *tag = nullptr) 00337 : LocationCheck(S, L, PreLoadKind, tag) {} 00338 00339 private: 00340 friend class ProgramPoint; 00341 PreLoad() {} 00342 static bool isKind(const ProgramPoint &location) { 00343 return location.getKind() == PreLoadKind; 00344 } 00345 }; 00346 00347 class PreStore : public LocationCheck { 00348 public: 00349 PreStore(const Stmt *S, const LocationContext *L, 00350 const ProgramPointTag *tag = nullptr) 00351 : LocationCheck(S, L, PreStoreKind, tag) {} 00352 00353 private: 00354 friend class ProgramPoint; 00355 PreStore() {} 00356 static bool isKind(const ProgramPoint &location) { 00357 return location.getKind() == PreStoreKind; 00358 } 00359 }; 00360 00361 class PostLoad : public PostStmt { 00362 public: 00363 PostLoad(const Stmt *S, const LocationContext *L, 00364 const ProgramPointTag *tag = nullptr) 00365 : PostStmt(S, PostLoadKind, L, tag) {} 00366 00367 private: 00368 friend class ProgramPoint; 00369 PostLoad() {} 00370 static bool isKind(const ProgramPoint &Location) { 00371 return Location.getKind() == PostLoadKind; 00372 } 00373 }; 00374 00375 /// \brief Represents a program point after a store evaluation. 00376 class PostStore : public PostStmt { 00377 public: 00378 /// Construct the post store point. 00379 /// \param Loc can be used to store the information about the location 00380 /// used in the form it was uttered in the code. 00381 PostStore(const Stmt *S, const LocationContext *L, const void *Loc, 00382 const ProgramPointTag *tag = nullptr) 00383 : PostStmt(S, PostStoreKind, L, tag) { 00384 assert(getData2() == nullptr); 00385 setData2(Loc); 00386 } 00387 00388 /// \brief Returns the information about the location used in the store, 00389 /// how it was uttered in the code. 00390 const void *getLocationValue() const { 00391 return getData2(); 00392 } 00393 00394 private: 00395 friend class ProgramPoint; 00396 PostStore() {} 00397 static bool isKind(const ProgramPoint &Location) { 00398 return Location.getKind() == PostStoreKind; 00399 } 00400 }; 00401 00402 class PostLValue : public PostStmt { 00403 public: 00404 PostLValue(const Stmt *S, const LocationContext *L, 00405 const ProgramPointTag *tag = nullptr) 00406 : PostStmt(S, PostLValueKind, L, tag) {} 00407 00408 private: 00409 friend class ProgramPoint; 00410 PostLValue() {} 00411 static bool isKind(const ProgramPoint &Location) { 00412 return Location.getKind() == PostLValueKind; 00413 } 00414 }; 00415 00416 /// Represents a point after we ran remove dead bindings BEFORE 00417 /// processing the given statement. 00418 class PreStmtPurgeDeadSymbols : public StmtPoint { 00419 public: 00420 PreStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L, 00421 const ProgramPointTag *tag = nullptr) 00422 : StmtPoint(S, nullptr, PreStmtPurgeDeadSymbolsKind, L, tag) { } 00423 00424 private: 00425 friend class ProgramPoint; 00426 PreStmtPurgeDeadSymbols() {} 00427 static bool isKind(const ProgramPoint &Location) { 00428 return Location.getKind() == PreStmtPurgeDeadSymbolsKind; 00429 } 00430 }; 00431 00432 /// Represents a point after we ran remove dead bindings AFTER 00433 /// processing the given statement. 00434 class PostStmtPurgeDeadSymbols : public StmtPoint { 00435 public: 00436 PostStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L, 00437 const ProgramPointTag *tag = nullptr) 00438 : StmtPoint(S, nullptr, PostStmtPurgeDeadSymbolsKind, L, tag) { } 00439 00440 private: 00441 friend class ProgramPoint; 00442 PostStmtPurgeDeadSymbols() {} 00443 static bool isKind(const ProgramPoint &Location) { 00444 return Location.getKind() == PostStmtPurgeDeadSymbolsKind; 00445 } 00446 }; 00447 00448 class BlockEdge : public ProgramPoint { 00449 public: 00450 BlockEdge(const CFGBlock *B1, const CFGBlock *B2, const LocationContext *L) 00451 : ProgramPoint(B1, B2, BlockEdgeKind, L) { 00452 assert(B1 && "BlockEdge: source block must be non-null"); 00453 assert(B2 && "BlockEdge: destination block must be non-null"); 00454 } 00455 00456 const CFGBlock *getSrc() const { 00457 return static_cast<const CFGBlock*>(getData1()); 00458 } 00459 00460 const CFGBlock *getDst() const { 00461 return static_cast<const CFGBlock*>(getData2()); 00462 } 00463 00464 private: 00465 friend class ProgramPoint; 00466 BlockEdge() {} 00467 static bool isKind(const ProgramPoint &Location) { 00468 return Location.getKind() == BlockEdgeKind; 00469 } 00470 }; 00471 00472 class PostInitializer : public ProgramPoint { 00473 public: 00474 /// \brief Construct a PostInitializer point that represents a location after 00475 /// CXXCtorInitializer expression evaluation. 00476 /// 00477 /// \param I The initializer. 00478 /// \param Loc The location of the field being initialized. 00479 PostInitializer(const CXXCtorInitializer *I, 00480 const void *Loc, 00481 const LocationContext *L) 00482 : ProgramPoint(I, Loc, PostInitializerKind, L) {} 00483 00484 const CXXCtorInitializer *getInitializer() const { 00485 return static_cast<const CXXCtorInitializer *>(getData1()); 00486 } 00487 00488 /// \brief Returns the location of the field. 00489 const void *getLocationValue() const { 00490 return getData2(); 00491 } 00492 00493 private: 00494 friend class ProgramPoint; 00495 PostInitializer() {} 00496 static bool isKind(const ProgramPoint &Location) { 00497 return Location.getKind() == PostInitializerKind; 00498 } 00499 }; 00500 00501 /// Represents an implicit call event. 00502 /// 00503 /// The nearest statement is provided for diagnostic purposes. 00504 class ImplicitCallPoint : public ProgramPoint { 00505 public: 00506 ImplicitCallPoint(const Decl *D, SourceLocation Loc, Kind K, 00507 const LocationContext *L, const ProgramPointTag *Tag) 00508 : ProgramPoint(Loc.getPtrEncoding(), D, K, L, Tag) {} 00509 00510 const Decl *getDecl() const { return static_cast<const Decl *>(getData2()); } 00511 SourceLocation getLocation() const { 00512 return SourceLocation::getFromPtrEncoding(getData1()); 00513 } 00514 00515 protected: 00516 ImplicitCallPoint() {} 00517 private: 00518 friend class ProgramPoint; 00519 static bool isKind(const ProgramPoint &Location) { 00520 return Location.getKind() >= MinImplicitCallKind && 00521 Location.getKind() <= MaxImplicitCallKind; 00522 } 00523 }; 00524 00525 /// Represents a program point just before an implicit call event. 00526 /// 00527 /// Explicit calls will appear as PreStmt program points. 00528 class PreImplicitCall : public ImplicitCallPoint { 00529 public: 00530 PreImplicitCall(const Decl *D, SourceLocation Loc, const LocationContext *L, 00531 const ProgramPointTag *Tag = nullptr) 00532 : ImplicitCallPoint(D, Loc, PreImplicitCallKind, L, Tag) {} 00533 00534 private: 00535 friend class ProgramPoint; 00536 PreImplicitCall() {} 00537 static bool isKind(const ProgramPoint &Location) { 00538 return Location.getKind() == PreImplicitCallKind; 00539 } 00540 }; 00541 00542 /// Represents a program point just after an implicit call event. 00543 /// 00544 /// Explicit calls will appear as PostStmt program points. 00545 class PostImplicitCall : public ImplicitCallPoint { 00546 public: 00547 PostImplicitCall(const Decl *D, SourceLocation Loc, const LocationContext *L, 00548 const ProgramPointTag *Tag = nullptr) 00549 : ImplicitCallPoint(D, Loc, PostImplicitCallKind, L, Tag) {} 00550 00551 private: 00552 friend class ProgramPoint; 00553 PostImplicitCall() {} 00554 static bool isKind(const ProgramPoint &Location) { 00555 return Location.getKind() == PostImplicitCallKind; 00556 } 00557 }; 00558 00559 /// Represents a point when we begin processing an inlined call. 00560 /// CallEnter uses the caller's location context. 00561 class CallEnter : public ProgramPoint { 00562 public: 00563 CallEnter(const Stmt *stmt, const StackFrameContext *calleeCtx, 00564 const LocationContext *callerCtx) 00565 : ProgramPoint(stmt, calleeCtx, CallEnterKind, callerCtx, nullptr) {} 00566 00567 const Stmt *getCallExpr() const { 00568 return static_cast<const Stmt *>(getData1()); 00569 } 00570 00571 const StackFrameContext *getCalleeContext() const { 00572 return static_cast<const StackFrameContext *>(getData2()); 00573 } 00574 00575 private: 00576 friend class ProgramPoint; 00577 CallEnter() {} 00578 static bool isKind(const ProgramPoint &Location) { 00579 return Location.getKind() == CallEnterKind; 00580 } 00581 }; 00582 00583 /// Represents a point when we start the call exit sequence (for inlined call). 00584 /// 00585 /// The call exit is simulated with a sequence of nodes, which occur between 00586 /// CallExitBegin and CallExitEnd. The following operations occur between the 00587 /// two program points: 00588 /// - CallExitBegin 00589 /// - Bind the return value 00590 /// - Run Remove dead bindings (to clean up the dead symbols from the callee). 00591 /// - CallExitEnd 00592 class CallExitBegin : public ProgramPoint { 00593 public: 00594 // CallExitBegin uses the callee's location context. 00595 CallExitBegin(const StackFrameContext *L) 00596 : ProgramPoint(nullptr, CallExitBeginKind, L, nullptr) {} 00597 00598 private: 00599 friend class ProgramPoint; 00600 CallExitBegin() {} 00601 static bool isKind(const ProgramPoint &Location) { 00602 return Location.getKind() == CallExitBeginKind; 00603 } 00604 }; 00605 00606 /// Represents a point when we finish the call exit sequence (for inlined call). 00607 /// \sa CallExitBegin 00608 class CallExitEnd : public ProgramPoint { 00609 public: 00610 // CallExitEnd uses the caller's location context. 00611 CallExitEnd(const StackFrameContext *CalleeCtx, 00612 const LocationContext *CallerCtx) 00613 : ProgramPoint(CalleeCtx, CallExitEndKind, CallerCtx, nullptr) {} 00614 00615 const StackFrameContext *getCalleeContext() const { 00616 return static_cast<const StackFrameContext *>(getData1()); 00617 } 00618 00619 private: 00620 friend class ProgramPoint; 00621 CallExitEnd() {} 00622 static bool isKind(const ProgramPoint &Location) { 00623 return Location.getKind() == CallExitEndKind; 00624 } 00625 }; 00626 00627 /// This is a meta program point, which should be skipped by all the diagnostic 00628 /// reasoning etc. 00629 class EpsilonPoint : public ProgramPoint { 00630 public: 00631 EpsilonPoint(const LocationContext *L, const void *Data1, 00632 const void *Data2 = nullptr, 00633 const ProgramPointTag *tag = nullptr) 00634 : ProgramPoint(Data1, Data2, EpsilonKind, L, tag) {} 00635 00636 const void *getData() const { return getData1(); } 00637 00638 private: 00639 friend class ProgramPoint; 00640 EpsilonPoint() {} 00641 static bool isKind(const ProgramPoint &Location) { 00642 return Location.getKind() == EpsilonKind; 00643 } 00644 }; 00645 00646 /// ProgramPoints can be "tagged" as representing points specific to a given 00647 /// analysis entity. Tags are abstract annotations, with an associated 00648 /// description and potentially other information. 00649 class ProgramPointTag { 00650 public: 00651 ProgramPointTag(void *tagKind = nullptr) : TagKind(tagKind) {} 00652 virtual ~ProgramPointTag(); 00653 virtual StringRef getTagDescription() const = 0; 00654 00655 protected: 00656 /// Used to implement 'isKind' in subclasses. 00657 const void *getTagKind() { return TagKind; } 00658 00659 private: 00660 const void *TagKind; 00661 }; 00662 00663 class SimpleProgramPointTag : public ProgramPointTag { 00664 std::string Desc; 00665 public: 00666 SimpleProgramPointTag(StringRef MsgProvider, StringRef Msg); 00667 StringRef getTagDescription() const override; 00668 }; 00669 00670 } // end namespace clang 00671 00672 00673 namespace llvm { // Traits specialization for DenseMap 00674 00675 template <> struct DenseMapInfo<clang::ProgramPoint> { 00676 00677 static inline clang::ProgramPoint getEmptyKey() { 00678 uintptr_t x = 00679 reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getEmptyKey()) & ~0x7; 00680 return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), nullptr); 00681 } 00682 00683 static inline clang::ProgramPoint getTombstoneKey() { 00684 uintptr_t x = 00685 reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getTombstoneKey()) & ~0x7; 00686 return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), nullptr); 00687 } 00688 00689 static unsigned getHashValue(const clang::ProgramPoint &Loc) { 00690 return Loc.getHashValue(); 00691 } 00692 00693 static bool isEqual(const clang::ProgramPoint &L, 00694 const clang::ProgramPoint &R) { 00695 return L == R; 00696 } 00697 00698 }; 00699 00700 template <> 00701 struct isPodLike<clang::ProgramPoint> { static const bool value = true; }; 00702 00703 } // end namespace llvm 00704 00705 #endif