From d3c680409041e76e3e2f9ff370698943e7d93e90 Mon Sep 17 00:00:00 2001 From: Vladislav Shchapov Date: Fri, 2 Sep 2022 21:09:52 +0500 Subject: [PATCH] Add class name output to formatter for std::exception Signed-off-by: Vladislav Shchapov --- include/fmt/std.h | 41 ++++++++++++++++++++++++++++++++++++++++- test/std-test.cc | 42 ++++++++++++++++++++++++++++++------------ 2 files changed, 70 insertions(+), 13 deletions(-) diff --git a/include/fmt/std.h b/include/fmt/std.h index 63dbebe3179d0..442691c0faba4 100644 --- a/include/fmt/std.h +++ b/include/fmt/std.h @@ -8,9 +8,12 @@ #ifndef FMT_STD_H_ #define FMT_STD_H_ +#include #include +#include #include #include +#include #include #include "ostream.h" @@ -28,6 +31,16 @@ # endif #endif +#if FMT_HAS_INCLUDE() || defined(__GLIBCXX__) +# include +# ifndef __GABIXX_CXXABI_H__ +# define FMT_HAS_CXXABI_H 1 +# endif +#endif +#ifndef FMT_HAS_CXXABI_H +# define FMT_HAS_CXXABI_H 0 +#endif + #ifdef __cpp_lib_filesystem FMT_BEGIN_NAMESPACE @@ -175,7 +188,33 @@ struct formatter< template auto format(const std::exception& ex, FormatContext& ctx) const -> typename FormatContext::iterator { - return fmt::formatter::format(ex.what(), ctx); + basic_memory_buffer msg; + const std::type_info& ti = typeid(ex); +#if FMT_HAS_CXXABI_H + int status = 0; + std::size_t size = 0; + std::unique_ptr demangled_name( + abi::__cxa_demangle(ti.name(), nullptr, &size, &status), std::free); + if (demangled_name) { + msg.append(string_view(demangled_name.get())); + } else { + msg.append(string_view(ti.name())); + } +#elif FMT_MSC_VERSION + string_view sv(ti.name()); + if (sv.starts_with("class ")) + sv.remove_prefix(6); + else if (sv.starts_with("struct ")) + sv.remove_prefix(7); + msg.append(sv); +#else + msg.append(string_view(ti.name())); +#endif + msg.append(string_view(": ")); + msg.append(string_view(ex.what())); + + return fmt::formatter::format( + basic_string_view(msg.data(), msg.size()), ctx); } }; FMT_END_NAMESPACE diff --git a/test/std-test.cc b/test/std-test.cc index 77cf793454c3c..243b6820bb7fa 100644 --- a/test/std-test.cc +++ b/test/std-test.cc @@ -81,21 +81,39 @@ TEST(std_test, variant) { #endif } -TEST(std_test, exception) { - std::string str("Test Exception"); - std::string escstr = fmt::format("\"{}\"", str); - +template void exception_test() { try { - throw std::runtime_error(str); - } catch (const std::exception& ex) { - EXPECT_EQ(fmt::format("{}", ex), str); - EXPECT_EQ(fmt::format("{:?}", ex), escstr); + throw std::runtime_error("Test Exception"); + } catch (const Catch& ex) { + EXPECT_EQ("std::runtime_error: Test Exception", fmt::format("{}", ex)); + EXPECT_EQ("\"std::runtime_error: Test Exception\"", + fmt::format("{:?}", ex)); } +} + +namespace my_ns1 { +namespace my_ns2 { +struct my_exception : public std::exception { + private: + std::string msg; + + public: + my_exception(const std::string& s) : msg(s) {} + const char* what() const noexcept override; +}; +const char* my_exception::what() const noexcept { return msg.c_str(); } +} // namespace my_ns2 +} // namespace my_ns1 + +TEST(std_test, exception) { + exception_test(); + exception_test(); try { - throw std::runtime_error(str); - } catch (const std::runtime_error& ex) { - EXPECT_EQ(fmt::format("{}", ex), str); - EXPECT_EQ(fmt::format("{:?}", ex), escstr); + using namespace my_ns1::my_ns2; + throw my_exception("My Exception"); + } catch (const std::exception& ex) { + EXPECT_EQ("my_ns1::my_ns2::my_exception: My Exception", + fmt::format("{}", ex)); } }