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