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::generators::mermaid::generator Class Reference

Sequence diagram MermaidJS generator. More...

Detailed Description

Sequence diagram MermaidJS generator.

Definition at line 49 of file sequence_diagram_generator.h.

#include <sequence_diagram_generator.h>

Public Member Functions

 generator (diagram_config &config, diagram_model &model)
 
void generate_diagram (std::ostream &ostr) const override
 Main generator method.
 
void generate_diagram_type (std::ostream &ostr) const override
 Generate the diagram type.
 
void generate_call (const clanguml::sequence_diagram::model::message &m, std::ostream &ostr) const
 Generate sequence diagram message.
 
void generate_return (const clanguml::sequence_diagram::model::message &m, std::ostream &ostr) const
 Generate sequence diagram return message.
 
void generate_participant (std::ostream &ostr, eid_t id, bool force=false) const
 Generate sequence diagram participant.
 
void generate_participant (std::ostream &ostr, const std::string &name) const
 Generate sequence diagram participant by name.
 
void generate_activity (eid_t activity_id, std::ostream &ostr, std::vector< eid_t > &visited) const
 Generate sequence diagram activity.
 
- Public Member Functions inherited from clanguml::common::generators::mermaid::generator< ConfigType, DiagramType >
 generator (ConfigType &config, DiagramType &model)
 Constructor.
 
 ~generator () override=default
 
void generate (std::ostream &ostr) const override
 Generate diagram.
 
virtual void generate_diagram (std::ostream &ostr) const =0
 Generate diagram specific part.
 
void generate_mermaid_directives (std::ostream &ostr, const std::vector< std::string > &directives) const
 Generate MermaidJS directives from config file.
 
virtual void generate_diagram_type (std::ostream &ostr) const =0
 Generate the diagram type.
 
virtual void generate_notes (std::ostream &ostr, const model::diagram_element &element) const
 Generate diagram notes.
 
void generate_metadata (std::ostream &ostr) const
 Generate comment with diagram metadata.
 
void generate_title (std::ostream &ostr) const
 Generate diagram title.
 
template<typename E >
void generate_link (std::ostream &ostr, const E &e) const
 Generate hyper link to element.
 
void print_debug (const common::model::source_location &e, std::ostream &ostr) const
 Print debug information in diagram comments.
 
- Public Member Functions inherited from clanguml::common::generators::generator< ConfigType, DiagramType >
 generator (ConfigType &config, DiagramType &model)
 Constructor.
 
virtual ~generator ()=default
 
virtual void generate (std::ostream &ostr) const =0
 Generate diagram.
 
const ConfigType & config () const
 Get reference to diagram config.
 
const DiagramType & model () const
 Get reference to diagram model.
 
std::optional< std::pair< std::string, std::string > > get_link_pattern (const common::model::source_location &sl) const
 
std::optional< std::pair< std::string, std::string > > get_tooltip_pattern (const common::model::source_location &sl) const
 
std::optional< std::string > render_link (const common::model::diagram_element &e) const
 
std::optional< std::string > render_link (const common::model::relationship &e) const
 
std::optional< std::string > render_tooltip (const common::model::diagram_element &e) const
 
std::optional< std::string > render_tooltip (const common::model::relationship &e) const
 
void init_context ()
 Initialize diagram Jinja context.
 
void update_context () const
 Update diagram Jinja context.
 
void init_env ()
 
const inja::json & context () const
 
inja::Environment & env () const
 

Private Member Functions

bool is_participant_generated (eid_t id) const
 Check if specified participant has already been generated.
 
std::string generate_alias (const model::participant &participant) const
 Generate MermaidJS alias for participant.
 
void generate_message_comment (std::ostream &ostr, const model::message &m) const
 Generate message call note.
 
model::function::message_render_mode select_method_arguments_render_mode () const
 Convert config to model message render mode.
 
void generate_from_to_sequences (std::ostream &ostr, bool star_participant_generated) const
 
void generate_to_sequences (std::ostream &ostr) const
 
