diff --git a/include/mimic++/printing/type/PostProcessing.hpp b/include/mimic++/printing/type/PostProcessing.hpp index 5822bd41e..7c9e6151e 100644 --- a/include/mimic++/printing/type/PostProcessing.hpp +++ b/include/mimic++/printing/type/PostProcessing.hpp @@ -417,22 +417,87 @@ namespace mimicpp::printing::type::detail return out; } + constexpr auto is_space = [](CharT const c) { + return static_cast(std::isspace(static_cast(c))); + }; + [[nodiscard]] inline StringViewT trimmed(StringViewT const str) { - constexpr auto is_space = [](CharT const c) { - return static_cast(std::isspace(static_cast(c))); - }; - return { std::ranges::find_if_not(str, is_space), std::ranges::find_if_not(str | std::views::reverse, is_space).base()}; } + struct special_type_info + { + struct function_t + { + StringT returnType; + StringT argList; + StringT specifiers; + }; + + std::optional functionInfo{}; + + struct template_t + { + StringT argList; + }; + + std::optional templateInfo{}; + }; + + [[nodiscard]] + inline std::tuple> detect_function_type_info(StringT name) + { + static const RegexT functionSuffix{ + R"(\))" + R"(((?:\s*\w+\b)*)" + R"(\s*&{0,2}))" + R"(\s*$)"}; + if (SMatchT matches{}; + std::regex_search(name, matches, functionSuffix)) + { + special_type_info::function_t functionInfo{}; + auto& [returnType, argList, specs] = functionInfo; + + specs.assign(matches[1].first, matches[1].second); + + auto reversedName = name + | std::views::reverse + | std::views::drop(matches[0].length()); + auto const argListBeginIter = util::find_closing_token(reversedName, ')', '('); + MIMICPP_ASSERT(argListBeginIter != reversedName.end(), "No function begin found."); + if (StringViewT const args{argListBeginIter.base(), matches[0].first}; + args != "void") + { + argList.assign(args.cbegin(), args.cend()); + } + + auto const returnTypeDelimiter = util::find_next_unwrapped_token( + std::ranges::subrange{argListBeginIter + 1, reversedName.end()}, + " ", + closingBrackets, + openingBrackets); + DEBUG_ASSERT(returnTypeDelimiter, "No return-type found."); + returnType.assign(reversedName.end().base(), returnTypeDelimiter.end().base()); + + name = StringT{returnTypeDelimiter.begin().base(), argListBeginIter.base() - 1}; + + return { + std::move(name), + std::move(functionInfo)}; + } + + return { + std::move(name), + std::nullopt}; + } + [[nodiscard]] - inline std::tuple>> detect_special_type_info(StringT name) + inline std::tuple> detect_template_type_info(StringT name) { - // it's a template type if (name.back() == '>') { auto reversedName = name @@ -440,11 +505,10 @@ namespace mimicpp::printing::type::detail | std::views::drop(1); auto const iter = util::find_closing_token(reversedName, '>', '<'); MIMICPP_ASSERT(iter != reversedName.end(), "No template begin found."); - std::tuple info{ - "<", - StringT{iter.base(), name.end() - 1}, - ">" + special_type_info::template_t info{ + {iter.base(), name.end() - 1} }; + name.erase(iter.base() - 1, name.cend()); return { @@ -452,6 +516,14 @@ namespace mimicpp::printing::type::detail std::move(info)}; } + return { + std::move(name), + std::nullopt}; + } + + [[nodiscard]] + inline std::tuple detect_special_type_info(StringT name) + { #if MIMICPP_DETAIL_IS_GCC static RegexT lambdaSuffixRegex{R"(#(\d+)}$)"}; @@ -465,50 +537,49 @@ namespace mimicpp::printing::type::detail auto const iter = util::find_closing_token(reversedName, '}', '{'); MIMICPP_ASSERT(iter != reversedName.end(), "No lambda begin found."); - std::tuple info{ - format::format("lambda#{}", StringViewT{matches[1].first, matches[1].second}), - "", - ""}; - name.erase(iter.base() - 1, name.cend()); + auto outIter = std::ranges::copy(StringViewT{"lambda#"}, iter.base() - 1).out; + outIter = std::ranges::copy(matches[1].first, matches[1].second, outIter).out; + name.erase(outIter, name.cend()); return { std::move(name), - std::move(info)}; + {}}; } #endif - static const RegexT functionSuffix{ - R"(\))" - R"(\s*(?:const)?)" - R"(\s*(?:volatile)?)" - R"(\s*&{0,2})" - R"(\s*$)"}; - if (SMatchT matches{}; - std::regex_search(name, matches, functionSuffix)) + special_type_info info{}; + std::tie(name, info.functionInfo) = detect_function_type_info(std::move(name)); + std::tie(name, info.templateInfo) = detect_template_type_info(std::move(name)); + + return { + std::move(name), + std::move(info)}; + } + + template + constexpr OutIter prettify_arg_list(OutIter out, StringViewT const argList) + { + bool isFirst{true}; + StringViewT pendingArgList{argList}; + while (!pendingArgList.empty()) { - auto reversedName = name - | std::views::reverse - | std::views::drop(matches[0].length()); - auto const iter = util::find_closing_token(reversedName, ')', '('); - MIMICPP_ASSERT(iter != reversedName.end(), "No function begin found."); - - StringViewT const argList{iter.base(), name.end() - matches[0].length()}; - std::tuple info{ - "(", - StringT{argList == "void" ? "" : argList}, - StringT{matches[0].first, matches[0].second} - }; - name.erase(iter.base() - 1, name.cend()); + if (!std::exchange(isFirst, false)) + { + out = std::ranges::copy(StringViewT{", "}, std::move(out)).out; + } - return { - std::move(name), - std::move(info)}; + auto const tokenDelimiter = util::find_next_unwrapped_token( + pendingArgList, + argumentDelimiter, + openingBrackets, + closingBrackets); + StringViewT const arg = trimmed(StringViewT{pendingArgList.begin(), tokenDelimiter.begin()}); + out = type::prettify_identifier(std::move(out), StringT{arg}); + pendingArgList = StringViewT{tokenDelimiter.end(), pendingArgList.end()}; } - return { - std::move(name), - std::nullopt}; + return out; } } @@ -519,9 +590,27 @@ namespace mimicpp::printing::type { name = detail::apply_general_prettification(std::move(name)); - std::optional> specialTypeInfo{}; + detail::special_type_info specialTypeInfo{}; std::tie(name, specialTypeInfo) = detail::detect_special_type_info(std::move(name)); + if (specialTypeInfo.functionInfo) + { + out = type::prettify_identifier( + std::move(out), + std::move(specialTypeInfo.functionInfo->returnType)); + out = format::format_to(std::move(out), " "); + } + + // maybe (member-)function pointer + bool const isParensWrapped = name.starts_with("(") + && name.ends_with(")"); + if (isParensWrapped) + { + out = format::format_to(std::move(out), "("); + name.pop_back(); + name.erase(0, 1); + } + if (auto reversedName = name | std::views::reverse; auto const lastScopeMatch = util::find_next_unwrapped_token( reversedName, @@ -541,31 +630,26 @@ namespace mimicpp::printing::type out = std::ranges::copy(name, std::move(out)).out; - if (specialTypeInfo) + if (isParensWrapped) { - auto const& [scopeBegin, argList, scopeEnd] = *specialTypeInfo; - out = std::ranges::copy(scopeBegin, std::move(out)).out; + out = format::format_to(std::move(out), ")"); + } - bool isFirst{true}; - StringViewT pendingArgList{argList}; - while (!pendingArgList.empty()) - { - if (!std::exchange(isFirst, false)) - { - out = std::ranges::copy(StringViewT{", "}, std::move(out)).out; - } - - auto const tokenDelimiter = util::find_next_unwrapped_token( - pendingArgList, - detail::argumentDelimiter, - detail::openingBrackets, - detail::closingBrackets); - StringViewT const arg = detail::trimmed(StringViewT{pendingArgList.begin(), tokenDelimiter.begin()}); - out = type::prettify_identifier(std::move(out), StringT{arg}); - pendingArgList = StringViewT{tokenDelimiter.end(), pendingArgList.end()}; - } + if (specialTypeInfo.templateInfo) + { + out = format::format_to(std::move(out), "<"); + out = detail::prettify_arg_list(std::move(out), specialTypeInfo.templateInfo->argList); + out = format::format_to(std::move(out), ">"); + } + + if (specialTypeInfo.functionInfo) + { + auto const& [ret, args, specs] = *specialTypeInfo.functionInfo; - out = std::ranges::copy(scopeEnd, std::move(out)).out; + out = format::format_to(std::move(out), "("); + out = detail::prettify_arg_list(std::move(out), args); + out = format::format_to(std::move(out), ")"); + out = std::ranges::copy(specs, std::move(out)).out; } return out; diff --git a/test/unit-tests/printing/TypePostProcessing.cpp b/test/unit-tests/printing/TypePostProcessing.cpp index 026e0a05e..bb0d75cbd 100644 --- a/test/unit-tests/printing/TypePostProcessing.cpp +++ b/test/unit-tests/printing/TypePostProcessing.cpp @@ -757,6 +757,20 @@ namespace { return std::source_location::current(); } + + auto bar(my_type const&, std::source_location* outLoc) + { + if (outLoc) + { + *outLoc = std::source_location::current(); + } + + struct bar_type + { + }; + + return bar_type{}; + } }; } @@ -792,10 +806,9 @@ TEST_CASE( Catch::Matchers::Equals("{anon-ns}::my_template::my_type")); } - SECTION("When template-dependant function-pointer is given.") + SECTION("When template-dependant member-function-pointer is given.") { - using type_t = decltype(my_typeLambda()); - StringT const rawName = printing::type::type_name::foo)>(); + StringT const rawName = printing::type::type_name>::foo)>(); CAPTURE(rawName); printing::type::prettify_identifier( @@ -805,11 +818,27 @@ TEST_CASE( ss.str(), Catch::Matchers::Equals( "std::source_location " // return type - "{anon-ns}::my_template::* " + "({anon-ns}::my_template::*)" "({anon-ns}::my_template::my_type const&)")); } - SECTION("When template-dependant function is given.") + SECTION("When template-dependant member-function-pointer, returning local type, is given.") + { + StringT const rawName = printing::type::type_name>::bar)>(); + CAPTURE(rawName); + + printing::type::prettify_identifier( + std::ostreambuf_iterator{ss}, + rawName); + REQUIRE_THAT( + ss.str(), + Catch::Matchers::Equals( + "{anon-ns}::my_template::{bar}::bar_type " // return type + "({anon-ns}::my_template::*)" + "({anon-ns}::my_template::my_type const&, std::source_location*)")); + } + + /*SECTION("When template-dependant function is given.") { using type_t = decltype(my_typeLambda()); auto const loc = my_template{}.foo({}); @@ -825,6 +854,7 @@ TEST_CASE( "std::source_location " // return type "{anon-ns}::my_template::foo" "({anon-ns}::my_template::my_type const&)")); + }*/ SECTION("When arbitrary template name is given.") {