Merge pull request #9 from bkryza/remove-usr-from-class-diagram-generator

Remove usr from class diagram generator
This commit is contained in:
Bartek Kryza
2021-10-03 18:50:58 +02:00
committed by GitHub
134 changed files with 2948 additions and 1483 deletions

View File

@@ -11,8 +11,12 @@ jobs:
with: with:
submodules: recursive submodules: recursive
- name: Install deps - 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 - name: Build and unit test
run: | run: |
make debug NUMPROC=2 make debug
make test make test

1
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1 @@
Just be nice

View File

@@ -20,6 +20,8 @@
.DEFAULT_GOAL := debug .DEFAULT_GOAL := debug
NUMPROC ?= $(shell nproc)
.PHONY: clean .PHONY: clean
clean: clean:
rm -rf debug release rm -rf debug release
@@ -35,7 +37,8 @@ release/CMakeLists.txt:
-DCMAKE_BUILD_TYPE=Release -DCMAKE_BUILD_TYPE=Release
debug: debug/CMakeLists.txt debug: debug/CMakeLists.txt
make -C debug -j echo "Using ${NUMPROC} cores"
make -C debug -j$(NUMPROC)
release: release/CMakeLists.txt release: release/CMakeLists.txt
make -C release -j make -C release -j

View File

