diff --git a/src/cx/cursor.h b/src/cx/cursor.h index bef867e0..246ff152 100644 --- a/src/cx/cursor.h +++ b/src/cx/cursor.h @@ -268,36 +268,29 @@ public: std::vector tokenize_template_parameters() const { - const auto &toks = tokenize(); + auto toks = tokenize(); std::vector res; bool inside_template{false}; bool is_namespace{false}; - for (const auto &tok : toks) { - auto t = clanguml::util::trim(tok); - if (t == ">") { - break; - } - if (inside_template) { - if (t == ",") - continue; - if (t == "::") { - 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; + + for (int i = 0; i < toks.size(); i++) { + // libclang returns ">..>>" in template as a single token... + auto t = toks[i]; + if (std::all_of(t.begin(), t.end(), + [](const char &c) { return c == '>'; })) { + toks[i] = ">"; + for (int j = 0; j < t.size() - 1; j++) + toks.insert(toks.begin() + i, ">"); } } + 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; } diff --git a/src/uml/class_diagram_visitor.h b/src/uml/class_diagram_visitor.h index a7bbef69..e46ab6a1 100644 --- a/src/uml/class_diagram_visitor.h +++ b/src/uml/class_diagram_visitor.h @@ -462,35 +462,18 @@ static enum CXChildVisitResult class_visitor( tinst.usr = tr.type_declaration().usr(); } - if (!tr.template_argument_type(0).is_invalid()) { - for (int i = 0; - 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)); + const auto &instantiation_params = + cursor.tokenize_template_parameters(); - spdlog::info( - "Adding template argument '{}'", - template_param); - } - } - else { - const auto &instantiation_params = - cursor.tokenize_template_parameters(); + for (const auto &template_param : + instantiation_params) { - for (const auto &template_param : - instantiation_params) { + class_template ct; + ct.type = template_param; + tinst.templates.emplace_back(std::move(ct)); - class_template ct; - ct.type = template_param; - tinst.templates.emplace_back(std::move(ct)); - - spdlog::info( - "Adding template argument '{}'", - template_param); - } + spdlog::info("Adding template argument '{}'", + template_param); } if (partial_specialization) { diff --git a/tests/t00012/t00012.cc b/tests/t00012/t00012.cc index b11c2979..4419edc0 100644 --- a/tests/t00012/t00012.cc +++ b/tests/t00012/t00012.cc @@ -1,4 +1,5 @@ #include +#include #include #include @@ -14,12 +15,20 @@ template class B { std::array ints; }; +template class C { + std::array ints; +}; + class R { A a1; A a2; B<3, 2, 1> b1; B<1, 1, 1, 1> b2; + + C>>>, 3, 3, + 3> + c1; }; } } diff --git a/tests/t00012/test_case.h b/tests/t00012/test_case.h index b155e1c9..ddd0756b 100644 --- a/tests/t00012/test_case.h +++ b/tests/t00012/test_case.h @@ -47,6 +47,15 @@ TEST_CASE("Test t00012", "[unit-test]") REQUIRE_THAT(puml, IsClassTemplate("A", "T, Ts...")); REQUIRE_THAT(puml, IsClassTemplate("B", "int Is...")); + REQUIRE_THAT(puml, IsInstantiation(_A("B"), _A("B<3, 2, 1>"))); + REQUIRE_THAT( + puml, IsInstantiation(_A("B"), _A("B<1, 1, 1, 1>"))); + REQUIRE_THAT(puml, + IsInstantiation(_A("C"), + _A("C>>>, 3, 3, " + "3>"))); + save_puml( "./" + config.output_directory + "/" + diagram->name + ".puml", puml); }