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 MsgProvider, StringRef 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 *, 2, unsigned> Data2;
93
94 // The LocationContext could be NULL to allow ProgramPoint to be used in
95 // context insensitive analysis.
96 llvm::PointerIntPair<const LocationContext *, 2, unsigned> L;
97
98 llvm::PointerIntPair<const ProgramPointTag *, 2, unsigned> Tag;
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 *tag) const {
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 ProgramPoint& PP = 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 ProgramPoint& PP = 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 (Kind) x;
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 & RHS) const {
196 return Data1 == RHS.Data1 &&
197 Data2 == RHS.Data2 &&
198 L == RHS.L &&
199 Tag == RHS.Tag;
200 }
201
202 bool operator!=(const ProgramPoint &RHS) const {
203 return Data1 != RHS.Data1 ||
204 Data2 != RHS.Data2 ||
205 L != RHS.L ||
206 Tag != RHS.Tag;
207 }
208
209 void Profile(llvm::FoldingSetNodeID& ID) const {
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 CR, llvm::raw_ostream &Out) const;
218
219 LLVM_DUMP_METHOD void dump() const;
220
221 static ProgramPoint getProgramPoint(const Stmt *S, ProgramPoint::Kind K,
222 const LocationContext *LC,
223 const ProgramPointTag *tag);
224};
225
226class BlockEntrance : public ProgramPoint {
227public:
228 BlockEntrance(const CFGBlock *B, const LocationContext *L,
229 const ProgramPointTag *tag = nullptr)
230 : ProgramPoint(B, BlockEntranceKind, L, tag) {
231 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<CFGElement> getFirstElement() 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 *B, const LocationContext *L)
254 : ProgramPoint(B, BlockExitKind, L) {}
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 *S, const void *p2, Kind k, const LocationContext *L,
275 const ProgramPointTag *tag)
276 : ProgramPoint(S, p2, k, L, tag) {
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 *S, const LocationContext *L, const ProgramPointTag *tag,
299 const Stmt *SubStmt = nullptr)
300 : StmtPoint(S, SubStmt, PreStmtKind, L, tag) {}
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 *S, const void *data, Kind k, const LocationContext *L,
316 const ProgramPointTag *tag = nullptr)
317 : StmtPoint(S, data, k, L, tag) {}
318
319public:
320 explicit PostStmt(const Stmt *S, Kind k, const LocationContext *L,
321 const ProgramPointTag *tag = nullptr)
322 : StmtPoint(S, nullptr, k, L, tag) {}
323
324 explicit PostStmt(const Stmt *S, const LocationContext *L,
325 const ProgramPointTag *tag = nullptr)
326 : StmtPoint(S, nullptr, PostStmtKind, L, tag) {}
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(S, FunctionExitKind, LC, tag) {}
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 *S, const LocationContext *L,
363 const ProgramPointTag *tag = nullptr)
364 : PostStmt(S, PostConditionKind, L, tag) {}
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 *S, const LocationContext *L,
378 ProgramPoint::Kind K, const ProgramPointTag *tag)
379 : StmtPoint(S, nullptr, K, L, tag) {}
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 *S, const LocationContext *L,
392 const ProgramPointTag *tag = nullptr)
393 : LocationCheck(S, L, PreLoadKind, tag) {}
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 *S, const LocationContext *L,
406 const ProgramPointTag *tag = nullptr)
407 : LocationCheck(S, L, PreStoreKind, tag) {}
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 *S, const LocationContext *L,
420 const ProgramPointTag *tag = nullptr)
421 : PostStmt(S, PostLoadKind, L, tag) {}
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 *S, const LocationContext *L, const void *Loc,
438 const ProgramPointTag *tag = nullptr)
439 : PostStmt(S, PostStoreKind, L, tag) {
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 *S, const LocationContext *L,
461 const ProgramPointTag *tag = nullptr)
462 : PostStmt(S, PostLValueKind, L, tag) {}
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 *S, const LocationContext *L,
477 const ProgramPointTag *tag = nullptr)
478 : StmtPoint(S, nullptr, PreStmtPurgeDeadSymbolsKind, L, tag) { }
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 *S, const LocationContext *L,
493 const ProgramPointTag *tag = nullptr)
494 : StmtPoint(S, nullptr, PostStmtPurgeDeadSymbolsKind, L, tag) { }
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 *B1, const CFGBlock *B2, const LocationContext *L)
507 : ProgramPoint(B1, B2, BlockEdgeKind, L) {
508 assert(B1 && "BlockEdge: source block must be non-null");
509 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(I, Loc, PostInitializerKind, L) {}
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 *D, SourceLocation Loc, Kind K,
563 const LocationContext *L, const ProgramPointTag *Tag)
564 : ProgramPoint(Loc.getPtrEncoding(), D, K, L, Tag) {}
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 *D, SourceLocation Loc, const LocationContext *L,
587 const ProgramPointTag *Tag = nullptr)
588 : ImplicitCallPoint(D, Loc, PreImplicitCallKind, L, Tag) {}
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 *D, SourceLocation Loc, const LocationContext *L,
604 const ProgramPointTag *Tag = nullptr)
605 : ImplicitCallPoint(D, Loc, PostImplicitCallKind, L, Tag) {}
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 *S, const LocationContext *L,
618 const ProgramPointTag *Tag = nullptr)
619 : StmtPoint(S, nullptr, PostAllocatorCallKind, L, Tag) {}
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 *stmt, const StackFrameContext *calleeCtx,
634 const LocationContext *callerCtx)
635 : ProgramPoint(stmt, calleeCtx, CallEnterKind, callerCtx, nullptr) {}
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 *L, const ReturnStmt *RS)
673 : ProgramPoint(RS, CallExitBeginKind, L, nullptr) { }
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(CalleeCtx, CallExitEndKind, CallerCtx, nullptr) {}
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 *LoopStmt, const LocationContext *LC)
717 : ProgramPoint(LoopStmt, nullptr, LoopExitKind, LC) {}
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 *L, const void *Data1,
736 const void *Data2 = nullptr,
737 const ProgramPointTag *tag = nullptr)
738 : ProgramPoint(Data1, Data2, EpsilonKind, L, tag) {}
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