Imported Upstream version 1.64.0
[platform/upstream/boost.git] / boost / dll / detail / demangling / msvc.hpp
1 //  Copyright 2016 Klemens Morgenstern
2 //
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt
5 // or copy at http://www.boost.org/LICENSE_1_0.txt)
6
7 #ifndef BOOST_DLL_DETAIL_DEMANGLING_MSVC_HPP_
8 #define BOOST_DLL_DETAIL_DEMANGLING_MSVC_HPP_
9
10 #include <boost/dll/detail/demangling/mangled_storage_base.hpp>
11 #include <iterator>
12 #include <algorithm>
13 #include <boost/type_traits/is_const.hpp>
14 #include <boost/type_traits/is_volatile.hpp>
15 #include <boost/type_traits/is_lvalue_reference.hpp>
16 #include <boost/type_traits/is_rvalue_reference.hpp>
17 #include <boost/type_traits/function_traits.hpp>
18 #include <boost/type_traits/remove_reference.hpp>
19
20 #include <boost/spirit/home/x3.hpp>
21
22 namespace boost { namespace dll { namespace detail {
23
24 class mangled_storage_impl  : public mangled_storage_base
25 {
26     template<typename T>
27     struct dummy {};
28
29     template<typename Return, typename ...Args>
30     std::vector<std::string> get_func_params(dummy<Return(Args...)>) const
31     {
32         return {get_name<Args>()...};
33     }
34     template<typename Return, typename ...Args>
35     std::string get_return_type(dummy<Return(Args...)>) const
36     {
37         return get_name<Return>();
38     }
39     //function to remove preceeding 'class ' or 'struct ' if the are given in this format.
40
41     inline static void trim_typename(std::string & val);
42 public:
43     using ctor_sym = std::string;
44     using dtor_sym = std::string;
45
46     using mangled_storage_base::mangled_storage_base;
47
48     template<typename T>
49     std::string get_variable(const std::string &name) const;
50
51     template<typename Func>
52     std::string get_function(const std::string &name) const;
53
54     template<typename Class, typename Func>
55     std::string get_mem_fn(const std::string &name) const;
56
57     template<typename Signature>
58     ctor_sym get_constructor() const;
59
60     template<typename Class>
61     dtor_sym get_destructor() const;
62
63     template<typename T> //overload, does not need to virtual.
64     std::string get_name() const
65     {
66         auto nm = mangled_storage_base::get_name<T>();
67         trim_typename(nm);
68         return nm;
69     }
70
71     template<typename T>
72     std::string get_vtable() const;
73
74     template<typename T>
75     std::vector<std::string> get_related() const;
76
77 };
78
79 void mangled_storage_impl::trim_typename(std::string & val)
80 {
81     //remove preceeding class or struct, because you might want to use a struct as class, et vice versa
82     if (val.size() >= 6)
83     {
84         using namespace std;
85         static constexpr char class_ [7] = "class ";
86         static constexpr char struct_[8] = "struct ";
87
88         if (equal(begin(class_), end(class_)-1, val.begin())) //aklright, starts with 'class '
89             val.erase(0, 6);
90         else if (val.size() >= 7)
91             if (equal(begin(struct_), end(struct_)-1, val.begin()))
92                 val.erase(0, 7);
93     }
94 }
95
96
97 namespace parser
98 {
99     namespace x3 = spirit::x3;
100
101     auto ptr_rule_impl(std::integral_constant<std::size_t, 32>)
102     {
103         return -((-x3::space) >> "__ptr32");
104     }
105     auto ptr_rule_impl(std::integral_constant<std::size_t, 64>)
106     {
107         return -((-x3::space) >> "__ptr64");
108     }
109
110     auto ptr_rule() { return ptr_rule_impl(std::integral_constant<std::size_t, sizeof(std::size_t)*8>());}
111
112     auto const visibility = ("public:" | x3::lit("protected:") | "private:");
113     auto const virtual_ = x3::space >> "virtual";
114     auto const static_     = x3::space >> x3::lit("static") ;
115
116     auto const_rule_impl(true_type )  {return x3::space >> "const";};
117     auto const_rule_impl(false_type)  {return x3::eps;};
118     template<typename T>
119     auto const_rule() {using t = is_const<typename remove_reference<T>::type>; return const_rule_impl(t());}
120
121     auto volatile_rule_impl(true_type )  {return x3::space >> "volatile";};
122     auto volatile_rule_impl(false_type)  {return x3::eps;};
123     template<typename T>
124     auto volatile_rule() {using t = is_volatile<typename remove_reference<T>::type>; return volatile_rule_impl(t());}
125
126
127     auto inv_const_rule_impl(true_type )  {return "const" >>  x3::space ;};
128     auto inv_const_rule_impl(false_type)  {return x3::eps;};
129     template<typename T>
130     auto inv_const_rule() {using t = is_const<typename remove_reference<T>::type>; return inv_const_rule_impl(t());}
131
132     auto inv_volatile_rule_impl(true_type )  {return "volatile" >> x3::space;};
133     auto inv_volatile_rule_impl(false_type)  {return x3::eps;};
134     template<typename T>
135     auto inv_volatile_rule() {using t = is_volatile<typename remove_reference<T>::type>; return inv_volatile_rule_impl(t());}
136
137
138     auto reference_rule_impl(false_type, false_type) {return x3::eps;}
139     auto reference_rule_impl(true_type,  false_type) {return x3::space >>"&"  ;}
140     auto reference_rule_impl(false_type, true_type ) {return x3::space >>"&&" ;}
141
142
143     template<typename T>
144     auto reference_rule() {using t_l = is_lvalue_reference<T>; using t_r = is_rvalue_reference<T>; return reference_rule_impl(t_l(), t_r());}
145
146     auto const class_ = ("class" | x3::lit("struct"));
147
148     //it takes a string, because it may be overloaded.
149     template<typename T>
150     auto type_rule(const std::string & type_name)
151     {
152         using namespace std;
153
154         return -(class_ >> x3::space)>> x3::string(type_name) >>
155                 const_rule<T>() >>
156                 volatile_rule<T>() >>
157                 reference_rule<T>() >>
158                 ptr_rule();
159     }
160     template<>
161     auto type_rule<void>(const std::string &) { return x3::string("void"); };
162
163     auto const cdecl_   = "__cdecl"     >> x3::space;
164     auto const stdcall  = "__stdcall"     >> x3::space;
165 #if defined(_WIN64)//seems to be necessary by msvc 14-x64
166     auto const thiscall = "__cdecl"     >> x3::space;
167 #else
168     auto const thiscall = "__thiscall"     >> x3::space;
169 #endif
170
171     template<typename Return, typename Arg>
172     auto arg_list(const mangled_storage_impl & ms, Return (*)(Arg))
173     {
174         using namespace std;
175
176         return type_rule<Arg>(ms.get_name<Arg>());
177     }
178
179     template<typename Return, typename First, typename Second, typename ...Args>
180     auto arg_list(const mangled_storage_impl & ms, Return (*)(First, Second, Args...))
181     {
182
183         using next_type = Return (*)(Second, Args...);
184         return type_rule<First>(ms.get_name<First>()) >> x3::char_(',') >> arg_list(ms, next_type());
185     }
186
187     template<typename Return>
188     auto arg_list(const mangled_storage_impl& /*ms*/, Return (*)())
189     {
190         return x3::string("void");
191     }
192 }
193
194
195 template<typename T> std::string mangled_storage_impl::get_variable(const std::string &name) const
196 {
197     using namespace std;
198     using namespace boost;
199
200     namespace x3 = spirit::x3;
201     using namespace parser;
202
203     auto type_name = get_name<T>();
204
205     auto matcher =
206             -(visibility >> static_ >> x3::space) >> //it may be a static class-member
207             parser::type_rule<T>(type_name) >> x3::space >>
208             name;
209
210     auto predicate = [&](const mangled_storage_base::entry & e)
211         {
212             if (e.demangled == name)//maybe not mangled,
213                 return true;
214
215             auto itr = e.demangled.begin();
216             auto end = e.demangled.end();
217             auto res = x3::parse(itr, end, matcher);
218             return res && (itr == end);
219         };
220
221     auto found = std::find_if(storage_.begin(), storage_.end(), predicate);
222
223     if (found != storage_.end())
224         return found->mangled;
225     else
226         return "";
227 }
228
229 template<typename Func> std::string mangled_storage_impl::get_function(const std::string &name) const
230 {
231     namespace x3 = spirit::x3;
232     using namespace parser;
233     using func_type = Func*;
234     using return_type = typename function_traits<Func>::result_type;
235     std::string return_type_name = get_name<return_type>();
236
237
238     auto matcher =
239                 -(visibility >> static_ >> x3::space) >> //it may be a static class-member, which does however not have the static attribute.
240                 parser::type_rule<return_type>(return_type_name) >>  x3::space >>
241                 cdecl_ >> //cdecl declaration for methods. stdcall cannot be
242                 name >> x3::lit('(') >> parser::arg_list(*this, func_type()) >> x3::lit(')') >>  parser::ptr_rule();
243
244
245     auto predicate = [&](const mangled_storage_base::entry & e)
246             {
247                 if (e.demangled == name)//maybe not mangled,
248                     return true;
249
250                 auto itr = e.demangled.begin();
251                 auto end = e.demangled.end();
252                 auto res = x3::parse(itr, end, matcher);
253
254                 return res && (itr == end);
255             };
256
257     auto found = std::find_if(storage_.begin(), storage_.end(), predicate);
258
259     if (found != storage_.end())
260         return found->mangled;
261     else
262         return "";
263
264 }
265
266 template<typename Class, typename Func>
267 std::string mangled_storage_impl::get_mem_fn(const std::string &name) const
268 {
269     namespace x3 = spirit::x3;
270     using namespace parser;
271     using func_type = Func*;
272     using return_type = typename function_traits<Func>::result_type;
273     auto return_type_name = get_name<return_type>();
274
275
276     auto cname = get_name<Class>();
277
278     auto matcher =
279                 visibility >> -virtual_ >> x3::space >>
280                 parser::type_rule<return_type>(return_type_name) >>  x3::space >>
281                 thiscall >> //cdecl declaration for methods. stdcall cannot be
282                 cname >> "::" >> name >>
283                 x3::lit('(') >> parser::arg_list(*this, func_type()) >> x3::lit(')') >>
284                 inv_const_rule<Class>() >> inv_volatile_rule<Class>() >> parser::ptr_rule();
285
286     auto predicate = [&](const mangled_storage_base::entry & e)
287             {
288                 auto itr = e.demangled.begin();
289                 auto end = e.demangled.end();
290                 auto res = x3::parse(itr, end, matcher);
291
292                 return res && (itr == end);
293             };
294
295     auto found = std::find_if(storage_.begin(), storage_.end(), predicate);
296
297     if (found != storage_.end())
298         return found->mangled;
299     else
300         return "";
301 }
302
303
304 template<typename Signature>
305 auto mangled_storage_impl::get_constructor() const -> ctor_sym
306 {
307     namespace x3 = spirit::x3;
308     using namespace parser;
309
310     using func_type = Signature*;
311
312
313     std::string ctor_name; // = class_name + "::" + name;
314     std::string unscoped_cname; //the unscoped class-name
315     {
316         auto class_name = get_return_type(dummy<Signature>());
317         auto pos = class_name.rfind("::");
318         if (pos == std::string::npos)
319         {
320             ctor_name = class_name+ "::" + class_name ;
321             unscoped_cname = class_name;
322         }
323         else
324         {
325             unscoped_cname = class_name.substr(pos+2) ;
326             ctor_name = class_name+ "::" + unscoped_cname;
327         }
328     }
329
330     auto matcher =
331                 visibility >> x3::space >>
332                 thiscall >> //cdecl declaration for methods. stdcall cannot be
333                 ctor_name >>
334                 x3::lit('(') >> parser::arg_list(*this, func_type()) >> x3::lit(')') >> parser::ptr_rule();
335
336
337     auto predicate = [&](const mangled_storage_base::entry & e)
338             {
339                 auto itr = e.demangled.begin();
340                 auto end = e.demangled.end();
341                 auto res = x3::parse(itr, end, matcher);
342
343                 return res && (itr == end);
344             };
345
346     auto f = std::find_if(storage_.begin(), storage_.end(), predicate);
347
348     if (f != storage_.end())
349         return f->mangled;
350     else
351         return "";
352 }
353
354 template<typename Class>
355 auto mangled_storage_impl::get_destructor() const -> dtor_sym
356 {
357     namespace x3 = spirit::x3;
358     using namespace parser;
359     std::string dtor_name; // = class_name + "::" + name;
360     std::string unscoped_cname; //the unscoped class-name
361     {
362         auto class_name = get_name<Class>();
363         auto pos = class_name.rfind("::");
364         if (pos == std::string::npos)
365         {
366             dtor_name = class_name+ "::~" + class_name  + "(void)";
367             unscoped_cname = class_name;
368         }
369         else
370         {
371             unscoped_cname = class_name.substr(pos+2) ;
372             dtor_name = class_name+ "::~" + unscoped_cname + "(void)";
373         }
374     }
375
376     auto matcher =
377                 visibility >> -virtual_ >> x3::space >>
378                 thiscall >> //cdecl declaration for methods. stdcall cannot be
379                 dtor_name >> parser::ptr_rule();
380
381
382     auto predicate = [&](const mangled_storage_base::entry & e)
383                 {
384                     auto itr = e.demangled.begin();
385                     auto end = e.demangled.end();
386                     auto res = x3::parse(itr, end, matcher);
387
388                     return res && (itr == end);
389                 };
390
391     auto found = std::find_if(storage_.begin(), storage_.end(), predicate);
392
393
394     if (found != storage_.end())
395         return found->mangled;
396     else
397         return "";
398 }
399
400 template<typename T>
401 std::string mangled_storage_impl::get_vtable() const
402 {
403     std::string id = "const " + get_name<T>() + "::`vftable'";
404
405     auto predicate = [&](const mangled_storage_base::entry & e)
406                 {
407                     return e.demangled == id;
408                 };
409
410     auto found = std::find_if(storage_.begin(), storage_.end(), predicate);
411
412
413     if (found != storage_.end())
414         return found->mangled;
415     else
416         return "";
417 }
418
419 template<typename T>
420 std::vector<std::string> mangled_storage_impl::get_related() const
421 {
422     std::vector<std::string> ret;
423     auto name = get_name<T>();
424
425     for (auto & c : storage_)
426     {
427         if (c.demangled.find(name) != std::string::npos)
428             ret.push_back(c.demangled);
429     }
430
431     return ret;
432 }
433
434
435 }}}
436
437
438
439 #endif /* BOOST_DLL_DETAIL_DEMANGLING_MSVC_HPP_ */