void generate_from_sequences (std::ostream &ostr) const
 
std::vector< eid_tfind_from_activities () const
 
std::vector< model::message_chain_tfind_to_message_chains () const
 

Private Attributes

std::set< eid_tgenerated_participants_
 
std::set< unsigned int > generated_comment_ids_
 
std::vector< model::messagealready_generated_in_static_context_
 
std::set< eid_tgenerated_activities_
 

Additional Inherited Members

- Protected Attributes inherited from clanguml::common::generators::mermaid::generator< ConfigType, DiagramType >
std::set< std::string > m_generated_aliases
 
- Protected Attributes inherited from clanguml::common::generators::generator< ConfigType, DiagramType >
inja::json m_context
 
inja::Environment m_env
 

Constructor & Destructor Documentation

◆ generator()

clanguml::sequence_diagram::generators::mermaid::generator::generator ( diagram_config config,
diagram_model model 
)

Definition at line 39 of file sequence_diagram_generator.cc.

41 : common_generator<diagram_config, diagram_model>{config, model}
42{
43}

Member Function Documentation

◆ find_from_activities()

std::vector< eid_t > clanguml::sequence_diagram::generators::mermaid::generator::find_from_activities ( ) const
private

Definition at line 737 of file sequence_diagram_generator.cc.

738{
739 std::vector<eid_t> start_from;
740 for (const auto &sf : config().from()) {
741 if (sf.location_type == location_t::function) {
742 bool found{false};
743 for (const auto &[k, v] : model().sequences()) {
744 if (model().participants().count(v.from()) == 0)
745 continue;
746
747 const auto &caller = *model().participants().at(v.from());
748 std::string vfrom = caller.full_name(false);
749 if (sf.location == vfrom) {
750 LOG_DBG("Found sequence diagram start point: {}", k);
751 start_from.push_back(k);
752 found = true;
753 }
754 }
755
756 if (!found)
757 throw error::invalid_sequence_from_condition(model().type(),
758 model().name(),
759 fmt::format("Failed to find participant matching '{}' for "
760 "'from' condition: ",
761 sf.location.to_string()));
762 }
763 }
764
765 return start_from;
766}

◆ find_to_message_chains()

std::vector< model::message_chain_t > clanguml::sequence_diagram::generators::mermaid::generator::find_to_message_chains ( ) const
private

Definition at line 609 of file sequence_diagram_generator.cc.

610{
611 std::vector<model::message_chain_t> result;
612
613 for (const auto &to_location : config().to()) {
614 auto to_activity_ids = model().get_to_activity_ids(to_location);
615
616 if (to_activity_ids.empty()) {
617 LOG_WARN("Failed to find participant matching '{}' for "
618 "'to' condition: ",
619 to_location.location.to_string());
620 }
621
622 for (const auto &to_activity_id : to_activity_ids) {
623 std::vector<model::message_chain_t> message_chains_unique =
624 model().get_all_from_to_message_chains(eid_t{}, to_activity_id);
625
626 result.insert(result.end(), message_chains_unique.begin(),
627 message_chains_unique.end());
628 }
629 }
630
631 return result;
632}

◆ generate_activity()

void clanguml::sequence_diagram::generators::mermaid::generator::generate_activity ( eid_t  activity_id,
std::ostream &  ostr,
std::vector< eid_t > &  visited 
) const

Generate sequence diagram activity.

Parameters
activity_idActivity id
ostrOutput stream
visitedList of already visited participants, this is necessary for breaking infinite recursion on recursive calls

Definition at line 195 of file sequence_diagram_generator.cc.

