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

Class diagram PlantUML generator. More...

Detailed Description

Class diagram PlantUML generator.

Definition at line 66 of file class_diagram_generator.h.

#include <class_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_top_level_elements (std::ostream &ostr) const
 In a nested diagram, generate the top level elements.
 
void generate_link (std::ostream &ostr, const class_element &e) const
 Generate a hyperlink for a class element.
 
void generate_alias (const class_ &c, std::ostream &ostr) const
 Generate PlantUML alias for a class element.
 
void generate_alias (const enum_ &e, std::ostream &ostr) const
 Generate PlantUML alias for a enum element.
 
void generate_alias (const concept_ &c, std::ostream &ostr) const
 Generate PlantUML alias for a concept element.
 
void generate (const class_ &c, std::ostream &ostr) const
 Render class element to PlantUML.
 
void generate_methods (const std::vector< class_method > &methods, std::ostream &ostr) const
 Render class methods to PlantUML.
 
void generate_methods (const method_groups_t &methods, std::ostream &ostr) const
 Render class methods to PlantUML in groups.
 
void generate_method (const class_method &m, std::ostream &ostr) const
 Render class method to PlantUML.
 
void generate_member (const class_member &m, std::ostream &ostr) const
 Render class member to PlantUML.
 
void generate_relationships (std::ostream &ostr) const
 Render all relationships in the diagram to PlantUML.
 
void generate_relationships (const class_ &c, std::ostream &ostr) const
 Render all relationships originating from class element.
 
void generate_relationship (const relationship &r, std::set< std::string > &rendered_relations) const
 Render a specific relationship to PlantUML.
 
void generate (const enum_ &e, std::ostream &ostr) const
 Render enum element to PlantUML.
 
void generate_relationships (const enum_ &c, std::ostream &ostr) const
 Render all relationships originating from enum element.
 
void generate (const concept_ &c, std::ostream &ostr) const
 Render concept element to PlantUML.
 
void generate_relationships (const concept_ &c, std::ostream &ostr) const
 Render all relationships originating from concept element.
 
void generate (const package &p, std::ostream &ostr) const
 Render package element to PlantUML.
 
void generate_relationships (const package &p, std::ostream &ostr) const
 Render all relationships originating from package element.
 
void generate_member_notes (std::ostream &ostream, const class_element &member, const std::string &alias) const
 Generate any notes attached specifically to some class element.
 
void generate_groups (std::ostream &ostr) const
 Generate elements grouped together in together groups.
 
method_groups_t group_methods (const std::vector< class_method > &methods) const
 Group class methods based on method type.
 
- 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 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.
 
template<typename E >
inja::json element_context (const E &e) const
 
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
 
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 Types

using method_groups_t = std::map< std::string, std::vector< class_method > >
 

Private Member Functions

std::string render_name (std::string name) const
 
template<typename T >
void sort_class_elements (std::vector< T > &elements) const
 

Private Attributes

const std::vector< std::string > method_groups_
 
common::generators::nested_element_stack< common::model::elementtogether_group_stack_
 

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
 

Member Typedef Documentation

◆ method_groups_t

Definition at line 67 of file class_diagram_generator.h.

Constructor & Destructor Documentation

◆ generator()

clanguml::class_diagram::generators::plantuml::generator::generator ( diagram_config config,
diagram_model model 
)

Definition at line 27 of file class_diagram_generator.cc.

28 : common_generator<diagram_config, diagram_model>{config, model}
29 , together_group_stack_{!config.generate_packages()}
30{
31}

Member Function Documentation

◆ generate() [1/4]

void clanguml::class_diagram::generators::plantuml::generator::generate ( const class_ c,
std::ostream &  ostr 
) const

Render class element to PlantUML.

Parameters
cClass element
ostrOutput stream

Definition at line 130 of file class_diagram_generator.cc.

