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 | |
30 | namespace clang { |
31 | |
32 | class AnalysisDeclContext; |
33 | class 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. |
38 | class ProgramPointTag { |
39 | public: |
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 | |
50 | private: |
51 | const void *const TagKind; |
52 | }; |
53 | |
54 | class SimpleProgramPointTag : public ProgramPointTag { |
55 | std::string Desc; |
56 | public: |
57 | SimpleProgramPointTag(StringRef MsgProvider, StringRef Msg); |
58 | StringRef getDebugTag() const override; |
59 | }; |
60 | |
61 | class ProgramPoint { |
62 | public: |
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 | |
94 | private: |
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 | |
106 | protected: |
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 | |
126 | protected: |
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 | |
132 | public: |
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 | |
225 | class BlockEntrance : public ProgramPoint { |
226 | public: |
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 | |
246 | private: |
247 | friend class ProgramPoint; |
248 | BlockEntrance() = default; |
249 | static bool isKind(const ProgramPoint &Location) { |
250 | return Location.getKind() == BlockEntranceKind; |
251 | } |
252 | }; |
253 | |
254 | class BlockExit : public ProgramPoint { |
255 | public: |
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 | |
267 | private: |
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. |
276 | class StmtPoint : public ProgramPoint { |
277 | public: |
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 | |
289 | protected: |
290 | StmtPoint() = default; |
291 | private: |
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 | |
300 | class PreStmt : public StmtPoint { |
301 | public: |
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 | |
308 | private: |
309 | friend class ProgramPoint; |
310 | PreStmt() = default; |
311 | static bool isKind(const ProgramPoint &Location) { |
312 | return Location.getKind() == PreStmtKind; |
313 | } |
314 | }; |
315 | |
316 | class PostStmt : public StmtPoint { |
317 | protected: |
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 | |
323 | public: |
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 | |
332 | private: |
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 | |
340 | class FunctionExitPoint : public ProgramPoint { |
341 | public: |
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 | |
355 | private: |
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. |
364 | class PostCondition : public PostStmt { |
365 | public: |
366 | PostCondition(const Stmt *S, const LocationContext *L, |
367 | const ProgramPointTag *tag = nullptr) |
368 | : PostStmt(S, PostConditionKind, L, tag) {} |
369 | |
370 | private: |
371 | friend class ProgramPoint; |
372 | PostCondition() = default; |
373 | static bool isKind(const ProgramPoint &Location) { |
374 | return Location.getKind() == PostConditionKind; |
375 | } |
376 | }; |
377 | |
378 | class LocationCheck : public StmtPoint { |
379 | protected: |
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 | |
385 | private: |
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 | |
393 | class PreLoad : public LocationCheck { |
394 | public: |
395 | PreLoad(const Stmt *S, const LocationContext *L, |
396 | const ProgramPointTag *tag = nullptr) |
397 | : LocationCheck(S, L, PreLoadKind, tag) {} |
398 | |
399 | private: |
400 | friend class ProgramPoint; |
401 | PreLoad() = default; |
402 | static bool isKind(const ProgramPoint &location) { |
403 | return location.getKind() == PreLoadKind; |
404 | } |
405 | }; |
406 | |
407 | class PreStore : public LocationCheck { |
408 | public: |
409 | PreStore(const Stmt *S, const LocationContext *L, |
410 | const ProgramPointTag *tag = nullptr) |
411 | : LocationCheck(S, L, PreStoreKind, tag) {} |
412 | |
413 | private: |
414 | friend class ProgramPoint; |
415 | PreStore() = default; |
416 | static bool isKind(const ProgramPoint &location) { |
417 | return location.getKind() == PreStoreKind; |
418 | } |
419 | }; |
420 | |
421 | class PostLoad : public PostStmt { |
422 | public: |
423 | PostLoad(const Stmt *S, const LocationContext *L, |
424 | const ProgramPointTag *tag = nullptr) |
425 | : PostStmt(S, PostLoadKind, L, tag) {} |
426 | |
427 | private: |
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. |
436 | class PostStore : public PostStmt { |
437 | public: |
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 | |
454 | private: |
455 | friend class ProgramPoint; |
456 | PostStore() = default; |
457 | static bool isKind(const ProgramPoint &Location) { |
458 | return Location.getKind() == PostStoreKind; |
459 | } |
460 | }; |
461 | |
462 | class PostLValue : public PostStmt { |
463 | public: |
464 | PostLValue(const Stmt *S, const LocationContext *L, |
465 | const ProgramPointTag *tag = nullptr) |
466 | : PostStmt(S, PostLValueKind, L, tag) {} |
467 | |
468 | private: |
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. |
478 | class PreStmtPurgeDeadSymbols : public StmtPoint { |
479 | public: |
480 | PreStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L, |
481 | const ProgramPointTag *tag = nullptr) |
482 | : StmtPoint(S, nullptr, PreStmtPurgeDeadSymbolsKind, L, tag) { } |
483 | |
484 | private: |
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. |
494 | class PostStmtPurgeDeadSymbols : public StmtPoint { |
495 | public: |
496 | PostStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L, |
497 | const ProgramPointTag *tag = nullptr) |
498 | : StmtPoint(S, nullptr, PostStmtPurgeDeadSymbolsKind, L, tag) { } |
499 | |
500 | private: |
501 | friend class ProgramPoint; |
502 | PostStmtPurgeDeadSymbols() = default; |
503 | static bool isKind(const ProgramPoint &Location) { |
504 | return Location.getKind() == PostStmtPurgeDeadSymbolsKind; |
505 | } |
506 | }; |
507 | |
508 | class BlockEdge : public ProgramPoint { |
509 | public: |
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 | |
524 | private: |
525 | friend class ProgramPoint; |
526 | BlockEdge() = default; |
527 | static bool isKind(const ProgramPoint &Location) { |
528 | return Location.getKind() == BlockEdgeKind; |
529 | } |
530 | }; |
531 | |
532 | class PostInitializer : public ProgramPoint { |
533 | public: |
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 | |
553 | private: |
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. |
564 | class ImplicitCallPoint : public ProgramPoint { |
565 | public: |
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 | |
576 | protected: |
577 | ImplicitCallPoint() = default; |
578 | private: |
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. |
589 | class PreImplicitCall : public ImplicitCallPoint { |
590 | public: |
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 | |
596 | private: |
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. |
607 | class PostImplicitCall : public ImplicitCallPoint { |
608 | public: |
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 | |
614 | private: |
615 | friend class ProgramPoint; |
616 | PostImplicitCall() = default; |
617 | static bool isKind(const ProgramPoint &Location) { |
618 | return Location.getKind() == PostImplicitCallKind; |
619 | } |
620 | }; |
621 | |
622 | class PostAllocatorCall : public StmtPoint { |
623 | public: |
624 | PostAllocatorCall(const Stmt *S, const LocationContext *L, |
625 | const ProgramPointTag *Tag = nullptr) |
626 | : StmtPoint(S, nullptr, PostAllocatorCallKind, L, Tag) {} |
627 | |
628 | private: |
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. |
638 | class CallEnter : public ProgramPoint { |
639 | public: |
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 | |
659 | private: |
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 |
676 | class CallExitBegin : public ProgramPoint { |
677 | public: |
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 | |
686 | private: |
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 |
696 | class CallExitEnd : public ProgramPoint { |
697 | public: |
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 | |
707 | private: |
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. |
721 | class LoopExit : public ProgramPoint { |
722 | public: |
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 | |
730 | private: |
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. |
740 | class EpsilonPoint : public ProgramPoint { |
741 | public: |
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 | |
749 | private: |
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 | |
760 | namespace llvm { // Traits specialization for DenseMap |
761 | |
762 | template <> struct DenseMapInfo<clang::ProgramPoint> { |
763 | |
764 | static 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 | |
771 | static 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 | |
778 | static unsigned getHashValue(const clang::ProgramPoint &Loc) { |
779 | return Loc.getHashValue(); |
780 | } |
781 | |
782 | static 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 |
Definitions
- ProgramPointTag
- ProgramPointTag
- getTagKind
- SimpleProgramPointTag
- ProgramPoint
- Kind
- ProgramPoint
- ProgramPoint
- ProgramPoint
- getData1
- getData2
- setData2
- getElementRef
- withTag
- castAs
- getAs
- getKind
- isPurgeKind
- getTag
- getLocationContext
- getStackFrame
- getHashValue
- operator==
- operator!=
- Profile
- BlockEntrance
- BlockEntrance
- getPreviousBlock
- getBlock
- getFirstElement
- BlockEntrance
- isKind
- BlockExit
- BlockExit
- getBlock
- getTerminator
- BlockExit
- isKind
- StmtPoint
- StmtPoint
- getStmt
- getStmtAs
- StmtPoint
- isKind
- PreStmt
- PreStmt
- getSubStmt
- PreStmt
- isKind
- PostStmt
- PostStmt
- PostStmt
- PostStmt
- PostStmt
- isKind
- FunctionExitPoint
- FunctionExitPoint
- getBlock
- getStmt
- FunctionExitPoint
- isKind
- PostCondition
- PostCondition
- PostCondition
- isKind
- LocationCheck
- LocationCheck
- LocationCheck
- isKind
- PreLoad
- PreLoad
- PreLoad
- isKind
- PreStore
- PreStore
- PreStore
- isKind
- PostLoad
- PostLoad
- PostLoad
- isKind
- PostStore
- PostStore
- getLocationValue
- PostStore
- isKind
- PostLValue
- PostLValue
- PostLValue
- isKind
- PreStmtPurgeDeadSymbols
- PreStmtPurgeDeadSymbols
- PreStmtPurgeDeadSymbols
- isKind
- PostStmtPurgeDeadSymbols
- PostStmtPurgeDeadSymbols
- PostStmtPurgeDeadSymbols
- isKind
- BlockEdge
- BlockEdge
- getSrc
- getDst
- BlockEdge
- isKind
- PostInitializer
- PostInitializer
- getInitializer
- getLocationValue
- PostInitializer
- isKind
- ImplicitCallPoint
- ImplicitCallPoint
- getDecl
- getLocation
- ImplicitCallPoint
- isKind
- PreImplicitCall
- PreImplicitCall
- PreImplicitCall
- isKind
- PostImplicitCall
- PostImplicitCall
- PostImplicitCall
- isKind
- PostAllocatorCall
- PostAllocatorCall
- PostAllocatorCall
- isKind
- CallEnter
- CallEnter
- getCallExpr
- getCalleeContext
- getEntry
- CallEnter
- isKind
- CallExitBegin
- CallExitBegin
- getReturnStmt
- CallExitBegin
- isKind
- CallExitEnd
- CallExitEnd
- getCalleeContext
- CallExitEnd
- isKind
- LoopExit
- LoopExit
- getLoopStmt
- LoopExit
- isKind
- EpsilonPoint
- EpsilonPoint
- getData
- EpsilonPoint
- isKind
- DenseMapInfo
- getEmptyKey
- getTombstoneKey
- getHashValue
Learn to use CMake with our Intro Training
Find out more