clang API Documentation

ProgramPoint.h
Go to the documentation of this file.
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