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