diff --git a/include/boost/dll/detail/demangling/msvc.hpp b/include/boost/dll/detail/demangling/msvc.hpp index d5a5c7cb..b9e51ce1 100644 --- a/include/boost/dll/detail/demangling/msvc.hpp +++ b/include/boost/dll/detail/demangling/msvc.hpp @@ -110,7 +110,7 @@ namespace parser } inline boost::core::string_view trim_ptrs(boost::core::string_view s) { - bool retry = false; + bool retry = false; do { retry = false; while (s.starts_with(" ")) { @@ -227,25 +227,37 @@ namespace parser } s.remove_prefix(mangled_name.size()); - if (std::is_const::value && !s.starts_with(" const")) { - return std::string::npos; + if (std::is_const::value) { + if (!s.starts_with(" const")) { + return std::string::npos; + } else { + s.remove_prefix(sizeof(" const") - 1); + } } - s.remove_prefix(sizeof(" const") - 1); - if (std::is_volatile::value && !s.starts_with(" volatile")) { - return std::string::npos; + if (std::is_volatile::value) { + if (!s.starts_with(" volatile")) { + return std::string::npos; + } else { + s.remove_prefix(sizeof(" volatile") - 1); + } } - s.remove_prefix(sizeof(" volatile") - 1); - if (std::is_rvalue_reference::value && !s.starts_with(" &&")) { - return std::string::npos; + if (std::is_rvalue_reference::value) { + if (!s.starts_with(" &&")) { + return std::string::npos; + } else { + s.remove_prefix(sizeof(" &&") - 1); + } } - s.remove_prefix(sizeof(" &&") - 1); - if (std::is_lvalue_reference::value && !s.starts_with(" &")) { - return std::string::npos; + if (std::is_lvalue_reference::value) { + if (!s.starts_with(" &")) { + return std::string::npos; + } else { + s.remove_prefix(sizeof(" &") - 1); + } } - s.remove_prefix(sizeof(" &") - 1); s = trim_ptrs(s); return s_orig.size() - s.size(); @@ -286,38 +298,121 @@ namespace parser return x3::string("void"); } + + template + std::string::size_type find_arg_list(const mangled_storage_impl& ms, boost::core::string_view s, Return (*)(Arg)) + { + return parser::find_type(ms, s); + } + + template + std::string::size_type find_arg_list(const mangled_storage_impl & ms, boost::core::string_view s, Return (*)(First, Second, Args...)) + { + using next_type = Return (*)(Second, Args...); + + const auto res = parser::find_type(ms, s); + if (res == std::string::npos) { + return std::string::npos; + } + s.remove_prefix(res); + if (!s.starts_with(",")) { + return std::string::npos; + } + s.remove_prefix(1); + + const auto new_res = parser::find_arg_list(ms, s, next_type()); + if (new_res == std::string::npos) { + return std::string::npos; + } + + return res + 1 + new_res; + } + + template + std::string::size_type find_arg_list(const mangled_storage_impl& ms, boost::core::string_view s, Return (*)()) { + return parser::find_type(ms, s); + } + struct is_destructor_with_name { const std::string dtor_name; inline bool operator()(boost::core::string_view s) const { { - const auto visibility_pos = find_visibility(s); + const auto visibility_pos = parser::find_visibility(s); if (visibility_pos == std::string::npos) { return false; } s.remove_prefix(visibility_pos); } + s = trim_prefix(s, " virtual"); { - const auto virtual_pos = find_visibility(s); - if (virtual_pos != std::string::npos) { + // cdecl declaration for methods. stdcall cannot be + const auto thiscall_pos = parser::find_thiscall(s); + if (thiscall_pos == std::string::npos) { return false; } + s.remove_prefix(thiscall_pos); + } + + if (!s.starts_with(dtor_name)) { + return false; + } + s.remove_prefix(dtor_name.size()); + s = parser::trim_ptrs(s); + return s.empty(); + } + + inline bool operator()(const mangled_storage_base::entry& e) const { + return (*this)(boost::core::string_view(e.demangled.data(), e.demangled.size())); + } + }; + + template + struct is_constructor_with_name { + const std::string ctor_name; + const mangled_storage_impl& ms; + + inline bool operator()(boost::core::string_view s) const { + { + const auto visibility_pos = parser::find_visibility(s); + if (visibility_pos == std::string::npos) { + return false; + } + s.remove_prefix(visibility_pos); } - s = trim_prefix(s, " virtual"); { // cdecl declaration for methods. stdcall cannot be - const auto thiscall_pos = find_thiscall(s); + const auto thiscall_pos = parser::find_thiscall(s); if (thiscall_pos == std::string::npos) { return false; } s.remove_prefix(thiscall_pos); } - if (!s.starts_with(dtor_name)) { + if (!s.starts_with(ctor_name)) { return false; } - s.remove_prefix(dtor_name.size()); - s = trim_ptrs(s); + s.remove_prefix(ctor_name.size()); + + if (!s.starts_with("(")) { + return false; + } + s.remove_prefix(1); + + { + const auto arg_list_pos = parser::find_arg_list(ms, s, Signature()); + if (arg_list_pos == std::string::npos) { + return false; + } + s.remove_prefix(arg_list_pos); + } + + if (!s.starts_with(")")) { + return false; + } + s.remove_prefix(1); + + s = parser::trim_ptrs(s); return s.empty(); } @@ -438,11 +533,7 @@ std::string mangled_storage_impl::get_mem_fn(const std::string &name) const template -auto mangled_storage_impl::get_constructor() const -> ctor_sym -{ - namespace x3 = spirit::x3; - using namespace parser; - +auto mangled_storage_impl::get_constructor() const -> ctor_sym { using func_type = Signature*; @@ -463,23 +554,7 @@ auto mangled_storage_impl::get_constructor() const -> ctor_sym } } - auto matcher = - visibility >> x3::space >> - thiscall >> //cdecl declaration for methods. stdcall cannot be - ctor_name >> - x3::lit('(') >> parser::arg_list(*this, func_type()) >> x3::lit(')') >> parser::ptr_rule(); - - - auto predicate = [&](const mangled_storage_base::entry & e) - { - auto itr = e.demangled.begin(); - auto end = e.demangled.end(); - auto res = x3::parse(itr, end, matcher); - - return res && (itr == end); - }; - - auto f = std::find_if(storage_.begin(), storage_.end(), predicate); + const auto f = std::find_if(storage_.begin(), storage_.end(), parser::is_constructor_with_name{ctor_name, *this}); if (f != storage_.end()) return f->mangled; diff --git a/test/cpp_mangling.cpp b/test/cpp_mangling.cpp index 3138632a..b8688911 100644 --- a/test/cpp_mangling.cpp +++ b/test/cpp_mangling.cpp @@ -8,6 +8,7 @@ #include +#if (__cplusplus > 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG > 201402L) #include int main(int argc, char* argv[]) @@ -43,5 +44,40 @@ int main(int argc, char* argv[]) BOOST_TEST(parser::is_destructor_with_name{"some_space::some_father::~some_father(void)"}("public: __thiscall some_space::some_father::~some_father(void) __ptr64")); + boost::dll::detail::mangled_storage_impl ms; + { + void(*ptr1)(int) = nullptr; + BOOST_TEST_EQ(parser::find_arg_list(ms, "int", ptr1), 3); + } + { + void(*ptr2)() = nullptr; + BOOST_TEST_EQ(parser::find_arg_list(ms, "void", ptr2), 4); + } + { + void(*ptr3)(int,int) = nullptr; + BOOST_TEST_EQ(parser::find_arg_list(ms, "int,int", ptr3), 7); + } + { + void(*ptr4)(int,short,long) = nullptr; + BOOST_TEST_EQ(parser::find_arg_list(ms, "int,short,long", ptr4), 14); + } + + + BOOST_TEST(( + parser::is_constructor_with_name{"some_space::some_class::some_class", ms} + ("public: __cdecl some_space::some_class::some_class(void) __ptr64") + )); + BOOST_TEST(( + parser::is_constructor_with_name{"some_space::some_class::some_class", ms} + ("private: __cdecl some_space::some_class::some_class(int)") + )); + BOOST_TEST(( + parser::is_constructor_with_name{"some_space::some_class::some_class", ms} + ("private: __cdecl some_space::some_class::some_class(int,int)") + )); + return boost::report_errors(); } +#else +int main() {return 0;} +#endif