131{
132 std::string class_type{"class"};
133 if (c.is_abstract())
134 class_type = "abstract";
135
136 ostr << class_type << " " << c.alias();
137
138 if (c.is_union())
139 ostr << " "
140 << "<<union>>";
141
142 if (config().generate_links) {
144 }
145
146 generate_style(ostr, c.type_name(), c);
147
148 ostr << " {" << '\n';
149
150 //
151 // Process methods
152 //
153 if (config().group_methods()) {
154 generate_methods(group_methods(c.methods()), ostr);
155 }
156 else {
157 generate_methods(c.methods(), ostr);
158 }
159
160 //
161 // Process relationships - here only generate the set of
162 // rendered_relationships we'll generate them in a seperate method
163 //
164 std::set<std::string> rendered_relations;
165
166 std::stringstream all_relations_str;
167 for (const auto &r : c.relationships()) {
168 try {
169 generate_relationship(r, rendered_relations);
170 }
171 catch (error::uml_alias_missing &e) {
172 LOG_DBG("Skipping {} relation from {} to {} due "
173 "to: {}",
174 to_string(r.type()), c.full_name(), r.destination(), e.what());
175 }
176 }
177
178 //
179 // Process members
180 //
181 std::vector<clanguml::class_diagram::model::class_member> members{
182 c.members()};
183
184 sort_class_elements(members);
185
186 if (config().group_methods())
187 ostr << "__\n";
188
189 for (const auto &m : members) {
190 if (!config().include_relations_also_as_members() &&
191 rendered_relations.find(m.name()) != rendered_relations.end())
192 continue;
193
194 generate_member(m, ostr);
195
196 ostr << '\n';
197 }
198
199 ostr << "}" << '\n';
200
201 generate_notes(ostr, c);
202
203 for (const auto &member : c.members())
204 generate_member_notes(ostr, member, c.alias());
205
206 for (const auto &method : c.methods())
207 generate_member_notes(ostr, method, c.alias());
208}

◆ generate() [2/4]

void clanguml::class_diagram::generators::plantuml::generator::generate ( const concept_ c,
std::ostream &  ostr 
) const

Render concept element to PlantUML.

Parameters
cConcept element
ostrOutput stream

Definition at line 359 of file class_diagram_generator.cc.

360{
361 std::string class_type{"class"};
362
363 ostr << class_type << " " << c.alias() << " <<concept>>";
364
365 if (config().generate_links) {
367 }
368
369 generate_style(ostr, c.type_name(), c);
370
371 ostr << " {" << '\n';
372
373 if (config().generate_concept_requirements() &&
374 (c.requires_parameters().size() + c.requires_statements().size() > 0)) {
375 std::vector<std::string> parameters;
376 parameters.reserve(c.requires_parameters().size());
377 for (const auto &p : c.requires_parameters()) {
378 parameters.emplace_back(p.to_string(config().using_namespace()));
379 }
380
381 ostr << fmt::format("({})\n", fmt::join(parameters, ","));
382
383 ostr << "..\n";
384
385 ostr << fmt::format("{}\n", fmt::join(c.requires_statements(), "\n"));
386 }
387
388 ostr << "}" << '\n';
389}

◆ generate() [3/4]

void clanguml::class_diagram::generators::plantuml::generator::generate ( const enum_ e,
std::ostream &  ostr 
) const

Render enum element to PlantUML.

Parameters
eEnum element
ostrOutput stream

Definition at line 623 of file class_diagram_generator.cc.

624{
625 ostr << "enum " << e.alias();
626
627 if (config().generate_links) {
629 }
630
631 generate_style(ostr, e.type_name(), e);
632
633 ostr << " {" << '\n';
634
635 for (const auto &enum_constant : e.constants()) {
636 ostr << enum_constant << '\n';
637 }
638
639 ostr << "}" << '\n';
640
641 generate_notes(ostr, e);
642}

◆ generate() [4/4]

void clanguml::class_diagram::generators::plantuml::generator::generate ( const package p,
std::ostream &  ostr 
) const

Render package element to PlantUML.

Parameters
pPackage element
ostrOutput stream

Definition at line 680 of file class_diagram_generator.cc.