@@ -2,7 +2,7 @@
![linux build](https://github.com/bkryza/clang-uml/actions/workflows/build.yml/badge.svg) ![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 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 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 existing project code. The configuration file or files for `clang-uml` define the

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -17,36 +17,6 @@ diagrams:
``` ```
## Source code ## 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 File t00018_impl.h
```cpp ```cpp
#pragma once #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 ## Generated UML diagrams
![t00018_class](./t00018_class.png "Pimpl pattern") ![t00018_class](./t00018_class.png "Pimpl pattern")

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -17,21 +17,25 @@ diagrams:
``` ```
## Source code ## Source code
File t00019.cc File t00019_layer2.h
```cpp ```cpp
#include "t00019_base.h" #pragma once
#include "t00019_layer1.h"
#include "t00019_layer2.h"
#include "t00019_layer3.h"
#include <memory>
namespace clanguml { namespace clanguml {
namespace t00019 { namespace t00019 {
class A { template <typename LowerLayer> class Layer2 : public LowerLayer {
public:
std::unique_ptr<Layer1<Layer2<Layer3<Base>>>> layers; 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 <typename LowerLayer> 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 <memory>
namespace clanguml {
namespace t00019 {
class A {
public:
std::unique_ptr<Layer1<Layer2<Layer3<Base>>>> layers;
};
}
}
``` ```
File t00019_layer3.h File t00019_layer3.h
```cpp ```cpp
@@ -126,30 +150,6 @@ private:
} }
} }
```
File t00019_layer2.h
```cpp
#pragma once
namespace clanguml {
namespace t00019 {
template <typename LowerLayer> 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 ## Generated UML diagrams
![t00019_class](./t00019_class.png "Layercake pattern") ![t00019_class](./t00019_class.png "Layercake pattern")

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -1,5 +1,5 @@
/** /**
* src/puml/class_diagram_generator.cc * src/class_diagram/generators/plantuml/class_diagram_generator.cc
* *
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com> * Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
* *
@@ -18,9 +18,10 @@
#include "class_diagram_generator.h" #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) std::string relative_to(std::string n, std::string c)
{ {
if (c.rfind(n) == std::string::npos) 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); return c.substr(n.size() + 2);
} }
//
// generator
//
generator::generator( generator::generator(
clanguml::config::class_diagram &config, diagram_model &model) clanguml::config::class_diagram &config, diagram_model &model)
: m_config(config) : m_config(config)
@@ -106,7 +103,7 @@ void generator::generate_alias(const class_ &c, std::ostream &ostr) const
if (c.is_abstract()) if (c.is_abstract())
class_type = "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'; 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 void generator::generate_alias(const enum_ &e, std::ostream &ostr) const
{ {
ostr << "enum" ostr << "enum"
<< " \"" << e.full_name(m_config.using_namespace); << " \"" << e.full_name();
ostr << "\" as " << e.alias() << '\n'; ostr << "\" as " << e.alias() << '\n';
} }
@@ -130,32 +127,32 @@ void generator::generate(const class_ &c, std::ostream &ostr) const
ostr << class_type << " " << c.alias(); ostr << class_type << " " << c.alias();
if (!c.style.empty()) if (!c.style().empty())
ostr << " " << c.style; ostr << " " << c.style();
ostr << " {" << '\n'; ostr << " {" << '\n';
// //
// Process methods // Process methods
// //
for (const auto &m : c.methods) { for (const auto &m : c.methods()) {
if (!m_config.should_include(m.scope)) if (!m_config.should_include(m.scope()))
continue; continue;
if (m.is_pure_virtual) if (m.is_pure_virtual())
ostr << "{abstract} "; ostr << "{abstract} ";
if (m.is_static) if (m.is_static())
ostr << "{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 << "("; ostr << "(";
if (true) { // TODO: add option to disable parameter generation if (true) { // TODO: add option to disable parameter generation
std::vector<std::string> params; std::vector<std::string> 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) { std::back_inserter(params), [this](const auto &mp) {
return mp.to_string(m_config.using_namespace); return mp.to_string(m_config.using_namespace);
}); });
@@ -163,15 +160,15 @@ void generator::generate(const class_ &c, std::ostream &ostr) const
} }
ostr << ")"; ostr << ")";
if (m.is_const) if (m.is_const())
ostr << " 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"; ostr << " = 0";
if (m.is_defaulted) if (m.is_defaulted())
ostr << " = default"; ostr << " = default";
ostr << " : " << ns_relative(uns, type); 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::stringstream all_relations_str;
std::set<std::string> unique_relations; std::set<std::string> unique_relations;
for (const auto &r : c.relationships) { for (const auto &r : c.relationships()) {
if (!m_config.should_include_relationship(name(r.type))) if (!m_config.should_include_relationship(name(r.type())))
continue; continue;
LOG_DBG("== Processing relationship {}", to_string(r.type)); LOG_DBG("== Processing relationship {}", to_string(r.type()));
std::stringstream relstr; std::stringstream relstr;
std::string destination; std::string destination;
try { try {
if (r.destination.find("#") != std::string::npos || destination = r.destination();
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;
}
LOG_DBG("=== Destination is: {}", destination); LOG_DBG("=== Destination is: {}", destination);
std::string puml_relation; std::string puml_relation;
if (!r.multiplicity_source.empty()) if (!r.multiplicity_source().empty())
puml_relation += "\"" + r.multiplicity_source + "\" "; 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()) if (!r.multiplicity_destination().empty())
puml_relation += " \"" + r.multiplicity_destination + "\""; puml_relation += " \"" + r.multiplicity_destination() + "\"";
relstr << m_model.to_alias(uns, ns_relative(uns, c.full_name(uns))) relstr << m_model.to_alias(ns_relative(uns, c.full_name())) << " "
<< " " << puml_relation << " " << puml_relation << " "
<< m_model.to_alias(uns, ns_relative(uns, destination)); << m_model.to_alias(ns_relative(uns, destination));
if (!r.label.empty()) { if (!r.label().empty()) {
relstr << " : " << to_string(r.scope) << r.label; relstr << " : " << to_string(r.scope()) << r.label();
rendered_relations.emplace(r.label); rendered_relations.emplace(r.label());
} }
if (unique_relations.count(relstr.str()) == 0) { 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) { catch (error::uml_alias_missing &e) {
LOG_ERROR("=== Skipping {} relation from {} to {} due " LOG_ERROR("=== Skipping {} relation from {} to {} due "
"to: {}", "to: {}",
to_string(r.type), c.full_name(uns), destination, e.what()); to_string(r.type()), c.full_name(), destination, e.what());
} }
} }
// //
// Process members // Process members
// //
for (const auto &m : c.members) { for (const auto &m : c.members()) {
if (!m_config.should_include(m.scope)) if (!m_config.should_include(m.scope()))
continue; continue;
if (!m_config.include_relations_also_as_members && 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; continue;
if (m.is_static) if (m.is_static())
ostr << "{static} "; ostr << "{static} ";
ostr << to_string(m.scope) << m.name << " : " ostr << to_string(m.scope()) << m.name() << " : "
<< ns_relative(uns, m.type) << '\n'; << ns_relative(uns, m.type()) << '\n';
} }
ostr << "}" << '\n'; ostr << "}" << '\n';
if (m_config.should_include_relationship("inheritance")) if (m_config.should_include_relationship("inheritance"))
for (const auto &b : c.bases) { for (const auto &b : c.parents()) {
std::stringstream relstr; std::stringstream relstr;
try { 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( << m_model.to_alias(ns_relative(uns, c.full_name()))
uns, ns_relative(uns, c.full_name(uns)))
<< '\n'; << '\n';
ostr << relstr.str(); ostr << relstr.str();
} }
catch (error::uml_alias_missing &e) { catch (error::uml_alias_missing &e) {
LOG_ERROR("=== Skipping inheritance relation from {} to {} due " LOG_ERROR("=== Skipping inheritance relation from {} to {} due "
"to: {}", "to: {}",
b.name, c.name, e.what()); b.name(), c.name(), e.what());
} }
} }
// //
// Process notes // Process notes
// //
for (auto decorator : c.decorators) { for (auto decorator : c.decorators()) {
auto note = std::dynamic_pointer_cast<decorators::note>(decorator); auto note = std::dynamic_pointer_cast<decorators::note>(decorator);
if (note && note->applies_to_diagram(m_config.name)) { if (note && note->applies_to_diagram(m_config.name)) {
ostr << "note " << note->position << " of " << c.alias() << '\n' 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(); ostr << "enum " << e.alias();
if (!e.style.empty()) if (!e.style().empty())
ostr << " " << e.style; ostr << " " << e.style();
ostr << " {" << '\n'; ostr << " {" << '\n';
for (const auto &enum_constant : e.constants) { for (const auto &enum_constant : e.constants()) {
ostr << enum_constant << '\n'; ostr << enum_constant << '\n';
} }
ostr << "}" << '\n'; ostr << "}" << '\n';
for (const auto &r : e.relationships) { for (const auto &r : e.relationships()) {
if (!m_config.should_include_relationship(name(r.type))) if (!m_config.should_include_relationship(name(r.type())))
continue; continue;
std::string destination; std::string destination;
std::stringstream relstr; std::stringstream relstr;
try { 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, destination = r.destination();
ns_relative(m_config.using_namespace, e.name))
<< " " << to_string(r.type) << " " relstr << m_model.to_alias(
<< m_model.to_alias(m_config.using_namespace, ns_relative(m_config.using_namespace, e.name()))
<< " " << to_string(r.type()) << " "
<< m_model.to_alias(
ns_relative(m_config.using_namespace, destination)); ns_relative(m_config.using_namespace, destination));
if (!r.label.empty()) if (!r.label().empty())
relstr << " : " << r.label; relstr << " : " << r.label();
relstr << '\n'; relstr << '\n';
@@ -353,14 +325,14 @@ void generator::generate(const enum_ &e, std::ostream &ostr) const
catch (error::uml_alias_missing &ex) { catch (error::uml_alias_missing &ex) {
LOG_ERROR("Skipping {} relation from {} to {} due " LOG_ERROR("Skipping {} relation from {} to {} due "
"to: {}", "to: {}",
to_string(r.type), e.name, destination, ex.what()); to_string(r.type()), e.full_name(), destination, ex.what());
} }
} }
// //
// Process notes // Process notes
// //
for (auto decorator : e.decorators) { for (auto decorator : e.decorators()) {
auto note = std::dynamic_pointer_cast<decorators::note>(decorator); auto note = std::dynamic_pointer_cast<decorators::note>(decorator);
if (note && note->applies_to_diagram(m_config.name)) { if (note && note->applies_to_diagram(m_config.name)) {
ostr << "note " << note->position << " of " << e.alias() << '\n' ostr << "note " << note->position << " of " << e.alias() << '\n'
@@ -378,8 +350,7 @@ void generator::generate(std::ostream &ostr) const
std::string note{b}; std::string note{b};
std::tuple<std::string, size_t, size_t> alias_match; std::tuple<std::string, size_t, size_t> alias_match;
while (util::find_element_alias(note, alias_match)) { while (util::find_element_alias(note, alias_match)) {
auto alias = m_model.to_alias(m_config.using_namespace, auto alias = m_model.to_alias(ns_relative(
ns_relative(
m_config.using_namespace, std::get<0>(alias_match))); m_config.using_namespace, std::get<0>(alias_match)));
note.replace( note.replace(
std::get<1>(alias_match), std::get<2>(alias_match), alias); 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")) { if (m_config.should_include_entities("classes")) {
for (const auto &c : m_model.classes) { for (const auto &c : m_model.classes()) {
if (!c.is_template_instantiation && if (!c.is_template_instantiation() &&
!m_config.should_include(c.name)) !m_config.should_include(c.name()))
continue; continue;
generate_alias(c, ostr); generate_alias(c, ostr);
ostr << '\n'; ostr << '\n';
} }
for (const auto &e : m_model.enums) { for (const auto &e : m_model.enums()) {
if (!m_config.should_include(e.name)) if (!m_config.should_include(e.name()))
continue; continue;
generate_alias(e, ostr); generate_alias(e, ostr);
ostr << '\n'; ostr << '\n';
} }
for (const auto &c : m_model.classes) { for (const auto &c : m_model.classes()) {
if (!c.is_template_instantiation && if (!c.is_template_instantiation() &&
!m_config.should_include(c.name)) !m_config.should_include(c.name()))
continue; continue;
generate(c, ostr); generate(c, ostr);
ostr << '\n'; ostr << '\n';
@@ -413,7 +384,7 @@ void generator::generate(std::ostream &ostr) const
} }
if (m_config.should_include_entities("enums")) if (m_config.should_include_entities("enums"))
for (const auto &e : m_model.enums) { for (const auto &e : m_model.enums()) {
generate(e, ostr); generate(e, ostr);
ostr << '\n'; ostr << '\n';
} }
@@ -423,8 +394,7 @@ void generator::generate(std::ostream &ostr) const
std::string note{b}; std::string note{b};
std::tuple<std::string, size_t, size_t> alias_match; std::tuple<std::string, size_t, size_t> alias_match;
while (util::find_element_alias(note, alias_match)) { while (util::find_element_alias(note, alias_match)) {
auto alias = m_model.to_alias(m_config.using_namespace, auto alias = m_model.to_alias(ns_relative(
ns_relative(
m_config.using_namespace, std::get<0>(alias_match))); m_config.using_namespace, std::get<0>(alias_match)));
note.replace( note.replace(
std::get<1>(alias_match), std::get<2>(alias_match), alias); 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); g.generate(os);
return 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, cppast::libclang_compilation_database &db, const std::string &name,
clanguml::config::class_diagram &diagram) clanguml::config::class_diagram &diagram)
{ {
spdlog::info("Generating diagram {}.puml", name); spdlog::info("Generating diagram {}.puml", name);
clanguml::model::class_diagram::diagram d; clanguml::class_diagram::model::diagram d;
d.name = name; d.set_name(name);
// Get all translation units matching the glob from diagram // Get all translation units matching the glob from diagram
// configuration // configuration
@@ -464,7 +433,8 @@ clanguml::model::class_diagram::diagram generate(
type_safe::ref(idx)}; type_safe::ref(idx)};
// Process all matching translation units // 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); cppast::parse_files(parser, translation_units, db);
for (auto &file : parser.files()) for (auto &file : parser.files())
ctx(file); ctx(file);

View File

@@ -1,5 +1,5 @@
/** /**
* src/puml/class_diagram_generator.h * src/class_diagram/generators/plantuml/class_diagram_generator.h
* *
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com> * Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
* *
@@ -17,10 +17,13 @@
*/ */
#pragma once #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 "config/config.h"
#include "cx/compilation_database.h" #include "cx/compilation_database.h"
#include "uml/class_diagram_model.h"
#include "uml/class_diagram_visitor.h"
#include "util/util.h" #include "util/util.h"
#include <cppast/cpp_entity_index.hpp> #include <cppast/cpp_entity_index.hpp>
@@ -33,16 +36,16 @@
#include <sstream> #include <sstream>
namespace clanguml { namespace clanguml {
namespace generators {
namespace class_diagram { namespace class_diagram {
namespace puml { namespace generators {
namespace plantuml {
using diagram_config = clanguml::config::class_diagram::diagram; using diagram_config = clanguml::class_diagram::model::diagram;
using diagram_model = clanguml::model::class_diagram::diagram; using diagram_model = clanguml::class_diagram::model::diagram;
using clanguml::model::class_diagram::class_; using clanguml::class_diagram::model::class_;
using clanguml::model::class_diagram::enum_; using clanguml::class_diagram::model::enum_;
using clanguml::model::class_diagram::relationship_t; using clanguml::class_diagram::model::relationship_t;
using clanguml::model::class_diagram::scope_t; using clanguml::class_diagram::model::scope_t;
using namespace clanguml::util; using namespace clanguml::util;
std::string relative_to(std::string n, std::string c); std::string relative_to(std::string n, std::string c);
@@ -74,12 +77,11 @@ private:
diagram_model &m_model; diagram_model &m_model;
}; };
} clanguml::class_diagram::model::diagram generate(
clanguml::model::class_diagram::diagram generate(
cppast::libclang_compilation_database &db, const std::string &name, cppast::libclang_compilation_database &db, const std::string &name,
clanguml::config::class_diagram &diagram); clanguml::config::class_diagram &diagram);
} }
} }
} }
}

View File

@@ -0,0 +1,143 @@
/**
* src/class_diagram/model/class.h
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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 <sstream>
namespace clanguml::class_diagram::model {
class_::class_(const std::vector<std::string> &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_member> &class_::members() const { return members_; }
const std::vector<class_method> &class_::methods() const { return methods_; }
const std::vector<class_parent> &class_::parents() const { return bases_; }
const std::vector<class_template> &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<std::string> tnames;
std::transform(templates_.cbegin(), templates_.cend(),
std::back_inserter(tnames), [this](const auto &tmplt) {
std::vector<std::string> 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(); });
}
}

View File

@@ -0,0 +1,82 @@
/**
* src/class_diagram/model/class.h
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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 <string>
#include <vector>
namespace clanguml::class_diagram::model {
class class_ : public element, public stylable_element {
public:
class_(const std::vector<std::string> &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<class_member> &members() const;
const std::vector<class_method> &methods() const;
const std::vector<class_parent> &parents() const;
const std::vector<class_template> &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<class_member> members_;
std::vector<class_method> methods_;
std::vector<class_parent> bases_;
std::vector<class_template> templates_;
std::string base_template_full_name_;
std::map<std::string, type_alias> type_aliases_;
std::string full_name_;
};
}

View File

@@ -0,0 +1,37 @@
/**
* src/class_diagram/model/class_element.cc
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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_; }
}

View File

@@ -0,0 +1,41 @@
/**
* src/class_diagram/model/class_element.h
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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 <string>
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_;
};
}

View File

@@ -0,0 +1,40 @@
/**
* src/class_diagram/model/class_member.cc
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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; }
}

View File

@@ -0,0 +1,42 @@
/**
* src/class_diagram/model/class_member.h
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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 <string>
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};
};
}

View File

@@ -0,0 +1,64 @@
/**
* src/class_diagram/model/class_method.cc
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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<method_parameter> &class_method::parameters() const
{
return parameters_;
}
void class_method::add_parameter(method_parameter &&parameter)
{
parameters_.emplace_back(std::move(parameter));
}
}

View File

@@ -0,0 +1,59 @@
/**
* src/class_diagram/model/class_method.h
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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 <string>
#include <vector>
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<method_parameter> &parameters() const;
void add_parameter(method_parameter &&parameter);
private:
std::vector<method_parameter> parameters_;
bool is_pure_virtual_{false};
bool is_virtual_{false};
bool is_const_{false};
bool is_defaulted_{false};
bool is_static_{false};
};
}

View File

@@ -0,0 +1,35 @@
/**
* src/class_diagram/model/class_parent.cc
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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_; }
}

View File

@@ -0,0 +1,42 @@
/**
* src/class_diagram/model/class_parent.h
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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 <string>
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_;
};
}

View File

@@ -0,0 +1,113 @@
/**
* src/class_diagram/model/class_relationship.cc
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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();
}
}

View File

@@ -0,0 +1,68 @@
/**
* src/class_diagram/model/class_relationship.h
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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 <string>
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};
};
}

View File

@@ -0,0 +1,60 @@
/**
* src/class_diagram/model/class_template.cc
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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());
}
}

View File

@@ -0,0 +1,50 @@
/**
* src/class_diagram/model/class_template.h
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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 <string>
#include <vector>
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};
};
}

View File

@@ -0,0 +1,82 @@
/**
* src/class_diagram/model/decorated_element.cc
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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<decorators::skip>(d))
return true;
return false;
}
bool decorated_element::skip_relationship() const
{
for (auto d : decorators_)
if (std::dynamic_pointer_cast<decorators::skip_relationship>(d))
return true;
return false;
}
std::pair<relationship_t, std::string> decorated_element::relationship() const
{
for (auto &d : decorators_)
if (std::dynamic_pointer_cast<decorators::association>(d))
return {relationship_t::kAssociation,
std::dynamic_pointer_cast<decorators::relationship>(d)
->multiplicity};
else if (std::dynamic_pointer_cast<decorators::aggregation>(d))
return {relationship_t::kAggregation,
std::dynamic_pointer_cast<decorators::relationship>(d)
->multiplicity};
else if (std::dynamic_pointer_cast<decorators::composition>(d))
return {relationship_t::kComposition,
std::dynamic_pointer_cast<decorators::relationship>(d)
->multiplicity};
return {relationship_t::kNone, ""};
}
std::string decorated_element::style_spec()
{
for (auto d : decorators_)
if (std::dynamic_pointer_cast<decorators::style>(d))
return std::dynamic_pointer_cast<decorators::style>(d)->spec;
return "";
}
const std::vector<std::shared_ptr<decorators::decorator>> &
decorated_element::decorators() const
{
return decorators_;
}
void decorated_element::add_decorators(
const std::vector<std::shared_ptr<decorators::decorator>> &decorators)
{
for (auto d : decorators) {
decorators_.push_back(d);
}
}
}

View File

@@ -0,0 +1,50 @@
/**
* src/class_diagram/model/decorated_element.h
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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 <memory>
#include <string>
#include <vector>
namespace clanguml::class_diagram::model {
class decorated_element {
public:
bool skip() const;
bool skip_relationship() const;
std::pair<relationship_t, std::string> relationship() const;
std::string style_spec();
const std::vector<std::shared_ptr<decorators::decorator>> &
decorators() const;
void add_decorators(
const std::vector<std::shared_ptr<decorators::decorator>> &decorators);
private:
std::vector<std::shared_ptr<decorators::decorator>> decorators_;
};
}

View File

@@ -0,0 +1,85 @@
/**
* src/class_diagram/model/diagram.cc
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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<class_> diagram::classes() const { return classes_; }
const std::vector<enum_> 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));
}
}

View File

@@ -0,0 +1,55 @@
/**
* src/class_diagram/model/diagram.h
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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 <string>
#include <vector>
namespace clanguml::class_diagram::model {
class diagram {
public:
std::string name() const;
void set_name(const std::string &name);
const std::vector<class_> classes() const;
const std::vector<enum_> 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<class_> classes_;
std::vector<enum_> enums_;
std::map<std::string, type_alias> type_aliases_;
};
}

View File

@@ -0,0 +1,68 @@
/**
* src/class_diagram/model/element.cc
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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<std::string> &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<std::string> &un)
{
using_namespaces_ = un;
}
const std::vector<std::string> &element::using_namespaces() const
{
return using_namespaces_;
}
std::vector<class_relationship> &element::relationships()
{
return relationships_;
}
const std::vector<class_relationship> &element::relationships() const
{
return relationships_;
}
}

View File

@@ -0,0 +1,66 @@
/**
* src/class_diagram/model/element.h
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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 <atomic>
#include <string>
#include <vector>
namespace clanguml::class_diagram::model {
class element : public decorated_element {
public:
element(const std::vector<std::string> &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<std::string> &ns) { namespace_ = ns; }
std::vector<std::string> get_namespace() const { return namespace_; }
virtual std::string full_name(bool relative) const { return name(); }
void set_using_namespaces(const std::vector<std::string> &un);
const std::vector<std::string> &using_namespaces() const;
std::vector<class_relationship> &relationships();
const std::vector<class_relationship> &relationships() const;
void add_relationship(class_relationship &&cr);
protected:
const uint64_t m_id{0};
private:
std::string name_;
std::vector<std::string> namespace_;
std::vector<std::string> using_namespaces_;
std::vector<class_relationship> relationships_;
static std::atomic_uint64_t m_nextId;
};
}

View File

@@ -0,0 +1,51 @@
/**
* src/class_diagram/model/enum.cc
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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 <sstream>
namespace clanguml::class_diagram::model {
enum_::enum_(const std::vector<std::string> &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<std::string> &enum_::constants() { return constants_; }
const std::vector<std::string> &enum_::constants() const { return constants_; }
}

View File

@@ -0,0 +1,43 @@
/**
* src/class_diagram/model/enum.h
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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 <string>
#include <vector>
namespace clanguml::class_diagram::model {
class enum_ : public element, public stylable_element {
public:
enum_(const std::vector<std::string> &using_namespaces);
friend bool operator==(const enum_ &l, const enum_ &r);
std::string full_name(bool relative = true) const override;
std::vector<std::string> &constants();
const std::vector<std::string> &constants() const;
private:
std::vector<std::string> constants_;
};
}

View File

@@ -0,0 +1,39 @@
/**
* src/class_diagram/model/enums.h
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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
};
}

View File

@@ -0,0 +1,51 @@
/**
* src/class_diagram/model/method_parameter.cc
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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<std::string> &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());
}
}

View File

@@ -0,0 +1,47 @@
/**
* src/class_diagram/model/method_parameter.h
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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 <string>
#include <vector>
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<std::string> &using_namespaces) const;
private:
std::string type_;
std::string name_;
std::string default_value_;
};
}

View File

@@ -0,0 +1,27 @@
/**
* src/class_diagram/model/stylable_element.cc
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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_; }
}

View File

@@ -0,0 +1,33 @@
/**
* src/class_diagram/model/stylable_element.h
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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 <string>
namespace clanguml::class_diagram::model {
class stylable_element {
public:
void set_style(const std::string &style);
std::string style() const;
private:
std::string style_;
};
}

View File

@@ -0,0 +1,34 @@
/**
* src/class_diagram/model/type_alias.cc
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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_; }
}

View File

@@ -0,0 +1,37 @@
/**
* src/class_diagram/model/type_alias.h
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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 <string>
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_;
};
}

View File

@@ -0,0 +1,57 @@
/**
* src/class_diagram/model/visitor/element_visitor_context.cc
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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 <typename T>
element_visitor_context<T>::element_visitor_context(
clanguml::class_diagram::model::diagram &diagram, T &element)
: element_{element}
, diagram_{diagram}
{
}
template <typename T>
void element_visitor_context<T>::set_parent_class(
clanguml::class_diagram::model::class_ *parent_class)
{
parent_class_ = parent_class;
}
template <typename T>
clanguml::class_diagram::model::class_ *
element_visitor_context<T>::parent_class()
{
return parent_class_;
}
template <typename T> T &element_visitor_context<T>::element()
{
return element_;
}
template <typename T>
clanguml::class_diagram::model::diagram &element_visitor_context<T>::diagram()
{
return diagram_;
}
}

View File

@@ -0,0 +1,48 @@
/**
* src/class_diagram/model/visitor/element_visitor_context.h
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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 <typename T> 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_;
};
}

View File

@@ -0,0 +1,135 @@
/**
* src/class_diagram/visitor/translation_unit_context.cc
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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<const cppast::cpp_type> &&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<const cppast::cpp_type>
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<const cppast::cpp_type>
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<const cppast::cpp_type> &&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<const cppast::cpp_type>
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<std::string> &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_;
}
}

View File

@@ -0,0 +1,87 @@
/**
* src/class_diagram/visitor/translation_unit_context.h
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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 <cppast/cpp_entity_index.hpp>
#include <cppast/cpp_type.hpp>
#include <type_safe/reference.hpp>
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<const cppast::cpp_type> &&ref);
type_safe::object_ref<const cppast::cpp_type> get_type_alias(
const std::string &full_name) const;
type_safe::object_ref<const cppast::cpp_type> 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<const cppast::cpp_type> &&ref);
type_safe::object_ref<const cppast::cpp_type> get_type_alias_template(
const std::string &full_name) const;
void push_namespace(const std::string &ns);
void pop_namespace();
const std::vector<std::string> &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<std::string> 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<std::string, type_safe::object_ref<const cppast::cpp_type>>
alias_index_;
// Map of discovered template aliases (declared with 'using' keyword)
std::map<std::string, type_safe::object_ref<const cppast::cpp_type>>
alias_template_index_;
};
}

View File

@@ -1,5 +1,5 @@
/** /**
* src/uml/class_diagram_visitor.h * src/class_diagram/visitor/translation_unit_visitor.h
* *
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com> * Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
* *
@@ -17,7 +17,8 @@
*/ */
#pragma once #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 "config/config.h"
#include "cx/cursor.h" #include "cx/cursor.h"
@@ -27,6 +28,7 @@
#include <cppast/cpp_function_template.hpp> #include <cppast/cpp_function_template.hpp>
#include <cppast/cpp_member_function.hpp> #include <cppast/cpp_member_function.hpp>
#include <cppast/cpp_member_variable.hpp> #include <cppast/cpp_member_variable.hpp>
#include <cppast/cpp_template.hpp>
#include <cppast/cpp_template_parameter.hpp> #include <cppast/cpp_template_parameter.hpp>
#include <cppast/cpp_type.hpp> #include <cppast/cpp_type.hpp>
#include <cppast/visitor.hpp> #include <cppast/visitor.hpp>
@@ -37,59 +39,13 @@
#include <memory> #include <memory>
#include <string> #include <string>
namespace clanguml { namespace clanguml::class_diagram::visitor {
namespace visitor {
namespace class_diagram {
struct tu_context { class translation_unit_visitor {
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<const cppast::cpp_type> &&ref);
type_safe::object_ref<const cppast::cpp_type> get_type_alias(
const std::string &full_name) const;
type_safe::object_ref<const cppast::cpp_type> 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<const cppast::cpp_type> &&ref);
type_safe::object_ref<const cppast::cpp_type> get_type_alias_template(
const std::string &full_name) const;
std::vector<std::string> namespace_;
cppast::cpp_entity_index &entity_index;
clanguml::model::class_diagram::diagram &d;
const clanguml::config::class_diagram &config;
std::map<std::string, type_safe::object_ref<const cppast::cpp_type>>
alias_index;
std::map<std::string, type_safe::object_ref<const cppast::cpp_type>>
alias_template_index;
};
template <typename T> 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 {
public: public:
tu_visitor(cppast::cpp_entity_index &idx_, translation_unit_visitor(cppast::cpp_entity_index &idx,
clanguml::model::class_diagram::diagram &d_, clanguml::class_diagram::model::diagram &diagram,
const clanguml::config::class_diagram &config_); const clanguml::config::class_diagram &config);
void operator()(const cppast::cpp_entity &file); void operator()(const cppast::cpp_entity &file);
@@ -100,78 +56,81 @@ public:
void process_enum_declaration(const cppast::cpp_enum &enm); void process_enum_declaration(const cppast::cpp_enum &enm);
void process_anonymous_enum(const cppast::cpp_enum &en, 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); cppast::cpp_access_specifier_kind as);
void process_field(const cppast::cpp_member_variable &mv, 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); cppast::cpp_access_specifier_kind as);
bool process_field_with_template_instantiation( bool process_field_with_template_instantiation(
const cppast::cpp_member_variable &mv, const cppast::cpp_type &tr, const cppast::cpp_member_variable &mv, const cppast::cpp_type &tr,
clanguml::model::class_diagram::class_ &c, clanguml::class_diagram::model::class_ &c,
clanguml::model::class_diagram::class_member &m, clanguml::class_diagram::model::class_member &m,
cppast::cpp_access_specifier_kind as); cppast::cpp_access_specifier_kind as);
void process_static_field(const cppast::cpp_variable &mv, 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); cppast::cpp_access_specifier_kind as);
void process_method(const cppast::cpp_member_function &mf, 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); cppast::cpp_access_specifier_kind as);
void process_template_method(const cppast::cpp_function_template &mf, 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); cppast::cpp_access_specifier_kind as);
void process_static_method(const cppast::cpp_function &mf, 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); cppast::cpp_access_specifier_kind as);
void process_constructor(const cppast::cpp_constructor &mf, 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); cppast::cpp_access_specifier_kind as);
void process_destructor(const cppast::cpp_destructor &mf, 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); cppast::cpp_access_specifier_kind as);
void process_function_parameter(const cppast::cpp_function_parameter &param, void process_function_parameter(const cppast::cpp_function_parameter &param,
clanguml::model::class_diagram::class_method &m, clanguml::class_diagram::model::class_method &m,
clanguml::model::class_diagram::class_ &c, clanguml::class_diagram::model::class_ &c,
const std::set<std::string> &template_parameter_names = {}); const std::set<std::string> &template_parameter_names = {});
bool find_relationships(const cppast::cpp_type &t, bool find_relationships(const cppast::cpp_type &t,
std::vector<std::pair<std::string, std::vector<std::pair<std::string,
clanguml::model::class_diagram::relationship_t>> &relationships, clanguml::class_diagram::model::relationship_t>> &relationships,
clanguml::model::class_diagram::relationship_t relationship_hint = clanguml::class_diagram::model::relationship_t relationship_hint =
clanguml::model::class_diagram::relationship_t::kNone); clanguml::class_diagram::model::relationship_t::kNone);
void process_template_type_parameter( void process_template_type_parameter(
const cppast::cpp_template_type_parameter &t, const cppast::cpp_template_type_parameter &t,
clanguml::model::class_diagram::class_ &parent); clanguml::class_diagram::model::class_ &parent);
void process_template_nontype_parameter( void process_template_nontype_parameter(
const cppast::cpp_non_type_template_parameter &t, 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( void process_template_template_parameter(
const cppast::cpp_template_template_parameter &t, 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, void process_friend(const cppast::cpp_friend &t,
clanguml::model::class_diagram::class_ &parent); clanguml::class_diagram::model::class_ &parent);
private: private:
clanguml::model::class_diagram::class_ build_template_instantiation( clanguml::class_diagram::model::class_ build_template_instantiation(
const cppast::cpp_template_instantiation_type &t, const cppast::cpp_template_instantiation_type &t,
std::optional<clanguml::model::class_diagram::class_ *> parent = {}); std::optional<clanguml::class_diagram::model::class_ *> 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); 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;
}; };
} }
}
}

View File

@@ -89,7 +89,8 @@ bool diagram::should_include(const std::string &name_) const
return false; 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) { for (const auto &s : exclude.scopes) {
if (s == scope) if (s == scope)
@@ -127,13 +128,13 @@ bool class_diagram::has_class(std::string clazz)
} }
namespace YAML { namespace YAML {
using clanguml::class_diagram::model::scope_t;
using clanguml::config::class_diagram; using clanguml::config::class_diagram;
using clanguml::config::config; using clanguml::config::config;
using clanguml::config::filter; using clanguml::config::filter;
using clanguml::config::plantuml; using clanguml::config::plantuml;
using clanguml::config::sequence_diagram; using clanguml::config::sequence_diagram;
using clanguml::config::source_location; using clanguml::config::source_location;
using clanguml::model::class_diagram::scope_t;
template <> struct convert<scope_t> { template <> struct convert<scope_t> {
static bool decode(const Node &node, scope_t &rhs) static bool decode(const Node &node, scope_t &rhs)
{ {

View File

@@ -17,7 +17,8 @@
*/ */
#pragma once #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 "util/util.h"
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
@@ -55,7 +56,7 @@ struct filter {
// E.g.: // E.g.:
// - public // - public
// - private // - private
std::vector<model::class_diagram::scope_t> scopes; std::vector<class_diagram::model::scope_t> scopes;
}; };
struct diagram { struct diagram {
@@ -76,7 +77,7 @@ struct diagram {
bool should_include(const std::string &name_) const; 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 { struct source_location {

View File

@@ -22,7 +22,6 @@
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include "cx/util.h" #include "cx/util.h"
#include "uml/class_diagram_model.h"
#include "util/util.h" #include "util/util.h"
namespace clanguml { namespace clanguml {

View File

@@ -1,5 +1,5 @@
/** /**
* src/uml/decorators.cc * src/decorators/decorators.cc
* *
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com> * Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
* *

View File

@@ -1,5 +1,5 @@
/** /**
* src/uml/decorators.h * src/decorators/decorators.h
* *
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com> * Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
* *

View File

@@ -18,13 +18,13 @@
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_DEBUG #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 "config/config.h"
#include "cx/compilation_database.h" #include "cx/compilation_database.h"
#include "puml/class_diagram_generator.h" #include "sequence_diagram/generators/plantuml/sequence_diagram_generator.h"
#include "puml/sequence_diagram_generator.h" #include "sequence_diagram/visitor/translation_unit_context.h"
#include "uml/class_diagram_model.h"
#include "uml/class_diagram_visitor.h"
#include "uml/sequence_diagram_visitor.h"
#include "util/util.h" #include "util/util.h"
#include <cli11/CLI11.hpp> #include <cli11/CLI11.hpp>
@@ -98,18 +98,20 @@ int main(int argc, const char *argv[])
ofs.open(path, std::ofstream::out | std::ofstream::trunc); ofs.open(path, std::ofstream::out | std::ofstream::trunc);
if (std::dynamic_pointer_cast<class_diagram>(diagram)) { if (std::dynamic_pointer_cast<class_diagram>(diagram)) {
auto model = generators::class_diagram::generate( auto model =
clanguml::class_diagram::generators::plantuml::generate(
db2, name, dynamic_cast<class_diagram &>(*diagram)); db2, name, dynamic_cast<class_diagram &>(*diagram));
ofs << clanguml::generators::class_diagram::puml::generator( ofs << clanguml::class_diagram::generators::plantuml::generator(
dynamic_cast<clanguml::config::class_diagram &>(*diagram), dynamic_cast<clanguml::config::class_diagram &>(*diagram),
model); model);
} }
else if (std::dynamic_pointer_cast<sequence_diagram>(diagram)) { else if (std::dynamic_pointer_cast<sequence_diagram>(diagram)) {
auto model = generators::sequence_diagram::generate( auto model =
clanguml::sequence_diagram::generators::plantuml::generate(
db, name, dynamic_cast<sequence_diagram &>(*diagram)); db, name, dynamic_cast<sequence_diagram &>(*diagram));
ofs << clanguml::generators::sequence_diagram::puml::generator( ofs << clanguml::sequence_diagram::generators::plantuml::generator(
dynamic_cast<clanguml::config::sequence_diagram &>(*diagram), dynamic_cast<clanguml::config::sequence_diagram &>(*diagram),
model); model);
} }

View File

@@ -1,5 +1,5 @@
/** /**
* src/puml/sequence_diagram_generator.h * src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc
* *
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com> * Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
* *
@@ -16,20 +16,21 @@
* limitations under the License. * limitations under the License.
*/ */
#include "puml/sequence_diagram_generator.h" #include "sequence_diagram_generator.h"
namespace clanguml::generators::sequence_diagram { #include "sequence_diagram/visitor/translation_unit_context.h"
namespace puml {
using diagram_model = clanguml::model::sequence_diagram::diagram; namespace clanguml::sequence_diagram::generators::plantuml {
using diagram_model = clanguml::sequence_diagram::model::diagram;
using diagram_config = clanguml::config::sequence_diagram::diagram; using diagram_config = clanguml::config::sequence_diagram::diagram;
using clanguml::config::source_location; using clanguml::config::source_location;
using clanguml::model::sequence_diagram::activity; using clanguml::sequence_diagram::model::activity;
using clanguml::model::sequence_diagram::message; using clanguml::sequence_diagram::model::message;
using clanguml::model::sequence_diagram::message_t; using clanguml::sequence_diagram::model::message_t;
using clanguml::visitor::sequence_diagram::tu_context; using clanguml::sequence_diagram::visitor::translation_unit_context;
using namespace clanguml::util; using namespace clanguml::util;
// //
// generator // generator
// //
@@ -117,14 +118,13 @@ std::ostream &operator<<(std::ostream &os, const generator &g)
g.generate(os); g.generate(os);
return 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::cx::compilation_database &db, const std::string &name,
clanguml::config::sequence_diagram &diagram) clanguml::config::sequence_diagram &diagram)
{ {
spdlog::info("Generating diagram {}.puml", name); spdlog::info("Generating diagram {}.puml", name);
clanguml::model::sequence_diagram::diagram d; clanguml::sequence_diagram::model::diagram d;
d.name = name; d.name = name;
// Get all translation units matching the glob from diagram // Get all translation units matching the glob from diagram
@@ -155,9 +155,10 @@ clanguml::model::sequence_diagram::diagram generate(
spdlog::debug("Cursor name: {}", spdlog::debug("Cursor name: {}",
clang_getCString(clang_getCursorDisplayName(cursor))); 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, auto res = clang_visitChildren(cursor,
clanguml::visitor::sequence_diagram::translation_unit_visitor, clanguml::sequence_diagram::visitor::translation_unit_visitor,
&ctx); &ctx);
spdlog::debug("Processing result: {}", res); spdlog::debug("Processing result: {}", res);

View File

@@ -1,5 +1,5 @@
/** /**
* src/puml/sequence_diagram_generator.h * src/sequence_diagram/generators/plantuml/sequence_diagram_generator.h
* *
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com> * Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
* *
@@ -19,8 +19,8 @@
#include "config/config.h" #include "config/config.h"
#include "cx/compilation_database.h" #include "cx/compilation_database.h"
#include "uml/sequence_diagram_model.h" #include "sequence_diagram/model/diagram.h"
#include "uml/sequence_diagram_visitor.h" #include "sequence_diagram/visitor/translation_unit_visitor.h"
#include "util/util.h" #include "util/util.h"
#include <glob/glob.hpp> #include <glob/glob.hpp>
@@ -31,25 +31,25 @@
#include <sstream> #include <sstream>
namespace clanguml { namespace clanguml {
namespace generators {
namespace sequence_diagram { 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 { class generator {
public: public:
generator(clanguml::config::sequence_diagram &config, diagram_model &model); 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; 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; 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; std::ostream &ostr) const;
void generate(std::ostream &ostr) const; void generate(std::ostream &ostr) const;
@@ -58,15 +58,14 @@ public:
private: private:
clanguml::config::sequence_diagram &m_config; clanguml::config::sequence_diagram &m_config;
clanguml::model::sequence_diagram::diagram &m_model; clanguml::sequence_diagram::model::diagram &m_model;
}; };
} clanguml::sequence_diagram::model::diagram generate(
clanguml::model::sequence_diagram::diagram generate(
clanguml::cx::compilation_database &db, const std::string &name, clanguml::cx::compilation_database &db, const std::string &name,
clanguml::config::sequence_diagram &diagram); clanguml::config::sequence_diagram &diagram);
} }
} }
} }
}

View File

@@ -1,5 +1,5 @@
/** /**
* src/uml/sequence_diagram_model.cc * src/sequence_diagram/model/activity.cc
* *
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com> * Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
* *
@@ -16,8 +16,8 @@
* limitations under the License. * limitations under the License.
*/ */
#include "sequence_diagram_visitor.h" #include "activity.h"
namespace clanguml::model::sequence_diagram { namespace clanguml::sequence_diagram::model {
} }

View File

@@ -0,0 +1,33 @@
/**
* src/sequence_diagram/model/activity.h
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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 <string>
#include <vector>
namespace clanguml::sequence_diagram::model {
struct activity {
std::string usr;
std::string from;
std::vector<message> messages;
};
}

View File

@@ -0,0 +1,32 @@
/**
* src/sequence_diagram/model/diagram.cc
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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 <clang-c/CXCompilationDatabase.h>
#include <clang-c/Index.h>
#include <spdlog/spdlog.h>
#include <functional>
#include <memory>
#include <string>
#include <vector>
namespace clanguml::sequence_diagram::model {
}

View File

@@ -0,0 +1,34 @@
/**
* src/sequence_diagram/model/diagram.h
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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 <map>
#include <string>
namespace clanguml::sequence_diagram::model {
struct diagram {
bool started{false};
std::string name;
std::map<std::string, activity> sequences;
};
}

View File

@@ -0,0 +1,24 @@
/**
* src/sequence_diagram/model/enums.h
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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 };
}

View File

@@ -0,0 +1,23 @@
/**
* src/sequence_diagram/model/message.cc
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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 {
}

View File

@@ -1,5 +1,5 @@
/** /**
* src/uml/sequence_diagram_model.h * src/sequence_diagram/model/message.h
* *
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com> * Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
* *
@@ -17,20 +17,12 @@
*/ */
#pragma once #pragma once
#include <clang-c/CXCompilationDatabase.h> #include "enums.h"
#include <clang-c/Index.h>
#include <spdlog/spdlog.h>
#include <functional>
#include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
namespace clanguml { namespace clanguml::sequence_diagram::model {
namespace model {
namespace sequence_diagram {
enum class message_t { kCall, kReturn };
struct message { struct message {
message_t type; message_t type;
@@ -43,18 +35,4 @@ struct message {
unsigned int line; unsigned int line;
}; };
struct activity {
std::string usr;
std::string from;
std::vector<message> messages;
};
struct diagram {
bool started{false};
std::string name;
std::map<std::string, activity> sequences;
};
}
}
} }

View File

@@ -0,0 +1,68 @@
/**
* src/sequence_diagram/visitor/translation_unit_context.cc
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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 <clang-c/CXCompilationDatabase.h>
#include <clang-c/Index.h>
#include <spdlog/spdlog.h>
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<std::string> &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_;
}
}

View File

@@ -0,0 +1,59 @@
/**
* src/sequence_diagram/visitor/translation_unit_context.h
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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 <functional>
#include <memory>
#include <string>
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<std::string> &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 &current_method();
private:
std::vector<std::string> namespace_;
cx::cursor current_method_;
clanguml::sequence_diagram::model::diagram &diagram_;
const clanguml::config::sequence_diagram &config_;
};
}

View File

@@ -1,5 +1,5 @@
/** /**
* src/uml/sequence_diagram_visitor.cc * src/sequence_diagram/visitor/translation_unit_visitor.cc
* *
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com> * Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
* *
@@ -16,30 +16,21 @@
* limitations under the License. * limitations under the License.
*/ */
#include "sequence_diagram_visitor.h" #include "translation_unit_visitor.h"
namespace clanguml::visitor::sequence_diagram { #include "translation_unit_context.h"
// namespace clanguml::sequence_diagram::visitor {
// tu_context
//
tu_context::tu_context(clanguml::model::sequence_diagram::diagram &d_,
const clanguml::config::sequence_diagram &config_)
: d{d_}
, config{config_}
{
}
enum CXChildVisitResult translation_unit_visitor( enum CXChildVisitResult translation_unit_visitor(
CXCursor cx_cursor, CXCursor cx_parent, CXClientData client_data) CXCursor cx_cursor, CXCursor cx_parent, CXClientData client_data)
{ {
using clanguml::model::sequence_diagram::activity; using clanguml::sequence_diagram::model::activity;
using clanguml::model::sequence_diagram::diagram; using clanguml::sequence_diagram::model::diagram;
using clanguml::model::sequence_diagram::message; using clanguml::sequence_diagram::model::message;
using clanguml::model::sequence_diagram::message_t; 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; enum CXChildVisitResult ret = CXChildVisit_Break;
@@ -54,7 +45,7 @@ enum CXChildVisitResult translation_unit_visitor(
case CXCursor_FunctionTemplate: case CXCursor_FunctionTemplate:
case CXCursor_CXXMethod: case CXCursor_CXXMethod:
case CXCursor_FunctionDecl: case CXCursor_FunctionDecl:
ctx->current_method = cursor; ctx->set_current_method(cursor);
ret = CXChildVisit_Recurse; ret = CXChildVisit_Recurse;
break; break;
case CXCursor_CallExpr: { case CXCursor_CallExpr: {
@@ -74,25 +65,28 @@ enum CXChildVisitResult translation_unit_visitor(
clang_getFileLocation(cursor.location(), &f, &line, &column, &offset); clang_getFileLocation(cursor.location(), &f, &line, &column, &offset);
std::string file{clang_getCString(clang_getFileName(f))}; std::string file{clang_getCString(clang_getFileName(f))};
auto &d = ctx->d; auto &d = ctx->diagram();
auto &config = ctx->config; auto &config = ctx->config();
if (referenced.kind() == CXCursor_CXXMethod) { if (referenced.kind() == CXCursor_CXXMethod) {
if (config.should_include(sp_name)) { if (config.should_include(sp_name)) {
// Get calling object // Get calling object
std::string caller{}; std::string caller{};
if (ctx->current_method.semantic_parent() if (ctx->current_method()
.semantic_parent()
.is_translation_unit() || .is_translation_unit() ||
ctx->current_method.semantic_parent().is_namespace()) { ctx->current_method().semantic_parent().is_namespace()) {
caller = ctx->current_method.semantic_parent() caller = ctx->current_method()
.semantic_parent()
.fully_qualified() + .fully_qualified() +
"::" + ctx->current_method.spelling() + "()"; "::" + ctx->current_method().spelling() + "()";
} }
else { else {
caller = caller = ctx->current_method()
ctx->current_method.semantic_parent().fully_qualified(); .semantic_parent()
.fully_qualified();
} }
auto caller_usr = ctx->current_method.usr(); auto caller_usr = ctx->current_method().usr();
// Get called object // Get called object
auto callee = referenced.semantic_parent().fully_qualified(); auto callee = referenced.semantic_parent().fully_qualified();
auto callee_usr = referenced.semantic_parent().usr(); auto callee_usr = referenced.semantic_parent().usr();
@@ -105,8 +99,8 @@ enum CXChildVisitResult translation_unit_visitor(
"\n\tCURRENT_METHOD: {}\n\tFROM: '{}'\n\tTO: " "\n\tCURRENT_METHOD: {}\n\tFROM: '{}'\n\tTO: "
"{}\n\tMESSAGE: {}\n\tFROM_USR: {}\n\tTO_USR: " "{}\n\tMESSAGE: {}\n\tFROM_USR: {}\n\tTO_USR: "
"{}\n\tRETURN_TYPE: {}", "{}\n\tRETURN_TYPE: {}",
file, line, d.name, ctx->current_method.spelling(), caller, file, line, d.name, ctx->current_method().spelling(),
callee, called_message, caller_usr, callee_usr, caller, callee, called_message, caller_usr, callee_usr,
referenced.type().result_type().spelling()); referenced.type().result_type().spelling());
message m; message m;
@@ -146,5 +140,4 @@ enum CXChildVisitResult translation_unit_visitor(
return ret; return ret;
} }
} }

View File

@@ -1,5 +1,5 @@
/** /**
* src/uml/sequence_diagram_visitor.h * src/sequence_diagram/visitor/translation_unit_visitor.h
* *
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com> * Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
* *
@@ -17,35 +17,13 @@
*/ */
#pragma once #pragma once
#include "cx/cursor.h"
#include "sequence_diagram_model.h"
#include "config/config.h" #include "config/config.h"
#include "cx/cursor.h"
#include "sequence_diagram/model/diagram.h"
#include <clang-c/CXCompilationDatabase.h> namespace clanguml::sequence_diagram::visitor {
#include <clang-c/Index.h>
#include <spdlog/spdlog.h>
#include <functional>
#include <memory>
#include <string>
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<std::string> namespace_;
cx::cursor current_method;
clanguml::model::sequence_diagram::diagram &d;
const clanguml::config::sequence_diagram &config;
};
enum CXChildVisitResult translation_unit_visitor( enum CXChildVisitResult translation_unit_visitor(
CXCursor cx_cursor, CXCursor cx_parent, CXClientData client_data); CXCursor cx_cursor, CXCursor cx_parent, CXClientData client_data);
} }
}
}

View File

@@ -1,309 +0,0 @@
/**
* src/uml/class_diagram_model.cc
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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<decorators::skip>(d))
return true;
return false;
}
bool decorated_element::skip_relationship() const
{
for (auto d : decorators)
if (std::dynamic_pointer_cast<decorators::skip_relationship>(d))
return true;
return false;
}
std::pair<relationship_t, std::string> decorated_element::relationship() const
{
for (auto &d : decorators)
if (std::dynamic_pointer_cast<decorators::association>(d))
return {relationship_t::kAssociation,
std::dynamic_pointer_cast<decorators::relationship>(d)
->multiplicity};
else if (std::dynamic_pointer_cast<decorators::aggregation>(d))
return {relationship_t::kAggregation,
std::dynamic_pointer_cast<decorators::relationship>(d)
->multiplicity};
else if (std::dynamic_pointer_cast<decorators::composition>(d))
return {relationship_t::kComposition,
std::dynamic_pointer_cast<decorators::relationship>(d)
->multiplicity};
return {relationship_t::kNone, ""};
}
std::string decorated_element::style_spec()
{
for (auto d : decorators)
if (std::dynamic_pointer_cast<decorators::style>(d))
return std::dynamic_pointer_cast<decorators::style>(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<std::string> &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<std::string> &using_namespaces) const
{
using namespace clanguml::util;
std::ostringstream ostr;
ostr << ns_relative(using_namespaces, name);
if (!templates.empty()) {
std::vector<std::string> tnames;
std::transform(templates.cbegin(), templates.cend(),
std::back_inserter(tnames), [&using_namespaces](const auto &tmplt) {
std::vector<std::string> 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<std::string> &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<std::string> &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<std::string> &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 "";
}
}
}
}

View File

@@ -1,210 +0,0 @@
/**
* src/uml/class_diagram_model.h
*
* Copyright (c) 2021 Bartek Kryza <bkryza@gmail.com>
*
* 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 <clang-c/CXCompilationDatabase.h>
#include <clang-c/Index.h>
#include <spdlog/spdlog.h>
#include <atomic>
#include <functional>
#include <map>
#include <memory>
#include <sstream>
#include <string>
#include <variant>
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<std::shared_ptr<decorators::decorator>> decorators;
bool skip() const;
bool skip_relationship() const;
std::pair<relationship_t, std::string> relationship() const;
std::string style_spec();
};
class element : public decorated_element {
public:
element();
std::string alias() const;
std::string name;
std::vector<std::string> 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<std::string> &using_namespaces) const;
};
struct class_method : public class_element {
std::vector<method_parameter> 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<class_member> members;
std::vector<class_method> methods;
std::vector<class_parent> bases;
std::vector<std::string> inner_classes;
std::vector<class_relationship> relationships;
std::vector<class_template> templates;
std::string base_template_usr;
std::map<std::string, type_alias> 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<std::string> &using_namespaces) const;
bool is_abstract() const;
};
struct enum_ : public element, public stylable_element {
std::vector<std::string> constants;
std::vector<class_relationship> relationships;
friend bool operator==(const enum_ &l, const enum_ &r);
std::string full_name(
const std::vector<std::string> &using_namespaces) const;
};
struct diagram {
std::string name;
std::vector<class_> classes;
std::vector<enum_> enums;
std::map<std::string, type_alias> 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<std::string> &using_namespaces,
const std::string &full_name) const;
std::string usr_to_name(const std::vector<std::string> &using_namespaces,
const std::string &usr) const;
};
}
}
}

View File

@@ -35,7 +35,7 @@ TEST_CASE("t00002", "[test-case][class]")
auto model = generate_class_diagram(db, diagram); auto model = generate_class_diagram(db, diagram);
REQUIRE(model.name == "t00002_class"); REQUIRE(model.name() == "t00002_class");
auto puml = generate_class_puml(diagram, model); auto puml = generate_class_puml(diagram, model);
AliasMatcher _A(puml); AliasMatcher _A(puml);

View File

@@ -34,7 +34,7 @@ TEST_CASE("t00003", "[test-case][class]")
auto model = generate_class_diagram(db, diagram); auto model = generate_class_diagram(db, diagram);
REQUIRE(model.name == "t00003_class"); REQUIRE(model.name() == "t00003_class");
auto puml = generate_class_puml(diagram, model); auto puml = generate_class_puml(diagram, model);
AliasMatcher _A(puml); AliasMatcher _A(puml);

Some files were not shown because too many files have changed in this diff Show More