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