From 95d83345a5b101018d0e709fad807e1223a82754 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Fri, 3 May 2024 15:11:46 +0200 Subject: [PATCH] Refactored sequence lambda inlining to diagram model (#261) --- src/sequence_diagram/model/diagram.cc | 110 +++++++++++++++++ src/sequence_diagram/model/diagram.h | 15 ++- .../visitor/translation_unit_visitor.cc | 112 +----------------- .../visitor/translation_unit_visitor.h | 7 +- 4 files changed, 122 insertions(+), 122 deletions(-) diff --git a/src/sequence_diagram/model/diagram.cc b/src/sequence_diagram/model/diagram.cc index 11bb1e04..c802ec76 100644 --- a/src/sequence_diagram/model/diagram.cc +++ b/src/sequence_diagram/model/diagram.cc @@ -409,6 +409,116 @@ bool diagram::is_empty() const return activities_.empty() || participants_.empty(); } +void diagram::inline_lambda_operator_calls() +{ + std::map activities; + std::map> participants; + std::set active_participants; + + for (auto &[id, act] : sequences()) { + model::activity new_activity{id}; + + // If activity is a lambda operator() - skip it + auto maybe_lambda_activity = get_participant(id); + + if (maybe_lambda_activity) { + const auto parent_class_id = + maybe_lambda_activity.value().class_id(); + auto maybe_parent_class = + get_participant(parent_class_id); + + if (maybe_parent_class && maybe_parent_class.value().is_lambda()) { + continue; + } + } + + // For other activities, check each message - if it calls lambda + // operator() - reattach the message to the next activity in the chain + // (assuming it's not lambda) + for (auto &m : act.messages()) { + + auto message_call_to_lambda{false}; + + message_call_to_lambda = + inline_lambda_operator_call(id, new_activity, m); + + if (!message_call_to_lambda) + new_activity.add_message(m); + } + + // Add activity + activities.insert({id, std::move(new_activity)}); + } + + for (auto &&[id, p] : this->participants()) { + // Skip participants which are lambda classes + if (const auto *maybe_class = + dynamic_cast(p.get()); + maybe_class && maybe_class->is_lambda()) { + continue; + } + + // Skip participants which are lambda operator methods + if (const auto *maybe_method = + dynamic_cast(p.get()); + maybe_method) { + auto maybe_class = + get_participant(maybe_method->class_id()); + if (maybe_class && maybe_class.value().is_lambda()) + continue; + } + + // Otherwise move the participant to the new diagram model + auto participant_id = p->id(); + participants.emplace(participant_id, std::move(p)); + } + + // Skip active participants which are not in lambdaless_diagram participants + for (auto id : this->active_participants()) { + if (participants.count(id)) { + active_participants.emplace(id); + } + } + + activities_ = std::move(activities); + participants_ = std::move(participants); + active_participants_ = std::move(active_participants); +} + +bool diagram::inline_lambda_operator_call( + const long id, model::activity &new_activity, const model::message &m) +{ + bool message_call_to_lambda{false}; + auto maybe_lambda_operator = get_participant(m.to()); + + if (maybe_lambda_operator) { + const auto parent_class_id = maybe_lambda_operator.value().class_id(); + auto maybe_parent_class = + get_participant(parent_class_id); + + if (maybe_parent_class && maybe_parent_class.value().is_lambda()) { + // auto new_message{m}; + // new_message.set_ + auto lambda_operator_activity = get_activity(m.to()); + + // For each call in that lambda activity - reattach this + // call to the current activity + for (auto &mm : lambda_operator_activity.messages()) { + if (!inline_lambda_operator_call(id, new_activity, mm)) { + auto new_message{mm}; + + new_message.set_from(id); + new_activity.add_message(new_message); + } + } + + message_call_to_lambda = true; + } + } + + return message_call_to_lambda; +} + void diagram::print() const { LOG_TRACE(" --- Participants ---"); diff --git a/src/sequence_diagram/model/diagram.h b/src/sequence_diagram/model/diagram.h index 30e9f714..b5819226 100644 --- a/src/sequence_diagram/model/diagram.h +++ b/src/sequence_diagram/model/diagram.h @@ -295,12 +295,12 @@ public: */ bool is_empty() const override; - void update_sequences_from_diagram(diagram &other) - { - activities_ = std::move(other.activities_); - participants_ = std::move(other.participants_); - active_participants_ = std::move(other.active_participants_); - } + /** + * If option to inline lambda calls is enabled, we need to modify the + * sequences to skip the lambda calls. In case lambda call does not lead + * to a non-lambda call, omit it entirely + */ + void inline_lambda_operator_calls(); private: /** @@ -344,6 +344,9 @@ private: return block_end_types.count(mt) > 0; }; + bool inline_lambda_operator_call( + const long id, model::activity &new_activity, const model::message &m); + std::map activities_; std::map> participants_; diff --git a/src/sequence_diagram/visitor/translation_unit_visitor.cc b/src/sequence_diagram/visitor/translation_unit_visitor.cc index 1bc9a7b8..7f34b505 100644 --- a/src/sequence_diagram/visitor/translation_unit_visitor.cc +++ b/src/sequence_diagram/visitor/translation_unit_visitor.cc @@ -2028,7 +2028,7 @@ void translation_unit_visitor::finalize() ensure_lambda_messages_have_operator_as_target(); if (config().inline_lambda_messages()) - inline_lambda_operator_calls(); + diagram().inline_lambda_operator_calls(); } void translation_unit_visitor::ensure_lambda_messages_have_operator_as_target() @@ -2075,116 +2075,6 @@ void translation_unit_visitor::resolve_ids_to_global() } } -void translation_unit_visitor::inline_lambda_operator_calls() -{ // If option to inline lambda calls is enabled, we need to modify the - // sequences to skip the lambda calls. In case lambda call does not lead - // to a non-lambda call, omit it entirely - - model::diagram lambdaless_diagram; - - for (auto &[id, act] : diagram().sequences()) { - model::activity new_activity{id}; - - // If activity is a lambda operator() - skip it - auto maybe_lambda_activity = - diagram().get_participant(id); - - if (maybe_lambda_activity) { - const auto parent_class_id = - maybe_lambda_activity.value().class_id(); - auto maybe_parent_class = - diagram().get_participant(parent_class_id); - - if (maybe_parent_class && maybe_parent_class.value().is_lambda()) { - continue; - } - } - - // For other activities, check each message - if it calls lambda - // operator() - reattach the message to the next activity in the chain - // (assuming it's not lambda) - for (auto &m : act.messages()) { - - auto message_call_to_lambda{false}; - - message_call_to_lambda = - inline_lambda_operator_call(id, new_activity, m); - - if (!message_call_to_lambda) - new_activity.add_message(m); - } - - // Add activity - lambdaless_diagram.sequences().insert({id, std::move(new_activity)}); - } - - for (auto &&[id, p] : diagram().participants()) { - // Skip participants which are lambda classes - if (const auto *maybe_class = - dynamic_cast(p.get()); - maybe_class && maybe_class->is_lambda()) { - continue; - } - - // Skip participants which are lambda operator methods - if (const auto *maybe_method = - dynamic_cast(p.get()); - maybe_method) { - auto maybe_class = diagram().get_participant( - maybe_method->class_id()); - if (maybe_class && maybe_class.value().is_lambda()) - continue; - } - - // Otherwise move the participant to the new diagram model - lambdaless_diagram.add_participant(std::move(p)); - } - - // Skip active participants which are not in lambdaless_diagram participants - for (auto id : diagram().active_participants()) { - if (lambdaless_diagram.participants().count(id)) { - lambdaless_diagram.add_active_participant(id); - } - } - - diagram().update_sequences_from_diagram(lambdaless_diagram); -} - -bool translation_unit_visitor::inline_lambda_operator_call( - const long id, model::activity &new_activity, const model::message &m) -{ - bool message_call_to_lambda{false}; - auto maybe_lambda_operator = - diagram().get_participant(m.to()); - - if (maybe_lambda_operator) { - const auto parent_class_id = maybe_lambda_operator.value().class_id(); - auto maybe_parent_class = - diagram().get_participant(parent_class_id); - - if (maybe_parent_class && maybe_parent_class.value().is_lambda()) { - // auto new_message{m}; - // new_message.set_ - auto lambda_operator_activity = diagram().get_activity(m.to()); - - // For each call in that lambda activity - reattach this - // call to the current activity - for (auto &mm : lambda_operator_activity.messages()) { - if (!inline_lambda_operator_call(id, new_activity, mm)) { - auto new_message{mm}; - - new_message.set_from(id); - new_activity.add_message(new_message); - } - } - - message_call_to_lambda = true; - } - } - - return message_call_to_lambda; -} - std::unique_ptr translation_unit_visitor::create_lambda_method_model( clang::CXXMethodDecl *declaration) diff --git a/src/sequence_diagram/visitor/translation_unit_visitor.h b/src/sequence_diagram/visitor/translation_unit_visitor.h index f404816a..071509b9 100644 --- a/src/sequence_diagram/visitor/translation_unit_visitor.h +++ b/src/sequence_diagram/visitor/translation_unit_visitor.h @@ -487,10 +487,9 @@ private: */ template_builder_t &tbuilder() { return template_builder_; } - void inline_lambda_operator_calls(); + void resolve_ids_to_global(); - bool inline_lambda_operator_call( - const long id, model::activity &new_activity, const model::message &m); + void ensure_lambda_messages_have_operator_as_target(); call_expression_context call_expression_context_; @@ -527,7 +526,5 @@ private: processed_comments_by_caller_id_; template_builder_t template_builder_; - void resolve_ids_to_global(); - void ensure_lambda_messages_have_operator_as_target(); }; } // namespace clanguml::sequence_diagram::visitor