AnalysisContext.h revision 9b823e8e1ccb8a2cb49923bad22a80ca96f41f92
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 "llvm/ADT/OwningPtr.h"
20#include "llvm/ADT/FoldingSet.h"
21#include "llvm/ADT/PointerUnion.h"
22#include "llvm/ADT/DenseMap.h"
23#include "llvm/Support/Allocator.h"
24
25namespace clang {
26
27class Decl;
28class Stmt;
29class CFG;
30class CFGBlock;
31class LiveVariables;
32class ParentMap;
33class ImplicitParamDecl;
34class LocationContextManager;
35class StackFrameContext;
36
37namespace idx { class TranslationUnit; }
38
39/// AnalysisContext contains the context data for the function or method under
40/// analysis.
41class AnalysisContext {
42  const Decl *D;
43
44  // TranslationUnit is NULL if we don't have multiple translation units.
45  idx::TranslationUnit *TU;
46
47  // AnalysisContext owns the following data.
48  CFG *cfg, *completeCFG;
49  bool builtCFG, builtCompleteCFG;
50  LiveVariables *liveness;
51  ParentMap *PM;
52  llvm::DenseMap<const BlockDecl*,void*> *ReferencedBlockVars;
53  llvm::BumpPtrAllocator A;
54  bool UseUnoptimizedCFG;
55  bool AddEHEdges;
56public:
57  AnalysisContext(const Decl *d, idx::TranslationUnit *tu,
58                  bool useUnoptimizedCFG = false,
59                  bool addehedges = false)
60    : D(d), TU(tu), cfg(0), completeCFG(0),
61      builtCFG(false), builtCompleteCFG(false),
62      liveness(0), PM(0),
63      ReferencedBlockVars(0), UseUnoptimizedCFG(useUnoptimizedCFG),
64      AddEHEdges(addehedges) {}
65
66  ~AnalysisContext();
67
68  ASTContext &getASTContext() { return D->getASTContext(); }
69  const Decl *getDecl() const { return D; }
70
71  idx::TranslationUnit *getTranslationUnit() const { return TU; }
72
73  /// getAddEHEdges - Return true iff we are adding exceptional edges from
74  /// callExprs.  If this is false, then try/catch statements and blocks
75  /// reachable from them can appear to be dead in the CFG, analysis passes must
76  /// cope with that.
77  bool getAddEHEdges() const { return AddEHEdges; }
78
79  bool getUseUnoptimizedCFG() const { return UseUnoptimizedCFG; }
80
81  Stmt *getBody();
82  CFG *getCFG();
83
84  /// Return a version of the CFG without any edges pruned.
85  CFG *getUnoptimizedCFG();
86
87  ParentMap &getParentMap();
88  LiveVariables *getLiveVariables();
89
90  typedef const VarDecl * const * referenced_decls_iterator;
91
92  std::pair<referenced_decls_iterator, referenced_decls_iterator>
93    getReferencedBlockVars(const BlockDecl *BD);
94
95  /// Return the ImplicitParamDecl* associated with 'self' if this
96  /// AnalysisContext wraps an ObjCMethodDecl.  Returns NULL otherwise.
97  const ImplicitParamDecl *getSelfDecl() const;
98};
99
100class AnalysisContextManager {
101  typedef llvm::DenseMap<const Decl*, AnalysisContext*> ContextMap;
102  ContextMap Contexts;
103  bool UseUnoptimizedCFG;
104public:
105  AnalysisContextManager(bool useUnoptimizedCFG = false)
106    : UseUnoptimizedCFG(useUnoptimizedCFG) {}
107
108  ~AnalysisContextManager();
109
110  AnalysisContext *getContext(const Decl *D, idx::TranslationUnit *TU = 0);
111
112  bool getUseUnoptimizedCFG() const { return UseUnoptimizedCFG; }
113
114  // Discard all previously created AnalysisContexts.
115  void clear();
116};
117
118class LocationContext : public llvm::FoldingSetNode {
119public:
120  enum ContextKind { StackFrame, Scope, Block };
121
122private:
123  ContextKind Kind;
124
125  // AnalysisContext can't be const since some methods may modify its member.
126  AnalysisContext *Ctx;
127
128  const LocationContext *Parent;
129
130protected:
131  LocationContext(ContextKind k, AnalysisContext *ctx,
132                  const LocationContext *parent)
133    : Kind(k), Ctx(ctx), Parent(parent) {}
134
135public:
136  virtual ~LocationContext();
137
138  ContextKind getKind() const { return Kind; }
139
140  AnalysisContext *getAnalysisContext() const { return Ctx; }
141
142  idx::TranslationUnit *getTranslationUnit() const {
143    return Ctx->getTranslationUnit();
144  }
145
146  const LocationContext *getParent() const { return Parent; }
147
148  bool isParentOf(const LocationContext *LC) const;
149
150  const Decl *getDecl() const { return getAnalysisContext()->getDecl(); }
151
152  CFG *getCFG() const { return getAnalysisContext()->getCFG(); }
153
154  LiveVariables *getLiveVariables() const {
155    return getAnalysisContext()->getLiveVariables();
156  }
157
158  ParentMap &getParentMap() const {
159    return getAnalysisContext()->getParentMap();
160  }
161
162  const ImplicitParamDecl *getSelfDecl() const {
163    return Ctx->getSelfDecl();
164  }
165
166  const StackFrameContext *getCurrentStackFrame() const;
167  const StackFrameContext *
168    getStackFrameForDeclContext(const DeclContext *DC) const;
169
170  virtual void Profile(llvm::FoldingSetNodeID &ID) = 0;
171
172  static bool classof(const LocationContext*) { return true; }
173
174public:
175  static void ProfileCommon(llvm::FoldingSetNodeID &ID,
176                            ContextKind ck,
177                            AnalysisContext *ctx,
178                            const LocationContext *parent,
179                            const void* data);
180};
181
182class StackFrameContext : public LocationContext {
183  // The callsite where this stack frame is established.
184  const Stmt *CallSite;
185
186  // The parent block of the callsite.
187  const CFGBlock *Block;
188
189  // The index of the callsite in the CFGBlock.
190  unsigned Index;
191
192  friend class LocationContextManager;
193  StackFrameContext(AnalysisContext *ctx, const LocationContext *parent,
194                    const Stmt *s, const CFGBlock *blk, unsigned idx)
195    : LocationContext(StackFrame, ctx, parent), CallSite(s), Block(blk),
196      Index(idx) {}
197
198public:
199  ~StackFrameContext() {}
200
201  const Stmt *getCallSite() const { return CallSite; }
202
203  const CFGBlock *getCallSiteBlock() const { return Block; }
204
205  unsigned getIndex() const { return Index; }
206
207  void Profile(llvm::FoldingSetNodeID &ID);
208
209  static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx,
210                      const LocationContext *parent, const Stmt *s,
211                      const CFGBlock *blk, unsigned idx) {
212    ProfileCommon(ID, StackFrame, ctx, parent, s);
213    ID.AddPointer(blk);
214    ID.AddInteger(idx);
215  }
216
217  static bool classof(const LocationContext* Ctx) {
218    return Ctx->getKind() == StackFrame;
219  }
220};
221
222class ScopeContext : public LocationContext {
223  const Stmt *Enter;
224
225  friend class LocationContextManager;
226  ScopeContext(AnalysisContext *ctx, const LocationContext *parent,
227               const Stmt *s)
228    : LocationContext(Scope, ctx, parent), Enter(s) {}
229
230public:
231  ~ScopeContext() {}
232
233  void Profile(llvm::FoldingSetNodeID &ID);
234
235  static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx,
236                      const LocationContext *parent, const Stmt *s) {
237    ProfileCommon(ID, Scope, ctx, parent, s);
238  }
239
240  static bool classof(const LocationContext* Ctx) {
241    return Ctx->getKind() == Scope;
242  }
243};
244
245class BlockInvocationContext : public LocationContext {
246  // FIXME: Add back context-sensivity (we don't want libAnalysis to know
247  //  about MemRegion).
248  const BlockDecl *BD;
249
250  friend class LocationContextManager;
251
252  BlockInvocationContext(AnalysisContext *ctx, const LocationContext *parent,
253                         const BlockDecl *bd)
254    : LocationContext(Block, ctx, parent), BD(bd) {}
255
256public:
257  ~BlockInvocationContext() {}
258
259  const BlockDecl *getBlockDecl() const { return BD; }
260
261  void Profile(llvm::FoldingSetNodeID &ID);
262
263  static void Profile(llvm::FoldingSetNodeID &ID, AnalysisContext *ctx,
264                      const LocationContext *parent, const BlockDecl *bd) {
265    ProfileCommon(ID, Block, ctx, parent, bd);
266  }
267
268  static bool classof(const LocationContext* Ctx) {
269    return Ctx->getKind() == Block;
270  }
271};
272
273class LocationContextManager {
274  llvm::FoldingSet<LocationContext> Contexts;
275public:
276  ~LocationContextManager();
277
278  const StackFrameContext *getStackFrame(AnalysisContext *ctx,
279                                         const LocationContext *parent,
280                                         const Stmt *s, const CFGBlock *blk,
281                                         unsigned idx);
282
283  const ScopeContext *getScope(AnalysisContext *ctx,
284                               const LocationContext *parent,
285                               const Stmt *s);
286
287  /// Discard all previously created LocationContext objects.
288  void clear();
289private:
290  template <typename LOC, typename DATA>
291  const LOC *getLocationContext(AnalysisContext *ctx,
292                                const LocationContext *parent,
293                                const DATA *d);
294};
295
296} // end clang namespace
297#endif
298