ProgramPoint.h revision ca804539d908d3a0e8c72a0df5f1f571d29490bb
1//==- ProgramPoint.h - Program Points for Path-Sensitive 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 the interface ProgramPoint, which identifies a
11//  distinct location in a function.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_CLANG_ANALYSIS_PROGRAM_POINT
16#define LLVM_CLANG_ANALYSIS_PROGRAM_POINT
17
18#include "clang/Analysis/AnalysisContext.h"
19#include "clang/Analysis/CFG.h"
20#include "llvm/Support/DataTypes.h"
21#include "llvm/ADT/DenseMap.h"
22#include "llvm/ADT/FoldingSet.h"
23#include "llvm/Support/Casting.h"
24#include "llvm/ADT/StringRef.h"
25#include <cassert>
26#include <utility>
27#include <string>
28
29namespace clang {
30
31class AnalysisContext;
32class FunctionDecl;
33class LocationContext;
34class ProgramPointTag;
35
36class ProgramPoint {
37public:
38  enum Kind { BlockEdgeKind,
39              BlockEntranceKind,
40              BlockExitKind,
41              PreStmtKind,
42              PostStmtKind,
43              PreLoadKind,
44              PostLoadKind,
45              PreStoreKind,
46              PostStoreKind,
47              PostPurgeDeadSymbolsKind,
48              PostStmtCustomKind,
49              PostConditionKind,
50              PostLValueKind,
51              PostInitializerKind,
52              CallEnterKind,
53              CallExitKind,
54              MinPostStmtKind = PostStmtKind,
55              MaxPostStmtKind = CallExitKind };
56
57private:
58  std::pair<const void *, const void *> Data;
59  Kind K;
60
61  // The LocationContext could be NULL to allow ProgramPoint to be used in
62  // context insensitive analysis.
63  const LocationContext *L;
64  const ProgramPointTag *Tag;
65
66  ProgramPoint();
67
68protected:
69  ProgramPoint(const void* P, Kind k, const LocationContext *l,
70               const ProgramPointTag *tag = 0)
71    : Data(P, static_cast<const void*>(NULL)), K(k), L(l), Tag(tag) {}
72
73  ProgramPoint(const void* P1, const void* P2, Kind k, const LocationContext *l,
74               const ProgramPointTag *tag = 0)
75    : Data(P1, P2), K(k), L(l), Tag(tag) {}
76
77protected:
78  const void* getData1() const { return Data.first; }
79  const void* getData2() const { return Data.second; }
80
81public:
82  Kind getKind() const { return K; }
83
84  const ProgramPointTag *getTag() const { return Tag; }
85
86  const LocationContext *getLocationContext() const { return L; }
87
88  // For use with DenseMap.  This hash is probably slow.
89  unsigned getHashValue() const {
90    llvm::FoldingSetNodeID ID;
91    Profile(ID);
92    return ID.ComputeHash();
93  }
94
95  static bool classof(const ProgramPoint*) { return true; }
96
97  bool operator==(const ProgramPoint & RHS) const {
98    return K == RHS.K && Data == RHS.Data && L == RHS.L && Tag == RHS.Tag;
99  }
100
101  bool operator!=(const ProgramPoint& RHS) const {
102    return K != RHS.K || Data != RHS.Data || L != RHS.L || Tag != RHS.Tag;
103  }
104
105  void Profile(llvm::FoldingSetNodeID& ID) const {
106    ID.AddInteger((unsigned) K);
107    ID.AddPointer(Data.first);
108    ID.AddPointer(Data.second);
109    ID.AddPointer(L);
110    ID.AddPointer(Tag);
111  }
112};
113
114class BlockEntrance : public ProgramPoint {
115public:
116  BlockEntrance(const CFGBlock* B, const LocationContext *L,
117                const ProgramPointTag *tag = 0)
118    : ProgramPoint(B, BlockEntranceKind, L, tag) {}
119
120  const CFGBlock* getBlock() const {
121    return reinterpret_cast<const CFGBlock*>(getData1());
122  }
123
124  const CFGElement getFirstElement() const {
125    const CFGBlock* B = getBlock();
126    return B->empty() ? CFGElement() : B->front();
127  }
128
129  /// Create a new BlockEntrance object that is the same as the original
130  /// except for using the specified tag value.
131  BlockEntrance withTag(const ProgramPointTag *tag) {
132    return BlockEntrance(getBlock(), getLocationContext(), tag);
133  }
134
135  static bool classof(const ProgramPoint* Location) {
136    return Location->getKind() == BlockEntranceKind;
137  }
138};
139
140class BlockExit : public ProgramPoint {
141public:
142  BlockExit(const CFGBlock* B, const LocationContext *L)
143    : ProgramPoint(B, BlockExitKind, L) {}
144
145  const CFGBlock* getBlock() const {
146    return reinterpret_cast<const CFGBlock*>(getData1());
147  }
148
149  const Stmt* getTerminator() const {
150    return getBlock()->getTerminator();
151  }
152
153  static bool classof(const ProgramPoint* Location) {
154    return Location->getKind() == BlockExitKind;
155  }
156};
157
158class StmtPoint : public ProgramPoint {
159public:
160  StmtPoint(const Stmt *S, const void *p2, Kind k, const LocationContext *L,
161            const ProgramPointTag *tag)
162    : ProgramPoint(S, p2, k, L, tag) {}
163
164  const Stmt *getStmt() const { return (const Stmt*) getData1(); }
165
166  template <typename T>
167  const T* getStmtAs() const { return llvm::dyn_cast<T>(getStmt()); }
168
169  static bool classof(const ProgramPoint* Location) {
170    unsigned k = Location->getKind();
171    return k >= PreStmtKind && k <= MaxPostStmtKind;
172  }
173};
174
175
176class PreStmt : public StmtPoint {
177public:
178  PreStmt(const Stmt *S, const LocationContext *L, const ProgramPointTag *tag,
179          const Stmt *SubStmt = 0)
180    : StmtPoint(S, SubStmt, PreStmtKind, L, tag) {}
181
182  const Stmt *getSubStmt() const { return (const Stmt*) getData2(); }
183
184  static bool classof(const ProgramPoint* Location) {
185    return Location->getKind() == PreStmtKind;
186  }
187};
188
189class PostStmt : public StmtPoint {
190protected:
191  PostStmt(const Stmt* S, const void* data, Kind k, const LocationContext *L,
192           const ProgramPointTag *tag =0)
193    : StmtPoint(S, data, k, L, tag) {}
194
195public:
196  explicit PostStmt(const Stmt* S, Kind k,
197                    const LocationContext *L, const ProgramPointTag *tag = 0)
198    : StmtPoint(S, NULL, k, L, tag) {}
199
200  explicit PostStmt(const Stmt* S, const LocationContext *L,
201                    const ProgramPointTag *tag = 0)
202    : StmtPoint(S, NULL, PostStmtKind, L, tag) {}
203
204  static bool classof(const ProgramPoint* Location) {
205    unsigned k = Location->getKind();
206    return k >= MinPostStmtKind && k <= MaxPostStmtKind;
207  }
208};
209
210class PostStmtCustom : public PostStmt {
211public:
212  PostStmtCustom(const Stmt* S,
213                 const std::pair<const void*, const void*>* TaggedData,\
214                 const LocationContext *L)
215    : PostStmt(S, TaggedData, PostStmtCustomKind, L) {}
216
217  const std::pair<const void*, const void*>& getTaggedPair() const {
218    return
219      *reinterpret_cast<const std::pair<const void*, const void*>*>(getData2());
220  }
221
222  const void* getTag() const { return getTaggedPair().first; }
223
224  const void* getTaggedData() const { return getTaggedPair().second; }
225
226  static bool classof(const ProgramPoint* Location) {
227    return Location->getKind() == PostStmtCustomKind;
228  }
229};
230
231// PostCondition represents the post program point of a branch condition.
232class PostCondition : public PostStmt {
233public:
234  PostCondition(const Stmt* S, const LocationContext *L,
235                const ProgramPointTag *tag = 0)
236    : PostStmt(S, PostConditionKind, L, tag) {}
237
238  static bool classof(const ProgramPoint* Location) {
239    return Location->getKind() == PostConditionKind;
240  }
241};
242
243class LocationCheck : public StmtPoint {
244protected:
245  LocationCheck(const Stmt *S, const LocationContext *L,
246                ProgramPoint::Kind K, const ProgramPointTag *tag)
247    : StmtPoint(S, NULL, K, L, tag) {}
248
249  static bool classof(const ProgramPoint *location) {
250    unsigned k = location->getKind();
251    return k == PreLoadKind || k == PreStoreKind;
252  }
253};
254
255class PreLoad : public LocationCheck {
256public:
257  PreLoad(const Stmt *S, const LocationContext *L,
258          const ProgramPointTag *tag = 0)
259    : LocationCheck(S, L, PreLoadKind, tag) {}
260
261  static bool classof(const ProgramPoint *location) {
262    return location->getKind() == PreLoadKind;
263  }
264};
265
266class PreStore : public LocationCheck {
267public:
268  PreStore(const Stmt *S, const LocationContext *L,
269           const ProgramPointTag *tag = 0)
270  : LocationCheck(S, L, PreStoreKind, tag) {}
271
272  static bool classof(const ProgramPoint *location) {
273    return location->getKind() == PreStoreKind;
274  }
275};
276
277class PostLoad : public PostStmt {
278public:
279  PostLoad(const Stmt* S, const LocationContext *L,
280           const ProgramPointTag *tag = 0)
281    : PostStmt(S, PostLoadKind, L, tag) {}
282
283  static bool classof(const ProgramPoint* Location) {
284    return Location->getKind() == PostLoadKind;
285  }
286};
287
288class PostStore : public PostStmt {
289public:
290  PostStore(const Stmt* S, const LocationContext *L,
291            const ProgramPointTag *tag = 0)
292    : PostStmt(S, PostStoreKind, L, tag) {}
293
294  static bool classof(const ProgramPoint* Location) {
295    return Location->getKind() == PostStoreKind;
296  }
297};
298
299class PostLValue : public PostStmt {
300public:
301  PostLValue(const Stmt* S, const LocationContext *L,
302             const ProgramPointTag *tag = 0)
303    : PostStmt(S, PostLValueKind, L, tag) {}
304
305  static bool classof(const ProgramPoint* Location) {
306    return Location->getKind() == PostLValueKind;
307  }
308};
309
310class PostPurgeDeadSymbols : public PostStmt {
311public:
312  PostPurgeDeadSymbols(const Stmt* S, const LocationContext *L,
313                       const ProgramPointTag *tag = 0)
314    : PostStmt(S, PostPurgeDeadSymbolsKind, L, tag) {}
315
316  static bool classof(const ProgramPoint* Location) {
317    return Location->getKind() == PostPurgeDeadSymbolsKind;
318  }
319};
320
321class BlockEdge : public ProgramPoint {
322public:
323  BlockEdge(const CFGBlock* B1, const CFGBlock* B2, const LocationContext *L)
324    : ProgramPoint(B1, B2, BlockEdgeKind, L) {}
325
326  const CFGBlock* getSrc() const {
327    return static_cast<const CFGBlock*>(getData1());
328  }
329
330  const CFGBlock* getDst() const {
331    return static_cast<const CFGBlock*>(getData2());
332  }
333
334  static bool classof(const ProgramPoint* Location) {
335    return Location->getKind() == BlockEdgeKind;
336  }
337};
338
339class PostInitializer : public ProgramPoint {
340public:
341  PostInitializer(const CXXCtorInitializer *I,
342                  const LocationContext *L)
343    : ProgramPoint(I, PostInitializerKind, L) {}
344
345  static bool classof(const ProgramPoint *Location) {
346    return Location->getKind() == PostInitializerKind;
347  }
348};
349
350class CallEnter : public StmtPoint {
351public:
352  CallEnter(const Stmt *stmt, const StackFrameContext *calleeCtx,
353            const LocationContext *callerCtx)
354    : StmtPoint(stmt, calleeCtx, CallEnterKind, callerCtx, 0) {}
355
356  const Stmt *getCallExpr() const {
357    return static_cast<const Stmt *>(getData1());
358  }
359
360  const StackFrameContext *getCalleeContext() const {
361    return static_cast<const StackFrameContext *>(getData2());
362  }
363
364  static bool classof(const ProgramPoint *Location) {
365    return Location->getKind() == CallEnterKind;
366  }
367};
368
369class CallExit : public StmtPoint {
370public:
371  // CallExit uses the callee's location context.
372  CallExit(const Stmt *S, const LocationContext *L)
373    : StmtPoint(S, 0, CallExitKind, L, 0) {}
374
375  static bool classof(const ProgramPoint *Location) {
376    return Location->getKind() == CallExitKind;
377  }
378};
379
380/// ProgramPoints can be "tagged" as representing points specific to a given
381/// analysis entity.  Tags are abstract annotations, with an associated
382/// description and potentially other information.
383class ProgramPointTag {
384public:
385  ProgramPointTag(void *tagKind = 0) : TagKind(tagKind) {}
386  virtual ~ProgramPointTag();
387  virtual StringRef getTagDescription() const = 0;
388
389protected:
390  const void *getTagKind() { return TagKind; }
391
392private:
393  const void *TagKind;
394};
395
396class SimpleProgramPointTag : public ProgramPointTag {
397  std::string desc;
398public:
399  SimpleProgramPointTag(StringRef description);
400  StringRef getTagDescription() const;
401};
402
403} // end namespace clang
404
405
406namespace llvm { // Traits specialization for DenseMap
407
408template <> struct DenseMapInfo<clang::ProgramPoint> {
409
410static inline clang::ProgramPoint getEmptyKey() {
411  uintptr_t x =
412   reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getEmptyKey()) & ~0x7;
413  return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), 0);
414}
415
416static inline clang::ProgramPoint getTombstoneKey() {
417  uintptr_t x =
418   reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getTombstoneKey()) & ~0x7;
419  return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), 0);
420}
421
422static unsigned getHashValue(const clang::ProgramPoint& Loc) {
423  return Loc.getHashValue();
424}
425
426static bool isEqual(const clang::ProgramPoint& L,
427                    const clang::ProgramPoint& R) {
428  return L == R;
429}
430
431};
432
433template <>
434struct isPodLike<clang::ProgramPoint> { static const bool value = true; };
435
436} // end namespace llvm
437
438#endif
439