From 08d0431a14de1ec07530e2728c91bf3d650b8e99 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Sun, 30 Oct 2022 10:17:47 +0100 Subject: [PATCH] Fixed template function sequence diagram test case --- src/sequence_diagram/model/participant.cc | 126 +++++++++++++----- src/sequence_diagram/model/participant.h | 74 +++++----- .../visitor/translation_unit_visitor.cc | 47 ++++++- .../visitor/translation_unit_visitor.h | 15 ++- tests/t20003/test_case.h | 6 +- 5 files changed, 181 insertions(+), 87 deletions(-) diff --git a/src/sequence_diagram/model/participant.cc b/src/sequence_diagram/model/participant.cc index 8b37dc6d..fe9ca514 100644 --- a/src/sequence_diagram/model/participant.cc +++ b/src/sequence_diagram/model/participant.cc @@ -19,6 +19,50 @@ #include "participant.h" namespace clanguml::sequence_diagram::model { + +std::ostringstream &template_trait::render_template_params( + std::ostringstream &ostr, const common::model::namespace_ &using_namespace, + bool relative) const +{ + using clanguml::common::model::namespace_; + + if (!templates_.empty()) { + std::vector tnames; + std::vector tnames_simplified; + + std::transform(templates_.cbegin(), templates_.cend(), + std::back_inserter(tnames), + [ns = using_namespace, relative]( + const auto &tmplt) { return tmplt.to_string(ns, relative); }); + + ostr << fmt::format("<{}>", fmt::join(tnames, ",")); + } + + return ostr; +} + +void template_trait::set_base_template(const std::string &full_name) +{ + base_template_full_name_ = full_name; +} + +std::string template_trait::base_template() const +{ + return base_template_full_name_; +} + +void template_trait::add_template( + class_diagram::model::template_parameter tmplt) +{ + templates_.push_back(std::move(tmplt)); +} + +const std::vector & +template_trait::templates() const +{ + return templates_; +} + class_::class_(const common::model::namespace_ &using_namespace) : participant{using_namespace} { @@ -42,17 +86,6 @@ void class_::is_template_instantiation(bool is_template_instantiation) is_template_instantiation_ = is_template_instantiation; } -void class_::add_template(class_diagram::model::template_parameter tmplt) -{ - templates_.emplace_back(std::move(tmplt)); -} - -const std::vector & -class_::templates() const -{ - return templates_; -} - std::string class_::full_name_no_ns() const { using namespace clanguml::util; @@ -61,7 +94,7 @@ std::string class_::full_name_no_ns() const ostr << name(); - render_template_params(ostr, false); + render_template_params(ostr, using_namespace(), false); return ostr.str(); } @@ -74,7 +107,7 @@ std::string class_::full_name(bool relative) const std::ostringstream ostr; ostr << name_and_ns(); - render_template_params(ostr, relative); + render_template_params(ostr, using_namespace(), relative); std::string res; @@ -89,26 +122,6 @@ std::string class_::full_name(bool relative) const return res; } -std::ostringstream &class_::render_template_params( - std::ostringstream &ostr, bool relative) const -{ - using clanguml::common::model::namespace_; - - if (!templates_.empty()) { - std::vector tnames; - std::vector tnames_simplified; - - std::transform(templates_.cbegin(), templates_.cend(), - std::back_inserter(tnames), - [ns = using_namespace(), relative]( - const auto &tmplt) { return tmplt.to_string(ns, relative); }); - - ostr << fmt::format("<{}>", fmt::join(tnames, ",")); - } - - return ostr; -} - function::function(const common::model::namespace_ &using_namespace) : participant{using_namespace} { @@ -135,4 +148,51 @@ std::string method::alias() const return fmt::format("C_{:022}", class_id_); } + +function_template::function_template( + const common::model::namespace_ &using_namespace) + : participant{using_namespace} +{ +} + +std::string function_template::full_name(bool relative) const +{ + using namespace clanguml::util; + using clanguml::common::model::namespace_; + + std::ostringstream ostr; + + ostr << name_and_ns(); + render_template_params(ostr, using_namespace(), relative); + + ostr << "()"; + + std::string res; + + if (relative) + res = using_namespace().relative(ostr.str()); + else + res = ostr.str(); + + if (res.empty()) + return "<>"; + + return res; +} + +std::string function_template::full_name_no_ns() const +{ + using namespace clanguml::util; + + std::ostringstream ostr; + + ostr << name(); + + render_template_params(ostr, using_namespace(), false); + + ostr << "()"; + + return ostr.str(); +} + } \ No newline at end of file diff --git a/src/sequence_diagram/model/participant.h b/src/sequence_diagram/model/participant.h index cb22fa3e..1990c7ec 100644 --- a/src/sequence_diagram/model/participant.h +++ b/src/sequence_diagram/model/participant.h @@ -26,6 +26,24 @@ namespace clanguml::sequence_diagram::model { +struct template_trait { + std::ostringstream &render_template_params(std::ostringstream &ostr, + const common::model::namespace_ &using_namespace, bool relative) const; + + void set_base_template(const std::string &full_name); + + std::string base_template() const; + + void add_template(class_diagram::model::template_parameter tmplt); + + const std::vector & + templates() const; + +private: + std::vector templates_; + std::string base_template_full_name_; +}; + struct participant : public common::model::element, public common::model::stylable_element { enum class stereotype_t { @@ -50,30 +68,8 @@ struct participant : public common::model::element, stereotype_t stereotype_{stereotype_t::participant}; }; -// -// struct template_trait { -// void set_base_template(const std::string &full_name) -// { -// base_template_full_name_ = full_name; -// } -// std::string base_template() const { return base_template_full_name_; } -// -// void add_template(class_diagram::model::template_parameter tmplt) -// { -// templates_.push_back(std::move(tmplt)); -// } -// -// const std::vector & -// templates() const -// { -// return templates_; -// } -// -// std::vector templates_; -// std::string base_template_full_name_; -//}; -struct class_ : public participant { +struct class_ : public participant, public template_trait { public: class_(const common::model::namespace_ &using_namespace); @@ -93,14 +89,6 @@ public: bool is_template_instantiation() const; void is_template_instantiation(bool is_template_instantiation); - void add_template(class_diagram::model::template_parameter tmplt); - - const std::vector & - templates() const; - - void set_base_template(const std::string &full_name); - std::string base_template() const; - friend bool operator==(const class_ &l, const class_ &r); std::string full_name(bool relative = true) const override; @@ -113,19 +101,12 @@ public: void is_alias(bool alias) { is_alias_ = alias; } - int calculate_template_specialization_match( - const class_ &other, const std::string &full_name) const; - private: - std::ostringstream &render_template_params( - std::ostringstream &ostr, bool relative) const; - bool is_struct_{false}; bool is_template_{false}; bool is_template_instantiation_{false}; bool is_alias_{false}; - std::vector templates_; - std::string base_template_full_name_; + std::map type_aliases_; @@ -172,6 +153,19 @@ private: std::string method_name_; }; -struct function_template : public participant { }; +struct function_template : public participant, public template_trait { + function_template(const common::model::namespace_ &using_namespace); + + function_template(const function_template &) = delete; + function_template(function_template &&) noexcept = delete; + function_template &operator=(const function_template &) = delete; + function_template &operator=(function_template &&) = delete; + + std::string type_name() const override { return "function_template"; } + + std::string full_name(bool relative = true) const override; + + std::string full_name_no_ns() const override; +}; } diff --git a/src/sequence_diagram/visitor/translation_unit_visitor.cc b/src/sequence_diagram/visitor/translation_unit_visitor.cc index b62a2198..c4e6be4f 100644 --- a/src/sequence_diagram/visitor/translation_unit_visitor.cc +++ b/src/sequence_diagram/visitor/translation_unit_visitor.cc @@ -243,6 +243,13 @@ bool translation_unit_visitor::VisitFunctionDecl(clang::FunctionDecl *f) LOG_DBG("Visiting function declaration {}", function_name); + if (f->isTemplated() && f->getDescribedTemplate()) { + // If the described templated of this function is already in the model + // skip it: + if (get_ast_local_id(f->getDescribedTemplate()->getID())) + return true; + } + auto f_ptr = std::make_unique( config().using_namespace()); @@ -272,9 +279,28 @@ bool translation_unit_visitor::VisitFunctionTemplateDecl( if (!diagram().should_include(function_name)) return true; - LOG_DBG("Visiting function template declaration {}", function_name); + LOG_DBG("Visiting function template declaration {} at {}", function_name, + function_template->getLocation().printToString(source_manager())); + + auto f_ptr = std::make_unique( + config().using_namespace()); + + common::model::namespace_ ns{function_name}; + f_ptr->set_name(ns.name()); + ns.pop_back(); + f_ptr->set_namespace(ns); + + process_template_parameters(*function_template, *f_ptr); + + f_ptr->set_id(common::to_id(f_ptr->full_name(false))); call_expression_context_.update(function_template); + call_expression_context_.set_caller_id(f_ptr->id()); + + set_ast_local_id(function_template->getID(), f_ptr->id()); + + // TODO: Handle overloaded functions with different arguments + diagram().add_participant(std::move(f_ptr)); return true; } @@ -305,7 +331,7 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr) m.from_name = diagram().participants.at(m.from)->full_name(false); const auto ¤t_ast_context = - call_expression_context_.get_ast_context(); + *call_expression_context_.get_ast_context(); if (const auto *operator_call_expr = clang::dyn_cast_or_null(expr); @@ -372,8 +398,17 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr) clang::FunctionTemplateDecl>(decl); m.to_name = to_string(ftd); - m.message_name = to_string(ftd); m.to = get_ast_local_id(ftd->getID()).value(); + auto message_name = + diagram() + .get_participant( + m.to) + .value() + .full_name(false) + .substr(); + m.message_name = + message_name.substr(0, message_name.size() - 2); + break; } } @@ -392,7 +427,7 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr) if (!callee_function) return true; - m.to_name = callee_function->getQualifiedNameAsString() + "()"; + m.to_name = callee_function->getQualifiedNameAsString(); m.message_name = callee_function->getNameAsString(); m.to = get_ast_local_id(callee_function->getID()).value(); } @@ -523,8 +558,8 @@ translation_unit_visitor::create_class_declaration(clang::CXXRecordDecl *cls) } bool translation_unit_visitor::process_template_parameters( - const clang::ClassTemplateDecl &template_declaration, - sequence_diagram::model::class_ &c) + const clang::TemplateDecl &template_declaration, + sequence_diagram::model::template_trait &c) { using class_diagram::model::template_parameter; diff --git a/src/sequence_diagram/visitor/translation_unit_visitor.h b/src/sequence_diagram/visitor/translation_unit_visitor.h index bc4dd548..e66b0c5c 100644 --- a/src/sequence_diagram/visitor/translation_unit_visitor.h +++ b/src/sequence_diagram/visitor/translation_unit_visitor.h @@ -61,10 +61,15 @@ struct call_expression_context { current_class_template_decl_ = clst; } - auto &get_ast_context() + clang::ASTContext *get_ast_context() { - return current_class_decl_ ? current_class_decl_->getASTContext() - : current_function_decl_->getASTContext(); + if(current_class_decl_) + return ¤t_class_decl_->getASTContext(); + + if(current_function_template_decl_) + return ¤t_function_template_decl_->getASTContext(); + + return ¤t_function_decl_->getASTContext(); } void update(clang::CXXMethodDecl *method) { current_method_decl_ = method; } @@ -241,8 +246,8 @@ private: create_class_declaration(clang::CXXRecordDecl *cls); bool process_template_parameters( - const clang::ClassTemplateDecl &template_declaration, - sequence_diagram::model::class_ &c); + const clang::TemplateDecl &template_declaration, + sequence_diagram::model::template_trait &c); // Reference to the output diagram model clanguml::sequence_diagram::model::diagram &diagram_; diff --git a/tests/t20003/test_case.h b/tests/t20003/test_case.h index efe4a4fa..557ba525 100644 --- a/tests/t20003/test_case.h +++ b/tests/t20003/test_case.h @@ -34,9 +34,9 @@ TEST_CASE("t20003", "[test-case][sequence]") REQUIRE_THAT(puml, StartsWith("@startuml")); REQUIRE_THAT(puml, EndsWith("@enduml\n")); - REQUIRE_THAT(puml, HasCall(_A("m1()"), _A("m2()"))); - REQUIRE_THAT(puml, HasCall(_A("m2()"), _A("m3()"))); - REQUIRE_THAT(puml, HasCall(_A("m3()"), _A("m4()"))); + REQUIRE_THAT(puml, HasCall(_A("m1()"), _A("m2()"), "m2")); + REQUIRE_THAT(puml, HasCall(_A("m2()"), _A("m3()"), "m3")); + REQUIRE_THAT(puml, HasCall(_A("m3()"), _A("m4()"), "m4")); save_puml( "./" + config.output_directory() + "/" + diagram->name + ".puml", puml);