ProgramStateTrait.h revision 355940
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 25namespace clang { 26namespace 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