197{
198 const auto &a = model().get_activity(activity_id);
199
200 const auto [it, inserted] = generated_activities_.emplace(activity_id);
201
202 if (config().fold_repeated_activities() && !inserted &&
203 !a.messages().empty()) {
204 const auto &p =
205 model().get_participant<model::participant>(activity_id);
206
207 if (p.has_value()) {
208 ostr << indent(1) << "Note over " << generate_alias(p.value())
209 << " : *\n";
210 }
211
212 return;
213 }
214
215 for (const auto &m : a.messages()) {
216 if (m.in_static_declaration_context()) {
218 continue;
219
221 }
222
223 if (m.type() == message_t::kCall) {
224 const auto &to =
225 model().get_participant<model::participant>(m.to());
226
227 visited.push_back(m.from());
228
229 LOG_DBG("Generating message [{}] --> [{}]", m.from(), m.to());
230
231 generate_call(m, ostr);
232
233 std::string to_alias = generate_alias(to.value());
234
235 ostr << indent(1) << "activate " << to_alias << '\n';
236
237 if (model().sequences().find(m.to()) != model().sequences().end()) {
238 if (std::find(visited.begin(), visited.end(), m.to()) ==
239 visited
240 .end()) { // break infinite recursion on recursive calls
241 LOG_DBG("Creating activity {} --> {} - missing sequence {}",
242 m.from(), m.to(), m.to());
243 generate_activity(m.to(), ostr, visited);
244 }
245 }
246 else
247 LOG_DBG("Skipping activity {} --> {} - missing sequence {}",
248 m.from(), m.to(), m.to());
249
250 generate_return(m, ostr);
251
252 ostr << indent(1) << "deactivate " << to_alias << '\n';
253
254 visited.pop_back();
255 }
256 else if (m.type() == message_t::kIf) {
257 print_debug(m, ostr);
259 ostr << indent(1) << "alt";
260 if (const auto &text = m.condition_text(); text.has_value())
261 ostr << " " << render_message_text(text.value());
262 ostr << '\n';
263 }
264 else if (m.type() == message_t::kElseIf) {
265 print_debug(m, ostr);
266 ostr << indent(1) << "else";
267 if (const auto &text = m.condition_text(); text.has_value())
268 ostr << " " << render_message_text(text.value());
269 ostr << '\n';
270 }
271 else if (m.type() == message_t::kElse) {
272 print_debug(m, ostr);
273 ostr << indent(1) << "else\n";
274 }
275 else if (m.type() == message_t::kIfEnd) {
276 ostr << indent(1) << "end\n";
277 }
278 else if (m.type() == message_t::kWhile) {
279 print_debug(m, ostr);
281 ostr << indent(1) << "loop";
282 if (const auto &text = m.condition_text(); text.has_value())
283 ostr << " " << render_message_text(text.value());
284 ostr << '\n';
285 }
286 else if (m.type() == message_t::kWhileEnd) {
287 ostr << indent(1) << "end\n";
288 }
289 else if (m.type() == message_t::kFor) {
290 print_debug(m, ostr);
292 ostr << indent(1) << "loop";
293 if (const auto &text = m.condition_text(); text.has_value())
294 ostr << " " << render_message_text(text.value());
295 ostr << '\n';
296 }
297 else if (m.type() == message_t::kForEnd) {
298 ostr << "end\n";
299 }
300 else if (m.type() == message_t::kDo) {
301 print_debug(m, ostr);
303 ostr << indent(1) << "loop";
304 if (const auto &text = m.condition_text(); text.has_value())
305 ostr << " " << render_message_text(text.value());
306 ostr << '\n';
307 }
308 else if (m.type() == message_t::kDoEnd) {
309 ostr << indent(1) << "end\n";
310 }
311 else if (m.type() == message_t::kTry) {
312 print_debug(m, ostr);
314 ostr << indent(1) << "critical\n";
315 }
316 else if (m.type() == message_t::kCatch) {
317 print_debug(m, ostr);
318 ostr << indent(1) << "option "
319 << render_message_text(m.message_name()) << '\n';
320 }
321 else if (m.type() == message_t::kTryEnd) {
322 print_debug(m, ostr);
323 ostr << indent(1) << "end\n";
324 }
325 else if (m.type() == message_t::kSwitch) {
326 print_debug(m, ostr);
328 ostr << indent(1) << "alt\n";
329 }
330 else if (m.type() == message_t::kCase) {
331 print_debug(m, ostr);
332 ostr << indent(1) << "else "
333 << render_message_text(m.message_name()) << '\n';
334 }
335 else if (m.type() == message_t::kSwitchEnd) {
336 ostr << indent(1) << "end\n";
337 }
338 else if (m.type() == message_t::kConditional) {
339 print_debug(m, ostr);
341 ostr << indent(1) << "alt";
342 if (const auto &text = m.condition_text(); text.has_value())
343 ostr << " " << render_message_text(text.value());
344 ostr << '\n';
345 }
346 else if (m.type() == message_t::kConditionalElse) {
347 print_debug(m, ostr);
348 ostr << indent(1) << "else\n";
349 }
350 else if (m.type() == message_t::kConditionalEnd) {
351 ostr << indent(1) << "end\n";
352 }
353 }
354}