681{
682 const auto &uns = config().using_namespace();
683
684 if (config().generate_packages()) {
685 LOG_DBG("Generating package {}", p.name());
686
687 // Don't generate packages from namespaces filtered out by
688 // using_namespace
689 if (!uns.starts_with({p.full_name(false)})) {
690 print_debug(p, ostr);
691 ostr << "package [" << p.name() << "] ";
692 ostr << "as " << p.alias();
693
694 if (p.is_deprecated())
695 ostr << " <<deprecated>>";
696
697 generate_style(ostr, p.type_name(), p);
698
699 ostr << " {" << '\n';
700 }
701 }
702
703 for (const auto &subpackage : p) {
704 if (dynamic_cast<package *>(subpackage.get()) != nullptr) {
705 // TODO: add option - generate_empty_packages
706 const auto &sp = dynamic_cast<package &>(*subpackage);
707 if (!sp.is_empty()) {
708 together_group_stack_.enter();
709
710 generate(sp, ostr);
711
712 together_group_stack_.leave();
713 }
714 }
715 else if (auto *cls = dynamic_cast<class_ *>(subpackage.get()); cls) {
716 if (model().should_include(*subpackage)) {
717 auto together_group =
718 config().get_together_group(cls->full_name(false));
719 if (together_group) {
720 together_group_stack_.group_together(
721 together_group.value(), cls);
722 }
723 else {
724 generate_alias(*cls, ostr);
725 generate(*cls, ostr);
726 }
727 }
728 }
729 else if (auto *enm = dynamic_cast<enum_ *>(subpackage.get()); enm) {
730 if (model().should_include(*subpackage)) {
731 auto together_group =
732 config().get_together_group(subpackage->full_name(false));
733 if (together_group) {
734 together_group_stack_.group_together(
735 together_group.value(), enm);
736 }
737 else {
738 generate_alias(*enm, ostr);
739 generate(*enm, ostr);
740 }
741 }
742 }
743 else if (auto *cpt = dynamic_cast<concept_ *>(subpackage.get()); cpt) {
744 if (model().should_include(*subpackage)) {
745 auto together_group =
746 config().get_together_group(cpt->full_name(false));
747 if (together_group) {
748 together_group_stack_.group_together(
749 together_group.value(), cpt);
750 }
751 else {
752 generate_alias(*cpt, ostr);
753 generate(*cpt, ostr);
754 }
755 }
756 }
757 }
758
759 if (config().generate_packages()) {
760 // Now generate any diagram elements which are in together
761 // groups
762 for (const auto &[group_name, group_elements] :
763 together_group_stack_.get_current_groups()) {
764 ostr << "together {\n";
765
766 for (auto *e : group_elements) {
767 if (auto *cls = dynamic_cast<class_ *>(e); cls) {
768 generate_alias(*cls, ostr);
769 generate(*cls, ostr);
770 }
771 if (auto *enm = dynamic_cast<enum_ *>(e); enm) {
772 generate_alias(*enm, ostr);
773 generate(*enm, ostr);
774 }
775 if (auto *cpt = dynamic_cast<concept_ *>(e); cpt) {
776 generate_alias(*cpt, ostr);
777 generate(*cpt, ostr);
778 }
779 }
780
781 ostr << "}\n";
782 }
783
784 // Don't generate packages from namespaces filtered out by
785 // using_namespace
786 if (!uns.starts_with({p.full_name(false)})) {
787 ostr << "}" << '\n';
788 generate_notes(ostr, p);
789 }
790 }
791}

◆ generate_alias() [1/3]

void clanguml::class_diagram::generators::plantuml::generator::generate_alias ( const class_ c,
std::ostream &  ostr 
) const

Generate PlantUML alias for a class element.

Parameters
cClass element
ostrOutput stream

Definition at line 71 of file class_diagram_generator.cc.

72{
73 std::string class_type{"class"};
74 if (c.is_abstract())
75 class_type = "abstract";
76
77 std::string full_name;
78 if (!config().generate_fully_qualified_name())
79 full_name = c.full_name_no_ns();
80 else
81 full_name = c.full_name();
82
83 assert(!full_name.empty());
84
85 print_debug(c, ostr);
86
87 ostr << class_type << " \""
88 << config().simplify_template_type(render_name(full_name));
89
90 ostr << "\" as " << c.alias() << '\n';
91
92 // Register the added alias
93 m_generated_aliases.emplace(c.alias());
94}

◆ generate_alias() [2/3]

void clanguml::class_diagram::generators::plantuml::generator::generate_alias ( const concept_ c,
std::ostream &  ostr 
) const

Generate PlantUML alias for a concept element.

Parameters
cConcept element
ostrOutput stream

Definition at line 113 of file class_diagram_generator.cc.

114{
115 print_debug(c, ostr);
116
117 if (!config().generate_fully_qualified_name())
118 ostr << "class"
119 << " \"" << c.full_name_no_ns();
120 else
121 ostr << "class"
122 << " \"" << render_name(c.full_name());
123
124 ostr << "\" as " << c.alias() << '\n';
125
126 // Register the added alias
127 m_generated_aliases.emplace(c.alias());
128}

◆ generate_alias() [3/3]

void clanguml::class_diagram::generators::plantuml::generator::generate_alias ( const enum_ e,
std::ostream &  ostr 
) const

Generate PlantUML alias for a enum element.

