diff --git a/src/class_diagram/visitor/translation_unit_visitor.cc b/src/class_diagram/visitor/translation_unit_visitor.cc index 7605b5f6..36be559b 100644 --- a/src/class_diagram/visitor/translation_unit_visitor.cc +++ b/src/class_diagram/visitor/translation_unit_visitor.cc @@ -405,10 +405,10 @@ bool translation_unit_visitor::process_template_parameters( // Add specialization arguments if (tspec) { if (!tspec.value().arguments_exposed()) { - process_unexposed_template_specialization_arguments(tspec, c); + process_unexposed_template_specialization_parameters(tspec, c); } else { - process_exposed_template_specialization_arguments(tspec, c); + process_exposed_template_specialization_parameters(tspec, c); } } else { @@ -451,7 +451,7 @@ void translation_unit_visitor::process_scope_template_parameters( } void translation_unit_visitor:: - process_exposed_template_specialization_arguments( + process_exposed_template_specialization_parameters( const type_safe::optional_ref &tspec, class_ &c) @@ -488,7 +488,7 @@ void translation_unit_visitor:: } void translation_unit_visitor:: - process_unexposed_template_specialization_arguments( + process_unexposed_template_specialization_parameters( const type_safe::optional_ref &tspec, class_ &c) const @@ -505,7 +505,7 @@ void translation_unit_visitor:: .primary_template() .get(ctx.entity_index()) .size() == 0) { - LOG_WARN("Template {} has no exposed arguments", + LOG_WARN("Template {} has no exposed parameters", tspec.value().name()); continue; @@ -1211,8 +1211,7 @@ void translation_unit_visitor::process_friend( } bool translation_unit_visitor::find_relationships(const cppast::cpp_type &t_, - std::vector> &relationships, - relationship_t relationship_hint) + found_relationships_t &relationships, relationship_t relationship_hint) { bool found{false}; @@ -1227,35 +1226,92 @@ bool translation_unit_visitor::find_relationships(const cppast::cpp_type &t_, relationship_t relationship_type = relationship_hint; const auto &t = cppast::remove_cv(cx::util::unreferenced(t_)); + auto name = cppast::to_string(t); + if (t.kind() == cppast::cpp_type_kind::array_t) { - auto &a = static_cast(t); - found = find_relationships( - a.value_type(), relationships, relationship_t::kAggregation); - return found; + found = find_relationships_in_array(relationships, t); } + else if (t_.kind() == cppast::cpp_type_kind::pointer_t) { + found = + find_relationships_in_pointer(t_, relationships, relationship_hint); + } + else if (t_.kind() == cppast::cpp_type_kind::reference_t) { + found = find_relationships_in_reference( + t_, relationships, relationship_hint); + } + else if (cppast::remove_cv(t_).kind() == + cppast::cpp_type_kind::user_defined_t) { + found = find_relationships_in_user_defined_type( + t_, relationships, fn, relationship_type, t); + } + else if (t.kind() == cppast::cpp_type_kind::template_instantiation_t) { + found = find_relationships_in_template_instantiation( + t, fn, relationships, relationship_type); + } + + return found; +} + +bool translation_unit_visitor::find_relationships_in_template_instantiation( + const cppast::cpp_type &t_, const std::string &fn, + found_relationships_t &relationships, relationship_t relationship_type) +{ + const auto &t = cppast::remove_cv(cx::util::unreferenced(t_)); + + const auto &tinst = + static_cast(t); auto name = cppast::to_string(t); - if (t_.kind() == cppast::cpp_type_kind::pointer_t) { - auto &p = static_cast(t_); - auto rt = relationship_t::kAssociation; - if (relationship_hint == relationship_t::kDependency) - rt = relationship_hint; - found = find_relationships(p.pointee(), relationships, rt); + bool found = false; + + if (!tinst.arguments_exposed()) { + LOG_DBG("Template instantiation {} has no exposed arguments", name); + + return found; } - else if (t_.kind() == cppast::cpp_type_kind::reference_t) { - auto &r = static_cast(t_); - auto rt = relationship_t::kAssociation; - if (r.reference_kind() == cppast::cpp_reference::cpp_ref_rvalue) { - rt = relationship_t::kAggregation; - } - if (relationship_hint == relationship_t::kDependency) - rt = relationship_hint; - found = find_relationships(r.referee(), relationships, rt); + + assert(tinst.arguments().has_value()); + assert(tinst.arguments().value().size() > 0u); + + [[maybe_unused]] const auto args_count = tinst.arguments().value().size(); + + const auto args = tinst.arguments().value(); + + const auto [ns, base_name] = cx::util::split_ns(fn); + + auto ns_and_name = ns; + ns_and_name.push_back(base_name); + + auto full_name = fmt::format("{}", fmt::join(ns_and_name, "::")); + + // Try to match common containers + // TODO: Refactor to a separate class with configurable + // container list + if (full_name.find("std::unique_ptr") == 0) { + found = find_relationships(args[0u].type().value(), relationships, + relationship_t::kAggregation); } - if (cppast::remove_cv(t_).kind() == cppast::cpp_type_kind::user_defined_t) { - LOG_DBG("User defined type: {} | {}", cppast::to_string(t_), - cppast::to_string(t_.canonical())); + else if (full_name.find("std::shared_ptr") == 0) { + found = find_relationships(args[0u].type().value(), relationships, + relationship_t::kAssociation); + } + else if (full_name.find("std::weak_ptr") == 0) { + found = find_relationships(args[0u].type().value(), relationships, + relationship_t::kAssociation); + } + else if (full_name.find("std::vector") == 0) { + if (args[0u].type().has_value()) + found = find_relationships(args[0u].type().value(), relationships, + relationship_t::kAggregation); + else + LOG_WARN( + "Failed to process template argument of std::vector at: {}", + fn); + } + else if (ctx.config().should_include(ns, name)) { + LOG_DBG("User defined template instantiation: {} | {}", + cppast::to_string(t_), cppast::to_string(t_.canonical())); if (relationship_type != relationship_t::kNone) relationships.emplace_back(cppast::to_string(t), relationship_type); @@ -1269,94 +1325,13 @@ bool translation_unit_visitor::find_relationships(const cppast::cpp_type &t_, cppast::to_string(ctx.get_type_alias(fn).get())); found = find_relationships( ctx.get_type_alias(fn).get(), relationships, relationship_type); - if (found) - return found; } } - else if (t.kind() == cppast::cpp_type_kind::template_instantiation_t) { - // class_relationship r; - - const auto &tinst = - static_cast(t); - - if (!tinst.arguments_exposed()) { - LOG_DBG("Template instantiation {} has no exposed arguments", name); - - return found; - } - - assert(tinst.arguments().has_value()); - assert(tinst.arguments().value().size() > 0u); - - [[maybe_unused]] const auto args_count = - tinst.arguments().value().size(); - - const auto args = tinst.arguments().value(); - - const auto [ns, base_name] = cx::util::split_ns(fn); - - auto ns_and_name = ns; - ns_and_name.push_back(base_name); - - auto full_name = fmt::format("{}", fmt::join(ns_and_name, "::")); - - // Try to match common containers - // TODO: Refactor to a separate class with configurable - // container list - if (full_name.find("std::unique_ptr") == 0) { - found = find_relationships(args[0u].type().value(), relationships, - relationship_t::kAggregation); - } - else if (full_name.find("std::shared_ptr") == 0) { - found = find_relationships(args[0u].type().value(), relationships, - relationship_t::kAssociation); - } - else if (full_name.find("std::weak_ptr") == 0) { - found = find_relationships(args[0u].type().value(), relationships, - relationship_t::kAssociation); - } - else if (full_name.find("std::vector") == 0) { - assert(args.size() == 1u); - if (args[0u].type().has_value()) - found = find_relationships(args[0u].type().value(), - relationships, relationship_t::kAggregation); - else - LOG_WARN( - "Failed to process template argument of std::vector at: {}", - fn); - } - else if (ctx.config().should_include(ns, name)) { - LOG_DBG("User defined template instantiation: {} | {}", - cppast::to_string(t_), cppast::to_string(t_.canonical())); - - if (relationship_type != relationship_t::kNone) - relationships.emplace_back( - cppast::to_string(t), relationship_type); - else - relationships.emplace_back( - cppast::to_string(t), relationship_t::kAggregation); - - // Check if t_ has an alias in the alias index - if (ctx.has_type_alias(fn)) { - LOG_DBG("Find relationship in alias of {} | {}", fn, - cppast::to_string(ctx.get_type_alias(fn).get())); - found = find_relationships(ctx.get_type_alias(fn).get(), - relationships, relationship_type); - if (found) - return found; - } - - return found; - } - // ??? - else { - for (const auto &arg : args) { - if (arg.type().has_value()) { - LOG_DBG("########## PROCESSING PARAMETER TYPE: {}", - cppast::to_string(arg.type().value())); - found = find_relationships( - arg.type().value(), relationships, relationship_type); - } + else { + for (const auto &arg : args) { + if (arg.type().has_value()) { + found = find_relationships( + arg.type().value(), relationships, relationship_type); } } } @@ -1364,6 +1339,70 @@ bool translation_unit_visitor::find_relationships(const cppast::cpp_type &t_, return found; } +bool translation_unit_visitor::find_relationships_in_user_defined_type( + const cppast::cpp_type &t_, found_relationships_t &relationships, + const std::string &fn, relationship_t &relationship_type, + const cppast::cpp_type &t) +{ + bool found; + LOG_DBG("Finding relationships in user defined type: {} | {}", + cppast::to_string(t_), cppast::to_string(t_.canonical())); + + if (relationship_type != relationship_t::kNone) + relationships.emplace_back(cppast::to_string(t), relationship_type); + else + relationships.emplace_back( + cppast::to_string(t), relationship_t::kAggregation); + + // Check if t_ has an alias in the alias index + if (ctx.has_type_alias(fn)) { + LOG_DBG("Find relationship in alias of {} | {}", fn, + cppast::to_string(ctx.get_type_alias(fn).get())); + found = find_relationships( + ctx.get_type_alias(fn).get(), relationships, relationship_type); + } + return found; +} + +bool translation_unit_visitor::find_relationships_in_reference( + const cppast::cpp_type &t_, found_relationships_t &relationships, + const relationship_t &relationship_hint) +{ + bool found; + auto &r = static_cast(t_); + auto rt = relationship_t::kAssociation; + if (r.reference_kind() == cppast::cpp_ref_rvalue) { + rt = relationship_t::kAggregation; + } + if (relationship_hint == relationship_t::kDependency) + rt = relationship_hint; + found = find_relationships(r.referee(), relationships, rt); + return found; +} + +bool translation_unit_visitor::find_relationships_in_pointer( + const cppast::cpp_type &t_, found_relationships_t &relationships, + const relationship_t &relationship_hint) +{ + bool found; + auto &p = static_cast(t_); + auto rt = relationship_t::kAssociation; + if (relationship_hint == relationship_t::kDependency) + rt = relationship_hint; + found = find_relationships(p.pointee(), relationships, rt); + return found; +} + +bool translation_unit_visitor::find_relationships_in_array( + found_relationships_t &relationships, const cppast::cpp_type &t) +{ + bool found; + auto &a = static_cast(t); + found = find_relationships( + a.value_type(), relationships, relationship_t::kAggregation); + return found; +} + std::unique_ptr translation_unit_visitor::build_template_instantiation( const cppast::cpp_template_instantiation_type &t, std::optional parent) diff --git a/src/class_diagram/visitor/translation_unit_visitor.h b/src/class_diagram/visitor/translation_unit_visitor.h index b46972d3..3805b19b 100644 --- a/src/class_diagram/visitor/translation_unit_visitor.h +++ b/src/class_diagram/visitor/translation_unit_visitor.h @@ -34,6 +34,7 @@ #include #include +#include #include #include #include @@ -43,6 +44,9 @@ namespace clanguml::class_diagram::visitor { +using found_relationships_t = + std::vector>; + class translation_unit_visitor { public: translation_unit_visitor(cppast::cpp_entity_index &idx, @@ -101,8 +105,7 @@ public: const std::set &template_parameter_names = {}); bool find_relationships(const cppast::cpp_type &t, - std::vector> &relationships, + found_relationships_t &relationships, clanguml::common::model::relationship_t relationship_hint = clanguml::common::model::relationship_t::kNone); @@ -133,12 +136,12 @@ public: void process_class_bases( const cppast::cpp_class &cls, model::class_ &c) const; - void process_unexposed_template_specialization_arguments( + void process_unexposed_template_specialization_parameters( const type_safe::optional_ref &tspec, model::class_ &c) const; - void process_exposed_template_specialization_arguments( + void process_exposed_template_specialization_parameters( const type_safe::optional_ref &tspec, model::class_ &c); @@ -165,9 +168,30 @@ private: * If t does not represent an alias, returns t. */ const cppast::cpp_type &resolve_alias(const cppast::cpp_type &t); + const cppast::cpp_type &resolve_alias_template( const cppast::cpp_type &type); + bool find_relationships_in_array( + found_relationships_t &relationships, const cppast::cpp_type &t); + + bool find_relationships_in_pointer(const cppast::cpp_type &t_, + found_relationships_t &relationships, + const common::model::relationship_t &relationship_hint); + + bool find_relationships_in_reference(const cppast::cpp_type &t_, + found_relationships_t &relationships, + const common::model::relationship_t &relationship_hint); + + bool find_relationships_in_user_defined_type(const cppast::cpp_type &t_, + found_relationships_t &relationships, const std::string &fn, + common::model::relationship_t &relationship_type, + const cppast::cpp_type &t); + + bool find_relationships_in_template_instantiation(const cppast::cpp_type &t, + const std::string &fn, found_relationships_t &relationships, + common::model::relationship_t relationship_type); + // ctx allows to track current visitor context, e.g. current namespace translation_unit_context ctx; };