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

Sequence diagram PlantUML generator. More...

Detailed Description

Sequence diagram PlantUML generator.

Definition at line 50 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_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::plantuml::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_config_layout_hints (std::ostream &ostr) const
 Generate diagram layout hints.
 
void generate_plantuml_directives (std::ostream &ostr, const std::vector< std::string > &directives) const
 Generate PlantUML directives from config file.
 
void generate_notes (std::ostream &ostr, const model::element &element) const
 Generate diagram notes.
 
void generate_style (std::ostream &ostr, const std::string &element_type, const model::stylable_element &el) const
 Generate diagram element PlantUML style.
 
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 generate_link (std::ostream &ostr, const relationship &e) const
 generate_link specialization for relationship
 
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 PlantUML alias for participant.
 
void generate_message_comment (std::ostream &ostr, const model::message &m) const
 Generate message call note.
 
void generate_from_to_sequences (std::ostream &ostr) 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
 
model::function::message_render_mode select_method_arguments_render_mode () const
 Convert config to model message render mode.
 

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::plantuml::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::plantuml::generator::generator ( diagram_config config,
diagram_model model 
)

Definition at line 37 of file sequence_diagram_generator.cc.

39 : common_generator<diagram_config, diagram_model>{config, model}
40{
41}

Member Function Documentation

◆ find_from_activities()

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

Definition at line 627 of file sequence_diagram_generator.cc.

628{
629 std::vector<eid_t> start_from;
630 for (const auto &sf : config().from()) {
631 if (sf.location_type == location_t::function) {
632 bool found{false};
633 for (const auto &[k, v] : model().sequences()) {
634 if (model().participants().count(v.from()) == 0)
635 continue;
636
637 const auto &caller = *model().participants().at(v.from());
638 std::string vfrom = caller.full_name(false);
639 if (sf.location == vfrom) {
640 LOG_DBG("Found sequence diagram start point: {}", k);
641 start_from.push_back(k);
642 found = true;
643 }
644 }
645
646 if (!found)
647 throw error::invalid_sequence_from_condition(model().type(),
648 model().name(),
649 fmt::format("Failed to find participant matching '{}' for "
650 "'from' condition: ",
651 sf.location.to_string()));
652 }
653 }
654
655 return start_from;
656}

◆ find_to_message_chains()

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

Definition at line 658 of file sequence_diagram_generator.cc.

659{
660 std::vector<model::message_chain_t> result;
661
662 for (const auto &to_location : config().to()) {
663 auto to_activity_ids = model().get_to_activity_ids(to_location);
664
665 if (to_activity_ids.empty()) {
666 LOG_WARN("Failed to find participant matching '{}' for "
667 "'to' condition: ",
668 to_location.location.to_string());
669 }
670
671 for (const auto &to_activity_id : to_activity_ids) {
672 std::vector<model::message_chain_t> message_chains_unique =
673 model().get_all_from_to_message_chains(eid_t{}, to_activity_id);
674
675 result.insert(result.end(), message_chains_unique.begin(),
676 message_chains_unique.end());
677 }
678 }
679
680 return result;
681}

◆ generate_activity()

void clanguml::sequence_diagram::generators::plantuml::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 156 of file sequence_diagram_generator.cc.