Parameters
eEnum element
ostrOutput stream

Definition at line 96 of file class_diagram_generator.cc.

97{
98 print_debug(e, ostr);
99
100 if (!config().generate_fully_qualified_name())
101 ostr << "enum"
102 << " \"" << e.name();
103 else
104 ostr << "enum"
105 << " \"" << render_name(e.full_name());
106
107 ostr << "\" as " << e.alias() << '\n';
108
109 // Register the added alias
110 m_generated_aliases.emplace(e.alias());
111}

◆ generate_diagram()

void clanguml::class_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 826 of file class_diagram_generator.cc.

827{
829
830 generate_groups(ostr);
831
833
835}

◆ generate_groups()

void clanguml::class_diagram::generators::plantuml::generator::generate_groups ( std::ostream &  ostr) const

Generate elements grouped together in together groups.

Parameters
ostrOutput stream

Definition at line 883 of file class_diagram_generator.cc.

884{
885 for (const auto &[group_name, group_elements] :
886 together_group_stack_.get_current_groups()) {
887 ostr << "together {\n";
888
889 for (auto *e : group_elements) {
890 if (auto *cls = dynamic_cast<class_ *>(e); cls) {
891 generate_alias(*cls, ostr);
892 generate(*cls, ostr);
893 }
894 if (auto *enm = dynamic_cast<enum_ *>(e); enm) {
895 generate_alias(*enm, ostr);
896 generate(*enm, ostr);
897 }
898 if (auto *cpt = dynamic_cast<concept_ *>(e); cpt) {
899 generate_alias(*cpt, ostr);
900 generate(*cpt, ostr);
901 }
902 }
903
904 ostr << "}\n";
905 }
906}

◆ generate_link()

void clanguml::class_diagram::generators::plantuml::generator::generate_link ( std::ostream &  ostr,
const class_element e 
) const

Generate a hyperlink for a class element.

Parameters
ostrOutput stream
eClass element (e.g. a method)

Definition at line 33 of file class_diagram_generator.cc.

35{
36 if (e.file_relative().empty())
37 return;
38
39 auto context = element_context(e);
40
41 auto maybe_link_pattern = get_link_pattern(e);
42 if (maybe_link_pattern) {
43 const auto &[link_prefix, link_pattern] = *maybe_link_pattern;
44 auto ec = element_context(e);
46
47 ostr << " [[[";
48 ostr << env().render(std::string_view{link_pattern}, context);
49 }
50
51 auto maybe_tooltip_pattern = get_tooltip_pattern(e);
52
53 if (maybe_tooltip_pattern) {
54 const auto &[tooltip_prefix, tooltip_pattern] = *maybe_tooltip_pattern;
55 auto ec = element_context(e);
57 ostr << "{";
58 ostr << env().render(std::string_view{tooltip_pattern}, ec);
59 ostr << "}";
60 }
61 ostr << "]]]";
62}

◆ generate_member()

void clanguml::class_diagram::generators::plantuml::generator::generate_member ( const class_member m,
std::ostream &  ostr 
) const

Render class member to PlantUML.

Parameters
mClass member
ostrOutput stream

Definition at line 339 of file class_diagram_generator.cc.

341{
342 namespace plantuml_common = clanguml::common::generators::plantuml;
343 const auto &uns = config().using_namespace();
344
345 print_debug(m, ostr);
346
347 if (m.is_static())
348 ostr << "{static} ";
349
350 ostr << plantuml_common::to_plantuml(m.access()) << m.name() << " : "
351 << render_name(
352 uns.relative(config().simplify_template_type(m.type())));
353
354 if (config().generate_links) {
355 generate_link(ostr, m);
356 }
357}

◆ generate_member_notes()

void clanguml::class_diagram::generators::plantuml::generator::generate_member_notes ( std::ostream &  ostream,
const class_element member,
const std::string &  alias 
) const

Generate any notes attached specifically to some class element.

Parameters
ostreamOutput stream
memberClass element (member or method)
aliasPlantUML class alias

Definition at line 391 of file class_diagram_generator.cc.

393{
394 for (const auto &decorator : member.decorators()) {
395 auto note = std::dynamic_pointer_cast<decorators::note>(decorator);
396 if (note && note->applies_to_diagram(config().name)) {
397 ostr << "note " << note->position << " of " << alias
398 << "::" << member.name() << '\n'
399 << note->text << '\n'
400 << "end note\n";
401 }
402 }
403}

