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