From fb90108799d70455379221e2d901b15feb41c7aa Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Sat, 16 Apr 2022 19:41:57 +0200 Subject: [PATCH] Ensure there are no relations in class diagram to excluded elements --- .../plantuml/class_diagram_generator.cc | 201 ++++++++++++++---- .../plantuml/class_diagram_generator.h | 15 +- src/common/generators/plantuml/generator.h | 1 + 3 files changed, 165 insertions(+), 52 deletions(-) diff --git a/src/class_diagram/generators/plantuml/class_diagram_generator.cc b/src/class_diagram/generators/plantuml/class_diagram_generator.cc index b0da432b..417baf42 100644 --- a/src/class_diagram/generators/plantuml/class_diagram_generator.cc +++ b/src/class_diagram/generators/plantuml/class_diagram_generator.cc @@ -70,6 +70,9 @@ void generator::generate_alias(const class_ &c, std::ostream &ostr) const ostr << class_type << " \"" << full_name; ostr << "\" as " << c.alias() << '\n'; + + // Register the added alias + m_generated_aliases.emplace(c.alias()); } void generator::generate_alias(const enum_ &e, std::ostream &ostr) const @@ -82,10 +85,12 @@ void generator::generate_alias(const enum_ &e, std::ostream &ostr) const << " \"" << e.full_name(); ostr << "\" as " << e.alias() << '\n'; + + // Register the added alias + m_generated_aliases.emplace(e.alias()); } -void generator::generate( - const class_ &c, std::ostream &ostr, std::ostream &relationships_ostr) const +void generator::generate(const class_ &c, std::ostream &ostr) const { namespace plantuml_common = clanguml::common::generators::plantuml; @@ -161,7 +166,8 @@ void generator::generate( } // - // Process relationships + // Process relationships - here only generate the set of + // rendered_relationships we'll generate them in a seperate method // std::set rendered_relations; @@ -174,7 +180,6 @@ void generator::generate( LOG_DBG("== Processing relationship {}", plantuml_common::to_plantuml(r.type(), r.style())); - std::stringstream relstr; std::string destination; try { destination = r.destination(); @@ -190,24 +195,9 @@ void generator::generate( if (!r.multiplicity_destination().empty()) puml_relation += " \"" + r.multiplicity_destination() + "\""; - relstr << c.alias() << " " << puml_relation << " " - << m_model.to_alias(uns.relative(destination)); - if (!r.label().empty()) { - relstr << " : " << plantuml_common::to_plantuml(r.access()) - << r.label(); rendered_relations.emplace(r.label()); } - - if (unique_relations.count(relstr.str()) == 0) { - unique_relations.emplace(relstr.str()); - - relstr << '\n'; - - LOG_DBG("=== Adding relation {}", relstr.str()); - - all_relations_str << relstr.str(); - } } catch (error::uml_alias_missing &e) { LOG_DBG("=== Skipping {} relation from {} to {} due " @@ -243,12 +233,90 @@ void generator::generate( ostr << "}" << '\n'; + generate_notes(ostr, c); +} + +void generator::generate_relationships( + const class_ &c, std::ostream &ostr) const +{ + namespace plantuml_common = clanguml::common::generators::plantuml; + + const auto &uns = m_config.using_namespace(); + + // + // Process relationships + // + std::set rendered_relations; + + std::stringstream all_relations_str; + std::set unique_relations; + for (const auto &r : c.relationships()) { + if (!m_model.should_include(r.type())) + continue; + + LOG_DBG("== Processing relationship {}", + plantuml_common::to_plantuml(r.type(), r.style())); + + std::stringstream relstr; + std::string destination; + try { + destination = r.destination(); + + LOG_DBG("=== Destination is: {}", destination); + + std::string puml_relation; + if (!r.multiplicity_source().empty()) + puml_relation += "\"" + r.multiplicity_source() + "\" "; + + puml_relation += plantuml_common::to_plantuml(r.type(), r.style()); + + if (!r.multiplicity_destination().empty()) + puml_relation += " \"" + r.multiplicity_destination() + "\""; + + auto target_alias = m_model.to_alias( + m_config.using_namespace().relative(destination)); + + if (m_generated_aliases.find(target_alias) == + m_generated_aliases.end()) + continue; + + relstr << c.alias() << " " << puml_relation << " " << target_alias; + + if (!r.label().empty()) { + relstr << " : " << plantuml_common::to_plantuml(r.access()) + << r.label(); + rendered_relations.emplace(r.label()); + } + + if (unique_relations.count(relstr.str()) == 0) { + unique_relations.emplace(relstr.str()); + + relstr << '\n'; + + LOG_DBG("=== Adding relation {}", relstr.str()); + + all_relations_str << relstr.str(); + } + } + catch (error::uml_alias_missing &e) { + LOG_DBG("=== Skipping {} relation from {} to {} due " + "to: {}", + plantuml_common::to_plantuml(r.type(), r.style()), + c.full_name(), destination, e.what()); + } + } + if (m_model.should_include(relationship_t::kExtension)) { for (const auto &b : c.parents()) { std::stringstream relstr; try { - relstr << m_model.to_alias(uns.relative(b.name())) << " <|-- " - << c.alias() << '\n'; + auto target_alias = m_model.to_alias(uns.relative(b.name())); + + if (m_generated_aliases.find(target_alias) == + m_generated_aliases.end()) + continue; + + relstr << target_alias << " <|-- " << c.alias() << '\n'; all_relations_str << relstr.str(); } catch (error::uml_alias_missing &e) { @@ -259,14 +327,10 @@ void generator::generate( } } - generate_notes(ostr, c); - - // Print relationships - relationships_ostr << all_relations_str.str(); + ostr << all_relations_str.str(); } -void generator::generate( - const enum_ &e, std::ostream &ostr, std::ostream &relationships_ostr) const +void generator::generate(const enum_ &e, std::ostream &ostr) const { ostr << "enum " << e.alias(); @@ -285,6 +349,11 @@ void generator::generate( ostr << "}" << '\n'; + generate_notes(ostr, e); +} + +void generator::generate_relationships(const enum_ &e, std::ostream &ostr) const +{ for (const auto &r : e.relationships()) { if (!m_model.should_include(r.type())) continue; @@ -294,19 +363,24 @@ void generator::generate( try { destination = r.destination(); + auto target_alias = m_model.to_alias( + m_config.using_namespace().relative(destination)); + + if (m_generated_aliases.find(target_alias) == + m_generated_aliases.end()) + continue; + relstr << e.alias() << " " << clanguml::common::generators::plantuml::to_plantuml( r.type(), r.style()) - << " " - << m_model.to_alias( - m_config.using_namespace().relative(destination)); + << " " << target_alias; if (!r.label().empty()) relstr << " : " << r.label(); relstr << '\n'; - relationships_ostr << relstr.str(); + ostr << relstr.str(); } catch (error::uml_alias_missing &ex) { LOG_DBG("Skipping {} relation from {} to {} due " @@ -316,12 +390,9 @@ void generator::generate( e.full_name(), destination, ex.what()); } } - - generate_notes(ostr, e); } -void generator::generate(const package &p, std::ostream &ostr, - std::ostream &relationships_ostr) const +void generator::generate(const package &p, std::ostream &ostr) const { const auto &uns = m_config.using_namespace(); @@ -349,20 +420,18 @@ void generator::generate(const package &p, std::ostream &ostr, // TODO: add option - generate_empty_packages const auto &sp = dynamic_cast(*subpackage); if (!sp.is_empty()) - generate(sp, ostr, relationships_ostr); + generate(sp, ostr); } else if (dynamic_cast(subpackage.get())) { if (m_model.should_include(*subpackage)) { generate_alias(dynamic_cast(*subpackage), ostr); - generate(dynamic_cast(*subpackage), ostr, - relationships_ostr); + generate(dynamic_cast(*subpackage), ostr); } } else if (dynamic_cast(subpackage.get())) { if (m_model.should_include(*subpackage)) { generate_alias(dynamic_cast(*subpackage), ostr); - generate(dynamic_cast(*subpackage), ostr, - relationships_ostr); + generate(dynamic_cast(*subpackage), ostr); } } } @@ -378,36 +447,76 @@ void generator::generate(const package &p, std::ostream &ostr, generate_notes(ostr, p); } +void generator::generate_relationships( + const package &p, std::ostream &ostr) const +{ + const auto &uns = m_config.using_namespace(); + + for (const auto &subpackage : p) { + if (dynamic_cast(subpackage.get())) { + // TODO: add option - generate_empty_packages + const auto &sp = dynamic_cast(*subpackage); + if (!sp.is_empty()) + generate_relationships(sp, ostr); + } + else if (dynamic_cast(subpackage.get())) { + if (m_model.should_include(*subpackage)) { + generate_relationships( + dynamic_cast(*subpackage), ostr); + } + } + else if (dynamic_cast(subpackage.get())) { + if (m_model.should_include(*subpackage)) { + generate_relationships( + dynamic_cast(*subpackage), ostr); + } + } + } +} + void generator::generate(std::ostream &ostr) const { ostr << "@startuml" << '\n'; - std::stringstream relationships_ostr; - generate_plantuml_directives(ostr, m_config.puml().before); for (const auto &p : m_model) { if (dynamic_cast(p.get())) { const auto &sp = dynamic_cast(*p); if (!sp.is_empty()) - generate(sp, ostr, relationships_ostr); + generate(sp, ostr); } else if (dynamic_cast(p.get())) { if (m_model.should_include(*p)) { generate_alias(dynamic_cast(*p), ostr); - generate(dynamic_cast(*p), ostr, relationships_ostr); + generate(dynamic_cast(*p), ostr); } } else if (dynamic_cast(p.get())) { if (m_model.should_include(*p)) { generate_alias(dynamic_cast(*p), ostr); - generate(dynamic_cast(*p), ostr, relationships_ostr); + generate(dynamic_cast(*p), ostr); } } ostr << '\n'; } - ostr << relationships_ostr.str(); + for (const auto &p : m_model) { + if (dynamic_cast(p.get())) { + generate_relationships(dynamic_cast(*p), ostr); + } + else if (dynamic_cast(p.get())) { + if (m_model.should_include(*p)) { + generate_relationships(dynamic_cast(*p), ostr); + } + } + else if (dynamic_cast(p.get())) { + if (m_model.should_include(*p)) { + generate_relationships(dynamic_cast(*p), ostr); + } + } + ostr << '\n'; + } generate_config_layout_hints(ostr); diff --git a/src/class_diagram/generators/plantuml/class_diagram_generator.h b/src/class_diagram/generators/plantuml/class_diagram_generator.h index 4aabbaee..81e0d191 100644 --- a/src/class_diagram/generators/plantuml/class_diagram_generator.h +++ b/src/class_diagram/generators/plantuml/class_diagram_generator.h @@ -65,14 +65,17 @@ public: void generate_alias(const enum_ &e, std::ostream &ostr) const; - void generate(const class_ &c, std::ostream &ostr, - std::ostream &relationships_ostr) const; + void generate(const class_ &c, std::ostream &ostr) const; - void generate(const enum_ &e, std::ostream &ostr, - std::ostream &relationships_ostr) const; + void generate_relationships(const class_ &c, std::ostream &ostr) const; - void generate(const package &p, std::ostream &ostr, - std::ostream &relationships_ostr) const; + void generate(const enum_ &e, std::ostream &ostr) const; + + void generate_relationships(const enum_ &c, std::ostream &ostr) const; + + void generate(const package &p, std::ostream &ostr) const; + + void generate_relationships(const package &p, std::ostream &ostr) const; void generate(std::ostream &ostr) const override; }; diff --git a/src/common/generators/plantuml/generator.h b/src/common/generators/plantuml/generator.h index fac0f8d3..e5c28b57 100644 --- a/src/common/generators/plantuml/generator.h +++ b/src/common/generators/plantuml/generator.h @@ -82,6 +82,7 @@ private: protected: ConfigType &m_config; DiagramType &m_model; + mutable std::set m_generated_aliases; inja::json m_context; mutable inja::Environment m_env; };