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