Clang Project

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