0.6.0
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 57 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.
 
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.
 
void build_reverse_call_graph (reverse_call_graph_activity_node &node, std::set< eid_t > visited_callers={}) const
 Build reverse call graph.
 
std::vector< eid_tget_to_activity_ids (const config::source_location &to_location) const
 Get ids of activities matching 'to'.
 
std::vector< eid_tget_from_activity_ids (const config::source_location &from_location) const
 Get ids of activities matching 'from'.
 
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 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 196 of file diagram.cc.

196{ 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 198 of file diagram.cc.

199{
201}

◆ 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 110 of file diagram.cc.

111{
112 active_participants_.emplace(id);
113}

◆ 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 143 of file diagram.cc.

144{
145 add_message(std::move(message));
146}

◆ 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 161 of file diagram.cc.

162{
164 const auto caller_id = m.from();
165
166 if (activities_.find(caller_id) != activities_.end()) {
167 auto &current_messages = get_activity(caller_id).messages();
168
169 if (current_messages.back().type() == message_t::kCase) {
170 // Do nothing - fallthroughs not supported yet...
171 }
172 else {
173 current_messages.emplace_back(std::move(m));
174 }
175 }
176}

◆ add_message()

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

Add message to current activity.

Parameters
messageMessage model

Definition at line 124 of file diagram.cc.

125{
126 const auto caller_id = message.from();
127 const auto callee_id = message.to();
128
129 if (activities_.find(caller_id) == activities_.end()) {
130 activity a{caller_id};
131 activities_.insert({caller_id, std::move(a)});
132 }
133
134 if (activities_.find(callee_id) == activities_.end()) {
135 activity a{callee_id};
136 activities_.insert({callee_id, std::move(a)});
137 }
138
139 get_activity(callee_id).add_caller(caller_id);
140 get_activity(caller_id).add_message(std::move(message));
141}

◆ 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 91 of file diagram.cc.

92{
93 const auto participant_id = p->id();
94
95 p->complete(true);
96
97 assert(participant_id.is_global());
98
99 if (participants_.find(participant_id) == participants_.end()) {
100 LOG_DBG("Adding '{}' participant: {}, {} [{}]", p->type_name(),
101 p->full_name(false), p->id(),
102 p->type_name() == "method"
103 ? dynamic_cast<method *>(p.get())->method_name()
104 : "");
105
106 participants_.emplace(participant_id, std::move(p));
107 }
108}

◆ build_reverse_call_graph()

void clanguml::sequence_diagram::model::diagram::build_reverse_call_graph ( reverse_call_graph_activity_node node,
std::set< eid_t visited_callers = {} 
) const

Build reverse call graph.

This method builds a reverse call graph tree based on callers() list stored in each activity.

Parameters
nodeThe current reverse call graph node
visited_callersThis is necessary for breaking recursive calls

Definition at line 309 of file diagram.cc.

311{
312 LOG_INFO("Building reverse call graph for activity: {}", node.activity_id);
313
314 if (sequences().count(node.activity_id) == 0)
315 return;
316
317 visited_callers.insert(node.activity_id);
318
319 const auto &callers = sequences().at(node.activity_id).callers();
320
321 for (const auto &caller : callers) {
322 if (visited_callers.count(caller) > 0) {
323 // break recursive calls
324 continue;
325 }
326
327 reverse_call_graph_activity_node caller_node;
328 caller_node.activity_id = caller;
329
330 build_reverse_call_graph(caller_node, visited_callers);
331
332 node.callers.emplace_back(std::move(caller_node));
333 }
334}

◆ 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 148 of file diagram.cc.

150{
151 const auto caller_id = message.from();
152
153 if (activities_.find(caller_id) != activities_.end()) {
154 auto &current_messages = get_activity(caller_id).messages();
155
157 std::move(message), start_type, current_messages);
158 }
159}

◆ 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 620 of file diagram.cc.