◆ generate_method()

void clanguml::class_diagram::generators::plantuml::generator::generate_method ( const class_method m,
std::ostream &  ostr 
) const

Render class method to PlantUML.

Parameters
mClass method
ostrOutput stream

Definition at line 265 of file class_diagram_generator.cc.

267{
268 namespace plantuml_common = clanguml::common::generators::plantuml;
269 const auto &uns = config().using_namespace();
270
271 constexpr auto kAbbreviatedMethodArgumentsLength{15};
272
273 print_debug(m, ostr);
274
275 if (m.is_pure_virtual())
276 ostr << "{abstract} ";
277
278 if (m.is_static())
279 ostr << "{static} ";
280
281 std::string type{uns.relative(config().simplify_template_type(m.type()))};
282
283 ostr << plantuml_common::to_plantuml(m.access()) << m.name();
284
285 if (!m.template_params().empty()) {
286 m.render_template_params(ostr, config().using_namespace(), false);
287 }
288
289 ostr << "(";
290 if (config().generate_method_arguments() !=
292 std::vector<std::string> params;
293 std::transform(m.parameters().cbegin(), m.parameters().cend(),
294 std::back_inserter(params), [this](const auto &mp) {
295 return config().simplify_template_type(
296 mp.to_string(config().using_namespace()));
297 });
298 auto args_string = fmt::format("{}", fmt::join(params, ", "));
299 if (config().generate_method_arguments() ==
301 args_string = clanguml::util::abbreviate(
302 args_string, kAbbreviatedMethodArgumentsLength);
303 }
304 ostr << args_string;
305 }
306 ostr << ")";
307
308 if (m.is_constexpr())
309 ostr << " constexpr";
310 else if (m.is_consteval())
311 ostr << " consteval";
312
313 if (m.is_const())
314 ostr << " const";
315
316 if (m.is_noexcept())
317 ostr << " noexcept";
318
319 assert(!(m.is_pure_virtual() && m.is_defaulted()));
320
321 if (m.is_pure_virtual())
322 ostr << " = 0";
323
324 if (m.is_defaulted())
325 ostr << " = default";
326 else if (m.is_deleted())
327 ostr << " = deleted";
328
329 if (m.is_coroutine())
330 ostr << " [coroutine]";
331
332 ostr << " : " << type;
333
334 if (config().generate_links) {
335 generate_link(ostr, m);
336 }
337}

◆ generate_methods() [1/2]

void clanguml::class_diagram::generators::plantuml::generator::generate_methods ( const method_groups_t methods,
std::ostream &  ostr 
) const

Render class methods to PlantUML in groups.

Parameters
methodsMethods grouped by method type
ostrOutput stream

Definition at line 210 of file class_diagram_generator.cc.

212{
213 bool is_first_non_empty_group{true};
214
215 for (const auto &group : method_groups_) {
216 const auto &group_methods = methods.at(group);
217 if (!group_methods.empty()) {
218 if (!is_first_non_empty_group)
219 ostr << "..\n";
220 is_first_non_empty_group = false;
222 }
223 }
224}

◆ generate_methods() [2/2]

void clanguml::class_diagram::generators::plantuml::generator::generate_methods ( const std::vector< class_method > &  methods,
std::ostream &  ostr 
) const

Render class methods to PlantUML.

Parameters
methodsList of class methods
ostrOutput stream

Definition at line 226 of file class_diagram_generator.cc.

228{
229 auto sorted_methods = methods;
230 sort_class_elements(sorted_methods);
231
232 for (const auto &m : sorted_methods) {
233 generate_method(m, ostr);
234 ostr << '\n';
235 }
236}

◆ generate_relationship()

void clanguml::class_diagram::generators::plantuml::generator::generate_relationship ( const relationship r,
std::set< std::string > &  rendered_relations 
) const

Render a specific relationship to PlantUML.

Parameters
rRelationship model
rendered_relationsSet of already rendered relationships, to ensure that there are no duplicate relationships

Definition at line 423 of file class_diagram_generator.cc.

