diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4fd30b9a..47ee668b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,8 +11,12 @@ jobs: with: submodules: recursive - name: Install deps - run: sudo apt install ccache cmake libyaml-cpp-dev libfmt-dev libspdlog-dev clang-12 libclang-12-dev libclang-cpp12-dev + run: sudo apt install git make gcc-10 g++-10 ccache cmake libyaml-cpp-dev libfmt-dev libspdlog-dev clang-12 libclang-12-dev libclang-cpp12-dev + - name: Select g++ version + run: | + sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 10 + sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 10 - name: Build and unit test run: | - make debug + NUMPROC=2 make debug make test diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..5ffd0386 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1 @@ +Just be nice diff --git a/Makefile b/Makefile index cc053baa..516b97d8 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,8 @@ .DEFAULT_GOAL := debug +NUMPROC ?= $(shell nproc) + .PHONY: clean clean: rm -rf debug release @@ -35,7 +37,8 @@ release/CMakeLists.txt: -DCMAKE_BUILD_TYPE=Release debug: debug/CMakeLists.txt - make -C debug -j + echo "Using ${NUMPROC} cores" + make -C debug -j$(NUMPROC) release: release/CMakeLists.txt make -C release -j diff --git a/README.md b/README.md index e253dd24..f48a44fd 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ![linux build](https://github.com/bkryza/clang-uml/actions/workflows/build.yml/badge.svg) -`clang-uml` is an automatic [PlantUML](https://plantuml.com) class and sequence +`clang-uml` is an automatic C++ to [PlantUML](https://plantuml.com) class and sequence diagram generator, driven by YAML configuration files. The main idea behind the project is to easily maintain up-to-date diagrams within a code-base or document existing project code. The configuration file or files for `clang-uml` define the diff --git a/docs/test_cases/t00002_class.png b/docs/test_cases/t00002_class.png index a2d1b5fe..c7cabb63 100644 Binary files a/docs/test_cases/t00002_class.png and b/docs/test_cases/t00002_class.png differ diff --git a/docs/test_cases/t00003_class.png b/docs/test_cases/t00003_class.png index 38013897..b6c50039 100644 Binary files a/docs/test_cases/t00003_class.png and b/docs/test_cases/t00003_class.png differ diff --git a/docs/test_cases/t00004_class.png b/docs/test_cases/t00004_class.png index b3959579..5d31b5c1 100644 Binary files a/docs/test_cases/t00004_class.png and b/docs/test_cases/t00004_class.png differ diff --git a/docs/test_cases/t00005_class.png b/docs/test_cases/t00005_class.png index a3e20bd9..86b95ac4 100644 Binary files a/docs/test_cases/t00005_class.png and b/docs/test_cases/t00005_class.png differ diff --git a/docs/test_cases/t00006_class.png b/docs/test_cases/t00006_class.png index 2da7c717..23133f84 100644 Binary files a/docs/test_cases/t00006_class.png and b/docs/test_cases/t00006_class.png differ diff --git a/docs/test_cases/t00007_class.png b/docs/test_cases/t00007_class.png index 28ccdff4..a7081e0f 100644 Binary files a/docs/test_cases/t00007_class.png and b/docs/test_cases/t00007_class.png differ diff --git a/docs/test_cases/t00008_class.png b/docs/test_cases/t00008_class.png index 0cd44f40..c77d374e 100644 Binary files a/docs/test_cases/t00008_class.png and b/docs/test_cases/t00008_class.png differ diff --git a/docs/test_cases/t00009_class.png b/docs/test_cases/t00009_class.png index 0dab4be7..3024da07 100644 Binary files a/docs/test_cases/t00009_class.png and b/docs/test_cases/t00009_class.png differ diff --git a/docs/test_cases/t00010_class.png b/docs/test_cases/t00010_class.png index d6f78220..920fd9a5 100644 Binary files a/docs/test_cases/t00010_class.png and b/docs/test_cases/t00010_class.png differ diff --git a/docs/test_cases/t00011_class.png b/docs/test_cases/t00011_class.png index 62e35eff..0e648478 100644 Binary files a/docs/test_cases/t00011_class.png and b/docs/test_cases/t00011_class.png differ diff --git a/docs/test_cases/t00012_class.png b/docs/test_cases/t00012_class.png index 63bc6179..ad78b4ba 100644 Binary files a/docs/test_cases/t00012_class.png and b/docs/test_cases/t00012_class.png differ diff --git a/docs/test_cases/t00013_class.png b/docs/test_cases/t00013_class.png index fb39642f..6e24d861 100644 Binary files a/docs/test_cases/t00013_class.png and b/docs/test_cases/t00013_class.png differ diff --git a/docs/test_cases/t00014_class.png b/docs/test_cases/t00014_class.png index 0954ed16..fcf58d9e 100644 Binary files a/docs/test_cases/t00014_class.png and b/docs/test_cases/t00014_class.png differ diff --git a/docs/test_cases/t00015_class.png b/docs/test_cases/t00015_class.png index 1689be22..254b39c9 100644 Binary files a/docs/test_cases/t00015_class.png and b/docs/test_cases/t00015_class.png differ diff --git a/docs/test_cases/t00016_class.png b/docs/test_cases/t00016_class.png index 0259e361..4b443082 100644 Binary files a/docs/test_cases/t00016_class.png and b/docs/test_cases/t00016_class.png differ diff --git a/docs/test_cases/t00017_class.png b/docs/test_cases/t00017_class.png index 32d0fa72..521b89a4 100644 Binary files a/docs/test_cases/t00017_class.png and b/docs/test_cases/t00017_class.png differ diff --git a/docs/test_cases/t00018.md b/docs/test_cases/t00018.md index 1b72af09..760615a8 100644 --- a/docs/test_cases/t00018.md +++ b/docs/test_cases/t00018.md @@ -17,36 +17,6 @@ diagrams: ``` ## Source code -File t00018_impl.cc -```cpp -#include "t00018_impl.h" -#include "t00018.h" - -namespace clanguml { -namespace t00018 { -namespace impl { - -widget::widget(int n) - : n(n) -{ -} - -void widget::draw(const clanguml::t00018::widget &w) const -{ - if (w.shown()) - std::cout << "drawing a const widget " << n << '\n'; -} - -void widget::draw(const clanguml::t00018::widget &w) -{ - if (w.shown()) - std::cout << "drawing a non-const widget " << n << '\n'; -} -} -} -} - -``` File t00018_impl.h ```cpp #pragma once @@ -131,6 +101,36 @@ widget &widget::operator=(widget &&) = default; } } +``` +File t00018_impl.cc +```cpp +#include "t00018_impl.h" +#include "t00018.h" + +namespace clanguml { +namespace t00018 { +namespace impl { + +widget::widget(int n) + : n(n) +{ +} + +void widget::draw(const clanguml::t00018::widget &w) const +{ + if (w.shown()) + std::cout << "drawing a const widget " << n << '\n'; +} + +void widget::draw(const clanguml::t00018::widget &w) +{ + if (w.shown()) + std::cout << "drawing a non-const widget " << n << '\n'; +} +} +} +} + ``` ## Generated UML diagrams ![t00018_class](./t00018_class.png "Pimpl pattern") diff --git a/docs/test_cases/t00018_class.png b/docs/test_cases/t00018_class.png index c3e3fa3b..1962786d 100644 Binary files a/docs/test_cases/t00018_class.png and b/docs/test_cases/t00018_class.png differ diff --git a/docs/test_cases/t00019.md b/docs/test_cases/t00019.md index 70d96ba5..9bd7c2b1 100644 --- a/docs/test_cases/t00019.md +++ b/docs/test_cases/t00019.md @@ -17,21 +17,25 @@ diagrams: ``` ## Source code -File t00019.cc +File t00019_layer2.h ```cpp -#include "t00019_base.h" -#include "t00019_layer1.h" -#include "t00019_layer2.h" -#include "t00019_layer3.h" - -#include +#pragma once namespace clanguml { namespace t00019 { -class A { -public: - std::unique_ptr>>> layers; +template class Layer2 : public LowerLayer { + + using LowerLayer::LowerLayer; + + using LowerLayer::m1; + + using LowerLayer::m2; + + int all_calls_count() const + { + return LowerLayer::m1_calls() + LowerLayer::m2_calls(); + } }; } } @@ -89,6 +93,26 @@ template class Layer1 : public LowerLayer { } } +``` +File t00019.cc +```cpp +#include "t00019_base.h" +#include "t00019_layer1.h" +#include "t00019_layer2.h" +#include "t00019_layer3.h" + +#include + +namespace clanguml { +namespace t00019 { + +class A { +public: + std::unique_ptr>>> layers; +}; +} +} + ``` File t00019_layer3.h ```cpp @@ -126,30 +150,6 @@ private: } } -``` -File t00019_layer2.h -```cpp -#pragma once - -namespace clanguml { -namespace t00019 { - -template class Layer2 : public LowerLayer { - - using LowerLayer::LowerLayer; - - using LowerLayer::m1; - - using LowerLayer::m2; - - int all_calls_count() const - { - return LowerLayer::m1_calls() + LowerLayer::m2_calls(); - } -}; -} -} - ``` ## Generated UML diagrams ![t00019_class](./t00019_class.png "Layercake pattern") diff --git a/docs/test_cases/t00019_class.png b/docs/test_cases/t00019_class.png index 9afcc255..04cdc046 100644 Binary files a/docs/test_cases/t00019_class.png and b/docs/test_cases/t00019_class.png differ diff --git a/docs/test_cases/t00020_class.png b/docs/test_cases/t00020_class.png index c7df1d23..acc44a80 100644 Binary files a/docs/test_cases/t00020_class.png and b/docs/test_cases/t00020_class.png differ diff --git a/docs/test_cases/t00021_class.png b/docs/test_cases/t00021_class.png index aacdaa00..8beb9d59 100644 Binary files a/docs/test_cases/t00021_class.png and b/docs/test_cases/t00021_class.png differ diff --git a/docs/test_cases/t00022_class.png b/docs/test_cases/t00022_class.png index 6fc33aea..101b46c9 100644 Binary files a/docs/test_cases/t00022_class.png and b/docs/test_cases/t00022_class.png differ diff --git a/docs/test_cases/t00023_class.png b/docs/test_cases/t00023_class.png index a94059a5..3e7c4112 100644 Binary files a/docs/test_cases/t00023_class.png and b/docs/test_cases/t00023_class.png differ diff --git a/docs/test_cases/t00024_class.png b/docs/test_cases/t00024_class.png index d21b6826..f66f0bb9 100644 Binary files a/docs/test_cases/t00024_class.png and b/docs/test_cases/t00024_class.png differ diff --git a/docs/test_cases/t00025_class.png b/docs/test_cases/t00025_class.png index e04810f0..e14192c1 100644 Binary files a/docs/test_cases/t00025_class.png and b/docs/test_cases/t00025_class.png differ diff --git a/docs/test_cases/t00026_class.png b/docs/test_cases/t00026_class.png index 76da28b8..34205bc5 100644 Binary files a/docs/test_cases/t00026_class.png and b/docs/test_cases/t00026_class.png differ diff --git a/docs/test_cases/t00027_class.png b/docs/test_cases/t00027_class.png index 8b18184c..0a68d68e 100644 Binary files a/docs/test_cases/t00027_class.png and b/docs/test_cases/t00027_class.png differ diff --git a/docs/test_cases/t00028_class.png b/docs/test_cases/t00028_class.png index 36b290d1..88458f63 100644 Binary files a/docs/test_cases/t00028_class.png and b/docs/test_cases/t00028_class.png differ diff --git a/docs/test_cases/t00029_class.png b/docs/test_cases/t00029_class.png index ec015724..46c0fd08 100644 Binary files a/docs/test_cases/t00029_class.png and b/docs/test_cases/t00029_class.png differ diff --git a/docs/test_cases/t00030_class.png b/docs/test_cases/t00030_class.png index f76932e7..c3eab966 100644 Binary files a/docs/test_cases/t00030_class.png and b/docs/test_cases/t00030_class.png differ diff --git a/docs/test_cases/t00031_class.png b/docs/test_cases/t00031_class.png index bc5ca0fb..2ad5ff2d 100644 Binary files a/docs/test_cases/t00031_class.png and b/docs/test_cases/t00031_class.png differ diff --git a/docs/test_cases/t00032_class.png b/docs/test_cases/t00032_class.png index ff515338..45a7d7e3 100644 Binary files a/docs/test_cases/t00032_class.png and b/docs/test_cases/t00032_class.png differ diff --git a/docs/test_cases/t00033_class.png b/docs/test_cases/t00033_class.png index ded3a806..0d6f7678 100644 Binary files a/docs/test_cases/t00033_class.png and b/docs/test_cases/t00033_class.png differ diff --git a/docs/test_cases/t20001_sequence.png b/docs/test_cases/t20001_sequence.png index 99576880..e972c3f5 100644 Binary files a/docs/test_cases/t20001_sequence.png and b/docs/test_cases/t20001_sequence.png differ diff --git a/docs/test_cases/t90000_class.png b/docs/test_cases/t90000_class.png index 643f4b36..3a516c01 100644 Binary files a/docs/test_cases/t90000_class.png and b/docs/test_cases/t90000_class.png differ diff --git a/src/puml/class_diagram_generator.cc b/src/class_diagram/generators/plantuml/class_diagram_generator.cc similarity index 66% rename from src/puml/class_diagram_generator.cc rename to src/class_diagram/generators/plantuml/class_diagram_generator.cc index 56a38b6b..afa2486f 100644 --- a/src/puml/class_diagram_generator.cc +++ b/src/class_diagram/generators/plantuml/class_diagram_generator.cc @@ -1,5 +1,5 @@ /** - * src/puml/class_diagram_generator.cc + * src/class_diagram/generators/plantuml/class_diagram_generator.cc * * Copyright (c) 2021 Bartek Kryza * @@ -18,9 +18,10 @@ #include "class_diagram_generator.h" -namespace clanguml::generators::class_diagram { +#include "util/error.h" + +namespace clanguml::class_diagram::generators::plantuml { -namespace puml { std::string relative_to(std::string n, std::string c) { if (c.rfind(n) == std::string::npos) @@ -29,10 +30,6 @@ std::string relative_to(std::string n, std::string c) return c.substr(n.size() + 2); } -// -// generator -// - generator::generator( clanguml::config::class_diagram &config, diagram_model &model) : m_config(config) @@ -106,7 +103,7 @@ void generator::generate_alias(const class_ &c, std::ostream &ostr) const if (c.is_abstract()) class_type = "abstract"; - ostr << class_type << " \"" << c.full_name(m_config.using_namespace); + ostr << class_type << " \"" << c.full_name(); ostr << "\" as " << c.alias() << '\n'; } @@ -114,7 +111,7 @@ void generator::generate_alias(const class_ &c, std::ostream &ostr) const void generator::generate_alias(const enum_ &e, std::ostream &ostr) const { ostr << "enum" - << " \"" << e.full_name(m_config.using_namespace); + << " \"" << e.full_name(); ostr << "\" as " << e.alias() << '\n'; } @@ -130,32 +127,32 @@ void generator::generate(const class_ &c, std::ostream &ostr) const ostr << class_type << " " << c.alias(); - if (!c.style.empty()) - ostr << " " << c.style; + if (!c.style().empty()) + ostr << " " << c.style(); ostr << " {" << '\n'; // // Process methods // - for (const auto &m : c.methods) { - if (!m_config.should_include(m.scope)) + for (const auto &m : c.methods()) { + if (!m_config.should_include(m.scope())) continue; - if (m.is_pure_virtual) + if (m.is_pure_virtual()) ostr << "{abstract} "; - if (m.is_static) + if (m.is_static()) ostr << "{static} "; - std::string type{m.type}; + std::string type{m.type()}; - ostr << to_string(m.scope) << m.name; + ostr << to_string(m.scope()) << m.name(); ostr << "("; if (true) { // TODO: add option to disable parameter generation std::vector params; - std::transform(m.parameters.begin(), m.parameters.end(), + std::transform(m.parameters().cbegin(), m.parameters().cend(), std::back_inserter(params), [this](const auto &mp) { return mp.to_string(m_config.using_namespace); }); @@ -163,15 +160,15 @@ void generator::generate(const class_ &c, std::ostream &ostr) const } ostr << ")"; - if (m.is_const) + if (m.is_const()) ostr << " const"; - assert(!(m.is_pure_virtual && m.is_defaulted)); + assert(!(m.is_pure_virtual() && m.is_defaulted())); - if (m.is_pure_virtual) + if (m.is_pure_virtual()) ostr << " = 0"; - if (m.is_defaulted) + if (m.is_defaulted()) ostr << " = default"; ostr << " : " << ns_relative(uns, type); @@ -186,49 +183,35 @@ 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))) + for (const auto &r : c.relationships()) { + if (!m_config.should_include_relationship(name(r.type()))) continue; - LOG_DBG("== Processing relationship {}", to_string(r.type)); + LOG_DBG("== Processing relationship {}", to_string(r.type())); std::stringstream relstr; std::string destination; try { - if (r.destination.find("#") != std::string::npos || - r.destination.find("@") != std::string::npos) { - destination = m_model.usr_to_name(uns, r.destination); - - // If something went wrong and we have an empty destination - // generate the relationship but comment it out for - // debugging - if (destination.empty()) { - relstr << "' "; - destination = r.destination; - } - } - else { - destination = r.destination; - } + destination = r.destination(); LOG_DBG("=== Destination is: {}", destination); std::string puml_relation; - if (!r.multiplicity_source.empty()) - puml_relation += "\"" + r.multiplicity_source + "\" "; + if (!r.multiplicity_source().empty()) + puml_relation += "\"" + r.multiplicity_source() + "\" "; - puml_relation += to_string(r.type, r.style); + puml_relation += to_string(r.type(), r.style()); - if (!r.multiplicity_destination.empty()) - puml_relation += " \"" + r.multiplicity_destination + "\""; + if (!r.multiplicity_destination().empty()) + puml_relation += " \"" + r.multiplicity_destination() + "\""; - relstr << m_model.to_alias(uns, ns_relative(uns, c.full_name(uns))) - << " " << puml_relation << " " - << m_model.to_alias(uns, ns_relative(uns, destination)); + relstr << m_model.to_alias(ns_relative(uns, c.full_name())) << " " + << puml_relation << " " + << m_model.to_alias(ns_relative(uns, destination)); - if (!r.label.empty()) { - relstr << " : " << to_string(r.scope) << r.label; - rendered_relations.emplace(r.label); + if (!r.label().empty()) { + relstr << " : " << to_string(r.scope()) << r.label(); + rendered_relations.emplace(r.label()); } if (unique_relations.count(relstr.str()) == 0) { @@ -244,52 +227,51 @@ 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(uns), destination, e.what()); + to_string(r.type()), c.full_name(), destination, e.what()); } } // // Process members // - for (const auto &m : c.members) { - if (!m_config.should_include(m.scope)) + for (const auto &m : c.members()) { + if (!m_config.should_include(m.scope())) continue; if (!m_config.include_relations_also_as_members && - rendered_relations.find(m.name) != rendered_relations.end()) + rendered_relations.find(m.name()) != rendered_relations.end()) continue; - if (m.is_static) + if (m.is_static()) ostr << "{static} "; - ostr << to_string(m.scope) << m.name << " : " - << ns_relative(uns, m.type) << '\n'; + ostr << to_string(m.scope()) << m.name() << " : " + << ns_relative(uns, m.type()) << '\n'; } ostr << "}" << '\n'; if (m_config.should_include_relationship("inheritance")) - for (const auto &b : c.bases) { + for (const auto &b : c.parents()) { std::stringstream relstr; try { - relstr << m_model.to_alias(uns, ns_relative(uns, b.name)) + relstr << m_model.to_alias(ns_relative(uns, b.name())) << " <|-- " - << m_model.to_alias( - uns, ns_relative(uns, c.full_name(uns))) + << m_model.to_alias(ns_relative(uns, c.full_name())) << '\n'; ostr << relstr.str(); } catch (error::uml_alias_missing &e) { LOG_ERROR("=== Skipping inheritance relation from {} to {} due " "to: {}", - b.name, c.name, e.what()); + b.name(), c.name(), e.what()); } } // // Process notes // - for (auto decorator : c.decorators) { + 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' @@ -306,45 +288,35 @@ void generator::generate(const enum_ &e, std::ostream &ostr) const { ostr << "enum " << e.alias(); - if (!e.style.empty()) - ostr << " " << e.style; + if (!e.style().empty()) + ostr << " " << e.style(); ostr << " {" << '\n'; - for (const auto &enum_constant : e.constants) { + for (const auto &enum_constant : e.constants()) { ostr << enum_constant << '\n'; } ostr << "}" << '\n'; - for (const auto &r : e.relationships) { - if (!m_config.should_include_relationship(name(r.type))) + for (const auto &r : e.relationships()) { + if (!m_config.should_include_relationship(name(r.type()))) continue; std::string destination; std::stringstream relstr; try { - if (r.destination.find("#") != std::string::npos || - r.destination.find("@") != std::string::npos) { - destination = m_model.usr_to_name( - m_config.using_namespace, r.destination); - if (destination.empty()) { - relstr << "' "; - destination = r.destination; - } - } - else { - destination = r.destination; - } - relstr << m_model.to_alias(m_config.using_namespace, - ns_relative(m_config.using_namespace, e.name)) - << " " << to_string(r.type) << " " - << m_model.to_alias(m_config.using_namespace, + destination = r.destination(); + + relstr << m_model.to_alias( + ns_relative(m_config.using_namespace, e.name())) + << " " << to_string(r.type()) << " " + << m_model.to_alias( ns_relative(m_config.using_namespace, destination)); - if (!r.label.empty()) - relstr << " : " << r.label; + if (!r.label().empty()) + relstr << " : " << r.label(); relstr << '\n'; @@ -353,14 +325,14 @@ 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.name, destination, ex.what()); + to_string(r.type()), e.full_name(), destination, ex.what()); } } // // Process notes // - for (auto decorator : e.decorators) { + 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' @@ -378,9 +350,8 @@ void generator::generate(std::ostream &ostr) const std::string note{b}; std::tuple alias_match; while (util::find_element_alias(note, alias_match)) { - auto alias = m_model.to_alias(m_config.using_namespace, - ns_relative( - m_config.using_namespace, std::get<0>(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); } @@ -388,24 +359,24 @@ void generator::generate(std::ostream &ostr) const } if (m_config.should_include_entities("classes")) { - for (const auto &c : m_model.classes) { - if (!c.is_template_instantiation && - !m_config.should_include(c.name)) + for (const auto &c : m_model.classes()) { + if (!c.is_template_instantiation() && + !m_config.should_include(c.name())) continue; generate_alias(c, ostr); ostr << '\n'; } - for (const auto &e : m_model.enums) { - if (!m_config.should_include(e.name)) + for (const auto &e : m_model.enums()) { + if (!m_config.should_include(e.name())) continue; generate_alias(e, ostr); ostr << '\n'; } - for (const auto &c : m_model.classes) { - if (!c.is_template_instantiation && - !m_config.should_include(c.name)) + for (const auto &c : m_model.classes()) { + if (!c.is_template_instantiation() && + !m_config.should_include(c.name())) continue; generate(c, ostr); ostr << '\n'; @@ -413,7 +384,7 @@ void generator::generate(std::ostream &ostr) const } if (m_config.should_include_entities("enums")) - for (const auto &e : m_model.enums) { + for (const auto &e : m_model.enums()) { generate(e, ostr); ostr << '\n'; } @@ -423,9 +394,8 @@ void generator::generate(std::ostream &ostr) const std::string note{b}; std::tuple alias_match; while (util::find_element_alias(note, alias_match)) { - auto alias = m_model.to_alias(m_config.using_namespace, - ns_relative( - m_config.using_namespace, std::get<0>(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); } @@ -439,15 +409,14 @@ std::ostream &operator<<(std::ostream &os, const generator &g) g.generate(os); return os; } -} // namespace puml -clanguml::model::class_diagram::diagram generate( +clanguml::class_diagram::model::diagram generate( cppast::libclang_compilation_database &db, const std::string &name, clanguml::config::class_diagram &diagram) { spdlog::info("Generating diagram {}.puml", name); - clanguml::model::class_diagram::diagram d; - d.name = name; + clanguml::class_diagram::model::diagram d; + d.set_name(name); // Get all translation units matching the glob from diagram // configuration @@ -464,7 +433,8 @@ clanguml::model::class_diagram::diagram generate( type_safe::ref(idx)}; // Process all matching translation units - clanguml::visitor::class_diagram::tu_visitor ctx(idx, d, diagram); + 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); diff --git a/src/puml/class_diagram_generator.h b/src/class_diagram/generators/plantuml/class_diagram_generator.h similarity index 73% rename from src/puml/class_diagram_generator.h rename to src/class_diagram/generators/plantuml/class_diagram_generator.h index 8ead962c..52d5b565 100644 --- a/src/puml/class_diagram_generator.h +++ b/src/class_diagram/generators/plantuml/class_diagram_generator.h @@ -1,5 +1,5 @@ /** - * src/puml/class_diagram_generator.h + * src/class_diagram/generators/plantuml/class_diagram_generator.h * * Copyright (c) 2021 Bartek Kryza * @@ -17,10 +17,13 @@ */ #pragma once +#include "class_diagram/model/class.h" +#include "class_diagram/model/class_relationship.h" +#include "class_diagram/model/diagram.h" +#include "class_diagram/model/enum.h" +#include "class_diagram/visitor/translation_unit_visitor.h" #include "config/config.h" #include "cx/compilation_database.h" -#include "uml/class_diagram_model.h" -#include "uml/class_diagram_visitor.h" #include "util/util.h" #include @@ -33,16 +36,16 @@ #include namespace clanguml { -namespace generators { namespace class_diagram { -namespace puml { +namespace generators { +namespace plantuml { -using diagram_config = clanguml::config::class_diagram::diagram; -using diagram_model = clanguml::model::class_diagram::diagram; -using clanguml::model::class_diagram::class_; -using clanguml::model::class_diagram::enum_; -using clanguml::model::class_diagram::relationship_t; -using clanguml::model::class_diagram::scope_t; +using diagram_config = clanguml::class_diagram::model::diagram; +using diagram_model = clanguml::class_diagram::model::diagram; +using clanguml::class_diagram::model::class_; +using clanguml::class_diagram::model::enum_; +using clanguml::class_diagram::model::relationship_t; +using clanguml::class_diagram::model::scope_t; using namespace clanguml::util; std::string relative_to(std::string n, std::string c); @@ -74,12 +77,11 @@ private: diagram_model &m_model; }; -} - -clanguml::model::class_diagram::diagram generate( +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/model/class.cc b/src/class_diagram/model/class.cc new file mode 100644 index 00000000..3d851e06 --- /dev/null +++ b/src/class_diagram/model/class.cc @@ -0,0 +1,143 @@ +/** + * src/class_diagram/model/class.h + * + * Copyright (c) 2021 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 "class.h" + +#include "util/util.h" + +#include + +namespace clanguml::class_diagram::model { + +class_::class_(const std::vector &using_namespaces) + : element{using_namespaces} +{ +} + +bool class_::is_struct() const { return is_struct_; } + +void class_::is_struct(bool is_struct) { is_struct_ = is_struct; } + +bool class_::is_template() const { return is_template_; } + +void class_::is_template(bool is_template) { is_template_ = is_template; } + +bool class_::is_template_instantiation() const +{ + return is_template_instantiation_; +} + +void class_::is_template_instantiation(bool is_template_instantiation) +{ + is_template_instantiation_ = is_template_instantiation; +} + +void class_::add_member(class_member &&member) +{ + members_.emplace_back(std::move(member)); +} + +void class_::add_method(class_method &&method) +{ + methods_.emplace_back(std::move(method)); +} + +void class_::add_parent(class_parent &&parent) +{ + bases_.emplace_back(std::move(parent)); +} + +void class_::add_template(class_template &&tmplt) +{ + templates_.emplace_back(std::move(tmplt)); +} + +const std::vector &class_::members() const { return members_; } + +const std::vector &class_::methods() const { return methods_; } + +const std::vector &class_::parents() const { return bases_; } + +const std::vector &class_::templates() const +{ + return templates_; +} + +void class_::set_base_template(const std::string &full_name) +{ + base_template_full_name_ = full_name; +} + +std::string class_::base_template() const { return base_template_full_name_; } + +bool operator==(const class_ &l, const class_ &r) +{ + return l.full_name() == r.full_name(); +} + +void class_::add_type_alias(type_alias &&ta) +{ + LOG_DBG("Adding class alias: {} -> {}", ta.alias(), ta.underlying_type()); + type_aliases_[ta.alias()] = std::move(ta); +} + +std::string class_::full_name(bool relative) const +{ + using namespace clanguml::util; + + std::ostringstream ostr; + if (relative) + ostr << ns_relative(using_namespaces(), name()); + else + ostr << name(); + + if (!templates_.empty()) { + std::vector tnames; + std::transform(templates_.cbegin(), templates_.cend(), + std::back_inserter(tnames), [this](const auto &tmplt) { + std::vector res; + + if (!tmplt.type().empty()) + res.push_back( + ns_relative(using_namespaces(), tmplt.type())); + + if (!tmplt.name().empty()) + res.push_back( + ns_relative(using_namespaces(), tmplt.name())); + + if (!tmplt.default_value().empty()) { + res.push_back("="); + res.push_back(tmplt.default_value()); + } + + return fmt::format("{}", fmt::join(res, " ")); + }); + ostr << fmt::format("<{}>", fmt::join(tnames, ",")); + } + + return ostr.str(); +} + +bool class_::is_abstract() const +{ + // TODO check if all base abstract methods are overriden + // with non-abstract methods + return std::any_of(methods_.begin(), methods_.end(), + [](const auto &method) { return method.is_pure_virtual(); }); +} +} diff --git a/src/class_diagram/model/class.h b/src/class_diagram/model/class.h new file mode 100644 index 00000000..e25d83b5 --- /dev/null +++ b/src/class_diagram/model/class.h @@ -0,0 +1,82 @@ +/** + * src/class_diagram/model/class.h + * + * Copyright (c) 2021 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 "class_member.h" +#include "class_method.h" +#include "class_parent.h" +#include "class_template.h" +#include "element.h" +#include "enums.h" +#include "stylable_element.h" +#include "type_alias.h" + +#include +#include + +namespace clanguml::class_diagram::model { + +class class_ : public element, public stylable_element { +public: + class_(const std::vector &using_namespaces); + + bool is_struct() const; + void is_struct(bool is_struct); + + bool is_template() const; + void is_template(bool is_template); + + bool is_template_instantiation() const; + void is_template_instantiation(bool is_template_instantiation); + + void add_member(class_member &&member); + void add_method(class_method &&method); + void add_parent(class_parent &&parent); + void add_template(class_template &&tmplt); + + const std::vector &members() const; + const std::vector &methods() const; + const std::vector &parents() const; + const std::vector &templates() const; + + void set_base_template(const std::string &full_name); + std::string base_template() const; + + friend bool operator==(const class_ &l, const class_ &r); + + void add_type_alias(type_alias &&ta); + + std::string full_name(bool relative = true) const override; + + bool is_abstract() const; + +private: + bool is_struct_{false}; + bool is_template_{false}; + bool is_template_instantiation_{false}; + std::vector members_; + std::vector methods_; + std::vector bases_; + std::vector templates_; + std::string base_template_full_name_; + std::map type_aliases_; + + std::string full_name_; +}; + +} diff --git a/src/class_diagram/model/class_element.cc b/src/class_diagram/model/class_element.cc new file mode 100644 index 00000000..02157ad8 --- /dev/null +++ b/src/class_diagram/model/class_element.cc @@ -0,0 +1,37 @@ +/** + * src/class_diagram/model/class_element.cc + * + * Copyright (c) 2021 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 "class_element.h" + +namespace clanguml::class_diagram::model { + +class_element::class_element( + scope_t scope, const std::string &name, const std::string &type) + : scope_{scope} + , name_{name} + , type_{type} +{ +} + +scope_t class_element::scope() const { return scope_; } + +std::string class_element::name() const { return name_; } + +std::string class_element::type() const { return type_; } + +} diff --git a/src/class_diagram/model/class_element.h b/src/class_diagram/model/class_element.h new file mode 100644 index 00000000..7f741f56 --- /dev/null +++ b/src/class_diagram/model/class_element.h @@ -0,0 +1,41 @@ +/** + * src/class_diagram/model/class_element.h + * + * Copyright (c) 2021 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 "decorated_element.h" + +#include + +namespace clanguml::class_diagram::model { + +class class_element : public decorated_element { +public: + class_element( + scope_t scope, const std::string &name, const std::string &type); + + scope_t scope() const; + std::string name() const; + std::string type() const; + +private: + scope_t scope_; + std::string name_; + std::string type_; +}; + +} diff --git a/src/class_diagram/model/class_member.cc b/src/class_diagram/model/class_member.cc new file mode 100644 index 00000000..50f37160 --- /dev/null +++ b/src/class_diagram/model/class_member.cc @@ -0,0 +1,40 @@ +/** + * src/class_diagram/model/class_member.cc + * + * Copyright (c) 2021 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 "class_member.h" + +namespace clanguml::class_diagram::model { + +class_member::class_member( + scope_t scope, const std::string &name, const std::string &type) + : class_element{scope, name, type} +{ +} + +bool class_member::is_relationship() const { return is_relationship_; } + +void class_member::is_relationship(bool is_relationship) +{ + is_relationship_ = is_relationship; +} + +bool class_member::is_static() const { return is_static_; } + +void class_member::is_static(bool is_static) { is_static_ = is_static; } + +} diff --git a/src/class_diagram/model/class_member.h b/src/class_diagram/model/class_member.h new file mode 100644 index 00000000..f04cbdf3 --- /dev/null +++ b/src/class_diagram/model/class_member.h @@ -0,0 +1,42 @@ +/** + * src/class_diagram/model/class_member.h + * + * Copyright (c) 2021 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 "class_element.h" + +#include + +namespace clanguml::class_diagram::model { + +class class_member : public class_element { +public: + class_member( + scope_t scope, const std::string &name, const std::string &type); + + bool is_relationship() const; + void is_relationship(bool is_relationship); + + bool is_static() const; + void is_static(bool is_static); + +private: + bool is_relationship_{false}; + bool is_static_{false}; +}; + +} diff --git a/src/class_diagram/model/class_method.cc b/src/class_diagram/model/class_method.cc new file mode 100644 index 00000000..745a3b55 --- /dev/null +++ b/src/class_diagram/model/class_method.cc @@ -0,0 +1,64 @@ +/** + * src/class_diagram/model/class_method.cc + * + * Copyright (c) 2021 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 "class_method.h" + +namespace clanguml::class_diagram::model { + +class_method::class_method( + scope_t scope, const std::string &name, const std::string &type) + : class_element{scope, name, type} +{ +} + +bool class_method::is_pure_virtual() const { return is_pure_virtual_; } + +void class_method::is_pure_virtual(bool is_pure_virtual) +{ + is_pure_virtual_ = is_pure_virtual; +} + +bool class_method::is_virtual() const { return is_virtual_; } + +void class_method::is_virtual(bool is_virtual) { is_virtual_ = is_virtual; } + +bool class_method::is_const() const { return is_const_; } + +void class_method::is_const(bool is_const) { is_const_ = is_const; } + +bool class_method::is_defaulted() const { return is_defaulted_; } + +void class_method::is_defaulted(bool is_defaulted) +{ + is_defaulted_ = is_defaulted; +} + +bool class_method::is_static() const { return is_static_; } + +void class_method::is_static(bool is_static) { is_static_ = is_static; } + +const std::vector &class_method::parameters() const +{ + return parameters_; +} + +void class_method::add_parameter(method_parameter &¶meter) +{ + parameters_.emplace_back(std::move(parameter)); +} +} diff --git a/src/class_diagram/model/class_method.h b/src/class_diagram/model/class_method.h new file mode 100644 index 00000000..98a829ce --- /dev/null +++ b/src/class_diagram/model/class_method.h @@ -0,0 +1,59 @@ +/** + * src/class_diagram/model/class_method.h + * + * Copyright (c) 2021 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 "class_element.h" +#include "method_parameter.h" + +#include +#include + +namespace clanguml::class_diagram::model { + +class class_method : public class_element { +public: + class_method( + scope_t scope, const std::string &name, const std::string &type); + + bool is_pure_virtual() const; + void is_pure_virtual(bool is_pure_virtual); + + bool is_virtual() const; + void is_virtual(bool is_virtual); + + bool is_const() const; + void is_const(bool is_const); + + bool is_defaulted() const; + void is_defaulted(bool is_defaulted); + + bool is_static() const; + void is_static(bool is_static); + + const std::vector ¶meters() const; + void add_parameter(method_parameter &¶meter); + +private: + std::vector parameters_; + bool is_pure_virtual_{false}; + bool is_virtual_{false}; + bool is_const_{false}; + bool is_defaulted_{false}; + bool is_static_{false}; +}; +} diff --git a/src/class_diagram/model/class_parent.cc b/src/class_diagram/model/class_parent.cc new file mode 100644 index 00000000..ede58319 --- /dev/null +++ b/src/class_diagram/model/class_parent.cc @@ -0,0 +1,35 @@ +/** + * src/class_diagram/model/class_parent.cc + * + * Copyright (c) 2021 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 "class_parent.h" + +namespace clanguml::class_diagram::model { + +void class_parent::set_name(const std::string &name) { name_ = name; } + +std::string class_parent::name() const { return name_; } + +void class_parent::is_virtual(bool is_virtual) { is_virtual_ = is_virtual; } + +bool class_parent::is_virtual() const { return is_virtual_; } + +void class_parent::set_access(access_t access) { access_ = access; } + +access_t class_parent::access() const { return access_; } + +} diff --git a/src/class_diagram/model/class_parent.h b/src/class_diagram/model/class_parent.h new file mode 100644 index 00000000..56f2f6a7 --- /dev/null +++ b/src/class_diagram/model/class_parent.h @@ -0,0 +1,42 @@ +/** + * src/class_diagram/model/class_parent.h + * + * Copyright (c) 2021 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 "enums.h" + +#include + +namespace clanguml::class_diagram::model { + +class class_parent { +public: + void set_name(const std::string &name); + std::string name() const; + + void is_virtual(bool is_virtual); + bool is_virtual() const; + + void set_access(access_t access); + access_t access() const; + +private: + std::string name_; + bool is_virtual_{false}; + access_t access_; +}; +} diff --git a/src/class_diagram/model/class_relationship.cc b/src/class_diagram/model/class_relationship.cc new file mode 100644 index 00000000..7bb1ae8d --- /dev/null +++ b/src/class_diagram/model/class_relationship.cc @@ -0,0 +1,113 @@ +/** + * src/class_diagram/model/class_relationship.cc + * + * Copyright (c) 2021 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 "class_relationship.h" + +namespace clanguml::class_diagram::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"; + } +} + +class_relationship::class_relationship(relationship_t type, + const std::string &destination, scope_t scope, const std::string &label, + const std::string &multiplicity_source, + const std::string &multiplicity_destination) + : type_{type} + , destination_{destination} + , scope_{scope} + , label_{label} + , multiplicity_source_{multiplicity_source} + , multiplicity_destination_{multiplicity_destination} +{ +} + +void class_relationship::set_type(relationship_t type) noexcept +{ + type_ = type; +} + +relationship_t class_relationship::type() const noexcept { return type_; } + +void class_relationship::set_destination(const std::string &destination) +{ + destination_ = destination; +} + +std::string class_relationship::destination() const { return destination_; } + +void class_relationship::set_multiplicity_source( + const std::string &multiplicity_source) +{ + multiplicity_source_ = multiplicity_source; +} + +std::string class_relationship::multiplicity_source() const +{ + return multiplicity_source_; +} + +void class_relationship::set_multiplicity_destination( + const std::string &multiplicity_destination) +{ + multiplicity_destination_ = multiplicity_destination; +} + +std::string class_relationship::multiplicity_destination() const +{ + return multiplicity_destination_; +} + +void class_relationship::set_label(const std::string &label) { label_ = label; } + +std::string class_relationship::label() const { return label_; } + +void class_relationship::set_scope(scope_t scope) noexcept { scope_ = scope; } + +scope_t class_relationship::scope() const noexcept { return scope_; } + +bool operator==(const class_relationship &l, const class_relationship &r) +{ + return l.type() == r.type() && l.destination() == r.destination() && + l.label() == r.label(); +} +} diff --git a/src/class_diagram/model/class_relationship.h b/src/class_diagram/model/class_relationship.h new file mode 100644 index 00000000..dd364c85 --- /dev/null +++ b/src/class_diagram/model/class_relationship.h @@ -0,0 +1,68 @@ +/** + * src/class_diagram/model/class_relationship.h + * + * Copyright (c) 2021 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 "decorated_element.h" +#include "stylable_element.h" + +#include + +namespace clanguml::class_diagram::model { + +std::string to_string(relationship_t r); + +class class_relationship : public decorated_element, public stylable_element { +public: + class_relationship(relationship_t type, const std::string &destination, + scope_t scope = scope_t::kNone, const std::string &label = "", + const std::string &multiplicity_source = "", + const std::string &multiplicity_destination = ""); + + virtual ~class_relationship() = default; + + void set_type(relationship_t type) noexcept; + relationship_t type() const noexcept; + + void set_destination(const std::string &destination); + std::string destination() const; + + void set_multiplicity_source(const std::string &multiplicity_source); + std::string multiplicity_source() const; + + void set_multiplicity_destination( + const std::string &multiplicity_destination); + std::string multiplicity_destination() const; + + void set_label(const std::string &label); + std::string label() const; + + void set_scope(scope_t scope) noexcept; + scope_t scope() const noexcept; + + friend bool operator==( + const class_relationship &l, const class_relationship &r); + +private: + relationship_t type_{relationship_t::kAssociation}; + std::string destination_; + std::string multiplicity_source_; + std::string multiplicity_destination_; + std::string label_; + scope_t scope_{scope_t::kNone}; +}; +} diff --git a/src/class_diagram/model/class_template.cc b/src/class_diagram/model/class_template.cc new file mode 100644 index 00000000..d4036317 --- /dev/null +++ b/src/class_diagram/model/class_template.cc @@ -0,0 +1,60 @@ +/** + * src/class_diagram/model/class_template.cc + * + * Copyright (c) 2021 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 "class_template.h" + +namespace clanguml::class_diagram::model { + +class_template::class_template(const std::string &type, const std::string &name, + const std::string &default_value, bool is_variadic) + : type_{type} + , name_{name} + , default_value_{default_value} + , is_variadic_{is_variadic} +{ + if (is_variadic) + name_ = name_ + "..."; +} + +void class_template::set_type(const std::string &type) { type_ = type; } + +std::string class_template::type() const { return type_; } + +void class_template::set_name(const std::string &name) { name_ = name; } + +std::string class_template::name() const { return name_; } + +void class_template::set_default_value(const std::string &value) +{ + default_value_ = value; +} + +std::string class_template::default_value() const { return default_value_; } + +void class_template::is_variadic(bool is_variadic) noexcept +{ + is_variadic_ = is_variadic; +} + +bool class_template::is_variadic() const noexcept { return is_variadic_; } + +bool operator==(const class_template &l, const class_template &r) +{ + return (l.name() == r.name()) && (l.type() == r.type()); +} +} diff --git a/src/class_diagram/model/class_template.h b/src/class_diagram/model/class_template.h new file mode 100644 index 00000000..4fe0cbc1 --- /dev/null +++ b/src/class_diagram/model/class_template.h @@ -0,0 +1,50 @@ +/** + * src/class_diagram/model/class_template.h + * + * Copyright (c) 2021 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 +#include + +namespace clanguml::class_diagram::model { + +class class_template { +public: + class_template(const std::string &type = "", const std::string &name = "", + const std::string &default_value = "", bool is_variadic = false); + + void set_type(const std::string &type); + std::string type() const; + + void set_name(const std::string &name); + std::string name() const; + + void set_default_value(const std::string &value); + std::string default_value() const; + + void is_variadic(bool is_variadic) noexcept; + bool is_variadic() const noexcept; + + friend bool operator==(const class_template &l, const class_template &r); + +private: + std::string type_; + std::string name_; + std::string default_value_; + bool is_variadic_{false}; +}; +} diff --git a/src/class_diagram/model/decorated_element.cc b/src/class_diagram/model/decorated_element.cc new file mode 100644 index 00000000..a7b59492 --- /dev/null +++ b/src/class_diagram/model/decorated_element.cc @@ -0,0 +1,82 @@ +/** + * src/class_diagram/model/decorated_element.cc + * + * Copyright (c) 2021 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 "decorated_element.h" + +namespace clanguml::class_diagram::model { + +bool decorated_element::skip() const +{ + for (auto d : decorators_) + if (std::dynamic_pointer_cast(d)) + return true; + + return false; +} + +bool decorated_element::skip_relationship() const +{ + for (auto d : decorators_) + if (std::dynamic_pointer_cast(d)) + return true; + + return false; +} + +std::pair decorated_element::relationship() const +{ + for (auto &d : decorators_) + if (std::dynamic_pointer_cast(d)) + return {relationship_t::kAssociation, + std::dynamic_pointer_cast(d) + ->multiplicity}; + else if (std::dynamic_pointer_cast(d)) + return {relationship_t::kAggregation, + std::dynamic_pointer_cast(d) + ->multiplicity}; + else if (std::dynamic_pointer_cast(d)) + return {relationship_t::kComposition, + std::dynamic_pointer_cast(d) + ->multiplicity}; + + return {relationship_t::kNone, ""}; +} + +std::string decorated_element::style_spec() +{ + for (auto d : decorators_) + if (std::dynamic_pointer_cast(d)) + return std::dynamic_pointer_cast(d)->spec; + + return ""; +} + +const std::vector> & +decorated_element::decorators() const +{ + return decorators_; +} + +void decorated_element::add_decorators( + const std::vector> &decorators) +{ + for (auto d : decorators) { + decorators_.push_back(d); + } +} +} diff --git a/src/class_diagram/model/decorated_element.h b/src/class_diagram/model/decorated_element.h new file mode 100644 index 00000000..a63803d4 --- /dev/null +++ b/src/class_diagram/model/decorated_element.h @@ -0,0 +1,50 @@ +/** + * src/class_diagram/model/decorated_element.h + * + * Copyright (c) 2021 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 "enums.h" + +#include "decorators/decorators.h" + +#include +#include +#include + +namespace clanguml::class_diagram::model { + +class decorated_element { +public: + bool skip() const; + + bool skip_relationship() const; + + std::pair relationship() const; + + std::string style_spec(); + + const std::vector> & + decorators() const; + + void add_decorators( + const std::vector> &decorators); + +private: + std::vector> decorators_; +}; + +} diff --git a/src/class_diagram/model/diagram.cc b/src/class_diagram/model/diagram.cc new file mode 100644 index 00000000..1fa636ca --- /dev/null +++ b/src/class_diagram/model/diagram.cc @@ -0,0 +1,85 @@ +/** + * src/class_diagram/model/diagram.cc + * + * Copyright (c) 2021 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" + +#include "util/error.h" +#include "util/util.h" + +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_; } + +bool diagram::has_class(const class_ &c) const +{ + return std::any_of(classes_.cbegin(), classes_.cend(), + [&c](const auto &cc) { return cc.full_name() == c.full_name(); }); +} + +void diagram::add_type_alias(type_alias &&ta) +{ + LOG_DBG("Adding global alias: {} -> {}", ta.alias(), ta.underlying_type()); + + type_aliases_[ta.alias()] = std::move(ta); +} + +void diagram::add_class(class_ &&c) +{ + LOG_DBG("Adding class: {}, {}", c.name(), c.full_name()); + if (!has_class(c)) + classes_.emplace_back(std::move(c)); + else + LOG_DBG("Class {} ({}) already in the model", c.name(), c.full_name()); +} + +void diagram::add_enum(enum_ &&e) +{ + LOG_DBG("Adding enum: {}", e.name()); + auto it = std::find(enums_.begin(), enums_.end(), e); + if (it == enums_.end()) + enums_.emplace_back(std::move(e)); + else + LOG_DBG("Enum {} already in the model", e.name()); +} + +std::string diagram::to_alias(const std::string &full_name) const +{ + LOG_DBG("Looking for alias for {}", full_name); + + for (const auto &c : classes_) { + if (c.full_name() == full_name) { + return c.alias(); + } + } + + for (const auto &e : enums_) { + if (e.full_name() == full_name) { + return e.alias(); + } + } + + throw error::uml_alias_missing( + fmt::format("Missing alias for {}", full_name)); +} +} diff --git a/src/class_diagram/model/diagram.h b/src/class_diagram/model/diagram.h new file mode 100644 index 00000000..1408d793 --- /dev/null +++ b/src/class_diagram/model/diagram.h @@ -0,0 +1,55 @@ +/** + * src/class_diagram/model/diagram.h + * + * Copyright (c) 2021 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 "class.h" +#include "enum.h" +#include "type_alias.h" + +#include +#include + +namespace clanguml::class_diagram::model { + +class diagram { +public: + std::string name() const; + + void set_name(const std::string &name); + + const std::vector classes() const; + + const std::vector enums() const; + + bool has_class(const class_ &c) const; + + void add_type_alias(type_alias &&ta); + + void add_class(class_ &&c); + + void add_enum(enum_ &&e); + + 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/class_diagram/model/element.cc b/src/class_diagram/model/element.cc new file mode 100644 index 00000000..9f523f4d --- /dev/null +++ b/src/class_diagram/model/element.cc @@ -0,0 +1,68 @@ +/** + * src/class_diagram/model/element.cc + * + * Copyright (c) 2021 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 "element.h" + +#include "util/util.h" + +namespace clanguml::class_diagram::model { + +std::atomic_uint64_t element::m_nextId = 1; + +element::element(const std::vector &using_namespaces) + : using_namespaces_{using_namespaces} + , m_id{m_nextId++} +{ +} + +std::string element::alias() const { return fmt::format("C_{:010}", m_id); } + +void element::add_relationship(class_relationship &&cr) +{ + if (cr.destination().empty()) { + LOG_WARN("Skipping relationship '{}' - {} - '{}' due empty " + "destination", + cr.destination(), to_string(cr.type()), full_name(true)); + return; + } + + auto it = std::find(relationships_.begin(), relationships_.end(), cr); + if (it == relationships_.end()) + relationships_.emplace_back(std::move(cr)); +} + +void element::set_using_namespaces(const std::vector &un) +{ + using_namespaces_ = un; +} + +const std::vector &element::using_namespaces() const +{ + return using_namespaces_; +} + +std::vector &element::relationships() +{ + return relationships_; +} + +const std::vector &element::relationships() const +{ + return relationships_; +} +} diff --git a/src/class_diagram/model/element.h b/src/class_diagram/model/element.h new file mode 100644 index 00000000..092feed2 --- /dev/null +++ b/src/class_diagram/model/element.h @@ -0,0 +1,66 @@ +/** + * src/class_diagram/model/element.h + * + * Copyright (c) 2021 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 "class_relationship.h" +#include "decorated_element.h" + +#include +#include +#include + +namespace clanguml::class_diagram::model { + +class element : public decorated_element { +public: + element(const std::vector &using_namespaces); + + std::string alias() const; + + void set_name(const std::string &name) { name_ = name; } + + std::string name() const { return name_; } + + void set_namespace(const std::vector &ns) { namespace_ = ns; } + + std::vector get_namespace() const { return namespace_; } + + virtual std::string full_name(bool relative) const { return name(); } + + void set_using_namespaces(const std::vector &un); + + const std::vector &using_namespaces() const; + + std::vector &relationships(); + + const std::vector &relationships() const; + + void add_relationship(class_relationship &&cr); + +protected: + const uint64_t m_id{0}; + +private: + std::string name_; + std::vector namespace_; + std::vector using_namespaces_; + std::vector relationships_; + + static std::atomic_uint64_t m_nextId; +}; +} diff --git a/src/class_diagram/model/enum.cc b/src/class_diagram/model/enum.cc new file mode 100644 index 00000000..6b9004c0 --- /dev/null +++ b/src/class_diagram/model/enum.cc @@ -0,0 +1,51 @@ +/** + * src/class_diagram/model/enum.cc + * + * Copyright (c) 2021 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 "enum.h" + +#include "util/util.h" + +#include + +namespace clanguml::class_diagram::model { + +enum_::enum_(const std::vector &using_namespaces) + : element{using_namespaces} +{ +} + +bool operator==(const enum_ &l, const enum_ &r) { return l.name() == r.name(); } + +std::string enum_::full_name(bool relative) const +{ + using namespace clanguml::util; + + std::ostringstream ostr; + if (relative) + ostr << ns_relative(using_namespaces(), name()); + else + ostr << name(); + + return ostr.str(); +} + +std::vector &enum_::constants() { return constants_; } + +const std::vector &enum_::constants() const { return constants_; } + +} diff --git a/src/class_diagram/model/enum.h b/src/class_diagram/model/enum.h new file mode 100644 index 00000000..19692097 --- /dev/null +++ b/src/class_diagram/model/enum.h @@ -0,0 +1,43 @@ +/** + * src/class_diagram/model/enum.h + * + * Copyright (c) 2021 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 "class.h" + +#include +#include + +namespace clanguml::class_diagram::model { + +class enum_ : public element, public stylable_element { +public: + enum_(const std::vector &using_namespaces); + + friend bool operator==(const enum_ &l, const enum_ &r); + + std::string full_name(bool relative = true) const override; + + std::vector &constants(); + + const std::vector &constants() const; + +private: + std::vector constants_; +}; + +} diff --git a/src/class_diagram/model/enums.h b/src/class_diagram/model/enums.h new file mode 100644 index 00000000..ee658bfa --- /dev/null +++ b/src/class_diagram/model/enums.h @@ -0,0 +1,39 @@ +/** + * src/class_diagram/model/enums.h + * + * Copyright (c) 2021 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::class_diagram::model { + +enum class access_t { kPublic, kProtected, kPrivate }; + +enum class scope_t { kPublic, kProtected, kPrivate, kNone }; + +enum class relationship_t { + kNone, + kExtension, + kComposition, + kAggregation, + kContainment, + kOwnership, + kAssociation, + kInstantiation, + kFriendship, + kDependency +}; + +} diff --git a/src/class_diagram/model/method_parameter.cc b/src/class_diagram/model/method_parameter.cc new file mode 100644 index 00000000..f64b5e1f --- /dev/null +++ b/src/class_diagram/model/method_parameter.cc @@ -0,0 +1,51 @@ +/** + * src/class_diagram/model/method_parameter.cc + * + * Copyright (c) 2021 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 "method_parameter.h" + +#include "util/util.h" + +namespace clanguml::class_diagram::model { + +void method_parameter::set_type(const std::string &type) { type_ = type; } + +std::string method_parameter::type() const { return type_; } + +void method_parameter::set_name(const std::string &name) { name_ = name; } + +std::string method_parameter::name() const { return name_; } + +void method_parameter::set_default_value(const std::string &value) +{ + default_value_ = value; +} + +std::string method_parameter::default_value() const { return default_value_; } + +std::string method_parameter::to_string( + const std::vector &using_namespaces) const +{ + using namespace clanguml::util; + auto t = ns_relative(using_namespaces, type()); + if (default_value().empty()) + return fmt::format("{} {}", t, name()); + + return fmt::format("{} {} = {}", t, name(), default_value()); +} + +} diff --git a/src/class_diagram/model/method_parameter.h b/src/class_diagram/model/method_parameter.h new file mode 100644 index 00000000..5b5cab0d --- /dev/null +++ b/src/class_diagram/model/method_parameter.h @@ -0,0 +1,47 @@ +/** + * src/class_diagram/model/method_parameter.h + * + * Copyright (c) 2021 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 "decorated_element.h" + +#include +#include + +namespace clanguml::class_diagram::model { + +class method_parameter : public decorated_element { +public: + void set_type(const std::string &type); + std::string type() const; + + void set_name(const std::string &name); + std::string name() const; + + void set_default_value(const std::string &value); + std::string default_value() const; + + std::string to_string( + const std::vector &using_namespaces) const; + +private: + std::string type_; + std::string name_; + std::string default_value_; +}; + +} diff --git a/src/class_diagram/model/stylable_element.cc b/src/class_diagram/model/stylable_element.cc new file mode 100644 index 00000000..090e9b5e --- /dev/null +++ b/src/class_diagram/model/stylable_element.cc @@ -0,0 +1,27 @@ +/** + * src/class_diagram/model/stylable_element.cc + * + * Copyright (c) 2021 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 "stylable_element.h" + +namespace clanguml::class_diagram::model { + +void stylable_element::set_style(const std::string &style) { style_ = style; } + +std::string stylable_element::style() const { return style_; } + +} diff --git a/src/class_diagram/model/stylable_element.h b/src/class_diagram/model/stylable_element.h new file mode 100644 index 00000000..e1aa3929 --- /dev/null +++ b/src/class_diagram/model/stylable_element.h @@ -0,0 +1,33 @@ +/** + * src/class_diagram/model/stylable_element.h + * + * Copyright (c) 2021 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::class_diagram::model { + +class stylable_element { +public: + void set_style(const std::string &style); + std::string style() const; + +private: + std::string style_; +}; + +} diff --git a/src/class_diagram/model/type_alias.cc b/src/class_diagram/model/type_alias.cc new file mode 100644 index 00000000..cde5f50d --- /dev/null +++ b/src/class_diagram/model/type_alias.cc @@ -0,0 +1,34 @@ +/** + * src/class_diagram/model/type_alias.cc + * + * Copyright (c) 2021 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 "type_alias.h" + +namespace clanguml::class_diagram::model { + +void type_alias::set_alias(const std::string &alias) { alias_ = alias; } + +std::string type_alias::alias() const { return alias_; } + +void type_alias::set_underlying_type(const std::string &type) +{ + underlying_type_ = type; +} + +std::string type_alias::underlying_type() const { return underlying_type_; } + +} diff --git a/src/class_diagram/model/type_alias.h b/src/class_diagram/model/type_alias.h new file mode 100644 index 00000000..d94ed579 --- /dev/null +++ b/src/class_diagram/model/type_alias.h @@ -0,0 +1,37 @@ +/** + * src/class_diagram/model/type_alias.h + * + * Copyright (c) 2021 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::class_diagram::model { + +class type_alias { +public: + void set_alias(const std::string &alias); + std::string alias() const; + + void set_underlying_type(const std::string &type); + std::string underlying_type() const; + +private: + std::string alias_; + std::string underlying_type_; +}; + +} diff --git a/src/class_diagram/visitor/element_visitor_context.cc b/src/class_diagram/visitor/element_visitor_context.cc new file mode 100644 index 00000000..4dc41aef --- /dev/null +++ b/src/class_diagram/visitor/element_visitor_context.cc @@ -0,0 +1,57 @@ +/** + * src/class_diagram/model/visitor/element_visitor_context.cc + * + * Copyright (c) 2021 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 "element_visitor_context.h" + +#include "translation_unit_context.h" + +namespace clanguml::class_diagram::visitor { + +template +element_visitor_context::element_visitor_context( + clanguml::class_diagram::model::diagram &diagram, T &element) + : element_{element} + , diagram_{diagram} +{ +} + +template +void element_visitor_context::set_parent_class( + clanguml::class_diagram::model::class_ *parent_class) +{ + parent_class_ = parent_class; +} + +template +clanguml::class_diagram::model::class_ * +element_visitor_context::parent_class() +{ + return parent_class_; +} + +template T &element_visitor_context::element() +{ + return element_; +} + +template +clanguml::class_diagram::model::diagram &element_visitor_context::diagram() +{ + return diagram_; +} +} diff --git a/src/class_diagram/visitor/element_visitor_context.h b/src/class_diagram/visitor/element_visitor_context.h new file mode 100644 index 00000000..89cc32c6 --- /dev/null +++ b/src/class_diagram/visitor/element_visitor_context.h @@ -0,0 +1,48 @@ +/** + * src/class_diagram/model/visitor/element_visitor_context.h + * + * Copyright (c) 2021 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 "class_diagram/model/class.h" +#include "class_diagram/model/diagram.h" + +namespace clanguml::class_diagram::visitor { + +class translation_unit_context; + +template class element_visitor_context { +public: + element_visitor_context( + clanguml::class_diagram::model::diagram &diagram, T &element); + + void set_parent_class(clanguml::class_diagram::model::class_ *parent_class); + + clanguml::class_diagram::model::class_ *parent_class(); + + T &element(); + + clanguml::class_diagram::model::diagram &diagram(); + +private: + translation_unit_context *ctx_; + + T &element_; + clanguml::class_diagram::model::class_ *parent_class_{}; + clanguml::class_diagram::model::diagram &diagram_; +}; + +} diff --git a/src/class_diagram/visitor/translation_unit_context.cc b/src/class_diagram/visitor/translation_unit_context.cc new file mode 100644 index 00000000..3fcc6eef --- /dev/null +++ b/src/class_diagram/visitor/translation_unit_context.cc @@ -0,0 +1,135 @@ +/** + * src/class_diagram/visitor/translation_unit_context.cc + * + * Copyright (c) 2021 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 "translation_unit_context.h" + +#include "cx/util.h" + +namespace clanguml::class_diagram::visitor { + +translation_unit_context::translation_unit_context( + cppast::cpp_entity_index &idx, + clanguml::class_diagram::model::diagram &diagram, + const clanguml::config::class_diagram &config) + : entity_index_{idx} + , diagram_{diagram} + , config_{config} +{ +} + +bool translation_unit_context::has_type_alias( + const std::string &full_name) const +{ + bool res = alias_index_.find(full_name) != alias_index_.end(); + + LOG_DBG("Alias {} {} found in index", full_name, res ? "" : "not"); + + return res; +} + +void translation_unit_context::add_type_alias(const std::string &full_name, + type_safe::object_ref &&ref) +{ + if (!has_type_alias(full_name)) { + LOG_DBG("Stored type alias: {} -> {} ", full_name, + cppast::to_string(ref.get())); + + alias_index_.emplace(full_name, std::move(ref)); + } +} + +type_safe::object_ref +translation_unit_context::get_type_alias(const std::string &full_name) const +{ + assert(has_type_alias(full_name)); + + return alias_index_.at(full_name); +} + +type_safe::object_ref +translation_unit_context::get_type_alias_final(const cppast::cpp_type &t) const +{ + const auto type_full_name = + cx::util::full_name(cppast::remove_cv(t), entity_index_, false); + + if (has_type_alias(type_full_name)) { + return get_type_alias_final(alias_index_.at(type_full_name).get()); + } + + return type_safe::ref(t); +} + +bool translation_unit_context::has_type_alias_template( + const std::string &full_name) const +{ + bool res = + alias_template_index_.find(full_name) != alias_template_index_.end(); + + LOG_DBG("Alias template {} {} found in index", full_name, res ? "" : "not"); + + return res; +} + +void translation_unit_context::add_type_alias_template( + const std::string &full_name, + type_safe::object_ref &&ref) +{ + if (!has_type_alias_template(full_name)) { + LOG_DBG("Stored type alias template for: {} ", full_name); + + alias_template_index_.emplace(full_name, std::move(ref)); + } +} + +type_safe::object_ref +translation_unit_context::get_type_alias_template( + const std::string &full_name) const +{ + assert(has_type_alias_template(full_name)); + + return alias_template_index_.at(full_name); +} + +void translation_unit_context::push_namespace(const std::string &ns) +{ + namespace_.push_back(ns); +} + +void translation_unit_context::pop_namespace() { namespace_.pop_back(); } + +const std::vector &translation_unit_context::get_namespace() const +{ + return namespace_; +} + +const cppast::cpp_entity_index &translation_unit_context::entity_index() const +{ + return entity_index_; +} + +const clanguml::config::class_diagram &translation_unit_context::config() const +{ + return config_; +} + +clanguml::class_diagram::model::diagram &translation_unit_context::diagram() +{ + return diagram_; +} + +} diff --git a/src/class_diagram/visitor/translation_unit_context.h b/src/class_diagram/visitor/translation_unit_context.h new file mode 100644 index 00000000..90ef0b9e --- /dev/null +++ b/src/class_diagram/visitor/translation_unit_context.h @@ -0,0 +1,87 @@ +/** + * src/class_diagram/visitor/translation_unit_context.h + * + * Copyright (c) 2021 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 +#include +#include + +namespace clanguml::class_diagram::visitor { + +class translation_unit_context { +public: + translation_unit_context(cppast::cpp_entity_index &idx, + clanguml::class_diagram::model::diagram &diagram, + const clanguml::config::class_diagram &config); + + bool has_type_alias(const std::string &full_name) const; + + void add_type_alias(const std::string &full_name, + type_safe::object_ref &&ref); + + type_safe::object_ref get_type_alias( + const std::string &full_name) const; + + type_safe::object_ref get_type_alias_final( + const cppast::cpp_type &t) const; + + bool has_type_alias_template(const std::string &full_name) const; + + void add_type_alias_template(const std::string &full_name, + type_safe::object_ref &&ref); + + type_safe::object_ref get_type_alias_template( + const std::string &full_name) const; + + void push_namespace(const std::string &ns); + + void pop_namespace(); + + const std::vector &get_namespace() const; + + const cppast::cpp_entity_index &entity_index() const; + + const clanguml::config::class_diagram &config() const; + + clanguml::class_diagram::model::diagram &diagram(); + +private: + // Current visitor namespace + std::vector namespace_; + + // Reference to the cppast entity index + cppast::cpp_entity_index &entity_index_; + + // Reference to the output diagram model + clanguml::class_diagram::model::diagram &diagram_; + + // Reference to class diagram config + const clanguml::config::class_diagram &config_; + + // Map of discovered aliases (declared with 'using' keyword) + std::map> + alias_index_; + + // Map of discovered template aliases (declared with 'using' keyword) + std::map> + alias_template_index_; +}; + +} diff --git a/src/uml/class_diagram_visitor.cc b/src/class_diagram/visitor/translation_unit_visitor.cc similarity index 65% rename from src/uml/class_diagram_visitor.cc rename to src/class_diagram/visitor/translation_unit_visitor.cc index 9b589cb5..a4a95e01 100644 --- a/src/uml/class_diagram_visitor.cc +++ b/src/class_diagram/visitor/translation_unit_visitor.cc @@ -1,5 +1,5 @@ /** - * src/uml/class_diagram_visitor.cc + * src/class_diagram/visitor/translation_unit_visitor.cc * * Copyright (c) 2021 Bartek Kryza * @@ -15,7 +15,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "class_diagram_visitor.h" + +#include "translation_unit_visitor.h" #include #include @@ -33,143 +34,54 @@ #include -namespace clanguml { -namespace visitor { -namespace class_diagram { +namespace clanguml::class_diagram::visitor { -using clanguml::model::class_diagram::class_; -using clanguml::model::class_diagram::class_member; -using clanguml::model::class_diagram::class_method; -using clanguml::model::class_diagram::class_parent; -using clanguml::model::class_diagram::class_relationship; -using clanguml::model::class_diagram::class_template; -using clanguml::model::class_diagram::diagram; -using clanguml::model::class_diagram::enum_; -using clanguml::model::class_diagram::method_parameter; -using clanguml::model::class_diagram::relationship_t; -using clanguml::model::class_diagram::scope_t; -using clanguml::model::class_diagram::type_alias; +using clanguml::class_diagram::model::access_t; +using clanguml::class_diagram::model::class_; +using clanguml::class_diagram::model::class_member; +using clanguml::class_diagram::model::class_method; +using clanguml::class_diagram::model::class_parent; +using clanguml::class_diagram::model::class_relationship; +using clanguml::class_diagram::model::class_template; +using clanguml::class_diagram::model::diagram; +using clanguml::class_diagram::model::enum_; +using clanguml::class_diagram::model::method_parameter; +using clanguml::class_diagram::model::relationship_t; +using clanguml::class_diagram::model::scope_t; +using clanguml::class_diagram::model::type_alias; namespace detail { -scope_t cpp_access_specifier_to_scope(cppast::cpp_access_specifier_kind as) +scope_t cpp_access_specifier_to_scope( + cppast::cpp_access_specifier_kind access_specifier) { - scope_t res = scope_t::kPublic; - switch (as) { + scope_t scope = scope_t::kPublic; + switch (access_specifier) { case cppast::cpp_access_specifier_kind::cpp_public: - res = scope_t::kPublic; + scope = scope_t::kPublic; break; case cppast::cpp_access_specifier_kind::cpp_private: - res = scope_t::kPrivate; + scope = scope_t::kPrivate; break; case cppast::cpp_access_specifier_kind::cpp_protected: - res = scope_t::kProtected; + scope = scope_t::kProtected; break; default: break; } - return res; + return scope; } } -// -// tu_context -// -tu_context::tu_context(cppast::cpp_entity_index &idx, - clanguml::model::class_diagram::diagram &d_, - const clanguml::config::class_diagram &config_) - : entity_index{idx} - , d{d_} - , config{config_} +translation_unit_visitor::translation_unit_visitor( + cppast::cpp_entity_index &idx, + clanguml::class_diagram::model::diagram &diagram, + const clanguml::config::class_diagram &config) + : ctx{idx, diagram, config} { } -bool tu_context::has_type_alias(const std::string &full_name) const -{ - bool res = alias_index.find(full_name) != alias_index.end(); - LOG_DBG("Alias {} {} found in index", full_name, res ? "" : "not"); - return res; -} - -void tu_context::add_type_alias(const std::string &full_name, - type_safe::object_ref &&ref) -{ - if (!has_type_alias(full_name)) { - LOG_DBG("Stored type alias: {} -> {} ", full_name, - cppast::to_string(ref.get())); - alias_index.emplace(full_name, std::move(ref)); - } -} - -type_safe::object_ref tu_context::get_type_alias( - const std::string &full_name) const -{ - assert(has_type_alias(full_name)); - - return alias_index.at(full_name); -} - -type_safe::object_ref tu_context::get_type_alias_final( - const cppast::cpp_type &t) const -{ - const auto fn = - cx::util::full_name(cppast::remove_cv(t), entity_index, false); - - if (has_type_alias(fn)) { - return get_type_alias_final(alias_index.at(fn).get()); - } - - return type_safe::ref(t); -} - -bool tu_context::has_type_alias_template(const std::string &full_name) const -{ - bool res = - alias_template_index.find(full_name) != alias_template_index.end(); - LOG_DBG("Alias template {} {} found in index", full_name, res ? "" : "not"); - return res; -} - -void tu_context::add_type_alias_template(const std::string &full_name, - type_safe::object_ref &&ref) -{ - if (!has_type_alias_template(full_name)) { - LOG_DBG("Stored type alias template for: {} ", full_name); - alias_template_index.emplace(full_name, std::move(ref)); - } -} - -type_safe::object_ref -tu_context::get_type_alias_template(const std::string &full_name) const -{ - assert(has_type_alias_template(full_name)); - - return alias_template_index.at(full_name); -} - -// -// element_visitor_context -// -template -element_visitor_context::element_visitor_context( - clanguml::model::class_diagram::diagram &d_, T &e) - : element(e) - , d{d_} -{ -} - -// -// tu_visitor -// - -tu_visitor::tu_visitor(cppast::cpp_entity_index &idx_, - clanguml::model::class_diagram::diagram &d_, - const clanguml::config::class_diagram &config_) - : ctx{idx_, d_, config_} -{ -} - -void tu_visitor::operator()(const cppast::cpp_entity &file) +void translation_unit_visitor::operator()(const cppast::cpp_entity &file) { cppast::visit(file, [&, this](const cppast::cpp_entity &e, cppast::visitor_info info) { @@ -183,7 +95,7 @@ void tu_visitor::operator()(const cppast::cpp_entity &file) static_cast(e); if (!ns_declaration.is_anonymous() && !ns_declaration.is_inline()) - ctx.namespace_.push_back(e.name()); + ctx.push_namespace(e.name()); } else { LOG_DBG("========== Leaving '{}' - {}", e.name(), @@ -193,13 +105,13 @@ void tu_visitor::operator()(const cppast::cpp_entity &file) static_cast(e); if (!ns_declaration.is_anonymous() && !ns_declaration.is_inline()) - ctx.namespace_.pop_back(); + ctx.pop_namespace(); } } else if (e.kind() == cppast::cpp_entity_kind::class_template_specialization_t) { LOG_DBG("========== Visiting '{}' - {}", - cx::util::full_name(ctx.namespace_, e), + cx::util::full_name(ctx.get_namespace(), e), cppast::to_string(e.kind())); auto &tspec = static_cast< @@ -210,13 +122,14 @@ void tu_visitor::operator()(const cppast::cpp_entity &file) } else if (e.kind() == cppast::cpp_entity_kind::class_t) { LOG_DBG("========== Visiting '{}' - {}", - cx::util::full_name(ctx.namespace_, e), + cx::util::full_name(ctx.get_namespace(), e), cppast::to_string(e.kind())); auto &cls = static_cast(e); - if (cppast::get_definition(ctx.entity_index, cls)) { + if (cppast::get_definition(ctx.entity_index(), cls)) { auto &clsdef = static_cast( - cppast::get_definition(ctx.entity_index, cls).value()); + cppast::get_definition(ctx.entity_index(), cls) + .value()); if (&cls != &clsdef) { LOG_DBG("Forward declaration of class {} - skipping...", cls.name()); @@ -224,40 +137,40 @@ void tu_visitor::operator()(const cppast::cpp_entity &file) } } - if (ctx.config.should_include( - cx::util::fully_prefixed(ctx.namespace_, cls))) + if (ctx.config().should_include( + cx::util::fully_prefixed(ctx.get_namespace(), cls))) process_class_declaration(cls); } else if (e.kind() == cppast::cpp_entity_kind::enum_t) { LOG_DBG("========== Visiting '{}' - {}", - cx::util::full_name(ctx.namespace_, e), + cx::util::full_name(ctx.get_namespace(), e), cppast::to_string(e.kind())); auto &enm = static_cast(e); - if (ctx.config.should_include( - cx::util::fully_prefixed(ctx.namespace_, enm))) + if (ctx.config().should_include( + cx::util::fully_prefixed(ctx.get_namespace(), enm))) process_enum_declaration(enm); } else if (e.kind() == cppast::cpp_entity_kind::type_alias_t) { LOG_DBG("========== Visiting '{}' - {}", - cx::util::full_name(ctx.namespace_, e), + cx::util::full_name(ctx.get_namespace(), e), cppast::to_string(e.kind())); auto &ta = static_cast(e); type_alias t; - t.alias = cx::util::full_name(ctx.namespace_, ta); - t.underlying_type = cx::util::full_name(ta.underlying_type(), - ctx.entity_index, cx::util::is_inside_class(e)); + t.set_alias(cx::util::full_name(ctx.get_namespace(), ta)); + t.set_underlying_type(cx::util::full_name(ta.underlying_type(), + ctx.entity_index(), cx::util::is_inside_class(e))); - ctx.add_type_alias(cx::util::full_name(ctx.namespace_, ta), + ctx.add_type_alias(cx::util::full_name(ctx.get_namespace(), ta), type_safe::ref(ta.underlying_type())); - ctx.d.add_type_alias(std::move(t)); + ctx.diagram().add_type_alias(std::move(t)); } else if (e.kind() == cppast::cpp_entity_kind::alias_template_t) { LOG_DBG("========== Visiting '{}' - {}", - cx::util::full_name(ctx.namespace_, e), + cx::util::full_name(ctx.get_namespace(), e), cppast::to_string(e.kind())); auto &at = static_cast(e); @@ -266,12 +179,13 @@ void tu_visitor::operator()(const cppast::cpp_entity &file) const cppast::cpp_template_instantiation_type &>( at.type_alias().underlying_type())); - ctx.d.add_class(std::move(tinst)); + ctx.diagram().add_class(std::move(tinst)); } }); } -void tu_visitor::process_enum_declaration(const cppast::cpp_enum &enm) +void translation_unit_visitor::process_enum_declaration( + const cppast::cpp_enum &enm) { if (enm.name().empty()) { // Anonymous enum values should be rendered as class fields @@ -279,24 +193,24 @@ void tu_visitor::process_enum_declaration(const cppast::cpp_enum &enm) return; } - enum_ e; - e.name = cx::util::full_name(ctx.namespace_, enm); + enum_ e{ctx.config().using_namespace}; + e.set_name(cx::util::full_name(ctx.get_namespace(), enm)); if (enm.comment().has_value()) - e.decorators = decorators::parse(enm.comment().value()); + e.add_decorators(decorators::parse(enm.comment().value())); if (e.skip()) return; - e.style = e.style_spec(); + e.set_style(e.style_spec()); // Process enum documentation comment if (enm.comment().has_value()) - e.decorators = decorators::parse(enm.comment().value()); + e.add_decorators(decorators::parse(enm.comment().value())); for (const auto &ev : enm) { if (ev.kind() == cppast::cpp_entity_kind::enum_value_t) { - e.constants.push_back(ev.name()); + e.constants().push_back(ev.name()); } } @@ -304,31 +218,27 @@ void tu_visitor::process_enum_declaration(const cppast::cpp_enum &enm) for (auto cur = enm.parent(); cur; cur = cur.value().parent()) { // find nearest parent class, if any if (cur.value().kind() == cppast::cpp_entity_kind::class_t) { - class_relationship containment; - containment.type = relationship_t::kContainment; - containment.destination = - cx::util::full_name(ctx.namespace_, cur.value()); - containment.scope = scope_t::kNone; - e.relationships.emplace_back(std::move(containment)); + e.add_relationship({relationship_t::kContainment, + cx::util::full_name(ctx.get_namespace(), cur.value())}); - LOG_DBG("Added relationship {} +-- {}", e.name, - containment.destination); + LOG_DBG("Added containment relationship {} +-- {}", e.name()); break; } } - ctx.d.add_enum(std::move(e)); + ctx.diagram().add_enum(std::move(e)); } -void tu_visitor::process_class_declaration(const cppast::cpp_class &cls, +void translation_unit_visitor::process_class_declaration( + const cppast::cpp_class &cls, type_safe::optional_ref tspec) { - class_ c; - c.is_struct = cls.class_kind() == cppast::cpp_class_kind::struct_t; - c.name = cx::util::full_name(ctx.namespace_, cls); + class_ c{ctx.config().using_namespace}; + c.is_struct(cls.class_kind() == cppast::cpp_class_kind::struct_t); + c.set_name(cx::util::full_name(ctx.get_namespace(), cls)); if (cls.comment().has_value()) - c.decorators = decorators::parse(cls.comment().value()); + c.add_decorators(decorators::parse(cls.comment().value())); cppast::cpp_access_specifier_kind last_access_specifier = cppast::cpp_access_specifier_kind::cpp_private; @@ -336,21 +246,21 @@ void tu_visitor::process_class_declaration(const cppast::cpp_class &cls, // Process class documentation comment if (cppast::is_templated(cls)) { if (cls.parent().value().comment().has_value()) - c.decorators = - decorators::parse(cls.parent().value().comment().value()); + c.add_decorators( + decorators::parse(cls.parent().value().comment().value())); } else { if (cls.comment().has_value()) - c.decorators = decorators::parse(cls.comment().value()); + c.add_decorators(decorators::parse(cls.comment().value())); } if (c.skip()) return; - c.style = c.style_spec(); + c.set_style(c.style_spec()); // Process class child entities - if (c.is_struct) + if (c.is_struct()) last_access_specifier = cppast::cpp_access_specifier_kind::cpp_public; for (auto &child : cls) { @@ -421,26 +331,27 @@ void tu_visitor::process_class_declaration(const cppast::cpp_class &cls, // Process class bases for (auto &base : cls.bases()) { class_parent cp; - cp.name = clanguml::cx::util::fully_prefixed(ctx.namespace_, base); - cp.is_virtual = base.is_virtual(); + cp.set_name( + clanguml::cx::util::fully_prefixed(ctx.get_namespace(), base)); + cp.is_virtual(base.is_virtual()); switch (base.access_specifier()) { case cppast::cpp_access_specifier_kind::cpp_private: - cp.access = class_parent::access_t::kPrivate; + cp.set_access(access_t::kPrivate); break; case cppast::cpp_access_specifier_kind::cpp_public: - cp.access = class_parent::access_t::kPublic; + cp.set_access(access_t::kPublic); break; case cppast::cpp_access_specifier_kind::cpp_protected: - cp.access = class_parent::access_t::kProtected; + cp.set_access(access_t::kProtected); break; default: - cp.access = class_parent::access_t::kPublic; + cp.set_access(access_t::kPublic); } - LOG_DBG("Found base class {} for class {}", cp.name, c.name); + LOG_DBG("Found base class {} for class {}", cp.name(), c.name()); - c.bases.emplace_back(std::move(cp)); + c.add_parent(std::move(cp)); } // Process class template arguments @@ -495,34 +406,26 @@ void tu_visitor::process_class_declaration(const cppast::cpp_class &cls, // Naive parse of template arguments: auto toks = util::split(ua, ","); for (const auto &t : toks) { - class_template ct; - ct.type = t; - ct.default_value = ""; - ct.is_variadic = false; - ct.name = ""; - c.templates.emplace_back(std::move(ct)); + c.add_template({t}); const auto &primary_template_ref = static_cast( tspec.value() .primary_template() - .get(ctx.entity_index)[0] + .get(ctx.entity_index())[0] .get()) .class_(); if (primary_template_ref.user_data()) { - auto base_template_usr = static_cast( - primary_template_ref.user_data()); + auto base_template_full_name = + static_cast( + primary_template_ref.user_data()); LOG_DBG("Primary template ref set to: {}", - base_template_usr); + base_template_full_name); // Add template specialization/instantiation // relationship - class_relationship r; - r.type = relationship_t::kInstantiation; - r.label = ""; - r.destination = base_template_usr; - r.scope = scope_t::kNone; - c.add_relationship(std::move(r)); + c.add_relationship({relationship_t::kInstantiation, + base_template_full_name}); } else { LOG_WARN("No user data for base template {}", @@ -581,32 +484,25 @@ void tu_visitor::process_class_declaration(const cppast::cpp_class &cls, for (auto cur = cls.parent(); cur; cur = cur.value().parent()) { // find nearest parent class, if any if (cur.value().kind() == cppast::cpp_entity_kind::class_t) { - class_relationship containment; - containment.type = relationship_t::kContainment; - containment.destination = - cx::util::full_name(ctx.namespace_, cur.value()); - c.add_relationship(std::move(containment)); + c.add_relationship({relationship_t::kContainment, + cx::util::full_name(ctx.get_namespace(), cur.value())}); - LOG_DBG("Added relationship {} +-- {}", - c.full_name(ctx.config.using_namespace), - containment.destination); + LOG_DBG("Added containment relationship {}", c.full_name()); break; } } - cls.set_user_data(strdup(c.full_name(ctx.config.using_namespace).c_str())); + cls.set_user_data(strdup(c.full_name().c_str())); LOG_DBG("Setting user data for class {}, {}", static_cast(cls.user_data()), fmt::ptr(reinterpret_cast(&cls))); - c.usr = c.full_name(ctx.config.using_namespace); - - ctx.d.add_class(std::move(c)); + ctx.diagram().add_class(std::move(c)); } -bool tu_visitor::process_field_with_template_instantiation( +bool translation_unit_visitor::process_field_with_template_instantiation( const cppast::cpp_member_variable &mv, const cppast::cpp_type &tr, class_ &c, class_member &m, cppast::cpp_access_specifier_kind as) { @@ -623,63 +519,61 @@ bool tu_visitor::process_field_with_template_instantiation( resolve_alias(template_instantiation_type)); class_ tinst = build_template_instantiation(unaliased); - tinst.usr = tinst.full_name(ctx.config.using_namespace); // Infer the relationship of this field to the template // instantiation - class_relationship rr; - rr.destination = tinst.full_name(ctx.config.using_namespace); + relationship_t relationship_type{}; if (mv.type().kind() == cppast::cpp_type_kind::pointer_t || mv.type().kind() == cppast::cpp_type_kind::reference_t) - rr.type = relationship_t::kAssociation; + relationship_type = relationship_t::kAssociation; + else - rr.type = relationship_t::kAggregation; - rr.label = mv.name(); - rr.scope = detail::cpp_access_specifier_to_scope(as); - rr.style = m.style_spec(); + relationship_type = relationship_t::kAggregation; + + class_relationship rr{relationship_type, tinst.full_name(), + detail::cpp_access_specifier_to_scope(as), mv.name()}; + rr.set_style(m.style_spec()); // Process field decorators auto [decorator_rtype, decorator_rmult] = m.relationship(); if (decorator_rtype != relationship_t::kNone) { - rr.type = decorator_rtype; + rr.set_type(decorator_rtype); auto mult = util::split(decorator_rmult, ":"); if (mult.size() == 2) { - rr.multiplicity_source = mult[0]; - rr.multiplicity_destination = mult[1]; + rr.set_multiplicity_source(mult[0]); + rr.set_multiplicity_destination(mult[1]); } } - if (ctx.config.should_include(tinst.name)) { + if (ctx.config().should_include(tinst.name())) { LOG_DBG("Adding field instantiation relationship {} {} {} : {}", - rr.destination, model::class_diagram::to_string(rr.type), c.usr, - rr.label); + rr.destination(), + clanguml::class_diagram::model::to_string(rr.type()), c.full_name(), + rr.label()); c.add_relationship(std::move(rr)); res = true; - LOG_DBG( - "Created template instantiation: {}, {}", tinst.name, tinst.usr); + LOG_DBG("Created template instantiation: {}", tinst.full_name()); - ctx.d.add_class(std::move(tinst)); + ctx.diagram().add_class(std::move(tinst)); } return res; } -void tu_visitor::process_field(const cppast::cpp_member_variable &mv, class_ &c, +void translation_unit_visitor::process_field( + const cppast::cpp_member_variable &mv, class_ &c, cppast::cpp_access_specifier_kind as) { bool template_instantiation_added_as_aggregation{false}; - class_member m; - m.name = mv.name(); - m.type = cppast::to_string(mv.type()); - m.scope = detail::cpp_access_specifier_to_scope(as); - m.is_static = false; + class_member m{detail::cpp_access_specifier_to_scope(as), mv.name(), + cppast::to_string(mv.type())}; if (mv.comment().has_value()) - m.decorators = decorators::parse(mv.comment().value()); + m.add_decorators(decorators::parse(mv.comment().value())); if (m.skip()) return; @@ -690,7 +584,7 @@ void tu_visitor::process_field(const cppast::cpp_member_variable &mv, class_ &c, tr.kind()); if (tr.kind() == cppast::cpp_type_kind::builtin_t) { - LOG_DBG("Builtin type found for field: {}", m.name); + LOG_DBG("Builtin type found for field: {}", m.name()); } else if (tr.kind() == cppast::cpp_type_kind::user_defined_t) { LOG_DBG("Processing user defined type field {} {}", @@ -717,83 +611,77 @@ void tu_visitor::process_field(const cppast::cpp_member_variable &mv, class_ &c, for (const auto &[type, relationship_type] : relationships) { if (relationship_type != relationship_t::kNone) { - class_relationship r; - r.destination = type; - r.type = relationship_type; - r.label = m.name; - r.scope = m.scope; - r.style = m.style_spec(); + class_relationship r{ + relationship_type, type, m.scope(), m.name()}; + r.set_style(m.style_spec()); auto [decorator_rtype, decorator_rmult] = m.relationship(); if (decorator_rtype != relationship_t::kNone) { - r.type = decorator_rtype; + r.set_type(decorator_rtype); auto mult = util::split(decorator_rmult, ":"); if (mult.size() == 2) { - r.multiplicity_source = mult[0]; - r.multiplicity_destination = mult[1]; + r.set_multiplicity_source(mult[0]); + r.set_multiplicity_destination(mult[1]); } } LOG_DBG("Adding field relationship {} {} {} : {}", - r.destination, model::class_diagram::to_string(r.type), - c.usr, r.label); + r.destination(), + clanguml::class_diagram::model::to_string(r.type()), + c.full_name(), r.label()); - c.relationships.emplace_back(std::move(r)); + c.add_relationship(std::move(r)); } } } - c.members.emplace_back(std::move(m)); + c.add_member(std::move(m)); } -void tu_visitor::process_anonymous_enum( +void translation_unit_visitor::process_anonymous_enum( const cppast::cpp_enum &en, class_ &c, cppast::cpp_access_specifier_kind as) { for (const auto &ev : en) { if (ev.kind() == cppast::cpp_entity_kind::enum_value_t) { - class_member m; - m.name = ev.name(); - m.type = "enum"; // TODO: Try to figure out real enum type - m.scope = detail::cpp_access_specifier_to_scope(as); - m.is_static = false; - c.members.emplace_back(std::move(m)); + class_member m{ + detail::cpp_access_specifier_to_scope(as), ev.name(), "enum"}; + c.add_member(std::move(m)); } } } -void tu_visitor::process_static_field(const cppast::cpp_variable &mv, class_ &c, +void translation_unit_visitor::process_static_field( + const cppast::cpp_variable &mv, class_ &c, cppast::cpp_access_specifier_kind as) { - class_member m; - m.name = mv.name(); - m.type = cppast::to_string(mv.type()); - m.scope = detail::cpp_access_specifier_to_scope(as); - m.is_static = true; + class_member m{detail::cpp_access_specifier_to_scope(as), mv.name(), + cppast::to_string(mv.type())}; + + m.is_static(true); if (mv.comment().has_value()) - m.decorators = decorators::parse(mv.comment().value()); + m.add_decorators(decorators::parse(mv.comment().value())); if (m.skip()) return; - c.members.emplace_back(std::move(m)); + c.add_member(std::move(m)); } -void tu_visitor::process_method(const cppast::cpp_member_function &mf, - class_ &c, cppast::cpp_access_specifier_kind as) +void translation_unit_visitor::process_method( + const cppast::cpp_member_function &mf, class_ &c, + cppast::cpp_access_specifier_kind as) { - class_method m; - m.name = util::trim(mf.name()); - m.type = cppast::to_string(mf.return_type()); - m.is_pure_virtual = cppast::is_pure(mf.virtual_info()); - m.is_virtual = cppast::is_virtual(mf.virtual_info()); - m.is_const = cppast::is_const(mf.cv_qualifier()); - m.is_defaulted = false; - m.is_static = false; - m.scope = detail::cpp_access_specifier_to_scope(as); + class_method m{detail::cpp_access_specifier_to_scope(as), + util::trim(mf.name()), cppast::to_string(mf.return_type())}; + m.is_pure_virtual(cppast::is_pure(mf.virtual_info())); + m.is_virtual(cppast::is_virtual(mf.virtual_info())); + m.is_const(cppast::is_const(mf.cv_qualifier())); + m.is_defaulted(false); + m.is_static(false); if (mf.comment().has_value()) - m.decorators = decorators::parse(mf.comment().value()); + m.add_decorators(decorators::parse(mf.comment().value())); if (m.skip()) return; @@ -801,34 +689,35 @@ void tu_visitor::process_method(const cppast::cpp_member_function &mf, for (auto ¶m : mf.parameters()) process_function_parameter(param, m, c); - LOG_DBG("Adding method: {}", m.name); + LOG_DBG("Adding method: {}", m.name()); - c.methods.emplace_back(std::move(m)); + c.add_method(std::move(m)); } -void tu_visitor::process_template_method( +void translation_unit_visitor::process_template_method( const cppast::cpp_function_template &mf, class_ &c, cppast::cpp_access_specifier_kind as) { - class_method m; - m.name = util::trim(mf.name()); + std::string type; if (mf.function().kind() == cppast::cpp_entity_kind::constructor_t) - m.type = "void"; + type = "void"; else - m.type = cppast::to_string( + type = cppast::to_string( static_cast(mf.function()) .return_type()); - m.is_pure_virtual = false; - m.is_virtual = false; - m.is_const = cppast::is_const( + + class_method m{ + detail::cpp_access_specifier_to_scope(as), util::trim(mf.name()), type}; + m.is_pure_virtual(false); + m.is_virtual(false); + m.is_const(cppast::is_const( static_cast(mf.function()) - .cv_qualifier()); - m.is_defaulted = false; - m.is_static = false; - m.scope = detail::cpp_access_specifier_to_scope(as); + .cv_qualifier())); + m.is_defaulted(false); + m.is_static(false); if (mf.comment().has_value()) - m.decorators = decorators::parse(mf.comment().value()); + m.add_decorators(decorators::parse(mf.comment().value())); if (m.skip()) return; @@ -841,88 +730,85 @@ void tu_visitor::process_template_method( for (auto ¶m : mf.function().parameters()) process_function_parameter(param, m, c, template_parameter_names); - LOG_DBG("Adding template method: {}", m.name); + LOG_DBG("Adding template method: {}", m.name()); - c.methods.emplace_back(std::move(m)); + c.add_method(std::move(m)); } -void tu_visitor::process_static_method(const cppast::cpp_function &mf, - class_ &c, cppast::cpp_access_specifier_kind as) -{ - class_method m; - m.name = util::trim(mf.name()); - m.type = cppast::to_string(mf.return_type()); - m.is_pure_virtual = false; - m.is_virtual = false; - m.is_const = false; - m.is_defaulted = false; - m.is_static = true; - m.scope = detail::cpp_access_specifier_to_scope(as); - - if (mf.comment().has_value()) - m.decorators = decorators::parse(mf.comment().value()); - - if (m.skip()) - return; - - for (auto ¶m : mf.parameters()) - process_function_parameter(param, m, c); - - LOG_DBG("Adding static method: {}", m.name); - - c.methods.emplace_back(std::move(m)); -} - -void tu_visitor::process_constructor(const cppast::cpp_constructor &mf, - class_ &c, cppast::cpp_access_specifier_kind as) -{ - class_method m; - m.name = util::trim(mf.name()); - m.type = "void"; - m.is_pure_virtual = false; - m.is_virtual = false; - m.is_const = false; - m.is_defaulted = false; - m.is_static = false; - m.scope = detail::cpp_access_specifier_to_scope(as); - - if (mf.comment().has_value()) - m.decorators = decorators::parse(mf.comment().value()); - - if (m.skip()) - return; - - for (auto ¶m : mf.parameters()) - process_function_parameter(param, m, c); - - c.methods.emplace_back(std::move(m)); -} - -void tu_visitor::process_destructor(const cppast::cpp_destructor &mf, class_ &c, +void translation_unit_visitor::process_static_method( + const cppast::cpp_function &mf, class_ &c, cppast::cpp_access_specifier_kind as) { - class_method m; - m.name = util::trim(mf.name()); - m.type = "void"; - m.is_pure_virtual = false; - m.is_virtual = cppast::is_virtual(mf.virtual_info()); - m.is_const = false; - m.is_defaulted = false; - m.is_static = false; - m.scope = detail::cpp_access_specifier_to_scope(as); + class_method m{detail::cpp_access_specifier_to_scope(as), + util::trim(mf.name()), cppast::to_string(mf.return_type())}; + m.is_pure_virtual(false); + m.is_virtual(false); + m.is_const(false); + m.is_defaulted(false); + m.is_static(true); - c.methods.emplace_back(std::move(m)); + if (mf.comment().has_value()) + m.add_decorators(decorators::parse(mf.comment().value())); + + if (m.skip()) + return; + + for (auto ¶m : mf.parameters()) + process_function_parameter(param, m, c); + + LOG_DBG("Adding static method: {}", m.name()); + + c.add_method(std::move(m)); } -void tu_visitor::process_function_parameter( +void translation_unit_visitor::process_constructor( + const cppast::cpp_constructor &mf, class_ &c, + cppast::cpp_access_specifier_kind as) +{ + class_method m{detail::cpp_access_specifier_to_scope(as), + util::trim(mf.name()), "void"}; + m.is_pure_virtual(false); + m.is_virtual(false); + m.is_const(false); + m.is_defaulted(false); + m.is_static(true); + + if (mf.comment().has_value()) + m.add_decorators(decorators::parse(mf.comment().value())); + + if (m.skip()) + return; + + for (auto ¶m : mf.parameters()) + process_function_parameter(param, m, c); + + c.add_method(std::move(m)); +} + +void translation_unit_visitor::process_destructor( + const cppast::cpp_destructor &mf, class_ &c, + cppast::cpp_access_specifier_kind as) +{ + class_method m{detail::cpp_access_specifier_to_scope(as), + util::trim(mf.name()), "void"}; + m.is_pure_virtual(false); + m.is_virtual(cppast::is_virtual(mf.virtual_info())); + m.is_const(false); + m.is_defaulted(false); + m.is_static(true); + + c.add_method(std::move(m)); +} + +void translation_unit_visitor::process_function_parameter( const cppast::cpp_function_parameter ¶m, class_method &m, class_ &c, const std::set &template_parameter_names) { method_parameter mp; - mp.name = param.name(); + mp.set_name(param.name()); if (param.comment().has_value()) - m.decorators = decorators::parse(param.comment().value()); + m.add_decorators(decorators::parse(param.comment().value())); if (mp.skip()) return; @@ -933,29 +819,29 @@ void tu_visitor::process_function_parameter( // TODO: Template instantiation parameters are not fully prefixed // so we have to deduce the correct namespace prefix of the // template which is being instantiated - mp.type = cppast::to_string(param.type()); + mp.set_type(cppast::to_string(param.type())); } else { - mp.type = cppast::to_string(param.type()); + mp.set_type(cppast::to_string(param.type())); } auto dv = param.default_value(); if (dv) { switch (dv.value().kind()) { case cppast::cpp_expression_kind::literal_t: - mp.default_value = + mp.set_default_value( static_cast(dv.value()) - .value(); + .value()); break; case cppast::cpp_expression_kind::unexposed_t: - mp.default_value = + mp.set_default_value( static_cast( dv.value()) .expression() - .as_string(); + .as_string()); break; default: - mp.default_value = "{}"; + mp.set_default_value("{}"); } } @@ -966,15 +852,13 @@ void tu_visitor::process_function_parameter( relationship_t::kDependency); for (const auto &[type, relationship_type] : relationships) { if ((relationship_type != relationship_t::kNone) && - (type != c.name)) { - class_relationship r; - r.destination = type; - r.type = relationship_t::kDependency; - r.label = ""; + (type != c.name())) { + class_relationship r{relationship_t::kDependency, type}; LOG_DBG("Adding field relationship {} {} {} : {}", - r.destination, model::class_diagram::to_string(r.type), - c.usr, r.label); + r.destination(), + clanguml::class_diagram::model::to_string(r.type()), + c.full_name(), r.label()); c.add_relationship(std::move(r)); } @@ -987,15 +871,16 @@ void tu_visitor::process_function_parameter( static_cast(t); if (template_instantiation_type.primary_template() - .get(ctx.entity_index) + .get(ctx.entity_index()) .size()) { // Here we need the name of the primary template with full // namespace prefix to apply config inclusion filters - auto primary_template_name = cx::util::full_name(ctx.namespace_, - template_instantiation_type.primary_template() - .get(ctx.entity_index)[0] - .get()); + auto primary_template_name = + cx::util::full_name(ctx.get_namespace(), + template_instantiation_type.primary_template() + .get(ctx.entity_index())[0] + .get()); // Now check if the template arguments of this function param // are a subset of the method template params - if yes this is // not an instantiation but just a reference to an existing @@ -1015,24 +900,23 @@ void tu_visitor::process_function_parameter( LOG_DBG("Maybe building instantiation for: {}", primary_template_name); - if (ctx.config.should_include(primary_template_name)) { + if (ctx.config().should_include(primary_template_name)) { if (template_is_not_instantiation) { LOG_DBG("Template is not an instantiation - " "only adding reference to template {}", - cx::util::full_name( - cppast::remove_cv(t), ctx.entity_index, false)); - class_relationship rr; - rr.destination = cx::util::full_name( - cppast::remove_cv(t), ctx.entity_index, false); - rr.type = relationship_t::kDependency; - rr.label = ""; + cx::util::full_name(cppast::remove_cv(t), + ctx.entity_index(), false)); + class_relationship rr{relationship_t::kDependency, + cx::util::full_name(cppast::remove_cv(t), + ctx.entity_index(), false)}; LOG_DBG("Adding field template dependency relationship " "{} {} {} " ": {}", - rr.destination, - model::class_diagram::to_string(rr.type), c.usr, - rr.label); + rr.destination(), + clanguml::class_diagram::model::to_string( + rr.type()), + c.full_name(), rr.label()); c.add_relationship(std::move(rr)); } else { @@ -1040,64 +924,49 @@ void tu_visitor::process_function_parameter( class_ tinst = build_template_instantiation( template_instantiation_type); - class_relationship rr; - rr.destination = tinst.usr; - rr.type = relationship_t::kDependency; - rr.label = ""; + class_relationship rr{ + relationship_t::kDependency, tinst.full_name()}; + LOG_DBG("Adding field dependency relationship {} {} {} " ": {}", - rr.destination, - model::class_diagram::to_string(rr.type), c.usr, - rr.label); + rr.destination(), + clanguml::class_diagram::model::to_string( + rr.type()), + c.full_name(), rr.label()); + c.add_relationship(std::move(rr)); - ctx.d.add_class(std::move(tinst)); + ctx.diagram().add_class(std::move(tinst)); } } } } } - m.parameters.emplace_back(std::move(mp)); + m.add_parameter(std::move(mp)); } -void tu_visitor::process_template_type_parameter( +void translation_unit_visitor::process_template_type_parameter( const cppast::cpp_template_type_parameter &t, class_ &parent) { - class_template ct; - ct.type = ""; - ct.default_value = ""; - ct.is_variadic = t.is_variadic(); - ct.name = t.name(); - if (ct.is_variadic) - ct.name += "..."; - parent.templates.emplace_back(std::move(ct)); + parent.add_template({"", t.name(), "", t.is_variadic()}); } -void tu_visitor::process_template_nontype_parameter( +void translation_unit_visitor::process_template_nontype_parameter( const cppast::cpp_non_type_template_parameter &t, class_ &parent) { - class_template ct; - ct.type = cppast::to_string(t.type()); - ct.name = t.name(); - ct.default_value = ""; - ct.is_variadic = t.is_variadic(); - if (ct.is_variadic) - ct.name += "..."; - parent.templates.emplace_back(std::move(ct)); + parent.add_template( + {cppast::to_string(t.type()), t.name(), "", t.is_variadic()}); } -void tu_visitor::process_template_template_parameter( +void translation_unit_visitor::process_template_template_parameter( const cppast::cpp_template_template_parameter &t, class_ &parent) { - class_template ct; - ct.type = ""; - ct.name = t.name() + "<>"; - ct.default_value = ""; - parent.templates.emplace_back(std::move(ct)); + parent.add_template({"", t.name() + "<>"}); } -void tu_visitor::process_friend(const cppast::cpp_friend &f, class_ &parent) +void translation_unit_visitor::process_friend( + const cppast::cpp_friend &f, class_ &parent) { // Only process friends to other classes or class templates if (!f.entity() || @@ -1106,12 +975,11 @@ void tu_visitor::process_friend(const cppast::cpp_friend &f, class_ &parent) cppast::cpp_entity_kind::class_template_t)) return; - class_relationship r; - r.type = relationship_t::kFriendship; - r.label = "<>"; + class_relationship r{ + relationship_t::kFriendship, "", scope_t::kNone, "<>"}; if (f.comment().has_value()) - r.decorators = decorators::parse(f.comment().value()); + r.add_decorators(decorators::parse(f.comment().value())); if (r.skip() || r.skip_relationship()) return; @@ -1119,12 +987,12 @@ void tu_visitor::process_friend(const cppast::cpp_friend &f, class_ &parent) if (f.type()) { auto name = cppast::to_string(f.type().value()); - if (!ctx.config.should_include(name)) + if (!ctx.config().should_include(name)) return; LOG_DBG("Type friend declaration {}", name); - r.destination = name; + r.set_destination(name); } else if (f.entity()) { std::string name{}; @@ -1154,13 +1022,13 @@ void tu_visitor::process_friend(const cppast::cpp_friend &f, class_ &parent) cppast::is_templated(f.entity().value()), cppast::to_string(f.entity().value().kind())); - name = cx::util::full_name(ctx.namespace_, f.entity().value()); + name = cx::util::full_name(ctx.get_namespace(), f.entity().value()); } - if (!ctx.config.should_include(name)) + if (!ctx.config().should_include(name)) return; - r.destination = name; + r.set_destination(name); } else { LOG_DBG("Friend declaration points neither to type or entity."); @@ -1170,14 +1038,14 @@ void tu_visitor::process_friend(const cppast::cpp_friend &f, class_ &parent) parent.add_relationship(std::move(r)); } -bool tu_visitor::find_relationships(const cppast::cpp_type &t_, +bool translation_unit_visitor::find_relationships(const cppast::cpp_type &t_, std::vector> &relationships, relationship_t relationship_hint) { bool found{false}; const auto fn = - cx::util::full_name(cppast::remove_cv(t_), ctx.entity_index, false); + cx::util::full_name(cppast::remove_cv(t_), ctx.entity_index(), false); LOG_DBG("Finding relationships for type {}, {}, {}", cppast::to_string(t_), t_.kind(), fn); @@ -1232,7 +1100,7 @@ bool tu_visitor::find_relationships(const cppast::cpp_type &t_, } } else if (t.kind() == cppast::cpp_type_kind::template_instantiation_t) { - class_relationship r; + // class_relationship r; auto &tinst = static_cast(t); @@ -1264,7 +1132,7 @@ bool tu_visitor::find_relationships(const cppast::cpp_type &t_, found = find_relationships(args[0u].type().value(), relationships, relationship_t::kAggregation); } - else if (ctx.config.should_include(fn)) { + else if (ctx.config().should_include(fn)) { LOG_DBG("User defined template instantiation: {} | {}", cppast::to_string(t_), cppast::to_string(t_.canonical())); @@ -1300,30 +1168,29 @@ bool tu_visitor::find_relationships(const cppast::cpp_type &t_, return found; } -class_ tu_visitor::build_template_instantiation( +class_ translation_unit_visitor::build_template_instantiation( const cppast::cpp_template_instantiation_type &t, - std::optional parent) + std::optional parent) { - class_ tinst; + class_ tinst{ctx.config().using_namespace}; std::string full_template_name; std::deque> template_base_params{}; // Determine the full template name - if (t.primary_template().get(ctx.entity_index).size()) { + if (t.primary_template().get(ctx.entity_index()).size()) { const auto &primary_template_ref = static_cast( - t.primary_template().get(ctx.entity_index)[0].get()) + t.primary_template().get(ctx.entity_index())[0].get()) .class_(); if (parent) - LOG_DBG("Template parent is {}", - (*parent)->full_name(ctx.config.using_namespace)); + LOG_DBG("Template parent is {}", (*parent)->full_name()); else LOG_DBG("Template parent is empty"); full_template_name = - cx::util::full_name(ctx.namespace_, primary_template_ref); + cx::util::full_name(ctx.get_namespace(), primary_template_ref); LOG_DBG("Found template instantiation: " "type={}, canonical={}, primary_template={}, full_" @@ -1331,8 +1198,9 @@ class_ tu_visitor::build_template_instantiation( cppast::to_string(t), cppast::to_string(t.canonical()), t.primary_template().name(), full_template_name); - if (full_template_name.back() == ':') - tinst.name = full_template_name + tinst.name; + if (full_template_name.back() == ':') { + tinst.set_name(full_template_name + tinst.name()); + } std::vector> template_parameter_names{}; if (primary_template_ref.scope_name().has_value()) { @@ -1383,9 +1251,9 @@ class_ tu_visitor::build_template_instantiation( } if (primary_template_ref.user_data()) { - tinst.base_template_usr = - static_cast(primary_template_ref.user_data()); - LOG_DBG("Primary template ref set to: {}", tinst.base_template_usr); + tinst.set_base_template( + static_cast(primary_template_ref.user_data())); + LOG_DBG("Primary template ref set to: {}", tinst.base_template()); } else LOG_WARN("No user data for base template {}", @@ -1413,14 +1281,13 @@ class_ tu_visitor::build_template_instantiation( LOG_DBG("Template namespace is {}", ns); - tinst.name = ns + util::split(cppast::to_string(t), "<")[0]; + tinst.set_name(ns + util::split(cppast::to_string(t), "<")[0]); - tinst.is_template_instantiation = true; + tinst.is_template_instantiation(true); - tinst.usr = tinst.full_name(ctx.config.using_namespace); - if (tinst.usr.substr(0, tinst.usr.find('<')).find("::") == + if (tinst.full_name().substr(0, tinst.full_name().find('<')).find("::") == std::string::npos) { - tinst.usr = ns + tinst.usr; + tinst.set_name(ns + tinst.full_name()); } // Process template argumetns @@ -1430,12 +1297,12 @@ class_ tu_visitor::build_template_instantiation( bool add_template_argument_as_base_class{false}; class_template ct; if (targ.type()) { - ct.type = cppast::to_string(targ.type().value()); + ct.set_type(cppast::to_string(targ.type().value())); - LOG_DBG("Template argument is a type {}", ct.type); + LOG_DBG("Template argument is a type {}", ct.type()); auto fn = cx::util::full_name( cppast::remove_cv(cx::util::unreferenced(targ.type().value())), - ctx.entity_index, false); + ctx.entity_index(), false); if (targ.type().value().kind() == cppast::cpp_type_kind::template_instantiation_t) { @@ -1444,34 +1311,29 @@ class_ tu_visitor::build_template_instantiation( const cppast::cpp_template_instantiation_type &>( targ.type().value()); - class_relationship tinst_dependency; - tinst_dependency.type = relationship_t::kDependency; - tinst_dependency.label = ""; - std::string nnn{"empty"}; if (parent) - nnn = (*parent)->name; + nnn = (*parent)->name(); class_ nested_tinst = build_template_instantiation(nested_template_parameter, - ctx.config.should_include(tinst.usr) + ctx.config().should_include(tinst.full_name(false)) ? std::make_optional(&tinst) : parent); - tinst_dependency.destination = - nested_tinst.full_name(ctx.config.using_namespace); + class_relationship tinst_dependency{ + relationship_t::kDependency, nested_tinst.full_name()}; - auto nested_tinst_usr = nested_tinst.usr; + auto nested_tinst_full_name = nested_tinst.full_name(); - if (ctx.config.should_include(fn)) { - ctx.d.add_class(std::move(nested_tinst)); + if (ctx.config().should_include(fn)) { + ctx.diagram().add_class(std::move(nested_tinst)); } - if (ctx.config.should_include(tinst.usr)) { + if (ctx.config().should_include(tinst.full_name(false))) { LOG_DBG("Creating nested template dependency to template " "instantiation {}, {} -> {}", - fn, tinst.full_name(ctx.config.using_namespace), - tinst_dependency.destination); + fn, tinst.full_name(), tinst_dependency.destination()); tinst.add_relationship(std::move(tinst_dependency)); } @@ -1479,35 +1341,30 @@ class_ tu_visitor::build_template_instantiation( LOG_DBG("Creating nested template dependency to parent " "template " "instantiation {}, {} -> {}", - fn, (*parent)->full_name(ctx.config.using_namespace), - tinst_dependency.destination); + fn, (*parent)->full_name(), + tinst_dependency.destination()); (*parent)->add_relationship(std::move(tinst_dependency)); } else { LOG_DBG("No nested template dependency to template " "instantiation: {}, {} -> {}", - fn, tinst.full_name(ctx.config.using_namespace), - tinst_dependency.destination); + fn, tinst.full_name(), tinst_dependency.destination()); } } else if (targ.type().value().kind() == cppast::cpp_type_kind::user_defined_t) { - class_relationship tinst_dependency; - tinst_dependency.type = relationship_t::kDependency; - tinst_dependency.label = ""; - - tinst_dependency.destination = cx::util::full_name( - cppast::remove_cv( - cx::util::unreferenced(targ.type().value())), - ctx.entity_index, false); + class_relationship tinst_dependency{relationship_t::kDependency, + cx::util::full_name( + cppast::remove_cv( + cx::util::unreferenced(targ.type().value())), + ctx.entity_index(), false)}; LOG_DBG("Creating nested template dependency to user defined " "type {} -> {}", - tinst.full_name(ctx.config.using_namespace), - tinst_dependency.destination); + tinst.full_name(), tinst_dependency.destination()); - if (ctx.config.should_include(fn)) { + if (ctx.config().should_include(fn)) { tinst.add_relationship(std::move(tinst_dependency)); } else if (parent) { @@ -1518,16 +1375,16 @@ class_ tu_visitor::build_template_instantiation( else if (targ.expression()) { const auto &exp = targ.expression().value(); if (exp.kind() == cppast::cpp_expression_kind::literal_t) - ct.type = + ct.set_type( static_cast(exp) - .value(); + .value()); else if (exp.kind() == cppast::cpp_expression_kind::unexposed_t) - ct.type = + ct.set_type( static_cast(exp) .expression() - .as_string(); + .as_string()); - LOG_DBG("Template argument is an expression {}", ct.type); + LOG_DBG("Template argument is an expression {}", ct.type()); } // In case any of the template arguments are base classes, add @@ -1545,65 +1402,55 @@ class_ tu_visitor::build_template_instantiation( } if (add_template_argument_as_base_class) { - LOG_DBG("Adding template argument '{}' as base class", ct.type); + LOG_DBG( + "Adding template argument '{}' as base class", ct.type()); class_parent cp; - cp.access = class_parent::access_t::kPublic; - cp.name = ct.type; + cp.set_access(access_t::kPublic); + cp.set_name(ct.type()); - tinst.bases.emplace_back(std::move(cp)); + tinst.add_parent(std::move(cp)); } } - LOG_DBG("Adding template argument '{}'", ct.type); + LOG_DBG("Adding template argument '{}'", ct.type()); - tinst.templates.emplace_back(std::move(ct)); + tinst.add_template(std::move(ct)); } - // Now update usr with the template arguments of the - // instantiations... (there must be a better way) - tinst.usr = tinst.full_name(ctx.config.using_namespace); - if (tinst.usr.substr(0, tinst.usr.find('<')).find("::") == - std::string::npos) { - tinst.usr = ns + tinst.usr; - } - - LOG_DBG("Setting tinst usr to {}", tinst.usr); - // Add instantiation relationship to primary template of this // instantiation - class_relationship r; const auto &tt = cppast::remove_cv(cx::util::unreferenced(t)); - auto fn = cx::util::full_name(tt, ctx.entity_index, false); + auto fn = cx::util::full_name(tt, ctx.entity_index(), false); fn = util::split(fn, "<")[0]; + std::string destination; if (ctx.has_type_alias(fn)) { // If this is a template alias - set the instantiation // relationship to the first alias target - r.destination = cppast::to_string(ctx.get_type_alias(fn).get()); + destination = cppast::to_string(ctx.get_type_alias(fn).get()); } else { // Otherwise point to the base template - r.destination = tinst.base_template_usr; + destination = tinst.base_template(); } - r.type = relationship_t::kInstantiation; - r.label = ""; - r.scope = scope_t::kNone; + class_relationship r{relationship_t::kInstantiation, destination}; tinst.add_relationship(std::move(r)); return tinst; } -const cppast::cpp_type &tu_visitor::resolve_alias(const cppast::cpp_type &t) +const cppast::cpp_type &translation_unit_visitor::resolve_alias( + const cppast::cpp_type &type) { - const auto &tt = cppast::remove_cv(cx::util::unreferenced(t)); - const auto fn = cx::util::full_name(tt, ctx.entity_index, false); - if (ctx.has_type_alias(fn)) { - return ctx.get_type_alias_final(tt).get(); + const auto &raw_type = cppast::remove_cv(cx::util::unreferenced(type)); + const auto type_full_name = + cx::util::full_name(raw_type, ctx.entity_index(), false); + if (ctx.has_type_alias(type_full_name)) { + return ctx.get_type_alias_final(raw_type).get(); } - return t; -} -} + return type; } + } diff --git a/src/uml/class_diagram_visitor.h b/src/class_diagram/visitor/translation_unit_visitor.h similarity index 51% rename from src/uml/class_diagram_visitor.h rename to src/class_diagram/visitor/translation_unit_visitor.h index 53d9c782..e1c8c6ad 100644 --- a/src/uml/class_diagram_visitor.h +++ b/src/class_diagram/visitor/translation_unit_visitor.h @@ -1,5 +1,5 @@ /** - * src/uml/class_diagram_visitor.h + * src/class_diagram/visitor/translation_unit_visitor.h * * Copyright (c) 2021 Bartek Kryza * @@ -17,7 +17,8 @@ */ #pragma once -#include "class_diagram_model.h" +#include "class_diagram/model/diagram.h" +#include "class_diagram/visitor/translation_unit_context.h" #include "config/config.h" #include "cx/cursor.h" @@ -27,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -37,59 +39,13 @@ #include #include -namespace clanguml { -namespace visitor { -namespace class_diagram { +namespace clanguml::class_diagram::visitor { -struct tu_context { - tu_context(cppast::cpp_entity_index &idx, - clanguml::model::class_diagram::diagram &d_, - const clanguml::config::class_diagram &config_); - - bool has_type_alias(const std::string &full_name) const; - - void add_type_alias(const std::string &full_name, - type_safe::object_ref &&ref); - - type_safe::object_ref get_type_alias( - const std::string &full_name) const; - - type_safe::object_ref get_type_alias_final( - const cppast::cpp_type &t) const; - - bool has_type_alias_template(const std::string &full_name) const; - - void add_type_alias_template(const std::string &full_name, - type_safe::object_ref &&ref); - - type_safe::object_ref get_type_alias_template( - const std::string &full_name) const; - - std::vector namespace_; - cppast::cpp_entity_index &entity_index; - clanguml::model::class_diagram::diagram &d; - const clanguml::config::class_diagram &config; - std::map> - alias_index; - std::map> - alias_template_index; -}; - -template struct element_visitor_context { - element_visitor_context(clanguml::model::class_diagram::diagram &d_, T &e); - - tu_context *ctx; - - T &element; - clanguml::model::class_diagram::class_ *parent_class{}; - clanguml::model::class_diagram::diagram &d; -}; - -class tu_visitor { +class translation_unit_visitor { public: - tu_visitor(cppast::cpp_entity_index &idx_, - clanguml::model::class_diagram::diagram &d_, - const clanguml::config::class_diagram &config_); + translation_unit_visitor(cppast::cpp_entity_index &idx, + clanguml::class_diagram::model::diagram &diagram, + const clanguml::config::class_diagram &config); void operator()(const cppast::cpp_entity &file); @@ -100,78 +56,81 @@ public: void process_enum_declaration(const cppast::cpp_enum &enm); void process_anonymous_enum(const cppast::cpp_enum &en, - clanguml::model::class_diagram::class_ &c, + clanguml::class_diagram::model::class_ &c, cppast::cpp_access_specifier_kind as); void process_field(const cppast::cpp_member_variable &mv, - clanguml::model::class_diagram::class_ &c, + clanguml::class_diagram::model::class_ &c, cppast::cpp_access_specifier_kind as); bool process_field_with_template_instantiation( const cppast::cpp_member_variable &mv, const cppast::cpp_type &tr, - clanguml::model::class_diagram::class_ &c, - clanguml::model::class_diagram::class_member &m, + clanguml::class_diagram::model::class_ &c, + clanguml::class_diagram::model::class_member &m, cppast::cpp_access_specifier_kind as); void process_static_field(const cppast::cpp_variable &mv, - clanguml::model::class_diagram::class_ &c, + clanguml::class_diagram::model::class_ &c, cppast::cpp_access_specifier_kind as); void process_method(const cppast::cpp_member_function &mf, - clanguml::model::class_diagram::class_ &c, + clanguml::class_diagram::model::class_ &c, cppast::cpp_access_specifier_kind as); void process_template_method(const cppast::cpp_function_template &mf, - clanguml::model::class_diagram::class_ &c, + clanguml::class_diagram::model::class_ &c, cppast::cpp_access_specifier_kind as); void process_static_method(const cppast::cpp_function &mf, - clanguml::model::class_diagram::class_ &c, + clanguml::class_diagram::model::class_ &c, cppast::cpp_access_specifier_kind as); void process_constructor(const cppast::cpp_constructor &mf, - clanguml::model::class_diagram::class_ &c, + clanguml::class_diagram::model::class_ &c, cppast::cpp_access_specifier_kind as); void process_destructor(const cppast::cpp_destructor &mf, - clanguml::model::class_diagram::class_ &c, + clanguml::class_diagram::model::class_ &c, cppast::cpp_access_specifier_kind as); void process_function_parameter(const cppast::cpp_function_parameter ¶m, - clanguml::model::class_diagram::class_method &m, - clanguml::model::class_diagram::class_ &c, + clanguml::class_diagram::model::class_method &m, + clanguml::class_diagram::model::class_ &c, const std::set &template_parameter_names = {}); bool find_relationships(const cppast::cpp_type &t, std::vector> &relationships, - clanguml::model::class_diagram::relationship_t relationship_hint = - clanguml::model::class_diagram::relationship_t::kNone); + clanguml::class_diagram::model::relationship_t>> &relationships, + clanguml::class_diagram::model::relationship_t relationship_hint = + clanguml::class_diagram::model::relationship_t::kNone); void process_template_type_parameter( const cppast::cpp_template_type_parameter &t, - clanguml::model::class_diagram::class_ &parent); + clanguml::class_diagram::model::class_ &parent); void process_template_nontype_parameter( const cppast::cpp_non_type_template_parameter &t, - clanguml::model::class_diagram::class_ &parent); + clanguml::class_diagram::model::class_ &parent); void process_template_template_parameter( const cppast::cpp_template_template_parameter &t, - clanguml::model::class_diagram::class_ &parent); + clanguml::class_diagram::model::class_ &parent); void process_friend(const cppast::cpp_friend &t, - clanguml::model::class_diagram::class_ &parent); + clanguml::class_diagram::model::class_ &parent); private: - clanguml::model::class_diagram::class_ build_template_instantiation( + clanguml::class_diagram::model::class_ build_template_instantiation( const cppast::cpp_template_instantiation_type &t, - std::optional parent = {}); + std::optional parent = {}); + /** + * Try to resolve a type instance into a type referenced through an alias. + * If t does not represent an alias, returns t. + */ const cppast::cpp_type &resolve_alias(const cppast::cpp_type &t); - tu_context ctx; + // ctx allows to track current visitor context, e.g. current namespace + translation_unit_context ctx; }; } -} -} diff --git a/src/config/config.cc b/src/config/config.cc index 8dc801e5..6fb1dfcc 100644 --- a/src/config/config.cc +++ b/src/config/config.cc @@ -89,7 +89,8 @@ bool diagram::should_include(const std::string &name_) const return false; } -bool diagram::should_include(const model::class_diagram::scope_t scope) const +bool diagram::should_include( + const clanguml::class_diagram::model::scope_t scope) const { for (const auto &s : exclude.scopes) { if (s == scope) @@ -127,13 +128,13 @@ bool class_diagram::has_class(std::string clazz) } namespace YAML { +using clanguml::class_diagram::model::scope_t; using clanguml::config::class_diagram; using clanguml::config::config; using clanguml::config::filter; using clanguml::config::plantuml; using clanguml::config::sequence_diagram; using clanguml::config::source_location; -using clanguml::model::class_diagram::scope_t; template <> struct convert { static bool decode(const Node &node, scope_t &rhs) { diff --git a/src/config/config.h b/src/config/config.h index 6ed9ff3f..d085e40e 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -17,7 +17,8 @@ */ #pragma once -#include "uml/class_diagram_model.h" +#include "class_diagram/model/diagram.h" +#include "class_diagram/model/enums.h" #include "util/util.h" #include @@ -55,7 +56,7 @@ struct filter { // E.g.: // - public // - private - std::vector scopes; + std::vector scopes; }; struct diagram { @@ -76,7 +77,7 @@ struct diagram { bool should_include(const std::string &name_) const; - bool should_include(const model::class_diagram::scope_t scope) const; + bool should_include(const class_diagram::model::scope_t scope) const; }; struct source_location { diff --git a/src/cx/type.h b/src/cx/type.h index ae32dabf..2856e47a 100644 --- a/src/cx/type.h +++ b/src/cx/type.h @@ -22,7 +22,6 @@ #include #include "cx/util.h" -#include "uml/class_diagram_model.h" #include "util/util.h" namespace clanguml { diff --git a/src/uml/decorators.cc b/src/decorators/decorators.cc similarity index 99% rename from src/uml/decorators.cc rename to src/decorators/decorators.cc index 35ad3723..97921469 100644 --- a/src/uml/decorators.cc +++ b/src/decorators/decorators.cc @@ -1,5 +1,5 @@ /** - * src/uml/decorators.cc + * src/decorators/decorators.cc * * Copyright (c) 2021 Bartek Kryza * diff --git a/src/uml/decorators.h b/src/decorators/decorators.h similarity index 98% rename from src/uml/decorators.h rename to src/decorators/decorators.h index 74c99960..edb25d1e 100644 --- a/src/uml/decorators.h +++ b/src/decorators/decorators.h @@ -1,5 +1,5 @@ /** - * src/uml/decorators.h + * src/decorators/decorators.h * * Copyright (c) 2021 Bartek Kryza * diff --git a/src/main.cc b/src/main.cc index f58014e8..1efbadbb 100644 --- a/src/main.cc +++ b/src/main.cc @@ -18,13 +18,13 @@ #define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_DEBUG +#include "class_diagram/generators/plantuml/class_diagram_generator.h" +#include "class_diagram/model/diagram.h" +#include "class_diagram/visitor/translation_unit_visitor.h" #include "config/config.h" #include "cx/compilation_database.h" -#include "puml/class_diagram_generator.h" -#include "puml/sequence_diagram_generator.h" -#include "uml/class_diagram_model.h" -#include "uml/class_diagram_visitor.h" -#include "uml/sequence_diagram_visitor.h" +#include "sequence_diagram/generators/plantuml/sequence_diagram_generator.h" +#include "sequence_diagram/visitor/translation_unit_context.h" #include "util/util.h" #include @@ -98,18 +98,20 @@ int main(int argc, const char *argv[]) ofs.open(path, std::ofstream::out | std::ofstream::trunc); if (std::dynamic_pointer_cast(diagram)) { - auto model = generators::class_diagram::generate( - db2, name, dynamic_cast(*diagram)); + auto model = + clanguml::class_diagram::generators::plantuml::generate( + db2, name, dynamic_cast(*diagram)); - ofs << clanguml::generators::class_diagram::puml::generator( + ofs << clanguml::class_diagram::generators::plantuml::generator( dynamic_cast(*diagram), model); } else if (std::dynamic_pointer_cast(diagram)) { - auto model = generators::sequence_diagram::generate( - db, name, dynamic_cast(*diagram)); + auto model = + clanguml::sequence_diagram::generators::plantuml::generate( + db, name, dynamic_cast(*diagram)); - ofs << clanguml::generators::sequence_diagram::puml::generator( + ofs << clanguml::sequence_diagram::generators::plantuml::generator( dynamic_cast(*diagram), model); } diff --git a/src/puml/sequence_diagram_generator.cc b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc similarity index 85% rename from src/puml/sequence_diagram_generator.cc rename to src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc index 9fb22b7f..2c142ef9 100644 --- a/src/puml/sequence_diagram_generator.cc +++ b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc @@ -1,5 +1,5 @@ /** - * src/puml/sequence_diagram_generator.h + * src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc * * Copyright (c) 2021 Bartek Kryza * @@ -16,20 +16,21 @@ * limitations under the License. */ -#include "puml/sequence_diagram_generator.h" +#include "sequence_diagram_generator.h" -namespace clanguml::generators::sequence_diagram { -namespace puml { -using diagram_model = clanguml::model::sequence_diagram::diagram; +#include "sequence_diagram/visitor/translation_unit_context.h" + +namespace clanguml::sequence_diagram::generators::plantuml { + +using diagram_model = clanguml::sequence_diagram::model::diagram; using diagram_config = clanguml::config::sequence_diagram::diagram; using clanguml::config::source_location; -using clanguml::model::sequence_diagram::activity; -using clanguml::model::sequence_diagram::message; -using clanguml::model::sequence_diagram::message_t; -using clanguml::visitor::sequence_diagram::tu_context; +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; - // // generator // @@ -117,14 +118,13 @@ std::ostream &operator<<(std::ostream &os, const generator &g) g.generate(os); return os; } -} -clanguml::model::sequence_diagram::diagram generate( +clanguml::sequence_diagram::model::diagram generate( clanguml::cx::compilation_database &db, const std::string &name, clanguml::config::sequence_diagram &diagram) { spdlog::info("Generating diagram {}.puml", name); - clanguml::model::sequence_diagram::diagram d; + clanguml::sequence_diagram::model::diagram d; d.name = name; // Get all translation units matching the glob from diagram @@ -155,9 +155,10 @@ clanguml::model::sequence_diagram::diagram generate( spdlog::debug("Cursor name: {}", clang_getCString(clang_getCursorDisplayName(cursor))); - clanguml::visitor::sequence_diagram::tu_context ctx(d, diagram); + clanguml::sequence_diagram::visitor::translation_unit_context ctx( + d, diagram); auto res = clang_visitChildren(cursor, - clanguml::visitor::sequence_diagram::translation_unit_visitor, + clanguml::sequence_diagram::visitor::translation_unit_visitor, &ctx); spdlog::debug("Processing result: {}", res); diff --git a/src/puml/sequence_diagram_generator.h b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.h similarity index 69% rename from src/puml/sequence_diagram_generator.h rename to src/sequence_diagram/generators/plantuml/sequence_diagram_generator.h index fce68305..5b63cc08 100644 --- a/src/puml/sequence_diagram_generator.h +++ b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.h @@ -1,5 +1,5 @@ /** - * src/puml/sequence_diagram_generator.h + * src/sequence_diagram/generators/plantuml/sequence_diagram_generator.h * * Copyright (c) 2021 Bartek Kryza * @@ -19,8 +19,8 @@ #include "config/config.h" #include "cx/compilation_database.h" -#include "uml/sequence_diagram_model.h" -#include "uml/sequence_diagram_visitor.h" +#include "sequence_diagram/model/diagram.h" +#include "sequence_diagram/visitor/translation_unit_visitor.h" #include "util/util.h" #include @@ -31,25 +31,25 @@ #include namespace clanguml { -namespace generators { namespace sequence_diagram { -namespace puml { +namespace generators { +namespace plantuml { -using diagram_model = clanguml::model::sequence_diagram::diagram; +using diagram_model = clanguml::sequence_diagram::model::diagram; class generator { public: generator(clanguml::config::sequence_diagram &config, diagram_model &model); - std::string to_string(clanguml::model::sequence_diagram::message_t r) const; + std::string to_string(clanguml::sequence_diagram::model::message_t r) const; - void generate_call(const clanguml::model::sequence_diagram::message &m, + void generate_call(const clanguml::sequence_diagram::model::message &m, std::ostream &ostr) const; - void generate_return(const clanguml::model::sequence_diagram::message &m, + void generate_return(const clanguml::sequence_diagram::model::message &m, std::ostream &ostr) const; - void generate_activity(const clanguml::model::sequence_diagram::activity &a, + void generate_activity(const clanguml::sequence_diagram::model::activity &a, std::ostream &ostr) const; void generate(std::ostream &ostr) const; @@ -58,15 +58,14 @@ public: private: clanguml::config::sequence_diagram &m_config; - clanguml::model::sequence_diagram::diagram &m_model; + clanguml::sequence_diagram::model::diagram &m_model; }; -} - -clanguml::model::sequence_diagram::diagram generate( +clanguml::sequence_diagram::model::diagram generate( clanguml::cx::compilation_database &db, const std::string &name, clanguml::config::sequence_diagram &diagram); } } } +} diff --git a/src/uml/sequence_diagram_model.cc b/src/sequence_diagram/model/activity.cc similarity index 83% rename from src/uml/sequence_diagram_model.cc rename to src/sequence_diagram/model/activity.cc index 64c760c7..aa5dc7a8 100644 --- a/src/uml/sequence_diagram_model.cc +++ b/src/sequence_diagram/model/activity.cc @@ -1,5 +1,5 @@ /** - * src/uml/sequence_diagram_model.cc + * src/sequence_diagram/model/activity.cc * * Copyright (c) 2021 Bartek Kryza * @@ -16,8 +16,8 @@ * limitations under the License. */ -#include "sequence_diagram_visitor.h" +#include "activity.h" -namespace clanguml::model::sequence_diagram { +namespace clanguml::sequence_diagram::model { } diff --git a/src/sequence_diagram/model/activity.h b/src/sequence_diagram/model/activity.h new file mode 100644 index 00000000..4ac2473e --- /dev/null +++ b/src/sequence_diagram/model/activity.h @@ -0,0 +1,33 @@ +/** + * src/sequence_diagram/model/activity.h + * + * Copyright (c) 2021 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 "message.h" + +#include +#include + +namespace clanguml::sequence_diagram::model { + +struct activity { + std::string usr; + std::string from; + std::vector messages; +}; + +} diff --git a/src/sequence_diagram/model/diagram.cc b/src/sequence_diagram/model/diagram.cc new file mode 100644 index 00000000..17ebd3fa --- /dev/null +++ b/src/sequence_diagram/model/diagram.cc @@ -0,0 +1,32 @@ +/** + * src/sequence_diagram/model/diagram.cc + * + * Copyright (c) 2021 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" + +#include +#include +#include + +#include +#include +#include +#include + +namespace clanguml::sequence_diagram::model { + +} diff --git a/src/sequence_diagram/model/diagram.h b/src/sequence_diagram/model/diagram.h new file mode 100644 index 00000000..44984631 --- /dev/null +++ b/src/sequence_diagram/model/diagram.h @@ -0,0 +1,34 @@ +/** + * src/sequence_diagram/model/diagram.h + * + * Copyright (c) 2021 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 "activity.h" + +#include +#include + +namespace clanguml::sequence_diagram::model { + +struct diagram { + bool started{false}; + std::string name; + + std::map sequences; +}; + +} diff --git a/src/sequence_diagram/model/enums.h b/src/sequence_diagram/model/enums.h new file mode 100644 index 00000000..d64bf49b --- /dev/null +++ b/src/sequence_diagram/model/enums.h @@ -0,0 +1,24 @@ +/** + * src/sequence_diagram/model/enums.h + * + * Copyright (c) 2021 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.cc b/src/sequence_diagram/model/message.cc new file mode 100644 index 00000000..1b694806 --- /dev/null +++ b/src/sequence_diagram/model/message.cc @@ -0,0 +1,23 @@ +/** + * src/sequence_diagram/model/message.cc + * + * Copyright (c) 2021 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 "message.h" + +namespace clanguml::sequence_diagram::model { + +} diff --git a/src/uml/sequence_diagram_model.h b/src/sequence_diagram/model/message.h similarity index 63% rename from src/uml/sequence_diagram_model.h rename to src/sequence_diagram/model/message.h index f100a170..54a148eb 100644 --- a/src/uml/sequence_diagram_model.h +++ b/src/sequence_diagram/model/message.h @@ -1,5 +1,5 @@ /** - * src/uml/sequence_diagram_model.h + * src/sequence_diagram/model/message.h * * Copyright (c) 2021 Bartek Kryza * @@ -17,20 +17,12 @@ */ #pragma once -#include -#include -#include +#include "enums.h" -#include -#include #include #include -namespace clanguml { -namespace model { -namespace sequence_diagram { - -enum class message_t { kCall, kReturn }; +namespace clanguml::sequence_diagram::model { struct message { message_t type; @@ -43,18 +35,4 @@ struct message { unsigned int line; }; -struct activity { - std::string usr; - std::string from; - std::vector messages; -}; - -struct diagram { - bool started{false}; - std::string name; - - std::map sequences; -}; -} -} } diff --git a/src/sequence_diagram/visitor/translation_unit_context.cc b/src/sequence_diagram/visitor/translation_unit_context.cc new file mode 100644 index 00000000..547875b9 --- /dev/null +++ b/src/sequence_diagram/visitor/translation_unit_context.cc @@ -0,0 +1,68 @@ +/** + * src/sequence_diagram/visitor/translation_unit_context.cc + * + * Copyright (c) 2021 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 "translation_unit_context.h" + +#include +#include +#include + +namespace clanguml::sequence_diagram::visitor { + +translation_unit_context::translation_unit_context( + clanguml::sequence_diagram::model::diagram &diagram, + const clanguml::config::sequence_diagram &config) + : diagram_{diagram} + , config_{config} +{ +} + +void translation_unit_context::push_namespace(const std::string &ns) +{ + namespace_.push_back(ns); +} + +void translation_unit_context::pop_namespace() { namespace_.pop_back(); } + +const std::vector &translation_unit_context::get_namespace() const +{ + return namespace_; +} + +const clanguml::config::sequence_diagram & +translation_unit_context::config() const +{ + return config_; +} + +clanguml::sequence_diagram::model::diagram &translation_unit_context::diagram() +{ + return diagram_; +} + +void translation_unit_context::set_current_method(cx::cursor method) +{ + current_method_ = method; +} + +cx::cursor &translation_unit_context::current_method() +{ + return current_method_; +} + +} diff --git a/src/sequence_diagram/visitor/translation_unit_context.h b/src/sequence_diagram/visitor/translation_unit_context.h new file mode 100644 index 00000000..f80da7e5 --- /dev/null +++ b/src/sequence_diagram/visitor/translation_unit_context.h @@ -0,0 +1,59 @@ +/** + * src/sequence_diagram/visitor/translation_unit_context.h + * + * Copyright (c) 2021 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 "cx/cursor.h" +#include "sequence_diagram/model/diagram.h" + +#include +#include +#include + +namespace clanguml::sequence_diagram::visitor { + +class translation_unit_context { +public: + translation_unit_context( + clanguml::sequence_diagram::model::diagram &diagram, + const clanguml::config::sequence_diagram &config); + + void push_namespace(const std::string &ns); + + void pop_namespace(); + + const std::vector &get_namespace() const; + + const cppast::cpp_entity_index &entity_index() const; + + const clanguml::config::sequence_diagram &config() const; + + clanguml::sequence_diagram::model::diagram &diagram(); + + void set_current_method(cx::cursor method); + + cx::cursor ¤t_method(); + +private: + std::vector namespace_; + cx::cursor current_method_; + clanguml::sequence_diagram::model::diagram &diagram_; + const clanguml::config::sequence_diagram &config_; +}; + +} diff --git a/src/uml/sequence_diagram_visitor.cc b/src/sequence_diagram/visitor/translation_unit_visitor.cc similarity index 75% rename from src/uml/sequence_diagram_visitor.cc rename to src/sequence_diagram/visitor/translation_unit_visitor.cc index 0f438a96..e3e23c92 100644 --- a/src/uml/sequence_diagram_visitor.cc +++ b/src/sequence_diagram/visitor/translation_unit_visitor.cc @@ -1,5 +1,5 @@ /** - * src/uml/sequence_diagram_visitor.cc + * src/sequence_diagram/visitor/translation_unit_visitor.cc * * Copyright (c) 2021 Bartek Kryza * @@ -16,30 +16,21 @@ * limitations under the License. */ -#include "sequence_diagram_visitor.h" +#include "translation_unit_visitor.h" -namespace clanguml::visitor::sequence_diagram { +#include "translation_unit_context.h" -// -// tu_context -// - -tu_context::tu_context(clanguml::model::sequence_diagram::diagram &d_, - const clanguml::config::sequence_diagram &config_) - : d{d_} - , config{config_} -{ -} +namespace clanguml::sequence_diagram::visitor { enum CXChildVisitResult translation_unit_visitor( CXCursor cx_cursor, CXCursor cx_parent, CXClientData client_data) { - using clanguml::model::sequence_diagram::activity; - using clanguml::model::sequence_diagram::diagram; - using clanguml::model::sequence_diagram::message; - using clanguml::model::sequence_diagram::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; - struct tu_context *ctx = (struct tu_context *)client_data; + auto *ctx = (struct translation_unit_context *)client_data; enum CXChildVisitResult ret = CXChildVisit_Break; @@ -54,7 +45,7 @@ enum CXChildVisitResult translation_unit_visitor( case CXCursor_FunctionTemplate: case CXCursor_CXXMethod: case CXCursor_FunctionDecl: - ctx->current_method = cursor; + ctx->set_current_method(cursor); ret = CXChildVisit_Recurse; break; case CXCursor_CallExpr: { @@ -74,25 +65,28 @@ enum CXChildVisitResult translation_unit_visitor( clang_getFileLocation(cursor.location(), &f, &line, &column, &offset); std::string file{clang_getCString(clang_getFileName(f))}; - auto &d = ctx->d; - auto &config = ctx->config; + auto &d = ctx->diagram(); + auto &config = ctx->config(); if (referenced.kind() == CXCursor_CXXMethod) { if (config.should_include(sp_name)) { // Get calling object std::string caller{}; - if (ctx->current_method.semantic_parent() + if (ctx->current_method() + .semantic_parent() .is_translation_unit() || - ctx->current_method.semantic_parent().is_namespace()) { - caller = ctx->current_method.semantic_parent() + ctx->current_method().semantic_parent().is_namespace()) { + caller = ctx->current_method() + .semantic_parent() .fully_qualified() + - "::" + ctx->current_method.spelling() + "()"; + "::" + ctx->current_method().spelling() + "()"; } else { - caller = - ctx->current_method.semantic_parent().fully_qualified(); + caller = ctx->current_method() + .semantic_parent() + .fully_qualified(); } - auto caller_usr = ctx->current_method.usr(); + auto caller_usr = ctx->current_method().usr(); // Get called object auto callee = referenced.semantic_parent().fully_qualified(); auto callee_usr = referenced.semantic_parent().usr(); @@ -105,8 +99,8 @@ enum CXChildVisitResult translation_unit_visitor( "\n\tCURRENT_METHOD: {}\n\tFROM: '{}'\n\tTO: " "{}\n\tMESSAGE: {}\n\tFROM_USR: {}\n\tTO_USR: " "{}\n\tRETURN_TYPE: {}", - file, line, d.name, ctx->current_method.spelling(), caller, - callee, called_message, caller_usr, callee_usr, + file, line, d.name, ctx->current_method().spelling(), + caller, callee, called_message, caller_usr, callee_usr, referenced.type().result_type().spelling()); message m; @@ -146,5 +140,4 @@ enum CXChildVisitResult translation_unit_visitor( return ret; } - } diff --git a/src/uml/sequence_diagram_visitor.h b/src/sequence_diagram/visitor/translation_unit_visitor.h similarity index 56% rename from src/uml/sequence_diagram_visitor.h rename to src/sequence_diagram/visitor/translation_unit_visitor.h index cfdfbdfa..752b2ab5 100644 --- a/src/uml/sequence_diagram_visitor.h +++ b/src/sequence_diagram/visitor/translation_unit_visitor.h @@ -1,5 +1,5 @@ /** - * src/uml/sequence_diagram_visitor.h + * src/sequence_diagram/visitor/translation_unit_visitor.h * * Copyright (c) 2021 Bartek Kryza * @@ -17,35 +17,13 @@ */ #pragma once -#include "cx/cursor.h" -#include "sequence_diagram_model.h" #include "config/config.h" +#include "cx/cursor.h" +#include "sequence_diagram/model/diagram.h" -#include -#include -#include - -#include -#include -#include - -namespace clanguml { -namespace visitor { -namespace sequence_diagram { - -struct tu_context { - tu_context(clanguml::model::sequence_diagram::diagram &d_, - const clanguml::config::sequence_diagram &config_); - - std::vector namespace_; - cx::cursor current_method; - clanguml::model::sequence_diagram::diagram &d; - const clanguml::config::sequence_diagram &config; -}; +namespace clanguml::sequence_diagram::visitor { enum CXChildVisitResult translation_unit_visitor( CXCursor cx_cursor, CXCursor cx_parent, CXClientData client_data); } -} -} diff --git a/src/uml/class_diagram_model.cc b/src/uml/class_diagram_model.cc deleted file mode 100644 index 9a4ac4d9..00000000 --- a/src/uml/class_diagram_model.cc +++ /dev/null @@ -1,309 +0,0 @@ -/** - * src/uml/class_diagram_model.cc - * - * Copyright (c) 2021 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 "class_diagram_model.h" - -namespace clanguml { -namespace model { -namespace class_diagram { -std::atomic_uint64_t element::m_nextId = 1; - -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"; - } -} - -// -// decorated_element -// - -bool decorated_element::skip() const -{ - for (auto d : decorators) - if (std::dynamic_pointer_cast(d)) - return true; - - return false; -} - -bool decorated_element::skip_relationship() const -{ - for (auto d : decorators) - if (std::dynamic_pointer_cast(d)) - return true; - - return false; -} - -std::pair decorated_element::relationship() const -{ - for (auto &d : decorators) - if (std::dynamic_pointer_cast(d)) - return {relationship_t::kAssociation, - std::dynamic_pointer_cast(d) - ->multiplicity}; - else if (std::dynamic_pointer_cast(d)) - return {relationship_t::kAggregation, - std::dynamic_pointer_cast(d) - ->multiplicity}; - else if (std::dynamic_pointer_cast(d)) - return {relationship_t::kComposition, - std::dynamic_pointer_cast(d) - ->multiplicity}; - - return {relationship_t::kNone, ""}; -} - -std::string decorated_element::style_spec() -{ - for (auto d : decorators) - if (std::dynamic_pointer_cast(d)) - return std::dynamic_pointer_cast(d)->spec; - - return ""; -} - -// -// element -// - -element::element() - : m_id{m_nextId++} -{ -} - -std::string element::alias() const { return fmt::format("C_{:010}", m_id); } - -// -// method_parameter -// - -std::string method_parameter::to_string( - const std::vector &using_namespaces) const -{ - using namespace clanguml::util; - auto t = ns_relative(using_namespaces, type); - if (default_value.empty()) - return fmt::format("{} {}", t, name); - - return fmt::format("{} {} = {}", t, name, default_value); -} - -// -// class_relationship -// - -bool operator==(const class_relationship &l, const class_relationship &r) -{ - return l.type == r.type && l.destination == r.destination && - l.label == r.label; -} - -// -// class_template -// - -bool operator==(const class_template &l, const class_template &r) -{ - return (l.name == r.name) && (l.type == r.type); -} - -// -// class_ -// - -bool operator==(const class_ &l, const class_ &r) -{ - return (l.usr == r.usr) && (l.templates == r.templates); -} - -void class_::add_type_alias(type_alias &&ta) -{ - LOG_DBG("Adding class alias: {} -> {}", ta.alias, ta.underlying_type); - type_aliases[ta.alias] = std::move(ta); -} - -void class_::add_relationship(class_relationship &&cr) -{ - if (cr.destination.empty()) { - LOG_WARN("Skipping relationship '{}' - {} - '{}' due empty destination", - cr.destination, to_string(cr.type), usr); - return; - } - - auto it = std::find(relationships.begin(), relationships.end(), cr); - if (it == relationships.end()) - relationships.emplace_back(std::move(cr)); -} - -std::string class_::full_name( - const std::vector &using_namespaces) const -{ - using namespace clanguml::util; - - std::ostringstream ostr; - ostr << ns_relative(using_namespaces, name); - - if (!templates.empty()) { - std::vector tnames; - std::transform(templates.cbegin(), templates.cend(), - std::back_inserter(tnames), [&using_namespaces](const auto &tmplt) { - std::vector res; - - if (!tmplt.type.empty()) - res.push_back(ns_relative(using_namespaces, tmplt.type)); - - if (!tmplt.name.empty()) - res.push_back(ns_relative(using_namespaces, tmplt.name)); - - if (!tmplt.default_value.empty()) { - res.push_back("="); - res.push_back(tmplt.default_value); - } - - return fmt::format("{}", fmt::join(res, " ")); - }); - ostr << fmt::format("<{}>", fmt::join(tnames, ",")); - } - - return ostr.str(); -} - -bool class_::is_abstract() const -{ - // TODO check if all base abstract methods are overriden - // with non-abstract methods - return std::any_of(methods.begin(), methods.end(), - [](const auto &method) { return method.is_pure_virtual; }); -} - -// -// enum_ -// - -bool operator==(const enum_ &l, const enum_ &r) { return l.name == r.name; } - -std::string enum_::full_name( - const std::vector &using_namespaces) const -{ - using namespace clanguml::util; - - std::ostringstream ostr; - ostr << ns_relative(using_namespaces, name); - - return ostr.str(); -} - -// -// diagram -// - -bool diagram::has_class(const std::string &usr) const -{ - return std::any_of(classes.cbegin(), classes.cend(), - [&usr](const auto &c) { return c.usr == usr; }); -} - -void diagram::add_type_alias(type_alias &&ta) -{ - LOG_DBG("Adding global alias: {} -> {}", ta.alias, ta.underlying_type); - - type_aliases[ta.alias] = std::move(ta); -} - -void diagram::add_class(class_ &&c) -{ - LOG_DBG("Adding class: {}, {}", c.name, c.usr); - if (!has_class(c.usr)) - classes.emplace_back(std::move(c)); - else - LOG_DBG("Class {} ({}) already in the model", c.name, c.usr); -} - -void diagram::add_enum(enum_ &&e) -{ - LOG_DBG("Adding enum: {}", e.name); - auto it = std::find(enums.begin(), enums.end(), e); - if (it == enums.end()) - enums.emplace_back(std::move(e)); - else - LOG_DBG("Enum {} already in the model", e.name); -} - -std::string diagram::to_alias(const std::vector &using_namespaces, - const std::string &full_name) const -{ - LOG_DBG("Looking for alias for {}", full_name); - - for (const auto &c : classes) { - if (c.full_name(using_namespaces) == full_name) { - return c.alias(); - } - } - - for (const auto &e : enums) { - if (e.full_name(using_namespaces) == full_name) { - return e.alias(); - } - } - - throw error::uml_alias_missing( - fmt::format("Missing alias for {}", full_name)); -} - -std::string diagram::usr_to_name( - const std::vector &using_namespaces, - const std::string &usr) const -{ - if (usr.empty()) - throw std::runtime_error("Empty USR"); - - for (const auto &c : classes) { - if (c.usr == usr) - return c.full_name(using_namespaces); - } - - return ""; -} - -} -} -} diff --git a/src/uml/class_diagram_model.h b/src/uml/class_diagram_model.h deleted file mode 100644 index df24dfc5..00000000 --- a/src/uml/class_diagram_model.h +++ /dev/null @@ -1,210 +0,0 @@ -/** - * src/uml/class_diagram_model.h - * - * Copyright (c) 2021 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 "decorators.h" -#include "util/error.h" -#include "util/util.h" - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace clanguml { -namespace model { -namespace class_diagram { - -enum class scope_t { kPublic, kProtected, kPrivate, kNone }; - -enum class relationship_t { - kNone, - kExtension, - kComposition, - kAggregation, - kContainment, - kOwnership, - kAssociation, - kInstantiation, - kFriendship, - kDependency -}; - -std::string to_string(relationship_t r); - -struct stylable_element { - std::string style; -}; - -struct decorated_element { - std::vector> decorators; - - bool skip() const; - - bool skip_relationship() const; - - std::pair relationship() const; - - std::string style_spec(); -}; - -class element : public decorated_element { -public: - element(); - - std::string alias() const; - - std::string name; - std::vector namespace_; - -protected: - const uint64_t m_id{0}; - -private: - static std::atomic_uint64_t m_nextId; -}; - -struct class_element : public decorated_element { - scope_t scope; - std::string name; - std::string type; -}; - -struct class_member : public class_element { - bool is_relationship{false}; - bool is_static{false}; -}; - -struct method_parameter : public decorated_element { - std::string type; - std::string name; - std::string default_value; - - std::string to_string( - const std::vector &using_namespaces) const; -}; - -struct class_method : public class_element { - std::vector parameters; - bool is_pure_virtual{false}; - bool is_virtual{false}; - bool is_const{false}; - bool is_defaulted{false}; - bool is_static{false}; -}; - -struct class_parent { - enum class access_t { kPublic, kProtected, kPrivate }; - std::string name; - bool is_virtual{false}; - access_t access; -}; - -struct class_relationship : public decorated_element, public stylable_element { - relationship_t type{relationship_t::kAssociation}; - std::string destination; - std::string multiplicity_source; - std::string multiplicity_destination; - std::string label; - scope_t scope{scope_t::kNone}; - - friend bool operator==( - const class_relationship &l, const class_relationship &r); -}; - -struct class_template { - std::string name; - std::string type; - std::string default_value; - bool is_variadic{false}; - - friend bool operator==(const class_template &l, const class_template &r); -}; - -struct type_alias { - std::string alias; - std::string underlying_type; -}; - -class class_ : public element, public stylable_element { -public: - std::string usr; - bool is_struct{false}; - bool is_template{false}; - bool is_template_instantiation{false}; - std::vector members; - std::vector methods; - std::vector bases; - std::vector inner_classes; - std::vector relationships; - std::vector templates; - std::string base_template_usr; - std::map type_aliases; - - friend bool operator==(const class_ &l, const class_ &r); - - void add_type_alias(type_alias &&ta); - - void add_relationship(class_relationship &&cr); - - std::string full_name( - const std::vector &using_namespaces) const; - - bool is_abstract() const; -}; - -struct enum_ : public element, public stylable_element { - std::vector constants; - std::vector relationships; - - friend bool operator==(const enum_ &l, const enum_ &r); - - std::string full_name( - const std::vector &using_namespaces) const; -}; - -struct diagram { - std::string name; - std::vector classes; - std::vector enums; - std::map type_aliases; - - bool has_class(const std::string &usr) const; - - void add_type_alias(type_alias &&ta); - - void add_class(class_ &&c); - - void add_enum(enum_ &&e); - - std::string to_alias(const std::vector &using_namespaces, - const std::string &full_name) const; - - std::string usr_to_name(const std::vector &using_namespaces, - const std::string &usr) const; -}; -} -} -} diff --git a/tests/t00002/test_case.h b/tests/t00002/test_case.h index d6beaf68..7508d570 100644 --- a/tests/t00002/test_case.h +++ b/tests/t00002/test_case.h @@ -35,7 +35,7 @@ TEST_CASE("t00002", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name == "t00002_class"); + REQUIRE(model.name() == "t00002_class"); auto puml = generate_class_puml(diagram, model); AliasMatcher _A(puml); diff --git a/tests/t00003/test_case.h b/tests/t00003/test_case.h index d8c04d41..98db2116 100644 --- a/tests/t00003/test_case.h +++ b/tests/t00003/test_case.h @@ -34,7 +34,7 @@ TEST_CASE("t00003", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name == "t00003_class"); + REQUIRE(model.name() == "t00003_class"); auto puml = generate_class_puml(diagram, model); AliasMatcher _A(puml); diff --git a/tests/t00004/test_case.h b/tests/t00004/test_case.h index 6508c5ed..0d1c2e66 100644 --- a/tests/t00004/test_case.h +++ b/tests/t00004/test_case.h @@ -36,7 +36,7 @@ TEST_CASE("t00004", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name == "t00004_class"); + REQUIRE(model.name() == "t00004_class"); auto puml = generate_class_puml(diagram, model); AliasMatcher _A(puml); diff --git a/tests/t00005/test_case.h b/tests/t00005/test_case.h index 1a76961e..7935a758 100644 --- a/tests/t00005/test_case.h +++ b/tests/t00005/test_case.h @@ -37,7 +37,7 @@ TEST_CASE("t00005", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name == "t00005_class"); + REQUIRE(model.name() == "t00005_class"); auto puml = generate_class_puml(diagram, model); AliasMatcher _A(puml); diff --git a/tests/t00006/test_case.h b/tests/t00006/test_case.h index 94b7ab71..b96d68e3 100644 --- a/tests/t00006/test_case.h +++ b/tests/t00006/test_case.h @@ -38,7 +38,7 @@ TEST_CASE("t00006", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name == "t00006_class"); + REQUIRE(model.name() == "t00006_class"); auto puml = generate_class_puml(diagram, model); AliasMatcher _A(puml); diff --git a/tests/t00007/test_case.h b/tests/t00007/test_case.h index ce51e6e7..427bcbf0 100644 --- a/tests/t00007/test_case.h +++ b/tests/t00007/test_case.h @@ -38,7 +38,7 @@ TEST_CASE("t00007", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name == "t00007_class"); + REQUIRE(model.name() == "t00007_class"); auto puml = generate_class_puml(diagram, model); AliasMatcher _A(puml); diff --git a/tests/t00008/test_case.h b/tests/t00008/test_case.h index d474b2af..24bc1bc1 100644 --- a/tests/t00008/test_case.h +++ b/tests/t00008/test_case.h @@ -35,7 +35,7 @@ TEST_CASE("t00008", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name == "t00008_class"); + REQUIRE(model.name() == "t00008_class"); auto puml = generate_class_puml(diagram, model); AliasMatcher _A(puml); diff --git a/tests/t00009/test_case.h b/tests/t00009/test_case.h index 6fc48835..cea1288f 100644 --- a/tests/t00009/test_case.h +++ b/tests/t00009/test_case.h @@ -35,7 +35,7 @@ TEST_CASE("t00009", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name == "t00009_class"); + REQUIRE(model.name() == "t00009_class"); auto puml = generate_class_puml(diagram, model); AliasMatcher _A(puml); diff --git a/tests/t00010/test_case.h b/tests/t00010/test_case.h index 13472978..c99465a1 100644 --- a/tests/t00010/test_case.h +++ b/tests/t00010/test_case.h @@ -35,7 +35,7 @@ TEST_CASE("t00010", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name == "t00010_class"); + REQUIRE(model.name() == "t00010_class"); auto puml = generate_class_puml(diagram, model); AliasMatcher _A(puml); diff --git a/tests/t00011/test_case.h b/tests/t00011/test_case.h index 14fbfe98..c6dac32c 100644 --- a/tests/t00011/test_case.h +++ b/tests/t00011/test_case.h @@ -35,7 +35,7 @@ TEST_CASE("t00011", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name == "t00011_class"); + REQUIRE(model.name() == "t00011_class"); auto puml = generate_class_puml(diagram, model); AliasMatcher _A(puml); diff --git a/tests/t00012/test_case.h b/tests/t00012/test_case.h index aaf26a43..426fafe6 100644 --- a/tests/t00012/test_case.h +++ b/tests/t00012/test_case.h @@ -35,7 +35,7 @@ TEST_CASE("t00012", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name == "t00012_class"); + REQUIRE(model.name() == "t00012_class"); auto puml = generate_class_puml(diagram, model); AliasMatcher _A(puml); diff --git a/tests/t00013/test_case.h b/tests/t00013/test_case.h index d8dd16d3..9d01e55a 100644 --- a/tests/t00013/test_case.h +++ b/tests/t00013/test_case.h @@ -35,7 +35,7 @@ TEST_CASE("t00013", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name == "t00013_class"); + REQUIRE(model.name() == "t00013_class"); auto puml = generate_class_puml(diagram, model); AliasMatcher _A(puml); diff --git a/tests/t00014/test_case.h b/tests/t00014/test_case.h index 17a646dd..c843de34 100644 --- a/tests/t00014/test_case.h +++ b/tests/t00014/test_case.h @@ -33,7 +33,7 @@ TEST_CASE("t00014", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name == "t00014_class"); + REQUIRE(model.name() == "t00014_class"); auto puml = generate_class_puml(diagram, model); AliasMatcher _A(puml); diff --git a/tests/t00015/test_case.h b/tests/t00015/test_case.h index f5f89f1b..0ea9d5f7 100644 --- a/tests/t00015/test_case.h +++ b/tests/t00015/test_case.h @@ -34,7 +34,7 @@ TEST_CASE("t00015", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name == "t00015_class"); + REQUIRE(model.name() == "t00015_class"); auto puml = generate_class_puml(diagram, model); AliasMatcher _A(puml); diff --git a/tests/t00016/test_case.h b/tests/t00016/test_case.h index 96ac4d2e..0f617472 100644 --- a/tests/t00016/test_case.h +++ b/tests/t00016/test_case.h @@ -34,7 +34,7 @@ TEST_CASE("t00016", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name == "t00016_class"); + REQUIRE(model.name() == "t00016_class"); auto puml = generate_class_puml(diagram, model); AliasMatcher _A(puml); diff --git a/tests/t00017/test_case.h b/tests/t00017/test_case.h index ef469653..e31e27b7 100644 --- a/tests/t00017/test_case.h +++ b/tests/t00017/test_case.h @@ -37,7 +37,7 @@ TEST_CASE("t00017", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name == "t00017_class"); + REQUIRE(model.name() == "t00017_class"); auto puml = generate_class_puml(diagram, model); AliasMatcher _A(puml); diff --git a/tests/t00018/test_case.h b/tests/t00018/test_case.h index d82a409d..d1ca11d7 100644 --- a/tests/t00018/test_case.h +++ b/tests/t00018/test_case.h @@ -34,7 +34,7 @@ TEST_CASE("t00018", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name == "t00018_class"); + REQUIRE(model.name() == "t00018_class"); auto puml = generate_class_puml(diagram, model); AliasMatcher _A(puml); diff --git a/tests/t00019/test_case.h b/tests/t00019/test_case.h index 07d03748..48fbaf5f 100644 --- a/tests/t00019/test_case.h +++ b/tests/t00019/test_case.h @@ -37,7 +37,7 @@ TEST_CASE("t00019", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name == "t00019_class"); + REQUIRE(model.name() == "t00019_class"); auto puml = generate_class_puml(diagram, model); AliasMatcher _A(puml); diff --git a/tests/t00020/test_case.h b/tests/t00020/test_case.h index 6512f0e1..2aeb53ba 100644 --- a/tests/t00020/test_case.h +++ b/tests/t00020/test_case.h @@ -34,7 +34,7 @@ TEST_CASE("t00020", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name == "t00020_class"); + REQUIRE(model.name() == "t00020_class"); auto puml = generate_class_puml(diagram, model); AliasMatcher _A(puml); diff --git a/tests/t00021/test_case.h b/tests/t00021/test_case.h index e6da5cbd..f96f965f 100644 --- a/tests/t00021/test_case.h +++ b/tests/t00021/test_case.h @@ -34,7 +34,7 @@ TEST_CASE("t00021", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name == "t00021_class"); + REQUIRE(model.name() == "t00021_class"); auto puml = generate_class_puml(diagram, model); AliasMatcher _A(puml); diff --git a/tests/t00022/test_case.h b/tests/t00022/test_case.h index 9b69fb25..2cdb5b35 100644 --- a/tests/t00022/test_case.h +++ b/tests/t00022/test_case.h @@ -34,7 +34,7 @@ TEST_CASE("t00022", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name == "t00022_class"); + REQUIRE(model.name() == "t00022_class"); auto puml = generate_class_puml(diagram, model); AliasMatcher _A(puml); diff --git a/tests/t00023/test_case.h b/tests/t00023/test_case.h index 1aecf485..8216c224 100644 --- a/tests/t00023/test_case.h +++ b/tests/t00023/test_case.h @@ -34,7 +34,7 @@ TEST_CASE("t00023", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name == "t00023_class"); + REQUIRE(model.name() == "t00023_class"); auto puml = generate_class_puml(diagram, model); AliasMatcher _A(puml); diff --git a/tests/t00024/test_case.h b/tests/t00024/test_case.h index e0a883db..8b347b38 100644 --- a/tests/t00024/test_case.h +++ b/tests/t00024/test_case.h @@ -34,7 +34,7 @@ TEST_CASE("t00024", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name == "t00024_class"); + REQUIRE(model.name() == "t00024_class"); auto puml = generate_class_puml(diagram, model); AliasMatcher _A(puml); diff --git a/tests/t00025/test_case.h b/tests/t00025/test_case.h index 61e714ea..a5283d1b 100644 --- a/tests/t00025/test_case.h +++ b/tests/t00025/test_case.h @@ -34,7 +34,7 @@ TEST_CASE("t00025", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name == "t00025_class"); + REQUIRE(model.name() == "t00025_class"); auto puml = generate_class_puml(diagram, model); AliasMatcher _A(puml); diff --git a/tests/t00026/test_case.h b/tests/t00026/test_case.h index 4dc8892c..ebd3ace6 100644 --- a/tests/t00026/test_case.h +++ b/tests/t00026/test_case.h @@ -34,7 +34,7 @@ TEST_CASE("t00026", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name == "t00026_class"); + REQUIRE(model.name() == "t00026_class"); auto puml = generate_class_puml(diagram, model); AliasMatcher _A(puml); diff --git a/tests/t00027/test_case.h b/tests/t00027/test_case.h index 7f04ae86..803d97fe 100644 --- a/tests/t00027/test_case.h +++ b/tests/t00027/test_case.h @@ -34,7 +34,7 @@ TEST_CASE("t00027", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name == "t00027_class"); + REQUIRE(model.name() == "t00027_class"); auto puml = generate_class_puml(diagram, model); AliasMatcher _A(puml); diff --git a/tests/t00028/test_case.h b/tests/t00028/test_case.h index 0844e910..76426fbd 100644 --- a/tests/t00028/test_case.h +++ b/tests/t00028/test_case.h @@ -34,7 +34,7 @@ TEST_CASE("t00028", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name == "t00028_class"); + REQUIRE(model.name() == "t00028_class"); auto puml = generate_class_puml(diagram, model); AliasMatcher _A(puml); diff --git a/tests/t00029/test_case.h b/tests/t00029/test_case.h index 8cd2bc7e..d795fe66 100644 --- a/tests/t00029/test_case.h +++ b/tests/t00029/test_case.h @@ -34,7 +34,7 @@ TEST_CASE("t00029", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name == "t00029_class"); + REQUIRE(model.name() == "t00029_class"); auto puml = generate_class_puml(diagram, model); AliasMatcher _A(puml); diff --git a/tests/t00030/test_case.h b/tests/t00030/test_case.h index 3427bab5..5de10b77 100644 --- a/tests/t00030/test_case.h +++ b/tests/t00030/test_case.h @@ -34,7 +34,7 @@ TEST_CASE("t00030", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name == "t00030_class"); + REQUIRE(model.name() == "t00030_class"); auto puml = generate_class_puml(diagram, model); AliasMatcher _A(puml); diff --git a/tests/t00031/test_case.h b/tests/t00031/test_case.h index fce9ac45..8f52d254 100644 --- a/tests/t00031/test_case.h +++ b/tests/t00031/test_case.h @@ -34,7 +34,7 @@ TEST_CASE("t00031", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name == "t00031_class"); + REQUIRE(model.name() == "t00031_class"); auto puml = generate_class_puml(diagram, model); AliasMatcher _A(puml); diff --git a/tests/t00032/test_case.h b/tests/t00032/test_case.h index d8effc23..1d245b01 100644 --- a/tests/t00032/test_case.h +++ b/tests/t00032/test_case.h @@ -34,7 +34,7 @@ TEST_CASE("t00032", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name == "t00032_class"); + REQUIRE(model.name() == "t00032_class"); auto puml = generate_class_puml(diagram, model); AliasMatcher _A(puml); diff --git a/tests/t00033/test_case.h b/tests/t00033/test_case.h index 5d33b085..ceec5c6e 100644 --- a/tests/t00033/test_case.h +++ b/tests/t00033/test_case.h @@ -34,7 +34,7 @@ TEST_CASE("t00033", "[test-case][class]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name == "t00033_class"); + REQUIRE(model.name() == "t00033_class"); auto puml = generate_class_puml(diagram, model); AliasMatcher _A(puml); diff --git a/tests/t90000/test_case.h b/tests/t90000/test_case.h index 8b58575e..d8ed9ac2 100644 --- a/tests/t90000/test_case.h +++ b/tests/t90000/test_case.h @@ -24,7 +24,7 @@ TEST_CASE("t90000", "[test-case][config]") auto model = generate_class_diagram(db, diagram); - REQUIRE(model.name == "t90000_class"); + REQUIRE(model.name() == "t90000_class"); auto puml = generate_class_puml(diagram, model); AliasMatcher _A(puml); diff --git a/tests/test_cases.cc b/tests/test_cases.cc index bde5c0c8..678478e8 100644 --- a/tests/test_cases.cc +++ b/tests/test_cases.cc @@ -40,23 +40,25 @@ std::pair load_config2( return std::make_pair(std::move(config), std::move(db)); } -clanguml::model::sequence_diagram::diagram generate_sequence_diagram( +clanguml::sequence_diagram::model::diagram generate_sequence_diagram( compilation_database &db, std::shared_ptr diagram) { auto diagram_model = - clanguml::generators::sequence_diagram::generate(db, diagram->name, + clanguml::sequence_diagram::generators::plantuml::generate(db, + diagram->name, dynamic_cast(*diagram)); return diagram_model; } -clanguml::model::class_diagram::diagram generate_class_diagram( +clanguml::class_diagram::model::diagram generate_class_diagram( cppast::libclang_compilation_database &db, std::shared_ptr diagram) { auto diagram_model = - clanguml::generators::class_diagram::generate(db, diagram->name, + clanguml::class_diagram::generators::plantuml::generate(db, + diagram->name, dynamic_cast(*diagram)); return diagram_model; @@ -64,9 +66,9 @@ clanguml::model::class_diagram::diagram generate_class_diagram( std::string generate_sequence_puml( std::shared_ptr config, - clanguml::model::sequence_diagram::diagram &model) + clanguml::sequence_diagram::model::diagram &model) { - using namespace clanguml::generators::sequence_diagram::puml; + using namespace clanguml::sequence_diagram::generators::plantuml; std::stringstream ss; @@ -78,9 +80,9 @@ std::string generate_sequence_puml( std::string generate_class_puml( std::shared_ptr config, - clanguml::model::class_diagram::diagram &model) + clanguml::class_diagram::model::diagram &model) { - using namespace clanguml::generators::class_diagram::puml; + using namespace clanguml::class_diagram::generators::plantuml; std::stringstream ss; diff --git a/tests/test_cases.h b/tests/test_cases.h index ddfd54b3..625ad19d 100644 --- a/tests/test_cases.h +++ b/tests/test_cases.h @@ -19,13 +19,13 @@ #define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_DEBUG +#include "class_diagram/generators/plantuml/class_diagram_generator.h" +#include "class_diagram/model/diagram.h" +#include "class_diagram/visitor/translation_unit_visitor.h" #include "config/config.h" #include "cx/compilation_database.h" -#include "puml/class_diagram_generator.h" -#include "puml/sequence_diagram_generator.h" -#include "uml/class_diagram_model.h" -#include "uml/class_diagram_visitor.h" -#include "uml/sequence_diagram_visitor.h" +#include "sequence_diagram/generators/plantuml/sequence_diagram_generator.h" +#include "sequence_diagram/visitor/translation_unit_visitor.h" #include "util/util.h" #define CATCH_CONFIG_RUNNER @@ -48,21 +48,21 @@ load_config(const std::string &test_name); std::pair load_config2( const std::string &test_name); -clanguml::model::sequence_diagram::diagram generate_sequence_diagram( +clanguml::sequence_diagram::model::diagram generate_sequence_diagram( compilation_database &db, std::shared_ptr diagram); -clanguml::model::class_diagram::diagram generate_class_diagram( +clanguml::class_diagram::model::diagram generate_class_diagram( compilation_database &db, std::shared_ptr diagram); std::string generate_sequence_puml( std::shared_ptr config, - clanguml::model::sequence_diagram::diagram &model); + clanguml::sequence_diagram::model::diagram &model); std::string generate_class_puml( std::shared_ptr config, - clanguml::model::class_diagram::diagram &model); + clanguml::class_diagram::model::diagram &model); void save_puml(const std::string &path, const std::string &puml); diff --git a/tests/test_decorator_parser.cc b/tests/test_decorator_parser.cc index 203a0c2f..01cdd0db 100644 --- a/tests/test_decorator_parser.cc +++ b/tests/test_decorator_parser.cc @@ -17,7 +17,7 @@ */ #define CATCH_CONFIG_MAIN -#include "uml/decorators.h" +#include "decorators/decorators.h" #include "catch.h"