621{
622 // Apply diagram filters and remove any empty block statements
624
625 // First in each sequence (activity) filter out any remaining
626 // uninteresting calls
627 for (auto &[id, act] : activities_) {
628 util::erase_if(act.messages(), [this](auto &m) {
629 if (m.type() != message_t::kCall)
630 return false;
631
632 const auto &to = get_participant<model::participant>(m.to());
633 if (!to || to.value().skip())
634 return true;
635
636 if (!should_include(to.value())) {
637 LOG_DBG("Excluding call from [{}] to {} [{}]", m.from(),
638 to.value().full_name(false), m.to());
639 return true;
640 }
641
642 return false;
643 });
644 }
645
646 // Now remove any empty block statements, e.g. if/endif
647 for (auto &[id, act] : activities_) {
648 int64_t block_nest_level{0};
649 std::vector<std::vector<message>> block_message_stack;
650 // Add first stack level - this level will contain the filtered
651 // message sequence
652 block_message_stack.emplace_back();
653
654 // First create a recursive stack from the messages and
655 // message blocks (e.g. if statements)
656 for (auto &m : act.messages()) {
657 if (is_begin_block_message(m.type())) {
658 block_nest_level++;
659 block_message_stack.push_back({m});
660 }
661 else if (is_end_block_message(m.type())) {
662 block_nest_level--;
663
664 block_message_stack.back().push_back(m);
665
666 // Check the last stack for any calls, if yes, collapse it
667 // on the previous stack
668 if (std::count_if(block_message_stack.back().begin(),
669 block_message_stack.back().end(), [](auto &m) {
670 return m.type() == message_t::kCall;
671 }) > 0) {
672 std::copy(block_message_stack.back().begin(),
673 block_message_stack.back().end(),
674 std::back_inserter(
675 block_message_stack.at(block_nest_level)));
676 }
677
678 block_message_stack.pop_back();
679
680 assert(block_nest_level >= 0);
681 }
682 else {
683 if (m.type() == message_t::kCall) {
684 // Set the message return type based on the callee return
685 // type
686 auto to_participant =
687 get_participant<sequence_diagram::model::function>(
688 m.to());
689 if (to_participant.has_value()) {
690 m.set_return_type(to_participant.value().return_type());
691 }
692 }
693 block_message_stack.back().push_back(m);
694 }
695 }
696
697 act.messages().clear();
698
699 for (auto &m : block_message_stack[0]) {
700 act.add_message(m);
701 }
702 }
703}

◆ 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 595 of file diagram.cc.

598{
599 bool is_empty_statement{true};
600
601 auto rit = current_messages.rbegin();
602 for (; rit != current_messages.rend(); rit++) {
603 if (rit->type() == statement_begin) {
604 break;
605 }
606 if (rit->type() == common::model::message_t::kCall) {
607 is_empty_statement = false;
608 break;
609 }
610 }
611
612 if (is_empty_statement) {
613 current_messages.erase((rit + 1).base(), current_messages.end());
614 }
615 else {
616 current_messages.emplace_back(std::move(m));
617 }
618}

◆ 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 66 of file diagram.cc.

68{
69 for (const auto &[id, participant] : participants_) {
70 if (participant->full_name(false) == full_name)
71 return {*participant};
72 }
73
74 return {};
75}

◆ 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 77 of file diagram.cc.

79{
80 if (participants_.find(id) != participants_.end())
81 return {*participants_.at(id)};
82
83 return {};
84}

◆ 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 122 of file diagram.cc.

