clang API Documentation

ProgramPoint.h
Go to the documentation of this file.
00001 //==- ProgramPoint.h - Program Points for Path-Sensitive Analysis --*- C++ -*-//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 //  This file defines the interface ProgramPoint, which identifies a
00011 //  distinct location in a function.
00012 //
00013 //===----------------------------------------------------------------------===//
00014 
00015 #ifndef LLVM_CLANG_ANALYSIS_PROGRAM_POINT
00016 #define LLVM_CLANG_ANALYSIS_PROGRAM_POINT
00017 
00018 #include "clang/Analysis/AnalysisContext.h"
00019 #include "clang/Analysis/CFG.h"
00020 #include "llvm/Support/DataTypes.h"
00021 #include "llvm/ADT/DenseMap.h"
00022 #include "llvm/ADT/PointerIntPair.h"
00023 #include "llvm/ADT/FoldingSet.h"
00024 #include "llvm/Support/Casting.h"
00025 #include "llvm/ADT/StringRef.h"
00026 #include <cassert>
00027 #include <utility>
00028 #include <string>
00029 
00030 namespace clang {
00031 
00032 class AnalysisDeclContext;
00033 class FunctionDecl;
00034 class LocationContext;
00035 class ProgramPointTag;
00036   
00037 class ProgramPoint {
00038 public:
00039   enum Kind { BlockEdgeKind,
00040               BlockEntranceKind,
00041               BlockExitKind,
00042               PreStmtKind,
00043               PreStmtPurgeDeadSymbolsKind,
00044               PostStmtPurgeDeadSymbolsKind,
00045               PostStmtKind,
00046               PreLoadKind,
00047               PostLoadKind,
00048               PreStoreKind,
00049               PostStoreKind,
00050               PostConditionKind,
00051               PostLValueKind,
00052               PostInitializerKind,
00053               CallEnterKind,
00054               CallExitBeginKind,
00055               CallExitEndKind,
00056               MinPostStmtKind = PostStmtKind,
00057               MaxPostStmtKind = CallExitEndKind,
00058               EpsilonKind};
00059 
00060 private:
00061   llvm::PointerIntPair<const void *, 2, unsigned> Data1;
00062   llvm::PointerIntPair<const void *, 2, unsigned> Data2;
00063 
00064   // The LocationContext could be NULL to allow ProgramPoint to be used in
00065   // context insensitive analysis.
00066   llvm::PointerIntPair<const LocationContext *, 2, unsigned> L;
00067 
00068   const ProgramPointTag *Tag;
00069 
00070   ProgramPoint();
00071   
00072 protected:
00073   ProgramPoint(const void *P,
00074                Kind k,
00075                const LocationContext *l,
00076                const ProgramPointTag *tag = 0)
00077     : Data1(P, ((unsigned) k) & 0x3),
00078       Data2(0, (((unsigned) k) >> 2) & 0x3),
00079       L(l, (((unsigned) k) >> 4) & 0x3),
00080       Tag(tag) {
00081         assert(getKind() == k);
00082         assert(getLocationContext() == l);
00083         assert(getData1() == P);
00084       }
00085         
00086   ProgramPoint(const void *P1,
00087                const void *P2,
00088                Kind k,
00089                const LocationContext *l,
00090                const ProgramPointTag *tag = 0)
00091     : Data1(P1, ((unsigned) k) & 0x3),
00092       Data2(P2, (((unsigned) k) >> 2) & 0x3),
00093       L(l, (((unsigned) k) >> 4) & 0x3),
00094       Tag(tag) {}
00095 
00096 protected:
00097   const void *getData1() const { return Data1.getPointer(); }
00098   const void *getData2() const { return Data2.getPointer(); }
00099   void setData2(const void *d) { Data2.setPointer(d); }
00100 
00101 public:
00102   /// Create a new ProgramPoint object that is the same as the original
00103   /// except for using the specified tag value.
00104   ProgramPoint withTag(const ProgramPointTag *tag) const {
00105     return ProgramPoint(getData1(), getData2(), getKind(),
00106                         getLocationContext(), tag);
00107   }
00108 
00109   Kind getKind() const {
00110     unsigned x = L.getInt();
00111     x <<= 2;
00112     x |= Data2.getInt();
00113     x <<= 2;
00114     x |= Data1.getInt();
00115     return (Kind) x;
00116   }
00117 
00118   /// \brief Is this a program point corresponding to purge/removal of dead
00119   /// symbols and bindings.
00120   bool isPurgeKind() {
00121     Kind K = getKind();
00122     return (K == PostStmtPurgeDeadSymbolsKind ||
00123             K == PreStmtPurgeDeadSymbolsKind);
00124   }
00125 
00126   const ProgramPointTag *getTag() const { return Tag; }
00127 
00128   const LocationContext *getLocationContext() const {
00129     return L.getPointer();
00130   }
00131 
00132   // For use with DenseMap.  This hash is probably slow.
00133   unsigned getHashValue() const {
00134     llvm::FoldingSetNodeID ID;
00135     Profile(ID);
00136     return ID.ComputeHash();
00137   }
00138 
00139   static bool classof(const ProgramPoint*) { return true; }
00140 
00141   bool operator==(const ProgramPoint & RHS) const {
00142     return Data1 == RHS.Data1 &&
00143            Data2 == RHS.Data2 &&
00144            L == RHS.L &&
00145            Tag == RHS.Tag;
00146   }
00147 
00148   bool operator!=(const ProgramPoint &RHS) const {
00149     return Data1 != RHS.Data1 ||
00150            Data2 != RHS.Data2 ||
00151            L != RHS.L ||
00152            Tag != RHS.Tag;
00153   }
00154 
00155   void Profile(llvm::FoldingSetNodeID& ID) const {
00156     ID.AddInteger((unsigned) getKind());
00157     ID.AddPointer(getData1());
00158     ID.AddPointer(getData2());
00159     ID.AddPointer(getLocationContext());
00160     ID.AddPointer(Tag);
00161   }
00162 
00163   static ProgramPoint getProgramPoint(const Stmt *S, ProgramPoint::Kind K,
00164                                       const LocationContext *LC,
00165                                       const ProgramPointTag *tag);
00166 };
00167 
00168 class BlockEntrance : public ProgramPoint {
00169 public:
00170   BlockEntrance(const CFGBlock *B, const LocationContext *L,
00171                 const ProgramPointTag *tag = 0)
00172     : ProgramPoint(B, BlockEntranceKind, L, tag) {    
00173     assert(B && "BlockEntrance requires non-null block");
00174   }
00175 
00176   const CFGBlock *getBlock() const {
00177     return reinterpret_cast<const CFGBlock*>(getData1());
00178   }
00179 
00180   const CFGElement getFirstElement() const {
00181     const CFGBlock *B = getBlock();
00182     return B->empty() ? CFGElement() : B->front();
00183   }
00184   
00185   static bool classof(const ProgramPoint* Location) {
00186     return Location->getKind() == BlockEntranceKind;
00187   }
00188 };
00189 
00190 class BlockExit : public ProgramPoint {
00191 public:
00192   BlockExit(const CFGBlock *B, const LocationContext *L)
00193     : ProgramPoint(B, BlockExitKind, L) {}
00194 
00195   const CFGBlock *getBlock() const {
00196     return reinterpret_cast<const CFGBlock*>(getData1());
00197   }
00198 
00199   const Stmt *getTerminator() const {
00200     return getBlock()->getTerminator();
00201   }
00202 
00203   static bool classof(const ProgramPoint* Location) {
00204     return Location->getKind() == BlockExitKind;
00205   }
00206 };
00207 
00208 class StmtPoint : public ProgramPoint {
00209 public:
00210   StmtPoint(const Stmt *S, const void *p2, Kind k, const LocationContext *L,
00211             const ProgramPointTag *tag)
00212     : ProgramPoint(S, p2, k, L, tag) {}
00213 
00214   const Stmt *getStmt() const { return (const Stmt*) getData1(); }
00215 
00216   template <typename T>
00217   const T* getStmtAs() const { return llvm::dyn_cast<T>(getStmt()); }
00218 
00219   static bool classof(const ProgramPoint* Location) {
00220     unsigned k = Location->getKind();
00221     return k >= PreStmtKind && k <= MaxPostStmtKind;
00222   }
00223 };
00224 
00225 
00226 class PreStmt : public StmtPoint {
00227 public:
00228   PreStmt(const Stmt *S, const LocationContext *L, const ProgramPointTag *tag,
00229           const Stmt *SubStmt = 0)
00230     : StmtPoint(S, SubStmt, PreStmtKind, L, tag) {}
00231 
00232   const Stmt *getSubStmt() const { return (const Stmt*) getData2(); }
00233 
00234   static bool classof(const ProgramPoint* Location) {
00235     return Location->getKind() == PreStmtKind;
00236   }
00237 };
00238 
00239 class PostStmt : public StmtPoint {
00240 protected:
00241   PostStmt(const Stmt *S, const void *data, Kind k, const LocationContext *L,
00242            const ProgramPointTag *tag = 0)
00243     : StmtPoint(S, data, k, L, tag) {}
00244 
00245 public:
00246   explicit PostStmt(const Stmt *S, Kind k, 
00247                     const LocationContext *L, const ProgramPointTag *tag = 0)
00248     : StmtPoint(S, NULL, k, L, tag) {}
00249 
00250   explicit PostStmt(const Stmt *S, const LocationContext *L,
00251                     const ProgramPointTag *tag = 0)
00252     : StmtPoint(S, NULL, PostStmtKind, L, tag) {}
00253 
00254   static bool classof(const ProgramPoint* Location) {
00255     unsigned k = Location->getKind();
00256     return k >= MinPostStmtKind && k <= MaxPostStmtKind;
00257   }
00258 };
00259 
00260 // PostCondition represents the post program point of a branch condition.
00261 class PostCondition : public PostStmt {
00262 public:
00263   PostCondition(const Stmt *S, const LocationContext *L,
00264                 const ProgramPointTag *tag = 0)
00265     : PostStmt(S, PostConditionKind, L, tag) {}
00266 
00267   static bool classof(const ProgramPoint* Location) {
00268     return Location->getKind() == PostConditionKind;
00269   }
00270 };
00271 
00272 class LocationCheck : public StmtPoint {
00273 protected:
00274   LocationCheck(const Stmt *S, const LocationContext *L,
00275                 ProgramPoint::Kind K, const ProgramPointTag *tag)
00276     : StmtPoint(S, NULL, K, L, tag) {}
00277     
00278   static bool classof(const ProgramPoint *location) {
00279     unsigned k = location->getKind();
00280     return k == PreLoadKind || k == PreStoreKind;
00281   }
00282 };
00283   
00284 class PreLoad : public LocationCheck {
00285 public:
00286   PreLoad(const Stmt *S, const LocationContext *L,
00287           const ProgramPointTag *tag = 0)
00288     : LocationCheck(S, L, PreLoadKind, tag) {}
00289   
00290   static bool classof(const ProgramPoint *location) {
00291     return location->getKind() == PreLoadKind;
00292   }
00293 };
00294 
00295 class PreStore : public LocationCheck {
00296 public:
00297   PreStore(const Stmt *S, const LocationContext *L,
00298            const ProgramPointTag *tag = 0)
00299   : LocationCheck(S, L, PreStoreKind, tag) {}
00300   
00301   static bool classof(const ProgramPoint *location) {
00302     return location->getKind() == PreStoreKind;
00303   }
00304 };
00305 
00306 class PostLoad : public PostStmt {
00307 public:
00308   PostLoad(const Stmt *S, const LocationContext *L,
00309            const ProgramPointTag *tag = 0)
00310     : PostStmt(S, PostLoadKind, L, tag) {}
00311 
00312   static bool classof(const ProgramPoint* Location) {
00313     return Location->getKind() == PostLoadKind;
00314   }
00315 };
00316 
00317 /// \class Represents a program point after a store evaluation.
00318 class PostStore : public PostStmt {
00319 public:
00320   /// Construct the post store point.
00321   /// \param Loc can be used to store the information about the location 
00322   /// used in the form it was uttered in the code.
00323   PostStore(const Stmt *S, const LocationContext *L, const void *Loc,
00324             const ProgramPointTag *tag = 0)
00325     : PostStmt(S, PostStoreKind, L, tag) {
00326     assert(getData2() == 0);
00327     setData2(Loc);
00328   }
00329 
00330   static bool classof(const ProgramPoint* Location) {
00331     return Location->getKind() == PostStoreKind;
00332   }
00333   
00334   /// \brief Returns the information about the location used in the store,
00335   /// how it was uttered in the code.
00336   const void *getLocationValue() const {
00337     return getData2();
00338   }
00339 
00340 };
00341 
00342 class PostLValue : public PostStmt {
00343 public:
00344   PostLValue(const Stmt *S, const LocationContext *L,
00345              const ProgramPointTag *tag = 0)
00346     : PostStmt(S, PostLValueKind, L, tag) {}
00347 
00348   static bool classof(const ProgramPoint* Location) {
00349     return Location->getKind() == PostLValueKind;
00350   }
00351 };
00352 
00353 /// \class Represents a point after we ran remove dead bindings BEFORE
00354 /// processing the given statement.
00355 class PreStmtPurgeDeadSymbols : public StmtPoint {
00356 public:
00357   PreStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L,
00358                        const ProgramPointTag *tag = 0)
00359     : StmtPoint(S, 0, PreStmtPurgeDeadSymbolsKind, L, tag) { }
00360 
00361   static bool classof(const ProgramPoint* Location) {
00362     return Location->getKind() == PreStmtPurgeDeadSymbolsKind;
00363   }
00364 };
00365 
00366 /// \class Represents a point after we ran remove dead bindings AFTER
00367 /// processing the  given statement.
00368 class PostStmtPurgeDeadSymbols : public StmtPoint {
00369 public:
00370   PostStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L,
00371                        const ProgramPointTag *tag = 0)
00372     : StmtPoint(S, 0, PostStmtPurgeDeadSymbolsKind, L, tag) { }
00373 
00374   static bool classof(const ProgramPoint* Location) {
00375     return Location->getKind() == PostStmtPurgeDeadSymbolsKind;
00376   }
00377 };
00378 
00379 class BlockEdge : public ProgramPoint {
00380 public:
00381   BlockEdge(const CFGBlock *B1, const CFGBlock *B2, const LocationContext *L)
00382     : ProgramPoint(B1, B2, BlockEdgeKind, L) {
00383     assert(B1 && "BlockEdge: source block must be non-null");
00384     assert(B2 && "BlockEdge: destination block must be non-null");    
00385   }
00386 
00387   const CFGBlock *getSrc() const {
00388     return static_cast<const CFGBlock*>(getData1());
00389   }
00390 
00391   const CFGBlock *getDst() const {
00392     return static_cast<const CFGBlock*>(getData2());
00393   }
00394 
00395   static bool classof(const ProgramPoint* Location) {
00396     return Location->getKind() == BlockEdgeKind;
00397   }
00398 };
00399 
00400 class PostInitializer : public ProgramPoint {
00401 public:
00402   PostInitializer(const CXXCtorInitializer *I, 
00403                   const LocationContext *L)
00404     : ProgramPoint(I, PostInitializerKind, L) {}
00405 
00406   static bool classof(const ProgramPoint *Location) {
00407     return Location->getKind() == PostInitializerKind;
00408   }
00409 };
00410 
00411 /// \class Represents a point when we begin processing an inlined call.
00412 class CallEnter : public StmtPoint {
00413 public:
00414   CallEnter(const Stmt *stmt, const StackFrameContext *calleeCtx, 
00415             const LocationContext *callerCtx)
00416     : StmtPoint(stmt, calleeCtx, CallEnterKind, callerCtx, 0) {}
00417 
00418   const Stmt *getCallExpr() const {
00419     return static_cast<const Stmt *>(getData1());
00420   }
00421 
00422   const StackFrameContext *getCalleeContext() const {
00423     return static_cast<const StackFrameContext *>(getData2());
00424   }
00425 
00426   static bool classof(const ProgramPoint *Location) {
00427     return Location->getKind() == CallEnterKind;
00428   }
00429 };
00430 
00431 /// \class Represents a point when we start the call exit sequence (for
00432 /// inlined call).
00433 ///
00434 /// The call exit is simulated with a sequence of nodes, which occur between
00435 /// CallExitBegin and CallExitEnd. The following operations occur between the
00436 /// two program points:
00437 /// - CallExitBegin
00438 /// - Bind the return value
00439 /// - Run Remove dead bindings (to clean up the dead symbols from the callee).
00440 /// - CallExitEnd
00441 class CallExitBegin : public StmtPoint {
00442 public:
00443   // CallExitBegin uses the callee's location context.
00444   CallExitBegin(const Stmt *S, const LocationContext *L)
00445     : StmtPoint(S, 0, CallExitBeginKind, L, 0) {}
00446 
00447   static bool classof(const ProgramPoint *Location) {
00448     return Location->getKind() == CallExitBeginKind;
00449   }
00450 };
00451 
00452 /// \class Represents a point when we finish the call exit sequence (for
00453 /// inlined call).
00454 /// \sa CallExitBegin
00455 class CallExitEnd : public StmtPoint {
00456 public:
00457   // CallExitEnd uses the caller's location context.
00458   CallExitEnd(const Stmt *S, const LocationContext *L)
00459     : StmtPoint(S, 0, CallExitEndKind, L, 0) {}
00460 
00461   static bool classof(const ProgramPoint *Location) {
00462     return Location->getKind() == CallExitEndKind;
00463   }
00464 };
00465 
00466 /// This is a meta program point, which should be skipped by all the diagnostic
00467 /// reasoning etc.
00468 class EpsilonPoint : public ProgramPoint {
00469 public:
00470   EpsilonPoint(const LocationContext *L, const void *Data1,
00471                const void *Data2 = 0, const ProgramPointTag *tag = 0)
00472     : ProgramPoint(Data1, Data2, EpsilonKind, L, tag) {}
00473 
00474   const void *getData() const { return getData1(); }
00475 
00476   static bool classof(const ProgramPoint* Location) {
00477     return Location->getKind() == EpsilonKind;
00478   }
00479 };
00480 
00481 /// ProgramPoints can be "tagged" as representing points specific to a given
00482 /// analysis entity.  Tags are abstract annotations, with an associated
00483 /// description and potentially other information.
00484 class ProgramPointTag {
00485 public:
00486   ProgramPointTag(void *tagKind = 0) : TagKind(tagKind) {}
00487   virtual ~ProgramPointTag();
00488   virtual StringRef getTagDescription() const = 0;    
00489 
00490 protected:
00491   /// Used to implement 'classof' in subclasses.
00492   const void *getTagKind() { return TagKind; }
00493   
00494 private:
00495   const void *TagKind;
00496 };
00497   
00498 class SimpleProgramPointTag : public ProgramPointTag {
00499   std::string desc;
00500 public:
00501   SimpleProgramPointTag(StringRef description);
00502   StringRef getTagDescription() const;
00503 };
00504 
00505 } // end namespace clang
00506 
00507 
00508 namespace llvm { // Traits specialization for DenseMap
00509 
00510 template <> struct DenseMapInfo<clang::ProgramPoint> {
00511 
00512 static inline clang::ProgramPoint getEmptyKey() {
00513   uintptr_t x =
00514    reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getEmptyKey()) & ~0x7;
00515   return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), 0);
00516 }
00517 
00518 static inline clang::ProgramPoint getTombstoneKey() {
00519   uintptr_t x =
00520    reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getTombstoneKey()) & ~0x7;
00521   return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), 0);
00522 }
00523 
00524 static unsigned getHashValue(const clang::ProgramPoint &Loc) {
00525   return Loc.getHashValue();
00526 }
00527 
00528 static bool isEqual(const clang::ProgramPoint &L,
00529                     const clang::ProgramPoint &R) {
00530   return L == R;
00531 }
00532 
00533 };
00534   
00535 template <>
00536 struct isPodLike<clang::ProgramPoint> { static const bool value = true; };
00537 
00538 } // end namespace llvm
00539 
00540 #endif