Home | History | Annotate | Line # | Download | only in PathSensitive
      1 //ProgramStateTrait.h - Partial implementations of ProgramStateTrait -*- C++ -*-
      2 //
      3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4 // See https://llvm.org/LICENSE.txt for license information.
      5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 //
      9 //  This file defines partial implementations of template specializations of
     10 //  the class ProgramStateTrait<>.  ProgramStateTrait<> is used by ProgramState
     11 //  to implement set/get methods for manipulating a ProgramState's
     12 //  generic data map.
     13 //
     14 //===----------------------------------------------------------------------===//
     15 
     16 #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATETRAIT_H
     17 #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATETRAIT_H
     18 
     19 #include "llvm/ADT/ImmutableList.h"
     20 #include "llvm/ADT/ImmutableMap.h"
     21 #include "llvm/ADT/ImmutableSet.h"
     22 #include "llvm/Support/Allocator.h"
     23 #include <cstdint>
     24 
     25 namespace clang {
     26 namespace ento {
     27 
     28   template <typename T> struct ProgramStatePartialTrait;
     29 
     30   /// Declares a program state trait for type \p Type called \p Name, and
     31   /// introduce a type named \c NameTy.
     32   /// The macro should not be used inside namespaces.
     33   #define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type) \
     34     namespace { \
     35       class Name {}; \
     36       using Name ## Ty = Type; \
     37     } \
     38     namespace clang { \
     39     namespace ento { \
     40       template <> \
     41       struct ProgramStateTrait<Name> \
     42         : public ProgramStatePartialTrait<Name ## Ty> { \
     43         static void *GDMIndex() { static int Index; return &Index; } \
     44       }; \
     45     } \
     46     }
     47 
     48   /// Declares a factory for objects of type \p Type in the program state
     49   /// manager. The type must provide a ::Factory sub-class. Commonly used for
     50   /// ImmutableMap, ImmutableSet, ImmutableList. The macro should not be used
     51   /// inside namespaces.
     52   #define REGISTER_FACTORY_WITH_PROGRAMSTATE(Type) \
     53     namespace clang { \
     54     namespace ento { \
     55       template <> \
     56       struct ProgramStateTrait<Type> \
     57         : public ProgramStatePartialTrait<Type> { \
     58         static void *GDMIndex() { static int Index; return &Index; } \
     59       }; \
     60     } \
     61     }
     62 
     63   /// Helper for registering a map trait.
     64   ///
     65   /// If the map type were written directly in the invocation of
     66   /// REGISTER_TRAIT_WITH_PROGRAMSTATE, the comma in the template arguments
     67   /// would be treated as a macro argument separator, which is wrong.
     68   /// This allows the user to specify a map type in a way that the preprocessor
     69   /// can deal with.
     70   #define CLANG_ENTO_PROGRAMSTATE_MAP(Key, Value) llvm::ImmutableMap<Key, Value>
     71 
     72   /// Declares an immutable map of type \p NameTy, suitable for placement into
     73   /// the ProgramState. This is implementing using llvm::ImmutableMap.
     74   ///
     75   /// \code
     76   /// State = State->set<Name>(K, V);
     77   /// const Value *V = State->get<Name>(K); // Returns NULL if not in the map.
     78   /// State = State->remove<Name>(K);
     79   /// NameTy Map = State->get<Name>();
     80   /// \endcode
     81   ///
     82   /// The macro should not be used inside namespaces, or for traits that must
     83   /// be accessible from more than one translation unit.
     84   #define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value) \
     85     REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, \
     86                                      CLANG_ENTO_PROGRAMSTATE_MAP(Key, Value))
     87 
     88   /// Declares an immutable map type \p Name and registers the factory
     89   /// for such maps in the program state, but does not add the map itself
     90   /// to the program state. Useful for managing lifetime of maps that are used
     91   /// as elements of other program state data structures.
     92   #define REGISTER_MAP_FACTORY_WITH_PROGRAMSTATE(Name, Key, Value) \
     93     using Name = llvm::ImmutableMap<Key, Value>; \
     94     REGISTER_FACTORY_WITH_PROGRAMSTATE(Name)
     95 
     96 
     97   /// Declares an immutable set of type \p NameTy, suitable for placement into
     98   /// the ProgramState. This is implementing using llvm::ImmutableSet.
     99   ///
    100   /// \code
    101   /// State = State->add<Name>(E);
    102   /// State = State->remove<Name>(E);
    103   /// bool Present = State->contains<Name>(E);
    104   /// NameTy Set = State->get<Name>();
    105   /// \endcode
    106   ///
    107   /// The macro should not be used inside namespaces, or for traits that must
    108   /// be accessible from more than one translation unit.
    109   #define REGISTER_SET_WITH_PROGRAMSTATE(Name, Elem) \
    110     REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, llvm::ImmutableSet<Elem>)
    111 
    112   /// Declares an immutable set type \p Name and registers the factory
    113   /// for such sets in the program state, but does not add the set itself
    114   /// to the program state. Useful for managing lifetime of sets that are used
    115   /// as elements of other program state data structures.
    116   #define REGISTER_SET_FACTORY_WITH_PROGRAMSTATE(Name, Elem) \
    117     using Name = llvm::ImmutableSet<Elem>; \
    118     REGISTER_FACTORY_WITH_PROGRAMSTATE(Name)
    119 
    120 
    121   /// Declares an immutable list type \p NameTy, suitable for placement into
    122   /// the ProgramState. This is implementing using llvm::ImmutableList.
    123   ///
    124   /// \code
    125   /// State = State->add<Name>(E); // Adds to the /end/ of the list.
    126   /// bool Present = State->contains<Name>(E);
    127   /// NameTy List = State->get<Name>();
    128   /// \endcode
    129   ///
    130   /// The macro should not be used inside namespaces, or for traits that must
    131   /// be accessible from more than one translation unit.
    132   #define REGISTER_LIST_WITH_PROGRAMSTATE(Name, Elem) \
    133     REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, llvm::ImmutableList<Elem>)
    134 
    135   /// Declares an immutable list of type \p Name and registers the factory
    136   /// for such lists in the program state, but does not add the list itself
    137   /// to the program state. Useful for managing lifetime of lists that are used
    138   /// as elements of other program state data structures.
    139   #define REGISTER_LIST_FACTORY_WITH_PROGRAMSTATE(Name, Elem) \
    140     using Name = llvm::ImmutableList<Elem>; \
    141     REGISTER_FACTORY_WITH_PROGRAMSTATE(Name)
    142 
    143 
    144   // Partial-specialization for ImmutableMap.
    145   template <typename Key, typename Data, typename Info>
    146   struct ProgramStatePartialTrait<llvm::ImmutableMap<Key, Data, Info>> {
    147     using data_type = llvm::ImmutableMap<Key, Data, Info>;
    148     using context_type = typename data_type::Factory &;
    149     using key_type = Key;
    150     using value_type = Data;
    151     using lookup_type = const value_type *;
    152 
    153     static data_type MakeData(void *const *p) {
    154       return p ? data_type((typename data_type::TreeTy *) *p)
    155                : data_type(nullptr);
    156     }
    157 
    158     static void *MakeVoidPtr(data_type B) {
    159       return B.getRoot();
    160     }
    161 
    162     static lookup_type Lookup(data_type B, key_type K) {
    163       return B.lookup(K);
    164     }
    165 
    166     static data_type Set(data_type B, key_type K, value_type E,
    167                          context_type F) {
    168       return F.add(B, K, E);
    169     }
    170 
    171     static data_type Remove(data_type B, key_type K, context_type F) {
    172       return F.remove(B, K);
    173     }
    174 
    175     static bool Contains(data_type B, key_type K) {
    176       return B.contains(K);
    177     }
    178 
    179     static context_type MakeContext(void *p) {
    180       return *((typename data_type::Factory *) p);
    181     }
    182 
    183     static void *CreateContext(llvm::BumpPtrAllocator& Alloc) {
    184       return new typename data_type::Factory(Alloc);
    185     }
    186 
    187     static void DeleteContext(void *Ctx) {
    188       delete (typename data_type::Factory *) Ctx;
    189     }
    190   };
    191 
    192   // Partial-specialization for ImmutableSet.
    193   template <typename Key, typename Info>
    194   struct ProgramStatePartialTrait<llvm::ImmutableSet<Key, Info>> {
    195     using data_type = llvm::ImmutableSet<Key, Info>;
    196     using context_type = typename data_type::Factory &;
    197     using key_type = Key;
    198 
    199     static data_type MakeData(void *const *p) {
    200       return p ? data_type((typename data_type::TreeTy *) *p)
    201                : data_type(nullptr);
    202     }
    203 
    204     static void *MakeVoidPtr(data_type B) {
    205       return B.getRoot();
    206     }
    207 
    208     static data_type Add(data_type B, key_type K, context_type F) {
    209       return F.add(B, K);
    210     }
    211 
    212     static data_type Remove(data_type B, key_type K, context_type F) {
    213       return F.remove(B, K);
    214     }
    215 
    216     static bool Contains(data_type B, key_type K) {
    217       return B.contains(K);
    218     }
    219 
    220     static context_type MakeContext(void *p) {
    221       return *((typename data_type::Factory *) p);
    222     }
    223 
    224     static void *CreateContext(llvm::BumpPtrAllocator &Alloc) {
    225       return new typename data_type::Factory(Alloc);
    226     }
    227 
    228     static void DeleteContext(void *Ctx) {
    229       delete (typename data_type::Factory *) Ctx;
    230     }
    231   };
    232 
    233   // Partial-specialization for ImmutableList.
    234   template <typename T>
    235   struct ProgramStatePartialTrait<llvm::ImmutableList<T>> {
    236     using data_type = llvm::ImmutableList<T>;
    237     using key_type = T;
    238     using context_type = typename data_type::Factory &;
    239 
    240     static data_type Add(data_type L, key_type K, context_type F) {
    241       return F.add(K, L);
    242     }
    243 
    244     static bool Contains(data_type L, key_type K) {
    245       return L.contains(K);
    246     }
    247 
    248     static data_type MakeData(void *const *p) {
    249       return p ? data_type((const llvm::ImmutableListImpl<T> *) *p)
    250                : data_type(nullptr);
    251     }
    252 
    253     static void *MakeVoidPtr(data_type D) {
    254       return const_cast<llvm::ImmutableListImpl<T> *>(D.getInternalPointer());
    255     }
    256 
    257     static context_type MakeContext(void *p) {
    258       return *((typename data_type::Factory *) p);
    259     }
    260 
    261     static void *CreateContext(llvm::BumpPtrAllocator &Alloc) {
    262       return new typename data_type::Factory(Alloc);
    263     }
    264 
    265     static void DeleteContext(void *Ctx) {
    266       delete (typename data_type::Factory *) Ctx;
    267     }
    268   };
    269 
    270   // Partial specialization for bool.
    271   template <> struct ProgramStatePartialTrait<bool> {
    272     using data_type = bool;
    273 
    274     static data_type MakeData(void *const *p) {
    275       return p ? (data_type) (uintptr_t) *p
    276                : data_type();
    277     }
    278 
    279     static void *MakeVoidPtr(data_type d) {
    280       return (void *) (uintptr_t) d;
    281     }
    282   };
    283 
    284   // Partial specialization for unsigned.
    285   template <> struct ProgramStatePartialTrait<unsigned> {
    286     using data_type = unsigned;
    287 
    288     static data_type MakeData(void *const *p) {
    289       return p ? (data_type) (uintptr_t) *p
    290                : data_type();
    291     }
    292 
    293     static void *MakeVoidPtr(data_type d) {
    294       return (void *) (uintptr_t) d;
    295     }
    296   };
    297 
    298   // Partial specialization for void*.
    299   template <> struct ProgramStatePartialTrait<void *> {
    300     using data_type = void *;
    301 
    302     static data_type MakeData(void *const *p) {
    303       return p ? *p
    304                : data_type();
    305     }
    306 
    307     static void *MakeVoidPtr(data_type d) {
    308       return d;
    309     }
    310   };
    311 
    312   // Partial specialization for const void *.
    313   template <> struct ProgramStatePartialTrait<const void *> {
    314     using data_type = const void *;
    315 
    316     static data_type MakeData(void *const *p) {
    317       return p ? *p : data_type();
    318     }
    319 
    320     static void *MakeVoidPtr(data_type d) {
    321       return const_cast<void *>(d);
    322     }
    323   };
    324 
    325 } // namespace ento
    326 } // namespace clang
    327 
    328 #endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATETRAIT_H
    329