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