0.5.4
C++ to UML diagram generator based on Clang
Loading...
Searching...
No Matches
Public Member Functions | Private Member Functions | Private Attributes | List of all members
clanguml::sequence_diagram::model::diagram Class Reference

Model of a sequence diagram. More...

Detailed Description

Model of a sequence diagram.

Definition at line 38 of file diagram.h.

#include <diagram.h>

Public Member Functions

 diagram ()=default
 
 diagram (const diagram &)=delete
 
 diagram (diagram &&)=default
 
diagramoperator= (const diagram &)=delete
 
diagramoperator= (diagram &&)=default
 
common::model::diagram_t type () const override
 Get the diagram model type - in this case sequence.
 
common::optional_ref< common::model::diagram_elementget (const std::string &full_name) const override
 Search for element in the diagram by fully qualified name.
 
common::optional_ref< common::model::diagram_elementget (eid_t id) const override
 Search for element in the diagram by id.
 
template<typename T >
common::optional_ref< T > get_participant (eid_t id) const
 Get participant by id.
 
void add_participant (std::unique_ptr< participant > p)
 Add sequence diagram participant.
 
void add_active_participant (eid_t id)
 Set participant with id as active.
 
bool has_activity (eid_t id) const
 Check if diagram has activity identified by caller id.
 
const activityget_activity (eid_t id) const
 Get reference to current activity of a participant.
 
activityget_activity (eid_t id)
 Get reference to current activity of a participant.
 
void add_message (model::message &&message)
 Add message to current activity.
 
void add_block_message (model::message &&message)
 Add block message to the current activity.
 
void end_block_message (model::message &&message, common::model::message_t start_type)
 End current block message.
 
void add_case_stmt_message (model::message &&m)
 Add switch block case statement.
 
std::map< eid_t, activity > & sequences ()
 Get all sequences in the diagram.
 
const std::map< eid_t, activity > & sequences () const
 Get all sequences in the diagram.
 
std::map< eid_t, std::unique_ptr< participant > > & participants ()
 Get map of all participants in the diagram.
 
const std::map< eid_t, std::unique_ptr< participant > > & participants () const
 Get map of all participants in the diagram.
 
std::set< eid_t > & active_participants ()
 Get all active participants in the diagram.
 
const std::set< eid_t > & active_participants () const
 Get all active participants in the diagram.
 
std::string to_alias (const std::string &full_name) const
 Convert element full name to PlantUML alias.
 
inja::json context () const override
 Return the elements JSON context for inja templates.
 
void print () const
 Debug method for printing entire diagram to console.
 
bool should_include (const sequence_diagram::model::participant &p) const
 Convenience should_include overload for participant.
 
std::vector< std::string > list_from_values () const
 Get list of all possible 'from' values in the model.
 
std::vector< std::string > list_to_values () const
 Get list of all possible 'to' values in the model.
 
std::vector< message_chain_tget_all_from_to_message_chains (eid_t from_activity, eid_t to_activity) const
 Generate a list of message chains matching a from_to constraint.
 
std::optional< eid_tget_to_activity_id (const config::source_location &to_location) const
 Get id of a 'to' activity.
 
std::optional< eid_tget_from_activity_id (const config::source_location &from_location) const
 Get id of a 'from' activity.
 
void finalize () override
 Once the diagram is complete, run any final processing.
 
bool is_empty () const override
 Check whether the diagram is empty.
 
void inline_lambda_operator_calls ()
 
- Public Member Functions inherited from clanguml::common::model::diagram
 diagram ()
 
 diagram (const diagram &)=delete
 
 diagram (diagram &&) noexcept
 
diagramoperator= (const diagram &)=delete
 
diagramoperator= (diagram &&) noexcept
 
virtual ~diagram ()
 
virtual diagram_t type () const =0
 Return type of the diagram.
 
virtual opt_ref< clanguml::common::model::diagram_elementget (const std::string &full_name) const =0
 
virtual common::optional_ref< clanguml::common::model::diagram_elementget (eid_t id) const =0
 
virtual common::optional_ref< clanguml::common::model::diagram_elementget_with_namespace (const std::string &name, const namespace_ &ns) const
 
void set_name (const std::string &name)
 
std::string name () const
 
void set_filter (std::unique_ptr< diagram_filter > filter)
 
const diagram_filterfilter () const
 
