diff --git a/src/uml/class_diagram_visitor.cc b/src/uml/class_diagram_visitor.cc index 9dc11e36..f52d74e2 100644 --- a/src/uml/class_diagram_visitor.cc +++ b/src/uml/class_diagram_visitor.cc @@ -520,13 +520,14 @@ void tu_visitor::process_function_parameter( // find relationship for the type std::vector> relationships; - find_relationships(param.type(), relationships); + find_relationships(cppast::remove_cv(param.type()), relationships, + relationship_t::kDependency); for (const auto &[type, relationship_type] : relationships) { if ((relationship_type != relationship_t::kNone) && (type != c.name)) { class_relationship r; r.destination = type; r.type = relationship_t::kDependency; - r.label = mp.name; + r.label = ""; spdlog::debug("Adding field relationship {} {} {} : {}", r.destination, model::class_diagram::to_string(r.type), c.usr, @@ -536,6 +537,50 @@ void tu_visitor::process_function_parameter( } } + // Also consider the container itself if it is user defined type + const auto &t = cppast::remove_cv(cx::util::unreferenced(param.type())); + spdlog::debug("###### {}", cppast::to_string(t)); + if (t.kind() == cppast::cpp_type_kind::template_instantiation_t) { + auto &template_instantiation_type = + static_cast(t); + if (template_instantiation_type.primary_template() + .get(ctx.entity_index) + .size()) { + // Here we need the name of the primary template with full + // namespace prefix to apply config inclusion filters + auto primary_template_name = cx::util::full_name( + template_instantiation_type.primary_template() + .get(ctx.entity_index)[0] + .get()); + + spdlog::debug( + "Maybe building instantiation for: {}", primary_template_name); + + if (ctx.config.should_include(primary_template_name)) { + class_ tinst = build_template_instantiation( + param, template_instantiation_type); + + class_relationship r; + r.destination = tinst.base_template_usr; + r.type = relationship_t::kInstantiation; + r.label = ""; + tinst.add_relationship(std::move(r)); + + class_relationship rr; + rr.destination = tinst.usr; + rr.type = relationship_t::kDependency; + rr.label = ""; + spdlog::debug( + "Adding field instantiation relationship {} {} {} : {}", + rr.destination, model::class_diagram::to_string(rr.type), + c.usr, rr.label); + c.add_relationship(std::move(rr)); + + ctx.d.add_class(std::move(tinst)); + } + } + } + m.parameters.emplace_back(std::move(mp)); } @@ -639,7 +684,8 @@ void tu_visitor::find_relationships(const cppast::cpp_type &t_, std::vector> &relationships, relationship_t relationship_hint) { - spdlog::debug("Finding relationships for type {}", cppast::to_string(t_)); + spdlog::debug("Finding relationships for type {}, {}", + cppast::to_string(t_), t_.kind()); relationship_t relationship_type = relationship_hint; const auto &t = cppast::remove_cv(cx::util::unreferenced(t_)); @@ -697,8 +743,10 @@ void tu_visitor::find_relationships(const cppast::cpp_type &t_, } else if (t_.kind() == cppast::cpp_type_kind::pointer_t) { auto &p = static_cast(t_); - find_relationships( - p.pointee(), relationships, relationship_t::kAssociation); + auto rt = relationship_t::kAssociation; + if (relationship_hint == relationship_t::kDependency) + rt = relationship_hint; + find_relationships(p.pointee(), relationships, rt); } else if (t_.kind() == cppast::cpp_type_kind::reference_t) { auto &r = static_cast(t_); @@ -706,6 +754,8 @@ void tu_visitor::find_relationships(const cppast::cpp_type &t_, if (r.reference_kind() == cppast::cpp_reference::cpp_ref_rvalue) { rt = relationship_t::kComposition; } + if (relationship_hint == relationship_t::kDependency) + rt = relationship_hint; find_relationships(r.referee(), relationships, rt); } else if (cppast::remove_cv(t_).kind() == @@ -713,28 +763,33 @@ void tu_visitor::find_relationships(const cppast::cpp_type &t_, if (ctx.config.should_include(cppast::to_string(t_.canonical()))) if (relationship_type != relationship_t::kNone) relationships.emplace_back( - cppast::to_string(cppast::remove_cv(t_)), - relationship_type); + cppast::to_string(t), relationship_type); else relationships.emplace_back( - cppast::to_string(cppast::remove_cv(t_)), - relationship_t::kComposition); + cppast::to_string(t), relationship_t::kComposition); } } class_ tu_visitor::build_template_instantiation(const cppast::cpp_entity &e, const cppast::cpp_template_instantiation_type &t) { - spdlog::debug("Found template instantiation: {} ({}) ..|> {}", + auto full_template_name = cx::util::full_name( + t.primary_template().get(ctx.entity_index)[0].get()); + + spdlog::debug("Found template instantiation: {} ({}) ..|> {}, {}", cppast::to_string(t), cppast::to_string(t.canonical()), - t.primary_template().name()); + t.primary_template().name(), full_template_name); class_ tinst; const auto &primary_template_ref = static_cast( t.primary_template().get(ctx.entity_index)[0].get()) .class_(); + tinst.name = primary_template_ref.name(); + if(full_template_name.back() == ':') + tinst.name = full_template_name + tinst.name; + if (primary_template_ref.user_data()) tinst.base_template_usr = static_cast(primary_template_ref.user_data()); diff --git a/tests/t00008/test_case.h b/tests/t00008/test_case.h index 678048c5..893d55b5 100644 --- a/tests/t00008/test_case.h +++ b/tests/t00008/test_case.h @@ -42,15 +42,19 @@ TEST_CASE("t00008", "[test-case][class]") REQUIRE_THAT(puml, StartsWith("@startuml")); REQUIRE_THAT(puml, EndsWith("@enduml\n")); - REQUIRE_THAT(puml, IsClassTemplate("A", "T, P, bool (*)(int, int), int N")); + //TODO: add option to resolve using declared types + //REQUIRE_THAT(puml, IsClassTemplate("A", "T, P, bool (*)(int, int), int N")); + REQUIRE_THAT(puml, IsClassTemplate("A", "T, P, CMP, int N")); REQUIRE_THAT(puml, IsClassTemplate("B", "T, C<>")); 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("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"))); + REQUIRE_THAT(puml, IsField(Public("std::array ints"))); + //TODO: add option to resolve using declared types + //REQUIRE_THAT(puml, IsField(Public("bool (*)(int, int) comparator"))); + REQUIRE_THAT(puml, IsField(Public("CMP comparator"))); save_puml( "./" + config.output_directory + "/" + diagram->name + ".puml", puml); diff --git a/tests/t00013/t00013.cc b/tests/t00013/t00013.cc index a8503165..dc8ca465 100644 --- a/tests/t00013/t00013.cc +++ b/tests/t00013/t00013.cc @@ -45,7 +45,7 @@ public: // Dependency relationship should be rendered only once int get_d2(D &&d) { return d.d; } - template T get_e(E &e) { return e.e; } + template T get_e(E e) { return e.e; } int get_int_e(const E &e) { return e.e; } int get_int_e2(E &e) { return e.e; } diff --git a/tests/t00014/test_case.h b/tests/t00014/test_case.h index 28fa82a7..15321415 100644 --- a/tests/t00014/test_case.h +++ b/tests/t00014/test_case.h @@ -40,7 +40,7 @@ TEST_CASE("t00014", "[test-case][class]") REQUIRE_THAT(puml, StartsWith("@startuml")); REQUIRE_THAT(puml, EndsWith("@enduml\n")); - REQUIRE_THAT(puml, IsClass(_A("S"))); + REQUIRE_THAT(puml, IsClassTemplate("A", "T, P")); /* REQUIRE_THAT(puml, IsClass(_A("B"))); REQUIRE_THAT(puml, IsClass(_A("C")));