425{
426 namespace plantuml_common = clanguml::common::generators::plantuml;
427
428 LOG_DBG("Processing relationship {}", to_string(r.type()));
429
430 std::string destination;
431
432 auto target_element = model().get(r.destination());
433 if (!target_element.has_value())
434 throw error::uml_alias_missing{fmt::format(
435 "Missing element in the model for ID: {}", r.destination())};
436
437 destination = target_element.value().full_name(false);
438
439 if (util::starts_with(destination, std::string{"::"}))
440 destination = destination.substr(2, destination.size());
441
442 std::string puml_relation;
443 if (!r.multiplicity_source().empty())
444 puml_relation += "\"" + r.multiplicity_source() + "\" ";
445
446 puml_relation += plantuml_common::to_plantuml(r, config());
447
448 if (!r.multiplicity_destination().empty())
449 puml_relation += " \"" + r.multiplicity_destination() + "\"";
450
451 if (!r.label().empty()) {
452 rendered_relations.emplace(r.label());
453 }
454}

◆ generate_relationships() [1/5]

void clanguml::class_diagram::generators::plantuml::generator::generate_relationships ( const class_ c,
std::ostream &  ostr 
) const

Render all relationships originating from class element.

Parameters
cClass element
ostrOutput stream

Definition at line 456 of file class_diagram_generator.cc.

458{
459 namespace plantuml_common = clanguml::common::generators::plantuml;
460
461 //
462 // Process relationships
463 //
464 std::set<std::string> rendered_relations;
465
466 std::stringstream all_relations_str;
467 std::set<std::string> unique_relations;
468
469 for (const auto &r : c.relationships()) {
470 LOG_DBG("== Processing relationship {}",
471 plantuml_common::to_plantuml(r, config()));
472
473 std::stringstream relstr;
474 eid_t destination{};
475 try {
476 destination = r.destination();
477
478 std::string puml_relation;
479 if (!r.multiplicity_source().empty())
480 puml_relation += "\"" + r.multiplicity_source() + "\" ";
481
482 puml_relation += plantuml_common::to_plantuml(r, config());
483
484 if (!r.multiplicity_destination().empty())
485 puml_relation += " \"" + r.multiplicity_destination() + "\"";
486
487 std::string target_alias;
488 try {
489 target_alias = model().to_alias(destination);
490 }
491 catch (...) {
492 LOG_DBG("Failed to find alias to {}", destination);
493 continue;
494 }
495
496 if (m_generated_aliases.find(target_alias) ==
498 continue;
499
500 relstr << c.alias() << " " << puml_relation << " " << target_alias;
501
502 if (!r.label().empty()) {
503 relstr << " : " << plantuml_common::to_plantuml(r.access())
504 << r.label();
505 rendered_relations.emplace(r.label());
506 }
507
508 if (unique_relations.count(relstr.str()) == 0) {
509 unique_relations.emplace(relstr.str());
510
511 relstr << '\n';
512
513 LOG_DBG("=== Adding relation {}", relstr.str());
514
515 all_relations_str << relstr.str();
516 }
517 }
518 catch (error::uml_alias_missing &e) {
519 LOG_DBG("=== Skipping {} relation from {} to {} due "
520 "to: {}",
521 to_string(r.type()), c.full_name(), destination, e.what());
522 }
523 }
524
525 if (model().should_include(relationship_t::kExtension)) {
526 for (const auto &b : c.parents()) {
527 std::stringstream relstr;
528 try {
529 auto target_alias = model().to_alias(b.id());
530
531 if (m_generated_aliases.find(target_alias) ==
533 continue;
534
535 relstr << target_alias << " <|-- " << c.alias() << '\n';
536 all_relations_str << relstr.str();
537 }
538 catch (error::uml_alias_missing &e) {
539 LOG_DBG("=== Skipping inheritance relation from {} to {} due "
540 "to: {}",
541 b.name(), c.name(), e.what());
542 }
543 }
544 }
545
546 ostr << all_relations_str.str();
547}

◆ generate_relationships() [2/5]

void clanguml::class_diagram::generators::plantuml::generator::generate_relationships ( const concept_ c,
std::ostream &  ostr 
) const

Render all relationships originating from concept element.

Parameters
cConcept element
ostrOutput stream

Definition at line 549 of file class_diagram_generator.cc.

551{
552 namespace plantuml_common = clanguml::common::generators::plantuml;
553
554 //
555 // Process relationships
556 //
557 std::set<std::string> rendered_relations;
558
559 std::stringstream all_relations_str;
560 std::set<std::string> unique_relations;
561
562 for (const auto &r : c.relationships()) {
563 if (!model().should_include(r.type()))
564 continue;
565
566 LOG_DBG("== Processing relationship {}", to_string(r.type()));
567
568 std::stringstream relstr;
569 eid_t destination{};
570 try {
571 destination = r.destination();
572
573 std::string puml_relation;
574 if (!r.multiplicity_source().empty())
575 puml_relation += "\"" + r.multiplicity_source() + "\" ";
576
577 puml_relation += plantuml_common::to_plantuml(r, config());
578
579 if (!r.multiplicity_destination().empty())
580 puml_relation += " \"" + r.multiplicity_destination() + "\"";
581
582 std::string target_alias;
583 try {
584 target_alias = model().to_alias(destination);
585 }
586 catch (...) {
587 LOG_DBG("Failed to find alias to {}", destination);
588 continue;
589 }
590
591 if (m_generated_aliases.find(target_alias) ==
593 continue;
594
595 relstr << c.alias() << " " << puml_relation << " " << target_alias;
596
597 if (!r.label().empty()) {
598 relstr << " : " << plantuml_common::to_plantuml(r.access())
599 << r.label();
600 rendered_relations.emplace(r.label());
601 }
602
603 if (unique_relations.count(relstr.str()) == 0) {
604 unique_relations.emplace(relstr.str());
605
606 relstr << '\n';
607
608 LOG_DBG("=== Adding relation {}", relstr.str());
609
610 all_relations_str << relstr.str();
611 }
612 }
613 catch (error::uml_alias_missing &e) {
614 LOG_DBG("=== Skipping {} relation from {} to {} due "
615 "to: {}",
616 to_string(r.type()), c.full_name(), destination, e.what());
617 }
618 }
619
620 ostr << all_relations_str.str();
621}

◆ generate_relationships() [3/5]

void clanguml::class_diagram::generators::plantuml::generator::generate_relationships ( const enum_ c,
std::ostream &  ostr 
) const

Render all relationships originating from enum element.

Parameters
cEnum element
ostrOutput stream

Definition at line 644 of file class_diagram_generator.cc.

645{
646 for (const auto &r : e.relationships()) {
647 eid_t destination{};
648 std::stringstream relstr;
649 try {
650 destination = r.destination();
651
652 auto target_alias = model().to_alias(destination);
653
654 if (m_generated_aliases.find(target_alias) ==
656 continue;
657
658 relstr << e.alias() << " "
660 r, config())
661 << " " << target_alias;
662
663 if (!r.label().empty())
664 relstr << " : " << r.label();
665
666 relstr << '\n';
667
668 ostr << relstr.str();
669 }
670 catch (error::uml_alias_missing &ex) {
671 LOG_DBG("Skipping {} relation from {} to {} due "
672 "to: {}",
674 r, config()),
675 e.full_name(), destination, ex.what());
676 }
677 }
678}

◆ generate_relationships() [4/5]

void clanguml::class_diagram::generators::plantuml::generator::generate_relationships ( const package p,
std::ostream &  ostr 
) const

Render all relationships originating from package element.

Parameters
pPackage element
ostrOutput stream

Definition at line 793 of file class_diagram_generator.cc.

795{
796 for (const auto &subpackage : p) {
797 if (dynamic_cast<package *>(subpackage.get()) != nullptr) {
798 // TODO: add option - generate_empty_packages, currently
799 // packages which do not contain anything but other
800 // packages are skipped
801 const auto &sp = dynamic_cast<package &>(*subpackage);
802 if (!sp.is_empty())
803 generate_relationships(sp, ostr);
804 }
805 else if (dynamic_cast<class_ *>(subpackage.get()) != nullptr) {
806 if (model().should_include(*subpackage)) {
808 dynamic_cast<class_ &>(*subpackage), ostr);
809 }
810 }
811 else if (dynamic_cast<enum_ *>(subpackage.get()) != nullptr) {
812 if (model().should_include(*subpackage)) {
814 dynamic_cast<enum_ &>(*subpackage), ostr);
815 }
816 }
817 else if (dynamic_cast<concept_ *>(subpackage.get()) != nullptr) {
818 if (model().should_include(*subpackage)) {
820 dynamic_cast<concept_ &>(*subpackage), ostr);
821 }
822 }
823 }
824}

◆ generate_relationships() [5/5]

void clanguml::class_diagram::generators::plantuml::generator::generate_relationships ( std::ostream &  ostr) const

Render all relationships in the diagram to PlantUML.

Parameters
ostrOutput stream

Definition at line 405 of file class_diagram_generator.cc.

