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

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of clang/include/clang/Analysis/ProgramPoint.h