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