◆ generate_alias()

std::string clanguml::sequence_diagram::generators::mermaid::generator::generate_alias ( const model::participant participant) const
private

Generate MermaidJS alias for participant.

Parameters
participantSequence diagram participant model
Returns
Particpant alias

Definition at line 514 of file sequence_diagram_generator.cc.

516{
517 if ((participant.type_name() == "function" ||
518 participant.type_name() == "function_template") &&
519 config().combine_free_functions_into_file_participants()) {
520 const auto file_id = common::to_id(participant.file());
521
522 return fmt::format("C_{:022}", file_id.value());
523 }
524
525 return participant.alias();
526}

◆ generate_call()

void clanguml::sequence_diagram::generators::mermaid::generator::generate_call ( const clanguml::sequence_diagram::model::message m,
std::ostream &  ostr 
) const

Generate sequence diagram message.

Parameters
mMessage model
ostrOutput stream

Definition at line 93 of file sequence_diagram_generator.cc.

94{
95 const auto &from = model().get_participant<model::participant>(m.from());
96 const auto &to = model().get_participant<model::participant>(m.to());
97
98 if (!from || !to) {
99 LOG_DBG("Skipping empty call from '{}' to '{}'", m.from(), m.to());
100 return;
101 }
102
103 generate_participant(ostr, m.from());
104 generate_participant(ostr, m.to());
105
106 std::string message;
107
110
111 if (to.value().type_name() == "method") {
112 const auto &f = dynamic_cast<const model::method &>(to.value());
113 message = f.message_name(render_mode);
114 }
115 else if (to.value().type_name() == "objc_method") {
116 const auto &f = dynamic_cast<const model::objc_method &>(to.value());
117 message = f.message_name(render_mode);
118 }
119 else if (config().combine_free_functions_into_file_participants()) {
120 if (to.value().type_name() == "function") {
121 const auto &f = dynamic_cast<const model::function &>(to.value());
122
123 message = f.message_name(render_mode);
124
125 if (f.is_cuda_kernel())
126 message = fmt::format("<< CUDA Kernel >><br>{}", message);
127 else if (f.is_cuda_device())
128 message = fmt::format("<< CUDA Device >><br>{}", message);
129 }
130 else if (to.value().type_name() == "function_template") {
131 const auto &f = dynamic_cast<const model::function &>(to.value());
132 message = f.message_name(render_mode);
133
134 if (f.is_cuda_kernel())
135 message = fmt::format("<< CUDA Kernel >><br>{}", message);
136 else if (f.is_cuda_device())
137 message = fmt::format("<< CUDA Device >><br>{}", message);
138 }
139 }
140
141 message = config().simplify_template_type(message);
142
143 const std::string from_alias = generate_alias(from.value());
144 const std::string to_alias = generate_alias(to.value());
145
146 print_debug(m, ostr);
147
149
150 ostr << indent(1) << from_alias << " "
151 << common::generators::mermaid::to_mermaid(message_t::kCall) << " ";
152
153 ostr << to_alias;
154
155 ostr << " : ";
156
158 ostr << "[";
159
160 ostr << message;
161
163 ostr << "]";
164
165 ostr << '\n';
166
167 LOG_DBG("Generated call '{}' from {} [{}] to {} [{}]", message,
168 from.value().full_name(false), m.from(), to.value().full_name(false),
169 m.to());
170}