void set_complete (bool complete)
 Set diagram in a complete state.
 
bool complete () const
 Whether the diagram is complete.
 
virtual void finalize ()
 Once the diagram is complete, run any final processing.
 
bool should_include (const element &e) const
 
bool should_include (const namespace_ &ns) const
 
bool should_include (const source_file &path) const
 
bool should_include (relationship r) const
 
bool should_include (relationship_t r) const
 
bool should_include (access_t s) const
 
bool should_include (const std::string &s) const =delete
 
virtual bool has_element (const eid_t) const
 
virtual bool should_include (const namespace_ &ns, const std::string &name) const
 
virtual inja::json context () const =0
 
virtual bool is_empty () const =0
 Check whether the diagram is empty.
 
virtual void apply_filter ()
 

Private Member Functions

void fold_or_end_block_statement (message &&m, common::model::message_t statement_begin, std::vector< message > &current_messages) const
 
bool is_begin_block_message (common::model::message_t mt)
 
bool is_end_block_message (common::model::message_t mt)
 
bool inline_lambda_operator_call (eid_t id, model::activity &new_activity, const model::message &m)
 

Private Attributes

std::map< eid_t, activityactivities_
 
std::map< eid_t, std::unique_ptr< participant > > participants_
 
std::set< eid_tactive_participants_
 

Constructor & Destructor Documentation

◆ diagram() [1/3]

clanguml::sequence_diagram::model::diagram::diagram ( )
default

◆ diagram() [2/3]

clanguml::sequence_diagram::model::diagram::diagram ( const diagram )
delete

◆ diagram() [3/3]

clanguml::sequence_diagram::model::diagram::diagram ( diagram &&  )
default

Member Function Documentation

◆ active_participants() [1/2]

std::set< eid_t > & clanguml::sequence_diagram::model::diagram::active_participants ( )

Get all active participants in the diagram.

Returns
Set of all active participant ids

Definition at line 171 of file diagram.cc.

171{ return active_participants_; }

◆ active_participants() [2/2]

const std::set< eid_t > & clanguml::sequence_diagram::model::diagram::active_participants ( ) const

Get all active participants in the diagram.

Returns
Set of all active participant ids

Definition at line 173 of file diagram.cc.

174{
176}

◆ add_active_participant()

void clanguml::sequence_diagram::model::diagram::add_active_participant ( eid_t  id)

Set participant with id as active.

Parameters
idId of participant to activate

Definition at line 93 of file diagram.cc.

94{
95 active_participants_.emplace(id);
96}

◆ add_block_message()

void clanguml::sequence_diagram::model::diagram::add_block_message ( model::message &&  message)

Add block message to the current activity.

Block messages represent sequence diagram blocks such as alt or loop.

The block messages can be stacked.

Parameters
messageMessage model

Definition at line 118 of file diagram.cc.

119{
120 add_message(std::move(message));
121}

◆ add_case_stmt_message()

void clanguml::sequence_diagram::model::diagram::add_case_stmt_message ( model::message &&  m)

Add switch block case statement.

Parameters
mMessage model

Definition at line 136 of file diagram.cc.

137{
139 const auto caller_id = m.from();
140
141 if (activities_.find(caller_id) != activities_.end()) {
142 auto &current_messages = get_activity(caller_id).messages();
143
144 if (current_messages.back().type() == message_t::kCase) {
145 // Do nothing - fallthroughs not supported yet...
146 }
147 else {
148 current_messages.emplace_back(std::move(m));
149 }
150 }
151}

◆ add_message()

void clanguml::sequence_diagram::model::diagram::add_message ( model::message &&  message)

Add message to current activity.

Parameters
messageMessage model

Definition at line 107 of file diagram.cc.

108{
109 const auto caller_id = message.from();
110 if (activities_.find(caller_id) == activities_.end()) {
111 activity a{caller_id};
112 activities_.insert({caller_id, std::move(a)});
113 }
114
115 get_activity(caller_id).add_message(std::move(message));
116}

◆ add_participant()

void clanguml::sequence_diagram::model::diagram::add_participant ( std::unique_ptr< participant p)

Add sequence diagram participant.

Parameters
pSequence diagram participant model

Definition at line 76 of file diagram.cc.

