1 // Copyright 2016 Klemens Morgenstern
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)
7 #ifndef BOOST_DLL_DETAIL_DEMANGLING_MSVC_HPP_
8 #define BOOST_DLL_DETAIL_DEMANGLING_MSVC_HPP_
10 #include <boost/dll/detail/demangling/mangled_storage_base.hpp>
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>
20 #include <boost/spirit/home/x3.hpp>
22 namespace boost { namespace dll { namespace detail {
24 class mangled_storage_impl : public mangled_storage_base
29 template<typename Return, typename ...Args>
30 std::vector<std::string> get_func_params(dummy<Return(Args...)>) const
32 return {get_name<Args>()...};
34 template<typename Return, typename ...Args>
35 std::string get_return_type(dummy<Return(Args...)>) const
37 return get_name<Return>();
39 //function to remove preceeding 'class ' or 'struct ' if the are given in this format.
41 inline static void trim_typename(std::string & val);
43 using ctor_sym = std::string;
44 using dtor_sym = std::string;
46 using mangled_storage_base::mangled_storage_base;
49 std::string get_variable(const std::string &name) const;
51 template<typename Func>
52 std::string get_function(const std::string &name) const;
54 template<typename Class, typename Func>
55 std::string get_mem_fn(const std::string &name) const;
57 template<typename Signature>
58 ctor_sym get_constructor() const;
60 template<typename Class>
61 dtor_sym get_destructor() const;
63 template<typename T> //overload, does not need to virtual.
64 std::string get_name() const
66 auto nm = mangled_storage_base::get_name<T>();
72 std::string get_vtable() const;
75 std::vector<std::string> get_related() const;
79 void mangled_storage_impl::trim_typename(std::string & val)
81 //remove preceeding class or struct, because you might want to use a struct as class, et vice versa
85 static constexpr char class_ [7] = "class ";
86 static constexpr char struct_[8] = "struct ";
88 if (equal(begin(class_), end(class_)-1, val.begin())) //aklright, starts with 'class '
90 else if (val.size() >= 7)
91 if (equal(begin(struct_), end(struct_)-1, val.begin()))
99 namespace x3 = spirit::x3;
101 auto ptr_rule_impl(std::integral_constant<std::size_t, 32>)
103 return -((-x3::space) >> "__ptr32");
105 auto ptr_rule_impl(std::integral_constant<std::size_t, 64>)
107 return -((-x3::space) >> "__ptr64");
110 auto ptr_rule() { return ptr_rule_impl(std::integral_constant<std::size_t, sizeof(std::size_t)*8>());}
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") ;
116 auto const_rule_impl(true_type ) {return x3::space >> "const";};
117 auto const_rule_impl(false_type) {return x3::eps;};
119 auto const_rule() {using t = is_const<typename remove_reference<T>::type>; return const_rule_impl(t());}
121 auto volatile_rule_impl(true_type ) {return x3::space >> "volatile";};
122 auto volatile_rule_impl(false_type) {return x3::eps;};
124 auto volatile_rule() {using t = is_volatile<typename remove_reference<T>::type>; return volatile_rule_impl(t());}
127 auto inv_const_rule_impl(true_type ) {return "const" >> x3::space ;};
128 auto inv_const_rule_impl(false_type) {return x3::eps;};
130 auto inv_const_rule() {using t = is_const<typename remove_reference<T>::type>; return inv_const_rule_impl(t());}
132 auto inv_volatile_rule_impl(true_type ) {return "volatile" >> x3::space;};
133 auto inv_volatile_rule_impl(false_type) {return x3::eps;};
135 auto inv_volatile_rule() {using t = is_volatile<typename remove_reference<T>::type>; return inv_volatile_rule_impl(t());}
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 >>"&&" ;}
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());}
146 auto const class_ = ("class" | x3::lit("struct"));
148 //it takes a string, because it may be overloaded.
150 auto type_rule(const std::string & type_name)
154 return -(class_ >> x3::space)>> x3::string(type_name) >>
156 volatile_rule<T>() >>
157 reference_rule<T>() >>
161 auto type_rule<void>(const std::string &) { return x3::string("void"); };
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;
168 auto const thiscall = "__thiscall" >> x3::space;
171 template<typename Return, typename Arg>
172 auto arg_list(const mangled_storage_impl & ms, Return (*)(Arg))
176 return type_rule<Arg>(ms.get_name<Arg>());
179 template<typename Return, typename First, typename Second, typename ...Args>
180 auto arg_list(const mangled_storage_impl & ms, Return (*)(First, Second, Args...))
183 using next_type = Return (*)(Second, Args...);
184 return type_rule<First>(ms.get_name<First>()) >> x3::char_(',') >> arg_list(ms, next_type());
187 template<typename Return>
188 auto arg_list(const mangled_storage_impl& /*ms*/, Return (*)())
190 return x3::string("void");
195 template<typename T> std::string mangled_storage_impl::get_variable(const std::string &name) const
198 using namespace boost;
200 namespace x3 = spirit::x3;
201 using namespace parser;
203 auto type_name = get_name<T>();
206 -(visibility >> static_ >> x3::space) >> //it may be a static class-member
207 parser::type_rule<T>(type_name) >> x3::space >>
210 auto predicate = [&](const mangled_storage_base::entry & e)
212 if (e.demangled == name)//maybe not mangled,
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);
221 auto found = std::find_if(storage_.begin(), storage_.end(), predicate);
223 if (found != storage_.end())
224 return found->mangled;
229 template<typename Func> std::string mangled_storage_impl::get_function(const std::string &name) const
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>();
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();
245 auto predicate = [&](const mangled_storage_base::entry & e)
247 if (e.demangled == name)//maybe not mangled,
250 auto itr = e.demangled.begin();
251 auto end = e.demangled.end();
252 auto res = x3::parse(itr, end, matcher);
254 return res && (itr == end);
257 auto found = std::find_if(storage_.begin(), storage_.end(), predicate);
259 if (found != storage_.end())
260 return found->mangled;
266 template<typename Class, typename Func>
267 std::string mangled_storage_impl::get_mem_fn(const std::string &name) const
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>();
276 auto cname = get_name<Class>();
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();
286 auto predicate = [&](const mangled_storage_base::entry & e)
288 auto itr = e.demangled.begin();
289 auto end = e.demangled.end();
290 auto res = x3::parse(itr, end, matcher);
292 return res && (itr == end);
295 auto found = std::find_if(storage_.begin(), storage_.end(), predicate);
297 if (found != storage_.end())
298 return found->mangled;
304 template<typename Signature>
305 auto mangled_storage_impl::get_constructor() const -> ctor_sym
307 namespace x3 = spirit::x3;
308 using namespace parser;
310 using func_type = Signature*;
313 std::string ctor_name; // = class_name + "::" + name;
314 std::string unscoped_cname; //the unscoped class-name
316 auto class_name = get_return_type(dummy<Signature>());
317 auto pos = class_name.rfind("::");
318 if (pos == std::string::npos)
320 ctor_name = class_name+ "::" + class_name ;
321 unscoped_cname = class_name;
325 unscoped_cname = class_name.substr(pos+2) ;
326 ctor_name = class_name+ "::" + unscoped_cname;
331 visibility >> x3::space >>
332 thiscall >> //cdecl declaration for methods. stdcall cannot be
334 x3::lit('(') >> parser::arg_list(*this, func_type()) >> x3::lit(')') >> parser::ptr_rule();
337 auto predicate = [&](const mangled_storage_base::entry & e)
339 auto itr = e.demangled.begin();
340 auto end = e.demangled.end();
341 auto res = x3::parse(itr, end, matcher);
343 return res && (itr == end);
346 auto f = std::find_if(storage_.begin(), storage_.end(), predicate);
348 if (f != storage_.end())
354 template<typename Class>
355 auto mangled_storage_impl::get_destructor() const -> dtor_sym
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
362 auto class_name = get_name<Class>();
363 auto pos = class_name.rfind("::");
364 if (pos == std::string::npos)
366 dtor_name = class_name+ "::~" + class_name + "(void)";
367 unscoped_cname = class_name;
371 unscoped_cname = class_name.substr(pos+2) ;
372 dtor_name = class_name+ "::~" + unscoped_cname + "(void)";
377 visibility >> -virtual_ >> x3::space >>
378 thiscall >> //cdecl declaration for methods. stdcall cannot be
379 dtor_name >> parser::ptr_rule();
382 auto predicate = [&](const mangled_storage_base::entry & e)
384 auto itr = e.demangled.begin();
385 auto end = e.demangled.end();
386 auto res = x3::parse(itr, end, matcher);
388 return res && (itr == end);
391 auto found = std::find_if(storage_.begin(), storage_.end(), predicate);
394 if (found != storage_.end())
395 return found->mangled;
401 std::string mangled_storage_impl::get_vtable() const
403 std::string id = "const " + get_name<T>() + "::`vftable'";
405 auto predicate = [&](const mangled_storage_base::entry & e)
407 return e.demangled == id;
410 auto found = std::find_if(storage_.begin(), storage_.end(), predicate);
413 if (found != storage_.end())
414 return found->mangled;
420 std::vector<std::string> mangled_storage_impl::get_related() const
422 std::vector<std::string> ret;
423 auto name = get_name<T>();
425 for (auto & c : storage_)
427 if (c.demangled.find(name) != std::string::npos)
428 ret.push_back(c.demangled);
439 #endif /* BOOST_DLL_DETAIL_DEMANGLING_MSVC_HPP_ */