122{ 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 115 of file diagram.cc.

116{
117 return activities_.at(id);
118}

◆ 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 336 of file diagram.cc.

338{
339 // Message (call) chains matching the specified from_to condition
340 std::vector<message_chain_t> message_chains;
341
342 // First, build reverse call graph starting from target `to_activity`
343 // `target_roots` should contain all activities which call `to_activity`
344 reverse_call_graph_activity_node target_roots;
345 target_roots.activity_id = to_activity;
346
347 for (const auto &[k, v] : sequences()) {
348 for (const auto &m : v.messages()) {
349 if (m.type() != common::model::message_t::kCall)
350 continue;
351
352 if (m.to() == to_activity) {
353 reverse_call_graph_activity_node node;
354 node.activity_id = m.from();
355 target_roots.callers.emplace_back(std::move(node));
356 }
357 }
358 }
359
360 // Now recurse from the initial target activities based on reverse
361 // callers list stored in each activity
362 for (auto &caller : target_roots.callers)
364
365 // Convert the reverse call graph into a list of call chains using
366 // depth first search
367 auto activity_id_chains = find_reverse_message_chains(target_roots);
368
369 // Make sure the activity call chains list is unique
370 sort(begin(activity_id_chains), end(activity_id_chains));
371 activity_id_chains.erase(
372 unique(begin(activity_id_chains), end(activity_id_chains)),
373 end(activity_id_chains));
374
375 // Convert the call chains with activity ids to lists of actual messages
376 for (const auto &chain : activity_id_chains) {
377 message_chain_t message_chain;
378 for (auto it = begin(chain); it != end(chain); it++) {
379 const auto next_it = it + 1;
380 if (next_it == end(chain))
381 break;
382
383 auto from_id = *it;
384 if (activities_.count(from_id) == 0)
385 continue;
386
387 auto to_id = *(next_it);
388
389 const auto &act = activities_.at(from_id);
390
391 for (const auto &m : act.messages()) {
392 if (m.to() == to_id) {
393 message_chain.push_back(m);
394 break;
395 }
396 }
397 }
398 message_chains.emplace_back(std::move(message_chain));
399 }
400
401 // Perform final filtering of the message chains
402 std::vector<message_chain_t> message_chains_filtered{};
403
404 for (auto &mc : message_chains) {
405 // Skip empty chains
406 if (mc.empty())
407 continue;
408
409 // Make sure the chain has valid starting point
410 if (from_activity.value() == 0 ||
411 (mc.front().from() == from_activity)) {
412 message_chains_filtered.push_back(mc);
413 }
414 }
415
416 int message_chain_index{};
417 for (const auto &mc : message_chains_filtered) {
418 LOG_INFO("\t{}: {}", message_chain_index++,
419 fmt::join(util::map<std::string>(mc,
420 [](const model::message &m) -> std::string {
421 return m.message_name();
422 }),
423 "->"));
424 }
425
426 return message_chains_filtered;
427}

◆ get_from_activity_ids()

std::vector< eid_t > clanguml::sequence_diagram::model::diagram::get_from_activity_ids ( const config::source_location from_location) const

Get ids of activities matching 'from'.

Parameters
from_locationSource activity
Returns
Activity id

Definition at line 281 of file diagram.cc.

283{
284 std::vector<eid_t> from_activities{};
285
286 for (const auto &[k, v] : sequences()) {
287 if (participants().count(v.from()) == 0)
288 continue;
289
290 const auto &caller = *participants().at(v.from());
291 std::string vfrom = caller.full_name(false);
292 if (from_location.location == vfrom) {
293 LOG_DBG("Found sequence diagram start point '{}': {}", vfrom, k);
294 from_activities.push_back(k);
295 }
296 }
297
298 if (from_activities.empty()) {
299 LOG_WARN("Failed to find 'from' participant {} for from "
300 "condition: ",
301 from_location.location.to_string());
302 }
303
304 util::remove_duplicates(from_activities);
305
306 return from_activities;
307}

◆ 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 98 of file diagram.h.

99 {
100 if (participants_.find(id) == participants_.end()) {
101 return {};
102 }
103
104 return common::optional_ref<T>(
105 dynamic_cast<T *>(participants_.at(id).get()));
106 }

◆ get_to_activity_ids()

std::vector< eid_t > clanguml::sequence_diagram::model::diagram::get_to_activity_ids ( const config::source_location to_location) const

Get ids of activities matching 'to'.

Parameters
to_locationTarget activity
Returns
Activity id

Definition at line 250 of file diagram.cc.

252{
253 std::vector<eid_t> to_activities{};
254
255 for (const auto &[k, v] : sequences()) {
256 for (const auto &m : v.messages()) {
257 if (m.type() != common::model::message_t::kCall)
258 continue;
259
260 const auto &callee = *participants().at(m.to());
261 std::string vto = callee.full_name(false);
262 if (to_location.location == vto) {
263 LOG_DBG(
264 "Found sequence diagram end point '{}': {}", vto, m.to());
265 to_activities.push_back(m.to());
266 }
267 }
268 }
269
270 if (to_activities.empty()) {
271 LOG_WARN("Failed to find 'to' participant {} for to "
272 "condition: ",
273 to_location.location.to_string());
274 }
275
276 util::remove_duplicates(to_activities);
277
278 return to_activities;
279}

◆ 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 120 of file diagram.cc.

120{ 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 510 of file diagram.cc.

512{
513 bool message_call_to_lambda{false};
514 auto maybe_lambda_operator = get_participant<model::method>(m.to());
515
516 if (maybe_lambda_operator) {
517 const auto parent_class_id = maybe_lambda_operator.value().class_id();
518 auto maybe_parent_class =
519 get_participant<model::class_>(parent_class_id);
520
521 if (maybe_parent_class && maybe_parent_class.value().is_lambda()) {
522 if (has_activity(m.to())) {
523 auto lambda_operator_activity = get_activity(m.to());
524
525 // For each call in that lambda activity - reattach this
526 // call to the current activity
527 for (auto &mm : lambda_operator_activity.messages()) {
528 if (!inline_lambda_operator_call(id, new_activity, mm)) {
529 auto new_message{mm};
530
531 new_message.set_from(id);
532 new_activity.add_message(new_message);
533 }
534 }
535 }
536
537 message_call_to_lambda = true;
538 }
539 }
540
541 return message_call_to_lambda;
542}

◆ 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 434 of file diagram.cc.

435{
436 std::map<eid_t, activity> activities;
437 std::map<eid_t, std::unique_ptr<participant>> participants;
438 std::set<eid_t> active_participants;
439
440 for (auto &[id, act] : sequences()) {
441 model::activity new_activity{id};
442
443 // If activity is a lambda operator() - skip it
444 auto maybe_lambda_activity = get_participant<model::method>(id);
445
446 if (maybe_lambda_activity) {
447 const auto parent_class_id =
448 maybe_lambda_activity.value().class_id();
449 auto maybe_parent_class =
450 get_participant<model::class_>(parent_class_id);
451
452 if (maybe_parent_class && maybe_parent_class.value().is_lambda()) {
453 continue;
454 }
455 }
456
457 // For other activities, check each message - if it calls lambda
458 // operator() - reattach the message to the next activity in the chain
459 // (assuming it's not lambda)
460 for (auto &m : act.messages()) {
461
462 auto message_call_to_lambda{false};
463
464 message_call_to_lambda =
465 inline_lambda_operator_call(id, new_activity, m);
466
467 if (!message_call_to_lambda)
468 new_activity.add_message(m);
469 }
470
471 // Add activity
472 activities.insert({id, std::move(new_activity)});
473 }
474
475 for (auto &&[id, p] : this->participants()) {
476 // Skip participants which are lambda classes
477 if (const auto *maybe_class =
478 dynamic_cast<const model::class_ *>(p.get());
479 maybe_class != nullptr && maybe_class->is_lambda()) {
480 continue;
481 }
482
483 // Skip participants which are lambda operator methods
484 if (const auto *maybe_method =
485 dynamic_cast<const model::method *>(p.get());
486 maybe_method != nullptr) {
487 auto maybe_class =
488 get_participant<model::class_>(maybe_method->class_id());
489 if (maybe_class && maybe_class.value().is_lambda())
490 continue;
491 }
492
493 // Otherwise move the participant to the new diagram model
494 auto participant_id = p->id();
495 participants.emplace(participant_id, std::move(p));
496 }
497
498 // Skip active participants which are not in lambdaless_diagram participants
499 for (auto id : this->active_participants()) {
500 if (participants.count(id) > 0) {
501 active_participants.emplace(id);
502 }
503 }
504
505 activities_ = std::move(activities);
506 participants_ = std::move(participants);
508}

◆ is_begin_block_message()

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

Definition at line 349 of file diagram.h.

350 {
352 static std::set<message_t> block_begin_types{message_t::kIf,
353 message_t::kWhile, message_t::kDo, message_t::kFor, message_t::kTry,
354 message_t::kSwitch, message_t::kConditional};
355
356 return block_begin_types.count(mt) > 0;
357 };

◆ 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 429 of file diagram.cc.

430{
431 return activities_.empty() || participants_.empty();
432}

◆ is_end_block_message()

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

Definition at line 359 of file diagram.h.

360 {
362 static std::set<message_t> block_end_types{message_t::kIfEnd,
363 message_t::kWhileEnd, message_t::kDoEnd, message_t::kForEnd,
364 message_t::kTryEnd, message_t::kSwitchEnd,
365 message_t::kConditionalEnd};
366
367 return block_end_types.count(mt) > 0;
368 };

◆ 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 211 of file diagram.cc.

212{
213 std::vector<std::string> result;
214
215 for (const auto &[from_id, act] : activities_) {
216
217 const auto &from_activity = *(participants_.at(from_id));
218 const auto &full_name = from_activity.full_name(false);
219 if (!full_name.empty())
220 result.push_back(full_name);
221 }
222
223 std::sort(result.begin(), result.end());
224 result.erase(std::unique(result.begin(), result.end()), result.end());
225
226 return result;
227}

◆ 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 229 of file diagram.cc.

230{
231 std::vector<std::string> result;
232
233 for (const auto &[from_id, act] : activities_) {
234 for (const auto &m : act.messages()) {
235 if (participants_.count(m.to()) > 0) {
236 const auto &to_activity = *(participants_.at(m.to()));
237 const auto &full_name = to_activity.full_name(false);
238 if (!full_name.empty())
239 result.push_back(full_name);
240 }
241 }
242 }
243
244 std::sort(result.begin(), result.end());
245 result.erase(std::unique(result.begin(), result.end()), result.end());
246
247 return result;
248}

◆ 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 185 of file diagram.cc.

186{
187 return participants_;
188}

◆ 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 191 of file diagram.cc.

192{
193 return participants_;
194}

◆ print()

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

Debug method for printing entire diagram to console.

Definition at line 544 of file diagram.cc.

545{
546 LOG_TRACE(" --- Participants ---");
547 for (const auto &[id, participant] : participants_) {
548 LOG_DBG("{} - {}", id, participant->to_string());
549 }
550
551 LOG_TRACE(" --- Activities ---");
552 for (const auto &[from_id, act] : activities_) {
553 if (participants_.count(from_id) == 0)
554 continue;
555
556 LOG_TRACE("Sequence id={}:", from_id);
557
558 const auto &from_activity = *(participants_.at(from_id));
559
560 LOG_TRACE(" Activity id={}, from={}:", act.from(),
561 from_activity.full_name(false));
562
563 for (const auto &message : act.messages()) {
564 if (participants_.find(message.from()) == participants_.end())
565 continue;
566
567 const auto &from_participant = *participants_.at(message.from());
568
569 if (participants_.find(message.to()) == participants_.end()) {
570 LOG_TRACE(" Message from={}, from_id={}, "
571 "to={}, to_id={}, name={}, type={}",
572 from_participant.full_name(false), from_participant.id(),
573 "__UNRESOLVABLE_ID__", message.to(), message.message_name(),
574 to_string(message.type()));
575 }
576 else {
577 const auto &to_participant = *participants_.at(message.to());
578
579 std::string message_comment{"None"};
580 if (const auto &cmt = message.comment(); cmt.has_value()) {
581 message_comment = cmt.value().at("comment");
582 }
583
584 LOG_TRACE(" Message from={}, from_id={}, "
585 "to={}, to_id={}, name={}, type={}, comment={}",
586 from_participant.full_name(false), from_participant.id(),
587 to_participant.full_name(false), to_participant.id(),
588 message.message_name(), to_string(message.type()),
589 message_comment);
590 }
591 }
592 }
593}

◆ 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 178 of file diagram.cc.

178{ 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 180 of file diagram.cc.

181{
182 return activities_;
183}

◆ 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 203 of file diagram.cc.

205{
206 return filter().should_include(p) &&
208 dynamic_cast<const common::model::source_location &>(p));
209}

◆ 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 86 of file diagram.cc.

87{
88 return full_name;
89}

◆ 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 61 of file diagram.cc.

Member Data Documentation

◆ active_participants_

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

Definition at line 377 of file diagram.h.

◆ activities_

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

Definition at line 373 of file diagram.h.

◆ participants_

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

Definition at line 375 of file diagram.h.


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