77{
78 const auto participant_id = p->id();
79
80 assert(participant_id.is_global());
81
82 if (participants_.find(participant_id) == participants_.end()) {
83 LOG_DBG("Adding '{}' participant: {}, {} [{}]", p->type_name(),
84 p->full_name(false), p->id(),
85 p->type_name() == "method"
86 ? dynamic_cast<method *>(p.get())->method_name()
87 : "");
88
89 participants_.emplace(participant_id, std::move(p));
90 }
91}

◆ context()

inja::json clanguml::sequence_diagram::model::diagram::context ( ) const
overridevirtual

Return the elements JSON context for inja templates.

Returns
JSON node with elements context.

Implements clanguml::common::model::diagram.

Definition at line 58 of file diagram.cc.

59{
60 inja::json ctx;
61 ctx["name"] = name();
62 ctx["type"] = "sequence";
63
64 inja::json::array_t elements{};
65
66 // Add classes
67 for (const auto &[id, p] : participants_) {
68 elements.emplace_back(p->context());
69 }
70
71 ctx["elements"] = elements;
72
73 return ctx;
74}

◆ end_block_message()

void clanguml::sequence_diagram::model::diagram::end_block_message ( model::message &&  message,
common::model::message_t  start_type 
)

End current block message.

Parameters
messageMessage model
start_typeType of block statement.

Definition at line 123 of file diagram.cc.

125{
126 const auto caller_id = message.from();
127
128 if (activities_.find(caller_id) != activities_.end()) {
129 auto &current_messages = get_activity(caller_id).messages();
130
132 std::move(message), start_type, current_messages);
133 }
134}

◆ finalize()

void clanguml::sequence_diagram::model::diagram::finalize ( )
overridevirtual

Once the diagram is complete, run any final processing.

This method should be overriden by specific diagram models to do some final tasks like cleaning up the model (e.g. some filters only work on completed diagrams).

Reimplemented from clanguml::common::model::diagram.

Definition at line 595 of file diagram.cc.

596{
597 // Apply diagram filters and remove any empty block statements
599
600 // First in each sequence (activity) filter out any remaining
601 // uninteresting calls
602 for (auto &[id, act] : activities_) {
603 util::erase_if(act.messages(), [this](auto &m) {
604 if (m.type() != message_t::kCall)
605 return false;
606
607 const auto &to = get_participant<model::participant>(m.to());
608 if (!to || to.value().skip())
609 return true;
610
611 if (!should_include(to.value())) {
612 LOG_DBG("Excluding call from [{}] to {} [{}]", m.from(),
613 to.value().full_name(false), m.to());
614 return true;
615 }
616
617 return false;
618 });
619 }
620
621 // Now remove any empty block statements, e.g. if/endif
622 for (auto &[id, act] : activities_) {
623 int64_t block_nest_level{0};
624 std::vector<std::vector<message>> block_message_stack;
625 // Add first stack level - this level will contain the filtered
626 // message sequence
627 block_message_stack.emplace_back();
628
629 // First create a recursive stack from the messages and
630 // message blocks (e.g. if statements)
631 for (auto &m : act.messages()) {
632 if (is_begin_block_message(m.type())) {
633 block_nest_level++;
634 block_message_stack.push_back({m});
635 }
636 else if (is_end_block_message(m.type())) {
637 block_nest_level--;
638
639 block_message_stack.back().push_back(m);
640
641 // Check the last stack for any calls, if yes, collapse it
642 // on the previous stack
643 if (std::count_if(block_message_stack.back().begin(),
644 block_message_stack.back().end(), [](auto &m) {
645 return m.type() == message_t::kCall;
646 }) > 0) {
647 std::copy(block_message_stack.back().begin(),
648 block_message_stack.back().end(),
649 std::back_inserter(
650 block_message_stack.at(block_nest_level)));
651 }
652
653 block_message_stack.pop_back();
654
655 assert(block_nest_level >= 0);
656 }
657 else {
658 if (m.type() == message_t::kCall) {
659 // Set the message return type based on the callee return
660 // type
661 auto to_participant =
662 get_participant<sequence_diagram::model::function>(
663 m.to());
664 if (to_participant.has_value()) {
665 m.set_return_type(to_participant.value().return_type());
666 }
667 }
668 block_message_stack.back().push_back(m);
669 }
670 }
671
672 act.messages().clear();
673
674 for (auto &m : block_message_stack[0]) {
675 act.add_message(m);
676 }
677 }
678}

