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