158{
159 const auto &a = model().get_activity(activity_id);
160
161 const auto [it, inserted] = generated_activities_.emplace(activity_id);
162
163 if (config().fold_repeated_activities() && !inserted &&
164 !a.messages().empty()) {
165 const auto &p =
166 model().get_participant<model::participant>(activity_id);
167
168 if (p.has_value()) {
169 ostr << "hnote over " << generate_alias(p.value()) << " : *\n";
170 // This is necessary to keep the hnote over the activity life line
171 ostr << generate_alias(p.value()) << "-[hidden]->"
172 << generate_alias(p.value()) << '\n';
173 }
174
175 return;
176 }
177
178 for (const auto &m : a.messages()) {
179 if (m.in_static_declaration_context()) {
181 continue;
182
184 }
185
186 if (m.type() == message_t::kCall) {
187 const auto &to =
188 model().get_participant<model::participant>(m.to());
189
190 visited.push_back(m.from());
191
192 LOG_DBG("Generating message [{}] --> [{}]", m.from(), m.to());
193
194 generate_call(m, ostr);
195
196 std::string to_alias = generate_alias(to.value());
197
198 ostr << "activate " << to_alias << '\n';
199
200 if (model().sequences().find(m.to()) != model().sequences().end()) {
201 if (std::find(visited.begin(), visited.end(), m.to()) ==
202 visited
203 .end()) { // break infinite recursion on recursive calls
204 LOG_DBG("Creating activity {} --> {} - missing sequence {}",
205 m.from(), m.to(), m.to());
206 generate_activity(m.to(), ostr, visited);
207 }
208 }
209 else
210 LOG_DBG("Skipping activity {} --> {} - missing sequence {}",
211 m.from(), m.to(), m.to());
212
213 generate_return(m, ostr);
214
215 ostr << "deactivate " << to_alias << '\n';
216
217 visited.pop_back();
218 }
219 else if (m.type() == message_t::kIf) {
220 print_debug(m, ostr);
222 ostr << "alt";
223 if (const auto &text = m.condition_text(); text.has_value())
224 ostr << " " << text.value();
225 ostr << '\n';
226 }
227 else if (m.type() == message_t::kElseIf) {
228 print_debug(m, ostr);
229 ostr << "else";
230 if (const auto &text = m.condition_text(); text.has_value())
231 ostr << " " << text.value();
232 ostr << '\n';
233 }
234 else if (m.type() == message_t::kElse) {
235 print_debug(m, ostr);
236 ostr << "else\n";
237 }
238 else if (m.type() == message_t::kIfEnd) {
239 ostr << "end\n";
240 }
241 else if (m.type() == message_t::kWhile) {
242 print_debug(m, ostr);
244 ostr << "loop";
245 if (const auto &text = m.condition_text(); text.has_value())
246 ostr << " " << text.value();
247 ostr << '\n';
248 }
249 else if (m.type() == message_t::kWhileEnd) {
250 ostr << "end\n";
251 }
252 else if (m.type() == message_t::kFor) {
253 print_debug(m, ostr);
255 ostr << "loop";
256 if (const auto &text = m.condition_text(); text.has_value())
257 ostr << " " << text.value();
258 ostr << '\n';
259 }
260 else if (m.type() == message_t::kForEnd) {
261 ostr << "end\n";
262 }
263 else if (m.type() == message_t::kDo) {
264 print_debug(m, ostr);
266 ostr << "loop";
267 if (const auto &text = m.condition_text(); text.has_value())
268 ostr << " " << text.value();
269 ostr << '\n';
270 }
271 else if (m.type() == message_t::kDoEnd) {
272 ostr << "end\n";
273 }
274 else if (m.type() == message_t::kTry) {
275 print_debug(m, ostr);
277 ostr << "group try\n";
278 }
279 else if (m.type() == message_t::kCatch) {
280 print_debug(m, ostr);
281 ostr << "else " << m.message_name() << '\n';
282 }
283 else if (m.type() == message_t::kTryEnd) {
284 print_debug(m, ostr);
285 ostr << "end\n";
286 }
287 else if (m.type() == message_t::kSwitch) {
288 print_debug(m, ostr);
290 ostr << "group switch\n";
291 }
292 else if (m.type() == message_t::kCase) {
293 print_debug(m, ostr);
294 ostr << "else " << m.message_name() << '\n';
295 }
296 else if (m.type() == message_t::kSwitchEnd) {
297 ostr << "end\n";
298 }
299 else if (m.type() == message_t::kConditional) {
300 print_debug(m, ostr);
302 ostr << "alt";
303 if (const auto &text = m.condition_text(); text.has_value())
304 ostr << " " << text.value();
305 ostr << '\n';
306 }
307 else if (m.type() == message_t::kConditionalElse) {
308 print_debug(m, ostr);
309 ostr << "else\n";
310 }
311 else if (m.type() == message_t::kConditionalEnd) {
312 ostr << "end\n";
313 }
314 }
315}

◆ generate_alias()

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

Generate PlantUML alias for participant.

Parameters
participantSequence diagram participant model
Returns
Particpant alias

Definition at line 536 of file sequence_diagram_generator.cc.

538{
539 if ((participant.type_name() == "function" ||
540 participant.type_name() == "function_template") &&
541 config().combine_free_functions_into_file_participants()) {
542 const auto file_id = common::to_id(participant.file());
543
544 return fmt::format("C_{:022}", file_id.value());
545 }
546
547 return participant.alias();
548}

◆ generate_call()

void clanguml::sequence_diagram::generators::plantuml::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 43 of file sequence_diagram_generator.cc.

44{
45 const auto &from = model().get_participant<model::participant>(m.from());
46 const auto &to = model().get_participant<model::participant>(m.to());
47
48 if (!from || !to) {
49 LOG_DBG("Skipping empty call from '{}' to '{}'", m.from(), m.to());
50 return;
51 }
52
53 generate_participant(ostr, m.from());
54 generate_participant(ostr, m.to());
55
56 std::string message;
57
60
61 if (to.value().type_name() == "method") {
62 const auto &f = dynamic_cast<const model::method &>(to.value());
63 const std::string_view style = f.is_static() ? "__" : "";
64 message =
65 fmt::format("{}{}{}", style, f.message_name(render_mode), style);
66 }
67 else if (to.value().type_name() == "objc_method") {
68 const auto &f = dynamic_cast<const model::objc_method &>(to.value());
69 const std::string_view style = f.is_static() ? "__" : "";
70 message =
71 fmt::format("{}{}{}", style, f.message_name(render_mode), style);
72 }
73 else if (config().combine_free_functions_into_file_participants()) {
74 if (to.value().type_name() == "function") {
75 const auto &f = dynamic_cast<const model::function &>(to.value());
76 message = f.message_name(render_mode);
77
78 if (f.is_cuda_kernel())
79 message = fmt::format("<< CUDA Kernel >>\\n{}", message);
80 else if (f.is_cuda_device())
81 message = fmt::format("<< CUDA Device >>\\n{}", message);
82 }
83 else if (to.value().type_name() == "function_template") {
84 const auto &f = dynamic_cast<const model::function &>(to.value());
85 message = f.message_name(render_mode);
86
87 if (f.is_cuda_kernel())
88 message = fmt::format("<< CUDA Kernel >>\\n{}", message);
89 else if (f.is_cuda_device())
90 message = fmt::format("<< CUDA Device >>\\n{}", message);
91 }
92 }
93
94 message = config().simplify_template_type(message);
95
96 const std::string from_alias = generate_alias(from.value());
97 const std::string to_alias = generate_alias(to.value());
98
99 print_debug(m, ostr);
100
102
103 ostr << from_alias << " "
104 << common::generators::plantuml::to_plantuml(message_t::kCall) << " ";
105
106 ostr << to_alias;
107
108 if (config().generate_links) {
110 }
111
112 ostr << " : ";
113
115 ostr << "**[**";
116
117 ostr << message;
118
120 ostr << "**]**";
121
122 ostr << '\n';
123
124 LOG_DBG("Generated call '{}' from {} [{}] to {} [{}]", message,
125 from.value().full_name(false), m.from(), to.value().full_name(false),
126 m.to());
127}

◆ generate_diagram()

void clanguml::sequence_diagram::generators::plantuml::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::plantuml::generator< ConfigType, DiagramType >.

Definition at line 550 of file sequence_diagram_generator.cc.

551{
552 model().print();
553
554 if (config().participants_order.has_value) {
555 for (const auto &p : config().participants_order()) {
556 LOG_DBG("Pregenerating participant {}", p);
557 generate_participant(ostr, p);
558 }
559 }
560
562
564
566}

◆ generate_from_sequences()

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

Definition at line 568 of file sequence_diagram_generator.cc.

569{
570 std::vector<eid_t> start_from = find_from_activities();
571
572 // Use this to break out of recurrent loops
573 std::vector<eid_t> visited_participants;
574
575 for (const auto from_id : start_from) {
576 if (model().participants().count(from_id) == 0)
577 continue;
578
579 const auto &from = model().get_participant<model::function>(from_id);
580
581 if (!from.has_value()) {
582 LOG_WARN("Failed to find participant {} for 'from' "
583 "condition");
584 continue;
585 }
586
587 generate_participant(ostr, from_id);
588
589 std::string from_alias = generate_alias(from.value());
590
593
594 // For methods or functions in diagrams where they are
595 // combined into file participants, we need to add an
596 // 'entry' point call to know which method relates to the
597 // first activity for this 'start_from' condition
598 if (from.value().type_name() == "method" ||
599 from.value().type_name() == "objc_method" ||
600 config().combine_free_functions_into_file_participants()) {
601 ostr << "[->" << " " << from_alias << " : "
602 << from.value().message_name(render_mode) << '\n';
603 }
604
605 ostr << "activate " << from_alias << '\n';
606
607 generate_activity(from_id, ostr, visited_participants);
608
609 if (from.value().type_name() == "method" ||
610 from.value().type_name() == "objc_method" ||
611 config().combine_free_functions_into_file_participants()) {
612
613 if (!from.value().is_void()) {
614 ostr << "[<--" << " " << from_alias;
615
616 if (config().generate_return_types())
617 ostr << " : //" << from.value().return_type() << "//";
618
619 ostr << '\n';
620 }
621 }
622
623 ostr << "deactivate " << from_alias << '\n';
624 }
625}

◆ generate_from_to_sequences()

void clanguml::sequence_diagram::generators::plantuml::generator::generate_from_to_sequences ( std::ostream &  ostr) const
private

Definition at line 719 of file sequence_diagram_generator.cc.

720{
721 for (const auto &ft : config().from_to()) {
722 // First, find the sequence of activities from 'from' location
723 // to 'to' location
724 assert(ft.size() == 2);
725
726 const auto &from_location = ft.front();
727 const auto &to_location = ft.back();
728
729 const auto from_activity_ids =
730 model().get_from_activity_ids(from_location);
731
732 const auto to_activity_ids = model().get_to_activity_ids(to_location);
733
734 if (from_activity_ids.empty()) {
735 throw error::invalid_sequence_from_condition(model().type(),
736 model().name(),
737 fmt::format("Failed to find participant matching '{}' for "
738 "'from' condition: ",
739 from_location.location.to_string()));
740 }
741
742 if (from_activity_ids.empty() || to_activity_ids.empty()) {
743 throw error::invalid_sequence_to_condition(model().type(),
744 model().name(),
745 fmt::format("Failed to find participant matching '{}' for "
746 "'to' condition: ",
747 to_location.location.to_string()));
748 }
749
750 bool first_separator_skipped{false};
751
752 for (const auto from_activity_id : from_activity_ids) {
753 if (model().participants().count(from_activity_id) == 0)
754 continue;
755
756 for (const auto to_activity_id : to_activity_ids) {
757 if (model().participants().count(to_activity_id) == 0)
758 continue;
759
760 auto message_chains_unique =
761 model().get_all_from_to_message_chains(
762 from_activity_id, to_activity_id);
763
764 for (const auto &mc : message_chains_unique) {
765 if (!first_separator_skipped)
766 first_separator_skipped = true;
767 else
768 ostr << "====\n";
769
770 const auto &from = model().get_participant<model::function>(
771 from_activity_id);
772
773 if (from.value().type_name() == "method" ||
774 from.value().type_name() == "objc_method" ||
775 config()
776 .combine_free_functions_into_file_participants()) {
777 generate_participant(ostr, from_activity_id);
778 ostr << "[->" << " " << generate_alias(from.value())
779 << " : "
780 << from.value().message_name(
782 << '\n';
783 }
784
785 for (const auto &m : mc) {
786 generate_call(m, ostr);
787 }
788 }
789 }
790 }
791 }
792}

◆ generate_message_comment()

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

Generate message call note.

Parameters
ostrOutput stream
mMessage

Definition at line 317 of file sequence_diagram_generator.cc.

319{
320 const auto &from = model().get_participant<model::participant>(m.from());
321 if (!from)
322 return;
323
324 // First generate message comments from \note directives in comments
325 bool comment_generated_from_note_decorators{false};
326 for (const auto &decorator : m.decorators()) {
327 auto note = std::dynamic_pointer_cast<decorators::note>(decorator);
328 if (note && note->applies_to_diagram(config().name)) {
329 comment_generated_from_note_decorators = true;
330
331 ostr << "note over " << generate_alias(from.value()) << '\n';
332
334 note->text, config().message_comment_width())
335 << '\n';
336
337 ostr << "end note" << '\n';
338 }
339 }
340
341 if (comment_generated_from_note_decorators)
342 return;
343
344 if (!config().generate_message_comments())
345 return;
346
347 // Now generate message notes from raw comments if enabled
348 if (const auto &comment = m.comment(); comment &&
349 generated_comment_ids_.emplace(comment.value().at("id")).second) {
350
351 ostr << "note over " << generate_alias(from.value()) << '\n';
352
353 ostr << util::format_message_comment(comment.value().at("comment"),
354 config().message_comment_width())
355 << '\n';
356
357 ostr << "end note" << '\n';
358 }
359}

◆ generate_participant() [1/2]

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

Generate sequence diagram participant by name.

This is convienience wrapper over generate_participant() by id.

Parameters
ostrOutput stream
nameFull participant name

Definition at line 361 of file sequence_diagram_generator.cc.

363{
364 auto p = model().get(name);
365
366 if (!p.has_value()) {
367 LOG_WARN("Cannot find participant {} from `participants_order` "
368 "option",
369 name);
370 return;
371 }
372
373 generate_participant(ostr, p.value().id(), true);
374}

◆ generate_participant() [2/2]

void clanguml::sequence_diagram::generators::plantuml::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 376 of file sequence_diagram_generator.cc.

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

◆ generate_return()

void clanguml::sequence_diagram::generators::plantuml::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 129 of file sequence_diagram_generator.cc.

130{
131
132 // Add return activity only for messages between different actors
133 // and only if the return type is different than void
134 if (m.from() == m.to())
135 return;
136
137 const auto &from = model().get_participant<model::participant>(m.from());
138 const auto &to = model().get_participant<model::function>(m.to());
139 if (to.has_value() && !to.value().is_void()) {
140 const std::string from_alias = generate_alias(from.value());
141
142 const std::string to_alias = generate_alias(to.value());
143
144 ostr << to_alias << " "
145 << common::generators::plantuml::to_plantuml(message_t::kReturn)
146 << " " << from_alias;
147
148 if (config().generate_return_types()) {
149 ostr << " : //" << m.return_type() << "//";
150 }
151
152 ostr << '\n';
153 }
154}

◆ generate_to_sequences()

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

Definition at line 683 of file sequence_diagram_generator.cc.

684{
685 std::vector<model::message_chain_t> message_chains =
687
688 bool first_separator_skipped{false};
689 for (const auto &mc : message_chains) {
690 if (!first_separator_skipped)
691 first_separator_skipped = true;
692 else
693 ostr << "====\n";
694
695 const auto from_activity_id = mc.front().from();
696
697 if (model().participants().count(from_activity_id) == 0)
698 continue;
699
700 const auto &from =
701 model().get_participant<model::function>(from_activity_id);
702
703 if (from.value().type_name() == "method" ||
704 from.value().type_name() == "objc_method" ||
705 config().combine_free_functions_into_file_participants()) {
706 generate_participant(ostr, from_activity_id);
707 ostr << "[->" << " " << generate_alias(from.value()) << " : "
708 << from.value().message_name(
710 << '\n';
711 }
712
713 for (const auto &m : mc) {
714 generate_call(m, ostr);
715 }
716 }
717}

◆ is_participant_generated()

bool clanguml::sequence_diagram::generators::plantuml::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 529 of file sequence_diagram_generator.cc.

530{
531 return std::find(generated_participants_.begin(),
533 id) != generated_participants_.end();
534}

◆ select_method_arguments_render_mode()

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

Convert config to model message render mode.

Returns
Method render mode.

Definition at line 795 of file sequence_diagram_generator.cc.

796{
797 if (config().generate_method_arguments() ==
800
801 if (config().generate_method_arguments() == config::method_arguments::none)
803
805}

Member Data Documentation

◆ already_generated_in_static_context_

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

Definition at line 164 of file sequence_diagram_generator.h.

◆ generated_activities_

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

Definition at line 165 of file sequence_diagram_generator.h.

◆ generated_comment_ids_

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

Definition at line 163 of file sequence_diagram_generator.h.

◆ generated_participants_

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

Definition at line 162 of file sequence_diagram_generator.h.


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