◆ generate_diagram()

void clanguml::sequence_diagram::generators::mermaid::generator::generate_diagram ( std::ostream &  ostr) const
overridevirtual

Main generator method.

This method is called first and coordinates the entire diagram generation.

Parameters
ostrOutput stream.

Implements clanguml::common::generators::mermaid::generator< ConfigType, DiagramType >.

Definition at line 528 of file sequence_diagram_generator.cc.

529{
530 model().print();
531
532 if (config().participants_order.has_value) {
533 for (const auto &p : config().participants_order()) {
534 LOG_DBG("Pregenerating participant {}", p);
535 generate_participant(ostr, p);
536 }
537 }
538
539 bool star_participant_generated{false};
540
541 generate_from_to_sequences(ostr, star_participant_generated);
542
544
546}

◆ generate_diagram_type()

void clanguml::sequence_diagram::generators::mermaid::generator::generate_diagram_type ( std::ostream &  ostr) const
overridevirtual

Generate the diagram type.

Parameters
ostrOutput stream

Implements clanguml::common::generators::mermaid::generator< ConfigType, DiagramType >.

Definition at line 45 of file sequence_diagram_generator.cc.

46{
47 ostr << "sequenceDiagram\n";
48}

◆ generate_from_sequences()

void clanguml::sequence_diagram::generators::mermaid::generator::generate_from_sequences ( std::ostream &  ostr) const
private

Definition at line 548 of file sequence_diagram_generator.cc.

549{
550 std::vector<eid_t> start_from = find_from_activities();
551
552 // Use this to break out of recurrent loops
553 std::vector<eid_t> visited_participants;
554 for (const auto from_id : start_from) {
555 if (model().participants().count(from_id) == 0)
556 continue;
557
558 const auto &from = model().get_participant<model::function>(from_id);
559
560 if (!from.has_value()) {
561 LOG_WARN("Failed to find participant {} for 'from' "
562 "condition");
563 continue;
564 }
565
566 generate_participant(ostr, from_id);
567
568 std::string from_alias = generate_alias(from.value());
569
572
573 // For methods or functions in diagrams where they are combined into
574 // file participants, we need to add an 'entry' point call to know
575 // which method relates to the first activity for this 'start_from'
576 // condition
577 if (from.value().type_name() == "method" ||
578 config().combine_free_functions_into_file_participants()) {
579 ostr << indent(1) << "* "
580 << common::generators::mermaid::to_mermaid(message_t::kCall)
581 << " " << from_alias << " : "
582 << from.value().message_name(render_mode) << '\n';
583 }
584
585 ostr << indent(1) << "activate " << from_alias << '\n';
586
587 generate_activity(from_id, ostr, visited_participants);
588
589 if (from.value().type_name() == "method" ||
590 config().combine_free_functions_into_file_participants()) {
591
592 if (!from.value().is_void()) {
593 ostr << indent(1) << from_alias << " "
595 message_t::kReturn)
596 << " *" << " : ";
597
598 if (config().generate_return_types())
599 ostr << from.value().return_type();
600
601 ostr << '\n';
602 }
603 }
604
605 ostr << indent(1) << "deactivate " << from_alias << '\n';
606 }
607}

◆ generate_from_to_sequences()

void clanguml::sequence_diagram::generators::mermaid::generator::generate_from_to_sequences ( std::ostream &  ostr,
bool  star_participant_generated 
) const
private

Definition at line 665 of file sequence_diagram_generator.cc.

