Skip to content

Commit

Permalink
fix: enhance type-prettification
Browse files Browse the repository at this point in the history
  • Loading branch information
DNKpp committed Mar 4, 2025
1 parent d510249 commit 399bde3
Show file tree
Hide file tree
Showing 2 changed files with 185 additions and 71 deletions.
216 changes: 150 additions & 66 deletions include/mimic++/printing/type/PostProcessing.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -417,41 +417,113 @@ namespace mimicpp::printing::type::detail
return out;
}

constexpr auto is_space = [](CharT const c) {
return static_cast<bool>(std::isspace(static_cast<int>(c)));
};

[[nodiscard]]
inline StringViewT trimmed(StringViewT const str)
{
constexpr auto is_space = [](CharT const c) {
return static_cast<bool>(std::isspace(static_cast<int>(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<function_t> functionInfo{};

struct template_t
{
StringT argList;
};

std::optional<template_t> templateInfo{};
};

[[nodiscard]]
inline std::tuple<StringT, std::optional<special_type_info::function_t>> 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;

Check notice on line 463 in include/mimic++/printing/type/PostProcessing.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

include/mimic++/printing/type/PostProcessing.hpp#L463

The scope of the variable 'argList' can be reduced.

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<StringT, std::optional<std::tuple<StringT, StringT, StringT>>> detect_special_type_info(StringT name)
inline std::tuple<StringT, std::optional<special_type_info::template_t>> detect_template_type_info(StringT name)
{
// it's a template type
if (name.back() == '>')
{
auto reversedName = name
| std::views::reverse
| 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 {
std::move(name),
std::move(info)};
}

return {
std::move(name),
std::nullopt};
}

[[nodiscard]]
inline std::tuple<StringT, special_type_info> detect_special_type_info(StringT name)
{
#if MIMICPP_DETAIL_IS_GCC

static RegexT lambdaSuffixRegex{R"(#(\d+)}$)"};
Expand All @@ -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 <print_iterator OutIter>
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;
}
}

Expand All @@ -519,9 +590,27 @@ namespace mimicpp::printing::type
{
name = detail::apply_general_prettification(std::move(name));

std::optional<std::tuple<StringT, StringT, StringT>> 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,
Expand All @@ -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;
Expand Down
40 changes: 35 additions & 5 deletions test/unit-tests/printing/TypePostProcessing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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{};
}
};
}

Expand Down Expand Up @@ -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<decltype(&my_template<type_t>::foo)>();
StringT const rawName = printing::type::type_name<decltype(&my_template<my_template<>>::foo)>();
CAPTURE(rawName);

printing::type::prettify_identifier(
Expand All @@ -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<decltype(&my_template<my_template<>>::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<type_t>{}.foo({});
Expand All @@ -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.")
{
Expand Down

0 comments on commit 399bde3

Please sign in to comment.