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:
submodules: recursive
- name: Install deps
run: sudo apt install ccache cmake libyaml-cpp-dev libfmt-dev libspdlog-dev clang-12 libclang-12-dev libclang-cpp12-dev
run: sudo apt install git make gcc-10 g++-10 ccache cmake libyaml-cpp-dev libfmt-dev libspdlog-dev clang-12 libclang-12-dev libclang-cpp12-dev
- name: Select g++ version
run: |
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 10
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 10
- name: Build and unit test
run: |
make debug
NUMPROC=2 make debug
make test

1
CODE_OF_CONDUCT.md Normal file
View File

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

View File

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

View File

@@ -2,7 +2,7 @@
![linux build](https://github.com/bkryza/clang-uml/actions/workflows/build.yml/badge.svg)
`clang-uml` is an automatic [PlantUML](https://plantuml.com) class and sequence
`clang-uml` is an automatic C++ to [PlantUML](https://plantuml.com) class and sequence
diagram generator, driven by YAML configuration files. The main idea behind the
project is to easily maintain up-to-date diagrams within a code-base or document
existing project code. The configuration file or files for `clang-uml` define the

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
File t00018_impl.cc
```cpp
#include "t00018_impl.h"
#include "t00018.h"
namespace clanguml {
namespace t00018 {
namespace impl {
widget::widget(int n)
: n(n)
{
}
void widget::draw(const clanguml::t00018::widget &w) const
{
if (w.shown())
std::cout << "drawing a const widget " << n << '\n';
}
void widget::draw(const clanguml::t00018::widget &w)
{
if (w.shown())
std::cout << "drawing a non-const widget " << n << '\n';
}
}
}
}
```
File t00018_impl.h
```cpp
#pragma once
@@ -131,6 +101,36 @@ widget &widget::operator=(widget &&) = default;
}
}
```
File t00018_impl.cc
```cpp
#include "t00018_impl.h"
#include "t00018.h"
namespace clanguml {
namespace t00018 {
namespace impl {
widget::widget(int n)
: n(n)
{
}
void widget::draw(const clanguml::t00018::widget &w) const
{
if (w.shown())
std::cout << "drawing a const widget " << n << '\n';
}
void widget::draw(const clanguml::t00018::widget &w)
{
if (w.shown())
std::cout << "drawing a non-const widget " << n << '\n';
}
}
}
}
```
## Generated UML diagrams
![t00018_class](./t00018_class.png "Pimpl pattern")

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
File t00019.cc
File t00019_layer2.h
```cpp
#include "t00019_base.h"
#include "t00019_layer1.h"
#include "t00019_layer2.h"
#include "t00019_layer3.h"
#include <memory>
#pragma once
namespace clanguml {
namespace t00019 {
class A {
public:
std::unique_ptr<Layer1<Layer2<Layer3<Base>>>> layers;
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();
}
};
}
}
@@ -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
```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
![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>
*
@@ -18,9 +18,10 @@
#include "class_diagram_generator.h"
namespace clanguml::generators::class_diagram {
#include "util/error.h"
namespace clanguml::class_diagram::generators::plantuml {
namespace puml {
std::string relative_to(std::string n, std::string c)
{
if (c.rfind(n) == std::string::npos)
@@ -29,10 +30,6 @@ std::string relative_to(std::string n, std::string c)
return c.substr(n.size() + 2);
}
//
// generator
//
generator::generator(
clanguml::config::class_diagram &config, diagram_model &model)
: m_config(config)
@@ -106,7 +103,7 @@ void generator::generate_alias(const class_ &c, std::ostream &ostr) const
if (c.is_abstract())
class_type = "abstract";
ostr << class_type << " \"" << c.full_name(m_config.using_namespace);
ostr << class_type << " \"" << c.full_name();
ostr << "\" as " << c.alias() << '\n';
}
@@ -114,7 +111,7 @@ void generator::generate_alias(const class_ &c, std::ostream &ostr) const
void generator::generate_alias(const enum_ &e, std::ostream &ostr) const
{
ostr << "enum"
<< " \"" << e.full_name(m_config.using_namespace);
<< " \"" << e.full_name();
ostr << "\" as " << e.alias() << '\n';
}
@@ -130,32 +127,32 @@ void generator::generate(const class_ &c, std::ostream &ostr) const
ostr << class_type << " " << c.alias();
if (!c.style.empty())
ostr << " " << c.style;
if (!c.style().empty())
ostr << " " << c.style();
ostr << " {" << '\n';
//
// Process methods
//
for (const auto &m : c.methods) {
if (!m_config.should_include(m.scope))
for (const auto &m : c.methods()) {
if (!m_config.should_include(m.scope()))
continue;
if (m.is_pure_virtual)
if (m.is_pure_virtual())
ostr << "{abstract} ";
if (m.is_static)
if (m.is_static())
ostr << "{static} ";
std::string type{m.type};
std::string type{m.type()};
ostr << to_string(m.scope) << m.name;
ostr << to_string(m.scope()) << m.name();
ostr << "(";
if (true) { // TODO: add option to disable parameter generation
std::vector<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) {
return mp.to_string(m_config.using_namespace);
});
@@ -163,15 +160,15 @@ void generator::generate(const class_ &c, std::ostream &ostr) const
}
ostr << ")";
if (m.is_const)
if (m.is_const())
ostr << " const";
assert(!(m.is_pure_virtual && m.is_defaulted));
assert(!(m.is_pure_virtual() && m.is_defaulted()));
if (m.is_pure_virtual)
if (m.is_pure_virtual())
ostr << " = 0";
if (m.is_defaulted)
if (m.is_defaulted())
ostr << " = default";
ostr << " : " << ns_relative(uns, type);
@@ -186,49 +183,35 @@ void generator::generate(const class_ &c, std::ostream &ostr) const
std::stringstream all_relations_str;
std::set<std::string> unique_relations;
for (const auto &r : c.relationships) {
if (!m_config.should_include_relationship(name(r.type)))
for (const auto &r : c.relationships()) {
if (!m_config.should_include_relationship(name(r.type())))
continue;
LOG_DBG("== Processing relationship {}", to_string(r.type));
LOG_DBG("== Processing relationship {}", to_string(r.type()));
std::stringstream relstr;
std::string destination;
try {
if (r.destination.find("#") != std::string::npos ||
r.destination.find("@") != std::string::npos) {
destination = m_model.usr_to_name(uns, r.destination);
// If something went wrong and we have an empty destination
// generate the relationship but comment it out for
// debugging
if (destination.empty()) {
relstr << "' ";
destination = r.destination;
}
}
else {
destination = r.destination;
}
destination = r.destination();
LOG_DBG("=== Destination is: {}", destination);
std::string puml_relation;
if (!r.multiplicity_source.empty())
puml_relation += "\"" + r.multiplicity_source + "\" ";
if (!r.multiplicity_source().empty())
puml_relation += "\"" + r.multiplicity_source() + "\" ";
puml_relation += to_string(r.type, r.style);
puml_relation += to_string(r.type(), r.style());
if (!r.multiplicity_destination.empty())
puml_relation += " \"" + r.multiplicity_destination + "\"";
if (!r.multiplicity_destination().empty())
puml_relation += " \"" + r.multiplicity_destination() + "\"";
relstr << m_model.to_alias(uns, ns_relative(uns, c.full_name(uns)))
<< " " << puml_relation << " "
<< m_model.to_alias(uns, ns_relative(uns, destination));
relstr << m_model.to_alias(ns_relative(uns, c.full_name())) << " "
<< puml_relation << " "
<< m_model.to_alias(ns_relative(uns, destination));
if (!r.label.empty()) {
relstr << " : " << to_string(r.scope) << r.label;
rendered_relations.emplace(r.label);
if (!r.label().empty()) {
relstr << " : " << to_string(r.scope()) << r.label();
rendered_relations.emplace(r.label());
}
if (unique_relations.count(relstr.str()) == 0) {
@@ -244,52 +227,51 @@ void generator::generate(const class_ &c, std::ostream &ostr) const
catch (error::uml_alias_missing &e) {
LOG_ERROR("=== Skipping {} relation from {} to {} due "
"to: {}",
to_string(r.type), c.full_name(uns), destination, e.what());
to_string(r.type()), c.full_name(), destination, e.what());
}
}
//
// Process members
//
for (const auto &m : c.members) {
if (!m_config.should_include(m.scope))
for (const auto &m : c.members()) {
if (!m_config.should_include(m.scope()))
continue;
if (!m_config.include_relations_also_as_members &&
rendered_relations.find(m.name) != rendered_relations.end())
rendered_relations.find(m.name()) != rendered_relations.end())
continue;
if (m.is_static)
if (m.is_static())
ostr << "{static} ";
ostr << to_string(m.scope) << m.name << " : "
<< ns_relative(uns, m.type) << '\n';
ostr << to_string(m.scope()) << m.name() << " : "
<< ns_relative(uns, m.type()) << '\n';
}
ostr << "}" << '\n';
if (m_config.should_include_relationship("inheritance"))
for (const auto &b : c.bases) {
for (const auto &b : c.parents()) {
std::stringstream relstr;
try {
relstr << m_model.to_alias(uns, ns_relative(uns, b.name))
relstr << m_model.to_alias(ns_relative(uns, b.name()))
<< " <|-- "
<< m_model.to_alias(
uns, ns_relative(uns, c.full_name(uns)))
<< m_model.to_alias(ns_relative(uns, c.full_name()))
<< '\n';
ostr << relstr.str();
}
catch (error::uml_alias_missing &e) {
LOG_ERROR("=== Skipping inheritance relation from {} to {} due "
"to: {}",
b.name, c.name, e.what());
b.name(), c.name(), e.what());
}
}
//
// Process notes
//
for (auto decorator : c.decorators) {
for (auto decorator : c.decorators()) {
auto note = std::dynamic_pointer_cast<decorators::note>(decorator);
if (note && note->applies_to_diagram(m_config.name)) {
ostr << "note " << note->position << " of " << c.alias() << '\n'
@@ -306,45 +288,35 @@ void generator::generate(const enum_ &e, std::ostream &ostr) const
{
ostr << "enum " << e.alias();
if (!e.style.empty())
ostr << " " << e.style;
if (!e.style().empty())
ostr << " " << e.style();
ostr << " {" << '\n';
for (const auto &enum_constant : e.constants) {
for (const auto &enum_constant : e.constants()) {
ostr << enum_constant << '\n';
}
ostr << "}" << '\n';
for (const auto &r : e.relationships) {
if (!m_config.should_include_relationship(name(r.type)))
for (const auto &r : e.relationships()) {
if (!m_config.should_include_relationship(name(r.type())))
continue;
std::string destination;
std::stringstream relstr;
try {
if (r.destination.find("#") != std::string::npos ||
r.destination.find("@") != std::string::npos) {
destination = m_model.usr_to_name(
m_config.using_namespace, r.destination);
if (destination.empty()) {
relstr << "' ";
destination = r.destination;
}
}
else {
destination = r.destination;
}
relstr << m_model.to_alias(m_config.using_namespace,
ns_relative(m_config.using_namespace, e.name))
<< " " << to_string(r.type) << " "
<< m_model.to_alias(m_config.using_namespace,
destination = r.destination();
relstr << m_model.to_alias(
ns_relative(m_config.using_namespace, e.name()))
<< " " << to_string(r.type()) << " "
<< m_model.to_alias(
ns_relative(m_config.using_namespace, destination));
if (!r.label.empty())
relstr << " : " << r.label;
if (!r.label().empty())
relstr << " : " << r.label();
relstr << '\n';
@@ -353,14 +325,14 @@ void generator::generate(const enum_ &e, std::ostream &ostr) const
catch (error::uml_alias_missing &ex) {
LOG_ERROR("Skipping {} relation from {} to {} due "
"to: {}",
to_string(r.type), e.name, destination, ex.what());
to_string(r.type()), e.full_name(), destination, ex.what());
}
}
//
// Process notes
//
for (auto decorator : e.decorators) {
for (auto decorator : e.decorators()) {
auto note = std::dynamic_pointer_cast<decorators::note>(decorator);
if (note && note->applies_to_diagram(m_config.name)) {
ostr << "note " << note->position << " of " << e.alias() << '\n'
@@ -378,9 +350,8 @@ void generator::generate(std::ostream &ostr) const
std::string note{b};
std::tuple<std::string, size_t, size_t> alias_match;
while (util::find_element_alias(note, alias_match)) {
auto alias = m_model.to_alias(m_config.using_namespace,
ns_relative(
m_config.using_namespace, std::get<0>(alias_match)));
auto alias = m_model.to_alias(ns_relative(
m_config.using_namespace, std::get<0>(alias_match)));
note.replace(
std::get<1>(alias_match), std::get<2>(alias_match), alias);
}
@@ -388,24 +359,24 @@ void generator::generate(std::ostream &ostr) const
}
if (m_config.should_include_entities("classes")) {
for (const auto &c : m_model.classes) {
if (!c.is_template_instantiation &&
!m_config.should_include(c.name))
for (const auto &c : m_model.classes()) {
if (!c.is_template_instantiation() &&
!m_config.should_include(c.name()))
continue;
generate_alias(c, ostr);
ostr << '\n';
}
for (const auto &e : m_model.enums) {
if (!m_config.should_include(e.name))
for (const auto &e : m_model.enums()) {
if (!m_config.should_include(e.name()))
continue;
generate_alias(e, ostr);
ostr << '\n';
}
for (const auto &c : m_model.classes) {
if (!c.is_template_instantiation &&
!m_config.should_include(c.name))
for (const auto &c : m_model.classes()) {
if (!c.is_template_instantiation() &&
!m_config.should_include(c.name()))
continue;
generate(c, ostr);
ostr << '\n';
@@ -413,7 +384,7 @@ void generator::generate(std::ostream &ostr) const
}
if (m_config.should_include_entities("enums"))
for (const auto &e : m_model.enums) {
for (const auto &e : m_model.enums()) {
generate(e, ostr);
ostr << '\n';
}
@@ -423,9 +394,8 @@ void generator::generate(std::ostream &ostr) const
std::string note{b};
std::tuple<std::string, size_t, size_t> alias_match;
while (util::find_element_alias(note, alias_match)) {
auto alias = m_model.to_alias(m_config.using_namespace,
ns_relative(
m_config.using_namespace, std::get<0>(alias_match)));
auto alias = m_model.to_alias(ns_relative(
m_config.using_namespace, std::get<0>(alias_match)));
note.replace(
std::get<1>(alias_match), std::get<2>(alias_match), alias);
}
@@ -439,15 +409,14 @@ std::ostream &operator<<(std::ostream &os, const generator &g)
g.generate(os);
return os;
}
} // namespace puml
clanguml::model::class_diagram::diagram generate(
clanguml::class_diagram::model::diagram generate(
cppast::libclang_compilation_database &db, const std::string &name,
clanguml::config::class_diagram &diagram)
{
spdlog::info("Generating diagram {}.puml", name);
clanguml::model::class_diagram::diagram d;
d.name = name;
clanguml::class_diagram::model::diagram d;
d.set_name(name);
// Get all translation units matching the glob from diagram
// configuration
@@ -464,7 +433,8 @@ clanguml::model::class_diagram::diagram generate(
type_safe::ref(idx)};
// Process all matching translation units
clanguml::visitor::class_diagram::tu_visitor ctx(idx, d, diagram);
clanguml::class_diagram::visitor::translation_unit_visitor ctx(
idx, d, diagram);
cppast::parse_files(parser, translation_units, db);
for (auto &file : parser.files())
ctx(file);

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

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>
*
@@ -17,7 +17,8 @@
*/
#pragma once
#include "class_diagram_model.h"
#include "class_diagram/model/diagram.h"
#include "class_diagram/visitor/translation_unit_context.h"
#include "config/config.h"
#include "cx/cursor.h"
@@ -27,6 +28,7 @@
#include <cppast/cpp_function_template.hpp>
#include <cppast/cpp_member_function.hpp>
#include <cppast/cpp_member_variable.hpp>
#include <cppast/cpp_template.hpp>
#include <cppast/cpp_template_parameter.hpp>
#include <cppast/cpp_type.hpp>
#include <cppast/visitor.hpp>
@@ -37,59 +39,13 @@
#include <memory>
#include <string>
namespace clanguml {
namespace visitor {
namespace class_diagram {
namespace clanguml::class_diagram::visitor {
struct tu_context {
tu_context(cppast::cpp_entity_index &idx,
clanguml::model::class_diagram::diagram &d_,
const clanguml::config::class_diagram &config_);
bool has_type_alias(const std::string &full_name) const;
void add_type_alias(const std::string &full_name,
type_safe::object_ref<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 {
class translation_unit_visitor {
public:
tu_visitor(cppast::cpp_entity_index &idx_,
clanguml::model::class_diagram::diagram &d_,
const clanguml::config::class_diagram &config_);
translation_unit_visitor(cppast::cpp_entity_index &idx,
clanguml::class_diagram::model::diagram &diagram,
const clanguml::config::class_diagram &config);
void operator()(const cppast::cpp_entity &file);
@@ -100,78 +56,81 @@ public:
void process_enum_declaration(const cppast::cpp_enum &enm);
void process_anonymous_enum(const cppast::cpp_enum &en,
clanguml::model::class_diagram::class_ &c,
clanguml::class_diagram::model::class_ &c,
cppast::cpp_access_specifier_kind as);
void process_field(const cppast::cpp_member_variable &mv,
clanguml::model::class_diagram::class_ &c,
clanguml::class_diagram::model::class_ &c,
cppast::cpp_access_specifier_kind as);
bool process_field_with_template_instantiation(
const cppast::cpp_member_variable &mv, const cppast::cpp_type &tr,
clanguml::model::class_diagram::class_ &c,
clanguml::model::class_diagram::class_member &m,
clanguml::class_diagram::model::class_ &c,
clanguml::class_diagram::model::class_member &m,
cppast::cpp_access_specifier_kind as);
void process_static_field(const cppast::cpp_variable &mv,
clanguml::model::class_diagram::class_ &c,
clanguml::class_diagram::model::class_ &c,
cppast::cpp_access_specifier_kind as);
void process_method(const cppast::cpp_member_function &mf,
clanguml::model::class_diagram::class_ &c,
clanguml::class_diagram::model::class_ &c,
cppast::cpp_access_specifier_kind as);
void process_template_method(const cppast::cpp_function_template &mf,
clanguml::model::class_diagram::class_ &c,
clanguml::class_diagram::model::class_ &c,
cppast::cpp_access_specifier_kind as);
void process_static_method(const cppast::cpp_function &mf,
clanguml::model::class_diagram::class_ &c,
clanguml::class_diagram::model::class_ &c,
cppast::cpp_access_specifier_kind as);
void process_constructor(const cppast::cpp_constructor &mf,
clanguml::model::class_diagram::class_ &c,
clanguml::class_diagram::model::class_ &c,
cppast::cpp_access_specifier_kind as);
void process_destructor(const cppast::cpp_destructor &mf,
clanguml::model::class_diagram::class_ &c,
clanguml::class_diagram::model::class_ &c,
cppast::cpp_access_specifier_kind as);
void process_function_parameter(const cppast::cpp_function_parameter &param,
clanguml::model::class_diagram::class_method &m,
clanguml::model::class_diagram::class_ &c,
clanguml::class_diagram::model::class_method &m,
clanguml::class_diagram::model::class_ &c,
const std::set<std::string> &template_parameter_names = {});
bool find_relationships(const cppast::cpp_type &t,
std::vector<std::pair<std::string,
clanguml::model::class_diagram::relationship_t>> &relationships,
clanguml::model::class_diagram::relationship_t relationship_hint =
clanguml::model::class_diagram::relationship_t::kNone);
clanguml::class_diagram::model::relationship_t>> &relationships,
clanguml::class_diagram::model::relationship_t relationship_hint =
clanguml::class_diagram::model::relationship_t::kNone);
void process_template_type_parameter(
const cppast::cpp_template_type_parameter &t,
clanguml::model::class_diagram::class_ &parent);
clanguml::class_diagram::model::class_ &parent);
void process_template_nontype_parameter(
const cppast::cpp_non_type_template_parameter &t,
clanguml::model::class_diagram::class_ &parent);
clanguml::class_diagram::model::class_ &parent);
void process_template_template_parameter(
const cppast::cpp_template_template_parameter &t,
clanguml::model::class_diagram::class_ &parent);
clanguml::class_diagram::model::class_ &parent);
void process_friend(const cppast::cpp_friend &t,
clanguml::model::class_diagram::class_ &parent);
clanguml::class_diagram::model::class_ &parent);
private:
clanguml::model::class_diagram::class_ build_template_instantiation(
clanguml::class_diagram::model::class_ build_template_instantiation(
const cppast::cpp_template_instantiation_type &t,
std::optional<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);
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;
}
bool diagram::should_include(const model::class_diagram::scope_t scope) const
bool diagram::should_include(
const clanguml::class_diagram::model::scope_t scope) const
{
for (const auto &s : exclude.scopes) {
if (s == scope)
@@ -127,13 +128,13 @@ bool class_diagram::has_class(std::string clazz)
}
namespace YAML {
using clanguml::class_diagram::model::scope_t;
using clanguml::config::class_diagram;
using clanguml::config::config;
using clanguml::config::filter;
using clanguml::config::plantuml;
using clanguml::config::sequence_diagram;
using clanguml::config::source_location;
using clanguml::model::class_diagram::scope_t;
template <> struct convert<scope_t> {
static bool decode(const Node &node, scope_t &rhs)
{

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
/**
* src/uml/decorators.cc
* src/decorators/decorators.cc
*
* 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>
*

View File

@@ -18,13 +18,13 @@
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_DEBUG
#include "class_diagram/generators/plantuml/class_diagram_generator.h"
#include "class_diagram/model/diagram.h"
#include "class_diagram/visitor/translation_unit_visitor.h"
#include "config/config.h"
#include "cx/compilation_database.h"
#include "puml/class_diagram_generator.h"
#include "puml/sequence_diagram_generator.h"
#include "uml/class_diagram_model.h"
#include "uml/class_diagram_visitor.h"
#include "uml/sequence_diagram_visitor.h"
#include "sequence_diagram/generators/plantuml/sequence_diagram_generator.h"
#include "sequence_diagram/visitor/translation_unit_context.h"
#include "util/util.h"
#include <cli11/CLI11.hpp>
@@ -98,18 +98,20 @@ int main(int argc, const char *argv[])
ofs.open(path, std::ofstream::out | std::ofstream::trunc);
if (std::dynamic_pointer_cast<class_diagram>(diagram)) {
auto model = generators::class_diagram::generate(
db2, name, dynamic_cast<class_diagram &>(*diagram));
auto model =
clanguml::class_diagram::generators::plantuml::generate(
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),
model);
}
else if (std::dynamic_pointer_cast<sequence_diagram>(diagram)) {
auto model = generators::sequence_diagram::generate(
db, name, dynamic_cast<sequence_diagram &>(*diagram));
auto model =
clanguml::sequence_diagram::generators::plantuml::generate(
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),
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>
*
@@ -16,20 +16,21 @@
* limitations under the License.
*/
#include "puml/sequence_diagram_generator.h"
#include "sequence_diagram_generator.h"
namespace clanguml::generators::sequence_diagram {
namespace puml {
using diagram_model = clanguml::model::sequence_diagram::diagram;
#include "sequence_diagram/visitor/translation_unit_context.h"
namespace clanguml::sequence_diagram::generators::plantuml {
using diagram_model = clanguml::sequence_diagram::model::diagram;
using diagram_config = clanguml::config::sequence_diagram::diagram;
using clanguml::config::source_location;
using clanguml::model::sequence_diagram::activity;
using clanguml::model::sequence_diagram::message;
using clanguml::model::sequence_diagram::message_t;
using clanguml::visitor::sequence_diagram::tu_context;
using clanguml::sequence_diagram::model::activity;
using clanguml::sequence_diagram::model::message;
using clanguml::sequence_diagram::model::message_t;
using clanguml::sequence_diagram::visitor::translation_unit_context;
using namespace clanguml::util;
//
// generator
//
@@ -117,14 +118,13 @@ std::ostream &operator<<(std::ostream &os, const generator &g)
g.generate(os);
return os;
}
}
clanguml::model::sequence_diagram::diagram generate(
clanguml::sequence_diagram::model::diagram generate(
clanguml::cx::compilation_database &db, const std::string &name,
clanguml::config::sequence_diagram &diagram)
{
spdlog::info("Generating diagram {}.puml", name);
clanguml::model::sequence_diagram::diagram d;
clanguml::sequence_diagram::model::diagram d;
d.name = name;
// Get all translation units matching the glob from diagram
@@ -155,9 +155,10 @@ clanguml::model::sequence_diagram::diagram generate(
spdlog::debug("Cursor name: {}",
clang_getCString(clang_getCursorDisplayName(cursor)));
clanguml::visitor::sequence_diagram::tu_context ctx(d, diagram);
clanguml::sequence_diagram::visitor::translation_unit_context ctx(
d, diagram);
auto res = clang_visitChildren(cursor,
clanguml::visitor::sequence_diagram::translation_unit_visitor,
clanguml::sequence_diagram::visitor::translation_unit_visitor,
&ctx);
spdlog::debug("Processing result: {}", res);

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>
*
@@ -19,8 +19,8 @@
#include "config/config.h"
#include "cx/compilation_database.h"
#include "uml/sequence_diagram_model.h"
#include "uml/sequence_diagram_visitor.h"
#include "sequence_diagram/model/diagram.h"
#include "sequence_diagram/visitor/translation_unit_visitor.h"
#include "util/util.h"
#include <glob/glob.hpp>
@@ -31,25 +31,25 @@
#include <sstream>
namespace clanguml {
namespace generators {
namespace sequence_diagram {
namespace puml {
namespace generators {
namespace plantuml {
using diagram_model = clanguml::model::sequence_diagram::diagram;
using diagram_model = clanguml::sequence_diagram::model::diagram;
class generator {
public:
generator(clanguml::config::sequence_diagram &config, diagram_model &model);
std::string to_string(clanguml::model::sequence_diagram::message_t r) const;
std::string to_string(clanguml::sequence_diagram::model::message_t r) const;
void generate_call(const clanguml::model::sequence_diagram::message &m,
void generate_call(const clanguml::sequence_diagram::model::message &m,
std::ostream &ostr) const;
void generate_return(const clanguml::model::sequence_diagram::message &m,
void generate_return(const clanguml::sequence_diagram::model::message &m,
std::ostream &ostr) const;
void generate_activity(const clanguml::model::sequence_diagram::activity &a,
void generate_activity(const clanguml::sequence_diagram::model::activity &a,
std::ostream &ostr) const;
void generate(std::ostream &ostr) const;
@@ -58,15 +58,14 @@ public:
private:
clanguml::config::sequence_diagram &m_config;
clanguml::model::sequence_diagram::diagram &m_model;
clanguml::sequence_diagram::model::diagram &m_model;
};
}
clanguml::model::sequence_diagram::diagram generate(
clanguml::sequence_diagram::model::diagram generate(
clanguml::cx::compilation_database &db, const std::string &name,
clanguml::config::sequence_diagram &diagram);
}
}
}
}

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>
*
@@ -16,8 +16,8 @@
* limitations under the License.
*/
#include "sequence_diagram_visitor.h"
#include "activity.h"
namespace clanguml::model::sequence_diagram {
namespace clanguml::sequence_diagram::model {
}

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>
*
@@ -17,20 +17,12 @@
*/
#pragma once
#include <clang-c/CXCompilationDatabase.h>
#include <clang-c/Index.h>
#include <spdlog/spdlog.h>
#include "enums.h"
#include <functional>
#include <memory>
#include <string>
#include <vector>
namespace clanguml {
namespace model {
namespace sequence_diagram {
enum class message_t { kCall, kReturn };
namespace clanguml::sequence_diagram::model {
struct message {
message_t type;
@@ -43,18 +35,4 @@ struct message {
unsigned int line;
};
struct activity {
std::string usr;
std::string from;
std::vector<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>
*
@@ -16,30 +16,21 @@
* limitations under the License.
*/
#include "sequence_diagram_visitor.h"
#include "translation_unit_visitor.h"
namespace clanguml::visitor::sequence_diagram {
#include "translation_unit_context.h"
//
// tu_context
//
tu_context::tu_context(clanguml::model::sequence_diagram::diagram &d_,
const clanguml::config::sequence_diagram &config_)
: d{d_}
, config{config_}
{
}
namespace clanguml::sequence_diagram::visitor {
enum CXChildVisitResult translation_unit_visitor(
CXCursor cx_cursor, CXCursor cx_parent, CXClientData client_data)
{
using clanguml::model::sequence_diagram::activity;
using clanguml::model::sequence_diagram::diagram;
using clanguml::model::sequence_diagram::message;
using clanguml::model::sequence_diagram::message_t;
using clanguml::sequence_diagram::model::activity;
using clanguml::sequence_diagram::model::diagram;
using clanguml::sequence_diagram::model::message;
using clanguml::sequence_diagram::model::message_t;
struct tu_context *ctx = (struct tu_context *)client_data;
auto *ctx = (struct translation_unit_context *)client_data;
enum CXChildVisitResult ret = CXChildVisit_Break;
@@ -54,7 +45,7 @@ enum CXChildVisitResult translation_unit_visitor(
case CXCursor_FunctionTemplate:
case CXCursor_CXXMethod:
case CXCursor_FunctionDecl:
ctx->current_method = cursor;
ctx->set_current_method(cursor);
ret = CXChildVisit_Recurse;
break;
case CXCursor_CallExpr: {
@@ -74,25 +65,28 @@ enum CXChildVisitResult translation_unit_visitor(
clang_getFileLocation(cursor.location(), &f, &line, &column, &offset);
std::string file{clang_getCString(clang_getFileName(f))};
auto &d = ctx->d;
auto &config = ctx->config;
auto &d = ctx->diagram();
auto &config = ctx->config();
if (referenced.kind() == CXCursor_CXXMethod) {
if (config.should_include(sp_name)) {
// Get calling object
std::string caller{};
if (ctx->current_method.semantic_parent()
if (ctx->current_method()
.semantic_parent()
.is_translation_unit() ||
ctx->current_method.semantic_parent().is_namespace()) {
caller = ctx->current_method.semantic_parent()
ctx->current_method().semantic_parent().is_namespace()) {
caller = ctx->current_method()
.semantic_parent()
.fully_qualified() +
"::" + ctx->current_method.spelling() + "()";
"::" + ctx->current_method().spelling() + "()";
}
else {
caller =
ctx->current_method.semantic_parent().fully_qualified();
caller = ctx->current_method()
.semantic_parent()
.fully_qualified();
}
auto caller_usr = ctx->current_method.usr();
auto caller_usr = ctx->current_method().usr();
// Get called object
auto callee = referenced.semantic_parent().fully_qualified();
auto callee_usr = referenced.semantic_parent().usr();
@@ -105,8 +99,8 @@ enum CXChildVisitResult translation_unit_visitor(
"\n\tCURRENT_METHOD: {}\n\tFROM: '{}'\n\tTO: "
"{}\n\tMESSAGE: {}\n\tFROM_USR: {}\n\tTO_USR: "
"{}\n\tRETURN_TYPE: {}",
file, line, d.name, ctx->current_method.spelling(), caller,
callee, called_message, caller_usr, callee_usr,
file, line, d.name, ctx->current_method().spelling(),
caller, callee, called_message, caller_usr, callee_usr,
referenced.type().result_type().spelling());
message m;
@@ -146,5 +140,4 @@ enum CXChildVisitResult translation_unit_visitor(
return ret;
}
}

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>
*
@@ -17,35 +17,13 @@
*/
#pragma once
#include "cx/cursor.h"
#include "sequence_diagram_model.h"
#include "config/config.h"
#include "cx/cursor.h"
#include "sequence_diagram/model/diagram.h"
#include <clang-c/CXCompilationDatabase.h>
#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;
};
namespace clanguml::sequence_diagram::visitor {
enum CXChildVisitResult translation_unit_visitor(
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);
REQUIRE(model.name == "t00002_class");
REQUIRE(model.name() == "t00002_class");
auto puml = generate_class_puml(diagram, model);
AliasMatcher _A(puml);

View File

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

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