diff --git a/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc index 13fb3238..aeb9e1e4 100644 --- a/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc +++ b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc @@ -248,7 +248,7 @@ void generator::generate(std::ostream &ostr) const visited_participants; const auto &from = - m_model.get_participant(start_from); + m_model.get_participant(start_from); if (!from.has_value()) { LOG_WARN("Failed to find participant {} for start_from " @@ -261,11 +261,29 @@ void generator::generate(std::ostream &ostr) const std::string from_alias = generate_alias(from.value()); + if (from.value().type_name() == "method" || + m_config.combine_free_functions_into_file_participants()) { + ostr << "[->" + << " " << from_alias << " : " + << from.value().message_name( + model::function::message_render_mode::full) + << std::endl; + } + ostr << "activate " << from_alias << std::endl; generate_activity( m_model.sequences[start_from], ostr, visited_participants); + if (from.value().type_name() == "method" || + m_config.combine_free_functions_into_file_participants()) { + + if (!from.value().is_void()) { + ostr << "[<--" + << " " << from_alias << std::endl; + } + } + ostr << "deactivate " << from_alias << std::endl; } else { diff --git a/src/sequence_diagram/model/participant.cc b/src/sequence_diagram/model/participant.cc index 94ca51d8..55a5f6fd 100644 --- a/src/sequence_diagram/model/participant.cc +++ b/src/sequence_diagram/model/participant.cc @@ -57,6 +57,10 @@ void template_trait::add_template( templates_.push_back(std::move(tmplt)); } +bool template_trait::is_implicit() const { return is_implicit_; } + +void template_trait::set_implicit(bool implicit) { is_implicit_ = implicit; } + const std::vector & template_trait::templates() const { @@ -95,6 +99,12 @@ int template_trait::calculate_template_specialization_match( return res; } +std::string participant::to_string() const +{ + return fmt::format( + "Participant '{}': id={} name={}", type_name(), id(), full_name(false)); +} + class_::class_(const common::model::namespace_ &using_namespace) : participant{using_namespace} { @@ -154,6 +164,14 @@ std::string class_::full_name(bool relative) const return res; } +bool class_::is_alias() const { return is_alias_; } + +void class_::is_alias(bool alias) { is_alias_ = alias; } + +bool class_::is_lambda() const { return is_lambda_; } + +void class_::is_lambda(bool is_lambda) { is_lambda_ = is_lambda; } + bool operator==(const class_ &l, const class_ &r) { return l.id() == r.id(); } function::function(const common::model::namespace_ &using_namespace) @@ -173,11 +191,38 @@ std::string function::full_name_no_ns() const fmt::join(parameters_, ","), is_const() ? " const" : ""); } +std::string function::message_name(message_render_mode mode) const +{ + if (mode == message_render_mode::no_arguments) { + return fmt::format("{}(){}", name(), is_const() ? " const" : ""); + } + + return fmt::format("{}({}){}", name(), fmt::join(parameters_, ","), + is_const() ? " const" : ""); +} + +bool function::is_const() const { return is_const_; } + +void function::is_const(bool c) { is_const_ = c; } + +bool function::is_void() const { return is_void_; } + +void function::is_void(bool v) { is_void_ = v; } + +void function::add_parameter(const std::string &a) { parameters_.push_back(a); } + +const std::vector &function::parameters() const +{ + return parameters_; +} + method::method(const common::model::namespace_ &using_namespace) : function{using_namespace} { } +const std::string method::method_name() const { return method_name_; } + std::string method::alias() const { assert(class_id_ >= 0); @@ -185,6 +230,41 @@ std::string method::alias() const return fmt::format("C_{:022}", class_id_); } +void method::set_method_name(const std::string &name) { method_name_ = name; } + +void method::set_class_id(diagram_element::id_t id) { class_id_ = id; } + +void method::set_class_full_name(const std::string &name) +{ + class_full_name_ = name; +} + +const auto &method::class_full_name() const { return class_full_name_; } + +std::string method::full_name(bool /*relative*/) const +{ + return fmt::format("{}::{}({}){}", class_full_name(), method_name(), + fmt::join(parameters(), ","), is_const() ? " const" : ""); +} + +std::string method::message_name(message_render_mode mode) const +{ + if (mode == message_render_mode::no_arguments) { + return fmt::format("{}(){}", method_name(), is_const() ? " const" : ""); + } + + return fmt::format("{}({}){}", method_name(), fmt::join(parameters(), ","), + is_const() ? " const" : ""); +} + +class_::diagram_element::id_t method::class_id() const { return class_id_; } + +std::string method::to_string() const +{ + return fmt::format("Participant '{}': id={}, name={}, class_id={}", + type_name(), id(), full_name(false), class_id()); +} + function_template::function_template( const common::model::namespace_ &using_namespace) : function{using_namespace} @@ -233,4 +313,19 @@ std::string function_template::full_name_no_ns() const return ostr.str(); } +std::string function_template::message_name(message_render_mode mode) const +{ + std::ostringstream s; + render_template_params(s, using_namespace(), true); + std::string template_params = s.str(); + + if (mode == message_render_mode::no_arguments) { + return fmt::format( + "{}{}(){}", name(), template_params, is_const() ? " const" : ""); + } + + return fmt::format("{}{}({}){}", name(), template_params, + fmt::join(parameters(), ","), is_const() ? " const" : ""); +} + } \ No newline at end of file diff --git a/src/sequence_diagram/model/participant.h b/src/sequence_diagram/model/participant.h index e633b7d2..03d59f4e 100644 --- a/src/sequence_diagram/model/participant.h +++ b/src/sequence_diagram/model/participant.h @@ -42,9 +42,9 @@ struct template_trait { int calculate_template_specialization_match( const template_trait &other, const std::string &full_name) const; - bool is_implicit() const { return is_implicit_; } + bool is_implicit() const; - void set_implicit(bool implicit) { is_implicit_ = implicit; } + void set_implicit(bool implicit); private: std::vector templates_; @@ -74,11 +74,7 @@ struct participant : public common::model::element, std::string type_name() const override { return "participant"; } - virtual std::string to_string() const - { - return fmt::format("Participant '{}': id={} name={}", type_name(), id(), - full_name(false)); - } + virtual std::string to_string() const; stereotype_t stereotype_{stereotype_t::participant}; }; @@ -111,13 +107,13 @@ public: bool is_abstract() const; - bool is_alias() const { return is_alias_; } + bool is_alias() const; - void is_alias(bool alias) { is_alias_ = alias; } + void is_alias(bool alias); - bool is_lambda() const { return is_lambda_; } + bool is_lambda() const; - void is_lambda(bool is_lambda) { is_lambda_ = is_lambda; } + void is_lambda(bool is_lambda); private: bool is_struct_{false}; @@ -154,26 +150,23 @@ struct function : public participant { std::string full_name_no_ns() const override; - virtual std::string message_name(message_render_mode mode) const - { - if (mode == message_render_mode::no_arguments) { - return fmt::format("{}(){}", name(), is_const() ? " const" : ""); - } + virtual std::string message_name(message_render_mode mode) const; - return fmt::format("{}({}){}", name(), fmt::join(parameters_, ","), - is_const() ? " const" : ""); - } + bool is_const() const; - bool is_const() const { return is_const_; } + void is_const(bool c); - void is_const(bool c) { is_const_ = c; } + bool is_void() const; - void add_parameter(const std::string &a) { parameters_.push_back(a); } + void is_void(bool v); - const std::vector ¶meters() const { return parameters_; } + void add_parameter(const std::string &a); + + const std::vector ¶meters() const; private: bool is_const_{false}; + bool is_void_{false}; std::vector parameters_; }; @@ -187,45 +180,25 @@ struct method : public function { std::string type_name() const override { return "method"; } - const std::string method_name() const { return method_name_; } + const std::string method_name() const; std::string alias() const override; - void set_method_name(const std::string &name) { method_name_ = name; } + void set_method_name(const std::string &name); - void set_class_id(diagram_element::id_t id) { class_id_ = id; } + void set_class_id(diagram_element::id_t id); - void set_class_full_name(const std::string &name) - { - class_full_name_ = name; - } + void set_class_full_name(const std::string &name); - const auto &class_full_name() const { return class_full_name_; } + const auto &class_full_name() const; - std::string full_name(bool /*relative*/) const override - { - return fmt::format("{}::{}({}){}", class_full_name(), method_name(), - fmt::join(parameters(), ","), is_const() ? " const" : ""); - } + std::string full_name(bool /*relative*/) const override; - std::string message_name(message_render_mode mode) const override - { - if (mode == message_render_mode::no_arguments) { - return fmt::format( - "{}(){}", method_name(), is_const() ? " const" : ""); - } + std::string message_name(message_render_mode mode) const override; - return fmt::format("{}({}){}", method_name(), - fmt::join(parameters(), ","), is_const() ? " const" : ""); - } + diagram_element::id_t class_id() const; - diagram_element::id_t class_id() const { return class_id_; } - - std::string to_string() const override - { - return fmt::format("Participant '{}': id={}, name={}, class_id={}", - type_name(), id(), full_name(false), class_id()); - } + std::string to_string() const override; private: diagram_element::id_t class_id_; @@ -247,20 +220,6 @@ struct function_template : public function, public template_trait { std::string full_name_no_ns() const override; - std::string message_name(message_render_mode mode) const override - { - std::ostringstream s; - render_template_params(s, using_namespace(), true); - std::string template_params = s.str(); - - if (mode == message_render_mode::no_arguments) { - return fmt::format("{}{}(){}", name(), template_params, - is_const() ? " const" : ""); - } - - return fmt::format("{}{}({}){}", name(), template_params, - fmt::join(parameters(), ","), is_const() ? " const" : ""); - } + std::string message_name(message_render_mode mode) const override; }; - } diff --git a/src/sequence_diagram/visitor/translation_unit_visitor.cc b/src/sequence_diagram/visitor/translation_unit_visitor.cc index 0f7bbf2b..14c1a2e8 100644 --- a/src/sequence_diagram/visitor/translation_unit_visitor.cc +++ b/src/sequence_diagram/visitor/translation_unit_visitor.cc @@ -307,6 +307,8 @@ bool translation_unit_visitor::VisitCXXMethodDecl(clang::CXXMethodDecl *m) const auto &method_class = get_participant(parent_decl).value(); + m_ptr->is_void(m->getReturnType()->isVoidType()); + m_ptr->set_class_id(method_class.id()); m_ptr->set_class_full_name(method_class.full_name(false)); m_ptr->set_name( @@ -370,6 +372,8 @@ bool translation_unit_visitor::VisitFunctionDecl(clang::FunctionDecl *f) f_ptr->set_id(common::to_id(f_ptr->full_name(false))); + f_ptr->is_void(f->getReturnType()->isVoidType()); + context().update(f); context().set_caller_id(f_ptr->id()); @@ -397,6 +401,8 @@ bool translation_unit_visitor::VisitFunctionDecl(clang::FunctionDecl *f) f_ptr->set_id(common::to_id(f_ptr->full_name(false))); + f_ptr->is_void(f->getReturnType()->isVoidType()); + context().update(f); context().set_caller_id(f_ptr->id()); @@ -441,6 +447,9 @@ bool translation_unit_visitor::VisitFunctionTemplateDecl( f_ptr->set_id(common::to_id(f_ptr->full_name(false))); + f_ptr->is_void( + function_template->getAsFunction()->getReturnType()->isVoidType()); + set_source_location(*function_template, *f_ptr); context().update(function_template); diff --git a/tests/t20005/test_case.h b/tests/t20005/test_case.h index 476ee657..add8b058 100644 --- a/tests/t20005/test_case.h +++ b/tests/t20005/test_case.h @@ -35,9 +35,10 @@ TEST_CASE("t20005", "[test-case][sequence]") REQUIRE_THAT(puml, EndsWith("@enduml\n")); // Check if all calls exist + REQUIRE_THAT(puml, HasEntrypoint(_A("C"), "c(T)")); REQUIRE_THAT(puml, HasCall(_A("C"), _A("B"), "b(T)")); REQUIRE_THAT(puml, HasCall(_A("B"), _A("A"), "a(T)")); - + REQUIRE_THAT(puml, HasExitpoint(_A("C"))); save_puml( "./" + config.output_directory() + "/" + diagram->name + ".puml", puml); } \ No newline at end of file diff --git a/tests/t20017/test_case.h b/tests/t20017/test_case.h index 94c4bf1a..d16bcc96 100644 --- a/tests/t20017/test_case.h +++ b/tests/t20017/test_case.h @@ -35,16 +35,19 @@ TEST_CASE("t20017", "[test-case][sequence]") REQUIRE_THAT(puml, EndsWith("@enduml\n")); // Check if all calls exist + REQUIRE_THAT(puml, HasEntrypoint(_A("t20017.cc"), "tmain()")); REQUIRE_THAT(puml, HasCall(_A("t20017.cc"), _A("include/t20017_a.h"), "a1(int,int)")); - REQUIRE_THAT( - puml, HasCall(_A("t20017.cc"), _A("include/t20017_a.h"), "a2(int,int)")); + REQUIRE_THAT(puml, + HasCall(_A("t20017.cc"), _A("include/t20017_a.h"), "a2(int,int)")); REQUIRE_THAT(puml, HasCall(_A("t20017.cc"), _A("include/t20017_a.h"), "a3(int,int)")); REQUIRE_THAT(puml, HasCall(_A("t20017.cc"), _A("include/t20017_b.h"), "b1(int,int)")); REQUIRE_THAT(puml, - HasCall(_A("t20017.cc"), _A("include/t20017_b.h"), "b2(int,int)")); + HasCall( + _A("t20017.cc"), _A("include/t20017_b.h"), "b2(int,int)")); + REQUIRE_THAT(puml, HasExitpoint(_A("t20017.cc"))); save_puml( "./" + config.output_directory() + "/" + diagram->name + ".puml", puml); diff --git a/tests/test_cases.cc b/tests/test_cases.cc index 80695a32..8846bfbe 100644 --- a/tests/test_cases.cc +++ b/tests/test_cases.cc @@ -310,4 +310,4 @@ int main(int argc, char *argv[]) clanguml::util::setup_logging(debug_log); return session.run(); -} +} \ No newline at end of file diff --git a/tests/test_cases.h b/tests/test_cases.h index 25ddc23f..f4e9fd87 100644 --- a/tests/test_cases.h +++ b/tests/test_cases.h @@ -79,26 +79,19 @@ template constexpr bool has_type() noexcept return (std::is_same_v || ... || false); } -struct Public { -}; +struct Public { }; -struct Protected { -}; +struct Protected { }; -struct Private { -}; +struct Private { }; -struct Abstract { -}; +struct Abstract { }; -struct Static { -}; +struct Static { }; -struct Const { -}; +struct Const { }; -struct Default { -}; +struct Default { }; struct HasCallWithResultMatcher : ContainsMatcher { HasCallWithResultMatcher( @@ -144,6 +137,20 @@ auto HasCallWithResponse(std::string const &from, std::string const &to, CasedString(fmt::format("{} --> {}", to, from), caseSensitivity)); } +ContainsMatcher HasEntrypoint(std::string const &to, std::string const &message, + CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes) +{ + return ContainsMatcher( + CasedString(fmt::format("[-> {} : {}", to, message), caseSensitivity)); +} + +ContainsMatcher HasExitpoint(std::string const &to, + CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes) +{ + return ContainsMatcher( + CasedString(fmt::format("[<-- {}", to), caseSensitivity)); +} + struct AliasMatcher { AliasMatcher(const std::string &puml_) : puml{split(puml_, "\n")}