diff --git a/src/uml/class_diagram_visitor.h b/src/uml/class_diagram_visitor.h index 07f89a25..2f2c1a66 100644 --- a/src/uml/class_diagram_visitor.h +++ b/src/uml/class_diagram_visitor.h @@ -103,56 +103,14 @@ scope_t cx_access_specifier_to_scope(CX_CXXAccessSpecifier as) return res; } -cx::type get_underlying_type(cx::type t) -{ - if (t.is_array()) { - return t.array_type(); - } - - auto template_arguments_count = t.template_arguments_count(); - - if (template_arguments_count == 0) - return t; - - auto name = t.canonical().unqualified(); - - std::vector template_arguments; - for (int i = 0; i < template_arguments_count; i++) { - auto tt = t.template_argument_type(i); - template_arguments.push_back(tt); - } - - if (name.find("std::unique_ptr") == 0) { - return get_underlying_type(template_arguments[0]); - } - if (name.find("std::shared_ptr") == 0) { - return get_underlying_type(template_arguments[0]); - } - if (name.find("std::vector") == 0) { - return get_underlying_type(template_arguments[0]); - } - if (name.find("std::array") == 0) { - return get_underlying_type(template_arguments[0]); - } - if (name.find("clanguml::t00006::custom_container") == 0) { - return get_underlying_type(template_arguments[0]); - } - if (name.find("std::map") == 0) { - return get_underlying_type(template_arguments[1]); - } - if (name.find("std::pair") == 0) { - return get_underlying_type(template_arguments[1]); - } - - return t; -} - -relationship_t get_relationship_type(cx::type t) +void find_relationships( + cx::type t, std::vector> &relationships) { relationship_t relationship_type = relationship_t::kNone; if (t.is_array()) { - return get_relationship_type(t.array_type()); + find_relationships(t.array_type(), relationships); + return; } auto name = t.canonical().unqualified(); @@ -169,44 +127,35 @@ relationship_t get_relationship_type(cx::type t) } if (name.find("std::unique_ptr") == 0) { - relationship_type = relationship_t::kComposition; - return get_relationship_type(template_arguments[0]); + find_relationships(template_arguments[0], relationships); } - if (name.find("std::shared_ptr") == 0) { - relationship_type = relationship_t::kAssociation; - return get_relationship_type(template_arguments[0]); + else if (name.find("std::shared_ptr") == 0) { + find_relationships(template_arguments[0], relationships); } - if (name.find("std::vector") == 0) { - relationship_type = relationship_t::kComposition; - return get_relationship_type(template_arguments[0]); + else if (name.find("std::vector") == 0) { + find_relationships(template_arguments[0], relationships); } - if (name.find("std::array") == 0) { - relationship_type = relationship_t::kComposition; - return get_relationship_type(template_arguments[0]); + else if (name.find("std::array") == 0) { + find_relationships(template_arguments[0], relationships); } - if (name.find("clanguml::t00006::custom_container") == 0) { - relationship_type = relationship_t::kComposition; - return get_relationship_type(template_arguments[0]); - } - if (name.find("std::map") == 0) { - relationship_type = relationship_t::kComposition; - return get_relationship_type(template_arguments[1]); + else { + for (const auto type : template_arguments) { + find_relationships(type, relationships); + } } } else if (t.kind() == CXType_Record) { - relationship_type = relationship_t::kOwnership; + relationships.emplace_back(t, relationship_t::kOwnership); } else if (t.kind() == CXType_Pointer) { - relationship_type = relationship_t::kAssociation; + relationships.emplace_back(t, relationship_t::kAssociation); } else if (t.kind() == CXType_LValueReference) { - relationship_type = relationship_t::kAssociation; + relationships.emplace_back(t, relationship_t::kAssociation); } else if (t.kind() == CXType_RValueReference) { - relationship_type = relationship_t::kOwnership; + relationships.emplace_back(t, relationship_t::kOwnership); } - - return relationship_type; } static enum CXChildVisitResult enum_visitor( @@ -389,22 +338,24 @@ static enum CXChildVisitResult class_visitor( if (t.is_relationship() && (config.should_include(t.canonical().unqualified()) || t.is_template() || t.is_array())) { - relationship_t relationship_type = - get_relationship_type(t); + std::vector> + relationships{}; + find_relationships(t, relationships); - if (relationship_type != relationship_t::kNone) { - class_relationship r; - r.destination = get_underlying_type(t) - .referenced() - .canonical() - .unqualified(); - r.type = relationship_type; - r.label = m.name; - ctx->element.relationships.emplace_back( - std::move(r)); + for (const auto &[type, relationship_type] : + relationships) { + if (relationship_type != relationship_t::kNone) { + class_relationship r; + r.destination = + type.referenced().canonical().unqualified(); + r.type = relationship_type; + r.label = m.name; + ctx->element.relationships.emplace_back( + std::move(r)); - spdlog::info( - "Added relationship to: {}", r.destination); + spdlog::info( + "Added relationship to: {}", r.destination); + } } } diff --git a/tests/t00006/t00006.cc b/tests/t00006/t00006.cc index e6dc2b77..f1bd5d2e 100644 --- a/tests/t00006/t00006.cc +++ b/tests/t00006/t00006.cc @@ -36,6 +36,21 @@ class J { class K { }; +class L { +}; + +class M { +}; + +class N { +}; + +class NN { +}; + +class NNN { +}; + template class custom_container { public: std::vector data; @@ -59,6 +74,10 @@ public: J j[10]; K *k[20]; + + std::vector> lm; + + std::tuple ns; }; } } diff --git a/tests/t00006/test_case.h b/tests/t00006/test_case.h index 3362bab3..063c6c18 100644 --- a/tests/t00006/test_case.h +++ b/tests/t00006/test_case.h @@ -57,7 +57,11 @@ TEST_CASE("Test t00006", "[unit-test]") REQUIRE_THAT(puml, IsClass("I")); REQUIRE_THAT(puml, IsClass("J")); REQUIRE_THAT(puml, IsClass("K")); - REQUIRE_THAT(puml, IsClass("R")); + REQUIRE_THAT(puml, IsClass("L")); + REQUIRE_THAT(puml, IsClass("M")); + REQUIRE_THAT(puml, IsClass("N")); + REQUIRE_THAT(puml, IsClass("NN")); + REQUIRE_THAT(puml, IsClass("NNN")); REQUIRE_THAT(puml, IsComposition("R", "A", "a")); REQUIRE_THAT(puml, IsAssociation("R", "B", "b")); @@ -70,6 +74,11 @@ TEST_CASE("Test t00006", "[unit-test]") REQUIRE_THAT(puml, IsAssociation("R", "I", "i")); REQUIRE_THAT(puml, IsComposition("R", "J", "j")); REQUIRE_THAT(puml, IsAssociation("R", "K", "k")); + REQUIRE_THAT(puml, IsComposition("R", "L", "lm")); + REQUIRE_THAT(puml, IsComposition("R", "M", "lm")); + REQUIRE_THAT(puml, IsComposition("R", "N", "ns")); + REQUIRE_THAT(puml, IsComposition("R", "NN", "ns")); + REQUIRE_THAT(puml, IsComposition("R", "NNN", "ns")); save_puml( "./" + config.output_directory + "/" + diagram->name + ".puml", puml);