◆ fold_or_end_block_statement()

void clanguml::sequence_diagram::model::diagram::fold_or_end_block_statement ( message &&  m,
common::model::message_t  statement_begin,
std::vector< message > &  current_messages 
) const
private

This method checks the last messages in sequence (current_messages), if they represent a block sequence identified by statement_begin (e.g. if/else) and there are no actual call expressions within this block statement the entire block statement is removed from the end of the sequence.

Otherwise the block statement is ended with a proper statement (e.g. endif)

Parameters
mMessage to add to the sequence
statement_beginType of message which begins this type of block statement (e.g. message_t::kIf)
current_messagesReference to the sequence messages which should be amended

Definition at line 570 of file diagram.cc.

573{
574 bool is_empty_statement{true};
575
576 auto rit = current_messages.rbegin();
577 for (; rit != current_messages.rend(); rit++) {
578 if (rit->type() == statement_begin) {
579 break;
580 }
581 if (rit->type() == common::model::message_t::kCall) {
582 is_empty_statement = false;
583 break;
584 }
585 }
586
587 if (is_empty_statement) {
588 current_messages.erase((rit + 1).base(), current_messages.end());
589 }
590 else {
591 current_messages.emplace_back(std::move(m));
592 }
593}

◆ get() [1/2]

common::optional_ref< common::model::diagram_element > clanguml::sequence_diagram::model::diagram::get ( const std::string &  full_name) const
overridevirtual

Search for element in the diagram by fully qualified name.

Parameters
full_nameFully qualified element name.
Returns
Optional reference to a diagram element.

Implements clanguml::common::model::diagram.

Definition at line 33 of file diagram.cc.

35{
36 for (const auto &[id, participant] : participants_) {
37 if (participant->full_name(false) == full_name)
38 return {*participant};
39 }
40
41 return {};
42}

◆ get() [2/2]

common::optional_ref< common::model::diagram_element > clanguml::sequence_diagram::model::diagram::get ( eid_t  id) const
overridevirtual

Search for element in the diagram by id.

Parameters
idElement id.
Returns
Optional reference to a diagram element.

Implements clanguml::common::model::diagram.

Definition at line 44 of file diagram.cc.

46{
47 if (participants_.find(id) != participants_.end())
48 return {*participants_.at(id)};
49
50 return {};
51}

◆ get_activity() [1/2]

activity & clanguml::sequence_diagram::model::diagram::get_activity ( eid_t  id)

Get reference to current activity of a participant.

Parameters
idParticipant id
Returns

Definition at line 105 of file diagram.cc.

105{ return activities_.at(id); }

◆ get_activity() [2/2]

const activity & clanguml::sequence_diagram::model::diagram::get_activity ( eid_t  id) const

Get reference to current activity of a participant.

Parameters
idParticipant id
Returns

Definition at line 98 of file diagram.cc.

99{
100 return activities_.at(id);
101}

◆ get_all_from_to_message_chains()

std::vector< message_chain_t > clanguml::sequence_diagram::model::diagram::get_all_from_to_message_chains ( eid_t  from_activity,
eid_t  to_activity 
) const

Generate a list of message chains matching a from_to constraint.

If 'from_activity' is 0, this method will return all message chains ending in 'to_activity'.

Parameters
from_activitySource activity for from_to message chain
to_activityTarget activity for from_to message chain
Returns
List of message chains

Definition at line 278 of file diagram.cc.

