1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | #ifndef LLVM_CLANG_ANALYSIS_ANALYSISDECLCONTEXT_H |
15 | #define LLVM_CLANG_ANALYSIS_ANALYSISDECLCONTEXT_H |
16 | |
17 | #include "clang/AST/DeclBase.h" |
18 | #include "clang/Analysis/BodyFarm.h" |
19 | #include "clang/Analysis/CFG.h" |
20 | #include "clang/Analysis/CodeInjector.h" |
21 | #include "clang/Basic/LLVM.h" |
22 | #include "llvm/ADT/DenseMap.h" |
23 | #include "llvm/ADT/FoldingSet.h" |
24 | #include "llvm/ADT/StringRef.h" |
25 | #include "llvm/ADT/iterator_range.h" |
26 | #include "llvm/Support/Allocator.h" |
27 | #include <functional> |
28 | #include <memory> |
29 | |
30 | namespace clang { |
31 | |
32 | class AnalysisDeclContextManager; |
33 | class ASTContext; |
34 | class BlockDecl; |
35 | class BlockInvocationContext; |
36 | class CFGReverseBlockReachabilityAnalysis; |
37 | class CFGStmtMap; |
38 | class ImplicitParamDecl; |
39 | class LocationContext; |
40 | class LocationContextManager; |
41 | class ParentMap; |
42 | class StackFrameContext; |
43 | class Stmt; |
44 | class VarDecl; |
45 | |
46 | |
47 | |
48 | class ManagedAnalysis { |
49 | protected: |
50 | ManagedAnalysis() = default; |
51 | |
52 | public: |
53 | virtual ~ManagedAnalysis(); |
54 | |
55 | |
56 | |
57 | |
58 | |
59 | |
60 | |
61 | |
62 | |
63 | |
64 | |
65 | }; |
66 | |
67 | |
68 | |
69 | class AnalysisDeclContext { |
70 | |
71 | |
72 | AnalysisDeclContextManager *Manager; |
73 | |
74 | const Decl * const D; |
75 | |
76 | std::unique_ptr<CFG> cfg, completeCFG; |
77 | std::unique_ptr<CFGStmtMap> cfgStmtMap; |
78 | |
79 | CFG::BuildOptions cfgBuildOptions; |
80 | CFG::BuildOptions::ForcedBlkExprs *forcedBlkExprs = nullptr; |
81 | |
82 | bool builtCFG = false; |
83 | bool builtCompleteCFG = false; |
84 | std::unique_ptr<ParentMap> PM; |
85 | std::unique_ptr<CFGReverseBlockReachabilityAnalysis> CFA; |
86 | |
87 | llvm::BumpPtrAllocator A; |
88 | |
89 | llvm::DenseMap<const BlockDecl *,void *> *ReferencedBlockVars = nullptr; |
90 | |
91 | void *ManagedAnalyses = nullptr; |
92 | |
93 | public: |
94 | AnalysisDeclContext(AnalysisDeclContextManager *Mgr, |
95 | const Decl *D); |
96 | |
97 | AnalysisDeclContext(AnalysisDeclContextManager *Mgr, |
98 | const Decl *D, |
99 | const CFG::BuildOptions &BuildOptions); |
100 | |
101 | ~AnalysisDeclContext(); |
102 | |
103 | ASTContext &getASTContext() const { return D->getASTContext(); } |
104 | const Decl *getDecl() const { return D; } |
105 | |
106 | |
107 | |
108 | AnalysisDeclContextManager *getManager() const { |
109 | return Manager; |
110 | } |
111 | |
112 | |
113 | CFG::BuildOptions &getCFGBuildOptions() { |
114 | return cfgBuildOptions; |
115 | } |
116 | |
117 | const CFG::BuildOptions &getCFGBuildOptions() const { |
118 | return cfgBuildOptions; |
119 | } |
120 | |
121 | |
122 | |
123 | |
124 | |
125 | bool getAddEHEdges() const { return cfgBuildOptions.AddEHEdges; } |
126 | bool getUseUnoptimizedCFG() const { |
127 | return !cfgBuildOptions.PruneTriviallyFalseEdges; |
128 | } |
129 | bool getAddImplicitDtors() const { return cfgBuildOptions.AddImplicitDtors; } |
130 | bool getAddInitializers() const { return cfgBuildOptions.AddInitializers; } |
131 | |
132 | void registerForcedBlockExpression(const Stmt *stmt); |
133 | const CFGBlock *getBlockForRegisteredExpression(const Stmt *stmt); |
134 | |
135 | |
136 | Stmt *getBody() const; |
137 | |
138 | |
139 | |
140 | |
141 | Stmt *getBody(bool &IsAutosynthesized) const; |
142 | |
143 | |
144 | |
145 | |
146 | |
147 | |
148 | bool isBodyAutosynthesized() const; |
149 | |
150 | |
151 | |
152 | |
153 | |
154 | |
155 | |
156 | bool isBodyAutosynthesizedFromModelFile() const; |
157 | |
158 | CFG *getCFG(); |
159 | |
160 | CFGStmtMap *getCFGStmtMap(); |
161 | |
162 | CFGReverseBlockReachabilityAnalysis *getCFGReachablityAnalysis(); |
163 | |
164 | |
165 | CFG *getUnoptimizedCFG(); |
166 | |
167 | void dumpCFG(bool ShowColors); |
168 | |
169 | |
170 | |
171 | |
172 | bool isCFGBuilt() const { return builtCFG; } |
173 | |
174 | ParentMap &getParentMap(); |
175 | |
176 | using referenced_decls_iterator = const VarDecl * const *; |
177 | |
178 | llvm::iterator_range<referenced_decls_iterator> |
179 | getReferencedBlockVars(const BlockDecl *BD); |
180 | |
181 | |
182 | |
183 | const ImplicitParamDecl *getSelfDecl() const; |
184 | |
185 | const StackFrameContext *getStackFrame(LocationContext const *Parent, |
186 | const Stmt *S, |
187 | const CFGBlock *Blk, |
188 | unsigned Idx); |
189 | |
190 | const BlockInvocationContext * |
191 | getBlockInvocationContext(const LocationContext *parent, |
192 | const BlockDecl *BD, |
193 | const void *ContextData); |
194 | |
195 | |
196 | |
197 | template <typename T> |
198 | T *getAnalysis() { |
199 | const void *tag = T::getTag(); |
200 | ManagedAnalysis *&data = getAnalysisImpl(tag); |
201 | if (!data) { |
202 | data = T::create(*this); |
203 | } |
204 | return static_cast<T *>(data); |
205 | } |
206 | |
207 | |
208 | |
209 | static bool isInStdNamespace(const Decl *D); |
210 | |
211 | private: |
212 | ManagedAnalysis *&getAnalysisImpl(const void* tag); |
213 | |
214 | LocationContextManager &getLocationContextManager(); |
215 | }; |
216 | |
217 | class LocationContext : public llvm::FoldingSetNode { |
218 | public: |
219 | enum ContextKind { StackFrame, Scope, Block }; |
220 | |
221 | private: |
222 | ContextKind Kind; |
223 | |
224 | |
225 | |
226 | AnalysisDeclContext *Ctx; |
227 | |
228 | const LocationContext *Parent; |
229 | int64_t ID; |
230 | |
231 | protected: |
232 | LocationContext(ContextKind k, AnalysisDeclContext *ctx, |
233 | const LocationContext *parent, |
234 | int64_t ID) |
235 | : Kind(k), Ctx(ctx), Parent(parent), ID(ID) {} |
236 | |
237 | public: |
238 | virtual ~LocationContext(); |
239 | |
240 | ContextKind getKind() const { return Kind; } |
241 | |
242 | int64_t getID() const { |
243 | return ID; |
244 | } |
245 | |
246 | AnalysisDeclContext *getAnalysisDeclContext() const { return Ctx; } |
247 | |
248 | const LocationContext *getParent() const { return Parent; } |
249 | |
250 | bool isParentOf(const LocationContext *LC) const; |
251 | |
252 | const Decl *getDecl() const { return getAnalysisDeclContext()->getDecl(); } |
253 | |
254 | CFG *getCFG() const { return getAnalysisDeclContext()->getCFG(); } |
255 | |
256 | template <typename T> |
257 | T *getAnalysis() const { |
258 | return getAnalysisDeclContext()->getAnalysis<T>(); |
259 | } |
260 | |
261 | ParentMap &getParentMap() const { |
262 | return getAnalysisDeclContext()->getParentMap(); |
263 | } |
264 | |
265 | const ImplicitParamDecl *getSelfDecl() const { |
266 | return Ctx->getSelfDecl(); |
267 | } |
268 | |
269 | const StackFrameContext *getStackFrame() const; |
270 | |
271 | |
272 | virtual bool inTopFrame() const; |
273 | |
274 | virtual void Profile(llvm::FoldingSetNodeID &ID) = 0; |
275 | |
276 | void dumpStack( |
277 | raw_ostream &OS, StringRef Indent = {}, const char *NL = "\n", |
278 | const char *Sep = "", |
279 | std::function<void(const LocationContext *)> printMoreInfoPerContext = |
280 | [](const LocationContext *) {}) const; |
281 | void dumpStack() const; |
282 | |
283 | public: |
284 | static void ProfileCommon(llvm::FoldingSetNodeID &ID, |
285 | ContextKind ck, |
286 | AnalysisDeclContext *ctx, |
287 | const LocationContext *parent, |
288 | const void *data); |
289 | }; |
290 | |
291 | class StackFrameContext : public LocationContext { |
292 | friend class LocationContextManager; |
293 | |
294 | |
295 | const Stmt *CallSite; |
296 | |
297 | |
298 | const CFGBlock *Block; |
299 | |
300 | |
301 | unsigned Index; |
302 | |
303 | StackFrameContext(AnalysisDeclContext *ctx, const LocationContext *parent, |
304 | const Stmt *s, const CFGBlock *blk, |
305 | unsigned idx, |
306 | int64_t ID) |
307 | : LocationContext(StackFrame, ctx, parent, ID), CallSite(s), |
308 | Block(blk), Index(idx) {} |
309 | |
310 | public: |
311 | ~StackFrameContext() override = default; |
312 | |
313 | const Stmt *getCallSite() const { return CallSite; } |
314 | |
315 | const CFGBlock *getCallSiteBlock() const { return Block; } |
316 | |
317 | |
318 | bool inTopFrame() const override { return getParent() == nullptr; } |
319 | |
320 | unsigned getIndex() const { return Index; } |
321 | |
322 | void Profile(llvm::FoldingSetNodeID &ID) override; |
323 | |
324 | static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx, |
325 | const LocationContext *parent, const Stmt *s, |
326 | const CFGBlock *blk, unsigned idx) { |
327 | ProfileCommon(ID, StackFrame, ctx, parent, s); |
328 | ID.AddPointer(blk); |
329 | ID.AddInteger(idx); |
330 | } |
331 | |
332 | static bool classof(const LocationContext *Ctx) { |
333 | return Ctx->getKind() == StackFrame; |
334 | } |
335 | }; |
336 | |
337 | class ScopeContext : public LocationContext { |
338 | friend class LocationContextManager; |
339 | |
340 | const Stmt *Enter; |
341 | |
342 | ScopeContext(AnalysisDeclContext *ctx, const LocationContext *parent, |
343 | const Stmt *s, int64_t ID) |
344 | : LocationContext(Scope, ctx, parent, ID), Enter(s) {} |
345 | |
346 | public: |
347 | ~ScopeContext() override = default; |
348 | |
349 | void Profile(llvm::FoldingSetNodeID &ID) override; |
350 | |
351 | static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx, |
352 | const LocationContext *parent, const Stmt *s) { |
353 | ProfileCommon(ID, Scope, ctx, parent, s); |
354 | } |
355 | |
356 | static bool classof(const LocationContext *Ctx) { |
357 | return Ctx->getKind() == Scope; |
358 | } |
359 | }; |
360 | |
361 | class BlockInvocationContext : public LocationContext { |
362 | friend class LocationContextManager; |
363 | |
364 | const BlockDecl *BD; |
365 | |
366 | |
367 | const void *ContextData; |
368 | |
369 | BlockInvocationContext(AnalysisDeclContext *ctx, |
370 | const LocationContext *parent, const BlockDecl *bd, |
371 | const void *contextData, int64_t ID) |
372 | : LocationContext(Block, ctx, parent, ID), BD(bd), |
373 | ContextData(contextData) {} |
374 | |
375 | public: |
376 | ~BlockInvocationContext() override = default; |
377 | |
378 | const BlockDecl *getBlockDecl() const { return BD; } |
379 | |
380 | const void *getContextData() const { return ContextData; } |
381 | |
382 | void Profile(llvm::FoldingSetNodeID &ID) override; |
383 | |
384 | static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx, |
385 | const LocationContext *parent, const BlockDecl *bd, |
386 | const void *contextData) { |
387 | ProfileCommon(ID, Block, ctx, parent, bd); |
388 | ID.AddPointer(contextData); |
389 | } |
390 | |
391 | static bool classof(const LocationContext *Ctx) { |
392 | return Ctx->getKind() == Block; |
393 | } |
394 | }; |
395 | |
396 | class LocationContextManager { |
397 | llvm::FoldingSet<LocationContext> Contexts; |
398 | |
399 | |
400 | int64_t NewID = 0; |
401 | |
402 | public: |
403 | ~LocationContextManager(); |
404 | |
405 | const StackFrameContext *getStackFrame(AnalysisDeclContext *ctx, |
406 | const LocationContext *parent, |
407 | const Stmt *s, |
408 | const CFGBlock *blk, unsigned idx); |
409 | |
410 | const ScopeContext *getScope(AnalysisDeclContext *ctx, |
411 | const LocationContext *parent, |
412 | const Stmt *s); |
413 | |
414 | const BlockInvocationContext * |
415 | getBlockInvocationContext(AnalysisDeclContext *ctx, |
416 | const LocationContext *parent, |
417 | const BlockDecl *BD, |
418 | const void *ContextData); |
419 | |
420 | |
421 | void clear(); |
422 | private: |
423 | template <typename LOC, typename DATA> |
424 | const LOC *getLocationContext(AnalysisDeclContext *ctx, |
425 | const LocationContext *parent, |
426 | const DATA *d); |
427 | }; |
428 | |
429 | class AnalysisDeclContextManager { |
430 | using ContextMap = |
431 | llvm::DenseMap<const Decl *, std::unique_ptr<AnalysisDeclContext>>; |
432 | |
433 | ContextMap Contexts; |
434 | LocationContextManager LocContexts; |
435 | CFG::BuildOptions cfgBuildOptions; |
436 | |
437 | |
438 | |
439 | std::unique_ptr<CodeInjector> Injector; |
440 | |
441 | |
442 | |
443 | BodyFarm FunctionBodyFarm; |
444 | |
445 | |
446 | |
447 | bool SynthesizeBodies; |
448 | |
449 | public: |
450 | AnalysisDeclContextManager(ASTContext &ASTCtx, bool useUnoptimizedCFG = false, |
451 | bool addImplicitDtors = false, |
452 | bool addInitializers = false, |
453 | bool addTemporaryDtors = false, |
454 | bool addLifetime = false, |
455 | bool addLoopExit = false, |
456 | bool addScopes = false, |
457 | bool synthesizeBodies = false, |
458 | bool addStaticInitBranches = false, |
459 | bool addCXXNewAllocator = true, |
460 | bool addRichCXXConstructors = true, |
461 | bool markElidedCXXConstructors = true, |
462 | CodeInjector *injector = nullptr); |
463 | |
464 | AnalysisDeclContext *getContext(const Decl *D); |
465 | |
466 | bool getUseUnoptimizedCFG() const { |
467 | return !cfgBuildOptions.PruneTriviallyFalseEdges; |
468 | } |
469 | |
470 | CFG::BuildOptions &getCFGBuildOptions() { |
471 | return cfgBuildOptions; |
472 | } |
473 | |
474 | |
475 | |
476 | bool synthesizeBodies() const { return SynthesizeBodies; } |
477 | |
478 | const StackFrameContext *getStackFrame(AnalysisDeclContext *Ctx, |
479 | LocationContext const *Parent, |
480 | const Stmt *S, |
481 | const CFGBlock *Blk, |
482 | unsigned Idx) { |
483 | return LocContexts.getStackFrame(Ctx, Parent, S, Blk, Idx); |
484 | } |
485 | |
486 | |
487 | const StackFrameContext *getStackFrame(const Decl *D) { |
488 | return LocContexts.getStackFrame(getContext(D), nullptr, nullptr, nullptr, |
489 | 0); |
490 | } |
491 | |
492 | |
493 | StackFrameContext const *getStackFrame(const Decl *D, |
494 | LocationContext const *Parent, |
495 | const Stmt *S, |
496 | const CFGBlock *Blk, |
497 | unsigned Idx) { |
498 | return LocContexts.getStackFrame(getContext(D), Parent, S, Blk, Idx); |
499 | } |
500 | |
501 | |
502 | BodyFarm &getBodyFarm(); |
503 | |
504 | |
505 | void clear(); |
506 | |
507 | private: |
508 | friend class AnalysisDeclContext; |
509 | |
510 | LocationContextManager &getLocationContextManager() { |
511 | return LocContexts; |
512 | } |
513 | }; |
514 | |
515 | } |
516 | |
517 | #endif |
518 | |