Fixed template instantiation with mixed type and non-type parameters

This commit is contained in:
Bartek Kryza
2021-03-14 11:59:50 +01:00
parent 0fc862332a
commit 93310b54e0
4 changed files with 44 additions and 50 deletions

View File

@@ -268,36 +268,29 @@ public:
std::vector<std::string> tokenize_template_parameters() const std::vector<std::string> tokenize_template_parameters() const
{ {
const auto &toks = tokenize(); auto toks = tokenize();
std::vector<std::string> res; std::vector<std::string> res;
bool inside_template{false}; bool inside_template{false};
bool is_namespace{false}; bool is_namespace{false};
for (const auto &tok : toks) {
auto t = clanguml::util::trim(tok); for (int i = 0; i < toks.size(); i++) {
if (t == ">") { // libclang returns ">..>>" in template as a single token...
break; auto t = toks[i];
} if (std::all_of(t.begin(), t.end(),
if (inside_template) { [](const char &c) { return c == '>'; })) {
if (t == ",") toks[i] = ">";
continue; for (int j = 0; j < t.size() - 1; j++)
if (t == "::") { toks.insert(toks.begin() + i, ">");
is_namespace = true;
res.back() += t;
}
else if (is_namespace) {
is_namespace = false;
res.back() += t;
}
else {
res.push_back(t);
}
}
if (t == "<") {
inside_template = true;
} }
} }
auto template_start = std::find(toks.begin(), toks.end(), "<");
auto template_end = std::find(toks.rbegin(), toks.rend(), ">");
return res; decltype(res) template_contents(
template_start + 1, template_end.base() - 1);
return clanguml::util::split(
fmt::format("{}", fmt::join(template_contents, "")), ",");
} }
const CXCursor &get() const { return m_cursor; } const CXCursor &get() const { return m_cursor; }

View File

@@ -462,35 +462,18 @@ static enum CXChildVisitResult class_visitor(
tinst.usr = tr.type_declaration().usr(); tinst.usr = tr.type_declaration().usr();
} }
if (!tr.template_argument_type(0).is_invalid()) { const auto &instantiation_params =
for (int i = 0; cursor.tokenize_template_parameters();
i < tr.template_arguments_count(); i++) {
auto template_param =
tr.template_argument_type(i);
class_template ct;
ct.type = template_param.spelling();
tinst.templates.emplace_back(std::move(ct));
spdlog::info( for (const auto &template_param :
"Adding template argument '{}'", instantiation_params) {
template_param);
}
}
else {
const auto &instantiation_params =
cursor.tokenize_template_parameters();
for (const auto &template_param : class_template ct;
instantiation_params) { ct.type = template_param;
tinst.templates.emplace_back(std::move(ct));
class_template ct; spdlog::info("Adding template argument '{}'",
ct.type = template_param; template_param);
tinst.templates.emplace_back(std::move(ct));
spdlog::info(
"Adding template argument '{}'",
template_param);
}
} }
if (partial_specialization) { if (partial_specialization) {

View File

@@ -1,4 +1,5 @@
#include <algorithm> #include <algorithm>
#include <map>
#include <numeric> #include <numeric>
#include <variant> #include <variant>
@@ -14,12 +15,20 @@ template <int... Is> class B {
std::array<int, sizeof...(Is)> ints; std::array<int, sizeof...(Is)> ints;
}; };
template <typename T, int... Is> class C {
std::array<T, sizeof...(Is)> ints;
};
class R { class R {
A<int, std::string, float> a1; A<int, std::string, float> a1;
A<int, std::string, bool> a2; A<int, std::string, bool> a2;
B<3, 2, 1> b1; B<3, 2, 1> b1;
B<1, 1, 1, 1> b2; B<1, 1, 1, 1> b2;
C<std::map<int, std::vector<std::vector<std::vector<std::string>>>>, 3, 3,
3>
c1;
}; };
} }
} }

View File

@@ -47,6 +47,15 @@ TEST_CASE("Test t00012", "[unit-test]")
REQUIRE_THAT(puml, IsClassTemplate("A", "T, Ts...")); REQUIRE_THAT(puml, IsClassTemplate("A", "T, Ts..."));
REQUIRE_THAT(puml, IsClassTemplate("B", "int Is...")); REQUIRE_THAT(puml, IsClassTemplate("B", "int Is..."));
REQUIRE_THAT(puml, IsInstantiation(_A("B<int Is...>"), _A("B<3, 2, 1>")));
REQUIRE_THAT(
puml, IsInstantiation(_A("B<int Is...>"), _A("B<1, 1, 1, 1>")));
REQUIRE_THAT(puml,
IsInstantiation(_A("C<T, int Is...>"),
_A("C<std::map<int, "
"std::vector<std::vector<std::vector<std::string>>>>, 3, 3, "
"3>")));
save_puml( save_puml(
"./" + config.output_directory + "/" + diagram->name + ".puml", puml); "./" + config.output_directory + "/" + diagram->name + ".puml", puml);
} }