280{
281 std::vector<message_chain_t> message_chains_unique{};
282
283 // Message (call) chains matching the specified from_to condition
284 std::vector<message_chain_t> message_chains;
285
286 // First find all 'to_activity' call targets in the sequences, i.e.
287 // all messages pointing to the final 'to_activity' activity
288 for (const auto &[k, v] : sequences()) {
289 for (const auto &m : v.messages()) {
290 if (m.type() != common::model::message_t::kCall)
291 continue;
292
293 if (m.to() == to_activity) {
294 message_chains.emplace_back();
295 message_chains.back().push_back(m);
296 }
297 }
298 }
299
300 std::map<unsigned int, std::vector<model::message>> calls_to_current_chain;
301 std::map<unsigned int, message_chain_t> current_chain;
302
303 int iter = 0;
304 while (true) {
305 bool added_message_to_some_chain{false};
306 // If target of current message matches any of the
307 // 'from' constraints in the last messages in
308 // current chains found on previous iteration - append
309 if (!calls_to_current_chain.empty()) {
310 for (auto &[message_chain_index, messages] :
311 calls_to_current_chain) {
312 for (auto &m : messages) {
313 message_chains.push_back(
314 current_chain[message_chain_index]);
315
316 message_chains.back().push_back(std::move(m));
317 }
318 }
319 calls_to_current_chain.clear();
320 }
321
322 LOG_TRACE("Message chains after iteration {}", iter++);
323 int message_chain_index{};
324 for (const auto &mc : message_chains) {
325 LOG_TRACE("\t{}: {}", message_chain_index++,
326 fmt::join(util::map<std::string>(mc,
327 [](const model::message &m) -> std::string {
328 return m.message_name();
329 }),
330 "<-"));
331 }
332
333 for (auto i = 0U; i < message_chains.size(); i++) {
334 auto &mc = message_chains[i];
335 current_chain[i] = mc;
336 for (const auto &[k, v] : sequences()) {
337 for (const auto &m : v.messages()) {
338 if (m.type() != common::model::message_t::kCall)
339 continue;
340
341 // Ignore recursive calls and call loops
342 if (m.to() == m.from() ||
343 std::any_of(
344 cbegin(mc), cend(mc), [&m](const auto &msg) {
345 return msg.to() == m.from();
346 })) {
347 continue;
348 }
349
350 if (m.to() == mc.back().from()) {
351 calls_to_current_chain[i].push_back(m);
352 added_message_to_some_chain = true;
353 }
354 }
355 }
356
357 // If there are more than one call to the current chain,
358 // duplicate it as many times as there are calls - 1
359 if (calls_to_current_chain.count(i) > 0 &&
360 !calls_to_current_chain[i].empty()) {
361 mc.push_back(calls_to_current_chain[i][0]);
362 calls_to_current_chain[i].erase(
363 calls_to_current_chain[i].begin());
364 }
365 }
366
367 // There is nothing more to find
368 if (!added_message_to_some_chain)
369 break;
370 }
371
372 // Reverse the message chains order (they were added starting from
373 // the destination activity)
374 for (auto &mc : message_chains) {
375 std::reverse(mc.begin(), mc.end());
376
377 if (mc.empty())
378 continue;
379
380 if (std::find(message_chains_unique.begin(),
381 message_chains_unique.end(), mc) != message_chains_unique.end())
382 continue;
383
384 if (from_activity.value() == 0 ||
385 (mc.front().from() == from_activity)) {
386 message_chains_unique.push_back(mc);
387 }
388 }
389
390 LOG_TRACE("Message chains unique", iter++);
391 int message_chain_index{};
392 for (const auto &mc : message_chains_unique) {
393 LOG_TRACE("\t{}: {}", message_chain_index++,
394 fmt::join(util::map<std::string>(mc,
395 [](const model::message &m) -> std::string {
396 return m.message_name();
397 }),
398 "->"));
399 }
400
401 return message_chains_unique;
402}

◆ get_from_activity_id()

std::optional< eid_t > clanguml::sequence_diagram::model::diagram::get_from_activity_id ( const config::source_location from_location) const

Get id of a 'from' activity.

Parameters
from_locationSource activity
Returns
Activity id

Definition at line 254 of file diagram.cc.

256{
257 std::optional<eid_t> from_activity{};
258
259 for (const auto &[k, v] : sequences()) {
260 const auto &caller = *participants().at(v.from());
261 std::string vfrom = caller.full_name(false);
262 if (vfrom == from_location.location) {
263 LOG_DBG("Found sequence diagram start point '{}': {}", vfrom, k);
264 from_activity = k;
265 break;
266 }
267 }
268
269 if (!from_activity.has_value()) {
270 LOG_WARN("Failed to find 'from' participant {} for from "
271 "condition",
272 from_location.location);
273 }
274
275 return from_activity;
276}

◆ get_participant()

template<typename T >
common::optional_ref< T > clanguml::sequence_diagram::model::diagram::get_participant ( eid_t  id) const
inline

Get participant by id.

Parameters
idParticipant id.
Returns
Optional reference to a diagram element.

Definition at line 79 of file diagram.h.

80 {
81 if (participants_.find(id) == participants_.end()) {
82 return {};
83 }
84
85 return common::optional_ref<T>(
86 dynamic_cast<T *>(participants_.at(id).get()));
87 }

◆ get_to_activity_id()

std::optional< eid_t > clanguml::sequence_diagram::model::diagram::get_to_activity_id ( const config::source_location to_location) const

Get id of a 'to' activity.

Parameters
to_locationTarget activity
Returns
Activity id

Definition at line 225 of file diagram.cc.

227{
228 std::optional<eid_t> to_activity{};
229
230 for (const auto &[k, v] : sequences()) {
231 for (const auto &m : v.messages()) {
232 if (m.type() != common::model::message_t::kCall)
233 continue;
234 const auto &callee = *participants().at(m.to());
235 std::string vto = callee.full_name(false);
236 if (vto == to_location.location) {
237 LOG_DBG(
238 "Found sequence diagram end point '{}': {}", vto, m.to());
239 to_activity = m.to();
240 break;
241 }
242 }
243 }
244
245 if (!to_activity.has_value()) {
246 LOG_WARN("Failed to find 'to' participant {} for to "
247 "condition",
248 to_location.location);
249 }
250
251 return to_activity;
252}

◆ has_activity()

bool clanguml::sequence_diagram::model::diagram::has_activity ( eid_t  id) const

Check if diagram has activity identified by caller id.

Parameters
idCaller id representing the activity
Returns
True, if an activity already exists

Definition at line 103 of file diagram.cc.

103{ return activities_.count(id) > 0; }

◆ inline_lambda_operator_call()

bool clanguml::sequence_diagram::model::diagram::inline_lambda_operator_call ( eid_t  id,
model::activity new_activity,
const model::message m 
)
private

Definition at line 485 of file diagram.cc.

487{
488 bool message_call_to_lambda{false};
489 auto maybe_lambda_operator = get_participant<model::method>(m.to());
490
491 if (maybe_lambda_operator) {
492 const auto parent_class_id = maybe_lambda_operator.value().class_id();
493 auto maybe_parent_class =
494 get_participant<model::class_>(parent_class_id);
495
496 if (maybe_parent_class && maybe_parent_class.value().is_lambda()) {
497 if (has_activity(m.to())) {
498 auto lambda_operator_activity = get_activity(m.to());
499
500 // For each call in that lambda activity - reattach this
501 // call to the current activity
502 for (auto &mm : lambda_operator_activity.messages()) {
503 if (!inline_lambda_operator_call(id, new_activity, mm)) {
504 auto new_message{mm};
505
506 new_message.set_from(id);
507 new_activity.add_message(new_message);
508 }
509 }
510 }
511
512 message_call_to_lambda = true;
513 }
514 }
515
516 return message_call_to_lambda;
517}

◆ inline_lambda_operator_calls()

void clanguml::sequence_diagram::model::diagram::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

Definition at line 409 of file diagram.cc.

410{
411 std::map<eid_t, activity> activities;
412 std::map<eid_t, std::unique_ptr<participant>> participants;
413 std::set<eid_t> active_participants;
414
415 for (auto &[id, act] : sequences()) {
416 model::activity new_activity{id};
417
418 // If activity is a lambda operator() - skip it
419 auto maybe_lambda_activity = get_participant<model::method>(id);
420
421 if (maybe_lambda_activity) {
422 const auto parent_class_id =
423 maybe_lambda_activity.value().class_id();
424 auto maybe_parent_class =
425 get_participant<model::class_>(parent_class_id);
426
427 if (maybe_parent_class && maybe_parent_class.value().is_lambda()) {
428 continue;
429 }
430 }
431
432 // For other activities, check each message - if it calls lambda
433 // operator() - reattach the message to the next activity in the chain
434 // (assuming it's not lambda)
435 for (auto &m : act.messages()) {
436
437 auto message_call_to_lambda{false};
438
439 message_call_to_lambda =
440 inline_lambda_operator_call(id, new_activity, m);
441
442 if (!message_call_to_lambda)
443 new_activity.add_message(m);
444 }
445
446 // Add activity
447 activities.insert({id, std::move(new_activity)});
448 }
449
450 for (auto &&[id, p] : this->participants()) {
451 // Skip participants which are lambda classes
452 if (const auto *maybe_class =
453 dynamic_cast<const model::class_ *>(p.get());
454 maybe_class != nullptr && maybe_class->is_lambda()) {
455 continue;
456 }
457
458 // Skip participants which are lambda operator methods
459 if (const auto *maybe_method =
460 dynamic_cast<const model::method *>(p.get());
461 maybe_method != nullptr) {
462 auto maybe_class =
463 get_participant<model::class_>(maybe_method->class_id());
464 if (maybe_class && maybe_class.value().is_lambda())
465 continue;
466 }
467
468 // Otherwise move the participant to the new diagram model
469 auto participant_id = p->id();
470 participants.emplace(participant_id, std::move(p));
471 }
472
473 // Skip active participants which are not in lambdaless_diagram participants
474 for (auto id : this->active_participants()) {
475 if (participants.count(id) > 0) {
476 active_participants.emplace(id);
477 }
478 }
479
480 activities_ = std::move(activities);
481 participants_ = std::move(participants);
483}

