From fd7d916e3eb9871e7d152bc3775c11d71d1e80f8 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Tue, 8 Feb 2022 22:19:38 +0100 Subject: [PATCH 01/18] Added layout hints config option to class diagrams --- src/config/config.cc | 38 +++++++++++++++++++++++++++++++ src/config/config.h | 10 ++++++++ tests/test_config.cc | 24 +++++++++++++++++++ tests/test_config_data/layout.yml | 22 ++++++++++++++++++ 4 files changed, 94 insertions(+) create mode 100644 tests/test_config_data/layout.yml diff --git a/src/config/config.cc b/src/config/config.cc index 72a8b2f9..fbf459d6 100644 --- a/src/config/config.cc +++ b/src/config/config.cc @@ -204,6 +204,8 @@ using clanguml::common::model::scope_t; using clanguml::config::class_diagram; using clanguml::config::config; using clanguml::config::filter; +using clanguml::config::hint_t; +using clanguml::config::layout_hint; using clanguml::config::method_arguments; using clanguml::config::package_diagram; using clanguml::config::plantuml; @@ -375,6 +377,7 @@ template <> struct convert { return false; get_option(node, rhs.classes); + get_option(node, rhs.layout); get_option(node, rhs.include_relations_also_as_members); get_option(node, rhs.generate_method_arguments); @@ -410,6 +413,41 @@ template <> struct convert { } }; +// +// layout_hint Yaml decoder +// +template <> struct convert { + static bool decode(const Node &node, layout_hint &rhs) + { + assert(node.Type() == NodeType::Map); + + if (node["up"]) { + rhs.hint = hint_t::up; + rhs.entity = node["up"].as(); + } + else if (node["down"]) { + rhs.hint = hint_t::down; + rhs.entity = node["down"].as(); + } + else if (node["left"]) { + rhs.hint = hint_t::left; + rhs.entity = node["left"].as(); + } + else if (node["right"]) { + rhs.hint = hint_t::right; + rhs.entity = node["right"].as(); + } + else if (node["hidden"]) { + rhs.hint = hint_t::hidden; + rhs.entity = node["hidden"].as(); + } + else + return false; + + return true; + } +}; + // // config Yaml decoder // diff --git a/src/config/config.h b/src/config/config.h index cb72d318..b4bf92ed 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -65,6 +65,15 @@ struct filter { std::vector scopes; }; +enum class hint_t { up, down, left, right, hidden }; + +struct layout_hint { + hint_t hint; + std::string entity; +}; + +using layout_hints = std::map>; + std::string to_string(const diagram_type t); struct inheritable_diagram_options { @@ -109,6 +118,7 @@ struct class_diagram : public diagram { diagram_type type() const override; option> classes{"classes"}; + option layout{"layout"}; bool has_class(std::string clazz); }; diff --git a/tests/test_config.cc b/tests/test_config.cc index 1a5aa603..fd693444 100644 --- a/tests/test_config.cc +++ b/tests/test_config.cc @@ -77,4 +77,28 @@ TEST_CASE("Test config includes", "[unit-test]") CHECK(cus.include_relations_also_as_members()); CHECK(cus.generate_method_arguments() == clanguml::config::method_arguments::none); +} + +TEST_CASE("Test config layout", "[unit-test]") +{ + auto cfg = clanguml::config::load("./test_config_data/layout.yml"); + + CHECK(cfg.diagrams.size() == 1); + auto &def = static_cast( + *cfg.diagrams["class_main"]); + CHECK(def.type() == clanguml::config::diagram_type::class_diagram); + + CHECK(def.layout().at("ABCD").size() == 2); + CHECK(def.layout().at("ABCD")[0].hint == clanguml::config::hint_t::up); + CHECK(def.layout().at("ABCD")[0].entity == "ABCD_SUBCLASS"); + CHECK(def.layout().at("ABCD")[1].hint == clanguml::config::hint_t::left); + CHECK(def.layout().at("ABCD")[1].entity == "ABCD_SIBLING"); + + CHECK(def.layout().at("ABCD_SIBLING").size() == 2); + CHECK(def.layout().at("ABCD_SIBLING")[0].hint == + clanguml::config::hint_t::right); + CHECK(def.layout().at("ABCD_SIBLING")[0].entity == "ABCD_OTHER_SIBLING"); + CHECK(def.layout().at("ABCD_SIBLING")[1].hint == + clanguml::config::hint_t::down); + CHECK(def.layout().at("ABCD_SIBLING")[1].entity == "ABCD_SIBLING_SIBLING"); } \ No newline at end of file diff --git a/tests/test_config_data/layout.yml b/tests/test_config_data/layout.yml new file mode 100644 index 00000000..d30f264d --- /dev/null +++ b/tests/test_config_data/layout.yml @@ -0,0 +1,22 @@ +compilation_database_dir: debug +output_directory: output +diagrams: + class_main: + type: class + glob: + - src/**/*.cc + - src/**/*.h + using_namespace: + - clanguml + generate_method_arguments: full + layout: + ABCD: + - up: ABCD_SUBCLASS + - left: ABCD_SIBLING + ABCD_SIBLING: + - right: ABCD_OTHER_SIBLING + - down: ABCD_SIBLING_SIBLING + include: + namespaces: + - clanguml + - ABCD \ No newline at end of file From 5835f230e496a5c7d14e9b95785e7e067638bc09 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Mon, 14 Feb 2022 22:51:29 +0100 Subject: [PATCH 02/18] Added layout hints config option to package diagrams --- src/config/config.cc | 2 ++ src/config/config.h | 2 ++ tests/test_config.cc | 45 +++++++++++++++++++++---------- tests/test_config_data/layout.yml | 17 +++++++++++- 4 files changed, 51 insertions(+), 15 deletions(-) diff --git a/src/config/config.cc b/src/config/config.cc index fbf459d6..c4402bec 100644 --- a/src/config/config.cc +++ b/src/config/config.cc @@ -409,6 +409,8 @@ template <> struct convert { if (!decode_diagram(node, rhs)) return false; + get_option(node, rhs.layout); + return true; } }; diff --git a/src/config/config.h b/src/config/config.h index b4bf92ed..9a954c90 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -135,6 +135,8 @@ struct package_diagram : public diagram { virtual ~package_diagram() = default; diagram_type type() const override; + + option layout{"layout"}; }; struct config : public inheritable_diagram_options { diff --git a/tests/test_config.cc b/tests/test_config.cc index fd693444..95091f8e 100644 --- a/tests/test_config.cc +++ b/tests/test_config.cc @@ -83,22 +83,39 @@ TEST_CASE("Test config layout", "[unit-test]") { auto cfg = clanguml::config::load("./test_config_data/layout.yml"); - CHECK(cfg.diagrams.size() == 1); + CHECK(cfg.diagrams.size() == 2); + auto &def = static_cast( *cfg.diagrams["class_main"]); - CHECK(def.type() == clanguml::config::diagram_type::class_diagram); - CHECK(def.layout().at("ABCD").size() == 2); - CHECK(def.layout().at("ABCD")[0].hint == clanguml::config::hint_t::up); - CHECK(def.layout().at("ABCD")[0].entity == "ABCD_SUBCLASS"); - CHECK(def.layout().at("ABCD")[1].hint == clanguml::config::hint_t::left); - CHECK(def.layout().at("ABCD")[1].entity == "ABCD_SIBLING"); + auto check_layout = [](const auto &diagram, + const clanguml::config::diagram_type type) { + CHECK(diagram.type() == type); - CHECK(def.layout().at("ABCD_SIBLING").size() == 2); - CHECK(def.layout().at("ABCD_SIBLING")[0].hint == - clanguml::config::hint_t::right); - CHECK(def.layout().at("ABCD_SIBLING")[0].entity == "ABCD_OTHER_SIBLING"); - CHECK(def.layout().at("ABCD_SIBLING")[1].hint == - clanguml::config::hint_t::down); - CHECK(def.layout().at("ABCD_SIBLING")[1].entity == "ABCD_SIBLING_SIBLING"); + CHECK(diagram.layout().at("ABCD").size() == 2); + CHECK(diagram.layout().at("ABCD")[0].hint == + clanguml::config::hint_t::up); + CHECK(diagram.layout().at("ABCD")[0].entity == "ABCD_SUBCLASS"); + CHECK(diagram.layout().at("ABCD")[1].hint == + clanguml::config::hint_t::left); + CHECK(diagram.layout().at("ABCD")[1].entity == "ABCD_SIBLING"); + + CHECK(diagram.layout().at("ABCD_SIBLING").size() == 2); + CHECK(diagram.layout().at("ABCD_SIBLING")[0].hint == + clanguml::config::hint_t::right); + CHECK(diagram.layout().at("ABCD_SIBLING")[0].entity == + "ABCD_OTHER_SIBLING"); + CHECK(diagram.layout().at("ABCD_SIBLING")[1].hint == + clanguml::config::hint_t::down); + CHECK(diagram.layout().at("ABCD_SIBLING")[1].entity == + "ABCD_SIBLING_SIBLING"); + }; + + check_layout(static_cast( + *cfg.diagrams["class_main"]), + clanguml::config::diagram_type::class_diagram); + + check_layout(static_cast( + *cfg.diagrams["package_main"]), + clanguml::config::diagram_type::package_diagram); } \ No newline at end of file diff --git a/tests/test_config_data/layout.yml b/tests/test_config_data/layout.yml index d30f264d..e70502dc 100644 --- a/tests/test_config_data/layout.yml +++ b/tests/test_config_data/layout.yml @@ -19,4 +19,19 @@ diagrams: include: namespaces: - clanguml - - ABCD \ No newline at end of file + - ABCD + package_main: + type: package + glob: + - src/**/*.cc + - src/**/*.h + using_namespace: + - clanguml + generate_method_arguments: full + layout: + ABCD: + - up: ABCD_SUBCLASS + - left: ABCD_SIBLING + ABCD_SIBLING: + - right: ABCD_OTHER_SIBLING + - down: ABCD_SIBLING_SIBLING \ No newline at end of file From db56949da3b85567e27ab688c5aad2f04a9d81d3 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Mon, 14 Feb 2022 23:49:53 +0100 Subject: [PATCH 03/18] Added package diagram layout hints generation --- src/config/config.cc | 20 +++++++++++--- src/config/config.h | 3 ++- .../plantuml/package_diagram_generator.cc | 27 +++++++++++++++++++ .../plantuml/package_diagram_generator.h | 2 ++ 4 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/config/config.cc b/src/config/config.cc index c4402bec..5489529d 100644 --- a/src/config/config.cc +++ b/src/config/config.cc @@ -58,6 +58,22 @@ std::string to_string(const diagram_type t) } } +std::string to_string(const hint_t t) +{ + switch (t) { + case hint_t::up: + return "up"; + case hint_t::down: + return "down"; + case hint_t::left: + return "left"; + case hint_t::right: + return "right"; + default: + assert(false); + } +} + void plantuml::append(const plantuml &r) { before.insert(before.end(), r.before.begin(), r.before.end()); @@ -439,10 +455,6 @@ template <> struct convert { rhs.hint = hint_t::right; rhs.entity = node["right"].as(); } - else if (node["hidden"]) { - rhs.hint = hint_t::hidden; - rhs.entity = node["hidden"].as(); - } else return false; diff --git a/src/config/config.h b/src/config/config.h index 9a954c90..9ae7b614 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -65,7 +65,7 @@ struct filter { std::vector scopes; }; -enum class hint_t { up, down, left, right, hidden }; +enum class hint_t { up, down, left, right }; struct layout_hint { hint_t hint; @@ -75,6 +75,7 @@ struct layout_hint { using layout_hints = std::map>; std::string to_string(const diagram_type t); +std::string to_string(const hint_t t); struct inheritable_diagram_options { option> glob{"glob"}; diff --git a/src/package_diagram/generators/plantuml/package_diagram_generator.cc b/src/package_diagram/generators/plantuml/package_diagram_generator.cc index 940a838d..a14c917b 100644 --- a/src/package_diagram/generators/plantuml/package_diagram_generator.cc +++ b/src/package_diagram/generators/plantuml/package_diagram_generator.cc @@ -109,6 +109,31 @@ void generator::generate_relationships( } } +void generator::generate_config_layout_hints(std::ostream &ostr) const +{ + const auto &uns = m_config.using_namespace(); + + // Generate layout hints + for (const auto &[entity, hints] : m_config.layout()) { + for (const auto &hint : hints) { + std::stringstream hint_str; + try { + hint_str << m_model.to_alias(ns_relative(uns, entity)) + << " -[hidden]" + << clanguml::config::to_string(hint.hint) << "- " + << m_model.to_alias(ns_relative(uns, hint.entity)) + << '\n'; + ostr << hint_str.str(); + } + catch (error::uml_alias_missing &e) { + LOG_ERROR("=== Skipping layout hint from {} to {} due " + "to: {}", + entity, hint.entity, e.what()); + } + } + } +} + void generator::generate(const package &p, std::ostream &ostr) const { const auto &uns = m_config.using_namespace(); @@ -175,6 +200,8 @@ void generator::generate(std::ostream &ostr) const ostr << '\n'; } + generate_config_layout_hints(ostr); + // Process aliases in any of the puml directives for (const auto &b : m_config.puml().after) { std::string note{b}; diff --git a/src/package_diagram/generators/plantuml/package_diagram_generator.h b/src/package_diagram/generators/plantuml/package_diagram_generator.h index ed5b8fcf..5fe96ed9 100644 --- a/src/package_diagram/generators/plantuml/package_diagram_generator.h +++ b/src/package_diagram/generators/plantuml/package_diagram_generator.h @@ -60,6 +60,8 @@ public: void generate_relationships(const package &p, std::ostream &ostr) const; + void generate_config_layout_hints(std::ostream &ostr) const; + void generate(const package &e, std::ostream &ostr) const; void generate(std::ostream &ostr) const; From 96c6851e5248ac0f7e0841dac734da2269415920 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Mon, 14 Feb 2022 23:50:04 +0100 Subject: [PATCH 04/18] Added package diagram layout hints generation test case --- tests/t30007/.clang-uml | 19 ++++++++++++++ tests/t30007/t30007.cc | 33 +++++++++++++++++++++++++ tests/t30007/test_case.h | 53 ++++++++++++++++++++++++++++++++++++++++ tests/test_cases.cc | 1 + tests/test_cases.h | 8 ++++++ 5 files changed, 114 insertions(+) create mode 100644 tests/t30007/.clang-uml create mode 100644 tests/t30007/t30007.cc create mode 100644 tests/t30007/test_case.h diff --git a/tests/t30007/.clang-uml b/tests/t30007/.clang-uml new file mode 100644 index 00000000..96c875a0 --- /dev/null +++ b/tests/t30007/.clang-uml @@ -0,0 +1,19 @@ +compilation_database_dir: .. +output_directory: puml +diagrams: + t30007_package: + type: package + glob: + - ../../tests/t30007/t30007.cc + include: + namespaces: + - clanguml::t30007 + using_namespace: + - clanguml::t30007 + layout: + C: + - up: 'A::AA' + - left: B + plantuml: + before: + - "' t30007 test package diagram" \ No newline at end of file diff --git a/tests/t30007/t30007.cc b/tests/t30007/t30007.cc new file mode 100644 index 00000000..e79461ab --- /dev/null +++ b/tests/t30007/t30007.cc @@ -0,0 +1,33 @@ +namespace clanguml { +namespace t30007 { + +namespace B { +struct BB { +}; +} + +/// \uml{note[top] Compare layout with t30006.} +namespace A { +namespace AA { +struct A1 { + B::BB *b; +}; +} +} + +namespace C { +struct CC { +}; +} + +/// \uml{note[bottom] Bottom A note.} +namespace A { +namespace AA { +struct A2 { + C::CC *c; +}; +} +} + +} +} \ No newline at end of file diff --git a/tests/t30007/test_case.h b/tests/t30007/test_case.h new file mode 100644 index 00000000..130f1e96 --- /dev/null +++ b/tests/t30007/test_case.h @@ -0,0 +1,53 @@ +/** + * tests/t30007/test_case.cc + * + * Copyright (c) 2021-2022 Bartek Kryza + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +TEST_CASE("t30007", "[test-case][package]") +{ + auto [config, db] = load_config("t30007"); + + auto diagram = config.diagrams["t30007_package"]; + + REQUIRE(diagram->should_include("clanguml::t30007::A")); + REQUIRE(diagram->should_include("clanguml::t30007::C")); + REQUIRE(!diagram->should_include("std::vector")); + + REQUIRE(diagram->name == "t30007_package"); + + auto model = generate_package_diagram(db, diagram); + + REQUIRE(model.name() == "t30007_package"); + + auto puml = generate_package_puml(diagram, model); + AliasMatcher _A(puml); + + REQUIRE_THAT(puml, StartsWith("@startuml")); + REQUIRE_THAT(puml, EndsWith("@enduml\n")); + + REQUIRE_THAT(puml, IsPackage("A")); + REQUIRE_THAT(puml, IsPackage("B")); + REQUIRE_THAT(puml, IsPackage("C")); + + REQUIRE_THAT(puml, IsDependency(_A("AA"), _A("B"))); + REQUIRE_THAT(puml, IsDependency(_A("AA"), _A("C"))); + + REQUIRE_THAT(puml, IsLayoutHint(_A("C"), "up", _A("AA"))); + REQUIRE_THAT(puml, IsLayoutHint(_A("C"), "left", _A("B"))); + + save_puml( + "./" + config.output_directory() + "/" + diagram->name + ".puml", puml); +} diff --git a/tests/test_cases.cc b/tests/test_cases.cc index 922e36be..e721378d 100644 --- a/tests/test_cases.cc +++ b/tests/test_cases.cc @@ -182,6 +182,7 @@ using namespace clanguml::test::matchers; #include "t30004/test_case.h" #include "t30005/test_case.h" #include "t30006/test_case.h" +#include "t30007/test_case.h" // // Other tests (e.g. configuration file) diff --git a/tests/test_cases.h b/tests/test_cases.h index c18f3c5f..b20dbd8b 100644 --- a/tests/test_cases.h +++ b/tests/test_cases.h @@ -351,6 +351,14 @@ ContainsMatcher IsDependency(std::string const &from, std::string const &to, CasedString(fmt::format("{} ..> {}", from, to), caseSensitivity)); } +ContainsMatcher IsLayoutHint(std::string const &from, std::string const &hint, + std::string const &to, + CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes) +{ + return ContainsMatcher(CasedString( + fmt::format("{} -[hidden]{}- {}", from, hint, to), caseSensitivity)); +} + ContainsMatcher HasNote(std::string const &cls, std::string const &position, std::string const ¬e, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes) From 7a475411eb0357d3762557fcfbe7592df727d82b Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Mon, 14 Feb 2022 23:51:43 +0100 Subject: [PATCH 05/18] Updated test cases documentation --- docs/test_cases.md | 1 + docs/test_cases/t00006.md | 1 + docs/test_cases/t00017.md | 13 ++++++++++++- docs/test_cases/t00017_class.png | Bin 24235 -> 28242 bytes docs/test_cases/t00028.md | 5 +++++ docs/test_cases/t00028_class.png | Bin 60872 -> 63318 bytes tests/test_cases.yaml | 3 +++ 7 files changed, 22 insertions(+), 1 deletion(-) diff --git a/docs/test_cases.md b/docs/test_cases.md index 1f0e4c0d..2b5459d5 100644 --- a/docs/test_cases.md +++ b/docs/test_cases.md @@ -43,5 +43,6 @@ * [t30004](./test_cases/t30004.md) - PlantUML package decorators test case * [t30005](./test_cases/t30005.md) - Package namespace alias test case * [t30006](./test_cases/t30006.md) - Package split namespace test case + * [t30007](./test_cases/t30007.md) - Package diagram layout hints test case ## Configuration diagrams * [t90000](./test_cases/t90000.md) - Basic config test diff --git a/docs/test_cases/t00006.md b/docs/test_cases/t00006.md index 7e7ade96..44b3d036 100644 --- a/docs/test_cases/t00006.md +++ b/docs/test_cases/t00006.md @@ -18,6 +18,7 @@ diagrams: ## Source code File t00006.cc ```cpp +#include #include #include diff --git a/docs/test_cases/t00017.md b/docs/test_cases/t00017.md index 503dacac..b673c436 100644 --- a/docs/test_cases/t00017.md +++ b/docs/test_cases/t00017.md @@ -19,6 +19,8 @@ diagrams: ## Source code File t00017.cc ```cpp +#include + namespace clanguml { namespace t00017 { class A { @@ -55,6 +57,15 @@ class K { }; class R { + explicit R(int &some_int, C &cc, const E &ee, F &&ff, I *&ii) + : some_int_reference{some_int} + , c{cc} + , e{ee} + , f{std::move(ff)} + , i{ii} + { + } + private: int some_int; int *some_int_pointer; @@ -64,7 +75,7 @@ private: B *b; C &c; const D *d; - const E &e{}; + const E &e; F &&f; G **g; H ***h; diff --git a/docs/test_cases/t00017_class.png b/docs/test_cases/t00017_class.png index cea9349adcc0e5516fb3a6f71f8b29d0806dd72e..b1cfc0a803f8f057862c032bffb07084615f1033 100644 GIT binary patch literal 28242 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 Q?{1Hz#N^mu3$G=;dH?_b literal 24235 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
Hh9V^1hy3xc(^BnWt?aPqI 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 literal 60872 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 %|{Jr_pKtM1tRbwL_A(v(U-xm_SZd3id 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

  • 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 Z@tOaiwPM6Pw!w_ouIOLRzIgA+{{ZmC+A075 diff --git a/tests/test_cases.yaml b/tests/test_cases.yaml index 7c3bdf30..399dd654 100644 --- a/tests/test_cases.yaml +++ b/tests/test_cases.yaml @@ -125,6 +125,9 @@ test_cases: - name: t30006 title: Package split namespace test case description: + - name: t30007 + title: Package diagram layout hints test case + description: Configuration diagrams: - name: t90000 title: Basic config test From 1e551ebbffa2ef65f359e5e357a50a3cc11a3044 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Mon, 14 Feb 2022 23:52:35 +0100 Subject: [PATCH 06/18] Updated test cases documentation --- docs/test_cases/t30007.md | 62 +++++++++++++++++++++++++++++ docs/test_cases/t30007_package.png | Bin 0 -> 9126 bytes 2 files changed, 62 insertions(+) create mode 100644 docs/test_cases/t30007.md create mode 100644 docs/test_cases/t30007_package.png diff --git a/docs/test_cases/t30007.md b/docs/test_cases/t30007.md new file mode 100644 index 00000000..b2af19b5 --- /dev/null +++ b/docs/test_cases/t30007.md @@ -0,0 +1,62 @@ +# t30007 - Package diagram layout hints test case +## Config +```yaml +compilation_database_dir: .. +output_directory: puml +diagrams: + t30007_package: + type: package + glob: + - ../../tests/t30007/t30007.cc + include: + namespaces: + - clanguml::t30007 + using_namespace: + - clanguml::t30007 + layout: + C: + - up: 'A::AA' + - left: B + plantuml: + before: + - "' t30007 test package diagram" +``` +## Source code +File t30007.cc +```cpp +namespace clanguml { +namespace t30007 { + +namespace B { +struct BB { +}; +} + +/// \uml{note[top] Compare layout with t30006.} +namespace A { +namespace AA { +struct A1 { + B::BB *b; +}; +} +} + +namespace C { +struct CC { +}; +} + +/// \uml{note[bottom] Bottom A note.} +namespace A { +namespace AA { +struct A2 { + C::CC *c; +}; +} +} + +} +} +``` +## Generated UML diagrams +![t30007_package](./t30007_package.png "Package diagram layout hints test case") diff --git a/docs/test_cases/t30007_package.png b/docs/test_cases/t30007_package.png new file mode 100644 index 0000000000000000000000000000000000000000..ddd91be610b0ed91100deaf7fe5226fc9f3cbc04 GIT binary patch literal 9126 zcmd6Nby(Ej^REKZ2rRJ(NGwZtNH+^CA}G?`p@g(ZO0$v+(j`bKQj*f$DF{e+cP-8D zt)K7jbD#UW&vXB{f89U!VRz1)b7tnu%$f5V5HC~}32-TK@7=pcpah4#ym#+DKJX#M zMgu5nwwZjuA68d+9ar-=j_>R&tz7RZS~^%do4Q(B(3!oXvvGBG6y@f2v@>;Zb+fnQ zGJj)F%p*b#tPuQ4L&x>M>G$pf%Xp;u#7^6`@{o4UquaOS@wn&i-J{P}g2`xj811Ix z>5%=J>JmajGdhZWY80SR(SLaNEj*|3_8lLe5P|>4-=;y{qV&j^%{d}?*U@@kJ_!gXc`xz-XtZZ8x3I6T z?|HhY+hXej$pwR8m~5UG2^wM(%59~otD7A3&%Ad3cGp;{23gtk7OGd#X56xQ}NzKN4Q*_>tQITE+2Jx@rCKt znFODc+5FkA&(-O6T8gN=x2sDz1st>mbAeo(O*dg+R{5R&a+>#RTBx4Smb%<%QHr}v z(H_kc0XgoarYbraL(RJ|EiGoQmZP7iN!~m&nAvbz4oH>~d3O{;?;lDi^-yln_^!6? z$(_(V%+TkQY`C*0?l}WKjmLuL;mE*%8Qm}Ce3Ai##ajRN-C;EEn(yTA@^COGrTZ_< z-7E-cY4>$akdjgyCgC0p(Spm(>Fn7~^66gPB0as~^^K3LoY!I_R71bc{pEaPdPzN> zNlQT1`k>(ybt07SNN=V_)a|HlJ;T2%N`i5$%W``(|8t_Ydf3=Fmu};A)xv@*#o5|m z!y#(kykDOMBd)_Iie}b&H1CV7rGalmdwl$e;H71wOCa{49tGy?&DDC@QQiJr2d=Tt zsm+Wp}MGX#SwDhvj;W-WvYS!Og z!nEAme-7NX?n0IVvwU(=tv@;(Of%P1 z;VOxS%1!K~BS_+7#1JzLH}5py)M#6ix-KOOX`R0nOu2YdUv{-O%RiL%j{LCJadB9Y zwn3>t%5CdjM55hcs-%AX60VeK*v09De7e}xk2OX7g?pn_6$j{^oc6M{aCue8lvh2}m-<2<5vb#Nk=Yhg7)>d z=gT5m3N6#qeNUutDMEZNEQxn+udoJ^T^Nq*tgy>fQU!l}20XRBGaX|y?h`HGn!Rh< zvr7!CqP zrioPR8cRKD&X8GEJaST=&5|>TXr^1KoyLVku&nBN!NcUq@}Uqj2Znx$Z>M;#O{*y> zFuhEf?V>D39GWCpICuB-9X1hsw^mjP5I^(6Z}twmu84t7;;gu{UB-;K2+ChrQzn+A zj@lNM6Zoc8zBiX+V`C8!5!ct(fmnn~R;^vxDu9=-&?mLt9%q`uzd7B<#kEq&n29dZ ztFjACLXV|(kEj-gzOtC>hhr*&3AiBG!=mavQt|Q2;7={k`|qTfWQEg8NiZTmxevzJ(1)9&3Vszb z(+%jCnQ`b_+5@MqY&XM%n&Ce<9-{43+20s>kmQ8p5-T*9WO4W^zWla&zVWyPs|5VB z=!eVQvuX~(p{g=hJRy<<*F~$NKJKQ2G8@1HFhaKd``)K=TV+yc1hrsluOgTo6eKa_ zWZ-Ic##TAgXE{CXplq`n&qeE%xl}TPmSvYh6AdA*Hb(36w$jU8wMCs42Ew zLa?{n*-pz6qON1@cU2yi!R97WPY3~3mBXx_j!sxa_#Zb?gYqTgt!qCF55xXlGcxGc z)eRL0`klb3-~I@kx9`m{6$HypTQoXZOO3-K+~X2|z@**`hpHxRL1fT*jQ_;JT4DDJ zKM3bh@?!>M4DvVc|NJ`I0PpT5<#`+qySJ;bJ%V*&foJ;Iy#WVIhpZrnL%BYCAxX)| zEG;c_b90NB?PBMy{k2-35Si@gGkRX`BuFbM;hfkDP>w`uw2Bhp>_e#0vx4u*CDBiw zoUoeQpSk@I9zJp(TOzRZA*{6yyGz=JzM05srw`$cJq06y_@SM^YoWC9v+_Z)29aK9i{<} zxHpKLygVj4Iy!N2advh*QKv<4C{8P@09$Mv^YbeEX>!{`u%*N9*cWxA6T-NAedmfB zyVVI8)-2RA)$EFTtZUU#q@twc?{{&uy1BVo=f2xI5X8qND+$yjAt50#F+|+l+%qf( zU`vm7GB$R0A8+rxXUULjZwX6-AaB66>fY{$__YS%utd{J(X7_jix;cv=;*w75p%x2 z&AJS+kPU|Nc`qeAev~ugAynhCv ze0-pcii!#;_9y6s*Q0qV%h!RaS^tc+>zbLHH#9WF#m2HMLssPGA-}8N(4O(UnG^4= z!M+%-hD$p-9t>y60eY^;p&*E;sI%i^{c4BDfNh>_7(u;IdmXCeTn6w*V0w~TFrvp| zYvgm+!D5?`!;FmpW%!2=X*cl>0i}^CkeLUjF){J&?JX}aualD#4i3%> zWd{c?4f>jj7`Q8;Sfp|y7g>`z zq6AiRAK<};D5O2nr3gwzQOC#v-H{Tf+l#ne*}@1So_p zrmO7B$o&S28*|lE_E<=#rkzF5F z&JULx8yg$EP{k!BU69*s{2>GhGxfLTf`8)6=D!&&IzEtLDlcR#m^|kk;m`+tJ$A)W6cbML{){(Mu`qiHe>=J$UCZP=<)9#CtD6i4>A<2wbekbyxL7nfZv zA~9uU<;64!uPQ-)F5t*L^575#hD9Z1<*V|S{0Gfa_EQ3NWWsj~Ru#!kNcc)8zdS^w ztgLKqZca%_iL$@uuhTe%`COeX5*@D%jGFx22ZZ>HfrUl*SX3kM5%{kQMS&ha-d$g> zc9<0{vNZU6vckP{4PH(kgYm$xIsX`f0MV}Yj7dG3Mk0iew$W)>;q!=&hDHuDlL-n~ zi8%}^CPsCo+u-Tu-w%Vq&abYzfZW{C!3c#)a{_t8P80CGd5&BbI%IbQa~KeU1(8<` zj*tFm6##eNn|Wp9tKUnL+|$?BrsgQ@jxuRxP~tWS`EyEipf6|3lsg-#LT@@rAE;k! zZM_brC5ZbI7fW0_8-S`n`4^@NmtRzD`zw15o|vb%w|I7WO%28UuLqw^|Axy<@M8%< z!EqY_h_sWG+W832U)A>@?FHupa^8$0f8(v)P$OFH7uCXH417lZltQ!NJ`Ew_|0|+A z`Wj`xZ7qvJ5vGSY6!dl^0KP^MFh0kp@`sQ?7dy+ksg5r(J0ERpBLht*XiP;@u=lu8 z(WG2B1aj)>6F&<~`5CK?wKZP@1w5ccab$ky=lqe4;K0L`J2pGHObkN)qlq?gBn-~O z{CmdqS*Jd0uTb;yNHzQ+v-KY3(Xe8jd)*J(x5HuZ;d?VmRWp^+7r@S<3qW6F>FpDLOcbw zK4AmBaH$C(oAe!%@1S4=Tq;T)@+YK3LH=osb&)*z3&F24CQF~ ze*HRThb}G5&#xI?wxqzD_lS>uCzD3Mi!KU?5-AO!q^Rni7fZT+G?o!CmxFezmIvk= zi5pKl;sfiHl{1{~GM&js1_ZD~n*MmMKaYn&e#{JJ#(P_nh*ioId0gPx6t1{A1O@>+)Dg z1qfL>#5JawxvEVhIFbPG9k*JEPA<7_dZ>?pH|LixH|myUpg@8nG4R1#NBrfPSkS}M*PQwlKCDlob3W`P^A&uI&Z58l2~chblqE8PM1dnXPcT#MNVG6OGTa{5n8;Z5Q+Pvo7et|$Bmecw0C zW%cKxES2QXX22eabB?4ZHFXIG_n!7p9Urvi1#sp02 zgKnsFmdUOXI=$=^xbMwD93hsf(68}B_A%*+JEymypZ6{IlPkhdAWk(!D0paMZ-@3B z2kP#ejBVt#e1L%vyUo@ncOzg!$QW@?%j&*2pAYN4X0#SN=tV8l&GM_EVpVr7iY@sc2dKuHb6TsTJtu3o)F4u7lONsWt~`B_`y@Q4?4t0~9jaT(gWKs5 z87y1I^@i01_2sHz&7cEkP8rC?|685^KtB6iXaYwTL<;Ij-uLZpST+5Llcfm!0#v@9 zl_K+*r(Q%O0IL{FW#%A&@TnmHw!&CSxdvzuxwpGwSxL#6sjeARxGFG|h8w?EWMQ z3SYTKjMgg?#=wPpg;u;PEjah>i{Kof262inw^au9-H0H4=~T==G<_}tSEc5PD+Q0R9fcV43$ji8Y&?Pt7wkIT~s`_Yt zC;lZgQ;M8Wv$@K>ra_6*UXg6}F1yq3ot@W^fJ-Hc4b;M|4N^5#jr%te_d` zp!awB(1p=3!!zGEl$tZ89ZAOl~cSP=;>K}3p2<&8bv3Y z#`So!-TWP%b|XKdnl36YFYi?M5{b6%l~u__G}ZDQj>~mdRU6o!Cc@9dGi>p*S8B{~ zBY3=4+6LsG!dBkziM#84bK&G3_l(^aO=yY6*cKH+UV%9HC%{%5hFn1^a+)m`NH z6Wj4mYrXO8n$Q2tope@hJwT!6oBWz;2B#`*38ppz623^e3{Ltu4QH-8IrK(QD&$deGutFw^y`OpzTo-YGw?rp7Shh0U)s%*HM+5 z%TslUKWcvdod#eRxZ%Lz5NW_+giGB|^=M)$bNb~kM!oN6eH&VbBd@L?_n%9geq20aSeTm9 z!!HINQB+dC^)(MaS5%Nbu^!4Oa;P;c1Dhe~X7%blc*(5?mYT+jkz6*JQ=`^gXGFoBp>yc*4W zo+){}K2$9{K{*pqYiNQ!e*$$G?H#YV&E-{;UlLYM;5a-xQ+@jMC9k1VIT(0;e0}Th zU#M?FO^7LAElVT!!`mzt zHq-Fp6CVC?As$J};;JP!zMbFQO<->yI7NF|u&j*bN0AQi`1G{xudhyPg$DdWRCb2~ zqQ$@pVsG~Z1e&ZZqPrl#RNZ zTV8o7J{hF&Qh698ICx;QZ z5T&P2*;rX+Qi-hjB(&p8z#rWFP4%H+@gF`gXL>oDC-G|Y4~26_QA^!YS{Rp>nFpGg zD>|j>7*v#LdU)LZ{CN@9nrK8hT4p}YsxI5x%f*R{wYn1}cG+;ODvbMrR8Xj-`OF(N ziylS&j=JtcIF*F+O0HN|WI~vb-)?1TY3V{+D6Q1HqfOm%Ohv_cGhgg30_Nm~U(G41 zKuHB8HD6y}CnsK85@RLYmF-|NLlYem1Vu!iv7bbAk!(o0-(4;%A;gqHbyWWvYm%(zaQQiX zbk|HG=Tb3b<)o&e{-71UrkFz`e6TK_s$WqRU-_b{MrU3e=f^geFDQVu_fHd2q-eKS zPq_w@85*JZ#3Sab&*dg{|HuBft2KXH7K@`~2JX@jr-vQ2&818r|6;=%Vn~vHxh6$< zrpMA+b8}w491FIbuvIP4wZpmJ&Z#&3v|yndva^<2(hKx0MIt+20e!WVv~hRKB1VHi zTiZmSch%gVV<=`!?K)lcYOT(BCWXc^H(w6AG*tef1P#$HLb{FCmJRRDd6Krmsb3Yw z&$X8l3r~|PLRK=qNmItbwc9Qwludto9>5h(ga5dK2Dp4XfE|EP+^ zMHM1sAeGZ+`41ia;Xm{&pfxZE$b!B5kNtsK=%0mT#dOG(%*@RE@k_y*Y(%CHzMsmL z{ZmF+$opf*)q!#U)I9ZYpc4?J#?Qs&@cX+Zc9^h|lB#NgSnJAOFq$D<1v)o~_sB=5 zdn(joMLN%j<@W;CgN%j-+j+wk9 Date: Tue, 15 Feb 2022 20:36:03 +0100 Subject: [PATCH 07/18] Added class diagram layout hints --- .../plantuml/class_diagram_generator.cc | 27 ++++++++++ .../plantuml/class_diagram_generator.h | 2 + tests/t00035/.clang-uml | 18 +++++++ tests/t00035/t00035.cc | 15 ++++++ tests/t00035/test_case.h | 52 +++++++++++++++++++ tests/test_cases.cc | 1 + 6 files changed, 115 insertions(+) create mode 100644 tests/t00035/.clang-uml create mode 100644 tests/t00035/t00035.cc create mode 100644 tests/t00035/test_case.h diff --git a/src/class_diagram/generators/plantuml/class_diagram_generator.cc b/src/class_diagram/generators/plantuml/class_diagram_generator.cc index 69e911ae..965939a5 100644 --- a/src/class_diagram/generators/plantuml/class_diagram_generator.cc +++ b/src/class_diagram/generators/plantuml/class_diagram_generator.cc @@ -348,6 +348,31 @@ void generator::generate(const enum_ &e, std::ostream &ostr) const } } +void generator::generate_config_layout_hints(std::ostream &ostr) const +{ + const auto &uns = m_config.using_namespace(); + + // Generate layout hints + for (const auto &[entity, hints] : m_config.layout()) { + for (const auto &hint : hints) { + std::stringstream hint_str; + try { + hint_str << m_model.to_alias(ns_relative(uns, entity)) + << " -[hidden]" + << clanguml::config::to_string(hint.hint) << "- " + << m_model.to_alias(ns_relative(uns, hint.entity)) + << '\n'; + ostr << hint_str.str(); + } + catch (error::uml_alias_missing &e) { + LOG_ERROR("=== Skipping layout hint from {} to {} due " + "to: {}", + entity, hint.entity, e.what()); + } + } + } +} + void generator::generate(std::ostream &ostr) const { ostr << "@startuml" << '\n'; @@ -393,6 +418,8 @@ void generator::generate(std::ostream &ostr) const ostr << '\n'; } + generate_config_layout_hints(ostr); + // Process aliases in any of the puml directives for (const auto &b : m_config.puml().after) { std::string note{b}; diff --git a/src/class_diagram/generators/plantuml/class_diagram_generator.h b/src/class_diagram/generators/plantuml/class_diagram_generator.h index 2f8388c0..eb48897c 100644 --- a/src/class_diagram/generators/plantuml/class_diagram_generator.h +++ b/src/class_diagram/generators/plantuml/class_diagram_generator.h @@ -64,6 +64,8 @@ public: void generate_alias(const enum_ &e, std::ostream &ostr) const; + void generate_config_layout_hints(std::ostream &ostr) const; + void generate(const class_ &c, std::ostream &ostr) const; void generate(const enum_ &e, std::ostream &ostr) const; diff --git a/tests/t00035/.clang-uml b/tests/t00035/.clang-uml new file mode 100644 index 00000000..e2ab858d --- /dev/null +++ b/tests/t00035/.clang-uml @@ -0,0 +1,18 @@ +compilation_database_dir: .. +output_directory: puml +diagrams: + t00035_class: + type: class + glob: + - ../../tests/t00035/t00035.cc + using_namespace: + - clanguml::t00035 + include: + namespaces: + - clanguml::t00035 + layout: + Center: + - up: Top + - down: Bottom + - left: Left + - right: Right diff --git a/tests/t00035/t00035.cc b/tests/t00035/t00035.cc new file mode 100644 index 00000000..12bb4ca6 --- /dev/null +++ b/tests/t00035/t00035.cc @@ -0,0 +1,15 @@ +namespace clanguml { +namespace t00035 { + +struct Top {}; + +struct Left {}; + +struct Center {}; + +struct Bottom {}; + +struct Right {}; + +} // namespace t00035 +} // namespace clanguml diff --git a/tests/t00035/test_case.h b/tests/t00035/test_case.h new file mode 100644 index 00000000..7cbf4163 --- /dev/null +++ b/tests/t00035/test_case.h @@ -0,0 +1,52 @@ +/** + * tests/t00035/test_case.cc + * + * Copyright (c) 2021-2022 Bartek Kryza + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +TEST_CASE("t00035", "[test-case][class]") +{ + auto [config, db] = load_config("t00035"); + + auto diagram = config.diagrams["t00035_class"]; + + REQUIRE(diagram->name == "t00035_class"); + + REQUIRE(diagram->should_include("clanguml::t00035::A")); + + auto model = generate_class_diagram(db, diagram); + + REQUIRE(model.name() == "t00035_class"); + + auto puml = generate_class_puml(diagram, model); + AliasMatcher _A(puml); + + REQUIRE_THAT(puml, StartsWith("@startuml")); + REQUIRE_THAT(puml, EndsWith("@enduml\n")); + + REQUIRE_THAT(puml, IsClass(_A("Top"))); + REQUIRE_THAT(puml, IsClass(_A("Bottom"))); + REQUIRE_THAT(puml, IsClass(_A("Center"))); + REQUIRE_THAT(puml, IsClass(_A("Left"))); + REQUIRE_THAT(puml, IsClass(_A("Right"))); + + REQUIRE_THAT(puml, IsLayoutHint(_A("Center"), "up", _A("Top"))); + REQUIRE_THAT(puml, IsLayoutHint(_A("Center"), "left", _A("Left"))); + REQUIRE_THAT(puml, IsLayoutHint(_A("Center"), "right", _A("Right"))); + REQUIRE_THAT(puml, IsLayoutHint(_A("Center"), "down", _A("Bottom"))); + + save_puml( + "./" + config.output_directory() + "/" + diagram->name + ".puml", puml); +} diff --git a/tests/test_cases.cc b/tests/test_cases.cc index e721378d..8e42aff2 100644 --- a/tests/test_cases.cc +++ b/tests/test_cases.cc @@ -166,6 +166,7 @@ using namespace clanguml::test::matchers; #include "t00032/test_case.h" #include "t00033/test_case.h" #include "t00034/test_case.h" +#include "t00035/test_case.h" // // Sequence diagram tests From 3bf313df61de9fd1d6005a15dfbefc42b4aaae90 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Tue, 15 Feb 2022 20:38:42 +0100 Subject: [PATCH 08/18] Updated test cases documentation --- docs/test_cases.md | 1 + docs/test_cases/t30001_package.png | Bin 10096 -> 10096 bytes docs/test_cases/t30002_package.png | Bin 33387 -> 33388 bytes docs/test_cases/t30003_package.png | Bin 12028 -> 12030 bytes docs/test_cases/t30004_package.png | Bin 14214 -> 14212 bytes docs/test_cases/t30005_package.png | Bin 12511 -> 12512 bytes docs/test_cases/t30006_package.png | Bin 7197 -> 7197 bytes docs/test_cases/t30007_package.png | Bin 9126 -> 9126 bytes tests/test_cases.yaml | 3 +++ 9 files changed, 4 insertions(+) diff --git a/docs/test_cases.md b/docs/test_cases.md index 2b5459d5..4f2b88f4 100644 --- a/docs/test_cases.md +++ b/docs/test_cases.md @@ -33,6 +33,7 @@ * [t00032](./test_cases/t00032.md) - Class template with template base classes test case * [t00033](./test_cases/t00033.md) - Nested template instantiation dependency test case * [t00034](./test_cases/t00034.md) - Template metaprogramming type function test case + * [t00035](./test_cases/t00035.md) - PlantUML class diagram layout hints test case ## Sequence diagrams * [t20001](./test_cases/t20001.md) - Basic sequence diagram test case * [t20002](./test_cases/t20002.md) - Free function sequence diagram test case diff --git a/docs/test_cases/t30001_package.png b/docs/test_cases/t30001_package.png index ccd8830e7d600793244d5784f3fec04c407411f5..18ed09a81865b7f897e99fa7884eedf3e21c335c 100644 GIT binary patch delta 334 zcmV-U0kQt@PVi2Ue19!TJ$1R#svEeL$voVQF`~vUtW70NWHR>Om+FSKUTAU=$ouf- z;Y%;qOlgxQHMC``PZo1{?Y{xbVepQRtKB8=U5+nuuaaK?%>wu-F+mVinbse3j#a7l zi7IndtaHVC$L0F)H)xVD zspnA$JFaq(Ng%F=J?vtyJ~a{|rT`NlgnAyuT^NjJP~;6%f1HGnXGX0!tVOPsSQ>2$ z8feUR3|@@XBIOjGw_J{gPyZJ%k~^U?nR2PocoCg|PRj{|hACH81s2h8$C zY2NwHd}*tUgF?;Ww7$e87}*-dw2(1O_qpaNg-}TIg@$~?Orq_(t88s!3iH{6z>% delta 334 zcmV-U0kQt@PVi2Ue1C?d9+xYvx`At%%)`wXBWmoz+Emg+CS(77scu;7g(eq)ybo_4 zzVtG~wXsQDL0i812Y88ZB1ED}E^E^g6Fc{4s&uggqI0+z2tzHRO%gkuGw8jE-<6v%CScCAxs3=Kufz diff --git a/docs/test_cases/t30002_package.png b/docs/test_cases/t30002_package.png index ce3d6e66d1e3f695d324ff80223bda5eb884a0e1..c8f91d6f206a9759c17bfa27289647824206e379 100644 GIT binary patch delta 440 zcmV;p0Z0DpgaYh@0+3mMo@rEAbZ~58Zgh2RYybfO004NLeUw{k!Y~+y?*sma@6s_W zNwkObVr)7$aFxkC+>9|Y&7@3INfVij{r5#hrU|4J3Voiw`FIn0TWhYgS+5#s!{=Xo zDd6?)4R{T`cYM6!jKI%1_Bg%d#O3Wh|252~Fjpa-La^&l-*Nk8e!s*mnE3@0w_$c__;{bWUDr%5cD(EH)Zw0xIZHLr z1&pGbivtwKoiL8WI0@r4j9Cyf9L6LZo`t`rVH|FagvQ|R?4u;*8(`8X<|u8f)sSd_I^<%iKW;0g`+ zmcxsYx?GDKo;N}c?w?LCpf9(js^nTojRv#fzmRlV-BQC?C_4(whR2-Qaje{q5aEcl zud~+l!$z4FHixI3mqY|38>6@`YP-S_Gf-tlH0c?OXx7CvX delta 438 zcmV;n0ZIPsgaYe?0+3mMooQ59bZ~58Zgh2RYybfO004NLeUx2m!Y~wu?*smabLkkC zB-%FiVmRFgxXNTsZ^jr=Gbw9RNfX%^`|pd&m?n@?DD-*y=I|zT&}go-smd1G^3@05 z2za@E1>V5u4Ii&KCGdTUJxx=QRRJy%J8JSBFO)Kd~yVV;t@ zO5anMqcH3#eODo#La^&l-*Nk8e!s*mnE3@0w_*0z@bNxzhpw5N?fB5+slz>iIZL(B z8H}QD6Yx~N13k6R(fHxGX=;8yMmRm)09jmC?~zmW7g!$QMMC_4%)CdZt`ajeXa5aEb) zFIi{4v{9ym&EaY1B@w~M#we}}xq;bNqeYcLUP$waZp1q&H>I}guIjbL8O)#WIt=Ap gZj3#~8Ei{5s%@0|%3zwKU)(}aInS8{a{D{H=7iChs9Wv+l?pZEk5zrC^w zLaxD0N-6VwMs8p_U&FE9LGAlx0A+4vGw7fNuQ)teWn?B8JQhMNW)D9f zFjtk-xypnxXk@VsFF?QN-AV&1pl^2ZD>K-v@4NvDxY}E{QU*nern$4y2L{UkeF5lx OtLG|S11Yn)0Yfc@L#k>3 delta 366 zcmV-!0g?XxUHn~;S$|h)R9JLyY+-J6b!}__0RR91c$|HZT}#6-6o&5u`w!=GLt2t< z>KeuvZc~^o4)<{*QnEIVV4IeF6h-{+W}7lv#SjRb^StkQb0*p_Wo(gmP{q<$w&(C9 zHF*Z6VVdC6xg3V@(Ex&^CJ9b(iwp6A`)s2)34fymMx%^Zihrlf@N7K(R=V4e_uIPQ z58Xe}!+tw@8yK7?ABT5Pqv`wO#t#p`gv;!>GqlW^G@Cernky|z3B(U@fPEZvS5`vI z6kq~`&>*1r8m99#9Qr-fy<0}0ORG{2nb1awoi)y&hZd}6@MxtG1*h;(ak-e?{}f;@ zYoSV6aB0wD8)BbIPx==_Z?kh&*2DJry1c|E7&#lo zjF5X+y=%h@3XzcZ4bAuqv$=6|(=u~y3Y+z0~ zgMg7Qfj3I0Jiu?QXq!{tkXld5L1#a){Y#Z)*-k}$#B5~_CrCt)=fjwG))gildrosRN3yGO)F_|KFMLDT&t}C5k@@XA&<^y-oQjU z-~xn*qbR0TB-uT5{R@9~{&ku|YrR`3D0GWXFFg|Af{o=y!kss$YZb%yMwxN??X3Wr z*=T1?tqij9V)8ENf9{Pm!b~}e0*lFxv)ILoDMH9YartS`n=c9Fd)#kd$}2*_8DX46 zZAzHEw5aMBa&7!GOVy+F71G?5EvOyC{QkB#V7WASplq(S|opDZ%s1wrHSngGKYnx$sWcSN_^{z*piX2Ld)29pPaO7 z{tPBPNZfnQ?;g0fElEqRt^(G`^+uKm-$y?{wvhbf`*Z#A8ZJtUsNvV4YILUScY@ym z(}oaMhRD=l9*z_No4o+MKMWY^0y_Btcsw4Tf(M6StI9_@;SS!o-u{1YZjvOY+~I!% z4+G|X3A|D|{oCDWYyM!xlk7CQTx?Qg0q%Z^j^Ifsiz>CH{0GzyEw?h~#|RooCh zQCB+5eLCC&0`?7|-KeJV(lkwvMtfg(Z+&IAcQ&h}ro}XeE!tKY4N(~Ln1?*RoI4Fu zX@N%&MIw#`A3&1bL)U-5Vwaz1Ikd*vHA10UvTEhX1FqOaZYA6~O{zu#UmMhu^vi1j zGQCyS=o&S#$#VK8=zr*q6~P>>j{?i-p0nJ?5s%%5ArT0pL}dtxa*NLP`cyEcVy3s~HL>J3>gb?N*T1T+&BON>X^X92UE{Q+q9 O=#BZFNQ1Ks0(doP7|%`s diff --git a/docs/test_cases/t30005_package.png b/docs/test_cases/t30005_package.png index b10a0efdf7e53fd4510ab99c6f9bb496db9c04c4..b97d27f1ffde5d2fff5ce1501f54cfdaeb803118 100644 GIT binary patch delta 309 zcmV-50m}a0Vc=nqSpiXzS|UT1Bs%SKF`U&6T+3vB+>9}zW)jw>k|r`4`|pd2%%)o? z1o}LE&&z4QG+Y~-XAQLFs}H^r@N)MGyoC4-pH7!h__~q57=J?VzfrMoMwO_z#&10C z3lw{!8mQ7E3~wtts0!}uzl6R}>*L=*lZ-1fPZQV)UCKfM2`Q#H#I!lJ3R12C6Ci|9 z%5V?j(F_i}g_;kO1j@qdm4LM@jh0JmTtEwr`HsW0RYvB5!P8c#@$m8d0!C^lb)j;h z3>q)eU!mIx23^v?RA^TP7U?NxajL~!g%F3NeH8`srHirww#VD`B_YAc#b|D%+Q4*Q z8j&+dq_UrADBiivjGMbE)($h6&+dZ=C0uQ++c|@6hT_6S={bqkG1)`Pe delta 308 zcmV-40n7g2Vc%hpSpiUyS|US+q&nwvF`U&6T+7P*xEW(a%_OW%B~4@^`|pd2%%)o? z1o}LE&&z4QG+Y~-XAQLB%TK-*@Ou9SyoBhToKBa7u)mSN7=Oaef1@Jb>{X(o8o%|p zFHqu*YM@FFjPEKts0!}uzl6R}tK;85X~vbAB{6J;E@h#B;*f*{ldw6l3KFh?P@t5B zA#>BB(G(86g_@6P3}s>UQou@B>KhUadVf&%3%hx=|j*%F;{ErcFtgvp{Q_CddDD*(GQaxyI<)qgx|BX G0WB|6;+p0F diff --git a/docs/test_cases/t30006_package.png b/docs/test_cases/t30006_package.png index 21376db726d460bf1891aaa795109ff0753de98f..51f2e6ee937f153a5530c43ac32a89914987c350 100644 GIT binary patch delta 344 zcmV-e0jK_*IGs3# zO8=N@+S zXyYU}Q-WEa$Pt=`Vh{E@j*!%=!}Hj%FwU9ccTc~r|Izk?C4V_*X?^iV=mZht>yv-| zFSqK1ZWwx45E|z~yIGdPR@zD#4HPrN2qvsC@ftE=fl#27GsejkB*Q7}^(JcEj#H?N zw@V2tRXM8`-i3fB8i}od2d|wfB!~M_>e1ltvj9WARo3W2YKKPi?Ay@3jQh&LMB0D? z^Q_L9*H}CtU`&E(>!K6S79q;V#2@a!OED!V#8}~!-oRv6IazQ>mG-Y_AlJg@F3eq; qRggK%rZ;g1r9y9f*fobTM~MkhcE@3yq7PDTq9~OJo=vm40c0A^@u<}R delta 344 zcmV-e0jK_*IGs3az6?p(9U%v2-z{ma*@(Pn@QlB=Z_!hu>06#pvb5DHq zC~XB=U7}u}$N@}!v4?v-3P7mU;dyLWXlr%xyQg2*|7iQcl7F1Dw7z%)I6;h}>yv-| zFSqK1t{-|>5R7xK>?})hD@-M|LK?*+CJ~7n6Q?la1_?z!dV~Cgc09zd~nLjLNL59g&Ga+J_|ThTWPc^gt9Q2XWxeQW!RS%C&G9X zoM&~;yvAZ4Axt6>ZC!N2*}_M;khsI`d1*um_!z^jR2!V^Dk} Date: Tue, 15 Feb 2022 23:37:22 +0100 Subject: [PATCH 09/18] Added t00035 docs --- docs/test_cases/t00035.md | 45 +++++++++++++++++++++++++++++++ docs/test_cases/t00035_class.png | Bin 0 -> 7327 bytes 2 files changed, 45 insertions(+) create mode 100644 docs/test_cases/t00035.md create mode 100644 docs/test_cases/t00035_class.png diff --git a/docs/test_cases/t00035.md b/docs/test_cases/t00035.md new file mode 100644 index 00000000..9d12ac48 --- /dev/null +++ b/docs/test_cases/t00035.md @@ -0,0 +1,45 @@ +# t00035 - PlantUML class diagram layout hints test case +## Config +```yaml +compilation_database_dir: .. +output_directory: puml +diagrams: + t00035_class: + type: class + glob: + - ../../tests/t00035/t00035.cc + using_namespace: + - clanguml::t00035 + include: + namespaces: + - clanguml::t00035 + layout: + Center: + - up: Top + - down: Bottom + - left: Left + - right: Right + +``` +## Source code +File t00035.cc +```cpp +namespace clanguml { +namespace t00035 { + +struct Top {}; + +struct Left {}; + +struct Center {}; + +struct Bottom {}; + +struct Right {}; + +} // namespace t00035 +} // namespace clanguml + +``` +## Generated UML diagrams +![t00035_class](./t00035_class.png "PlantUML class diagram layout hints test case") diff --git a/docs/test_cases/t00035_class.png b/docs/test_cases/t00035_class.png new file mode 100644 index 0000000000000000000000000000000000000000..3acf67b191c7f21cad13ce5571f3b6e90442bdc1 GIT binary patch literal 7327 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 mKfg!f9RZ5^Ur4-lCAC?o&!O2a2H; Date: Tue, 15 Feb 2022 23:37:47 +0100 Subject: [PATCH 10/18] Refactored class_diagram generator to common base class template --- .../plantuml/class_diagram_generator.cc | 181 +++--------------- .../plantuml/class_diagram_generator.h | 28 +-- src/common/generators/plantuml/generator.cc | 59 ++++++ src/common/generators/plantuml/generator.h | 120 ++++++++++++ src/common/model/enums.cc | 81 ++++++++ src/common/model/enums.h | 7 + src/common/model/relationship.cc | 28 --- src/common/model/relationship.h | 2 - tests/t00035/t00035.cc | 15 +- 9 files changed, 316 insertions(+), 205 deletions(-) create mode 100644 src/common/generators/plantuml/generator.cc create mode 100644 src/common/generators/plantuml/generator.h create mode 100644 src/common/model/enums.cc diff --git a/src/class_diagram/generators/plantuml/class_diagram_generator.cc b/src/class_diagram/generators/plantuml/class_diagram_generator.cc index 965939a5..4071dc99 100644 --- a/src/class_diagram/generators/plantuml/class_diagram_generator.cc +++ b/src/class_diagram/generators/plantuml/class_diagram_generator.cc @@ -22,81 +22,12 @@ namespace clanguml::class_diagram::generators::plantuml { -std::string relative_to(std::string n, std::string c) -{ - if (c.rfind(n) == std::string::npos) - return c; - - return c.substr(n.size() + 2); -} - generator::generator( clanguml::config::class_diagram &config, diagram_model &model) - : m_config(config) - , m_model(model) + : common_generator{config, model} { } -std::string generator::to_string(scope_t scope) const -{ - switch (scope) { - case scope_t::kPublic: - return "+"; - case scope_t::kProtected: - return "#"; - case scope_t::kPrivate: - return "-"; - default: - return ""; - } -} - -std::string generator::to_string(relationship_t r, std::string style) const -{ - switch (r) { - case relationship_t::kOwnership: - case relationship_t::kComposition: - return style.empty() ? "*--" : fmt::format("*-[{}]-", style); - case relationship_t::kAggregation: - return style.empty() ? "o--" : fmt::format("o-[{}]-", style); - case relationship_t::kContainment: - return style.empty() ? "--+" : fmt::format("-[{}]-+", style); - case relationship_t::kAssociation: - return style.empty() ? "-->" : fmt::format("-[{}]->", style); - case relationship_t::kInstantiation: - return style.empty() ? "..|>" : fmt::format(".[{}].|>", style); - case relationship_t::kFriendship: - return style.empty() ? "<.." : fmt::format("<.[{}].", style); - case relationship_t::kDependency: - return style.empty() ? "..>" : fmt::format(".[{}].>", style); - default: - return ""; - } -} - -std::string generator::name(relationship_t r) const -{ - switch (r) { - case relationship_t::kOwnership: - case relationship_t::kComposition: - return "composition"; - case relationship_t::kAggregation: - return "aggregation"; - case relationship_t::kContainment: - return "containment"; - case relationship_t::kAssociation: - return "association"; - case relationship_t::kInstantiation: - return "instantiation"; - case relationship_t::kFriendship: - return "friendship"; - case relationship_t::kDependency: - return "dependency"; - default: - return "unknown"; - } -} - void generator::generate_alias(const class_ &c, std::ostream &ostr) const { std::string class_type{"class"}; @@ -118,6 +49,7 @@ void generator::generate_alias(const enum_ &e, std::ostream &ostr) const void generator::generate(const class_ &c, std::ostream &ostr) const { + namespace plantuml_common = clanguml::common::generators::plantuml; const auto &uns = m_config.using_namespace(); @@ -147,7 +79,7 @@ void generator::generate(const class_ &c, std::ostream &ostr) const std::string type{m.type()}; - ostr << to_string(m.scope()) << m.name(); + ostr << plantuml_common::to_plantuml(m.scope()) << m.name(); ostr << "("; if (m_config.generate_method_arguments() != @@ -190,10 +122,12 @@ void generator::generate(const class_ &c, std::ostream &ostr) const std::stringstream all_relations_str; std::set unique_relations; for (const auto &r : c.relationships()) { - if (!m_config.should_include_relationship(name(r.type()))) + if (!m_config.should_include_relationship( + common::model::to_string(r.type()))) continue; - LOG_DBG("== Processing relationship {}", to_string(r.type())); + LOG_DBG("== Processing relationship {}", + plantuml_common::to_plantuml(r.type(), r.style())); std::stringstream relstr; std::string destination; @@ -206,7 +140,7 @@ void generator::generate(const class_ &c, std::ostream &ostr) const if (!r.multiplicity_source().empty()) puml_relation += "\"" + r.multiplicity_source() + "\" "; - puml_relation += to_string(r.type(), r.style()); + puml_relation += plantuml_common::to_plantuml(r.type(), r.style()); if (!r.multiplicity_destination().empty()) puml_relation += " \"" + r.multiplicity_destination() + "\""; @@ -216,7 +150,8 @@ void generator::generate(const class_ &c, std::ostream &ostr) const << m_model.to_alias(ns_relative(uns, destination)); if (!r.label().empty()) { - relstr << " : " << to_string(r.scope()) << r.label(); + relstr << " : " << plantuml_common::to_plantuml(r.scope()) + << r.label(); rendered_relations.emplace(r.label()); } @@ -233,7 +168,8 @@ void generator::generate(const class_ &c, std::ostream &ostr) const catch (error::uml_alias_missing &e) { LOG_ERROR("=== Skipping {} relation from {} to {} due " "to: {}", - to_string(r.type()), c.full_name(), destination, e.what()); + plantuml_common::to_plantuml(r.type(), r.style()), + c.full_name(), destination, e.what()); } } @@ -251,13 +187,13 @@ void generator::generate(const class_ &c, std::ostream &ostr) const if (m.is_static()) ostr << "{static} "; - ostr << to_string(m.scope()) << m.name() << " : " + ostr << plantuml_common::to_plantuml(m.scope()) << m.name() << " : " << ns_relative(uns, m.type()) << '\n'; } ostr << "}" << '\n'; - if (m_config.should_include_relationship("inheritance")) + if (m_config.should_include_relationship("inheritance")) { for (const auto &b : c.parents()) { std::stringstream relstr; try { @@ -273,19 +209,10 @@ void generator::generate(const class_ &c, std::ostream &ostr) const b.name(), c.name(), e.what()); } } - - // - // Process notes - // - for (auto decorator : c.decorators()) { - auto note = std::dynamic_pointer_cast(decorator); - if (note && note->applies_to_diagram(m_config.name)) { - ostr << "note " << note->position << " of " << c.alias() << '\n' - << note->text << '\n' - << "end note\n"; - } } + generate_notes(ostr, c); + // Print relationships ostr << all_relations_str.str(); } @@ -306,18 +233,21 @@ void generator::generate(const enum_ &e, std::ostream &ostr) const ostr << "}" << '\n'; for (const auto &r : e.relationships()) { - if (!m_config.should_include_relationship(name(r.type()))) + if (!m_config.should_include_relationship( + common::model::to_string(r.type()))) continue; std::string destination; std::stringstream relstr; try { - destination = r.destination(); relstr << m_model.to_alias( ns_relative(m_config.using_namespace(), e.name())) - << " " << to_string(r.type()) << " " + << " " + << clanguml::common::generators::plantuml::to_plantuml( + r.type(), r.style()) + << " " << m_model.to_alias( ns_relative(m_config.using_namespace(), destination)); @@ -331,63 +261,20 @@ void generator::generate(const enum_ &e, std::ostream &ostr) const catch (error::uml_alias_missing &ex) { LOG_ERROR("Skipping {} relation from {} to {} due " "to: {}", - to_string(r.type()), e.full_name(), destination, ex.what()); + clanguml::common::generators::plantuml::to_plantuml( + r.type(), r.style()), + e.full_name(), destination, ex.what()); } } - // - // Process notes - // - for (auto decorator : e.decorators()) { - auto note = std::dynamic_pointer_cast(decorator); - if (note && note->applies_to_diagram(m_config.name)) { - ostr << "note " << note->position << " of " << e.alias() << '\n' - << note->text << '\n' - << "end note\n"; - } - } -} - -void generator::generate_config_layout_hints(std::ostream &ostr) const -{ - const auto &uns = m_config.using_namespace(); - - // Generate layout hints - for (const auto &[entity, hints] : m_config.layout()) { - for (const auto &hint : hints) { - std::stringstream hint_str; - try { - hint_str << m_model.to_alias(ns_relative(uns, entity)) - << " -[hidden]" - << clanguml::config::to_string(hint.hint) << "- " - << m_model.to_alias(ns_relative(uns, hint.entity)) - << '\n'; - ostr << hint_str.str(); - } - catch (error::uml_alias_missing &e) { - LOG_ERROR("=== Skipping layout hint from {} to {} due " - "to: {}", - entity, hint.entity, e.what()); - } - } - } + generate_notes(ostr, e); } void generator::generate(std::ostream &ostr) const { ostr << "@startuml" << '\n'; - for (const auto &b : m_config.puml().before) { - std::string note{b}; - std::tuple alias_match; - while (util::find_element_alias(note, alias_match)) { - auto alias = m_model.to_alias(ns_relative( - m_config.using_namespace(), std::get<0>(alias_match))); - note.replace( - std::get<1>(alias_match), std::get<2>(alias_match), alias); - } - ostr << note << '\n'; - } + generate_plantuml_directives(ostr, m_config.puml().before); if (m_config.should_include_entities("classes")) { for (const auto &c : m_model.classes()) { @@ -420,21 +307,11 @@ void generator::generate(std::ostream &ostr) const generate_config_layout_hints(ostr); - // Process aliases in any of the puml directives - for (const auto &b : m_config.puml().after) { - std::string note{b}; - std::tuple alias_match; - while (util::find_element_alias(note, alias_match)) { - auto alias = m_model.to_alias(ns_relative( - m_config.using_namespace(), std::get<0>(alias_match))); - note.replace( - std::get<1>(alias_match), std::get<2>(alias_match), alias); - } - ostr << note << '\n'; - } + generate_plantuml_directives(ostr, m_config.puml().after); ostr << "@enduml" << '\n'; } + std::ostream &operator<<(std::ostream &os, const generator &g) { g.generate(os); diff --git a/src/class_diagram/generators/plantuml/class_diagram_generator.h b/src/class_diagram/generators/plantuml/class_diagram_generator.h index eb48897c..148a50af 100644 --- a/src/class_diagram/generators/plantuml/class_diagram_generator.h +++ b/src/class_diagram/generators/plantuml/class_diagram_generator.h @@ -21,6 +21,7 @@ #include "class_diagram/model/diagram.h" #include "class_diagram/model/enum.h" #include "class_diagram/visitor/translation_unit_visitor.h" +#include "common/generators/plantuml/generator.h" #include "common/model/relationship.h" #include "config/config.h" #include "cx/compilation_database.h" @@ -40,43 +41,34 @@ namespace class_diagram { namespace generators { namespace plantuml { -using diagram_config = clanguml::class_diagram::model::diagram; +using diagram_config = clanguml::config::class_diagram; using diagram_model = clanguml::class_diagram::model::diagram; +template +using common_generator = + clanguml::common::generators::plantuml::generator; + using clanguml::class_diagram::model::class_; using clanguml::class_diagram::model::enum_; using clanguml::common::model::relationship_t; using clanguml::common::model::scope_t; + using namespace clanguml::util; -std::string relative_to(std::string n, std::string c); - -class generator { +class generator : public common_generator { public: - generator(clanguml::config::class_diagram &config, diagram_model &model); - - std::string to_string(scope_t scope) const; - - std::string to_string(relationship_t r, std::string style = "") const; - - std::string name(relationship_t r) const; + generator(diagram_config &config, diagram_model &model); void generate_alias(const class_ &c, std::ostream &ostr) const; void generate_alias(const enum_ &e, std::ostream &ostr) const; - void generate_config_layout_hints(std::ostream &ostr) const; - void generate(const class_ &c, std::ostream &ostr) const; void generate(const enum_ &e, std::ostream &ostr) const; - void generate(std::ostream &ostr) const; + void generate(std::ostream &ostr) const override; friend std::ostream &operator<<(std::ostream &os, const generator &g); - -private: - clanguml::config::class_diagram &m_config; - diagram_model &m_model; }; clanguml::class_diagram::model::diagram generate( diff --git a/src/common/generators/plantuml/generator.cc b/src/common/generators/plantuml/generator.cc new file mode 100644 index 00000000..8cc60542 --- /dev/null +++ b/src/common/generators/plantuml/generator.cc @@ -0,0 +1,59 @@ +/** + * src/common/generators/plantuml/generator.h + * + * Copyright (c) 2021-2022 Bartek Kryza + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "generator.h" + +namespace clanguml::common::generators::plantuml { + +std::string to_plantuml(relationship_t r, std::string style) +{ + switch (r) { + case relationship_t::kOwnership: + case relationship_t::kComposition: + return style.empty() ? "*--" : fmt::format("*-[{}]-", style); + case relationship_t::kAggregation: + return style.empty() ? "o--" : fmt::format("o-[{}]-", style); + case relationship_t::kContainment: + return style.empty() ? "--+" : fmt::format("-[{}]-+", style); + case relationship_t::kAssociation: + return style.empty() ? "-->" : fmt::format("-[{}]->", style); + case relationship_t::kInstantiation: + return style.empty() ? "..|>" : fmt::format(".[{}].|>", style); + case relationship_t::kFriendship: + return style.empty() ? "<.." : fmt::format("<.[{}].", style); + case relationship_t::kDependency: + return style.empty() ? "..>" : fmt::format(".[{}].>", style); + default: + return ""; + } +} + +std::string to_plantuml(scope_t scope) +{ + switch (scope) { + case scope_t::kPublic: + return "+"; + case scope_t::kProtected: + return "#"; + case scope_t::kPrivate: + return "-"; + default: + return ""; + } +} + +} diff --git a/src/common/generators/plantuml/generator.h b/src/common/generators/plantuml/generator.h new file mode 100644 index 00000000..7e3a28c4 --- /dev/null +++ b/src/common/generators/plantuml/generator.h @@ -0,0 +1,120 @@ +/** + * src/common/generators/plantuml/generator.h + * + * Copyright (c) 2021-2022 Bartek Kryza + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include "config/config.h" +#include "generator.h" +#include "util/error.h" +#include "util/util.h" + +#include + +namespace clanguml::common::generators::plantuml { + +using clanguml::common::model::relationship_t; +using clanguml::common::model::scope_t; + +std::string to_plantuml(relationship_t r, std::string style); + +std::string to_plantuml(scope_t scope); + +template class generator { +public: + generator(ConfigType &config, DiagramType &model) + : m_config{config} + , m_model{model} + { + } + + virtual ~generator() = default; + + virtual void generate(std::ostream &ostr) const = 0; + + void generate_config_layout_hints(std::ostream &ostr) const; + + void generate_plantuml_directives( + std::ostream &ostr, const std::vector &directives) const; + + void generate_notes( + std::ostream &ostr, const model::element &decorators) const; + +protected: + ConfigType &m_config; + DiagramType &m_model; +}; + +template +void generator::generate_config_layout_hints(std::ostream &ostr) const +{ + using namespace clanguml::util; + + const auto &uns = m_config.using_namespace(); + + // Generate layout hints + for (const auto &[entity, hints] : m_config.layout()) { + for (const auto &hint : hints) { + std::stringstream hint_str; + try { + hint_str << m_model.to_alias(ns_relative(uns, entity)) + << " -[hidden]" + << clanguml::config::to_string(hint.hint) << "- " + << m_model.to_alias(ns_relative(uns, hint.entity)) + << '\n'; + ostr << hint_str.str(); + } + catch (clanguml::error::uml_alias_missing &e) { + LOG_ERROR("=== Skipping layout hint from {} to {} due " + "to: {}", + entity, hint.entity, e.what()); + } + } + } +} + +template +void generator::generate_plantuml_directives( + std::ostream &ostr, const std::vector &directives) const +{ + for (const auto &b : directives) { + std::string note{b}; + std::tuple alias_match; + while (util::find_element_alias(note, alias_match)) { + auto alias = m_model.to_alias(util::ns_relative( + m_config.using_namespace(), std::get<0>(alias_match))); + note.replace( + std::get<1>(alias_match), std::get<2>(alias_match), alias); + } + ostr << note << '\n'; + } +} + +template +void generator::generate_notes( + std::ostream &ostr, const model::element &e) const +{ + for (auto decorator : e.decorators()) { + auto note = std::dynamic_pointer_cast(decorator); + if (note && note->applies_to_diagram(m_config.name)) { + ostr << "note " << note->position << " of " << e.alias() << '\n' + << note->text << '\n' + << "end note\n"; + } + } +} + +} diff --git a/src/common/model/enums.cc b/src/common/model/enums.cc new file mode 100644 index 00000000..a0c88f6a --- /dev/null +++ b/src/common/model/enums.cc @@ -0,0 +1,81 @@ +/** + * src/class_diagram/model/enums.cc + * + * Copyright (c) 2021-2022 Bartek Kryza + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "enums.h" + +#include + +namespace clanguml::common::model { + +std::string to_string(relationship_t r) +{ + switch (r) { + case relationship_t::kNone: + return "none"; + case relationship_t::kExtension: + return "extension"; + case relationship_t::kComposition: + return "composition"; + case relationship_t::kAggregation: + return "aggregation"; + case relationship_t::kContainment: + return "containment"; + case relationship_t::kOwnership: + return "ownership"; + case relationship_t::kAssociation: + return "association"; + case relationship_t::kInstantiation: + return "instantiation"; + case relationship_t::kFriendship: + return "friendship"; + case relationship_t::kDependency: + return "dependency"; + default: + assert(false); + } +} + +std::string to_string(scope_t s) +{ + switch (s) { + case scope_t::kPublic: + return "public"; + case scope_t::kProtected: + return "protected"; + case scope_t::kPrivate: + return "private"; + case scope_t::kNone: + return "none"; + default: + assert(false); + } +} + +std::string to_string(access_t a) +{ + switch (a) { + case access_t::kPublic: + return "public"; + case access_t::kProtected: + return "protected"; + case access_t::kPrivate: + return "private"; + default: + assert(false); + } +} +} diff --git a/src/common/model/enums.h b/src/common/model/enums.h index 08c78d45..86a6a210 100644 --- a/src/common/model/enums.h +++ b/src/common/model/enums.h @@ -17,6 +17,8 @@ */ #pragma once +#include + namespace clanguml::common::model { enum class access_t { kPublic, kProtected, kPrivate }; @@ -36,4 +38,9 @@ enum class relationship_t { kDependency }; +std::string to_string(relationship_t r); + +std::string to_string(scope_t r); + +std::string to_string(access_t r); } diff --git a/src/common/model/relationship.cc b/src/common/model/relationship.cc index 96c92fd6..f384e40a 100644 --- a/src/common/model/relationship.cc +++ b/src/common/model/relationship.cc @@ -20,34 +20,6 @@ namespace clanguml::common::model { -std::string to_string(relationship_t r) -{ - switch (r) { - case relationship_t::kNone: - return "none"; - case relationship_t::kExtension: - return "extension"; - case relationship_t::kComposition: - return "composition"; - case relationship_t::kAggregation: - return "aggregation"; - case relationship_t::kContainment: - return "containment"; - case relationship_t::kOwnership: - return "ownership"; - case relationship_t::kAssociation: - return "association"; - case relationship_t::kInstantiation: - return "instantiation"; - case relationship_t::kFriendship: - return "frendship"; - case relationship_t::kDependency: - return "dependency"; - default: - return "invalid"; - } -} - relationship::relationship(relationship_t type, const std::string &destination, scope_t scope, const std::string &label, const std::string &multiplicity_source, diff --git a/src/common/model/relationship.h b/src/common/model/relationship.h index 0bb66390..d75addf8 100644 --- a/src/common/model/relationship.h +++ b/src/common/model/relationship.h @@ -24,8 +24,6 @@ namespace clanguml::common::model { -std::string to_string(relationship_t r); - class relationship : public common::model::decorated_element, public common::model::stylable_element { public: diff --git a/tests/t00035/t00035.cc b/tests/t00035/t00035.cc index 12bb4ca6..dbc01d47 100644 --- a/tests/t00035/t00035.cc +++ b/tests/t00035/t00035.cc @@ -1,15 +1,20 @@ namespace clanguml { namespace t00035 { -struct Top {}; +struct Top { +}; -struct Left {}; +struct Left { +}; -struct Center {}; +struct Center { +}; -struct Bottom {}; +struct Bottom { +}; -struct Right {}; +struct Right { +}; } // namespace t00035 } // namespace clanguml From fb00743702c36f82484a1a19f5fe81c158b1f5ad Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Wed, 16 Feb 2022 00:09:09 +0100 Subject: [PATCH 11/18] Refactored package_diagram generator to common base class template --- .../plantuml/class_diagram_generator.cc | 9 +- .../plantuml/class_diagram_generator.h | 2 - src/common/generators/plantuml/generator.h | 10 ++ .../plantuml/package_diagram_generator.cc | 125 +----------------- .../plantuml/package_diagram_generator.h | 26 ++-- 5 files changed, 25 insertions(+), 147 deletions(-) diff --git a/src/class_diagram/generators/plantuml/class_diagram_generator.cc b/src/class_diagram/generators/plantuml/class_diagram_generator.cc index 4071dc99..bed14dbf 100644 --- a/src/class_diagram/generators/plantuml/class_diagram_generator.cc +++ b/src/class_diagram/generators/plantuml/class_diagram_generator.cc @@ -22,8 +22,7 @@ namespace clanguml::class_diagram::generators::plantuml { -generator::generator( - clanguml::config::class_diagram &config, diagram_model &model) +generator::generator(diagram_config &config, diagram_model &model) : common_generator{config, model} { } @@ -312,12 +311,6 @@ void generator::generate(std::ostream &ostr) const ostr << "@enduml" << '\n'; } -std::ostream &operator<<(std::ostream &os, const generator &g) -{ - g.generate(os); - return os; -} - clanguml::class_diagram::model::diagram generate( cppast::libclang_compilation_database &db, const std::string &name, clanguml::config::class_diagram &diagram) diff --git a/src/class_diagram/generators/plantuml/class_diagram_generator.h b/src/class_diagram/generators/plantuml/class_diagram_generator.h index 148a50af..a14f881c 100644 --- a/src/class_diagram/generators/plantuml/class_diagram_generator.h +++ b/src/class_diagram/generators/plantuml/class_diagram_generator.h @@ -67,8 +67,6 @@ public: void generate(const enum_ &e, std::ostream &ostr) const; void generate(std::ostream &ostr) const override; - - friend std::ostream &operator<<(std::ostream &os, const generator &g); }; clanguml::class_diagram::model::diagram generate( diff --git a/src/common/generators/plantuml/generator.h b/src/common/generators/plantuml/generator.h index 7e3a28c4..21ee64e7 100644 --- a/src/common/generators/plantuml/generator.h +++ b/src/common/generators/plantuml/generator.h @@ -45,6 +45,9 @@ public: virtual void generate(std::ostream &ostr) const = 0; + template + friend std::ostream &operator<<(std::ostream &os, const generator &g); + void generate_config_layout_hints(std::ostream &ostr) const; void generate_plantuml_directives( @@ -58,6 +61,13 @@ protected: DiagramType &m_model; }; +template +std::ostream &operator<<(std::ostream &os, const generator &g) +{ + g.generate(os); + return os; +} + template void generator::generate_config_layout_hints(std::ostream &ostr) const { diff --git a/src/package_diagram/generators/plantuml/package_diagram_generator.cc b/src/package_diagram/generators/plantuml/package_diagram_generator.cc index a14c917b..289cf9ea 100644 --- a/src/package_diagram/generators/plantuml/package_diagram_generator.cc +++ b/src/package_diagram/generators/plantuml/package_diagram_generator.cc @@ -22,61 +22,9 @@ namespace clanguml::package_diagram::generators::plantuml { -std::string relative_to(std::string n, std::string c) +generator::generator(diagram_config &config, diagram_model &model) + : common_generator{config, model} { - if (c.rfind(n) == std::string::npos) - return c; - - return c.substr(n.size() + 2); -} - -generator::generator( - clanguml::config::package_diagram &config, diagram_model &model) - : m_config(config) - , m_model(model) -{ -} - -std::string generator::to_string(relationship_t r, std::string style) const -{ - switch (r) { - case relationship_t::kOwnership: - case relationship_t::kComposition: - return style.empty() ? "*--" : fmt::format("*-[{}]-", style); - case relationship_t::kAggregation: - return style.empty() ? "o--" : fmt::format("o-[{}]-", style); - case relationship_t::kContainment: - return style.empty() ? "--+" : fmt::format("-[{}]-+", style); - case relationship_t::kAssociation: - return style.empty() ? "-->" : fmt::format("-[{}]->", style); - case relationship_t::kInstantiation: - return style.empty() ? "..|>" : fmt::format(".[{}].|>", style); - case relationship_t::kFriendship: - return style.empty() ? "<.." : fmt::format("<.[{}].", style); - case relationship_t::kDependency: - return style.empty() ? "..>" : fmt::format(".[{}].>", style); - default: - return ""; - } -} - -std::string generator::name(relationship_t r) const -{ - switch (r) { - case relationship_t::kOwnership: - case relationship_t::kComposition: - return "composition"; - case relationship_t::kAggregation: - return "aggregation"; - case relationship_t::kContainment: - return "containment"; - case relationship_t::kAssociation: - return "association"; - case relationship_t::kDependency: - return "dependency"; - default: - return "unknown"; - } } void generator::generate_relationships( @@ -109,31 +57,6 @@ void generator::generate_relationships( } } -void generator::generate_config_layout_hints(std::ostream &ostr) const -{ - const auto &uns = m_config.using_namespace(); - - // Generate layout hints - for (const auto &[entity, hints] : m_config.layout()) { - for (const auto &hint : hints) { - std::stringstream hint_str; - try { - hint_str << m_model.to_alias(ns_relative(uns, entity)) - << " -[hidden]" - << clanguml::config::to_string(hint.hint) << "- " - << m_model.to_alias(ns_relative(uns, hint.entity)) - << '\n'; - ostr << hint_str.str(); - } - catch (error::uml_alias_missing &e) { - LOG_ERROR("=== Skipping layout hint from {} to {} due " - "to: {}", - entity, hint.entity, e.what()); - } - } - } -} - void generator::generate(const package &p, std::ostream &ostr) const { const auto &uns = m_config.using_namespace(); @@ -157,35 +80,14 @@ void generator::generate(const package &p, std::ostream &ostr) const ostr << "}" << '\n'; - // - // Process notes - // - for (auto decorator : p.decorators()) { - auto note = std::dynamic_pointer_cast(decorator); - if (note && note->applies_to_diagram(m_config.name)) { - ostr << "note " << note->position << " of " << p.alias() << '\n' - << note->text << '\n' - << "end note\n"; - } - } + generate_notes(ostr, p); } void generator::generate(std::ostream &ostr) const { ostr << "@startuml" << '\n'; - // Process aliases in any of the puml directives - for (const auto &b : m_config.puml().before) { - std::string note{b}; - std::tuple alias_match; - while (util::find_element_alias(note, alias_match)) { - auto alias = m_model.to_alias(ns_relative( - m_config.using_namespace(), std::get<0>(alias_match))); - note.replace( - std::get<1>(alias_match), std::get<2>(alias_match), alias); - } - ostr << note << '\n'; - } + generate_plantuml_directives(ostr, m_config.puml().before); if (m_config.should_include_entities("packages")) { for (const auto &p : m_model) { @@ -202,28 +104,11 @@ void generator::generate(std::ostream &ostr) const generate_config_layout_hints(ostr); - // Process aliases in any of the puml directives - for (const auto &b : m_config.puml().after) { - std::string note{b}; - std::tuple alias_match; - while (util::find_element_alias(note, alias_match)) { - auto alias = m_model.to_alias(ns_relative( - m_config.using_namespace(), std::get<0>(alias_match))); - note.replace( - std::get<1>(alias_match), std::get<2>(alias_match), alias); - } - ostr << note << '\n'; - } + generate_plantuml_directives(ostr, m_config.puml().after); ostr << "@enduml" << '\n'; } -std::ostream &operator<<(std::ostream &os, const generator &g) -{ - g.generate(os); - return os; -} - clanguml::package_diagram::model::diagram generate( cppast::libclang_compilation_database &db, const std::string &name, clanguml::config::package_diagram &diagram) diff --git a/src/package_diagram/generators/plantuml/package_diagram_generator.h b/src/package_diagram/generators/plantuml/package_diagram_generator.h index 5fe96ed9..95bf027f 100644 --- a/src/package_diagram/generators/plantuml/package_diagram_generator.h +++ b/src/package_diagram/generators/plantuml/package_diagram_generator.h @@ -17,6 +17,7 @@ */ #pragma once +#include "common/generators/plantuml/generator.h" #include "common/model/relationship.h" #include "config/config.h" #include "cx/compilation_database.h" @@ -39,38 +40,29 @@ namespace package_diagram { namespace generators { namespace plantuml { -using diagram_config = clanguml::package_diagram::model::diagram; +using diagram_config = clanguml::config::package_diagram; using diagram_model = clanguml::package_diagram::model::diagram; + +template +using common_generator = + clanguml::common::generators::plantuml::generator; + using clanguml::common::model::relationship_t; using clanguml::common::model::scope_t; using clanguml::package_diagram::model::package; using namespace clanguml::util; -std::string relative_to(std::string n, std::string c); - -class generator { +class generator : public common_generator { public: - generator(clanguml::config::package_diagram &config, diagram_model &model); - - std::string to_string(relationship_t r, std::string style = "") const; - - std::string name(relationship_t r) const; + generator(diagram_config &config, diagram_model &model); void generate_alias(const package &c, std::ostream &ostr) const; void generate_relationships(const package &p, std::ostream &ostr) const; - void generate_config_layout_hints(std::ostream &ostr) const; - void generate(const package &e, std::ostream &ostr) const; void generate(std::ostream &ostr) const; - - friend std::ostream &operator<<(std::ostream &os, const generator &g); - -private: - clanguml::config::package_diagram &m_config; - diagram_model &m_model; }; clanguml::package_diagram::model::diagram generate( From 4eab1e62b59e5fcc30af2c3cbb171c3ab96f5b1a Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Wed, 16 Feb 2022 19:54:49 +0100 Subject: [PATCH 12/18] Refactored sequence diagram generator --- src/common/generators/plantuml/generator.cc | 12 ++++++ src/common/generators/plantuml/generator.h | 4 +- src/common/model/enums.cc | 12 ++++++ src/common/model/enums.h | 5 +++ .../plantuml/sequence_diagram_generator.cc | 38 ++++--------------- .../plantuml/sequence_diagram_generator.h | 18 ++++----- src/sequence_diagram/model/diagram.cc | 5 +++ src/sequence_diagram/model/diagram.h | 2 + src/sequence_diagram/model/enums.h | 24 ------------ src/sequence_diagram/model/message.h | 4 +- .../visitor/translation_unit_visitor.cc | 2 +- 11 files changed, 57 insertions(+), 69 deletions(-) delete mode 100644 src/sequence_diagram/model/enums.h diff --git a/src/common/generators/plantuml/generator.cc b/src/common/generators/plantuml/generator.cc index 8cc60542..139a04b8 100644 --- a/src/common/generators/plantuml/generator.cc +++ b/src/common/generators/plantuml/generator.cc @@ -56,4 +56,16 @@ std::string to_plantuml(scope_t scope) } } +std::string to_plantuml(message_t r) +{ + switch (r) { + case message_t::kCall: + return "->"; + case message_t::kReturn: + return "-->"; + default: + return ""; + } +} + } diff --git a/src/common/generators/plantuml/generator.h b/src/common/generators/plantuml/generator.h index 21ee64e7..46febef1 100644 --- a/src/common/generators/plantuml/generator.h +++ b/src/common/generators/plantuml/generator.h @@ -18,7 +18,6 @@ #pragma once #include "config/config.h" -#include "generator.h" #include "util/error.h" #include "util/util.h" @@ -26,12 +25,13 @@ namespace clanguml::common::generators::plantuml { +using clanguml::common::model::message_t; using clanguml::common::model::relationship_t; using clanguml::common::model::scope_t; std::string to_plantuml(relationship_t r, std::string style); - std::string to_plantuml(scope_t scope); +std::string to_plantuml(message_t r); template class generator { public: diff --git a/src/common/model/enums.cc b/src/common/model/enums.cc index a0c88f6a..df734e6d 100644 --- a/src/common/model/enums.cc +++ b/src/common/model/enums.cc @@ -78,4 +78,16 @@ std::string to_string(access_t a) assert(false); } } + +std::string to_string(message_t r) +{ + switch (r) { + case message_t::kCall: + return "call"; + case message_t::kReturn: + return "return"; + default: + assert(false); + } +} } diff --git a/src/common/model/enums.h b/src/common/model/enums.h index 86a6a210..2b553562 100644 --- a/src/common/model/enums.h +++ b/src/common/model/enums.h @@ -38,9 +38,14 @@ enum class relationship_t { kDependency }; +enum class message_t { kCall, kReturn }; + std::string to_string(relationship_t r); std::string to_string(scope_t r); std::string to_string(access_t r); + +std::string to_string(message_t r); + } diff --git a/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc index 6bb06a4c..6e126966 100644 --- a/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc +++ b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc @@ -25,12 +25,10 @@ namespace clanguml::sequence_diagram::generators::plantuml { -using diagram_model = clanguml::sequence_diagram::model::diagram; -using diagram_config = clanguml::config::sequence_diagram::diagram; +using clanguml::common::model::message_t; using clanguml::config::source_location; using clanguml::sequence_diagram::model::activity; using clanguml::sequence_diagram::model::message; -using clanguml::sequence_diagram::model::message_t; using clanguml::sequence_diagram::visitor::translation_unit_context; using namespace clanguml::util; @@ -40,31 +38,18 @@ using namespace clanguml::util; generator::generator( clanguml::config::sequence_diagram &config, diagram_model &model) - : m_config(config) - , m_model(model) + : common_generator{config, model} { } -std::string generator::to_string(message_t r) const -{ - switch (r) { - case message_t::kCall: - return "->"; - case message_t::kReturn: - return "<--"; - default: - return ""; - } -} - void generator::generate_call(const message &m, std::ostream &ostr) const { const auto from = ns_relative(m_config.using_namespace(), m.from); const auto to = ns_relative(m_config.using_namespace(), m.to); ostr << '"' << from << "\" " - << "->" - << " \"" << to << "\" : " << m.message << "()" << std::endl; + << common::generators::plantuml::to_plantuml(message_t::kCall) << " \"" + << to << "\" : " << m.message << "()" << std::endl; } void generator::generate_return(const message &m, std::ostream &ostr) const @@ -76,7 +61,7 @@ void generator::generate_return(const message &m, std::ostream &ostr) const const auto to = ns_relative(m_config.using_namespace(), m.to); ostr << '"' << to << "\" " - << "-->" + << common::generators::plantuml::to_plantuml(message_t::kReturn) << " \"" << from << "\"" << std::endl; } } @@ -98,8 +83,7 @@ void generator::generate(std::ostream &ostr) const { ostr << "@startuml" << std::endl; - for (const auto &b : m_config.puml().before) - ostr << b << std::endl; + generate_plantuml_directives(ostr, m_config.puml().before); for (const auto &sf : m_config.start_from()) { if (sf.location_type == source_location::location_t::function) { @@ -117,18 +101,12 @@ void generator::generate(std::ostream &ostr) const continue; } } - for (const auto &a : m_config.puml().after) - ostr << a << std::endl; + + generate_plantuml_directives(ostr, m_config.puml().after); ostr << "@enduml" << std::endl; } -std::ostream &operator<<(std::ostream &os, const generator &g) -{ - g.generate(os); - return os; -} - clanguml::sequence_diagram::model::diagram generate( cppast::libclang_compilation_database &db, const std::string &name, clanguml::config::sequence_diagram &diagram) diff --git a/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.h b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.h index f54fc42a..b47aa630 100644 --- a/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.h +++ b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.h @@ -17,6 +17,7 @@ */ #pragma once +#include "common/generators/plantuml/generator.h" #include "config/config.h" #include "cx/compilation_database.h" #include "sequence_diagram/model/diagram.h" @@ -36,13 +37,16 @@ namespace sequence_diagram { namespace generators { namespace plantuml { +using diagram_config = clanguml::config::sequence_diagram; using diagram_model = clanguml::sequence_diagram::model::diagram; -class generator { -public: - generator(clanguml::config::sequence_diagram &config, diagram_model &model); +template +using common_generator = + clanguml::common::generators::plantuml::generator; - std::string to_string(clanguml::sequence_diagram::model::message_t r) const; +class generator : public common_generator { +public: + generator(diagram_config &config, diagram_model &model); void generate_call(const clanguml::sequence_diagram::model::message &m, std::ostream &ostr) const; @@ -54,12 +58,6 @@ public: std::ostream &ostr) const; void generate(std::ostream &ostr) const; - - friend std::ostream &operator<<(std::ostream &os, const generator &g); - -private: - clanguml::config::sequence_diagram &m_config; - clanguml::sequence_diagram::model::diagram &m_model; }; clanguml::sequence_diagram::model::diagram generate( diff --git a/src/sequence_diagram/model/diagram.cc b/src/sequence_diagram/model/diagram.cc index 6204153b..b83869ce 100644 --- a/src/sequence_diagram/model/diagram.cc +++ b/src/sequence_diagram/model/diagram.cc @@ -29,4 +29,9 @@ namespace clanguml::sequence_diagram::model { +std::string diagram::to_alias(const std::string &full_name) const +{ + return full_name; +} + } diff --git a/src/sequence_diagram/model/diagram.h b/src/sequence_diagram/model/diagram.h index e6ddf2cf..240a0b1b 100644 --- a/src/sequence_diagram/model/diagram.h +++ b/src/sequence_diagram/model/diagram.h @@ -25,6 +25,8 @@ namespace clanguml::sequence_diagram::model { struct diagram { + std::string to_alias(const std::string &full_name) const; + bool started{false}; std::string name; diff --git a/src/sequence_diagram/model/enums.h b/src/sequence_diagram/model/enums.h deleted file mode 100644 index 05a808e7..00000000 --- a/src/sequence_diagram/model/enums.h +++ /dev/null @@ -1,24 +0,0 @@ -/** - * src/sequence_diagram/model/enums.h - * - * Copyright (c) 2021-2022 Bartek Kryza - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#pragma once - -namespace clanguml::sequence_diagram::model { - -enum class message_t { kCall, kReturn }; - -} diff --git a/src/sequence_diagram/model/message.h b/src/sequence_diagram/model/message.h index 8c790eab..cbe7cbfd 100644 --- a/src/sequence_diagram/model/message.h +++ b/src/sequence_diagram/model/message.h @@ -17,7 +17,7 @@ */ #pragma once -#include "enums.h" +#include "common/model/enums.h" #include #include @@ -25,7 +25,7 @@ namespace clanguml::sequence_diagram::model { struct message { - message_t type; + common::model::message_t type; std::string from; std::uint_least64_t from_usr; std::string to; diff --git a/src/sequence_diagram/visitor/translation_unit_visitor.cc b/src/sequence_diagram/visitor/translation_unit_visitor.cc index 7091dafd..65244d07 100644 --- a/src/sequence_diagram/visitor/translation_unit_visitor.cc +++ b/src/sequence_diagram/visitor/translation_unit_visitor.cc @@ -36,10 +36,10 @@ translation_unit_visitor::translation_unit_visitor( void translation_unit_visitor::process_activities(const cppast::cpp_function &e) { + using clanguml::common::model::message_t; using clanguml::sequence_diagram::model::activity; using clanguml::sequence_diagram::model::diagram; using clanguml::sequence_diagram::model::message; - using clanguml::sequence_diagram::model::message_t; using cppast::cpp_entity; using cppast::cpp_entity_kind; using cppast::cpp_function; From e7afdba19aa246448462c7ec0842fb3887fcc75e Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Wed, 16 Feb 2022 21:00:18 +0100 Subject: [PATCH 13/18] Refactored generator function to common namespace --- .../plantuml/class_diagram_generator.cc | 32 -------------- .../plantuml/class_diagram_generator.h | 4 -- src/common/generators/plantuml/generator.h | 35 +++++++++++++++ src/main.cc | 36 +++++++++++----- .../plantuml/package_diagram_generator.cc | 32 -------------- .../plantuml/package_diagram_generator.h | 5 --- .../plantuml/sequence_diagram_generator.cc | 31 ------------- .../plantuml/sequence_diagram_generator.h | 4 -- src/sequence_diagram/model/diagram.cc | 4 ++ src/sequence_diagram/model/diagram.h | 8 +++- tests/t20001/test_case.h | 2 +- tests/t20002/test_case.h | 2 +- tests/test_cases.cc | 43 ++++++++++++------- 13 files changed, 102 insertions(+), 136 deletions(-) diff --git a/src/class_diagram/generators/plantuml/class_diagram_generator.cc b/src/class_diagram/generators/plantuml/class_diagram_generator.cc index bed14dbf..3e7b906d 100644 --- a/src/class_diagram/generators/plantuml/class_diagram_generator.cc +++ b/src/class_diagram/generators/plantuml/class_diagram_generator.cc @@ -311,36 +311,4 @@ void generator::generate(std::ostream &ostr) const ostr << "@enduml" << '\n'; } -clanguml::class_diagram::model::diagram generate( - cppast::libclang_compilation_database &db, const std::string &name, - clanguml::config::class_diagram &diagram) -{ - LOG_DBG("Generating diagram {}.puml", name); - clanguml::class_diagram::model::diagram d; - d.set_name(name); - - // Get all translation units matching the glob from diagram - // configuration - std::vector translation_units{}; - for (const auto &g : diagram.glob()) { - LOG_DBG("Processing glob: {}", g); - const auto matches = glob::rglob(g); - std::copy(matches.begin(), matches.end(), - std::back_inserter(translation_units)); - } - - cppast::cpp_entity_index idx; - cppast::simple_file_parser parser{ - type_safe::ref(idx)}; - - // Process all matching translation units - clanguml::class_diagram::visitor::translation_unit_visitor ctx( - idx, d, diagram); - cppast::parse_files(parser, translation_units, db); - for (auto &file : parser.files()) - ctx(file); - - return d; -} - } diff --git a/src/class_diagram/generators/plantuml/class_diagram_generator.h b/src/class_diagram/generators/plantuml/class_diagram_generator.h index a14f881c..ea6bf845 100644 --- a/src/class_diagram/generators/plantuml/class_diagram_generator.h +++ b/src/class_diagram/generators/plantuml/class_diagram_generator.h @@ -69,10 +69,6 @@ public: void generate(std::ostream &ostr) const override; }; -clanguml::class_diagram::model::diagram generate( - cppast::libclang_compilation_database &db, const std::string &name, - clanguml::config::class_diagram &diagram); - } } } diff --git a/src/common/generators/plantuml/generator.h b/src/common/generators/plantuml/generator.h index 46febef1..9906dbd7 100644 --- a/src/common/generators/plantuml/generator.h +++ b/src/common/generators/plantuml/generator.h @@ -21,6 +21,9 @@ #include "util/error.h" #include "util/util.h" +#include +#include + #include namespace clanguml::common::generators::plantuml { @@ -127,4 +130,36 @@ void generator::generate_notes( } } +template +DiagramModel generate(cppast::libclang_compilation_database &db, + const std::string &name, DiagramConfig &diagram) +{ + LOG_INFO("Generating diagram {}.puml", name); + DiagramModel d; + d.set_name(name); + + // Get all translation units matching the glob from diagram + // configuration + std::vector translation_units{}; + for (const auto &g : diagram.glob()) { + LOG_DBG("Processing glob: {}", g); + const auto matches = glob::rglob(g); + std::copy(matches.begin(), matches.end(), + std::back_inserter(translation_units)); + } + + cppast::cpp_entity_index idx; + cppast::simple_file_parser parser{ + type_safe::ref(idx)}; + + // Process all matching translation units + DiagramVisitor ctx(idx, d, diagram); + cppast::parse_files(parser, translation_units, db); + for (auto &file : parser.files()) + ctx(file); + + return d; +} + } diff --git a/src/main.cc b/src/main.cc index 1b95a308..6f02be90 100644 --- a/src/main.cc +++ b/src/main.cc @@ -113,31 +113,47 @@ int main(int argc, const char *argv[]) ofs.open(path, std::ofstream::out | std::ofstream::trunc); if (diagram->type() == diagram_type::class_diagram) { + using diagram_config = clanguml::config::class_diagram; + using diagram_model = clanguml::class_diagram::model::diagram; + using diagram_visitor = + clanguml::class_diagram::visitor::translation_unit_visitor; + auto model = - clanguml::class_diagram::generators::plantuml::generate( - db, name, dynamic_cast(*diagram)); + clanguml::common::generators::plantuml::generate(db, diagram->name, + dynamic_cast(*diagram)); ofs << clanguml::class_diagram::generators::plantuml::generator( - dynamic_cast(*diagram), - model); + dynamic_cast(*diagram), model); } else if (diagram->type() == diagram_type::sequence_diagram) { + using diagram_config = clanguml::config::sequence_diagram; + using diagram_model = clanguml::sequence_diagram::model::diagram; + using diagram_visitor = + clanguml::sequence_diagram::visitor::translation_unit_visitor; + auto model = - clanguml::sequence_diagram::generators::plantuml::generate( - db, name, dynamic_cast(*diagram)); + clanguml::common::generators::plantuml::generate(db, diagram->name, + dynamic_cast(*diagram)); ofs << clanguml::sequence_diagram::generators::plantuml::generator( dynamic_cast(*diagram), model); } else if (diagram->type() == diagram_type::package_diagram) { + using diagram_config = clanguml::config::package_diagram; + using diagram_model = clanguml::package_diagram::model::diagram; + using diagram_visitor = + clanguml::package_diagram::visitor::translation_unit_visitor; + auto model = - clanguml::package_diagram::generators::plantuml::generate( - db, name, dynamic_cast(*diagram)); + clanguml::common::generators::plantuml::generate(db, diagram->name, + dynamic_cast(*diagram)); ofs << clanguml::package_diagram::generators::plantuml::generator( - dynamic_cast(*diagram), - model); + dynamic_cast(*diagram), model); } LOG_INFO("Written {} diagram to {}", name, path.string()); diff --git a/src/package_diagram/generators/plantuml/package_diagram_generator.cc b/src/package_diagram/generators/plantuml/package_diagram_generator.cc index 289cf9ea..f1a68570 100644 --- a/src/package_diagram/generators/plantuml/package_diagram_generator.cc +++ b/src/package_diagram/generators/plantuml/package_diagram_generator.cc @@ -109,36 +109,4 @@ void generator::generate(std::ostream &ostr) const ostr << "@enduml" << '\n'; } -clanguml::package_diagram::model::diagram generate( - cppast::libclang_compilation_database &db, const std::string &name, - clanguml::config::package_diagram &diagram) -{ - LOG_INFO("Generating package diagram {}.puml", name); - clanguml::package_diagram::model::diagram d; - d.set_name(name); - - // Get all translation units matching the glob from diagram - // configuration - std::vector translation_units{}; - for (const auto &g : diagram.glob()) { - LOG_DBG("Processing glob: {}", g); - const auto matches = glob::rglob(g); - std::copy(matches.begin(), matches.end(), - std::back_inserter(translation_units)); - } - - cppast::cpp_entity_index idx; - cppast::simple_file_parser parser{ - type_safe::ref(idx)}; - - // Process all matching translation units - clanguml::package_diagram::visitor::translation_unit_visitor ctx( - idx, d, diagram); - cppast::parse_files(parser, translation_units, db); - for (auto &file : parser.files()) - ctx(file); - - return d; -} - } diff --git a/src/package_diagram/generators/plantuml/package_diagram_generator.h b/src/package_diagram/generators/plantuml/package_diagram_generator.h index 95bf027f..a29e0743 100644 --- a/src/package_diagram/generators/plantuml/package_diagram_generator.h +++ b/src/package_diagram/generators/plantuml/package_diagram_generator.h @@ -28,7 +28,6 @@ #include #include -#include #include #include @@ -65,10 +64,6 @@ public: void generate(std::ostream &ostr) const; }; -clanguml::package_diagram::model::diagram generate( - cppast::libclang_compilation_database &db, const std::string &name, - clanguml::config::package_diagram &diagram); - } } } diff --git a/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc index 6e126966..76b6277f 100644 --- a/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc +++ b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc @@ -107,35 +107,4 @@ void generator::generate(std::ostream &ostr) const ostr << "@enduml" << std::endl; } -clanguml::sequence_diagram::model::diagram generate( - cppast::libclang_compilation_database &db, const std::string &name, - clanguml::config::sequence_diagram &diagram) -{ - spdlog::info("Generating diagram {}.puml", name); - clanguml::sequence_diagram::model::diagram d; - d.name = name; - - cppast::cpp_entity_index idx; - cppast::simple_file_parser parser{ - type_safe::ref(idx)}; - - clanguml::sequence_diagram::visitor::translation_unit_visitor visitor( - idx, d, diagram); - - // Get all translation units matching the glob from diagram - // configuration - std::vector translation_units{}; - for (const auto &g : diagram.glob()) { - spdlog::debug("Processing glob: {}", g); - const auto matches = glob::rglob(g); - std::copy(matches.begin(), matches.end(), - std::back_inserter(translation_units)); - } - cppast::parse_files(parser, translation_units, db); - - for (auto &file : parser.files()) - visitor(file); - - return d; -} } diff --git a/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.h b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.h index b47aa630..efcf1c0c 100644 --- a/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.h +++ b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.h @@ -60,10 +60,6 @@ public: void generate(std::ostream &ostr) const; }; -clanguml::sequence_diagram::model::diagram generate( - cppast::libclang_compilation_database &db, const std::string &name, - clanguml::config::sequence_diagram &diagram); - } } } diff --git a/src/sequence_diagram/model/diagram.cc b/src/sequence_diagram/model/diagram.cc index b83869ce..f85568f4 100644 --- a/src/sequence_diagram/model/diagram.cc +++ b/src/sequence_diagram/model/diagram.cc @@ -29,6 +29,10 @@ namespace clanguml::sequence_diagram::model { +std::string diagram::name() const { return name_; } + +void diagram::set_name(const std::string &name) { name_ = name; } + std::string diagram::to_alias(const std::string &full_name) const { return full_name; diff --git a/src/sequence_diagram/model/diagram.h b/src/sequence_diagram/model/diagram.h index 240a0b1b..67f6df39 100644 --- a/src/sequence_diagram/model/diagram.h +++ b/src/sequence_diagram/model/diagram.h @@ -25,12 +25,18 @@ namespace clanguml::sequence_diagram::model { struct diagram { + std::string name() const; + + void set_name(const std::string &name); + std::string to_alias(const std::string &full_name) const; bool started{false}; - std::string name; std::map sequences; + +private: + std::string name_; }; } diff --git a/tests/t20001/test_case.h b/tests/t20001/test_case.h index 1958db5c..66319027 100644 --- a/tests/t20001/test_case.h +++ b/tests/t20001/test_case.h @@ -30,7 +30,7 @@ TEST_CASE("t20001", "[test-case][sequence]") auto model = generate_sequence_diagram(db, diagram); - REQUIRE(model.name == "t20001_sequence"); + REQUIRE(model.name() == "t20001_sequence"); auto puml = generate_sequence_puml(diagram, model); diff --git a/tests/t20002/test_case.h b/tests/t20002/test_case.h index 5b4e3752..24cc8501 100644 --- a/tests/t20002/test_case.h +++ b/tests/t20002/test_case.h @@ -26,7 +26,7 @@ TEST_CASE("t20002", "[test-case][sequence]") auto model = generate_sequence_diagram(db, diagram); - REQUIRE(model.name == "t20002_sequence"); + REQUIRE(model.name() == "t20002_sequence"); auto puml = generate_sequence_puml(diagram, model); diff --git a/tests/test_cases.cc b/tests/test_cases.cc index 8e42aff2..30190d72 100644 --- a/tests/test_cases.cc +++ b/tests/test_cases.cc @@ -16,6 +16,7 @@ * limitations under the License. */ #include "test_cases.h" +#include "common/generators/plantuml/generator.h" #include @@ -44,36 +45,48 @@ clanguml::sequence_diagram::model::diagram generate_sequence_diagram( cppast::libclang_compilation_database &db, std::shared_ptr diagram) { - auto diagram_model = - clanguml::sequence_diagram::generators::plantuml::generate(db, - diagram->name, - dynamic_cast(*diagram)); + using diagram_config = clanguml::config::sequence_diagram; + using diagram_model = clanguml::sequence_diagram::model::diagram; + using diagram_visitor = + clanguml::sequence_diagram::visitor::translation_unit_visitor; - return diagram_model; + auto model = clanguml::common::generators::plantuml::generate(db, diagram->name, + dynamic_cast(*diagram)); + + return model; } clanguml::class_diagram::model::diagram generate_class_diagram( cppast::libclang_compilation_database &db, std::shared_ptr diagram) { - auto diagram_model = - clanguml::class_diagram::generators::plantuml::generate(db, - diagram->name, - dynamic_cast(*diagram)); + using diagram_config = clanguml::config::class_diagram; + using diagram_model = clanguml::class_diagram::model::diagram; + using diagram_visitor = + clanguml::class_diagram::visitor::translation_unit_visitor; - return diagram_model; + auto model = clanguml::common::generators::plantuml::generate( + db, diagram->name, dynamic_cast(*diagram)); + + return model; } clanguml::package_diagram::model::diagram generate_package_diagram( cppast::libclang_compilation_database &db, std::shared_ptr diagram) { - auto diagram_model = - clanguml::package_diagram::generators::plantuml::generate(db, - diagram->name, - dynamic_cast(*diagram)); + using diagram_config = clanguml::config::package_diagram; + using diagram_model = clanguml::package_diagram::model::diagram; + using diagram_visitor = + clanguml::package_diagram::visitor::translation_unit_visitor; - return diagram_model; + auto model = clanguml::common::generators::plantuml::generate( + db, diagram->name, dynamic_cast(*diagram)); + + return model; } std::string generate_sequence_puml( From 3b6aa48b8216ba58fbe5663af7ea1f397aef13b5 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Wed, 16 Feb 2022 21:13:58 +0100 Subject: [PATCH 14/18] Refactored common diagram methods to common class --- src/class_diagram/model/diagram.cc | 4 ---- src/class_diagram/model/diagram.h | 8 ++----- src/common/model/diagram.cc | 27 +++++++++++++++++++++ src/common/model/diagram.h | 34 +++++++++++++++++++++++++++ src/package_diagram/model/diagram.cc | 4 ---- src/package_diagram/model/diagram.h | 10 +++----- src/sequence_diagram/model/diagram.cc | 4 ---- src/sequence_diagram/model/diagram.h | 11 +++------ 8 files changed, 69 insertions(+), 33 deletions(-) create mode 100644 src/common/model/diagram.cc create mode 100644 src/common/model/diagram.h diff --git a/src/class_diagram/model/diagram.cc b/src/class_diagram/model/diagram.cc index 9eb6664b..46ec8185 100644 --- a/src/class_diagram/model/diagram.cc +++ b/src/class_diagram/model/diagram.cc @@ -23,10 +23,6 @@ namespace clanguml::class_diagram::model { -std::string diagram::name() const { return name_; } - -void diagram::set_name(const std::string &name) { name_ = name; } - const std::vector diagram::classes() const { return classes_; } const std::vector diagram::enums() const { return enums_; } diff --git a/src/class_diagram/model/diagram.h b/src/class_diagram/model/diagram.h index 0dffe194..7f230b02 100644 --- a/src/class_diagram/model/diagram.h +++ b/src/class_diagram/model/diagram.h @@ -18,6 +18,7 @@ #pragma once #include "class.h" +#include "common/model/diagram.h" #include "enum.h" #include "type_alias.h" @@ -26,12 +27,8 @@ namespace clanguml::class_diagram::model { -class diagram { +class diagram : public clanguml::common::model::diagram { public: - std::string name() const; - - void set_name(const std::string &name); - const std::vector classes() const; const std::vector enums() const; @@ -47,7 +44,6 @@ public: std::string to_alias(const std::string &full_name) const; private: - std::string name_; std::vector classes_; std::vector enums_; std::map type_aliases_; diff --git a/src/common/model/diagram.cc b/src/common/model/diagram.cc new file mode 100644 index 00000000..1f4263f5 --- /dev/null +++ b/src/common/model/diagram.cc @@ -0,0 +1,27 @@ +/** + * src/common/model/diagram.cc + * + * Copyright (c) 2021-2022 Bartek Kryza + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "diagram.h" + +namespace clanguml::common::model { + +std::string diagram::name() const { return name_; } + +void diagram::set_name(const std::string &name) { name_ = name; } + +} \ No newline at end of file diff --git a/src/common/model/diagram.h b/src/common/model/diagram.h new file mode 100644 index 00000000..3e4f95b0 --- /dev/null +++ b/src/common/model/diagram.h @@ -0,0 +1,34 @@ +/** + * src/common/model/diagram.h + * + * Copyright (c) 2021-2022 Bartek Kryza + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include + +namespace clanguml::common::model { + +class diagram { +public: + std::string name() const; + + void set_name(const std::string &name); + +private: + std::string name_; +}; + +} diff --git a/src/package_diagram/model/diagram.cc b/src/package_diagram/model/diagram.cc index 1ec49861..00a70863 100644 --- a/src/package_diagram/model/diagram.cc +++ b/src/package_diagram/model/diagram.cc @@ -23,10 +23,6 @@ namespace clanguml::package_diagram::model { -std::string diagram::name() const { return name_; } - -void diagram::set_name(const std::string &name) { name_ = name; } - std::string diagram::to_alias(const std::string &full_name) const { LOG_DBG("Looking for alias for {}", full_name); diff --git a/src/package_diagram/model/diagram.h b/src/package_diagram/model/diagram.h index 7a18f8ea..85dd70b0 100644 --- a/src/package_diagram/model/diagram.h +++ b/src/package_diagram/model/diagram.h @@ -17,6 +17,7 @@ */ #pragma once +#include "common/model/diagram.h" #include "package.h" #include @@ -26,17 +27,12 @@ namespace clanguml::package_diagram::model { -class diagram : public detail::package_trait { +class diagram : public clanguml::common::model::diagram, + public detail::package_trait { public: - std::string name() const; - - void set_name(const std::string &name); - std::string to_alias(const std::string &full_name) const; private: - std::string name_; - std::vector> packages_; }; } diff --git a/src/sequence_diagram/model/diagram.cc b/src/sequence_diagram/model/diagram.cc index f85568f4..b83869ce 100644 --- a/src/sequence_diagram/model/diagram.cc +++ b/src/sequence_diagram/model/diagram.cc @@ -29,10 +29,6 @@ namespace clanguml::sequence_diagram::model { -std::string diagram::name() const { return name_; } - -void diagram::set_name(const std::string &name) { name_ = name; } - std::string diagram::to_alias(const std::string &full_name) const { return full_name; diff --git a/src/sequence_diagram/model/diagram.h b/src/sequence_diagram/model/diagram.h index 67f6df39..8cbc70eb 100644 --- a/src/sequence_diagram/model/diagram.h +++ b/src/sequence_diagram/model/diagram.h @@ -18,25 +18,20 @@ #pragma once #include "activity.h" +#include "common/model/diagram.h" #include #include namespace clanguml::sequence_diagram::model { -struct diagram { - std::string name() const; - - void set_name(const std::string &name); - +class diagram : public clanguml::common::model::diagram { +public: std::string to_alias(const std::string &full_name) const; bool started{false}; std::map sequences; - -private: - std::string name_; }; } From decab5bc456e73a2b9a5d4282f6ea19508922f68 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Wed, 16 Feb 2022 21:41:21 +0100 Subject: [PATCH 15/18] Updated clang-uml uml diagrams --- uml/class_model_class_diagram.yml | 4 ++++ uml/diagram_model_class_diagram.yml | 1 + uml/package_model_class_diagram.yml | 4 ++++ uml/sequence_model_class_diagram.yml | 4 ++++ 4 files changed, 13 insertions(+) diff --git a/uml/class_model_class_diagram.yml b/uml/class_model_class_diagram.yml index d5c70e5b..f705aca9 100644 --- a/uml/class_model_class_diagram.yml +++ b/uml/class_model_class_diagram.yml @@ -1,10 +1,14 @@ type: class include_relations_also_as_members: false +generate_method_arguments: none glob: + - src/common/model/*.h + - src/common/model/*.cc - src/class_diagram/model/*.h - src/class_diagram/model/*.cc include: namespaces: + - clanguml::common::model - clanguml::class_diagram::model using_namespace: - clanguml::class_diagram::model diff --git a/uml/diagram_model_class_diagram.yml b/uml/diagram_model_class_diagram.yml index 2264ce80..e19b60d7 100644 --- a/uml/diagram_model_class_diagram.yml +++ b/uml/diagram_model_class_diagram.yml @@ -1,5 +1,6 @@ type: class include_relations_also_as_members: false +generate_method_arguments: none glob: - src/common/model/*.h - src/common/model/*.cc diff --git a/uml/package_model_class_diagram.yml b/uml/package_model_class_diagram.yml index 4a85a917..d5648a54 100644 --- a/uml/package_model_class_diagram.yml +++ b/uml/package_model_class_diagram.yml @@ -1,10 +1,14 @@ type: class include_relations_also_as_members: false +generate_method_arguments: none glob: + - src/common/model/*.h + - src/common/model/*.cc - src/package_diagram/model/*.h - src/package_diagram/model/*.cc include: namespaces: + - clanguml::common::model - clanguml::package_diagram::model using_namespace: - clanguml::package_diagram::model diff --git a/uml/sequence_model_class_diagram.yml b/uml/sequence_model_class_diagram.yml index ed54cf72..03de4ba9 100644 --- a/uml/sequence_model_class_diagram.yml +++ b/uml/sequence_model_class_diagram.yml @@ -1,10 +1,14 @@ type: class include_relations_also_as_members: false +generate_method_arguments: none glob: + - src/common/model/*.h + - src/common/model/*.cc - src/sequence_diagram/model/*.h - src/sequence_diagram/model/*.cc include: namespaces: + - clanguml::common::model - clanguml::sequence_diagram::model using_namespace: - clanguml::sequence_diagram::model From b1178a808919358ecef942c20e7f1cc397bdc7f1 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Wed, 16 Feb 2022 21:46:22 +0100 Subject: [PATCH 16/18] Fixed formatting --- docs/test_cases/t00035.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/docs/test_cases/t00035.md b/docs/test_cases/t00035.md index 9d12ac48..e803b114 100644 --- a/docs/test_cases/t00035.md +++ b/docs/test_cases/t00035.md @@ -27,15 +27,20 @@ File t00035.cc namespace clanguml { namespace t00035 { -struct Top {}; +struct Top { +}; -struct Left {}; +struct Left { +}; -struct Center {}; +struct Center { +}; -struct Bottom {}; +struct Bottom { +}; -struct Right {}; +struct Right { +}; } // namespace t00035 } // namespace clanguml From 1b65832e1319eb74c215e2222b54a5128dc48118 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Wed, 16 Feb 2022 22:00:16 +0100 Subject: [PATCH 17/18] Updated configuration file docs --- docs/configuration_file.md | 48 +++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/docs/configuration_file.md b/docs/configuration_file.md index 6bb4174f..d4cab6b8 100644 --- a/docs/configuration_file.md +++ b/docs/configuration_file.md @@ -10,13 +10,14 @@ * `type` - type of diagram, one of [`class`, `sequence`] * `glob` - list of glob patterns to match source code files for analysis * `include_relations_also_as_members` - when set to `false`, class members for relationships are rendered in UML are skipped from class definition (default: `true`) +* `generate_method_arguments` - determines whether the class diagrams methods contain full arguments (`full`), are abbreviated (`abbreviated`) or skipped (`none`) * `using_namespace` - similar to C++ `using namespace`, a `A::B` value here will render a class `A::B::C::MyClass` in the diagram as `C::MyClass` * `include` - definition of inclusion patterns: * `namespaces` - list of namespaces to include * `relationships` - list of relationships to include * `entity_types` - list of entity types to include (e.g. `class`, `enum`) * `scopes` - list of visibility scopes to include (e.g. `private`) -* `exclude` - definition of exclusion patterns: +* `exclude` - definition of excqlusion patterns: * `namespaces` - list of namespaces to exclude * `relationships` - list of relationships to exclude * `entity_types` - list of entity types to exclude (e.g. `class`, `enum`) @@ -24,3 +25,48 @@ * `plantuml` - verbatim PlantUML directives which should be added to a diagram * `before` - list of directives which will be added before the generated diagram * `after` - list of directives which will be added after the generated diagram + + +## Example complete config + +```yaml +# Directory containing the compile_commands.json file +compilation_database_dir: debug +# The directory where *.puml files will be generated +output_directory: docs/diagrams +# Set this as default for all diagrams +generate_method_arguments: none +# The map of diagrams - keys are also diagram file names +diagrams: + main_package: + # Include this diagram definition from a separate file + include!: uml/main_package_diagram.yml + config_class: + type: class + # Do not include rendered relations in the class box + include_relations_also_as_members: false + # Limiting the number of files to include can significantly + # improve the generation time + glob: + - src/common/model/*.h + - src/common/model/*.cc + - src/class_diagram/model/*.h + - src/class_diagram/model/*.cc + include: + # Only include entities from the following namespaces + namespaces: + - clanguml::common::model + - clanguml::class_diagram::model + exclude: + # Do not include private members and methods in the diagram + scopes: + - private + # Entities from this namespace will be shortened + # (can only contain one element at the moment) + using_namespace: + - clanguml::class_diagram::model + plantuml: + # Add this line to the beginning of the resulting puml file + before: + - 'title clang-uml class diagram model' +``` \ No newline at end of file From d50a45b033f017f1a28c74f328b6e1d6db7e1316 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Wed, 16 Feb 2022 22:03:25 +0100 Subject: [PATCH 18/18] Updated configuration file docs --- docs/configuration_file.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/configuration_file.md b/docs/configuration_file.md index d4cab6b8..41d4bbb8 100644 --- a/docs/configuration_file.md +++ b/docs/configuration_file.md @@ -7,7 +7,7 @@ the key of the diagram YAML node ### Diagram options -* `type` - type of diagram, one of [`class`, `sequence`] +* `type` - type of diagram, one of [`class`, `sequence`, `package`] * `glob` - list of glob patterns to match source code files for analysis * `include_relations_also_as_members` - when set to `false`, class members for relationships are rendered in UML are skipped from class definition (default: `true`) * `generate_method_arguments` - determines whether the class diagrams methods contain full arguments (`full`), are abbreviated (`abbreviated`) or skipped (`none`) @@ -22,6 +22,7 @@ * `relationships` - list of relationships to exclude * `entity_types` - list of entity types to exclude (e.g. `class`, `enum`) * `scopes` - list of visibility scopes to exclude (e.g. `private`) +* `layout` - add layout hints for entities (classes, packages) * `plantuml` - verbatim PlantUML directives which should be added to a diagram * `before` - list of directives which will be added before the generated diagram * `after` - list of directives which will be added after the generated diagram @@ -61,6 +62,11 @@ diagrams: # Do not include private members and methods in the diagram scopes: - private + layout: + # Add layout hints for PlantUML + ClassA: + - up: ClassB + - left: ClassC # Entities from this namespace will be shortened # (can only contain one element at the moment) using_namespace: