From 7c3d396c9eafd8856d39ec41ca16ec07f5ddad2e Mon Sep 17 00:00:00 2001 From: DNKpp Date: Sat, 11 Apr 2026 17:15:42 +0200 Subject: [PATCH 01/97] refactor: move common_type_printer specialization to printing/state/CommonTypes.hpp --- .../mimic++/printing/state/CommonTypes.hpp | 17 ++++++++++++++++- include/mimic++/utilities/SourceLocation.hpp | 19 +------------------ 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/include/mimic++/printing/state/CommonTypes.hpp b/include/mimic++/printing/state/CommonTypes.hpp index eb8ccd0bb1..6ae7064124 100644 --- a/include/mimic++/printing/state/CommonTypes.hpp +++ b/include/mimic++/printing/state/CommonTypes.hpp @@ -1,4 +1,4 @@ -// Copyright Dominic (DNKpp) Koepke 2024 - 2026. +// Copyright Dominic (DNKpp) Koepke 2024-2026. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // https://www.boost.org/LICENSE_1_0.txt) @@ -19,6 +19,7 @@ #include "mimic++/printing/type/PrintType.hpp" #include "mimic++/utilities/C++20Compatibility.hpp" #include "mimic++/utilities/C++23Backports.hpp" // unreachable +#include "mimic++/utilities/SourceLocation.hpp" #ifndef MIMICPP_DETAIL_IS_MODULE #include @@ -70,6 +71,20 @@ struct mimicpp::printing::detail::state::common_type_printer + struct common_type_printer + { + template + static constexpr OutIter print(OutIter out, util::SourceLocation const& loc) + { + return detail::print_source_location( + std::move(out), + loc.file_name(), + loc.line(), + loc.function_name()); + } + }; + template <> struct common_type_printer { diff --git a/include/mimic++/utilities/SourceLocation.hpp b/include/mimic++/utilities/SourceLocation.hpp index fe1cdecfdd..5cdf281c39 100644 --- a/include/mimic++/utilities/SourceLocation.hpp +++ b/include/mimic++/utilities/SourceLocation.hpp @@ -1,4 +1,4 @@ -// Copyright Dominic (DNKpp) Koepke 2024 - 2025. +// Copyright Dominic (DNKpp) Koepke 2024-2026. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // https://www.boost.org/LICENSE_1_0.txt) @@ -10,9 +10,6 @@ #include "mimic++/config/Config.hpp" #include "mimic++/printing/Fwd.hpp" -#include "mimic++/printing/PathPrinter.hpp" -#include "mimic++/printing/state/CommonTypes.hpp" -#include "mimic++/printing/type/PrintType.hpp" #ifndef MIMICPP_DETAIL_IS_MODULE #include @@ -115,18 +112,4 @@ MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp::util }; } -template <> -struct mimicpp::printing::detail::state::common_type_printer -{ - template - static constexpr OutIter print(OutIter out, util::SourceLocation const& loc) - { - return detail::print_source_location( - std::move(out), - loc.file_name(), - loc.line(), - loc.function_name()); - } -}; - #endif From bd24da06d57b80af8f55e652e020ebe2f62f48d4 Mon Sep 17 00:00:00 2001 From: DNKpp Date: Sat, 11 Apr 2026 17:16:09 +0200 Subject: [PATCH 02/97] test: add case for incomplete types --- test/unit-tests/printing/TypePrinter.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/test/unit-tests/printing/TypePrinter.cpp b/test/unit-tests/printing/TypePrinter.cpp index 4db0534779..9e1f8906b2 100644 --- a/test/unit-tests/printing/TypePrinter.cpp +++ b/test/unit-tests/printing/TypePrinter.cpp @@ -1,4 +1,4 @@ -// Copyright Dominic (DNKpp) Koepke 2024 - 2025. +// Copyright Dominic (DNKpp) Koepke 2024-2026. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // https://www.boost.org/LICENSE_1_0.txt) @@ -712,6 +712,24 @@ TEST_CASE( Catch::Matchers::Equals("{anon-ns}::MyEnumClass")); } +namespace +{ + class FwdClass; + struct FwdStruct; +} + +TEST_CASE( + "Incomplete types are printed nicely.", + "[print]") +{ + CHECK_THAT( + print_type(), + Catch::Matchers::Equals("{anon-ns}::FwdClass")); + CHECK_THAT( + print_type(), + Catch::Matchers::Equals("{anon-ns}::FwdStruct")); +} + #endif namespace From d5fac689071bea8815c271bdb56baaa63cac549b Mon Sep 17 00:00:00 2001 From: DNKpp Date: Sat, 11 Apr 2026 17:16:59 +0200 Subject: [PATCH 03/97] refactor: replace type_info type-name deduction approach with source-location based --- include/mimic++/printing/type/PrintType.hpp | 99 ++++++++------------- 1 file changed, 38 insertions(+), 61 deletions(-) diff --git a/include/mimic++/printing/type/PrintType.hpp b/include/mimic++/printing/type/PrintType.hpp index 91a39a23d6..c4fefadf46 100644 --- a/include/mimic++/printing/type/PrintType.hpp +++ b/include/mimic++/printing/type/PrintType.hpp @@ -1,4 +1,4 @@ -// Copyright Dominic (DNKpp) Koepke 2024 - 2025. +// Copyright Dominic (DNKpp) Koepke 2024-2026. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // https://www.boost.org/LICENSE_1_0.txt) @@ -13,6 +13,7 @@ #include "mimic++/printing/Format.hpp" #include "mimic++/printing/Fwd.hpp" #include "mimic++/utilities/PriorityTag.hpp" +#include "mimic++/utilities/SourceLocation.hpp" #ifndef MIMICPP_DETAIL_IS_MODULE #include @@ -20,12 +21,39 @@ #include #include #include - #include #include #endif MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp::printing::type { + namespace detail + { + template + [[nodiscard]] + consteval std::string_view raw_type_name(std::type_identity const) noexcept + { + return util::SourceLocation{}.function_name(); + } + + inline constexpr auto typeNameConfig = std::invoke( + [] { + auto const rawName = raw_type_name(std::type_identity{}); + std::string_view const intName{"int"}; + std::size_t const prefix = rawName.rfind(intName); + MIMICPP_ASSERT(prefix != std::string_view::npos, "Did not find `int` in the type-name string."); + + struct type_name_config + { + std::size_t prefix{}; + std::size_t suffix{}; + }; + + return type_name_config{ + .prefix = prefix, + .suffix = rawName.size() - intName.size() - prefix}; + }); + } + /** * \brief Returns the (potentially demangled) name. * \ingroup PRINTING_TYPE @@ -38,7 +66,14 @@ MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp::printing::type */ template [[nodiscard]] - StringT type_name(); + StringT type_name() + { + auto rawName = detail::raw_type_name(std::type_identity{}); + rawName.remove_prefix(detail::typeNameConfig.prefix); + rawName.remove_suffix(detail::typeNameConfig.suffix); + + return StringT{rawName}; + } /** * \brief Prettifies a demangled name. @@ -86,58 +121,6 @@ MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp::printing::type #ifdef MIMICPP_CONFIG_EXPERIMENTAL_PRETTY_TYPES - #if MIMICPP_DETAIL_IS_GCC || MIMICPP_DETAIL_IS_CLANG - - #ifndef MIMICPP_DETAIL_IS_MODULE - #include - #include - #include - #endif - -namespace mimicpp::printing::type -{ - namespace detail - { - struct free_deleter - { - void operator()(char* const c) const noexcept - { - std::free(c); - } - }; - } - - template - StringT type_name() - { - auto* const rawName = typeid(T).name(); - - // see: https://gcc.gnu.org/onlinedocs/libstdc++/manual/ext_demangling.html - int status{}; - std::unique_ptr const demangledName{ - abi::__cxa_demangle(rawName, nullptr, nullptr, &status)}; - if (0 == status) - { - return {demangledName.get()}; - } - - return {rawName}; - } -} - - #else - -namespace mimicpp::printing::type -{ - template - StringT type_name() - { - return typeid(T).name(); - } -} - - #endif - #include "mimic++/printing/type/NameParser.hpp" #include "mimic++/printing/type/NamePrintVisitor.hpp" @@ -197,12 +180,6 @@ namespace mimicpp::printing::type namespace mimicpp::printing::type { - template - StringT type_name() - { - return typeid(T).name(); - } - template MIMICPP_DETAIL_CONSTEXPR_STRING OutIter prettify_type(OutIter out, StringT name) { From 8e34ccc5459eb6df18918cc2c81b776d751cc0ff Mon Sep 17 00:00:00 2001 From: DNKpp Date: Sat, 11 Apr 2026 17:33:22 +0200 Subject: [PATCH 04/97] refactor: printing::type::type_name returns a std::string_view instead of a std::string --- include/mimic++/printing/type/PrintType.hpp | 27 ++--- include/mimic++/printing/type/Templated.hpp | 10 +- .../printing/TypePostProcessing.cpp | 98 +++++++++---------- 3 files changed, 68 insertions(+), 67 deletions(-) diff --git a/include/mimic++/printing/type/PrintType.hpp b/include/mimic++/printing/type/PrintType.hpp index c4fefadf46..632c047de9 100644 --- a/include/mimic++/printing/type/PrintType.hpp +++ b/include/mimic++/printing/type/PrintType.hpp @@ -66,13 +66,13 @@ MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp::printing::type */ template [[nodiscard]] - StringT type_name() + consteval std::string_view type_name() noexcept { - auto rawName = detail::raw_type_name(std::type_identity{}); - rawName.remove_prefix(detail::typeNameConfig.prefix); - rawName.remove_suffix(detail::typeNameConfig.suffix); + auto typeName = detail::raw_type_name(std::type_identity{}); + typeName.remove_prefix(detail::typeNameConfig.prefix); + typeName.remove_suffix(detail::typeNameConfig.suffix); - return StringT{rawName}; + return typeName; } /** @@ -95,7 +95,7 @@ MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp::printing::type * this function simply outputs the provided name without any modifications. */ template - MIMICPP_DETAIL_CONSTEXPR_STRING OutIter prettify_type(OutIter out, StringT name); + constexpr OutIter prettify_type(OutIter out, std::string_view name); /** * \brief Prettifies a function name produces by e.g. `std::source_location::function_name()`. @@ -116,7 +116,7 @@ MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp::printing::type * this function simply outputs the provided name without any modifications. */ template - MIMICPP_DETAIL_CONSTEXPR_STRING OutIter prettify_function(OutIter out, StringT name); + constexpr OutIter prettify_function(OutIter out, std::string_view name); } #ifdef MIMICPP_CONFIG_EXPERIMENTAL_PRETTY_TYPES @@ -127,7 +127,7 @@ MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp::printing::type namespace mimicpp::printing::type { template - MIMICPP_DETAIL_CONSTEXPR_STRING OutIter prettify_type(OutIter out, StringT name) + constexpr OutIter prettify_type(OutIter out, std::string_view const name) { static_assert(parsing::parser_visitor>); @@ -141,7 +141,7 @@ namespace mimicpp::printing::type namespace detail { [[nodiscard]] - MIMICPP_DETAIL_CONSTEXPR_STRING StringT remove_template_details(StringT name) + constexpr std::string_view remove_template_details(std::string_view const name) { if (name.ends_with(']')) { @@ -153,7 +153,8 @@ namespace mimicpp::printing::type closingIter + 1, rest.end(), lexing::is_space); - name.erase(end.base(), name.end()); + + return std::string_view{name.begin(), end.base()}; } } @@ -162,7 +163,7 @@ namespace mimicpp::printing::type } template - MIMICPP_DETAIL_CONSTEXPR_STRING OutIter prettify_function(OutIter out, StringT name) + constexpr OutIter prettify_function(OutIter out, std::string_view name) { name = detail::remove_template_details(std::move(name)); @@ -181,13 +182,13 @@ namespace mimicpp::printing::type namespace mimicpp::printing::type { template - MIMICPP_DETAIL_CONSTEXPR_STRING OutIter prettify_type(OutIter out, StringT name) + constexpr OutIter prettify_type(OutIter out, std::string_view const name) { return std::ranges::copy(name, std::move(out)).out; } template - MIMICPP_DETAIL_CONSTEXPR_STRING OutIter prettify_function(OutIter out, StringT name) + constexpr OutIter prettify_function(OutIter out, std::string_view const name) { return std::ranges::copy(name, std::move(out)).out; } diff --git a/include/mimic++/printing/type/Templated.hpp b/include/mimic++/printing/type/Templated.hpp index f8d7fb4e10..a35e39440f 100644 --- a/include/mimic++/printing/type/Templated.hpp +++ b/include/mimic++/printing/type/Templated.hpp @@ -1,4 +1,4 @@ -// Copyright Dominic (DNKpp) Koepke 2024 - 2025. +// Copyright Dominic (DNKpp) Koepke 2024-2026. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // https://www.boost.org/LICENSE_1_0.txt) @@ -32,10 +32,10 @@ namespace mimicpp::printing::type::detail template constexpr OutIter pretty_template_name(OutIter out) { - StringT name = type_name(); - auto const iter = std::ranges::find(name, '<'); - MIMICPP_ASSERT(iter != name.cend(), "Given name is not a template."); - name.erase(iter, name.end()); + std::string_view name = type_name(); + auto const templateArgListPos = name.find('<'); + MIMICPP_ASSERT(templateArgListPos != std::string_view::npos, "Given name is not a template."); + name = name.substr(0u, templateArgListPos); return type::prettify_type(std::move(out), std::move(name)); } diff --git a/test/unit-tests/printing/TypePostProcessing.cpp b/test/unit-tests/printing/TypePostProcessing.cpp index 5866fafbdd..6efbe246d1 100644 --- a/test/unit-tests/printing/TypePostProcessing.cpp +++ b/test/unit-tests/printing/TypePostProcessing.cpp @@ -1,4 +1,4 @@ -// Copyright Dominic (DNKpp) Koepke 2024 - 2025. +// Copyright Dominic (DNKpp) Koepke 2024-2026. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // https://www.boost.org/LICENSE_1_0.txt) @@ -208,7 +208,7 @@ TEMPLATE_TEST_CASE( long, long long) { - StringT const rawName = printing::type::type_name(); + StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); StringStreamT ss{}; @@ -216,7 +216,7 @@ TEMPLATE_TEST_CASE( SECTION("When explicit signed name is given.") { using T = std::make_signed_t; - StringT const name = printing::type::type_name(); + StringT const name{printing::type::type_name()}; CAPTURE(name); printing::type::prettify_type( @@ -230,7 +230,7 @@ TEMPLATE_TEST_CASE( SECTION("When unsigned name is given.") { using T = std::make_unsigned_t; - StringT const name = printing::type::type_name(); + StringT const name{printing::type::type_name()}; CAPTURE(name); printing::type::prettify_type( @@ -250,7 +250,7 @@ TEST_CASE( SECTION("When type-name in anonymous-namespace is given.") { - StringT const rawName = printing::type::type_name(); + StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); printing::type::prettify_type( @@ -267,7 +267,7 @@ TEST_CASE( { } constexpr anon_class [[maybe_unused]]{}; - StringT const rawName = printing::type::type_name(); + StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); printing::type::prettify_type( @@ -284,7 +284,7 @@ TEST_CASE( { } constexpr anon_struct [[maybe_unused]]{}; - StringT const rawName = printing::type::type_name(); + StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); printing::type::prettify_type( @@ -302,7 +302,7 @@ TEST_CASE( dummy } constexpr anon_enum [[maybe_unused]]{}; - StringT const rawName = printing::type::type_name(); + StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); printing::type::prettify_type( @@ -315,7 +315,7 @@ TEST_CASE( SECTION("When nested type-name is given.") { - StringT const rawName = printing::type::type_name(); + StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); printing::type::prettify_type( @@ -328,7 +328,7 @@ TEST_CASE( SECTION("When lambda is given.") { - StringT const rawName = printing::type::type_name(); + StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); printing::type::prettify_type( @@ -346,7 +346,7 @@ TEST_CASE( SECTION("When lambda with params is given.") { [[maybe_unused]] constexpr auto lambda = [](std::string const&) {}; - StringT const rawName = printing::type::type_name(); + StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); printing::type::prettify_type( @@ -359,7 +359,7 @@ TEST_CASE( SECTION("When lambda-local type-name is given.") { - StringT const rawName = printing::type::type_name(); + StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); printing::type::prettify_type( @@ -377,7 +377,7 @@ TEST_CASE( SECTION("When mutable lambda-local type-name is given.") { - StringT const rawName = printing::type::type_name(); + StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); printing::type::prettify_type( @@ -396,7 +396,7 @@ TEST_CASE( SECTION("When noexcept lambda-local type-name is given.") { // noexcept doesn't seem to be part of the spec list - StringT const rawName = printing::type::type_name(); + StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); printing::type::prettify_type( @@ -414,7 +414,7 @@ TEST_CASE( SECTION("When nested lambda-local type-name is given.") { - StringT const rawName = printing::type::type_name(); + StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); printing::type::prettify_type( @@ -434,7 +434,7 @@ TEST_CASE( SECTION("When nested lambda-local type-name is given (more inner lambdas).") { - StringT const rawName = printing::type::type_name(); + StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); printing::type::prettify_type( @@ -454,7 +454,7 @@ TEST_CASE( SECTION("When free-function local type-name is given.") { - StringT const rawName = printing::type::type_name(); + StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); printing::type::prettify_type( @@ -470,7 +470,7 @@ TEST_CASE( SECTION("When public function local type-name is given.") { - StringT const rawName = printing::type::type_name(); + StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); printing::type::prettify_type( @@ -488,7 +488,7 @@ TEST_CASE( SECTION("When public noexcept function local type-name is given.") { // noexcept has no effect - StringT const rawName = printing::type::type_name(); + StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); printing::type::prettify_type( @@ -505,7 +505,7 @@ TEST_CASE( SECTION("When public const-function local type-name is given.") { - StringT const rawName = printing::type::type_name(); + StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); printing::type::prettify_type( @@ -522,7 +522,7 @@ TEST_CASE( SECTION("When public static-function local type-name is given.") { - StringT const rawName = printing::type::type_name(); + StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); printing::type::prettify_type( @@ -539,7 +539,7 @@ TEST_CASE( SECTION("When public lvalue-function local type-name is given.") { - StringT const rawName = printing::type::type_name().my_typeLvalueFunction())>(); + StringT const rawName{printing::type::type_name().my_typeLvalueFunction())>()}; CAPTURE(rawName); printing::type::prettify_type( @@ -556,7 +556,7 @@ TEST_CASE( SECTION("When public const lvalue-function local type-name is given.") { - StringT const rawName = printing::type::type_name().my_typeConstLvalueFunction())>(); + StringT const rawName{printing::type::type_name().my_typeConstLvalueFunction())>()}; CAPTURE(rawName); printing::type::prettify_type( @@ -573,7 +573,7 @@ TEST_CASE( SECTION("When public rvalue-function local type-name is given.") { - StringT const rawName = printing::type::type_name(); + StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); printing::type::prettify_type( @@ -590,7 +590,7 @@ TEST_CASE( SECTION("When public const rvalue-function local type-name is given.") { - StringT const rawName = printing::type::type_name().my_typeConstRvalueFunction())>(); + StringT const rawName{printing::type::type_name().my_typeConstRvalueFunction())>()}; CAPTURE(rawName); printing::type::prettify_type( @@ -607,7 +607,7 @@ TEST_CASE( SECTION("When private function local type-name is given.") { - StringT const rawName = printing::type::type_name(); + StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); printing::type::prettify_type( @@ -624,7 +624,7 @@ TEST_CASE( SECTION("When public operator local type-name is given.") { - StringT const rawName = printing::type::type_name(); + StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); printing::type::prettify_type( @@ -652,7 +652,7 @@ TEST_CASE( { }; - StringT const rawName = printing::type::type_name(); + StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); printing::type::prettify_type( @@ -671,7 +671,7 @@ TEST_CASE( { }; - StringT const rawName = printing::type::type_name(); + StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); printing::type::prettify_type( @@ -697,7 +697,7 @@ TEST_CASE( { }; - StringT const rawName = printing::type::type_name(); + StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); printing::type::prettify_type( @@ -733,7 +733,7 @@ TEST_CASE( { }; - StringT const rawName = printing::type::type_name(); + StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); printing::type::prettify_type( @@ -767,7 +767,7 @@ TEST_CASE( { }; - StringT const rawName = printing::type::type_name(); + StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); printing::type::prettify_type( @@ -798,7 +798,7 @@ TEST_CASE( SECTION("When function-local type is returned.") { using return_t = decltype(my_typeLambda()); - StringT const rawName = printing::type::type_name(); + StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); printing::type::prettify_type( @@ -819,7 +819,7 @@ TEST_CASE( SECTION("When function-local type is parameter.") { using param_t = decltype(my_typeLambda()); - StringT const rawName = printing::type::type_name(); + StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); printing::type::prettify_type( @@ -848,7 +848,7 @@ TEST_CASE( SECTION("When function-local type is returned.") { using return_t = decltype(my_typeLambda()); - StringT const rawName = printing::type::type_name(); + StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); printing::type::prettify_type( @@ -869,7 +869,7 @@ TEST_CASE( SECTION("When function-local type is parameter.") { using param_t = decltype(my_typeLambda()); - StringT const rawName = printing::type::type_name(); + StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); printing::type::prettify_type( @@ -891,7 +891,7 @@ TEST_CASE( SECTION("When function-ptr is returned.") { using ret_t = void (*)(); - StringT const rawName = printing::type::type_name(); + StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); printing::type::prettify_type( @@ -907,7 +907,7 @@ TEST_CASE( { using ret1_t = void (*)(); using ret2_t = ret1_t (*)(); - StringT const rawName = printing::type::type_name(); + StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); printing::type::prettify_type( @@ -958,7 +958,7 @@ TEST_CASE( SECTION("When template name in anonymous-namespace is given.") { - StringT const rawName = printing::type::type_name>(); + StringT const rawName{printing::type::type_name>()}; CAPTURE(rawName); printing::type::prettify_type( @@ -971,7 +971,7 @@ TEST_CASE( SECTION("When template-dependant name is given.") { - StringT const rawName = printing::type::type_name::my_type>(); + StringT const rawName{printing::type::type_name::my_type>()}; CAPTURE(rawName); printing::type::prettify_type( @@ -984,7 +984,7 @@ TEST_CASE( SECTION("When template-dependant member-function-pointer is given.") { - StringT const rawName = printing::type::type_name>::foo)>(); + StringT const rawName{printing::type::type_name>::foo)>()}; CAPTURE(rawName); printing::type::prettify_type( @@ -1013,7 +1013,7 @@ TEST_CASE( SECTION("When template-dependant member-function-pointer, returning local type, is given.") { - StringT const rawName = printing::type::type_name>::bar)>(); + StringT const rawName{printing::type::type_name>::bar)>()}; CAPTURE(rawName); StringT const returnPattern = @@ -1052,7 +1052,7 @@ TEST_CASE( SECTION("When arbitrary template name is given.") { using type_t = decltype(my_typeLambda()); - StringT const rawName = printing::type::type_name>(); + StringT const rawName{printing::type::type_name>()}; CAPTURE(rawName); printing::type::prettify_type( @@ -1226,7 +1226,7 @@ TEST_CASE( SECTION("When ordering operator is used.") { auto const [expectedFunctionName, rawName] = GENERATE( - (table)({ + (table)({ { R"(operator\s?<)", printing::type::type_name()}, {R"(operator\s?<=)", printing::type::type_name()}, { R"(operator\s?>)", printing::type::type_name(42))>()}, @@ -1249,7 +1249,7 @@ TEST_CASE( SECTION("When nested ordering operator is used.") { auto const [expectedFunctionName, expectedNestedFunctionName, rawName] = GENERATE( - (table)({ + (table)({ { R"(operator\s?<)", R"(operator\s?>=)", printing::type::type_name()}, {R"(operator\s?<=)", R"(operator\s?>)", printing::type::type_name()}, { R"(operator\s?>)", R"(operator\s?<=)", printing::type::type_name(""))>()}, @@ -1273,7 +1273,7 @@ TEST_CASE( SECTION("When spaceship-operator is used.") { - StringT const rawName = printing::type::type_name(42))>(); + StringT const rawName{printing::type::type_name(42))>()}; CAPTURE(rawName); printing::type::prettify_type( @@ -1297,7 +1297,7 @@ TEST_CASE( SECTION("When identifier contains operator() scope.") { - StringT const rawName = printing::type::type_name(); + StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); printing::type::prettify_type( @@ -1314,7 +1314,7 @@ TEST_CASE( SECTION("When member-function-pointer to operator() is given.") { - StringT const rawName = printing::type::type_name(); + StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); printing::type::prettify_type( @@ -1375,7 +1375,7 @@ TEST_CASE( "printing::type::prettify_function omits function args with just `void` content.", "[print]") { - StringT const name = "ret my_function(void)"; + StringT const name{"ret my_function(void)"}; StringStreamT ss{}; printing::type::prettify_function( From 87bc8e335aeb92996853e9481588794140dc5abf Mon Sep 17 00:00:00 2001 From: DNKpp Date: Sat, 11 Apr 2026 19:48:14 +0200 Subject: [PATCH 05/97] test: correct some type-name printing related test-cases --- test/unit-tests/InterfaceMock.cpp | 2 +- test/unit-tests/facade/Traits.cpp | 4 +- .../printing/TypePostProcessing.cpp | 42 +++++++++++-------- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/test/unit-tests/InterfaceMock.cpp b/test/unit-tests/InterfaceMock.cpp index 3554d05c04..aae4d2a165 100644 --- a/test/unit-tests/InterfaceMock.cpp +++ b/test/unit-tests/InterfaceMock.cpp @@ -402,7 +402,7 @@ TEST_CASE( expectation.mock_name(), Catch::Matchers::ContainsSubstring("derived") && Catch::Matchers::EndsWith("::foo") - && Catch::Matchers::Matches(R"(.+derived::foo)")); + && Catch::Matchers::Matches(R"((.+::)?derived::foo)")); } STOP_WARNING_SUPPRESSION diff --git a/test/unit-tests/facade/Traits.cpp b/test/unit-tests/facade/Traits.cpp index 58b5e68ada..99f9fba99e 100644 --- a/test/unit-tests/facade/Traits.cpp +++ b/test/unit-tests/facade/Traits.cpp @@ -117,7 +117,7 @@ TEST_CASE( expectation.mock_name(), Catch::Matchers::ContainsSubstring("Type") && Catch::Matchers::EndsWith("::foo") - && Catch::Matchers::Matches(R"(.+Type::foo)")); + && Catch::Matchers::Matches(R"((.+::)?Type::foo)")); } TEST_CASE( @@ -142,6 +142,6 @@ TEST_CASE( expectation.mock_name(), Catch::Matchers::ContainsSubstring("Type") && Catch::Matchers::EndsWith("::foo") - && Catch::Matchers::Matches(R"(.+Type::foo)")); + && Catch::Matchers::Matches(R"((.+::)?Type::foo)")); } diff --git a/test/unit-tests/printing/TypePostProcessing.cpp b/test/unit-tests/printing/TypePostProcessing.cpp index 6efbe246d1..85c6dff747 100644 --- a/test/unit-tests/printing/TypePostProcessing.cpp +++ b/test/unit-tests/printing/TypePostProcessing.cpp @@ -190,7 +190,7 @@ namespace StringT const lambdaScopePattern = topLevelLambdaPattern + "::"; StringT const anonNsScopePattern = R"(\{anon-ns\}::)"; - StringT const anonTypePattern = R"((\$_\d+|\{unnamed type#\d+\}|))"; + StringT const anonTypePattern = R"((\$_\d+|\{unnamed type#\d+\}||))"; StringT const testCaseScopePattern = R"(CATCH2_INTERNAL_TEST_\d+::)"; StringT const callOpScopePattern = R"(operator\s?\(\)::)"; } @@ -265,7 +265,7 @@ TEST_CASE( { class { - } constexpr anon_class [[maybe_unused]]{}; + } anon_class [[maybe_unused]]{}; StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); @@ -282,7 +282,7 @@ TEST_CASE( { class { - } constexpr anon_struct [[maybe_unused]]{}; + } anon_struct [[maybe_unused]]{}; StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); @@ -300,7 +300,7 @@ TEST_CASE( enum { dummy - } constexpr anon_enum [[maybe_unused]]{}; + } anon_enum [[maybe_unused]]{}; StringT const rawName{printing::type::type_name()}; CAPTURE(rawName); @@ -660,7 +660,7 @@ TEST_CASE( rawName); REQUIRE_THAT( std::move(ss).str(), - Catch::Matchers::Matches(testCaseScopePattern + R"(my_type)")); + Catch::Matchers::Matches("(" + testCaseScopePattern + ")?my_type")); } SECTION("When local type is queried inside a lambda.") @@ -680,10 +680,11 @@ TEST_CASE( REQUIRE_THAT( std::move(ss).str(), Catch::Matchers::Matches( - testCaseScopePattern + "(" + + testCaseScopePattern + lambdaScopePattern + callOpScopePattern - + "my_type")); + + ")?my_type")); }); } @@ -706,10 +707,11 @@ TEST_CASE( REQUIRE_THAT( std::move(_ss).str(), Catch::Matchers::Matches( - testCaseScopePattern + "(" + + testCaseScopePattern + "outer::" + callOpScopePattern - + "my_type")); + + ")?my_type")); } }; @@ -742,10 +744,11 @@ TEST_CASE( REQUIRE_THAT( std::move(*_ss).str(), Catch::Matchers::Matches( - testCaseScopePattern + "(" + + testCaseScopePattern + lambdaScopePattern + callOpScopePattern - + "my_type")); + + ")?my_type")); }, &ss, std::move(d1), @@ -776,12 +779,13 @@ TEST_CASE( REQUIRE_THAT( std::move(*_ss).str(), Catch::Matchers::Matches( - testCaseScopePattern + "(" + + testCaseScopePattern + lambdaScopePattern + callOpScopePattern + lambdaScopePattern + callOpScopePattern - + "my_type")); + + ")?my_type")); }, other_type{}); }, @@ -858,11 +862,12 @@ TEST_CASE( REQUIRE_THAT( ss.str(), Catch::Matchers::Matches( - anonNsScopePattern + "(" + + anonNsScopePattern + R"((?:my_typeLambda::)?)" // gcc produces this extra scope + lambdaScopePattern + callOpScopePattern - + "my_type " + + ")?my_type " R"(\(\*\)\(\))")); } @@ -880,11 +885,12 @@ TEST_CASE( ss.str(), Catch::Matchers::Matches( R"(void \(\*\)\()" + "(" + anonNsScopePattern + R"((?:my_typeLambda::)?)" // gcc produces this extra scope + lambdaScopePattern + callOpScopePattern - + "my_type" + + ")?my_type" R"(\))")); } @@ -1366,9 +1372,9 @@ TEST_CASE( printing::type::prettify_type( std::ostreambuf_iterator{ss}, rawName); - REQUIRE_THAT( + CHECK_THAT( ss.str(), - Catch::Matchers::Matches(testCaseScopePattern + "outer::~outer::my_type")); + Catch::Matchers::Matches("(" + testCaseScopePattern + "outer::~outer::)?my_type")); } TEST_CASE( From 683989b1473bb4b19d78eb63e750d712461a0919 Mon Sep 17 00:00:00 2001 From: DNKpp Date: Sun, 12 Apr 2026 16:15:22 +0200 Subject: [PATCH 06/97] fix: util::StaticString stores its underlying string null-terminated --- include/mimic++/utilities/StaticString.hpp | 48 +++++++++------------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/include/mimic++/utilities/StaticString.hpp b/include/mimic++/utilities/StaticString.hpp index 62a8de9344..deee50ff53 100644 --- a/include/mimic++/utilities/StaticString.hpp +++ b/include/mimic++/utilities/StaticString.hpp @@ -1,4 +1,4 @@ -// Copyright Dominic (DNKpp) Koepke 2024 - 2025. +// Copyright Dominic (DNKpp) Koepke 2024-2026. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // https://www.boost.org/LICENSE_1_0.txt) @@ -11,8 +11,11 @@ #ifndef MIMICPP_DETAIL_IS_MODULE #include + #include + #include #include - #include + #include + #include #endif MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp::util @@ -21,18 +24,19 @@ MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp::util class StaticString { public: - Char data[length]; + // We intentionally keep the null-terminator. + std::array data; [[nodiscard]] // - explicit(false) consteval StaticString(Char const (&arr)[length + 1]) noexcept + explicit(false) consteval StaticString(Char const (&arr)[length + 1u]) noexcept { - std::ranges::copy_n(arr, length, std::ranges::begin(data)); + std::ranges::copy(arr, data.begin()); } [[nodiscard]] static constexpr bool empty() noexcept { - return false; + return length == 0u; } [[nodiscard]] @@ -44,47 +48,35 @@ MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp::util [[nodiscard]] constexpr auto begin() const noexcept { - return std::ranges::begin(data); + return data.cbegin(); } [[nodiscard]] constexpr auto end() const noexcept { - return std::ranges::end(data); - } - }; - - template - class StaticString - { - public: - [[nodiscard]] // - explicit(false) consteval StaticString([[maybe_unused]] Char const (&arr)[1]) noexcept - { + return begin() + size(); } [[nodiscard]] - static constexpr bool empty() noexcept + constexpr std::basic_string_view view() const noexcept { - return true; + return {begin(), end()}; } [[nodiscard]] - static constexpr std::size_t size() noexcept + constexpr std::basic_string str() const noexcept { - return 0u; + return {begin(), end()}; } [[nodiscard]] - static constexpr Char const* begin() noexcept - { - return nullptr; - } + friend bool operator==(StaticString const&, StaticString const&) = default; + template > String> [[nodiscard]] - static constexpr Char const* end() noexcept + constexpr bool operator==(String const& other) const noexcept { - return nullptr; + return view() == std::basic_string_view{other}; } }; From 65b048120c6db579a34dac47fbdd0a545a259543 Mon Sep 17 00:00:00 2001 From: DNKpp Date: Sun, 12 Apr 2026 16:25:30 +0200 Subject: [PATCH 07/97] refactor: add separate type-name-print-tests test-suite --- test/CMakeLists.txt | 3 +- test/type-name-print-tests/BuiltinTypes.cpp | 144 ++++++++++++++++++ test/type-name-print-tests/CMakeLists.txt | 28 ++++ test/type-name-print-tests/Common.hpp | 105 +++++++++++++ .../printing/TypePostProcessing.cpp | 47 ------ 5 files changed, 279 insertions(+), 48 deletions(-) create mode 100644 test/type-name-print-tests/BuiltinTypes.cpp create mode 100644 test/type-name-print-tests/CMakeLists.txt create mode 100644 test/type-name-print-tests/Common.hpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index d4a83a2ab1..30abaa5c8a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright Dominic (DNKpp) Koepke 2024 - 2025. +# Copyright Dominic (DNKpp) Koepke 2024-2026. # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # https://www.boost.org/LICENSE_1_0.txt) @@ -11,6 +11,7 @@ add_subdirectory(compile-errors) option(MIMICPP_ENABLE_UNIT_TESTS "Determines, whether the unit-tests shall be built." ON) if (MIMICPP_ENABLE_UNIT_TESTS) add_subdirectory(unit-tests) + add_subdirectory(type-name-print-tests) endif () if (MIMICPP_CONFIG_EXPERIMENTAL_ENABLE_CXX20_MODULES__UNPORTABLE__) diff --git a/test/type-name-print-tests/BuiltinTypes.cpp b/test/type-name-print-tests/BuiltinTypes.cpp new file mode 100644 index 0000000000..a1390bf8ad --- /dev/null +++ b/test/type-name-print-tests/BuiltinTypes.cpp @@ -0,0 +1,144 @@ +// Copyright Dominic (DNKpp) Koepke 2026. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// https://www.boost.org/LICENSE_1_0.txt) + +#include "mimic++/printing/TypePrinter.hpp" + +#include "Common.hpp" + +using namespace mimicpp; + +TEMPLATE_TEST_CASE( + "printing::type::prettify_type handles built-in integral types correctly.", + "[print][print::type]", + char, + short, + int, + long, + long long) +{ + std::ostringstream ss{}; + + SECTION("When is given as-is.") + { + std::string const name{printing::type::type_name()}; + CAPTURE(name); + + printing::type::prettify_type( + std::ostreambuf_iterator{ss}, + name); + CHECK_THAT( + std::move(ss).str(), + Catch::Matchers::Matches(name)); + } + + SECTION("When explicit signed name is given.") + { + using T = std::make_signed_t; + std::string const name{printing::type::type_name()}; + CAPTURE(name); + + printing::type::prettify_type( + std::ostreambuf_iterator{ss}, + name); + CHECK_THAT( + std::move(ss).str(), + Catch::Matchers::Matches(name)); + } + + SECTION("When unsigned name is given.") + { + using T = std::make_unsigned_t; + std::string const name{printing::type::type_name()}; + CAPTURE(name); + + printing::type::prettify_type( + std::ostreambuf_iterator{ss}, + name); + CHECK_THAT( + std::move(ss).str(), + Catch::Matchers::Matches(name)); + } +} + +TEMPLATE_LIST_TEST_CASE( + "printing::type::prettify_type handles bool correctly.", + "[print][print::type]", + testing::common_mod_list) +{ + std::string const suffixPattern{TestType::suffix}; + CAPTURE(suffixPattern); + using T = testing::mod_type_t; + + std::string const name{printing::type::type_name()}; + CAPTURE(name); + + std::ostringstream ss{}; + printing::type::prettify_type( + std::ostreambuf_iterator{ss}, + name); + CHECK_THAT( + std::move(ss).str(), + Catch::Matchers::Matches("bool" + suffixPattern)); +} + +namespace +{ + template + [[nodiscard]] + std::pair make_case(std::string expected) + { + return { + std::move(expected), + std::string{printing::type::type_name()}}; + } +} + +TEMPLATE_LIST_TEST_CASE( + "printing::type::prettify_type handles built-in float types correctly.", + "[print][print::type]", + testing::common_mod_list) +{ + std::string const suffixPattern{TestType::suffix}; + CAPTURE(suffixPattern); + + auto const [expectedBase, rawName] = GENERATE( + (make_case>("float")), + (make_case>("double")), + (make_case>("long double"))); + CAPTURE(rawName); + + std::ostringstream ss{}; + printing::type::prettify_type( + std::ostreambuf_iterator{ss}, + rawName); + CHECK_THAT( + std::move(ss).str(), + Catch::Matchers::Matches(expectedBase + suffixPattern)); +} + +TEMPLATE_LIST_TEST_CASE( + "printing::type::prettify_type handles built-in character types correctly.", + "[print][print::type]", + testing::common_mod_list) +{ + std::string const suffixPattern{TestType::suffix}; + CAPTURE(suffixPattern); + + auto const [expectedBase, rawName] = GENERATE( + (make_case>("char")), + (make_case>("wchar_t")), + (make_case>("char8_t")), + (make_case>("char16_t")), + (make_case>("char32_t"))); + CAPTURE(rawName); + + std::ostringstream ss{}; + printing::type::prettify_type( + std::ostreambuf_iterator{ss}, + rawName); + CHECK_THAT( + std::move(ss).str(), + Catch::Matchers::Matches(expectedBase + suffixPattern)); +} diff --git a/test/type-name-print-tests/CMakeLists.txt b/test/type-name-print-tests/CMakeLists.txt new file mode 100644 index 0000000000..3ac2b417c6 --- /dev/null +++ b/test/type-name-print-tests/CMakeLists.txt @@ -0,0 +1,28 @@ +# Copyright Dominic (DNKpp) Koepke 2026. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# https://www.boost.org/LICENSE_1_0.txt) + +set(TARGET_NAME mimicpp-type-name-print-tests) + +add_executable(${TARGET_NAME} + "BuiltinTypes.cpp" +) + +include(Mimic++-EnableSanitizers) +enable_sanitizers(${TARGET_NAME}) + +find_package(Catch2 REQUIRED) +target_link_libraries(${TARGET_NAME} PRIVATE + mimicpp::header-only + mimicpp::test::basics + Catch2::Catch2WithMain +) + +target_precompile_headers(${TARGET_NAME} PRIVATE + + "../unit-tests/Catch2FallbackStringifier.hpp" + +) + +catch_discover_tests(${TARGET_NAME}) diff --git a/test/type-name-print-tests/Common.hpp b/test/type-name-print-tests/Common.hpp new file mode 100644 index 0000000000..7f8c5c56d3 --- /dev/null +++ b/test/type-name-print-tests/Common.hpp @@ -0,0 +1,105 @@ +// Copyright Dominic (DNKpp) Koepke 2026. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// https://www.boost.org/LICENSE_1_0.txt) + +#pragma once + +#include "mimic++/utilities/StaticString.hpp" +#include "mimic++/utilities/TypeList.hpp" + +#include +#include + +namespace mimicpp::testing +{ + [[nodiscard, maybe_unused]] + inline std::string maybe_pattern(std::string const& pattern) + { + return "(:?" + pattern + ")?"; + } + + template + struct modifier + { + using type = T; + static constexpr std::string_view suffix = suffixText.view(); + }; + + namespace mods + { + template + using decayed = modifier; + + template + using add_lvalue_ref = modifier; + template + using add_const_lvalue_ref = modifier; + template + using add_volatile_lvalue_ref = modifier; + template + using add_cv_lvalue_ref = modifier; + + template + using add_rvalue_ref = modifier; + template + using add_const_rvalue_ref = modifier; + template + using add_volatile_rvalue_ref = modifier; + template + using add_cv_rvalue_ref = modifier; + + template + using add_pointer = modifier; + template + using add_const_pointer = modifier; + } + + template