667{
668 for (const auto &ft : config().from_to()) {
669 // First, find the sequence of activities from 'from' location
670 // to 'to' location
671 assert(ft.size() == 2);
672
673 const auto &from_location = ft.front();
674 const auto &to_location = ft.back();
675
676 auto from_activity_ids = model().get_from_activity_ids(from_location);
677 auto to_activity_ids = model().get_to_activity_ids(to_location);
678
679 if (from_activity_ids.empty()) {
680 throw error::invalid_sequence_from_condition(model().type(),
681 model().name(),
682 fmt::format("Failed to find participant matching '{}' for "
683 "'from' condition: ",
684 from_location.location.to_string()));
685 }
686
687 if (from_activity_ids.empty() || to_activity_ids.empty()) {
688 throw error::invalid_sequence_to_condition(model().type(),
689 model().name(),
690 fmt::format("Failed to find participant matching '{}' for "
691 "'to' condition: ",
692 to_location.location.to_string()));
693 }
694
695 for (const auto from_activity_id : from_activity_ids) {
696 if (model().participants().count(from_activity_id) == 0)
697 continue;
698
699 for (const auto to_activity_id : to_activity_ids) {
700 if (model().participants().count(to_activity_id) == 0)
701 continue;
702
703 auto message_chains_unique =
704 model().get_all_from_to_message_chains(
705 from_activity_id, to_activity_id);
706
707 for (const auto &mc : message_chains_unique) {
708 const auto &from = model().get_participant<model::function>(
709 from_activity_id);
710
711 if (from.value().type_name() == "method" ||
712 config()
713 .combine_free_functions_into_file_participants()) {
714 if (!star_participant_generated) {
715 ostr << indent(1) << "participant *\n";
716 star_participant_generated = true;
717 }
718 generate_participant(ostr, from_activity_id);
719 ostr << indent(1) << "* "
721 message_t::kCall)
722 << " " << generate_alias(from.value()) << " : "
723 << from.value().message_name(
725 << '\n';
726 }
727
728 for (const auto &m : mc) {
729 generate_call(m, ostr);
730 }
731 }
732 }
733 }
734 }
735}

◆ generate_message_comment()

void clanguml::sequence_diagram::generators::mermaid::generator::generate_message_comment ( std::ostream &  ostr,
const model::message m 
) const
private

Generate message call note.

Parameters
ostrOutput stream
mMessage

Definition at line 50 of file sequence_diagram_generator.cc.

52{
53 const auto &from = model().get_participant<model::participant>(m.from());
54 if (!from)
55 return;
56
57 bool comment_generated_from_note_decorators{false};
58 for (const auto &decorator : m.decorators()) {
59 auto note = std::dynamic_pointer_cast<decorators::note>(decorator);
60 if (note && note->applies_to_diagram(config().name)) {
61 comment_generated_from_note_decorators = true;
62
63 ostr << indent(1) << "note over " << generate_alias(from.value())
64 << ": ";
65
66 auto formatted_message = util::format_message_comment(
67 note->text, config().message_comment_width());
68
69 util::replace_all(formatted_message, "\n", "<br/>");
70 ostr << formatted_message << '\n';
71 }
72 }
73
74 if (comment_generated_from_note_decorators)
75 return;
76
77 if (const auto &cmt = m.comment(); config().generate_message_comments() &&
78 cmt.has_value() &&
79 generated_comment_ids_.emplace(cmt.value().at("id")).second) {
80
81 ostr << indent(1) << "note over " << generate_alias(from.value())
82 << ": ";
83
84 auto formatted_message = util::format_message_comment(
85 cmt.value().at("comment"), config().message_comment_width());
86
87 util::replace_all(formatted_message, "\n", "<br/>");
88
89 ostr << formatted_message << '\n';
90 }
91}

◆ generate_participant() [1/2]

void clanguml::sequence_diagram::generators::mermaid::generator::generate_participant ( std::ostream &  ostr,
const std::string &  name 
) const

Generate sequence diagram participant by name.

This is convenience wrapper over generate_participant() by id.

Parameters
ostrOutput stream
nameFull participant name

Definition at line 356 of file sequence_diagram_generator.cc.

358{
359 auto p = model().get(name);
360
361 if (!p.has_value()) {
362 LOG_WARN("Cannot find participant {} from `participants_order` option",
363 name);
364 return;
365 }
366
367 generate_participant(ostr, p.value().id(), true);
368}

◆ generate_participant() [2/2]

void clanguml::sequence_diagram::generators::mermaid::generator::generate_participant ( std::ostream &  ostr,
eid_t  id,
bool  force = false 
) const

Generate sequence diagram participant.

Parameters
ostrOutput stream
idParticipant id
forceIf true, generate the participant even if its not in the set of active participants
Returns
Id of the generated participant

Definition at line 370 of file sequence_diagram_generator.cc.

372{
373 eid_t participant_id{};
374
375 if (!force) {
376 for (const auto pid : model().active_participants()) {
377 if (pid == id) {
378 participant_id = pid;
379 break;
380 }
381 }
382 }
383 else
384 participant_id = id;
385
386 if (participant_id == 0)
387 return;
388
389 if (is_participant_generated(participant_id))
390 return;
391
392 const auto &participant =
393 model().get_participant<model::participant>(participant_id).value();
394
395 if (participant.type_name() == "method") {
396 const auto class_id =
397 model()
398 .get_participant<model::method>(participant_id)
399 .value()
400 .class_id();
401
402 if (is_participant_generated(class_id))
403 return;
404
405 const auto &class_participant =
406 model().get_participant<model::participant>(class_id).value();
407
408 print_debug(class_participant, ostr);
409
410 auto participant_name =
411 config().using_namespace().relative(config().simplify_template_type(
412 display_name_adapter(class_participant).full_name(false)));
414
415 ostr << indent(1) << "participant " << class_participant.alias()
416 << " as " << participant_name;
417
418 ostr << '\n';
419
420 generated_participants_.emplace(class_id);
421 }
422 else if (participant.type_name() == "objc_method") {
423 const auto class_id =
424 model()
425 .get_participant<model::objc_method>(participant_id)
426 .value()
427 .class_id();
428
429 if (is_participant_generated(class_id))
430 return;
431
432 const auto &class_participant =
433 model().get_participant<model::participant>(class_id).value();
434
435 print_debug(class_participant, ostr);
436
437 auto participant_name =
438 config().using_namespace().relative(config().simplify_template_type(
439 display_name_adapter(class_participant).full_name(false)));
441
442 ostr << indent(1) << "participant " << class_participant.alias()
443 << " as " << "<< ObjC Interface >><br>" << participant_name;
444
445 ostr << '\n';
446
447 generated_participants_.emplace(class_id);
448 }
449 else if ((participant.type_name() == "function" ||
450 participant.type_name() == "function_template") &&
451 config().combine_free_functions_into_file_participants()) {
452 // Create a single participant for all functions declared in a
453 // single file
454 const auto &f =
455 model().get_participant<model::function>(participant_id).value();
456
457 const auto &file_path = f.file();
458
459 assert(!file_path.empty());
460
461 const auto file_id = common::to_id(file_path);
462
463 if (is_participant_generated(file_id))
464 return;
465
466 auto participant_name = util::path_to_url(std::filesystem::relative(
467 std::filesystem::path{file_path}, config().root_directory())
468 .string());
469
470 ostr << indent(1) << "participant "
471 << fmt::format("C_{:022}", file_id.value()) << " as "
472 << participant_name;
473 ostr << '\n';
474
475 generated_participants_.emplace(file_id);
476 }
477 else {
478 print_debug(participant, ostr);
479
480 auto participant_name =
481 config().using_namespace().relative(config().simplify_template_type(
482 display_name_adapter(participant).full_name(false)));
484
485 ostr << indent(1) << "participant " << participant.alias() << " as ";
486
487 if (participant.type_name() == "function" ||
488 participant.type_name() == "function_template") {
489 const auto &f =
490 model()
491 .get_participant<model::function>(participant_id)
492 .value();
493
494 if (f.is_cuda_kernel())
495 ostr << "<< CUDA Kernel >><br>";
496 else if (f.is_cuda_device())
497 ostr << "<< CUDA Device >><br>";
498 }
499
500 ostr << participant_name;
501 ostr << '\n';
502
503 generated_participants_.emplace(participant_id);
504 }
505}

