33 std::vector<std::vector<eid_t>> all_message_chains;
34 std::vector<eid_t> current_chain;
40 current_chain.push_back(node.activity_id);
42 if (node.callers.empty()) {
43 auto reversed = current_chain;
44 std::reverse(reversed.begin(), reversed.end());
45 all_message_chains.emplace_back(std::move(reversed));
48 for (
const auto &child : node.callers) {
54 current_chain.pop_back();
60 return all_message_chains;
69 const std::string &full_name)
const
95 const auto participant_id = p->id();
99 assert(participant_id.is_global());
102 LOG_DBG(
"Adding '{}' participant: {}, {} [{}]", p->type_name(),
103 p->full_name(
false), p->id(),
104 p->type_name() ==
"method"
159 std::move(
message), start_type, current_messages);
166 const auto caller_id = m.from();
171 if (current_messages.back().type() == message_t::kCase) {
175 current_messages.emplace_back(std::move(m));
192const std::map<eid_t, std::unique_ptr<participant>> &
215 std::vector<std::string> result;
220 const auto &full_name = from_activity.full_name(
false);
221 if (!full_name.empty())
222 result.push_back(full_name);
225 std::sort(result.begin(), result.end());
226 result.erase(std::unique(result.begin(), result.end()), result.end());
233 std::vector<std::string> result;
236 for (
const auto &m : act.messages()) {
239 const auto &full_name = to_activity.full_name(
false);
240 if (!full_name.empty())
241 result.push_back(full_name);
246 std::sort(result.begin(), result.end());
247 result.erase(std::unique(result.begin(), result.end()), result.end());
255 std::vector<eid_t> to_activities{};
258 for (
const auto &m : v.messages()) {
263 std::string vto = callee.full_name(
false);
266 "Found sequence diagram end point '{}': {}", vto, m.to());
267 to_activities.push_back(m.to());
272 if (to_activities.empty()) {
273 LOG_WARN(
"Failed to find 'to' participant {} for to "
280 return to_activities;
286 std::vector<eid_t> from_activities{};
293 std::string vfrom = caller.full_name(
false);
294 if (from_location.
location == vfrom) {
295 LOG_DBG(
"Found sequence diagram start point '{}': {}", vfrom, k);
296 from_activities.push_back(k);
300 if (from_activities.empty()) {
301 LOG_WARN(
"Failed to find 'from' participant {} for from "
308 return from_activities;
312 std::set<eid_t> visited_callers)
const
323 for (
const auto &caller : callers) {
324 if (visited_callers.count(caller) > 0) {
334 node.
callers.emplace_back(std::move(caller_node));
339 const eid_t from_activity,
const eid_t to_activity)
const
342 std::vector<message_chain_t> message_chains;
350 for (
const auto &m : v.messages()) {
354 if (m.to() == to_activity) {
357 target_roots.
callers.emplace_back(std::move(node));
364 for (
auto &caller : target_roots.
callers)
372 sort(begin(activity_id_chains), end(activity_id_chains));
373 activity_id_chains.erase(
374 unique(begin(activity_id_chains), end(activity_id_chains)),
375 end(activity_id_chains));
378 for (
const auto &chain : activity_id_chains) {
380 for (
auto it = begin(chain); it != end(chain); it++) {
381 const auto next_it = it + 1;
382 if (next_it == end(chain))
389 auto to_id = *(next_it);
393 for (
const auto &m : act.messages()) {
394 if (m.to() == to_id) {
395 message_chain.push_back(m);
400 message_chains.emplace_back(std::move(message_chain));
404 std::vector<message_chain_t> message_chains_filtered{};
406 for (
auto &mc : message_chains) {
412 if (from_activity.
value() == 0 ||
413 (mc.front().from() == from_activity)) {
414 message_chains_filtered.push_back(mc);
418 int message_chain_index{};
419 for (
const auto &mc : message_chains_filtered) {
420 LOG_INFO(
"\t{}: {}", message_chain_index++,
421 fmt::join(util::map<std::string>(mc,
428 return message_chains_filtered;
438 using namespace std::string_literals;
440 std::map<eid_t, activity> activities;
441 std::map<eid_t, std::unique_ptr<participant>>
participants;
450 auto maybe_lambda_activity = get_participant<model::method>(
id);
452 if (maybe_lambda_activity) {
453 const auto parent_class_id =
454 maybe_lambda_activity.value().class_id();
455 auto maybe_parent_class =
456 get_participant<model::class_>(parent_class_id);
458 if (maybe_parent_class && maybe_parent_class.value().is_lambda()) {
466 for (
auto &m : act.messages()) {
468 auto message_call_to_lambda{
false};
470 message_call_to_lambda =
473 if (!message_call_to_lambda)
474 new_activity.add_message(m);
478 activities.insert({id, std::move(new_activity)});
483 if (
const auto *maybe_class =
485 maybe_class !=
nullptr && maybe_class->
is_lambda()) {
490 if (
const auto *maybe_method =
492 maybe_method !=
nullptr) {
494 get_participant<model::class_>(maybe_method->class_id());
495 if (maybe_class && maybe_class.value().is_lambda()) {
501 auto participant_id = p->id();
507 if (participants.count(
id) > 0) {
520 using namespace std::string_literals;
522 bool message_call_to_lambda{
false};
523 auto maybe_lambda_operator = get_participant<model::method>(m.
to());
525 if (maybe_lambda_operator) {
526 const auto parent_class_id = maybe_lambda_operator.value().class_id();
527 auto maybe_parent_class =
528 get_participant<model::class_>(parent_class_id);
530 if (maybe_parent_class && maybe_parent_class.value().is_lambda()) {
536 for (
auto &mm : lambda_operator_activity.messages()) {
544 auto new_message{mm};
546 new_message.set_from(
id);
553 message_call_to_lambda =
true;
557 return message_call_to_lambda;
576 LOG_TRACE(
" Activity id={}, from={}:", act.from(),
577 from_activity.full_name(
false));
579 for (
const auto &
message : act.messages()) {
588 " Return from={}, from_id={}, name={}, type={}",
589 from_participant.full_name(
false),
593 const auto &to_participant =
596 LOG_TRACE(
" Return from={}, from_id={}, "
597 "to={}, to_id={}, name={}, type={}",
598 from_participant.full_name(
false),
599 from_participant.id(), to_participant.full_name(
false),
605 LOG_TRACE(
" Message from={}, from_id={}, "
606 "to={}, to_id={}, name={}, type={}",
607 from_participant.full_name(
false), from_participant.id(),
614 std::string message_comment{
"None"};
616 message_comment = cmt.value().at(
"comment");
619 LOG_TRACE(
" Message from={}, from_id={}, "
620 "to={}, to_id={}, name={}, type={}, comment={}",
621 from_participant.full_name(
false), from_participant.id(),
622 to_participant.full_name(
false), to_participant.id(),
632 std::vector<message> ¤t_messages)
const
634 bool is_empty_statement{
true};
636 auto rit = current_messages.rbegin();
637 for (; rit != current_messages.rend(); rit++) {
638 if (rit->type() == statement_begin) {
642 is_empty_statement =
false;
646 is_empty_statement =
false;
650 is_empty_statement =
false;
655 if (is_empty_statement) {
656 current_messages.erase((rit + 1).base(), current_messages.end());
659 current_messages.emplace_back(std::move(m));
672 if (m.type() != message_t::kCall)
675 const auto &to = get_participant<model::participant>(m.to());
676 if (!to || to.value().skip())
679 if (!should_include(to.value())) {
680 LOG_DBG(
"Excluding call from [{}] to {} [{}]", m.from(),
681 to.value().full_name(false), m.to());
690 for (
auto &[
id, act] : activities_) {
691 int64_t block_nest_level{0};
692 std::vector<std::vector<message>> block_message_stack;
695 block_message_stack.emplace_back();
699 for (
auto &m : act.messages()) {
700 if (is_begin_block_message(m.type())) {
702 block_message_stack.push_back({m});
704 else if (is_end_block_message(m.type())) {
707 block_message_stack.back().push_back(m);
711 if (std::count_if(block_message_stack.back().begin(),
712 block_message_stack.back().end(), [](
auto &m) {
713 return (m.type() == message_t::kCall) ||
714 (m.type() == message_t::kReturn) ||
715 (m.type() == message_t::kCoReturn);
717 std::copy(block_message_stack.back().begin(),
718 block_message_stack.back().end(),
720 block_message_stack.at(block_nest_level)));
723 block_message_stack.pop_back();
725 assert(block_nest_level >= 0);
728 if (m.type() == message_t::kCall) {
731 auto to_participant =
732 get_participant<sequence_diagram::model::function>(
734 if (to_participant.has_value()) {
735 m.set_return_type(to_participant.value().return_type());
738 block_message_stack.back().push_back(m);
742 act.messages().clear();
744 for (
auto &m : block_message_stack[0]) {
750void diagram::handle_invalid_from_condition(
753 std::string error_message =
754 fmt::format(
"Failed to find participant matching '{}' for "
759 std::vector<std::string> from_participants;
760 for (
const auto &[k, v] : sequences()) {
761 if (participants().count(v.from()) == 0)
764 const auto &caller = *participants().at(v.from());
765 from_participants.emplace_back(caller.full_name(
false));
771 if (!possible_matches.empty()) {
773 fmt::format(
" Did you mean: '{}'?", possible_matches.at(0));
780void diagram::handle_invalid_to_condition(
783 std::string error_message =
784 fmt::format(
"Failed to find participant matching '{}' for "
789 std::vector<std::string> to_participants;
790 for (
const auto &[k, v] : sequences()) {
791 for (
const auto &m : v.messages()) {
795 const auto &callee = *participants().at(m.to());
796 to_participants.emplace_back(callee.full_name(
false));
803 if (!possible_matches.empty()) {
805 fmt::format(
" Did you mean: '{}'?", possible_matches.at(0));
815bool check_diagram_type<clanguml::sequence_diagram::model::diagram>(
diagram_t t)
817 return t == diagram_t::kSequence;