1e5dd7070Spatrick //==- ProgramPoint.h - Program Points for Path-Sensitive Analysis --*- C++ -*-//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick //  This file defines the interface ProgramPoint, which identifies a
10e5dd7070Spatrick //  distinct location in a function.
11e5dd7070Spatrick //
12e5dd7070Spatrick //===----------------------------------------------------------------------===//
13e5dd7070Spatrick 
14e5dd7070Spatrick #ifndef LLVM_CLANG_ANALYSIS_PROGRAMPOINT_H
15e5dd7070Spatrick #define LLVM_CLANG_ANALYSIS_PROGRAMPOINT_H
16e5dd7070Spatrick 
17e5dd7070Spatrick #include "clang/Analysis/AnalysisDeclContext.h"
18e5dd7070Spatrick #include "clang/Analysis/CFG.h"
19e5dd7070Spatrick #include "llvm/ADT/DenseMap.h"
20e5dd7070Spatrick #include "llvm/ADT/FoldingSet.h"
21e5dd7070Spatrick #include "llvm/ADT/PointerIntPair.h"
22e5dd7070Spatrick #include "llvm/ADT/StringRef.h"
23e5dd7070Spatrick #include "llvm/Support/Casting.h"
24e5dd7070Spatrick #include "llvm/Support/DataTypes.h"
25e5dd7070Spatrick #include <cassert>
26*12c85518Srobert #include <optional>
27e5dd7070Spatrick #include <string>
28e5dd7070Spatrick #include <utility>
29e5dd7070Spatrick 
30e5dd7070Spatrick namespace clang {
31e5dd7070Spatrick 
32e5dd7070Spatrick class AnalysisDeclContext;
33e5dd7070Spatrick class LocationContext;
34e5dd7070Spatrick 
35e5dd7070Spatrick /// ProgramPoints can be "tagged" as representing points specific to a given
36e5dd7070Spatrick /// analysis entity.  Tags are abstract annotations, with an associated
37e5dd7070Spatrick /// description and potentially other information.
38e5dd7070Spatrick class ProgramPointTag {
39e5dd7070Spatrick public:
TagKind(tagKind)40e5dd7070Spatrick   ProgramPointTag(void *tagKind = nullptr) : TagKind(tagKind) {}
41e5dd7070Spatrick   virtual ~ProgramPointTag();
42e5dd7070Spatrick   virtual StringRef getTagDescription() const = 0;
43e5dd7070Spatrick 
44e5dd7070Spatrick   /// Used to implement 'isKind' in subclasses.
getTagKind()45e5dd7070Spatrick   const void *getTagKind() const { return TagKind; }
46e5dd7070Spatrick 
47e5dd7070Spatrick private:
48e5dd7070Spatrick   const void *const TagKind;
49e5dd7070Spatrick };
50e5dd7070Spatrick 
51e5dd7070Spatrick class SimpleProgramPointTag : public ProgramPointTag {
52e5dd7070Spatrick   std::string Desc;
53e5dd7070Spatrick public:
54e5dd7070Spatrick   SimpleProgramPointTag(StringRef MsgProvider, StringRef Msg);
55e5dd7070Spatrick   StringRef getTagDescription() const override;
56e5dd7070Spatrick };
57e5dd7070Spatrick 
58e5dd7070Spatrick class ProgramPoint {
59e5dd7070Spatrick public:
60e5dd7070Spatrick   enum Kind { BlockEdgeKind,
61e5dd7070Spatrick               BlockEntranceKind,
62e5dd7070Spatrick               BlockExitKind,
63e5dd7070Spatrick               PreStmtKind,
64e5dd7070Spatrick               PreStmtPurgeDeadSymbolsKind,
65e5dd7070Spatrick               PostStmtPurgeDeadSymbolsKind,
66e5dd7070Spatrick               PostStmtKind,
67e5dd7070Spatrick               PreLoadKind,
68e5dd7070Spatrick               PostLoadKind,
69e5dd7070Spatrick               PreStoreKind,
70e5dd7070Spatrick               PostStoreKind,
71e5dd7070Spatrick               PostConditionKind,
72e5dd7070Spatrick               PostLValueKind,
73e5dd7070Spatrick               PostAllocatorCallKind,
74e5dd7070Spatrick               MinPostStmtKind = PostStmtKind,
75e5dd7070Spatrick               MaxPostStmtKind = PostAllocatorCallKind,
76e5dd7070Spatrick               PostInitializerKind,
77e5dd7070Spatrick               CallEnterKind,
78e5dd7070Spatrick               CallExitBeginKind,
79e5dd7070Spatrick               CallExitEndKind,
80e5dd7070Spatrick               FunctionExitKind,
81e5dd7070Spatrick               PreImplicitCallKind,
82e5dd7070Spatrick               PostImplicitCallKind,
83e5dd7070Spatrick               MinImplicitCallKind = PreImplicitCallKind,
84e5dd7070Spatrick               MaxImplicitCallKind = PostImplicitCallKind,
85e5dd7070Spatrick               LoopExitKind,
86e5dd7070Spatrick               EpsilonKind};
87e5dd7070Spatrick 
88e5dd7070Spatrick private:
89e5dd7070Spatrick   const void *Data1;
90e5dd7070Spatrick   llvm::PointerIntPair<const void *, 2, unsigned> Data2;
91e5dd7070Spatrick 
92e5dd7070Spatrick   // The LocationContext could be NULL to allow ProgramPoint to be used in
93e5dd7070Spatrick   // context insensitive analysis.
94e5dd7070Spatrick   llvm::PointerIntPair<const LocationContext *, 2, unsigned> L;
95e5dd7070Spatrick 
96e5dd7070Spatrick   llvm::PointerIntPair<const ProgramPointTag *, 2, unsigned> Tag;
97e5dd7070Spatrick 
98e5dd7070Spatrick protected:
99e5dd7070Spatrick   ProgramPoint() = default;
100e5dd7070Spatrick   ProgramPoint(const void *P,
101e5dd7070Spatrick                Kind k,
102e5dd7070Spatrick                const LocationContext *l,
103e5dd7070Spatrick                const ProgramPointTag *tag = nullptr)
Data1(P)104e5dd7070Spatrick     : Data1(P),
105e5dd7070Spatrick       Data2(nullptr, (((unsigned) k) >> 0) & 0x3),
106e5dd7070Spatrick       L(l, (((unsigned) k) >> 2) & 0x3),
107e5dd7070Spatrick       Tag(tag, (((unsigned) k) >> 4) & 0x3) {
108e5dd7070Spatrick         assert(getKind() == k);
109e5dd7070Spatrick         assert(getLocationContext() == l);
110e5dd7070Spatrick         assert(getData1() == P);
111e5dd7070Spatrick       }
112e5dd7070Spatrick 
113e5dd7070Spatrick   ProgramPoint(const void *P1,
114e5dd7070Spatrick                const void *P2,
115e5dd7070Spatrick                Kind k,
116e5dd7070Spatrick                const LocationContext *l,
117e5dd7070Spatrick                const ProgramPointTag *tag = nullptr)
Data1(P1)118e5dd7070Spatrick     : Data1(P1),
119e5dd7070Spatrick       Data2(P2, (((unsigned) k) >> 0) & 0x3),
120e5dd7070Spatrick       L(l, (((unsigned) k) >> 2) & 0x3),
121e5dd7070Spatrick       Tag(tag, (((unsigned) k) >> 4) & 0x3) {}
122e5dd7070Spatrick 
123e5dd7070Spatrick protected:
getData1()124e5dd7070Spatrick   const void *getData1() const { return Data1; }
getData2()125e5dd7070Spatrick   const void *getData2() const { return Data2.getPointer(); }
setData2(const void * d)126e5dd7070Spatrick   void setData2(const void *d) { Data2.setPointer(d); }
127e5dd7070Spatrick 
128e5dd7070Spatrick public:
129e5dd7070Spatrick   /// Create a new ProgramPoint object that is the same as the original
130e5dd7070Spatrick   /// except for using the specified tag value.
withTag(const ProgramPointTag * tag)131e5dd7070Spatrick   ProgramPoint withTag(const ProgramPointTag *tag) const {
132e5dd7070Spatrick     return ProgramPoint(getData1(), getData2(), getKind(),
133e5dd7070Spatrick                         getLocationContext(), tag);
134e5dd7070Spatrick   }
135e5dd7070Spatrick 
136e5dd7070Spatrick   /// Convert to the specified ProgramPoint type, asserting that this
137e5dd7070Spatrick   /// ProgramPoint is of the desired type.
138e5dd7070Spatrick   template<typename T>
castAs()139e5dd7070Spatrick   T castAs() const {
140e5dd7070Spatrick     assert(T::isKind(*this));
141e5dd7070Spatrick     T t;
142e5dd7070Spatrick     ProgramPoint& PP = t;
143e5dd7070Spatrick     PP = *this;
144e5dd7070Spatrick     return t;
145e5dd7070Spatrick   }
146e5dd7070Spatrick 
147*12c85518Srobert   /// Convert to the specified ProgramPoint type, returning std::nullopt if this
148e5dd7070Spatrick   /// ProgramPoint is not of the desired type.
getAs()149*12c85518Srobert   template <typename T> std::optional<T> getAs() const {
150e5dd7070Spatrick     if (!T::isKind(*this))
151*12c85518Srobert       return std::nullopt;
152e5dd7070Spatrick     T t;
153e5dd7070Spatrick     ProgramPoint& PP = t;
154e5dd7070Spatrick     PP = *this;
155e5dd7070Spatrick     return t;
156e5dd7070Spatrick   }
157e5dd7070Spatrick 
getKind()158e5dd7070Spatrick   Kind getKind() const {
159e5dd7070Spatrick     unsigned x = Tag.getInt();
160e5dd7070Spatrick     x <<= 2;
161e5dd7070Spatrick     x |= L.getInt();
162e5dd7070Spatrick     x <<= 2;
163e5dd7070Spatrick     x |= Data2.getInt();
164e5dd7070Spatrick     return (Kind) x;
165e5dd7070Spatrick   }
166e5dd7070Spatrick 
167e5dd7070Spatrick   /// Is this a program point corresponding to purge/removal of dead
168e5dd7070Spatrick   /// symbols and bindings.
isPurgeKind()169e5dd7070Spatrick   bool isPurgeKind() {
170e5dd7070Spatrick     Kind K = getKind();
171e5dd7070Spatrick     return (K == PostStmtPurgeDeadSymbolsKind ||
172e5dd7070Spatrick             K == PreStmtPurgeDeadSymbolsKind);
173e5dd7070Spatrick   }
174e5dd7070Spatrick 
getTag()175e5dd7070Spatrick   const ProgramPointTag *getTag() const { return Tag.getPointer(); }
176e5dd7070Spatrick 
getLocationContext()177e5dd7070Spatrick   const LocationContext *getLocationContext() const {
178e5dd7070Spatrick     return L.getPointer();
179e5dd7070Spatrick   }
180e5dd7070Spatrick 
getStackFrame()181e5dd7070Spatrick   const StackFrameContext *getStackFrame() const {
182e5dd7070Spatrick     return getLocationContext()->getStackFrame();
183e5dd7070Spatrick   }
184e5dd7070Spatrick 
185e5dd7070Spatrick   // For use with DenseMap.  This hash is probably slow.
getHashValue()186e5dd7070Spatrick   unsigned getHashValue() const {
187e5dd7070Spatrick     llvm::FoldingSetNodeID ID;
188e5dd7070Spatrick     Profile(ID);
189e5dd7070Spatrick     return ID.ComputeHash();
190e5dd7070Spatrick   }
191e5dd7070Spatrick 
192e5dd7070Spatrick   bool operator==(const ProgramPoint & RHS) const {
193e5dd7070Spatrick     return Data1 == RHS.Data1 &&
194e5dd7070Spatrick            Data2 == RHS.Data2 &&
195e5dd7070Spatrick            L == RHS.L &&
196e5dd7070Spatrick            Tag == RHS.Tag;
197e5dd7070Spatrick   }
198e5dd7070Spatrick 
199e5dd7070Spatrick   bool operator!=(const ProgramPoint &RHS) const {
200e5dd7070Spatrick     return Data1 != RHS.Data1 ||
201e5dd7070Spatrick            Data2 != RHS.Data2 ||
202e5dd7070Spatrick            L != RHS.L ||
203e5dd7070Spatrick            Tag != RHS.Tag;
204e5dd7070Spatrick   }
205e5dd7070Spatrick 
Profile(llvm::FoldingSetNodeID & ID)206e5dd7070Spatrick   void Profile(llvm::FoldingSetNodeID& ID) const {
207e5dd7070Spatrick     ID.AddInteger((unsigned) getKind());
208e5dd7070Spatrick     ID.AddPointer(getData1());
209e5dd7070Spatrick     ID.AddPointer(getData2());
210e5dd7070Spatrick     ID.AddPointer(getLocationContext());
211e5dd7070Spatrick     ID.AddPointer(getTag());
212e5dd7070Spatrick   }
213e5dd7070Spatrick 
214e5dd7070Spatrick   void printJson(llvm::raw_ostream &Out, const char *NL = "\n") const;
215e5dd7070Spatrick 
216e5dd7070Spatrick   LLVM_DUMP_METHOD void dump() const;
217e5dd7070Spatrick 
218e5dd7070Spatrick   static ProgramPoint getProgramPoint(const Stmt *S, ProgramPoint::Kind K,
219e5dd7070Spatrick                                       const LocationContext *LC,
220e5dd7070Spatrick                                       const ProgramPointTag *tag);
221e5dd7070Spatrick };
222e5dd7070Spatrick 
223e5dd7070Spatrick class BlockEntrance : public ProgramPoint {
224e5dd7070Spatrick public:
225e5dd7070Spatrick   BlockEntrance(const CFGBlock *B, const LocationContext *L,
226e5dd7070Spatrick                 const ProgramPointTag *tag = nullptr)
ProgramPoint(B,BlockEntranceKind,L,tag)227e5dd7070Spatrick     : ProgramPoint(B, BlockEntranceKind, L, tag) {
228e5dd7070Spatrick     assert(B && "BlockEntrance requires non-null block");
229e5dd7070Spatrick   }
230e5dd7070Spatrick 
getBlock()231e5dd7070Spatrick   const CFGBlock *getBlock() const {
232e5dd7070Spatrick     return reinterpret_cast<const CFGBlock*>(getData1());
233e5dd7070Spatrick   }
234e5dd7070Spatrick 
getFirstElement()235*12c85518Srobert   std::optional<CFGElement> getFirstElement() const {
236e5dd7070Spatrick     const CFGBlock *B = getBlock();
237*12c85518Srobert     return B->empty() ? std::optional<CFGElement>() : B->front();
238e5dd7070Spatrick   }
239e5dd7070Spatrick 
240e5dd7070Spatrick private:
241e5dd7070Spatrick   friend class ProgramPoint;
242e5dd7070Spatrick   BlockEntrance() = default;
isKind(const ProgramPoint & Location)243e5dd7070Spatrick   static bool isKind(const ProgramPoint &Location) {
244e5dd7070Spatrick     return Location.getKind() == BlockEntranceKind;
245e5dd7070Spatrick   }
246e5dd7070Spatrick };
247e5dd7070Spatrick 
248e5dd7070Spatrick class BlockExit : public ProgramPoint {
249e5dd7070Spatrick public:
BlockExit(const CFGBlock * B,const LocationContext * L)250e5dd7070Spatrick   BlockExit(const CFGBlock *B, const LocationContext *L)
251e5dd7070Spatrick     : ProgramPoint(B, BlockExitKind, L) {}
252e5dd7070Spatrick 
getBlock()253e5dd7070Spatrick   const CFGBlock *getBlock() const {
254e5dd7070Spatrick     return reinterpret_cast<const CFGBlock*>(getData1());
255e5dd7070Spatrick   }
256e5dd7070Spatrick 
getTerminator()257e5dd7070Spatrick   const Stmt *getTerminator() const {
258e5dd7070Spatrick     return getBlock()->getTerminatorStmt();
259e5dd7070Spatrick   }
260e5dd7070Spatrick 
261e5dd7070Spatrick private:
262e5dd7070Spatrick   friend class ProgramPoint;
263e5dd7070Spatrick   BlockExit() = default;
isKind(const ProgramPoint & Location)264e5dd7070Spatrick   static bool isKind(const ProgramPoint &Location) {
265e5dd7070Spatrick     return Location.getKind() == BlockExitKind;
266e5dd7070Spatrick   }
267e5dd7070Spatrick };
268e5dd7070Spatrick 
269e5dd7070Spatrick class StmtPoint : public ProgramPoint {
270e5dd7070Spatrick public:
StmtPoint(const Stmt * S,const void * p2,Kind k,const LocationContext * L,const ProgramPointTag * tag)271e5dd7070Spatrick   StmtPoint(const Stmt *S, const void *p2, Kind k, const LocationContext *L,
272e5dd7070Spatrick             const ProgramPointTag *tag)
273e5dd7070Spatrick     : ProgramPoint(S, p2, k, L, tag) {
274e5dd7070Spatrick     assert(S);
275e5dd7070Spatrick   }
276e5dd7070Spatrick 
getStmt()277e5dd7070Spatrick   const Stmt *getStmt() const { return (const Stmt*) getData1(); }
278e5dd7070Spatrick 
279e5dd7070Spatrick   template <typename T>
getStmtAs()280e5dd7070Spatrick   const T* getStmtAs() const { return dyn_cast<T>(getStmt()); }
281e5dd7070Spatrick 
282e5dd7070Spatrick protected:
283e5dd7070Spatrick   StmtPoint() = default;
284e5dd7070Spatrick private:
285e5dd7070Spatrick   friend class ProgramPoint;
isKind(const ProgramPoint & Location)286e5dd7070Spatrick   static bool isKind(const ProgramPoint &Location) {
287e5dd7070Spatrick     unsigned k = Location.getKind();
288e5dd7070Spatrick     return k >= PreStmtKind && k <= MaxPostStmtKind;
289e5dd7070Spatrick   }
290e5dd7070Spatrick };
291e5dd7070Spatrick 
292e5dd7070Spatrick 
293e5dd7070Spatrick class PreStmt : public StmtPoint {
294e5dd7070Spatrick public:
295e5dd7070Spatrick   PreStmt(const Stmt *S, const LocationContext *L, const ProgramPointTag *tag,
296e5dd7070Spatrick           const Stmt *SubStmt = nullptr)
StmtPoint(S,SubStmt,PreStmtKind,L,tag)297e5dd7070Spatrick     : StmtPoint(S, SubStmt, PreStmtKind, L, tag) {}
298e5dd7070Spatrick 
getSubStmt()299e5dd7070Spatrick   const Stmt *getSubStmt() const { return (const Stmt*) getData2(); }
300e5dd7070Spatrick 
301e5dd7070Spatrick private:
302e5dd7070Spatrick   friend class ProgramPoint;
303e5dd7070Spatrick   PreStmt() = default;
isKind(const ProgramPoint & Location)304e5dd7070Spatrick   static bool isKind(const ProgramPoint &Location) {
305e5dd7070Spatrick     return Location.getKind() == PreStmtKind;
306e5dd7070Spatrick   }
307e5dd7070Spatrick };
308e5dd7070Spatrick 
309e5dd7070Spatrick class PostStmt : public StmtPoint {
310e5dd7070Spatrick protected:
311e5dd7070Spatrick   PostStmt() = default;
312e5dd7070Spatrick   PostStmt(const Stmt *S, const void *data, Kind k, const LocationContext *L,
313e5dd7070Spatrick            const ProgramPointTag *tag = nullptr)
StmtPoint(S,data,k,L,tag)314e5dd7070Spatrick     : StmtPoint(S, data, k, L, tag) {}
315e5dd7070Spatrick 
316e5dd7070Spatrick public:
317e5dd7070Spatrick   explicit PostStmt(const Stmt *S, Kind k, const LocationContext *L,
318e5dd7070Spatrick                     const ProgramPointTag *tag = nullptr)
StmtPoint(S,nullptr,k,L,tag)319e5dd7070Spatrick     : StmtPoint(S, nullptr, k, L, tag) {}
320e5dd7070Spatrick 
321e5dd7070Spatrick   explicit PostStmt(const Stmt *S, const LocationContext *L,
322e5dd7070Spatrick                     const ProgramPointTag *tag = nullptr)
StmtPoint(S,nullptr,PostStmtKind,L,tag)323e5dd7070Spatrick     : StmtPoint(S, nullptr, PostStmtKind, L, tag) {}
324e5dd7070Spatrick 
325e5dd7070Spatrick private:
326e5dd7070Spatrick   friend class ProgramPoint;
isKind(const ProgramPoint & Location)327e5dd7070Spatrick   static bool isKind(const ProgramPoint &Location) {
328e5dd7070Spatrick     unsigned k = Location.getKind();
329e5dd7070Spatrick     return k >= MinPostStmtKind && k <= MaxPostStmtKind;
330e5dd7070Spatrick   }
331e5dd7070Spatrick };
332e5dd7070Spatrick 
333e5dd7070Spatrick class FunctionExitPoint : public ProgramPoint {
334e5dd7070Spatrick public:
335e5dd7070Spatrick   explicit FunctionExitPoint(const ReturnStmt *S,
336e5dd7070Spatrick                              const LocationContext *LC,
337e5dd7070Spatrick                              const ProgramPointTag *tag = nullptr)
ProgramPoint(S,FunctionExitKind,LC,tag)338e5dd7070Spatrick       : ProgramPoint(S, FunctionExitKind, LC, tag) {}
339e5dd7070Spatrick 
getBlock()340e5dd7070Spatrick   const CFGBlock *getBlock() const {
341e5dd7070Spatrick     return &getLocationContext()->getCFG()->getExit();
342e5dd7070Spatrick   }
343e5dd7070Spatrick 
getStmt()344e5dd7070Spatrick   const ReturnStmt *getStmt() const {
345e5dd7070Spatrick     return reinterpret_cast<const ReturnStmt *>(getData1());
346e5dd7070Spatrick   }
347e5dd7070Spatrick 
348e5dd7070Spatrick private:
349e5dd7070Spatrick   friend class ProgramPoint;
350e5dd7070Spatrick   FunctionExitPoint() = default;
isKind(const ProgramPoint & Location)351e5dd7070Spatrick   static bool isKind(const ProgramPoint &Location) {
352e5dd7070Spatrick     return Location.getKind() == FunctionExitKind;
353e5dd7070Spatrick   }
354e5dd7070Spatrick };
355e5dd7070Spatrick 
356e5dd7070Spatrick // PostCondition represents the post program point of a branch condition.
357e5dd7070Spatrick class PostCondition : public PostStmt {
358e5dd7070Spatrick public:
359e5dd7070Spatrick   PostCondition(const Stmt *S, const LocationContext *L,
360e5dd7070Spatrick                 const ProgramPointTag *tag = nullptr)
PostStmt(S,PostConditionKind,L,tag)361e5dd7070Spatrick     : PostStmt(S, PostConditionKind, L, tag) {}
362e5dd7070Spatrick 
363e5dd7070Spatrick private:
364e5dd7070Spatrick   friend class ProgramPoint;
365e5dd7070Spatrick   PostCondition() = default;
isKind(const ProgramPoint & Location)366e5dd7070Spatrick   static bool isKind(const ProgramPoint &Location) {
367e5dd7070Spatrick     return Location.getKind() == PostConditionKind;
368e5dd7070Spatrick   }
369e5dd7070Spatrick };
370e5dd7070Spatrick 
371e5dd7070Spatrick class LocationCheck : public StmtPoint {
372e5dd7070Spatrick protected:
373e5dd7070Spatrick   LocationCheck() = default;
LocationCheck(const Stmt * S,const LocationContext * L,ProgramPoint::Kind K,const ProgramPointTag * tag)374e5dd7070Spatrick   LocationCheck(const Stmt *S, const LocationContext *L,
375e5dd7070Spatrick                 ProgramPoint::Kind K, const ProgramPointTag *tag)
376e5dd7070Spatrick     : StmtPoint(S, nullptr, K, L, tag) {}
377e5dd7070Spatrick 
378e5dd7070Spatrick private:
379e5dd7070Spatrick   friend class ProgramPoint;
isKind(const ProgramPoint & location)380e5dd7070Spatrick   static bool isKind(const ProgramPoint &location) {
381e5dd7070Spatrick     unsigned k = location.getKind();
382e5dd7070Spatrick     return k == PreLoadKind || k == PreStoreKind;
383e5dd7070Spatrick   }
384e5dd7070Spatrick };
385e5dd7070Spatrick 
386e5dd7070Spatrick class PreLoad : public LocationCheck {
387e5dd7070Spatrick public:
388e5dd7070Spatrick   PreLoad(const Stmt *S, const LocationContext *L,
389e5dd7070Spatrick           const ProgramPointTag *tag = nullptr)
LocationCheck(S,L,PreLoadKind,tag)390e5dd7070Spatrick     : LocationCheck(S, L, PreLoadKind, tag) {}
391e5dd7070Spatrick 
392e5dd7070Spatrick private:
393e5dd7070Spatrick   friend class ProgramPoint;
394e5dd7070Spatrick   PreLoad() = default;
isKind(const ProgramPoint & location)395e5dd7070Spatrick   static bool isKind(const ProgramPoint &location) {
396e5dd7070Spatrick     return location.getKind() == PreLoadKind;
397e5dd7070Spatrick   }
398e5dd7070Spatrick };
399e5dd7070Spatrick 
400e5dd7070Spatrick class PreStore : public LocationCheck {
401e5dd7070Spatrick public:
402e5dd7070Spatrick   PreStore(const Stmt *S, const LocationContext *L,
403e5dd7070Spatrick            const ProgramPointTag *tag = nullptr)
LocationCheck(S,L,PreStoreKind,tag)404e5dd7070Spatrick   : LocationCheck(S, L, PreStoreKind, tag) {}
405e5dd7070Spatrick 
406e5dd7070Spatrick private:
407e5dd7070Spatrick   friend class ProgramPoint;
408e5dd7070Spatrick   PreStore() = default;
isKind(const ProgramPoint & location)409e5dd7070Spatrick   static bool isKind(const ProgramPoint &location) {
410e5dd7070Spatrick     return location.getKind() == PreStoreKind;
411e5dd7070Spatrick   }
412e5dd7070Spatrick };
413e5dd7070Spatrick 
414e5dd7070Spatrick class PostLoad : public PostStmt {
415e5dd7070Spatrick public:
416e5dd7070Spatrick   PostLoad(const Stmt *S, const LocationContext *L,
417e5dd7070Spatrick            const ProgramPointTag *tag = nullptr)
PostStmt(S,PostLoadKind,L,tag)418e5dd7070Spatrick     : PostStmt(S, PostLoadKind, L, tag) {}
419e5dd7070Spatrick 
420e5dd7070Spatrick private:
421e5dd7070Spatrick   friend class ProgramPoint;
422e5dd7070Spatrick   PostLoad() = default;
isKind(const ProgramPoint & Location)423e5dd7070Spatrick   static bool isKind(const ProgramPoint &Location) {
424e5dd7070Spatrick     return Location.getKind() == PostLoadKind;
425e5dd7070Spatrick   }
426e5dd7070Spatrick };
427e5dd7070Spatrick 
428e5dd7070Spatrick /// Represents a program point after a store evaluation.
429e5dd7070Spatrick class PostStore : public PostStmt {
430e5dd7070Spatrick public:
431e5dd7070Spatrick   /// Construct the post store point.
432e5dd7070Spatrick   /// \param Loc can be used to store the information about the location
433e5dd7070Spatrick   /// used in the form it was uttered in the code.
434e5dd7070Spatrick   PostStore(const Stmt *S, const LocationContext *L, const void *Loc,
435e5dd7070Spatrick             const ProgramPointTag *tag = nullptr)
PostStmt(S,PostStoreKind,L,tag)436e5dd7070Spatrick     : PostStmt(S, PostStoreKind, L, tag) {
437e5dd7070Spatrick     assert(getData2() == nullptr);
438e5dd7070Spatrick     setData2(Loc);
439e5dd7070Spatrick   }
440e5dd7070Spatrick 
441e5dd7070Spatrick   /// Returns the information about the location used in the store,
442e5dd7070Spatrick   /// how it was uttered in the code.
getLocationValue()443e5dd7070Spatrick   const void *getLocationValue() const {
444e5dd7070Spatrick     return getData2();
445e5dd7070Spatrick   }
446e5dd7070Spatrick 
447e5dd7070Spatrick private:
448e5dd7070Spatrick   friend class ProgramPoint;
449e5dd7070Spatrick   PostStore() = default;
isKind(const ProgramPoint & Location)450e5dd7070Spatrick   static bool isKind(const ProgramPoint &Location) {
451e5dd7070Spatrick     return Location.getKind() == PostStoreKind;
452e5dd7070Spatrick   }
453e5dd7070Spatrick };
454e5dd7070Spatrick 
455e5dd7070Spatrick class PostLValue : public PostStmt {
456e5dd7070Spatrick public:
457e5dd7070Spatrick   PostLValue(const Stmt *S, const LocationContext *L,
458e5dd7070Spatrick              const ProgramPointTag *tag = nullptr)
PostStmt(S,PostLValueKind,L,tag)459e5dd7070Spatrick     : PostStmt(S, PostLValueKind, L, tag) {}
460e5dd7070Spatrick 
461e5dd7070Spatrick private:
462e5dd7070Spatrick   friend class ProgramPoint;
463e5dd7070Spatrick   PostLValue() = default;
isKind(const ProgramPoint & Location)464e5dd7070Spatrick   static bool isKind(const ProgramPoint &Location) {
465e5dd7070Spatrick     return Location.getKind() == PostLValueKind;
466e5dd7070Spatrick   }
467e5dd7070Spatrick };
468e5dd7070Spatrick 
469e5dd7070Spatrick /// Represents a point after we ran remove dead bindings BEFORE
470e5dd7070Spatrick /// processing the given statement.
471e5dd7070Spatrick class PreStmtPurgeDeadSymbols : public StmtPoint {
472e5dd7070Spatrick public:
473e5dd7070Spatrick   PreStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L,
474e5dd7070Spatrick                        const ProgramPointTag *tag = nullptr)
StmtPoint(S,nullptr,PreStmtPurgeDeadSymbolsKind,L,tag)475e5dd7070Spatrick     : StmtPoint(S, nullptr, PreStmtPurgeDeadSymbolsKind, L, tag) { }
476e5dd7070Spatrick 
477e5dd7070Spatrick private:
478e5dd7070Spatrick   friend class ProgramPoint;
479e5dd7070Spatrick   PreStmtPurgeDeadSymbols() = default;
isKind(const ProgramPoint & Location)480e5dd7070Spatrick   static bool isKind(const ProgramPoint &Location) {
481e5dd7070Spatrick     return Location.getKind() == PreStmtPurgeDeadSymbolsKind;
482e5dd7070Spatrick   }
483e5dd7070Spatrick };
484e5dd7070Spatrick 
485e5dd7070Spatrick /// Represents a point after we ran remove dead bindings AFTER
486e5dd7070Spatrick /// processing the  given statement.
487e5dd7070Spatrick class PostStmtPurgeDeadSymbols : public StmtPoint {
488e5dd7070Spatrick public:
489e5dd7070Spatrick   PostStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L,
490e5dd7070Spatrick                        const ProgramPointTag *tag = nullptr)
StmtPoint(S,nullptr,PostStmtPurgeDeadSymbolsKind,L,tag)491e5dd7070Spatrick     : StmtPoint(S, nullptr, PostStmtPurgeDeadSymbolsKind, L, tag) { }
492e5dd7070Spatrick 
493e5dd7070Spatrick private:
494e5dd7070Spatrick   friend class ProgramPoint;
495e5dd7070Spatrick   PostStmtPurgeDeadSymbols() = default;
isKind(const ProgramPoint & Location)496e5dd7070Spatrick   static bool isKind(const ProgramPoint &Location) {
497e5dd7070Spatrick     return Location.getKind() == PostStmtPurgeDeadSymbolsKind;
498e5dd7070Spatrick   }
499e5dd7070Spatrick };
500e5dd7070Spatrick 
501e5dd7070Spatrick class BlockEdge : public ProgramPoint {
502e5dd7070Spatrick public:
BlockEdge(const CFGBlock * B1,const CFGBlock * B2,const LocationContext * L)503e5dd7070Spatrick   BlockEdge(const CFGBlock *B1, const CFGBlock *B2, const LocationContext *L)
504e5dd7070Spatrick     : ProgramPoint(B1, B2, BlockEdgeKind, L) {
505e5dd7070Spatrick     assert(B1 && "BlockEdge: source block must be non-null");
506e5dd7070Spatrick     assert(B2 && "BlockEdge: destination block must be non-null");
507e5dd7070Spatrick   }
508e5dd7070Spatrick 
getSrc()509e5dd7070Spatrick   const CFGBlock *getSrc() const {
510e5dd7070Spatrick     return static_cast<const CFGBlock*>(getData1());
511e5dd7070Spatrick   }
512e5dd7070Spatrick 
getDst()513e5dd7070Spatrick   const CFGBlock *getDst() const {
514e5dd7070Spatrick     return static_cast<const CFGBlock*>(getData2());
515e5dd7070Spatrick   }
516e5dd7070Spatrick 
517e5dd7070Spatrick private:
518e5dd7070Spatrick   friend class ProgramPoint;
519e5dd7070Spatrick   BlockEdge() = default;
isKind(const ProgramPoint & Location)520e5dd7070Spatrick   static bool isKind(const ProgramPoint &Location) {
521e5dd7070Spatrick     return Location.getKind() == BlockEdgeKind;
522e5dd7070Spatrick   }
523e5dd7070Spatrick };
524e5dd7070Spatrick 
525e5dd7070Spatrick class PostInitializer : public ProgramPoint {
526e5dd7070Spatrick public:
527e5dd7070Spatrick   /// Construct a PostInitializer point that represents a location after
528e5dd7070Spatrick   ///   CXXCtorInitializer expression evaluation.
529e5dd7070Spatrick   ///
530e5dd7070Spatrick   /// \param I The initializer.
531e5dd7070Spatrick   /// \param Loc The location of the field being initialized.
PostInitializer(const CXXCtorInitializer * I,const void * Loc,const LocationContext * L)532e5dd7070Spatrick   PostInitializer(const CXXCtorInitializer *I,
533e5dd7070Spatrick                   const void *Loc,
534e5dd7070Spatrick                   const LocationContext *L)
535e5dd7070Spatrick     : ProgramPoint(I, Loc, PostInitializerKind, L) {}
536e5dd7070Spatrick 
getInitializer()537e5dd7070Spatrick   const CXXCtorInitializer *getInitializer() const {
538e5dd7070Spatrick     return static_cast<const CXXCtorInitializer *>(getData1());
539e5dd7070Spatrick   }
540e5dd7070Spatrick 
541e5dd7070Spatrick   /// Returns the location of the field.
getLocationValue()542e5dd7070Spatrick   const void *getLocationValue() const {
543e5dd7070Spatrick     return getData2();
544e5dd7070Spatrick   }
545e5dd7070Spatrick 
546e5dd7070Spatrick private:
547e5dd7070Spatrick   friend class ProgramPoint;
548e5dd7070Spatrick   PostInitializer() = default;
isKind(const ProgramPoint & Location)549e5dd7070Spatrick   static bool isKind(const ProgramPoint &Location) {
550e5dd7070Spatrick     return Location.getKind() == PostInitializerKind;
551e5dd7070Spatrick   }
552e5dd7070Spatrick };
553e5dd7070Spatrick 
554e5dd7070Spatrick /// Represents an implicit call event.
555e5dd7070Spatrick ///
556e5dd7070Spatrick /// The nearest statement is provided for diagnostic purposes.
557e5dd7070Spatrick class ImplicitCallPoint : public ProgramPoint {
558e5dd7070Spatrick public:
ImplicitCallPoint(const Decl * D,SourceLocation Loc,Kind K,const LocationContext * L,const ProgramPointTag * Tag)559e5dd7070Spatrick   ImplicitCallPoint(const Decl *D, SourceLocation Loc, Kind K,
560e5dd7070Spatrick                     const LocationContext *L, const ProgramPointTag *Tag)
561e5dd7070Spatrick     : ProgramPoint(Loc.getPtrEncoding(), D, K, L, Tag) {}
562e5dd7070Spatrick 
getDecl()563e5dd7070Spatrick   const Decl *getDecl() const { return static_cast<const Decl *>(getData2()); }
getLocation()564e5dd7070Spatrick   SourceLocation getLocation() const {
565e5dd7070Spatrick     return SourceLocation::getFromPtrEncoding(getData1());
566e5dd7070Spatrick   }
567e5dd7070Spatrick 
568e5dd7070Spatrick protected:
569e5dd7070Spatrick   ImplicitCallPoint() = default;
570e5dd7070Spatrick private:
571e5dd7070Spatrick   friend class ProgramPoint;
isKind(const ProgramPoint & Location)572e5dd7070Spatrick   static bool isKind(const ProgramPoint &Location) {
573e5dd7070Spatrick     return Location.getKind() >= MinImplicitCallKind &&
574e5dd7070Spatrick            Location.getKind() <= MaxImplicitCallKind;
575e5dd7070Spatrick   }
576e5dd7070Spatrick };
577e5dd7070Spatrick 
578e5dd7070Spatrick /// Represents a program point just before an implicit call event.
579e5dd7070Spatrick ///
580e5dd7070Spatrick /// Explicit calls will appear as PreStmt program points.
581e5dd7070Spatrick class PreImplicitCall : public ImplicitCallPoint {
582e5dd7070Spatrick public:
583e5dd7070Spatrick   PreImplicitCall(const Decl *D, SourceLocation Loc, const LocationContext *L,
584e5dd7070Spatrick                   const ProgramPointTag *Tag = nullptr)
ImplicitCallPoint(D,Loc,PreImplicitCallKind,L,Tag)585e5dd7070Spatrick     : ImplicitCallPoint(D, Loc, PreImplicitCallKind, L, Tag) {}
586e5dd7070Spatrick 
587e5dd7070Spatrick private:
588e5dd7070Spatrick   friend class ProgramPoint;
589e5dd7070Spatrick   PreImplicitCall() = default;
isKind(const ProgramPoint & Location)590e5dd7070Spatrick   static bool isKind(const ProgramPoint &Location) {
591e5dd7070Spatrick     return Location.getKind() == PreImplicitCallKind;
592e5dd7070Spatrick   }
593e5dd7070Spatrick };
594e5dd7070Spatrick 
595e5dd7070Spatrick /// Represents a program point just after an implicit call event.
596e5dd7070Spatrick ///
597e5dd7070Spatrick /// Explicit calls will appear as PostStmt program points.
598e5dd7070Spatrick class PostImplicitCall : public ImplicitCallPoint {
599e5dd7070Spatrick public:
600e5dd7070Spatrick   PostImplicitCall(const Decl *D, SourceLocation Loc, const LocationContext *L,
601e5dd7070Spatrick                    const ProgramPointTag *Tag = nullptr)
ImplicitCallPoint(D,Loc,PostImplicitCallKind,L,Tag)602e5dd7070Spatrick     : ImplicitCallPoint(D, Loc, PostImplicitCallKind, L, Tag) {}
603e5dd7070Spatrick 
604e5dd7070Spatrick private:
605e5dd7070Spatrick   friend class ProgramPoint;
606e5dd7070Spatrick   PostImplicitCall() = default;
isKind(const ProgramPoint & Location)607e5dd7070Spatrick   static bool isKind(const ProgramPoint &Location) {
608e5dd7070Spatrick     return Location.getKind() == PostImplicitCallKind;
609e5dd7070Spatrick   }
610e5dd7070Spatrick };
611e5dd7070Spatrick 
612e5dd7070Spatrick class PostAllocatorCall : public StmtPoint {
613e5dd7070Spatrick public:
614e5dd7070Spatrick   PostAllocatorCall(const Stmt *S, const LocationContext *L,
615e5dd7070Spatrick                     const ProgramPointTag *Tag = nullptr)
StmtPoint(S,nullptr,PostAllocatorCallKind,L,Tag)616e5dd7070Spatrick       : StmtPoint(S, nullptr, PostAllocatorCallKind, L, Tag) {}
617e5dd7070Spatrick 
618e5dd7070Spatrick private:
619e5dd7070Spatrick   friend class ProgramPoint;
620e5dd7070Spatrick   PostAllocatorCall() = default;
isKind(const ProgramPoint & Location)621e5dd7070Spatrick   static bool isKind(const ProgramPoint &Location) {
622e5dd7070Spatrick     return Location.getKind() == PostAllocatorCallKind;
623e5dd7070Spatrick   }
624e5dd7070Spatrick };
625e5dd7070Spatrick 
626e5dd7070Spatrick /// Represents a point when we begin processing an inlined call.
627e5dd7070Spatrick /// CallEnter uses the caller's location context.
628e5dd7070Spatrick class CallEnter : public ProgramPoint {
629e5dd7070Spatrick public:
CallEnter(const Stmt * stmt,const StackFrameContext * calleeCtx,const LocationContext * callerCtx)630e5dd7070Spatrick   CallEnter(const Stmt *stmt, const StackFrameContext *calleeCtx,
631e5dd7070Spatrick             const LocationContext *callerCtx)
632e5dd7070Spatrick     : ProgramPoint(stmt, calleeCtx, CallEnterKind, callerCtx, nullptr) {}
633e5dd7070Spatrick 
getCallExpr()634e5dd7070Spatrick   const Stmt *getCallExpr() const {
635e5dd7070Spatrick     return static_cast<const Stmt *>(getData1());
636e5dd7070Spatrick   }
637e5dd7070Spatrick 
getCalleeContext()638e5dd7070Spatrick   const StackFrameContext *getCalleeContext() const {
639e5dd7070Spatrick     return static_cast<const StackFrameContext *>(getData2());
640e5dd7070Spatrick   }
641e5dd7070Spatrick 
642e5dd7070Spatrick   /// Returns the entry block in the CFG for the entered function.
getEntry()643e5dd7070Spatrick   const CFGBlock *getEntry() const {
644e5dd7070Spatrick     const StackFrameContext *CalleeCtx = getCalleeContext();
645e5dd7070Spatrick     const CFG *CalleeCFG = CalleeCtx->getCFG();
646e5dd7070Spatrick     return &(CalleeCFG->getEntry());
647e5dd7070Spatrick   }
648e5dd7070Spatrick 
649e5dd7070Spatrick private:
650e5dd7070Spatrick   friend class ProgramPoint;
651e5dd7070Spatrick   CallEnter() = default;
isKind(const ProgramPoint & Location)652e5dd7070Spatrick   static bool isKind(const ProgramPoint &Location) {
653e5dd7070Spatrick     return Location.getKind() == CallEnterKind;
654e5dd7070Spatrick   }
655e5dd7070Spatrick };
656e5dd7070Spatrick 
657e5dd7070Spatrick /// Represents a point when we start the call exit sequence (for inlined call).
658e5dd7070Spatrick ///
659e5dd7070Spatrick /// The call exit is simulated with a sequence of nodes, which occur between
660e5dd7070Spatrick /// CallExitBegin and CallExitEnd. The following operations occur between the
661e5dd7070Spatrick /// two program points:
662e5dd7070Spatrick /// - CallExitBegin
663e5dd7070Spatrick /// - Bind the return value
664e5dd7070Spatrick /// - Run Remove dead bindings (to clean up the dead symbols from the callee).
665e5dd7070Spatrick /// - CallExitEnd
666e5dd7070Spatrick class CallExitBegin : public ProgramPoint {
667e5dd7070Spatrick public:
668e5dd7070Spatrick   // CallExitBegin uses the callee's location context.
CallExitBegin(const StackFrameContext * L,const ReturnStmt * RS)669e5dd7070Spatrick   CallExitBegin(const StackFrameContext *L, const ReturnStmt *RS)
670e5dd7070Spatrick     : ProgramPoint(RS, CallExitBeginKind, L, nullptr) { }
671e5dd7070Spatrick 
getReturnStmt()672e5dd7070Spatrick   const ReturnStmt *getReturnStmt() const {
673e5dd7070Spatrick     return static_cast<const ReturnStmt *>(getData1());
674e5dd7070Spatrick   }
675e5dd7070Spatrick 
676e5dd7070Spatrick private:
677e5dd7070Spatrick   friend class ProgramPoint;
678e5dd7070Spatrick   CallExitBegin() = default;
isKind(const ProgramPoint & Location)679e5dd7070Spatrick   static bool isKind(const ProgramPoint &Location) {
680e5dd7070Spatrick     return Location.getKind() == CallExitBeginKind;
681e5dd7070Spatrick   }
682e5dd7070Spatrick };
683e5dd7070Spatrick 
684e5dd7070Spatrick /// Represents a point when we finish the call exit sequence (for inlined call).
685e5dd7070Spatrick /// \sa CallExitBegin
686e5dd7070Spatrick class CallExitEnd : public ProgramPoint {
687e5dd7070Spatrick public:
688e5dd7070Spatrick   // CallExitEnd uses the caller's location context.
CallExitEnd(const StackFrameContext * CalleeCtx,const LocationContext * CallerCtx)689e5dd7070Spatrick   CallExitEnd(const StackFrameContext *CalleeCtx,
690e5dd7070Spatrick               const LocationContext *CallerCtx)
691e5dd7070Spatrick     : ProgramPoint(CalleeCtx, CallExitEndKind, CallerCtx, nullptr) {}
692e5dd7070Spatrick 
getCalleeContext()693e5dd7070Spatrick   const StackFrameContext *getCalleeContext() const {
694e5dd7070Spatrick     return static_cast<const StackFrameContext *>(getData1());
695e5dd7070Spatrick   }
696e5dd7070Spatrick 
697e5dd7070Spatrick private:
698e5dd7070Spatrick   friend class ProgramPoint;
699e5dd7070Spatrick   CallExitEnd() = default;
isKind(const ProgramPoint & Location)700e5dd7070Spatrick   static bool isKind(const ProgramPoint &Location) {
701e5dd7070Spatrick     return Location.getKind() == CallExitEndKind;
702e5dd7070Spatrick   }
703e5dd7070Spatrick };
704e5dd7070Spatrick 
705e5dd7070Spatrick /// Represents a point when we exit a loop.
706e5dd7070Spatrick /// When this ProgramPoint is encountered we can be sure that the symbolic
707e5dd7070Spatrick /// execution of the corresponding LoopStmt is finished on the given path.
708e5dd7070Spatrick /// Note: It is possible to encounter a LoopExit element when we haven't even
709e5dd7070Spatrick /// encountered the loop itself. At the current state not all loop exits will
710e5dd7070Spatrick /// result in a LoopExit program point.
711e5dd7070Spatrick class LoopExit : public ProgramPoint {
712e5dd7070Spatrick public:
LoopExit(const Stmt * LoopStmt,const LocationContext * LC)713e5dd7070Spatrick     LoopExit(const Stmt *LoopStmt, const LocationContext *LC)
714e5dd7070Spatrick             : ProgramPoint(LoopStmt, nullptr, LoopExitKind, LC) {}
715e5dd7070Spatrick 
getLoopStmt()716e5dd7070Spatrick     const Stmt *getLoopStmt() const {
717e5dd7070Spatrick       return static_cast<const Stmt *>(getData1());
718e5dd7070Spatrick     }
719e5dd7070Spatrick 
720e5dd7070Spatrick private:
721e5dd7070Spatrick     friend class ProgramPoint;
722e5dd7070Spatrick     LoopExit() = default;
isKind(const ProgramPoint & Location)723e5dd7070Spatrick     static bool isKind(const ProgramPoint &Location) {
724e5dd7070Spatrick       return Location.getKind() == LoopExitKind;
725e5dd7070Spatrick     }
726e5dd7070Spatrick };
727e5dd7070Spatrick 
728e5dd7070Spatrick /// This is a meta program point, which should be skipped by all the diagnostic
729e5dd7070Spatrick /// reasoning etc.
730e5dd7070Spatrick class EpsilonPoint : public ProgramPoint {
731e5dd7070Spatrick public:
732e5dd7070Spatrick   EpsilonPoint(const LocationContext *L, const void *Data1,
733e5dd7070Spatrick                const void *Data2 = nullptr,
734e5dd7070Spatrick                const ProgramPointTag *tag = nullptr)
ProgramPoint(Data1,Data2,EpsilonKind,L,tag)735e5dd7070Spatrick     : ProgramPoint(Data1, Data2, EpsilonKind, L, tag) {}
736e5dd7070Spatrick 
getData()737e5dd7070Spatrick   const void *getData() const { return getData1(); }
738e5dd7070Spatrick 
739e5dd7070Spatrick private:
740e5dd7070Spatrick   friend class ProgramPoint;
741e5dd7070Spatrick   EpsilonPoint() = default;
isKind(const ProgramPoint & Location)742e5dd7070Spatrick   static bool isKind(const ProgramPoint &Location) {
743e5dd7070Spatrick     return Location.getKind() == EpsilonKind;
744e5dd7070Spatrick   }
745e5dd7070Spatrick };
746e5dd7070Spatrick 
747e5dd7070Spatrick } // end namespace clang
748e5dd7070Spatrick 
749e5dd7070Spatrick 
750e5dd7070Spatrick namespace llvm { // Traits specialization for DenseMap
751e5dd7070Spatrick 
752e5dd7070Spatrick template <> struct DenseMapInfo<clang::ProgramPoint> {
753e5dd7070Spatrick 
754e5dd7070Spatrick static inline clang::ProgramPoint getEmptyKey() {
755e5dd7070Spatrick   uintptr_t x =
756e5dd7070Spatrick    reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getEmptyKey()) & ~0x7;
757e5dd7070Spatrick   return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), nullptr);
758e5dd7070Spatrick }
759e5dd7070Spatrick 
760e5dd7070Spatrick static inline clang::ProgramPoint getTombstoneKey() {
761e5dd7070Spatrick   uintptr_t x =
762e5dd7070Spatrick    reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getTombstoneKey()) & ~0x7;
763e5dd7070Spatrick   return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), nullptr);
764e5dd7070Spatrick }
765e5dd7070Spatrick 
766e5dd7070Spatrick static unsigned getHashValue(const clang::ProgramPoint &Loc) {
767e5dd7070Spatrick   return Loc.getHashValue();
768e5dd7070Spatrick }
769e5dd7070Spatrick 
770e5dd7070Spatrick static bool isEqual(const clang::ProgramPoint &L,
771e5dd7070Spatrick                     const clang::ProgramPoint &R) {
772e5dd7070Spatrick   return L == R;
773e5dd7070Spatrick }
774e5dd7070Spatrick 
775e5dd7070Spatrick };
776e5dd7070Spatrick 
777e5dd7070Spatrick } // end namespace llvm
778e5dd7070Spatrick 
779e5dd7070Spatrick #endif
780