406{
407 for (const auto &p : model()) {
408 if (auto *pkg = dynamic_cast<package *>(p.get()); pkg) {
409 generate_relationships(*pkg, ostr);
410 }
411 else if (auto *cls = dynamic_cast<class_ *>(p.get()); cls) {
412 generate_relationships(*cls, ostr);
413 }
414 else if (auto *enm = dynamic_cast<enum_ *>(p.get()); enm) {
415 generate_relationships(*enm, ostr);
416 }
417 else if (auto *cpt = dynamic_cast<concept_ *>(p.get()); cpt) {
418 generate_relationships(*cpt, ostr);
419 }
420 }
421}

◆ generate_top_level_elements()

void clanguml::class_diagram::generators::plantuml::generator::generate_top_level_elements ( std::ostream &  ostr) const

In a nested diagram, generate the top level elements.

This method iterates over the top level elements. In case the diagram is nested (i.e. includes packages), for each package it recursively call generation of elements contained in each package.

Parameters
parentJSON node

Definition at line 837 of file class_diagram_generator.cc.

838{
839 for (const auto &p : model()) {
840 if (auto *pkg = dynamic_cast<package *>(p.get()); pkg) {
841 if (!pkg->is_empty())
842 generate(*pkg, ostr);
843 }
844 else if (auto *cls = dynamic_cast<class_ *>(p.get()); cls) {
845 auto together_group =
846 config().get_together_group(cls->full_name(false));
847 if (together_group) {
848 together_group_stack_.group_together(
849 together_group.value(), cls);
850 }
851 else {
852 generate_alias(*cls, ostr);
853 generate(*cls, ostr);
854 }
855 }
856 else if (auto *enm = dynamic_cast<enum_ *>(p.get()); enm) {
857 auto together_group =
858 config().get_together_group(enm->full_name(false));
859 if (together_group) {
860 together_group_stack_.group_together(
861 together_group.value(), enm);
862 }
863 else {
864 generate_alias(*enm, ostr);
865 generate(*enm, ostr);
866 }
867 }
868 else if (auto *cpt = dynamic_cast<concept_ *>(p.get()); cpt) {
869 auto together_group =
870 config().get_together_group(cpt->full_name(false));
871 if (together_group) {
872 together_group_stack_.group_together(
873 together_group.value(), cpt);
874 }
875 else {
876 generate_alias(*cpt, ostr);
877 generate(*cpt, ostr);
878 }
879 }
880 }
881}

◆ group_methods()

generator::method_groups_t clanguml::class_diagram::generators::plantuml::generator::group_methods ( const std::vector< class_method > &  methods) const

Group class methods based on method type.

Parameters
methodsList of class methods.
Returns
Map of method groups.

Definition at line 238 of file class_diagram_generator.cc.

240{
241 std::map<std::string, std::vector<class_method>> result;
242
243 for (const auto &g : method_groups_) {
244 result[g] = {};
245 }
246
247 for (const auto &m : methods) {
248 if (m.is_constructor() || m.is_destructor()) {
249 result["constructors"].push_back(m);
250 }
251 else if (m.is_copy_assignment() || m.is_move_assignment()) {
252 result["assignment"].push_back(m);
253 }
254 else if (m.is_operator()) {
255 result["operators"].push_back(m);
256 }
257 else {
258 result["other"].push_back(m);
259 }
260 }
261
262 return result;
263}

◆ render_name()

std::string clanguml::class_diagram::generators::plantuml::generator::render_name ( std::string  name) const
private

Definition at line 64 of file class_diagram_generator.cc.

65{
66 util::replace_all(name, "##", "::");
67
68 return name;
69}

◆ sort_class_elements()

template<typename T >
void clanguml::class_diagram::generators::plantuml::generator::sort_class_elements ( std::vector< T > &  elements) const
inlineprivate

Definition at line 277 of file class_diagram_generator.h.

278 {
279 if (config().member_order() == config::member_order_t::lexical) {
280 std::sort(elements.begin(), elements.end(),
281 [](const auto &m1, const auto &m2) {
282 return m1.name() < m2.name();
283 });
284 }
285 }

Member Data Documentation

◆ method_groups_

const std::vector<std::string> clanguml::class_diagram::generators::plantuml::generator::method_groups_
private
Initial value:
{
"constructors", "assignment", "operators", "other"}

Definition at line 271 of file class_diagram_generator.h.

◆ together_group_stack_

common::generators::nested_element_stack<common::model::element> clanguml::class_diagram::generators::plantuml::generator::together_group_stack_
mutableprivate

Definition at line 288 of file class_diagram_generator.h.


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