◆ is_begin_block_message()

bool clanguml::sequence_diagram::model::diagram::is_begin_block_message ( common::model::message_t  mt)
inlineprivate

Definition at line 325 of file diagram.h.

326 {
328 static std::set<message_t> block_begin_types{message_t::kIf,
329 message_t::kWhile, message_t::kDo, message_t::kFor, message_t::kTry,
330 message_t::kSwitch, message_t::kConditional};
331
332 return block_begin_types.count(mt) > 0;
333 };

◆ is_empty()

bool clanguml::sequence_diagram::model::diagram::is_empty ( ) const
overridevirtual

Check whether the diagram is empty.

Returns
True, if diagram is empty

Implements clanguml::common::model::diagram.

Definition at line 404 of file diagram.cc.

405{
406 return activities_.empty() || participants_.empty();
407}

◆ is_end_block_message()

bool clanguml::sequence_diagram::model::diagram::is_end_block_message ( common::model::message_t  mt)
inlineprivate

Definition at line 335 of file diagram.h.

336 {
338 static std::set<message_t> block_end_types{message_t::kIfEnd,
339 message_t::kWhileEnd, message_t::kDoEnd, message_t::kForEnd,
340 message_t::kTryEnd, message_t::kSwitchEnd,
341 message_t::kConditionalEnd};
342
343 return block_end_types.count(mt) > 0;
344 };

◆ list_from_values()

std::vector< std::string > clanguml::sequence_diagram::model::diagram::list_from_values ( ) const

Get list of all possible 'from' values in the model.

Returns
List of all possible 'from' values

Definition at line 186 of file diagram.cc.

187{
188 std::vector<std::string> result;
189
190 for (const auto &[from_id, act] : activities_) {
191
192 const auto &from_activity = *(participants_.at(from_id));
193 const auto &full_name = from_activity.full_name(false);
194 if (!full_name.empty())
195 result.push_back(full_name);
196 }
197
198 std::sort(result.begin(), result.end());
199 result.erase(std::unique(result.begin(), result.end()), result.end());
200
201 return result;
202}

◆ list_to_values()

std::vector< std::string > clanguml::sequence_diagram::model::diagram::list_to_values ( ) const

Get list of all possible 'to' values in the model.

Returns
List of all possible 'to' values

Definition at line 204 of file diagram.cc.

205{
206 std::vector<std::string> result;
207
208 for (const auto &[from_id, act] : activities_) {
209 for (const auto &m : act.messages()) {
210 if (participants_.count(m.to()) > 0) {
211 const auto &to_activity = *(participants_.at(m.to()));
212 const auto &full_name = to_activity.full_name(false);
213 if (!full_name.empty())
214 result.push_back(full_name);
215 }
216 }
217 }
218
219 std::sort(result.begin(), result.end());
220 result.erase(std::unique(result.begin(), result.end()), result.end());
221
222 return result;
223}

◆ operator=() [1/2]

diagram & clanguml::sequence_diagram::model::diagram::operator= ( const diagram )
delete

◆ operator=() [2/2]

diagram & clanguml::sequence_diagram::model::diagram::operator= ( diagram &&  )
default

◆ participants() [1/2]

std::map< eid_t, std::unique_ptr< participant > > & clanguml::sequence_diagram::model::diagram::participants ( )

Get map of all participants in the diagram.

Returns
Map of participants in the diagram

Definition at line 160 of file diagram.cc.

161{
162 return participants_;
163}

◆ participants() [2/2]

const std::map< eid_t, std::unique_ptr< participant > > & clanguml::sequence_diagram::model::diagram::participants ( ) const

