diff --git a/src/cx/cursor.h b/src/cx/cursor.h index 6e3a45c2..bef867e0 100644 --- a/src/cx/cursor.h +++ b/src/cx/cursor.h @@ -266,6 +266,40 @@ public: return res; } + std::vector tokenize_template_parameters() const + { + const 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; + } + } + + return res; + } + const CXCursor &get() const { return m_cursor; } private: diff --git a/src/cx/type.h b/src/cx/type.h index 60c6a543..4abf2276 100644 --- a/src/cx/type.h +++ b/src/cx/type.h @@ -69,6 +69,8 @@ public: return clang_isRestrictQualifiedType(m_type); } + bool is_invalid() const { return kind() == CXType_Invalid; } + std::string typedef_name() const { return to_string(clang_getTypedefName(m_type)); diff --git a/src/uml/class_diagram_visitor.h b/src/uml/class_diagram_visitor.h index 69431c41..a7bbef69 100644 --- a/src/uml/class_diagram_visitor.h +++ b/src/uml/class_diagram_visitor.h @@ -345,13 +345,18 @@ static enum CXChildVisitResult class_visitor( ret = CXChildVisit_Continue; } break; case CXCursor_NonTypeTemplateParameter: { - spdlog::info("Found template nontype parameter: {}: {}", - cursor.spelling(), cursor.type()); + spdlog::info( + "Found template nontype parameter: {}: {}, isvariadic={}", + cursor.spelling(), cursor.type(), + cursor.is_template_parameter_variadic()); class_template ct; ct.type = cursor.type().canonical().spelling(); ct.name = cursor.spelling(); ct.default_value = ""; + ct.is_variadic = cursor.is_template_parameter_variadic(); + if (ct.is_variadic) + ct.name += "..."; ctx->element.templates.emplace_back(std::move(ct)); ret = CXChildVisit_Continue; @@ -456,13 +461,38 @@ static enum CXChildVisitResult class_visitor( else { tinst.usr = tr.type_declaration().usr(); } - for (int i = 0; i < tr.template_arguments_count(); - i++) { - class_template ct; - ct.type = - tr.template_argument_type(i).spelling(); - tinst.templates.emplace_back(std::move(ct)); + + 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)); + + spdlog::info( + "Adding template argument '{}'", + template_param); + } } + else { + const auto &instantiation_params = + cursor.tokenize_template_parameters(); + + for (const auto &template_param : + instantiation_params) { + + class_template ct; + ct.type = template_param; + tinst.templates.emplace_back(std::move(ct)); + + spdlog::info( + "Adding template argument '{}'", + template_param); + } + } + if (partial_specialization) { tinst.base_template_usr = template_type.usr(); } @@ -496,7 +526,6 @@ static enum CXChildVisitResult class_visitor( } } if (!added_relation_to_instantiation) { - relationship_t relationship_type = relationship_t::kNone; diff --git a/tests/t00012/t00012.cc b/tests/t00012/t00012.cc index 20fbc296..b11c2979 100644 --- a/tests/t00012/t00012.cc +++ b/tests/t00012/t00012.cc @@ -9,5 +9,17 @@ template class A { T value; std::variant values; }; + +template class B { + std::array ints; +}; + +class R { + A a1; + A a2; + + B<3, 2, 1> b1; + B<1, 1, 1, 1> b2; +}; } } diff --git a/tests/t00012/test_case.h b/tests/t00012/test_case.h index fe770bbb..b155e1c9 100644 --- a/tests/t00012/test_case.h +++ b/tests/t00012/test_case.h @@ -45,6 +45,7 @@ TEST_CASE("Test t00012", "[unit-test]") REQUIRE_THAT(puml, StartsWith("@startuml")); REQUIRE_THAT(puml, EndsWith("@enduml\n")); REQUIRE_THAT(puml, IsClassTemplate("A", "T, Ts...")); + REQUIRE_THAT(puml, IsClassTemplate("B", "int Is...")); save_puml( "./" + config.output_directory + "/" + diagram->name + ".puml", puml);