◆ generate_return()

void clanguml::sequence_diagram::generators::mermaid::generator::generate_return ( const clanguml::sequence_diagram::model::message m,
std::ostream &  ostr 
) const

Generate sequence diagram return message.

Parameters
mMessage model
ostrOutput stream

Definition at line 172 of file sequence_diagram_generator.cc.

173{
174 // Add return activity only for messages between different actors and
175 // only if the return type is different than void
176 const auto &from = model().get_participant<model::participant>(m.from());
177 const auto &to = model().get_participant<model::function>(m.to());
178 if ((m.from() != m.to()) && !to.value().is_void()) {
179 const std::string from_alias = generate_alias(from.value());
180
181 const std::string to_alias = generate_alias(to.value());
182
183 ostr << indent(1) << to_alias << " "
184 << common::generators::mermaid::to_mermaid(message_t::kReturn)
185 << " " << from_alias << " : ";
186
187 if (config().generate_return_types()) {
188 ostr << m.return_type();
189 }
190
191 ostr << '\n';
192 }
193}

◆ generate_to_sequences()

void clanguml::sequence_diagram::generators::mermaid::generator::generate_to_sequences ( std::ostream &  ostr) const
private

Definition at line 634 of file sequence_diagram_generator.cc.

635{
636 std::vector<model::message_chain_t> message_chains =
638
639 for (const auto &mc : message_chains) {
640 const auto from_activity_id = mc.front().from();
641
642 if (model().participants().count(from_activity_id) == 0)
643 continue;
644
645 const auto &from =
646 model().get_participant<model::function>(from_activity_id);
647
648 if (from.value().type_name() == "method" ||
649 config().combine_free_functions_into_file_participants()) {
650 generate_participant(ostr, from_activity_id);
651 ostr << indent(1) << "* "
652 << common::generators::mermaid::to_mermaid(message_t::kCall)
653 << " " << generate_alias(from.value()) << " : "
654 << from.value().message_name(
656 << '\n';
657 }
658
659 for (const auto &m : mc) {
660 generate_call(m, ostr);
661 }
662 }
663}

◆ is_participant_generated()

bool clanguml::sequence_diagram::generators::mermaid::generator::is_participant_generated ( eid_t  id) const
private

Check if specified participant has already been generated.

Parameters
idParticipant id.
Returns
True, if participant has already been generated.

Definition at line 507 of file sequence_diagram_generator.cc.

508{
509 return std::find(generated_participants_.begin(),
511 id) != generated_participants_.end();
512}

◆ select_method_arguments_render_mode()

model::function::message_render_mode clanguml::sequence_diagram::generators::mermaid::generator::select_method_arguments_render_mode ( ) const
private

Convert config to model message render mode.

Returns
Method render mode.

Definition at line 769 of file sequence_diagram_generator.cc.

770{
771 if (config().generate_method_arguments() ==
774
775 if (config().generate_method_arguments() == config::method_arguments::none)
777
779}

Member Data Documentation

◆ already_generated_in_static_context_

std::vector<model::message> clanguml::sequence_diagram::generators::mermaid::generator::already_generated_in_static_context_
mutableprivate

Definition at line 171 of file sequence_diagram_generator.h.

◆ generated_activities_

std::set<eid_t> clanguml::sequence_diagram::generators::mermaid::generator::generated_activities_
mutableprivate

Definition at line 172 of file sequence_diagram_generator.h.

◆ generated_comment_ids_

std::set<unsigned int> clanguml::sequence_diagram::generators::mermaid::generator::generated_comment_ids_
mutableprivate

Definition at line 170 of file sequence_diagram_generator.h.

◆ generated_participants_

std::set<eid_t> clanguml::sequence_diagram::generators::mermaid::generator::generated_participants_
mutableprivate

Definition at line 169 of file sequence_diagram_generator.h.


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