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 bool Contains(data_type B, key_type K) { 85 return B.contains(K); 86 } 87 88 static inline context_type MakeContext(void *p) { 89 return *((typename data_type::Factory*) p); 90 } 91 92 static void *CreateContext(llvm::BumpPtrAllocator& Alloc) { 93 return new typename data_type::Factory(Alloc); 94 } 95 96 static void DeleteContext(void *Ctx) { 97 delete (typename data_type::Factory*) Ctx; 98 } 99 }; 100 101 /// Helper for registering a map trait. 102 /// 103 /// If the map type were written directly in the invocation of 104 /// REGISTER_TRAIT_WITH_PROGRAMSTATE, the comma in the template arguments 105 /// would be treated as a macro argument separator, which is wrong. 106 /// This allows the user to specify a map type in a way that the preprocessor 107 /// can deal with. 108 #define CLANG_ENTO_PROGRAMSTATE_MAP(Key, Value) llvm::ImmutableMap<Key, Value> 109 110 111 // Partial-specialization for ImmutableSet. 112 113 template <typename Key, typename Info> 114 struct ProgramStatePartialTrait< llvm::ImmutableSet<Key,Info> > { 115 typedef llvm::ImmutableSet<Key,Info> data_type; 116 typedef typename data_type::Factory& context_type; 117 typedef Key key_type; 118 119 static inline data_type MakeData(void *const* p) { 120 return p ? data_type((typename data_type::TreeTy*) *p) 121 : data_type(nullptr); 122 } 123 124 static inline void *MakeVoidPtr(data_type B) { 125 return B.getRoot(); 126 } 127 128 static data_type Add(data_type B, key_type K, context_type F) { 129 return F.add(B, K); 130 } 131 132 static data_type Remove(data_type B, key_type K, context_type F) { 133 return F.remove(B, K); 134 } 135 136 static bool Contains(data_type B, key_type K) { 137 return B.contains(K); 138 } 139 140 static inline context_type MakeContext(void *p) { 141 return *((typename data_type::Factory*) p); 142 } 143 144 static void *CreateContext(llvm::BumpPtrAllocator& Alloc) { 145 return new typename data_type::Factory(Alloc); 146 } 147 148 static void DeleteContext(void *Ctx) { 149 delete (typename data_type::Factory*) Ctx; 150 } 151 }; 152 153 154 // Partial-specialization for ImmutableList. 155 156 template <typename T> 157 struct ProgramStatePartialTrait< llvm::ImmutableList<T> > { 158 typedef llvm::ImmutableList<T> data_type; 159 typedef T key_type; 160 typedef typename data_type::Factory& context_type; 161 162 static data_type Add(data_type L, key_type K, context_type F) { 163 return F.add(K, L); 164 } 165 166 static bool Contains(data_type L, key_type K) { 167 return L.contains(K); 168 } 169 170 static inline data_type MakeData(void *const* p) { 171 return p ? data_type((const llvm::ImmutableListImpl<T>*) *p) 172 : data_type(nullptr); 173 } 174 175 static inline void *MakeVoidPtr(data_type D) { 176 return const_cast<llvm::ImmutableListImpl<T> *>(D.getInternalPointer()); 177 } 178 179 static inline 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 193 // Partial specialization for bool. 194 template <> struct ProgramStatePartialTrait<bool> { 195 typedef bool data_type; 196 197 static inline data_type MakeData(void *const* p) { 198 return p ? (data_type) (uintptr_t) *p 199 : data_type(); 200 } 201 static inline void *MakeVoidPtr(data_type d) { 202 return (void*) (uintptr_t) d; 203 } 204 }; 205 206 // Partial specialization for unsigned. 207 template <> struct ProgramStatePartialTrait<unsigned> { 208 typedef unsigned data_type; 209 210 static inline data_type MakeData(void *const* p) { 211 return p ? (data_type) (uintptr_t) *p 212 : data_type(); 213 } 214 static inline void *MakeVoidPtr(data_type d) { 215 return (void*) (uintptr_t) d; 216 } 217 }; 218 219 // Partial specialization for void*. 220 template <> struct ProgramStatePartialTrait<void*> { 221 typedef void *data_type; 222 223 static inline data_type MakeData(void *const* p) { 224 return p ? *p 225 : data_type(); 226 } 227 static inline void *MakeVoidPtr(data_type d) { 228 return d; 229 } 230 }; 231 232 // Partial specialization for const void *. 233 template <> struct ProgramStatePartialTrait<const void *> { 234 typedef const void *data_type; 235 236 static inline data_type MakeData(void * const *p) { 237 return p ? *p : data_type(); 238 } 239 240 static inline void *MakeVoidPtr(data_type d) { 241 return const_cast<void *>(d); 242 } 243 }; 244 245 } // end ento namespace 246 247 } // end clang namespace 248 249 #endif 250