1 //ProgramStateTrait.h - Partial implementations of ProgramStateTrait -*- 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 partial implementations of template specializations of 11 // the class ProgramStateTrait<>. ProgramStateTrait<> is used by ProgramState 12 // to implement set/get methods for manipulating a ProgramState's 13 // generic data map. 14 // 15 //===----------------------------------------------------------------------===// 16 17 18 #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATETRAIT_H 19 #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATETRAIT_H 20 21 #include "llvm/Support/Allocator.h" 22 #include "llvm/Support/DataTypes.h" 23 24 namespace llvm { 25 template <typename K, typename D, typename I> class ImmutableMap; 26 template <typename K, typename I> class ImmutableSet; 27 template <typename T> class ImmutableList; 28 template <typename T> class ImmutableListImpl; 29 } 30 31 namespace clang { 32 33 namespace ento { 34 template <typename T> struct ProgramStatePartialTrait; 35 36 /// Declares a program state trait for type \p Type called \p Name, and 37 /// introduce a typedef named \c NameTy. 38 /// The macro should not be used inside namespaces, or for traits that must 39 /// be accessible from more than one translation unit. 40 #define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type) \ 41 namespace { \ 42 class Name {}; \ 43 typedef Type Name ## Ty; \ 44 } \ 45 namespace clang { \ 46 namespace ento { \ 47 template <> \ 48 struct ProgramStateTrait<Name> \ 49 : public ProgramStatePartialTrait<Name ## Ty> { \ 50 static void *GDMIndex() { static int Index; return &Index; } \ 51 }; \ 52 } \ 53 } 54 55 56 // Partial-specialization for ImmutableMap. 57 58 template <typename Key, typename Data, typename Info> 59 struct ProgramStatePartialTrait< llvm::ImmutableMap<Key,Data,Info> > { 60 typedef llvm::ImmutableMap<Key,Data,Info> data_type; 61 typedef typename data_type::Factory& context_type; 62 typedef Key key_type; 63 typedef Data value_type; 64 typedef const value_type* lookup_type; 65 66 static inline data_type MakeData(void *const* p) { 67 return p ? data_type((typename data_type::TreeTy*) *p) 68 : data_type(nullptr); 69 } 70 static inline void *MakeVoidPtr(data_type B) { 71 return B.getRoot(); 72 } 73 static lookup_type Lookup(data_type B, key_type K) { 74 return B.lookup(K); 75 } 76 static data_type Set(data_type B, key_type K, value_type E,context_type F){ 77 return F.add(B, K, E); 78 } 79 80 static data_type Remove(data_type B, key_type K, context_type F) { 81 return F.remove(B, K); 82 } 83 84 static inline context_type MakeContext(void *p) { 85 return *((typename data_type::Factory*) p); 86 } 87 88 static void *CreateContext(llvm::BumpPtrAllocator& Alloc) { 89 return new typename data_type::Factory(Alloc); 90 } 91 92 static void DeleteContext(void *Ctx) { 93 delete (typename data_type::Factory*) Ctx; 94 } 95 }; 96 97 /// Helper for registering a map trait. 98 /// 99 /// If the map type were written directly in the invocation of 100 /// REGISTER_TRAIT_WITH_PROGRAMSTATE, the comma in the template arguments 101 /// would be treated as a macro argument separator, which is wrong. 102 /// This allows the user to specify a map type in a way that the preprocessor 103 /// can deal with. 104 #define CLANG_ENTO_PROGRAMSTATE_MAP(Key, Value) llvm::ImmutableMap<Key, Value> 105 106 107 // Partial-specialization for ImmutableSet. 108 109 template <typename Key, typename Info> 110 struct ProgramStatePartialTrait< llvm::ImmutableSet<Key,Info> > { 111 typedef llvm::ImmutableSet<Key,Info> data_type; 112 typedef typename data_type::Factory& context_type; 113 typedef Key key_type; 114 115 static inline data_type MakeData(void *const* p) { 116 return p ? data_type((typename data_type::TreeTy*) *p) 117 : data_type(nullptr); 118 } 119 120 static inline void *MakeVoidPtr(data_type B) { 121 return B.getRoot(); 122 } 123 124 static data_type Add(data_type B, key_type K, context_type F) { 125 return F.add(B, K); 126 } 127 128 static data_type Remove(data_type B, key_type K, context_type F) { 129 return F.remove(B, K); 130 } 131 132 static bool Contains(data_type B, key_type K) { 133 return B.contains(K); 134 } 135 136 static inline context_type MakeContext(void *p) { 137 return *((typename data_type::Factory*) p); 138 } 139 140 static void *CreateContext(llvm::BumpPtrAllocator& Alloc) { 141 return new typename data_type::Factory(Alloc); 142 } 143 144 static void DeleteContext(void *Ctx) { 145 delete (typename data_type::Factory*) Ctx; 146 } 147 }; 148 149 150 // Partial-specialization for ImmutableList. 151 152 template <typename T> 153 struct ProgramStatePartialTrait< llvm::ImmutableList<T> > { 154 typedef llvm::ImmutableList<T> data_type; 155 typedef T key_type; 156 typedef typename data_type::Factory& context_type; 157 158 static data_type Add(data_type L, key_type K, context_type F) { 159 return F.add(K, L); 160 } 161 162 static bool Contains(data_type L, key_type K) { 163 return L.contains(K); 164 } 165 166 static inline data_type MakeData(void *const* p) { 167 return p ? data_type((const llvm::ImmutableListImpl<T>*) *p) 168 : data_type(nullptr); 169 } 170 171 static inline void *MakeVoidPtr(data_type D) { 172 return const_cast<llvm::ImmutableListImpl<T> *>(D.getInternalPointer()); 173 } 174 175 static inline context_type MakeContext(void *p) { 176 return *((typename data_type::Factory*) p); 177 } 178 179 static void *CreateContext(llvm::BumpPtrAllocator& Alloc) { 180 return new typename data_type::Factory(Alloc); 181 } 182 183 static void DeleteContext(void *Ctx) { 184 delete (typename data_type::Factory*) Ctx; 185 } 186 }; 187 188 189 // Partial specialization for bool. 190 template <> struct ProgramStatePartialTrait<bool> { 191 typedef bool data_type; 192 193 static inline data_type MakeData(void *const* p) { 194 return p ? (data_type) (uintptr_t) *p 195 : data_type(); 196 } 197 static inline void *MakeVoidPtr(data_type d) { 198 return (void*) (uintptr_t) d; 199 } 200 }; 201 202 // Partial specialization for unsigned. 203 template <> struct ProgramStatePartialTrait<unsigned> { 204 typedef unsigned data_type; 205 206 static inline data_type MakeData(void *const* p) { 207 return p ? (data_type) (uintptr_t) *p 208 : data_type(); 209 } 210 static inline void *MakeVoidPtr(data_type d) { 211 return (void*) (uintptr_t) d; 212 } 213 }; 214 215 // Partial specialization for void*. 216 template <> struct ProgramStatePartialTrait<void*> { 217 typedef void *data_type; 218 219 static inline data_type MakeData(void *const* p) { 220 return p ? *p 221 : data_type(); 222 } 223 static inline void *MakeVoidPtr(data_type d) { 224 return d; 225 } 226 }; 227 228 // Partial specialization for const void *. 229 template <> struct ProgramStatePartialTrait<const void *> { 230 typedef const void *data_type; 231 232 static inline data_type MakeData(void * const *p) { 233 return p ? *p : data_type(); 234 } 235 236 static inline void *MakeVoidPtr(data_type d) { 237 return const_cast<void *>(d); 238 } 239 }; 240 241 } // end ento namespace 242 243 } // end clang namespace 244 245 #endif 246