AnalysisContext.h revision a5937bbfd19e61d651a58b0f0ffeef68457902a5
1//=== AnalysisContext.h - Analysis context for Path Sens analysis --*- C++ -*-//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file defines AnalysisContext, a class that manages the analysis context
11// data for path sensitive analysis.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_CLANG_ANALYSIS_ANALYSISCONTEXT_H
16#define LLVM_CLANG_ANALYSIS_ANALYSISCONTEXT_H
17
18#include "clang/AST/Decl.h"
19#include "clang/AST/Expr.h"
20#include "clang/Analysis/CFG.h"
21#include "llvm/ADT/OwningPtr.h"
22#include "llvm/ADT/IntrusiveRefCntPtr.h"
23#include "llvm/ADT/FoldingSet.h"
24#include "llvm/ADT/PointerUnion.h"
25#include "llvm/ADT/DenseMap.h"
26#include "llvm/Support/Allocator.h"
27
28namespace clang {
29
30class Decl;
31class Stmt;
32class CFGReverseBlockReachabilityAnalysis;
33class CFGStmtMap;
34class LiveVariables;
35class ManagedAnalysis;
36class ParentMap;
37class PseudoConstantAnalysis;
38class ImplicitParamDecl;
39class LocationContextManager;
40class StackFrameContext;
41
42namespace idx { class TranslationUnit; }
43
44/// The base class of a hierarchy of objects representing analyses tied
45/// to AnalysisContext.
46class ManagedAnalysis {
47protected:
48  ManagedAnalysis() {}
49public:
50  virtual ~ManagedAnalysis();
51
52  // Subclasses need to implement:
53  //
54  //  static const void *getTag();
55  //
56  // Which returns a fixed pointer address to distinguish classes of
57  // analysis objects.  They also need to implement:
58  //
59  //  static [Derived*] create(AnalysisContext &Ctx);
60  //
61  // which creates the analysis object given an AnalysisContext.
62};
63
64/// AnalysisContext contains the context data for the function or method under
65/// analysis.
66class AnalysisContext {
67  const Decl *D;
68
69  // TranslationUnit is NULL if we don't have multiple translation units.
70  idx::TranslationUnit *TU;
71
72  llvm::OwningPtr<CFG> cfg, completeCFG;
73  llvm::OwningPtr<CFGStmtMap> cfgStmtMap;
74
75  CFG::BuildOptions cfgBuildOptions;
76  CFG::BuildOptions::ForcedBlkExprs *forcedBlkExprs;
77
78  bool builtCFG, builtCompleteCFG;
79
80  llvm::OwningPtr<LiveVariables> liveness;
81  llvm::OwningPtr<LiveVariables> relaxedLiveness;
82  llvm::OwningPtr<ParentMap> PM;
83  llvm::OwningPtr<PseudoConstantAnalysis> PCA;
84  llvm::OwningPtr<CFGReverseBlockReachabilityAnalysis> CFA;
85
86  llvm::BumpPtrAllocator A;
87
88  // FIXME: remove.
89  llvm::DenseMap<const BlockDecl*,void*> *ReferencedBlockVars;
90
91  void *ManagedAnalyses;
92
93public:
94  AnalysisContext(const Decl *d, idx::TranslationUnit *tu);
95
96  AnalysisContext(const Decl *d, idx::TranslationUnit *tu,
97                  const CFG::BuildOptions &buildOptions);
98
99  ~AnalysisContext();
100
101  ASTContext &getASTContext() { return D->getASTContext(); }
102  const Decl *getDecl() const { return D; }
103
104  idx::TranslationUnit *getTranslationUnit() const { return TU; }
105
106  /// Return the build options used to construct the CFG.
107  CFG::BuildOptions &getCFGBuildOptions() {
108    return cfgBuildOptions;
109  }
110
111  const CFG::BuildOptions &getCFGBuildOptions() const {
112    return cfgBuildOptions;
113  }
114
115  /// getAddEHEdges - Return true iff we are adding exceptional edges from
116  /// callExprs.  If this is false, then try/catch statements and blocks
117  /// reachable from them can appear to be dead in the CFG, analysis passes must
118  /// cope with that.
119  bool getAddEHEdges() const { return cfgBuildOptions.AddEHEdges; }
120  bool getUseUnoptimizedCFG() const {
121      return !cfgBuildOptions.PruneTriviallyFalseEdges;
122  }
123  bool getAddImplicitDtors() const { return cfgBuildOptions.AddImplicitDtors; }
124  bool getAddInitializers() const { return cfgBuildOptions.AddInitializers; }
125
126  void registerForcedBlockExpression(const Stmt *stmt);
127  const CFGBlock *getBlockForRegisteredExpression(const Stmt *stmt);
128
129  Stmt *getBody() const;
130  CFG *getCFG();
131
132  CFGStmtMap *getCFGStmtMap();
133
134  CFGReverseBlockReachabilityAnalysis *getCFGReachablityAnalysis();
135
136  /// Return a version of the CFG without any edges pruned.
137  CFG *getUnoptimizedCFG();
138
139  void dumpCFG();
140
141  /// \brief Returns true if we have built a CFG for this analysis context.
142  /// Note that this doesn't correspond to whether or not a valid CFG exists, it
143  /// corresponds to whether we *attempted* to build one.
144  bool isCFGBuilt() const { return builtCFG; }
145
146  ParentMap &getParentMap();
147  PseudoConstantAnalysis *getPseudoConstantAnalysis();
148
149  typedef const VarDecl * const * referenced_decls_iterator;
150
151  std::pair<referenced_decls_iterator, referenced_decls_iterator>
152    getReferencedBlockVars(const BlockDecl *BD);
153
154  /// Return the ImplicitParamDecl* associated with 'self' if this
155  /// AnalysisContext wraps an ObjCMethodDecl.  Returns NULL otherwise.
156  const ImplicitParamDecl *getSelfDecl() const;
157
158  /// Return the specified analysis object, lazily running the analysis if
159  /// necessary.  Return NULL if the analysis could not run.
160  template <typename T>
161  T *getAnalysis() {
162    const void *tag = T::getTag();
163    ManagedAnalysis *&data = getAnalysisImpl(tag);
164    if (!data) {
165      data = T::create(*this);
166    }
167    return static_cast<T*>(data);
168  }
169private:
170  ManagedAnalysis *&getAnalysisImpl(const void* tag);
171};
172
173class AnalysisContextManager {
174  typedef llvm::DenseMap<const Decl*, AnalysisContext*> ContextMap;
175  ContextMap Contexts;
176  CFG::BuildOptions cfgBuildOptions;
177public:
178  AnalysisContextManager(bool useUnoptimizedCFG = false,
179                         bool addImplicitDtors = false,
180                         bool addInitializers = false);
181
182  ~AnalysisContextManager();
183
184  AnalysisContext *getContext(const Decl *D, idx::TranslationUnit *TU = 0);
185
186  bool getUseUnoptimizedCFG() const {
187    return !cfgBuildOptions.PruneTriviallyFalseEdges;
188  }
189
190  CFG::BuildOptions &getCFGBuildOptions() {
191    return cfgBuildOptions;
192  }
193
194  /// Discard all previously created AnalysisContexts.
195  void clear();
196};
197
198class LocationContext : public llvm::FoldingSetNode {
199public:
200  enum ContextKind { StackFrame, Scope, Block };
201
202private:
203  ContextKind Kind;
204
205  // AnalysisContext can't be const since some methods may modify its member.
206  AnalysisContext *Ctx;
207
208  const LocationContext *Parent;
209
210protected:
211  LocationContext(ContextKind k, AnalysisContext *ctx,
212                  const LocationContext *parent)
213    : Kind(k), Ctx(ctx), Parent(parent) {}
214
215public:
216  virtual ~LocationContext();
217
218  ContextKind getKind() const { return Kind; }
219
220  AnalysisContext *getAnalysisContext() const { return Ctx; }
221
222  idx::TranslationUnit *getTranslationUnit() const {
223    return Ctx->getTranslationUnit();
224  }
225
226  const LocationContext *getParent() const { return Parent; }
227
228  bool isParentOf(const LocationContext *LC) const;
229
230  const Decl *getDecl() const { return getAnalysisContext()->getDecl(); }
231
232  CFG *getCFG() const { return getAnalysisContext()->getCFG(); }
233
234  template <typename T>
235  T *getAnalysis() const {
236    return getAnalysisContext()->getAnalysis<T>();
237  }
238
239  ParentMap &getParentMap() const {
240    return getAnalysisContext()->getParentMap();
241  }
242
243  const ImplicitParamDecl *getSelfDecl() const {
244    return Ctx->getSelfDecl();
245  }
246
247  const StackFrameContext *getCurrentStackFrame() const;
248  const StackFrameContext *
249    getStackFrameForDeclContext(const DeclContext *DC) const;
250
251  virtual void Profile(llvm::FoldingSetNodeID &ID) = 0;
252
253  static bool classof(const LocationContext*) { return true; }
254
255public:
256  static void ProfileCommon(llvm::FoldingSetNodeID &ID,
257                            ContextKind ck,
258                            AnalysisContext *ctx,
259                            const LocationContext *parent,
260                            const void *data);
261};
262
263class StackFrameContext : public LocationContext {
264  // The callsite where this stack frame is established.
265  const Stmt *CallSite;
266
267  // The parent block of the callsite.
268  const CFGBlock *Block;
269
270  // The index of the callsite in the CFGBlock.
271  unsigned Index;
272
273  friend class LocationContextManager;
274  StackFrameContext(AnalysisContext *ctx, const LocationContext *parent,
275                    const Stmt *s, const CFGBlock *blk,
276                    unsigned idx)
277    : LocationContext(StackFrame, ctx, parent), CallSite(s),
278      Block(blk), Index(idx) {}
279
280public:
281  ~StackFrameContext() {}
282
283  const Stmt *getCallSite() const { return CallSite; }
284
285  const CFGBlock *getCallSiteBlock() const { return Block; }
286
287  unsigned getIndex() const { return Index; }
288
289  void Profile(llvm::FoldingSetNodeID &ID);
290
291  static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx,
292                      const LocationContext *parent, const Stmt *s,
293                      const CFGBlock *blk, unsigned idx) {
294    ProfileCommon(ID, StackFrame, ctx, parent, s);
295    ID.AddPointer(blk);
296    ID.AddInteger(idx);
297  }
298
299  static bool classof(const LocationContext *Ctx) {
300    return Ctx->getKind() == StackFrame;
301  }
302};
303
304class ScopeContext : public LocationContext {
305  const Stmt *Enter;
306
307  friend class LocationContextManager;
308  ScopeContext(AnalysisContext *ctx, const LocationContext *parent,
309               const Stmt *s)
310    : LocationContext(Scope, ctx, parent), Enter(s) {}
311
312public:
313  ~ScopeContext() {}
314
315  void Profile(llvm::FoldingSetNodeID &ID);
316
317  static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx,
318                      const LocationContext *parent, const Stmt *s) {
319    ProfileCommon(ID, Scope, ctx, parent, s);
320  }
321
322  static bool classof(const LocationContext *Ctx) {
323    return Ctx->getKind() == Scope;
324  }
325};
326
327class BlockInvocationContext : public LocationContext {
328  // FIXME: Add back context-sensivity (we don't want libAnalysis to know
329  //  about MemRegion).
330  const BlockDecl *BD;
331
332  friend class LocationContextManager;
333
334  BlockInvocationContext(AnalysisContext *ctx, const LocationContext *parent,
335                         const BlockDecl *bd)
336    : LocationContext(Block, ctx, parent), BD(bd) {}
337
338public:
339  ~BlockInvocationContext() {}
340
341  const BlockDecl *getBlockDecl() const { return BD; }
342
343  void Profile(llvm::FoldingSetNodeID &ID);
344
345  static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx,
346                      const LocationContext *parent, const BlockDecl *bd) {
347    ProfileCommon(ID, Block, ctx, parent, bd);
348  }
349
350  static bool classof(const LocationContext *Ctx) {
351    return Ctx->getKind() == Block;
352  }
353};
354
355class LocationContextManager {
356  llvm::FoldingSet<LocationContext> Contexts;
357public:
358  ~LocationContextManager();
359
360  const StackFrameContext *getStackFrame(AnalysisContext *ctx,
361                                         const LocationContext *parent,
362                                         const Stmt *s,
363                                         const CFGBlock *blk, unsigned idx);
364
365  const ScopeContext *getScope(AnalysisContext *ctx,
366                               const LocationContext *parent,
367                               const Stmt *s);
368
369  /// Discard all previously created LocationContext objects.
370  void clear();
371private:
372  template <typename LOC, typename DATA>
373  const LOC *getLocationContext(AnalysisContext *ctx,
374                                const LocationContext *parent,
375                                const DATA *d);
376};
377
378} // end clang namespace
379#endif
380