diff --git a/README.md b/README.md index 959b2972..c23c67cf 100644 --- a/README.md +++ b/README.md @@ -252,23 +252,17 @@ The following C++ code: namespace clanguml { namespace t20029 { -using encoder_function_t = std::function; - std::string encode_b64(std::string &&content) { return std::move(content); } template class Encoder : public T { public: bool send(std::string &&msg) { - auto encoded = encode(std::move(msg)); - return T::send(std::move(encoded)); + return T::send(std::move(encode(std::move(msg)))); } protected: std::string encode(std::string &&msg) { return encode_b64(std::move(msg)); } - -private: - encoder_function_t f_; }; template class Retrier : public T { diff --git a/src/config/config.cc b/src/config/config.cc index deb5d458..7891b2f5 100644 --- a/src/config/config.cc +++ b/src/config/config.cc @@ -594,6 +594,7 @@ template <> struct convert { get_option(node, rhs.start_from); get_option(node, rhs.combine_free_functions_into_file_participants); get_option(node, rhs.relative_to); + get_option(node, rhs.participants_order); rhs.initialize_type_aliases(); diff --git a/src/config/config.h b/src/config/config.h index 77e18787..94fda926 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -144,6 +144,7 @@ struct inheritable_diagram_options { "comment_parser", comment_parser_t::plain}; option combine_free_functions_into_file_participants{ "combine_free_functions_into_file_participants", false}; + option> participants_order{"participants_order"}; void inherit(const inheritable_diagram_options &parent); diff --git a/src/main.cc b/src/main.cc index da418888..efe97439 100644 --- a/src/main.cc +++ b/src/main.cc @@ -79,7 +79,7 @@ void generate_diagram(const std::string &od, const std::string &name, /// Find translation units for diagrams. /// /// For each diagram to be generated, this function selects translation units -/// to be used for this diagram. The diagrams are selected as an intersection +/// to be used for this diagram. The files are selected as an intersection /// between all translation units found in the compilation database and the /// `glob` patterns specified for each diagram in the configuration file. /// diff --git a/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc index a88ee3b1..8e285299 100644 --- a/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc +++ b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc @@ -220,93 +220,119 @@ void generator::generate_activity(const activity &a, std::ostream &ostr, } } -void generator::generate_participant(std::ostream &ostr, common::id_t id) const +void generator::generate_participant( + std::ostream &ostr, const std::string &name) const { - for (const auto participant_id : m_model.active_participants()) { - if (participant_id != id) - continue; - - if (is_participant_generated(participant_id)) - return; - - const auto &participant = - m_model.get_participant(participant_id).value(); - - if (participant.type_name() == "method") { - const auto class_id = - m_model.get_participant(participant_id) - .value() - .class_id(); - - if (is_participant_generated(class_id)) - return; - - const auto &class_participant = - m_model.get_participant(class_id).value(); - - ostr << "participant \"" - << render_name(m_config.using_namespace().relative( - class_participant.full_name(false))) - << "\" as " << class_participant.alias(); - - if (m_config.generate_links) { - common_generator::generate_link( - ostr, class_participant); - } - - ostr << '\n'; - - generated_participants_.emplace(class_id); - } - else if ((participant.type_name() == "function" || - participant.type_name() == "function_template") && - m_config.combine_free_functions_into_file_participants()) { - // Create a single participant for all functions declared in a - // single file - const auto &file_path = - m_model.get_participant(participant_id) - .value() - .file(); - - assert(!file_path.empty()); - - const auto file_id = common::to_id(file_path); - - if (is_participant_generated(file_id)) - return; - - [[maybe_unused]] const auto &relative_to = - std::filesystem::canonical(m_config.relative_to()); - - auto participant_name = std::filesystem::relative( - std::filesystem::path{file_path}, relative_to) - .string(); - - ostr << "participant \"" << render_name(participant_name) - << "\" as " << fmt::format("C_{:022}", file_id); - - ostr << '\n'; - - generated_participants_.emplace(file_id); - } - else { - ostr << "participant \"" - << m_config.using_namespace().relative( - participant.full_name(false)) - << "\" as " << participant.alias(); - - if (m_config.generate_links) { - common_generator::generate_link( - ostr, participant); - } - - ostr << '\n'; - - generated_participants_.emplace(participant_id); - } + auto p = m_model.get(name); + if (!p.has_value()) { + LOG_WARN("Cannot find participant {} from `participants_order` option", + name); return; } + + generate_participant(ostr, p.value().id(), true); +} + +void generator::generate_participant( + std::ostream &ostr, common::id_t id, bool force) const +{ + common::id_t participant_id{0}; + + if (!force) { + for (const auto pid : m_model.active_participants()) { + if (pid == id) { + participant_id = pid; + break; + } + } + } + else + participant_id = id; + + if (participant_id == 0) + return; + + if (is_participant_generated(participant_id)) + return; + + const auto &participant = + m_model.get_participant(participant_id).value(); + + if (participant.type_name() == "method") { + const auto class_id = + m_model.get_participant(participant_id) + .value() + .class_id(); + + if (is_participant_generated(class_id)) + return; + + const auto &class_participant = + m_model.get_participant(class_id).value(); + + ostr << "participant \"" + << render_name(m_config.using_namespace().relative( + class_participant.full_name(false))) + << "\" as " << class_participant.alias(); + + if (m_config.generate_links) { + common_generator::generate_link( + ostr, class_participant); + } + + ostr << '\n'; + + generated_participants_.emplace(class_id); + } + else if ((participant.type_name() == "function" || + participant.type_name() == "function_template") && + m_config.combine_free_functions_into_file_participants()) { + // Create a single participant for all functions declared in a + // single file + const auto &file_path = + m_model.get_participant(participant_id) + .value() + .file(); + + assert(!file_path.empty()); + + const auto file_id = common::to_id(file_path); + + if (is_participant_generated(file_id)) + return; + + [[maybe_unused]] const auto &relative_to = + std::filesystem::canonical(m_config.relative_to()); + + auto participant_name = std::filesystem::relative( + std::filesystem::path{file_path}, relative_to) + .string(); + + ostr << "participant \"" << render_name(participant_name) << "\" as " + << fmt::format("C_{:022}", file_id); + + ostr << '\n'; + + generated_participants_.emplace(file_id); + } + else { + ostr << "participant \"" + << m_config.using_namespace().relative( + participant.full_name(false)) + << "\" as " << participant.alias(); + + if (m_config.generate_links) { + common_generator::generate_link( + ostr, participant); + } + + ostr << '\n'; + + generated_participants_.emplace(participant_id); + } + + return; } bool generator::is_participant_generated(common::id_t id) const @@ -324,6 +350,13 @@ void generator::generate(std::ostream &ostr) const generate_plantuml_directives(ostr, m_config.puml().before); + if (m_config.participants_order.has_value) { + for (const auto &p : m_config.participants_order()) { + LOG_DBG("Pregenerating participant {}", p); + generate_participant(ostr, p); + } + } + for (const auto &sf : m_config.start_from()) { if (sf.location_type == source_location::location_t::function) { common::model::diagram_element::id_t start_from; @@ -404,5 +437,4 @@ std::string generator::generate_alias( return participant.alias(); } - } diff --git a/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.h b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.h index 23a4cbe7..07e99c3c 100644 --- a/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.h +++ b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.h @@ -52,7 +52,11 @@ public: void generate_return(const clanguml::sequence_diagram::model::message &m, std::ostream &ostr) const; - void generate_participant(std::ostream &ostr, common::id_t id) const; + void generate_participant( + std::ostream &ostr, common::id_t id, bool force = false) const; + + void generate_participant( + std::ostream &ostr, const std::string &name) const; void generate_activity(const clanguml::sequence_diagram::model::activity &a, std::ostream &ostr, diff --git a/tests/t20029/.clang-uml b/tests/t20029/.clang-uml index 6f1d0df7..8308648f 100644 --- a/tests/t20029/.clang-uml +++ b/tests/t20029/.clang-uml @@ -14,4 +14,10 @@ diagrams: using_namespace: - clanguml::t20029 start_from: - - function: "clanguml::t20029::tmain()" \ No newline at end of file + - function: clanguml::t20029::tmain() + participants_order: + - clanguml::t20029::tmain() + - clanguml::t20029::Encoder> + - clanguml::t20029::Retrier + - clanguml::t20029::ConnectionPool + - clanguml::t20029::encode_b64(std::string &&) \ No newline at end of file