Get map of all participants in the diagram.

Returns
Map of participants in the diagram

Definition at line 166 of file diagram.cc.

167{
168 return participants_;
169}

◆ print()

void clanguml::sequence_diagram::model::diagram::print ( ) const

Debug method for printing entire diagram to console.

Definition at line 519 of file diagram.cc.

520{
521 LOG_TRACE(" --- Participants ---");
522 for (const auto &[id, participant] : participants_) {
523 LOG_DBG("{} - {}", id, participant->to_string());
524 }
525
526 LOG_TRACE(" --- Activities ---");
527 for (const auto &[from_id, act] : activities_) {
528 if (participants_.count(from_id) == 0)
529 continue;
530
531 LOG_TRACE("Sequence id={}:", from_id);
532
533 const auto &from_activity = *(participants_.at(from_id));
534
535 LOG_TRACE(" Activity id={}, from={}:", act.from(),
536 from_activity.full_name(false));
537
538 for (const auto &message : act.messages()) {
539 if (participants_.find(message.from()) == participants_.end())
540 continue;
541
542 const auto &from_participant = *participants_.at(message.from());
543
544 if (participants_.find(message.to()) == participants_.end()) {
545 LOG_TRACE(" Message from={}, from_id={}, "
546 "to={}, to_id={}, name={}, type={}",
547 from_participant.full_name(false), from_participant.id(),
548 "__UNRESOLVABLE_ID__", message.to(), message.message_name(),
549 to_string(message.type()));
550 }
551 else {
552 const auto &to_participant = *participants_.at(message.to());
553
554 std::string message_comment{"None"};
555 if (const auto &cmt = message.comment(); cmt.has_value()) {
556 message_comment = cmt.value().at("comment");
557 }
558
559 LOG_TRACE(" Message from={}, from_id={}, "
560 "to={}, to_id={}, name={}, type={}, comment={}",
561 from_participant.full_name(false), from_participant.id(),
562 to_participant.full_name(false), to_participant.id(),
563 message.message_name(), to_string(message.type()),
564 message_comment);
565 }
566 }
567 }
568}

◆ sequences() [1/2]

std::map< eid_t, activity > & clanguml::sequence_diagram::model::diagram::sequences ( )

Get all sequences in the diagram.

Returns
Map of sequences in the diagram

Definition at line 153 of file diagram.cc.

153{ return activities_; }

◆ sequences() [2/2]

const std::map< eid_t, activity > & clanguml::sequence_diagram::model::diagram::sequences ( ) const

Get all sequences in the diagram.

Returns
Map of sequences in the diagram

Definition at line 155 of file diagram.cc.

156{
157 return activities_;
158}

◆ should_include()

bool clanguml::sequence_diagram::model::diagram::should_include ( const sequence_diagram::model::participant p) const

Convenience should_include overload for participant.

Parameters
pParticipant model
Returns
True, if the participant should be included in the diagram

Definition at line 178 of file diagram.cc.

180{
181 return filter().should_include(p) &&
183 dynamic_cast<const common::model::source_location &>(p));
184}

◆ to_alias()

std::string clanguml::sequence_diagram::model::diagram::to_alias ( const std::string &  full_name) const

Convert element full name to PlantUML alias.

Todo:
This method does not belong here - refactor to PlantUML specific code.
Parameters
full_nameFull name of the diagram element.
Returns
PlantUML alias.

Definition at line 53 of file diagram.cc.

54{
55 return full_name;
56}

◆ type()

common::model::diagram_t clanguml::sequence_diagram::model::diagram::type ( ) const
overridevirtual

Get the diagram model type - in this case sequence.

Returns
Type of sequence diagram.

Implements clanguml::common::model::diagram.

Definition at line 28 of file diagram.cc.

Member Data Documentation

◆ active_participants_

std::set<eid_t> clanguml::sequence_diagram::model::diagram::active_participants_
private

Definition at line 353 of file diagram.h.

◆ activities_

std::map<eid_t, activity> clanguml::sequence_diagram::model::diagram::activities_
private

Definition at line 349 of file diagram.h.

◆ participants_

std::map<eid_t, std::unique_ptr<participant> > clanguml::sequence_diagram::model::diagram::participants_
private

Definition at line 351 of file diagram.h.


The documentation for this class was generated from the following files: