From 25254fc81d1c4e6a50279c49f9693d20288b40ee Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Sat, 6 Mar 2021 20:41:29 +0100 Subject: [PATCH] Added handling of nontype template parameters --- src/cx/cursor.h | 19 +++++++++++++++++++ src/puml/class_diagram_generator.h | 20 ++++++++++++++++++-- src/uml/class_diagram_model.h | 2 ++ src/uml/class_diagram_visitor.h | 27 +++++++++++++++++---------- tests/t00008/t00008.cc | 8 +++++++- tests/t00008/test_case.h | 4 +++- 6 files changed, 66 insertions(+), 14 deletions(-) diff --git a/src/cx/cursor.h b/src/cx/cursor.h index b6e549bc..57fb9408 100644 --- a/src/cx/cursor.h +++ b/src/cx/cursor.h @@ -223,3 +223,22 @@ private: }; } } + +template <> struct fmt::formatter { + template constexpr auto parse(ParseContext &ctx) + { + return ctx.begin(); + } + + template + auto format(const clanguml::cx::cursor &c, FormatContext &ctx) + { + return fmt::format_to(ctx.out(), + "(cx::cursor spelling={}, display_name={}, kind={}, " + "is_expression={}, template_argument_count={})", + c.spelling(), c.display_name(), c.kind_spelling(), + c.is_expression(), c.template_argument_count() + + ); + } +}; diff --git a/src/puml/class_diagram_generator.h b/src/puml/class_diagram_generator.h index 758fd54f..af593fb3 100644 --- a/src/puml/class_diagram_generator.h +++ b/src/puml/class_diagram_generator.h @@ -105,8 +105,24 @@ public: if (!c.templates.empty()) { std::vector tnames; std::transform(c.templates.cbegin(), c.templates.cend(), - std::back_inserter(tnames), - [](const auto &tmplt) { return tmplt.name; }); + std::back_inserter(tnames), [this](const auto &tmplt) { + std::vector res; + + if (!tmplt.type.empty()) + res.push_back( + ns_relative(m_config.using_namespace, tmplt.type)); + + if (!tmplt.name.empty()) + res.push_back( + ns_relative(m_config.using_namespace, tmplt.name)); + + if (!tmplt.default_value.empty()) { + res.push_back("="); + res.push_back(tmplt.default_value); + } + + return fmt::format("{}", fmt::join(res, " ")); + }); ostr << fmt::format("<{}>", fmt::join(tnames, ", ")); } diff --git a/src/uml/class_diagram_model.h b/src/uml/class_diagram_model.h index 31942ee8..e44e850a 100644 --- a/src/uml/class_diagram_model.h +++ b/src/uml/class_diagram_model.h @@ -89,6 +89,8 @@ struct class_relationship { struct class_template { std::string name; + std::string type; + std::string default_value; }; struct class_ : public element { diff --git a/src/uml/class_diagram_visitor.h b/src/uml/class_diagram_visitor.h index 73419992..9ce91646 100644 --- a/src/uml/class_diagram_visitor.h +++ b/src/uml/class_diagram_visitor.h @@ -209,9 +209,8 @@ static enum CXChildVisitResult class_visitor( std::string cursor_name_str = cursor.spelling(); - spdlog::info("Visiting {}: {} - {}:{}", - ctx->element.is_struct ? "struct" : "class", ctx->element.name, - cursor_name_str, cursor.kind()); + spdlog::info("Visiting {}: {} - {}", + ctx->element.is_struct ? "struct" : "class", ctx->element.name, cursor); auto &config = ctx->ctx->config; @@ -285,19 +284,27 @@ static enum CXChildVisitResult class_visitor( ret = CXChildVisit_Continue; break; case CXCursor_TemplateTypeParameter: { - spdlog::info( - "Found template type parameter: {}", cursor.spelling()); + spdlog::info("Found template type parameter: {}: {}", + cursor.spelling(), cursor.type()); class_template ct; + ct.type = ""; ct.name = cursor.spelling(); + ct.default_value = ""; ctx->element.templates.emplace_back(std::move(ct)); ret = CXChildVisit_Continue; } break; - case CXCursor_NonTypeTemplateParameter: - spdlog::info( - "Found template nontype parameter: {}", cursor.spelling()); + case CXCursor_NonTypeTemplateParameter: { + spdlog::info("Found template nontype parameter: {}: {}", + cursor.spelling(), cursor.type()); + class_template ct; + ct.type = cursor.type().canonical().spelling(); + ct.name = cursor.spelling(); + ct.default_value = ""; + ctx->element.templates.emplace_back(std::move(ct)); + ret = CXChildVisit_Continue; - break; + } break; case CXCursor_TemplateTemplateParameter: spdlog::info( "Found template template parameter: {}", cursor.spelling()); @@ -468,7 +475,7 @@ static enum CXChildVisitResult translation_unit_visitor( case CXCursor_ClassTemplate: [[fallthrough]]; case CXCursor_ClassDecl: { - spdlog::debug("Found class or class template declaration: {}", + spdlog::info("Found class or class template declaration: {}", cursor_name_str); if (!ctx->config.should_include(cursor.fully_qualified())) { ret = CXChildVisit_Continue; diff --git a/tests/t00008/t00008.cc b/tests/t00008/t00008.cc index 94c0b5bf..47ff3aca 100644 --- a/tests/t00008/t00008.cc +++ b/tests/t00008/t00008.cc @@ -1,13 +1,19 @@ +#include #include namespace clanguml { namespace t00008 { -template class A { + +using CMP = bool (*)(const int, const int); +template class A { public: T value; T *pointer; T &reference; std::vector

values; + std::array ints; + + CMP comparator; }; } } diff --git a/tests/t00008/test_case.h b/tests/t00008/test_case.h index efcba415..a2949d4d 100644 --- a/tests/t00008/test_case.h +++ b/tests/t00008/test_case.h @@ -43,12 +43,14 @@ TEST_CASE("Test t00008", "[unit-test]") REQUIRE_THAT(puml, StartsWith("@startuml")); REQUIRE_THAT(puml, EndsWith("@enduml\n")); - REQUIRE_THAT(puml, IsClassTemplate("A", "T, P")); + REQUIRE_THAT(puml, IsClassTemplate("A", "T, P, bool (*)(int, int), int N")); REQUIRE_THAT(puml, IsField(Public("T value"))); REQUIRE_THAT(puml, IsField(Public("T * pointer"))); REQUIRE_THAT(puml, IsField(Public("T & reference"))); REQUIRE_THAT(puml, IsField(Public("std::vector

values"))); + REQUIRE_THAT(puml, IsField(Public("std::array ints"))); + REQUIRE_THAT(puml, IsField(Public("bool (*)(int, int) comparator"))); save_puml( "./" + config.output_directory + "/" + diagram->name + ".puml", puml);