Merge pull request #16 from bkryza/enable-packages-in-class-diagrams
Enable packages in class diagrams
11
README.md
@@ -2,11 +2,11 @@
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
`clang-uml` is an automatic C++ to [PlantUML](https://plantuml.com) class and sequence
|
`clang-uml` is an automatic C++ to [PlantUML](https://plantuml.com) class, sequence
|
||||||
diagram generator, driven by YAML configuration files. The main idea behind the
|
and package diagram generator, driven by YAML configuration files. The main idea behind the
|
||||||
project is to easily maintain up-to-date diagrams within a code-base or document
|
project is to easily maintain up-to-date diagrams within a code-base or document
|
||||||
existing project code. The configuration file or files for `clang-uml` define the
|
existing project code. The configuration file or files for `clang-uml` define the
|
||||||
type and contents of each diagram.
|
type and contents of each generated diagram.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
Main features supported so far include:
|
Main features supported so far include:
|
||||||
@@ -17,11 +17,14 @@ Main features supported so far include:
|
|||||||
* Template instantiation relationships
|
* Template instantiation relationships
|
||||||
* Relationship inference from C++ containers and smart pointers
|
* Relationship inference from C++ containers and smart pointers
|
||||||
* Namespace based content filtering
|
* Namespace based content filtering
|
||||||
|
* Optional package generation from namespaces
|
||||||
* Sequence diagram generation
|
* Sequence diagram generation
|
||||||
* Generation of sequence diagram from one code location to another
|
* Generation of sequence diagram from one code location to another (currently only for non-template code)
|
||||||
* Package diagram generation
|
* Package diagram generation
|
||||||
* Generation of package diagram based on C++ namespaces
|
* Generation of package diagram based on C++ namespaces
|
||||||
|
|
||||||
|
To see what `clang-uml` can do so far, checkout the diagrams generated for unit test cases [here](./docs/test_cases.md).
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
### Building from source
|
### Building from source
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
* [t00033](./test_cases/t00033.md) - Nested template instantiation dependency test case
|
* [t00033](./test_cases/t00033.md) - Nested template instantiation dependency test case
|
||||||
* [t00034](./test_cases/t00034.md) - Template metaprogramming type function test case
|
* [t00034](./test_cases/t00034.md) - Template metaprogramming type function test case
|
||||||
* [t00035](./test_cases/t00035.md) - PlantUML class diagram layout hints test case
|
* [t00035](./test_cases/t00035.md) - PlantUML class diagram layout hints test case
|
||||||
|
* [t00036](./test_cases/t00036.md) - Class diagram with namespaces generated as packages
|
||||||
## Sequence diagrams
|
## Sequence diagrams
|
||||||
* [t20001](./test_cases/t20001.md) - Basic sequence diagram test case
|
* [t20001](./test_cases/t20001.md) - Basic sequence diagram test case
|
||||||
* [t20002](./test_cases/t20002.md) - Free function sequence diagram test case
|
* [t20002](./test_cases/t20002.md) - Free function sequence diagram test case
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 8.4 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 9.8 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
57
docs/test_cases/t00036.md
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
# t00036 - Class diagram with namespaces generated as packages
|
||||||
|
## Config
|
||||||
|
```yaml
|
||||||
|
compilation_database_dir: ..
|
||||||
|
output_directory: puml
|
||||||
|
diagrams:
|
||||||
|
t00036_class:
|
||||||
|
type: class
|
||||||
|
generate_packages: true
|
||||||
|
glob:
|
||||||
|
- ../../tests/t00036/t00036.cc
|
||||||
|
using_namespace:
|
||||||
|
- clanguml::t00036
|
||||||
|
include:
|
||||||
|
namespaces:
|
||||||
|
- clanguml::t00036
|
||||||
|
```
|
||||||
|
## Source code
|
||||||
|
File t00036.cc
|
||||||
|
```cpp
|
||||||
|
namespace clanguml {
|
||||||
|
namespace t00036 {
|
||||||
|
|
||||||
|
namespace ns1 {
|
||||||
|
|
||||||
|
enum class E { blue, yellow };
|
||||||
|
|
||||||
|
namespace ns11 {
|
||||||
|
|
||||||
|
template <typename T> struct A {
|
||||||
|
T a;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace ns111 {
|
||||||
|
|
||||||
|
struct B {
|
||||||
|
A<int> a_int;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ns2 {
|
||||||
|
namespace ns22 {
|
||||||
|
|
||||||
|
struct C;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace t00036
|
||||||
|
} // namespace clanguml
|
||||||
|
|
||||||
|
```
|
||||||
|
## Generated UML diagrams
|
||||||
|

|
||||||
BIN
docs/test_cases/t00036_class.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 8.9 KiB |
@@ -33,6 +33,11 @@ void generator::generate_alias(const class_ &c, std::ostream &ostr) const
|
|||||||
if (c.is_abstract())
|
if (c.is_abstract())
|
||||||
class_type = "abstract";
|
class_type = "abstract";
|
||||||
|
|
||||||
|
auto full_name = c.full_name();
|
||||||
|
|
||||||
|
if (m_config.generate_packages())
|
||||||
|
ostr << class_type << " \"" << c.full_name_no_ns();
|
||||||
|
else
|
||||||
ostr << class_type << " \"" << c.full_name();
|
ostr << class_type << " \"" << c.full_name();
|
||||||
|
|
||||||
ostr << "\" as " << c.alias() << '\n';
|
ostr << "\" as " << c.alias() << '\n';
|
||||||
@@ -40,13 +45,18 @@ void generator::generate_alias(const class_ &c, std::ostream &ostr) const
|
|||||||
|
|
||||||
void generator::generate_alias(const enum_ &e, std::ostream &ostr) const
|
void generator::generate_alias(const enum_ &e, std::ostream &ostr) const
|
||||||
{
|
{
|
||||||
|
if (m_config.generate_packages())
|
||||||
|
ostr << "enum"
|
||||||
|
<< " \"" << e.name();
|
||||||
|
else
|
||||||
ostr << "enum"
|
ostr << "enum"
|
||||||
<< " \"" << e.full_name();
|
<< " \"" << e.full_name();
|
||||||
|
|
||||||
ostr << "\" as " << e.alias() << '\n';
|
ostr << "\" as " << e.alias() << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
void generator::generate(const class_ &c, std::ostream &ostr) const
|
void generator::generate(
|
||||||
|
const class_ &c, std::ostream &ostr, std::ostream &relationships_ostr) const
|
||||||
{
|
{
|
||||||
namespace plantuml_common = clanguml::common::generators::plantuml;
|
namespace plantuml_common = clanguml::common::generators::plantuml;
|
||||||
|
|
||||||
@@ -89,7 +99,7 @@ void generator::generate(const class_ &c, std::ostream &ostr) const
|
|||||||
return mp.to_string(m_config.using_namespace());
|
return mp.to_string(m_config.using_namespace());
|
||||||
});
|
});
|
||||||
auto args_string = fmt::format("{}", fmt::join(params, ", "));
|
auto args_string = fmt::format("{}", fmt::join(params, ", "));
|
||||||
if (m_config.generate_method_arguments() !=
|
if (m_config.generate_method_arguments() ==
|
||||||
config::method_arguments::abbreviated) {
|
config::method_arguments::abbreviated) {
|
||||||
args_string = clanguml::util::abbreviate(args_string, 10);
|
args_string = clanguml::util::abbreviate(args_string, 10);
|
||||||
}
|
}
|
||||||
@@ -213,10 +223,11 @@ void generator::generate(const class_ &c, std::ostream &ostr) const
|
|||||||
generate_notes(ostr, c);
|
generate_notes(ostr, c);
|
||||||
|
|
||||||
// Print relationships
|
// Print relationships
|
||||||
ostr << all_relations_str.str();
|
relationships_ostr << all_relations_str.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
void generator::generate(const enum_ &e, std::ostream &ostr) const
|
void generator::generate(
|
||||||
|
const enum_ &e, std::ostream &ostr, std::ostream &relationships_ostr) const
|
||||||
{
|
{
|
||||||
ostr << "enum " << e.alias();
|
ostr << "enum " << e.alias();
|
||||||
|
|
||||||
@@ -255,7 +266,7 @@ void generator::generate(const enum_ &e, std::ostream &ostr) const
|
|||||||
|
|
||||||
relstr << '\n';
|
relstr << '\n';
|
||||||
|
|
||||||
ostr << relstr.str();
|
relationships_ostr << relstr.str();
|
||||||
}
|
}
|
||||||
catch (error::uml_alias_missing &ex) {
|
catch (error::uml_alias_missing &ex) {
|
||||||
LOG_ERROR("Skipping {} relation from {} to {} due "
|
LOG_ERROR("Skipping {} relation from {} to {} due "
|
||||||
@@ -269,40 +280,72 @@ void generator::generate(const enum_ &e, std::ostream &ostr) const
|
|||||||
generate_notes(ostr, e);
|
generate_notes(ostr, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void generator::generate(const package &p, std::ostream &ostr,
|
||||||
|
std::ostream &relationships_ostr) const
|
||||||
|
{
|
||||||
|
if (m_config.generate_packages()) {
|
||||||
|
LOG_DBG("Generating package {}", p.name());
|
||||||
|
|
||||||
|
ostr << "package [" << p.name() << "] ";
|
||||||
|
ostr << "as " << p.alias();
|
||||||
|
|
||||||
|
if (p.is_deprecated())
|
||||||
|
ostr << " <<deprecated>>";
|
||||||
|
|
||||||
|
if (!p.style().empty())
|
||||||
|
ostr << " " << p.style();
|
||||||
|
|
||||||
|
ostr << " {" << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &subpackage : p) {
|
||||||
|
if (dynamic_cast<package *>(subpackage.get())) {
|
||||||
|
generate(
|
||||||
|
dynamic_cast<package &>(*subpackage), ostr, relationships_ostr);
|
||||||
|
}
|
||||||
|
if (dynamic_cast<class_ *>(subpackage.get())) {
|
||||||
|
generate_alias(dynamic_cast<class_ &>(*subpackage), ostr);
|
||||||
|
generate(
|
||||||
|
dynamic_cast<class_ &>(*subpackage), ostr, relationships_ostr);
|
||||||
|
}
|
||||||
|
if (dynamic_cast<enum_ *>(subpackage.get())) {
|
||||||
|
generate_alias(dynamic_cast<enum_ &>(*subpackage), ostr);
|
||||||
|
generate(
|
||||||
|
dynamic_cast<enum_ &>(*subpackage), ostr, relationships_ostr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_config.generate_packages()) {
|
||||||
|
ostr << "}" << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
generate_notes(ostr, p);
|
||||||
|
}
|
||||||
|
|
||||||
void generator::generate(std::ostream &ostr) const
|
void generator::generate(std::ostream &ostr) const
|
||||||
{
|
{
|
||||||
ostr << "@startuml" << '\n';
|
ostr << "@startuml" << '\n';
|
||||||
|
|
||||||
|
std::stringstream relationship_ostr;
|
||||||
|
|
||||||
generate_plantuml_directives(ostr, m_config.puml().before);
|
generate_plantuml_directives(ostr, m_config.puml().before);
|
||||||
|
|
||||||
if (m_config.should_include_entities("classes")) {
|
for (const auto &p : m_model) {
|
||||||
for (const auto &c : m_model.classes()) {
|
if (dynamic_cast<package *>(p.get())) {
|
||||||
if (!m_config.should_include(c.name()))
|
generate(dynamic_cast<package &>(*p), ostr, relationship_ostr);
|
||||||
continue;
|
}
|
||||||
generate_alias(c, ostr);
|
if (dynamic_cast<class_ *>(p.get())) {
|
||||||
|
generate_alias(dynamic_cast<class_ &>(*p), ostr);
|
||||||
|
generate(dynamic_cast<class_ &>(*p), ostr, relationship_ostr);
|
||||||
|
}
|
||||||
|
if (dynamic_cast<enum_ *>(p.get())) {
|
||||||
|
generate_alias(dynamic_cast<enum_ &>(*p), ostr);
|
||||||
|
generate(dynamic_cast<enum_ &>(*p), ostr, relationship_ostr);
|
||||||
|
}
|
||||||
ostr << '\n';
|
ostr << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &e : m_model.enums()) {
|
ostr << relationship_ostr.str();
|
||||||
if (!m_config.should_include(e.name()))
|
|
||||||
continue;
|
|
||||||
generate_alias(e, ostr);
|
|
||||||
ostr << '\n';
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto &c : m_model.classes()) {
|
|
||||||
if (!m_config.should_include(c.name()))
|
|
||||||
continue;
|
|
||||||
generate(c, ostr);
|
|
||||||
ostr << '\n';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_config.should_include_entities("enums"))
|
|
||||||
for (const auto &e : m_model.enums()) {
|
|
||||||
generate(e, ostr);
|
|
||||||
ostr << '\n';
|
|
||||||
}
|
|
||||||
|
|
||||||
generate_config_layout_hints(ostr);
|
generate_config_layout_hints(ostr);
|
||||||
|
|
||||||
@@ -310,5 +353,4 @@ void generator::generate(std::ostream &ostr) const
|
|||||||
|
|
||||||
ostr << "@enduml" << '\n';
|
ostr << "@enduml" << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ using common_generator =
|
|||||||
|
|
||||||
using clanguml::class_diagram::model::class_;
|
using clanguml::class_diagram::model::class_;
|
||||||
using clanguml::class_diagram::model::enum_;
|
using clanguml::class_diagram::model::enum_;
|
||||||
|
using clanguml::common::model::package;
|
||||||
using clanguml::common::model::relationship_t;
|
using clanguml::common::model::relationship_t;
|
||||||
using clanguml::common::model::scope_t;
|
using clanguml::common::model::scope_t;
|
||||||
|
|
||||||
@@ -62,9 +63,14 @@ public:
|
|||||||
|
|
||||||
void generate_alias(const enum_ &e, std::ostream &ostr) const;
|
void generate_alias(const enum_ &e, std::ostream &ostr) const;
|
||||||
|
|
||||||
void generate(const class_ &c, std::ostream &ostr) const;
|
void generate(const class_ &c, std::ostream &ostr,
|
||||||
|
std::ostream &relationships_ostr) const;
|
||||||
|
|
||||||
void generate(const enum_ &e, std::ostream &ostr) const;
|
void generate(const enum_ &e, std::ostream &ostr,
|
||||||
|
std::ostream &relationships_ostr) const;
|
||||||
|
|
||||||
|
void generate(const package &p, std::ostream &ostr,
|
||||||
|
std::ostream &relationships_ostr) const;
|
||||||
|
|
||||||
void generate(std::ostream &ostr) const override;
|
void generate(std::ostream &ostr) const override;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -96,16 +96,36 @@ void class_::add_type_alias(type_alias &&ta)
|
|||||||
type_aliases_[ta.alias()] = std::move(ta);
|
type_aliases_[ta.alias()] = std::move(ta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string class_::full_name_no_ns() const
|
||||||
|
{
|
||||||
|
using namespace clanguml::util;
|
||||||
|
|
||||||
|
std::ostringstream ostr;
|
||||||
|
|
||||||
|
ostr << name();
|
||||||
|
|
||||||
|
render_template_params(ostr);
|
||||||
|
|
||||||
|
return ostr.str();
|
||||||
|
}
|
||||||
|
|
||||||
std::string class_::full_name(bool relative) const
|
std::string class_::full_name(bool relative) const
|
||||||
{
|
{
|
||||||
using namespace clanguml::util;
|
using namespace clanguml::util;
|
||||||
|
|
||||||
std::ostringstream ostr;
|
std::ostringstream ostr;
|
||||||
if (relative)
|
if (relative && starts_with(get_namespace(), using_namespaces()))
|
||||||
ostr << ns_relative(using_namespaces(), name());
|
ostr << ns_relative(using_namespaces(), name_and_ns());
|
||||||
else
|
else
|
||||||
ostr << name();
|
ostr << name_and_ns();
|
||||||
|
|
||||||
|
render_template_params(ostr);
|
||||||
|
|
||||||
|
return ostr.str();
|
||||||
|
}
|
||||||
|
std::ostringstream &class_::render_template_params(
|
||||||
|
std::ostringstream &ostr) const
|
||||||
|
{
|
||||||
if (!templates_.empty()) {
|
if (!templates_.empty()) {
|
||||||
std::vector<std::string> tnames;
|
std::vector<std::string> tnames;
|
||||||
std::transform(templates_.cbegin(), templates_.cend(),
|
std::transform(templates_.cbegin(), templates_.cend(),
|
||||||
@@ -114,11 +134,11 @@ std::string class_::full_name(bool relative) const
|
|||||||
|
|
||||||
if (!tmplt.type().empty())
|
if (!tmplt.type().empty())
|
||||||
res.push_back(
|
res.push_back(
|
||||||
ns_relative(using_namespaces(), tmplt.type()));
|
util::ns_relative(using_namespaces(), tmplt.type()));
|
||||||
|
|
||||||
if (!tmplt.name().empty())
|
if (!tmplt.name().empty())
|
||||||
res.push_back(
|
res.push_back(
|
||||||
ns_relative(using_namespaces(), tmplt.name()));
|
util::ns_relative(using_namespaces(), tmplt.name()));
|
||||||
|
|
||||||
if (!tmplt.default_value().empty()) {
|
if (!tmplt.default_value().empty()) {
|
||||||
res.push_back("=");
|
res.push_back("=");
|
||||||
@@ -129,8 +149,7 @@ std::string class_::full_name(bool relative) const
|
|||||||
});
|
});
|
||||||
ostr << fmt::format("<{}>", fmt::join(tnames, ","));
|
ostr << fmt::format("<{}>", fmt::join(tnames, ","));
|
||||||
}
|
}
|
||||||
|
return ostr;
|
||||||
return ostr.str();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool class_::is_abstract() const
|
bool class_::is_abstract() const
|
||||||
|
|||||||
@@ -36,6 +36,11 @@ class class_ : public common::model::element,
|
|||||||
public:
|
public:
|
||||||
class_(const std::vector<std::string> &using_namespaces);
|
class_(const std::vector<std::string> &using_namespaces);
|
||||||
|
|
||||||
|
class_(const class_ &) = delete;
|
||||||
|
class_(class_ &&) noexcept = delete;
|
||||||
|
class_ &operator=(const class_ &) = delete;
|
||||||
|
class_ &operator=(class_ &&) = delete;
|
||||||
|
|
||||||
bool is_struct() const;
|
bool is_struct() const;
|
||||||
void is_struct(bool is_struct);
|
void is_struct(bool is_struct);
|
||||||
|
|
||||||
@@ -64,9 +69,13 @@ public:
|
|||||||
|
|
||||||
std::string full_name(bool relative = true) const override;
|
std::string full_name(bool relative = true) const override;
|
||||||
|
|
||||||
|
std::string full_name_no_ns() const;
|
||||||
|
|
||||||
bool is_abstract() const;
|
bool is_abstract() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::ostringstream &render_template_params(std::ostringstream &ostr) const;
|
||||||
|
|
||||||
bool is_struct_{false};
|
bool is_struct_{false};
|
||||||
bool is_template_{false};
|
bool is_template_{false};
|
||||||
bool is_template_instantiation_{false};
|
bool is_template_instantiation_{false};
|
||||||
|
|||||||
@@ -21,42 +21,89 @@
|
|||||||
#include "util/error.h"
|
#include "util/error.h"
|
||||||
#include "util/util.h"
|
#include "util/util.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace clanguml::class_diagram::model {
|
namespace clanguml::class_diagram::model {
|
||||||
|
|
||||||
const std::vector<class_> diagram::classes() const { return classes_; }
|
const std::vector<type_safe::object_ref<const class_>> diagram::classes() const
|
||||||
|
{
|
||||||
|
return classes_;
|
||||||
|
}
|
||||||
|
|
||||||
const std::vector<enum_> diagram::enums() const { return enums_; }
|
const std::vector<type_safe::object_ref<const enum_>> diagram::enums() const
|
||||||
|
{
|
||||||
|
return enums_;
|
||||||
|
}
|
||||||
|
|
||||||
bool diagram::has_class(const class_ &c) const
|
bool diagram::has_class(const class_ &c) const
|
||||||
{
|
{
|
||||||
return std::any_of(classes_.cbegin(), classes_.cend(),
|
return std::any_of(classes_.cbegin(), classes_.cend(),
|
||||||
[&c](const auto &cc) { return cc.full_name() == c.full_name(); });
|
[&c](const auto &cc) { return cc.get().full_name() == c.full_name(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void diagram::add_type_alias(type_alias &&ta)
|
bool diagram::has_enum(const enum_ &e) const
|
||||||
{
|
{
|
||||||
LOG_DBG("Adding global alias: {} -> {}", ta.alias(), ta.underlying_type());
|
return std::any_of(enums_.cbegin(), enums_.cend(),
|
||||||
|
[&e](const auto &ee) { return ee.get().full_name() == e.full_name(); });
|
||||||
type_aliases_[ta.alias()] = std::move(ta);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void diagram::add_class(class_ &&c)
|
void diagram::add_type_alias(std::unique_ptr<type_alias> &&ta)
|
||||||
{
|
{
|
||||||
LOG_DBG("Adding class: {}, {}", c.name(), c.full_name());
|
LOG_DBG(
|
||||||
if (!has_class(c))
|
"Adding global alias: {} -> {}", ta->alias(), ta->underlying_type());
|
||||||
classes_.emplace_back(std::move(c));
|
|
||||||
|
type_aliases_[ta->alias()] = std::move(ta);
|
||||||
|
}
|
||||||
|
|
||||||
|
void diagram::add_package(std::unique_ptr<common::model::package> &&p)
|
||||||
|
{
|
||||||
|
LOG_DBG("Adding namespace package: {}, {}", p->name(), p->full_name(true));
|
||||||
|
|
||||||
|
auto ns = p->get_relative_namespace();
|
||||||
|
add_element(ns, std::move(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
void diagram::add_class(std::unique_ptr<class_> &&c)
|
||||||
|
{
|
||||||
|
LOG_DBG("Adding class: {}, {}", c->name(), c->full_name());
|
||||||
|
|
||||||
|
if (util::contains(c->name(), "::"))
|
||||||
|
throw std::runtime_error("Name cannot contain namespace: " + c->name());
|
||||||
|
|
||||||
|
if (util::contains(c->name(), "<"))
|
||||||
|
throw std::runtime_error("Name cannot contain <: " + c->name());
|
||||||
|
|
||||||
|
if (util::contains(c->name(), "*"))
|
||||||
|
throw std::runtime_error("Name cannot contain *: " + c->name());
|
||||||
|
|
||||||
|
if (!has_class(*c)) {
|
||||||
|
classes_.emplace_back(*c);
|
||||||
|
auto ns = c->get_relative_namespace();
|
||||||
|
auto name = c->name();
|
||||||
|
add_element(ns, std::move(c));
|
||||||
|
ns.push_back(name);
|
||||||
|
const auto ccc = get_element<class_>(ns);
|
||||||
|
assert(ccc.value().name() == name);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
LOG_DBG("Class {} ({}) already in the model", c.name(), c.full_name());
|
LOG_DBG(
|
||||||
|
"Class {} ({}) already in the model", c->name(), c->full_name());
|
||||||
}
|
}
|
||||||
|
|
||||||
void diagram::add_enum(enum_ &&e)
|
void diagram::add_enum(std::unique_ptr<enum_> &&e)
|
||||||
{
|
{
|
||||||
LOG_DBG("Adding enum: {}", e.name());
|
LOG_DBG("Adding enum: {}", e->name());
|
||||||
auto it = std::find(enums_.begin(), enums_.end(), e);
|
|
||||||
if (it == enums_.end())
|
assert(!util::contains(e->name(), "::"));
|
||||||
enums_.emplace_back(std::move(e));
|
|
||||||
|
if (!has_enum(*e)) {
|
||||||
|
enums_.emplace_back(*e);
|
||||||
|
auto ns = e->get_relative_namespace();
|
||||||
|
add_element(ns, std::move(e));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
LOG_DBG("Enum {} already in the model", e.name());
|
LOG_DBG("Enum {} already in the model", e->name());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string diagram::to_alias(const std::string &full_name) const
|
std::string diagram::to_alias(const std::string &full_name) const
|
||||||
@@ -64,18 +111,20 @@ std::string diagram::to_alias(const std::string &full_name) const
|
|||||||
LOG_DBG("Looking for alias for {}", full_name);
|
LOG_DBG("Looking for alias for {}", full_name);
|
||||||
|
|
||||||
for (const auto &c : classes_) {
|
for (const auto &c : classes_) {
|
||||||
if (c.full_name() == full_name) {
|
const auto &cc = c.get();
|
||||||
return c.alias();
|
if (cc.full_name() == full_name) {
|
||||||
|
return c->alias();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &e : enums_) {
|
for (const auto &e : enums_) {
|
||||||
if (e.full_name() == full_name) {
|
if (e.get().full_name() == full_name) {
|
||||||
return e.alias();
|
return e->alias();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw error::uml_alias_missing(
|
throw error::uml_alias_missing(
|
||||||
fmt::format("Missing alias for {}", full_name));
|
fmt::format("Missing alias for {}", full_name));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
#include "class.h"
|
#include "class.h"
|
||||||
#include "common/model/diagram.h"
|
#include "common/model/diagram.h"
|
||||||
|
#include "common/model/nested_trait.h"
|
||||||
|
#include "common/model/package.h"
|
||||||
#include "enum.h"
|
#include "enum.h"
|
||||||
#include "type_alias.h"
|
#include "type_alias.h"
|
||||||
|
|
||||||
@@ -27,7 +29,9 @@
|
|||||||
|
|
||||||
namespace clanguml::class_diagram::model {
|
namespace clanguml::class_diagram::model {
|
||||||
|
|
||||||
class diagram : public clanguml::common::model::diagram {
|
class diagram : public clanguml::common::model::diagram,
|
||||||
|
public clanguml::common::model::nested_trait<
|
||||||
|
clanguml::common::model::element> {
|
||||||
public:
|
public:
|
||||||
diagram() = default;
|
diagram() = default;
|
||||||
|
|
||||||
@@ -36,23 +40,29 @@ public:
|
|||||||
diagram &operator=(const diagram &) = delete;
|
diagram &operator=(const diagram &) = delete;
|
||||||
diagram &operator=(diagram &&) = default;
|
diagram &operator=(diagram &&) = default;
|
||||||
|
|
||||||
const std::vector<class_> classes() const;
|
const std::vector<type_safe::object_ref<const class_>> classes() const;
|
||||||
|
|
||||||
const std::vector<enum_> enums() const;
|
const std::vector<type_safe::object_ref<const enum_>> enums() const;
|
||||||
|
|
||||||
bool has_class(const class_ &c) const;
|
bool has_class(const class_ &c) const;
|
||||||
|
|
||||||
void add_type_alias(type_alias &&ta);
|
bool has_enum(const enum_ &e) const;
|
||||||
|
|
||||||
void add_class(class_ &&c);
|
void add_type_alias(std::unique_ptr<type_alias> &&ta);
|
||||||
|
|
||||||
void add_enum(enum_ &&e);
|
void add_class(std::unique_ptr<class_> &&c);
|
||||||
|
|
||||||
|
void add_enum(std::unique_ptr<enum_> &&e);
|
||||||
|
|
||||||
|
void add_package(std::unique_ptr<common::model::package> &&p);
|
||||||
|
|
||||||
std::string to_alias(const std::string &full_name) const;
|
std::string to_alias(const std::string &full_name) const;
|
||||||
|
|
||||||
|
friend void print_diagram_tree(const diagram &d, const int level);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<class_> classes_;
|
std::vector<type_safe::object_ref<const class_, false>> classes_;
|
||||||
std::vector<enum_> enums_;
|
std::vector<type_safe::object_ref<const enum_, false>> enums_;
|
||||||
std::map<std::string, type_alias> type_aliases_;
|
std::map<std::string, std::unique_ptr<type_alias>> type_aliases_;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,10 @@ enum_::enum_(const std::vector<std::string> &using_namespaces)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const enum_ &l, const enum_ &r) { return l.name() == r.name(); }
|
bool operator==(const enum_ &l, const enum_ &r)
|
||||||
|
{
|
||||||
|
return (l.get_namespace() == r.get_namespace()) && (l.name() == r.name());
|
||||||
|
}
|
||||||
|
|
||||||
std::string enum_::full_name(bool relative) const
|
std::string enum_::full_name(bool relative) const
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -29,6 +29,12 @@ class enum_ : public common::model::element,
|
|||||||
public:
|
public:
|
||||||
enum_(const std::vector<std::string> &using_namespaces);
|
enum_(const std::vector<std::string> &using_namespaces);
|
||||||
|
|
||||||
|
enum_(const enum_ &) = delete;
|
||||||
|
enum_(enum_ &&) = default;
|
||||||
|
enum_ &operator=(const enum_ &) = delete;
|
||||||
|
enum_ &operator=(enum_ &&) = default;
|
||||||
|
|
||||||
|
// TODO: Do we need this?
|
||||||
friend bool operator==(const enum_ &l, const enum_ &r);
|
friend bool operator==(const enum_ &l, const enum_ &r);
|
||||||
|
|
||||||
std::string full_name(bool relative = true) const override;
|
std::string full_name(bool relative = true) const override;
|
||||||
|
|||||||
@@ -32,6 +32,53 @@ translation_unit_context::translation_unit_context(
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool translation_unit_context::has_namespace_alias(
|
||||||
|
const std::string &full_name) const
|
||||||
|
{
|
||||||
|
bool res =
|
||||||
|
namespace_alias_index_.find(full_name) != namespace_alias_index_.end();
|
||||||
|
|
||||||
|
LOG_DBG("Alias {} {} found in index", full_name, res ? "" : "not");
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void translation_unit_context::add_namespace_alias(const std::string &full_name,
|
||||||
|
type_safe::object_ref<const cppast::cpp_namespace> ref)
|
||||||
|
{
|
||||||
|
if (!has_namespace_alias(full_name)) {
|
||||||
|
LOG_DBG(
|
||||||
|
"Stored namespace alias: {} -> {} ", full_name, ref.get().name());
|
||||||
|
|
||||||
|
namespace_alias_index_.emplace(full_name, std::move(ref));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type_safe::object_ref<const cppast::cpp_namespace>
|
||||||
|
translation_unit_context::get_namespace_alias(
|
||||||
|
const std::string &full_name) const
|
||||||
|
{
|
||||||
|
assert(has_namespace_alias(full_name));
|
||||||
|
|
||||||
|
return namespace_alias_index_.at(full_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_safe::object_ref<const cppast::cpp_namespace>
|
||||||
|
translation_unit_context::get_namespace_alias_final(
|
||||||
|
const cppast::cpp_namespace &ns) const
|
||||||
|
{
|
||||||
|
auto ns_full_name = cx::util::full_name({}, ns);
|
||||||
|
|
||||||
|
ns_full_name = cx::util::ns(ns) + "::" + ns_full_name;
|
||||||
|
|
||||||
|
if (has_namespace_alias(ns_full_name)) {
|
||||||
|
return get_namespace_alias_final(
|
||||||
|
namespace_alias_index_.at(ns_full_name).get());
|
||||||
|
}
|
||||||
|
|
||||||
|
return type_safe::ref(ns);
|
||||||
|
}
|
||||||
|
|
||||||
bool translation_unit_context::has_type_alias(
|
bool translation_unit_context::has_type_alias(
|
||||||
const std::string &full_name) const
|
const std::string &full_name) const
|
||||||
{
|
{
|
||||||
@@ -132,4 +179,16 @@ clanguml::class_diagram::model::diagram &translation_unit_context::diagram()
|
|||||||
return diagram_;
|
return diagram_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void translation_unit_context::set_current_package(
|
||||||
|
type_safe::optional_ref<common::model::package> p)
|
||||||
|
{
|
||||||
|
current_package_ = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
type_safe::optional_ref<common::model::package>
|
||||||
|
translation_unit_context::get_current_package() const
|
||||||
|
{
|
||||||
|
return current_package_;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "config/config.h"
|
#include "config/config.h"
|
||||||
|
|
||||||
#include <cppast/cpp_entity_index.hpp>
|
#include <cppast/cpp_entity_index.hpp>
|
||||||
|
#include <cppast/cpp_namespace.hpp>
|
||||||
#include <cppast/cpp_type.hpp>
|
#include <cppast/cpp_type.hpp>
|
||||||
#include <type_safe/reference.hpp>
|
#include <type_safe/reference.hpp>
|
||||||
|
|
||||||
@@ -31,6 +32,17 @@ public:
|
|||||||
clanguml::class_diagram::model::diagram &diagram,
|
clanguml::class_diagram::model::diagram &diagram,
|
||||||
const clanguml::config::class_diagram &config);
|
const clanguml::config::class_diagram &config);
|
||||||
|
|
||||||
|
bool has_namespace_alias(const std::string &full_name) const;
|
||||||
|
|
||||||
|
void add_namespace_alias(const std::string &full_name,
|
||||||
|
type_safe::object_ref<const cppast::cpp_namespace> ref);
|
||||||
|
|
||||||
|
type_safe::object_ref<const cppast::cpp_namespace> get_namespace_alias(
|
||||||
|
const std::string &full_name) const;
|
||||||
|
|
||||||
|
type_safe::object_ref<const cppast::cpp_namespace>
|
||||||
|
get_namespace_alias_final(const cppast::cpp_namespace &t) const;
|
||||||
|
|
||||||
bool has_type_alias(const std::string &full_name) const;
|
bool has_type_alias(const std::string &full_name) const;
|
||||||
|
|
||||||
void add_type_alias(const std::string &full_name,
|
void add_type_alias(const std::string &full_name,
|
||||||
@@ -62,6 +74,10 @@ public:
|
|||||||
|
|
||||||
clanguml::class_diagram::model::diagram &diagram();
|
clanguml::class_diagram::model::diagram &diagram();
|
||||||
|
|
||||||
|
void set_current_package(type_safe::optional_ref<common::model::package> p);
|
||||||
|
|
||||||
|
type_safe::optional_ref<common::model::package> get_current_package() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Current visitor namespace
|
// Current visitor namespace
|
||||||
std::vector<std::string> namespace_;
|
std::vector<std::string> namespace_;
|
||||||
@@ -75,6 +91,10 @@ private:
|
|||||||
// Reference to class diagram config
|
// Reference to class diagram config
|
||||||
const clanguml::config::class_diagram &config_;
|
const clanguml::config::class_diagram &config_;
|
||||||
|
|
||||||
|
// Map of discovered aliases (declared with 'namespace' keyword)
|
||||||
|
std::map<std::string, type_safe::object_ref<const cppast::cpp_namespace>>
|
||||||
|
namespace_alias_index_;
|
||||||
|
|
||||||
// Map of discovered aliases (declared with 'using' keyword)
|
// Map of discovered aliases (declared with 'using' keyword)
|
||||||
std::map<std::string, type_safe::object_ref<const cppast::cpp_type>>
|
std::map<std::string, type_safe::object_ref<const cppast::cpp_type>>
|
||||||
alias_index_;
|
alias_index_;
|
||||||
@@ -82,6 +102,8 @@ private:
|
|||||||
// Map of discovered template aliases (declared with 'using' keyword)
|
// Map of discovered template aliases (declared with 'using' keyword)
|
||||||
std::map<std::string, type_safe::object_ref<const cppast::cpp_type>>
|
std::map<std::string, type_safe::object_ref<const cppast::cpp_type>>
|
||||||
alias_template_index_;
|
alias_template_index_;
|
||||||
|
|
||||||
|
type_safe::optional_ref<common::model::package> current_package_;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,11 @@
|
|||||||
#include <cppast/visitor.hpp>
|
#include <cppast/visitor.hpp>
|
||||||
#include <type_safe/reference.hpp>
|
#include <type_safe/reference.hpp>
|
||||||
|
|
||||||
|
#include <class_diagram/model/class.h>
|
||||||
|
#include <common/model/enums.h>
|
||||||
|
#include <cppast/cpp_alias_template.hpp>
|
||||||
|
#include <cppast/cpp_type_alias.hpp>
|
||||||
|
#include <deque>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -41,6 +46,9 @@
|
|||||||
|
|
||||||
namespace clanguml::class_diagram::visitor {
|
namespace clanguml::class_diagram::visitor {
|
||||||
|
|
||||||
|
using found_relationships_t =
|
||||||
|
std::vector<std::pair<std::string, common::model::relationship_t>>;
|
||||||
|
|
||||||
class translation_unit_visitor {
|
class translation_unit_visitor {
|
||||||
public:
|
public:
|
||||||
translation_unit_visitor(cppast::cpp_entity_index &idx,
|
translation_unit_visitor(cppast::cpp_entity_index &idx,
|
||||||
@@ -99,8 +107,7 @@ public:
|
|||||||
const std::set<std::string> &template_parameter_names = {});
|
const std::set<std::string> &template_parameter_names = {});
|
||||||
|
|
||||||
bool find_relationships(const cppast::cpp_type &t,
|
bool find_relationships(const cppast::cpp_type &t,
|
||||||
std::vector<std::pair<std::string,
|
found_relationships_t &relationships,
|
||||||
clanguml::common::model::relationship_t>> &relationships,
|
|
||||||
clanguml::common::model::relationship_t relationship_hint =
|
clanguml::common::model::relationship_t relationship_hint =
|
||||||
clanguml::common::model::relationship_t::kNone);
|
clanguml::common::model::relationship_t::kNone);
|
||||||
|
|
||||||
@@ -119,8 +126,42 @@ public:
|
|||||||
void process_friend(const cppast::cpp_friend &t,
|
void process_friend(const cppast::cpp_friend &t,
|
||||||
clanguml::class_diagram::model::class_ &parent);
|
clanguml::class_diagram::model::class_ &parent);
|
||||||
|
|
||||||
|
void process_namespace(const cppast::cpp_entity &e,
|
||||||
|
const cppast::cpp_namespace &ns_declaration);
|
||||||
|
|
||||||
|
void process_type_alias(const cppast::cpp_type_alias &ta);
|
||||||
|
|
||||||
|
void process_type_alias_template(const cppast::cpp_alias_template &at);
|
||||||
|
|
||||||
|
void process_class_children(const cppast::cpp_class &cls, model::class_ &c);
|
||||||
|
|
||||||
|
void process_class_bases(
|
||||||
|
const cppast::cpp_class &cls, model::class_ &c) const;
|
||||||
|
|
||||||
|
void process_unexposed_template_specialization_parameters(
|
||||||
|
const type_safe::optional_ref<const cppast::cpp_template_specialization>
|
||||||
|
&tspec,
|
||||||
|
model::class_ &c) const;
|
||||||
|
|
||||||
|
void process_exposed_template_specialization_parameters(
|
||||||
|
const type_safe::optional_ref<const cppast::cpp_template_specialization>
|
||||||
|
&tspec,
|
||||||
|
model::class_ &c);
|
||||||
|
|
||||||
|
void process_scope_template_parameters(
|
||||||
|
model::class_ &c, const cppast::cpp_scope_name &scope);
|
||||||
|
|
||||||
|
bool process_template_parameters(const cppast::cpp_class &cls,
|
||||||
|
model::class_ &c,
|
||||||
|
const type_safe::optional_ref<const cppast::cpp_template_specialization>
|
||||||
|
&tspec);
|
||||||
|
|
||||||
|
void process_class_containment(
|
||||||
|
const cppast::cpp_class &cls, model::class_ &c) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
clanguml::class_diagram::model::class_ build_template_instantiation(
|
std::unique_ptr<clanguml::class_diagram::model::class_>
|
||||||
|
build_template_instantiation(
|
||||||
const cppast::cpp_template_instantiation_type &t,
|
const cppast::cpp_template_instantiation_type &t,
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> parent = {});
|
std::optional<clanguml::class_diagram::model::class_ *> parent = {});
|
||||||
|
|
||||||
@@ -130,6 +171,54 @@ private:
|
|||||||
*/
|
*/
|
||||||
const cppast::cpp_type &resolve_alias(const cppast::cpp_type &t);
|
const cppast::cpp_type &resolve_alias(const cppast::cpp_type &t);
|
||||||
|
|
||||||
|
const cppast::cpp_type &resolve_alias_template(
|
||||||
|
const cppast::cpp_type &type);
|
||||||
|
|
||||||
|
bool find_relationships_in_array(
|
||||||
|
found_relationships_t &relationships, const cppast::cpp_type &t);
|
||||||
|
|
||||||
|
bool find_relationships_in_pointer(const cppast::cpp_type &t_,
|
||||||
|
found_relationships_t &relationships,
|
||||||
|
const common::model::relationship_t &relationship_hint);
|
||||||
|
|
||||||
|
bool find_relationships_in_reference(const cppast::cpp_type &t_,
|
||||||
|
found_relationships_t &relationships,
|
||||||
|
const common::model::relationship_t &relationship_hint);
|
||||||
|
|
||||||
|
bool find_relationships_in_user_defined_type(const cppast::cpp_type &t_,
|
||||||
|
found_relationships_t &relationships, const std::string &fn,
|
||||||
|
common::model::relationship_t &relationship_type,
|
||||||
|
const cppast::cpp_type &t);
|
||||||
|
|
||||||
|
bool find_relationships_in_template_instantiation(const cppast::cpp_type &t,
|
||||||
|
const std::string &fn, found_relationships_t &relationships,
|
||||||
|
common::model::relationship_t relationship_type);
|
||||||
|
|
||||||
|
void build_template_instantiation_primary_template(
|
||||||
|
const cppast::cpp_template_instantiation_type &t,
|
||||||
|
clanguml::class_diagram::model::class_ &tinst,
|
||||||
|
std::deque<std::tuple<std::string, int, bool>> &template_base_params,
|
||||||
|
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
||||||
|
std::string &full_template_name) const;
|
||||||
|
|
||||||
|
void build_template_instantiation_process_type_argument(
|
||||||
|
const std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
||||||
|
model::class_ &tinst, const cppast::cpp_template_argument &targ,
|
||||||
|
model::class_template &ct);
|
||||||
|
|
||||||
|
void build_template_instantiation_process_expression_argument(
|
||||||
|
const cppast::cpp_template_argument &targ,
|
||||||
|
model::class_template &ct) const;
|
||||||
|
|
||||||
|
bool build_template_instantiation_add_base_classes(model::class_ &tinst,
|
||||||
|
std::deque<std::tuple<std::string, int, bool>> &template_base_params,
|
||||||
|
int arg_index, bool variadic_params,
|
||||||
|
const model::class_template &ct) const;
|
||||||
|
|
||||||
|
void process_function_parameter_find_relationships_in_template(
|
||||||
|
model::class_ &c, const std::set<std::string> &template_parameter_names,
|
||||||
|
const cppast::cpp_type &t);
|
||||||
|
|
||||||
// ctx allows to track current visitor context, e.g. current namespace
|
// ctx allows to track current visitor context, e.g. current namespace
|
||||||
translation_unit_context ctx;
|
translation_unit_context ctx;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,6 +20,8 @@
|
|||||||
|
|
||||||
#include "util/util.h"
|
#include "util/util.h"
|
||||||
|
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
namespace clanguml::common::model {
|
namespace clanguml::common::model {
|
||||||
|
|
||||||
std::atomic_uint64_t element::m_nextId = 1;
|
std::atomic_uint64_t element::m_nextId = 1;
|
||||||
@@ -28,6 +30,8 @@ element::element(const std::vector<std::string> &using_namespaces)
|
|||||||
: using_namespaces_{using_namespaces}
|
: using_namespaces_{using_namespaces}
|
||||||
, m_id{m_nextId++}
|
, m_id{m_nextId++}
|
||||||
{
|
{
|
||||||
|
for (const auto &n : using_namespaces_)
|
||||||
|
assert(!util::contains(n, "::"));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string element::alias() const { return fmt::format("C_{:010}", m_id); }
|
std::string element::alias() const { return fmt::format("C_{:010}", m_id); }
|
||||||
@@ -41,6 +45,13 @@ void element::add_relationship(relationship &&cr)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((cr.type() == relationship_t::kInstantiation) &&
|
||||||
|
(cr.destination() == full_name(true))) {
|
||||||
|
LOG_WARN("Skipping self instantiation relationship for {}",
|
||||||
|
cr.destination());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
LOG_DBG("Adding relationship: '{}' - {} - '{}'", cr.destination(),
|
LOG_DBG("Adding relationship: '{}' - {} - '{}'", cr.destination(),
|
||||||
to_string(cr.type()), full_name(true));
|
to_string(cr.type()), full_name(true));
|
||||||
|
|
||||||
@@ -50,6 +61,9 @@ void element::add_relationship(relationship &&cr)
|
|||||||
|
|
||||||
void element::set_using_namespaces(const std::vector<std::string> &un)
|
void element::set_using_namespaces(const std::vector<std::string> &un)
|
||||||
{
|
{
|
||||||
|
for (const auto &n : un)
|
||||||
|
assert(!util::contains(n, "::"));
|
||||||
|
|
||||||
using_namespaces_ = un;
|
using_namespaces_ = un;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,4 +80,19 @@ const std::vector<relationship> &element::relationships() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
void element::append(const element &e) { decorated_element::append(e); }
|
void element::append(const element &e) { decorated_element::append(e); }
|
||||||
|
|
||||||
|
bool operator==(const element &l, const element &r)
|
||||||
|
{
|
||||||
|
return l.full_name(false) == r.full_name(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream &operator<<(std::ostream &out, const element &rhs)
|
||||||
|
{
|
||||||
|
out << "(" << rhs.name() << ", ns=["
|
||||||
|
<< util::join(rhs.get_namespace(), "::") << "], full_name=["
|
||||||
|
<< rhs.full_name(true) << "])";
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,8 +19,10 @@
|
|||||||
|
|
||||||
#include "decorated_element.h"
|
#include "decorated_element.h"
|
||||||
#include "relationship.h"
|
#include "relationship.h"
|
||||||
|
#include "util/util.h"
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <exception>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -30,16 +32,32 @@ class element : public decorated_element {
|
|||||||
public:
|
public:
|
||||||
element(const std::vector<std::string> &using_namespaces);
|
element(const std::vector<std::string> &using_namespaces);
|
||||||
|
|
||||||
|
virtual ~element() = default;
|
||||||
|
|
||||||
std::string alias() const;
|
std::string alias() const;
|
||||||
|
|
||||||
void set_name(const std::string &name) { name_ = name; }
|
void set_name(const std::string &name) { name_ = name; }
|
||||||
|
|
||||||
std::string name() const { return name_; }
|
std::string name() const { return name_; }
|
||||||
|
|
||||||
|
std::string name_and_ns() const
|
||||||
|
{
|
||||||
|
auto ns = namespace_;
|
||||||
|
ns.push_back(name());
|
||||||
|
return util::join(ns, "::");
|
||||||
|
}
|
||||||
|
|
||||||
void set_namespace(const std::vector<std::string> &ns) { namespace_ = ns; }
|
void set_namespace(const std::vector<std::string> &ns) { namespace_ = ns; }
|
||||||
|
|
||||||
std::vector<std::string> get_namespace() const { return namespace_; }
|
std::vector<std::string> get_namespace() const { return namespace_; }
|
||||||
|
|
||||||
|
std::vector<std::string> get_relative_namespace() const
|
||||||
|
{
|
||||||
|
auto relative_ns = namespace_;
|
||||||
|
util::remove_prefix(relative_ns, using_namespaces_);
|
||||||
|
return relative_ns;
|
||||||
|
}
|
||||||
|
|
||||||
virtual std::string full_name(bool relative) const { return name(); }
|
virtual std::string full_name(bool relative) const { return name(); }
|
||||||
|
|
||||||
void set_using_namespaces(const std::vector<std::string> &un);
|
void set_using_namespaces(const std::vector<std::string> &un);
|
||||||
@@ -54,6 +72,10 @@ public:
|
|||||||
|
|
||||||
void append(const element &e);
|
void append(const element &e);
|
||||||
|
|
||||||
|
friend bool operator==(const element &l, const element &r);
|
||||||
|
|
||||||
|
friend std::ostream &operator<<(std::ostream &out, const element &rhs);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const uint64_t m_id{0};
|
const uint64_t m_id{0};
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include <type_safe/optional_ref.hpp>
|
#include <type_safe/optional_ref.hpp>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -37,7 +38,7 @@ public:
|
|||||||
|
|
||||||
virtual ~nested_trait() = default;
|
virtual ~nested_trait() = default;
|
||||||
|
|
||||||
void add_element(std::unique_ptr<T> p)
|
template <typename V = T> void add_element(std::unique_ptr<V> p)
|
||||||
{
|
{
|
||||||
auto it = std::find_if(elements_.begin(), elements_.end(),
|
auto it = std::find_if(elements_.begin(), elements_.end(),
|
||||||
[&p](const auto &e) { return *e == *p; });
|
[&p](const auto &e) { return *e == *p; });
|
||||||
@@ -50,11 +51,12 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_element(std::vector<std::string> path, std::unique_ptr<T> p)
|
template <typename V = T>
|
||||||
|
void add_element(std::vector<std::string> path, std::unique_ptr<V> p)
|
||||||
{
|
{
|
||||||
assert(p);
|
assert(p);
|
||||||
|
|
||||||
LOG_DBG("Adding nested element {} at path '{}'", p->name(),
|
LOG_DBG("Adding nested element {} at path {}", p->name(),
|
||||||
fmt::join(path, "::"));
|
fmt::join(path, "::"));
|
||||||
|
|
||||||
if (path.empty()) {
|
if (path.empty()) {
|
||||||
@@ -64,42 +66,57 @@ public:
|
|||||||
|
|
||||||
auto parent = get_element(path);
|
auto parent = get_element(path);
|
||||||
|
|
||||||
if (parent)
|
if (parent && dynamic_cast<nested_trait<T> *>(&parent.value()))
|
||||||
parent.value().add_element(std::move(p));
|
dynamic_cast<nested_trait<T> &>(parent.value())
|
||||||
else
|
.template add_element<V>(std::move(p));
|
||||||
|
else {
|
||||||
spdlog::error(
|
spdlog::error(
|
||||||
"No parent element found at: {}", fmt::join(path, "::"));
|
"No parent element found at: {}", fmt::join(path, "::"));
|
||||||
|
throw std::runtime_error("No parent element found");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type_safe::optional_ref<T> get_element(std::vector<std::string> path) const
|
template <typename V = T>
|
||||||
|
auto get_element(std::vector<std::string> path) const
|
||||||
{
|
{
|
||||||
LOG_DBG("Getting nested element at path: {}", fmt::join(path, "::"));
|
LOG_DBG("Getting nested element at path: {}", fmt::join(path, "::"));
|
||||||
|
|
||||||
if (path.empty() || !has_element(path.at(0))) {
|
if (path.empty() || !has_element(path.at(0))) {
|
||||||
LOG_WARN("Nested element {} not found in element",
|
LOG_WARN("Nested element {} not found in element",
|
||||||
fmt::join(path, "::"));
|
fmt::join(path, "::"));
|
||||||
return {};
|
return type_safe::optional_ref<V>{};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto p = get_element(path.at(0));
|
|
||||||
if (path.size() == 1)
|
if (path.size() == 1)
|
||||||
return p;
|
return get_element<V>(path.at(0));
|
||||||
|
|
||||||
return p.value().get_element(
|
auto p = get_element<T>(path.at(0));
|
||||||
|
|
||||||
|
if (!p)
|
||||||
|
return type_safe::optional_ref<V>{};
|
||||||
|
|
||||||
|
if (dynamic_cast<nested_trait<T> *>(&p.value()))
|
||||||
|
return dynamic_cast<nested_trait<T> &>(p.value()).get_element<V>(
|
||||||
std::vector<std::string>(path.begin() + 1, path.end()));
|
std::vector<std::string>(path.begin() + 1, path.end()));
|
||||||
|
|
||||||
|
return type_safe::optional_ref<V>{};
|
||||||
}
|
}
|
||||||
|
|
||||||
type_safe::optional_ref<T> get_element(const std::string &name) const
|
template <typename V = T> auto get_element(const std::string &name) const
|
||||||
{
|
{
|
||||||
auto it = std::find_if(elements_.cbegin(), elements_.cend(),
|
auto it = std::find_if(elements_.cbegin(), elements_.cend(),
|
||||||
[&](const auto &p) { return name == p->name(); });
|
[&](const auto &p) { return name == p->name(); });
|
||||||
|
|
||||||
if (it == elements_.end())
|
if (it == elements_.end())
|
||||||
return {};
|
return type_safe::optional_ref<V>{type_safe::nullopt};
|
||||||
|
|
||||||
assert(it->get() != nullptr);
|
assert(it->get() != nullptr);
|
||||||
|
|
||||||
return type_safe::ref(*(it->get()));
|
if (dynamic_cast<V *>(it->get()))
|
||||||
|
return type_safe::optional_ref<V>{
|
||||||
|
type_safe::ref<V>(dynamic_cast<V &>(*it->get()))};
|
||||||
|
|
||||||
|
return type_safe::optional_ref<V>{type_safe::nullopt};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_element(const std::string &name) const
|
bool has_element(const std::string &name) const
|
||||||
@@ -118,6 +135,24 @@ public:
|
|||||||
auto begin() const { return elements_.begin(); }
|
auto begin() const { return elements_.begin(); }
|
||||||
auto end() const { return elements_.end(); }
|
auto end() const { return elements_.end(); }
|
||||||
|
|
||||||
|
void print_tree(const int level)
|
||||||
|
{
|
||||||
|
const auto &d = *this;
|
||||||
|
|
||||||
|
if (level == 0) {
|
||||||
|
std::cout << "--- Printing tree:\n";
|
||||||
|
}
|
||||||
|
for (const auto &e : d) {
|
||||||
|
if (dynamic_cast<nested_trait<T> *>(e.get())) {
|
||||||
|
std::cout << std::string(level, ' ') << "[" << *e << "]\n";
|
||||||
|
dynamic_cast<nested_trait<T> *>(e.get())->print_tree(level + 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
std::cout << std::string(level, ' ') << "- " << *e << "]\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::unique_ptr<T>> elements_;
|
std::vector<std::unique_ptr<T>> elements_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* src/package_diagram/model/class.h
|
* src/common/model/class.h
|
||||||
*
|
*
|
||||||
* Copyright (c) 2021-2022 Bartek Kryza <bkryza@gmail.com>
|
* Copyright (c) 2021-2022 Bartek Kryza <bkryza@gmail.com>
|
||||||
*
|
*
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
namespace clanguml::package_diagram::model {
|
namespace clanguml::common::model {
|
||||||
package::package(const std::vector<std::string> &using_namespaces)
|
package::package(const std::vector<std::string> &using_namespaces)
|
||||||
: element{using_namespaces}
|
: element{using_namespaces}
|
||||||
{
|
{
|
||||||
@@ -43,11 +43,6 @@ std::string package::full_name(bool relative) const
|
|||||||
return fmt::format("{}", fmt::join(fn, "::"));
|
return fmt::format("{}", fmt::join(fn, "::"));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const package &l, const package &r)
|
|
||||||
{
|
|
||||||
return l.full_name(false) == r.full_name(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool package::is_deprecated() const { return is_deprecated_; }
|
bool package::is_deprecated() const { return is_deprecated_; }
|
||||||
|
|
||||||
void package::set_deprecated(bool deprecated) { is_deprecated_ = deprecated; }
|
void package::set_deprecated(bool deprecated) { is_deprecated_ = deprecated; }
|
||||||
@@ -29,11 +29,11 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace clanguml::package_diagram::model {
|
namespace clanguml::common::model {
|
||||||
|
|
||||||
class package : public common::model::element,
|
class package : public element,
|
||||||
public common::model::stylable_element,
|
public stylable_element,
|
||||||
public common::model::nested_trait<package> {
|
public nested_trait<element> {
|
||||||
public:
|
public:
|
||||||
package(const std::vector<std::string> &using_namespaces);
|
package(const std::vector<std::string> &using_namespaces);
|
||||||
|
|
||||||
@@ -44,8 +44,6 @@ public:
|
|||||||
|
|
||||||
std::string full_name(bool relative) const override;
|
std::string full_name(bool relative) const override;
|
||||||
|
|
||||||
friend bool operator==(const package &l, const package &r);
|
|
||||||
|
|
||||||
bool is_deprecated() const;
|
bool is_deprecated() const;
|
||||||
|
|
||||||
void set_deprecated(bool deprecated);
|
void set_deprecated(bool deprecated);
|
||||||
@@ -129,6 +129,20 @@ bool diagram::should_include_relationship(const std::string &rel)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool diagram::should_include(
|
||||||
|
const std::pair<std::vector<std::string>, std::string> &name) const
|
||||||
|
{
|
||||||
|
return should_include(std::get<0>(name), std::get<1>(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool diagram::should_include(
|
||||||
|
const std::vector<std::string> &ns, const std::string &name) const
|
||||||
|
{
|
||||||
|
auto ns_and_name = ns;
|
||||||
|
ns_and_name.push_back(name);
|
||||||
|
return should_include(util::join(ns_and_name, "::"));
|
||||||
|
}
|
||||||
|
|
||||||
bool diagram::should_include(const std::string &name_) const
|
bool diagram::should_include(const std::string &name_) const
|
||||||
{
|
{
|
||||||
auto name = clanguml::util::unqualify(name_);
|
auto name = clanguml::util::unqualify(name_);
|
||||||
@@ -150,7 +164,7 @@ bool diagram::should_include(const std::string &name_) const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
spdlog::debug("Skipping from diagram: {}", name);
|
LOG_DBG("Skipping from diagram: {}", name);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -396,6 +410,7 @@ template <> struct convert<class_diagram> {
|
|||||||
get_option(node, rhs.layout);
|
get_option(node, rhs.layout);
|
||||||
get_option(node, rhs.include_relations_also_as_members);
|
get_option(node, rhs.include_relations_also_as_members);
|
||||||
get_option(node, rhs.generate_method_arguments);
|
get_option(node, rhs.generate_method_arguments);
|
||||||
|
get_option(node, rhs.generate_packages);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -476,6 +491,7 @@ template <> struct convert<config> {
|
|||||||
get_option(node, rhs.include_relations_also_as_members);
|
get_option(node, rhs.include_relations_also_as_members);
|
||||||
get_option(node, rhs.puml);
|
get_option(node, rhs.puml);
|
||||||
get_option(node, rhs.generate_method_arguments);
|
get_option(node, rhs.generate_method_arguments);
|
||||||
|
get_option(node, rhs.generate_packages);
|
||||||
|
|
||||||
auto diagrams = node["diagrams"];
|
auto diagrams = node["diagrams"];
|
||||||
|
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ struct inheritable_diagram_options {
|
|||||||
option<plantuml> puml{"plantuml", option_inherit_mode::append};
|
option<plantuml> puml{"plantuml", option_inherit_mode::append};
|
||||||
option<method_arguments> generate_method_arguments{
|
option<method_arguments> generate_method_arguments{
|
||||||
"generate_method_arguments", method_arguments::full};
|
"generate_method_arguments", method_arguments::full};
|
||||||
|
option<bool> generate_packages{"generate_packages", false};
|
||||||
|
|
||||||
void inherit(const inheritable_diagram_options &parent);
|
void inherit(const inheritable_diagram_options &parent);
|
||||||
};
|
};
|
||||||
@@ -102,9 +103,16 @@ struct diagram : public inheritable_diagram_options {
|
|||||||
|
|
||||||
bool should_include_relationship(const std::string &rel);
|
bool should_include_relationship(const std::string &rel);
|
||||||
|
|
||||||
bool should_include(const std::string &name_) const;
|
bool should_include(
|
||||||
|
const std::pair<std::vector<std::string>, std::string> &name) const;
|
||||||
|
|
||||||
|
bool should_include(
|
||||||
|
const std::vector<std::string> &ns, const std::string &name) const;
|
||||||
|
|
||||||
bool should_include(const common::model::scope_t scope) const;
|
bool should_include(const common::model::scope_t scope) const;
|
||||||
|
bool should_include(const std::string &name_) const;
|
||||||
|
|
||||||
|
private:
|
||||||
};
|
};
|
||||||
|
|
||||||
struct source_location {
|
struct source_location {
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ template <typename T> struct option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void operator()(const T &v) { set(v); }
|
||||||
|
|
||||||
T &operator()() { return value; }
|
T &operator()() { return value; }
|
||||||
|
|
||||||
const T &operator()() const { return value; }
|
const T &operator()() const { return value; }
|
||||||
|
|||||||
@@ -126,6 +126,16 @@ bool is_inside_class(const cppast::cpp_entity &e)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<std::vector<std::string>, std::string> split_ns(
|
||||||
|
const std::string &full_name)
|
||||||
|
{
|
||||||
|
auto name_before_template = ::clanguml::util::split(full_name, "<")[0];
|
||||||
|
auto ns = ::clanguml::util::split(name_before_template, "::");
|
||||||
|
auto name = ns.back();
|
||||||
|
ns.pop_back();
|
||||||
|
return {ns, name};
|
||||||
|
}
|
||||||
|
|
||||||
std::string ns(const cppast::cpp_type &t, const cppast::cpp_entity_index &idx)
|
std::string ns(const cppast::cpp_type &t, const cppast::cpp_entity_index &idx)
|
||||||
{
|
{
|
||||||
if (t.kind() == cppast::cpp_type_kind::user_defined_t &&
|
if (t.kind() == cppast::cpp_type_kind::user_defined_t &&
|
||||||
|
|||||||
@@ -58,6 +58,9 @@ type_safe::optional_ref<const cppast::cpp_namespace> entity_ns(
|
|||||||
|
|
||||||
std::string ns(const cppast::cpp_type &t, const cppast::cpp_entity_index &idx);
|
std::string ns(const cppast::cpp_type &t, const cppast::cpp_entity_index &idx);
|
||||||
|
|
||||||
|
std::pair<std::vector<std::string>, std::string> split_ns(
|
||||||
|
const std::string &full_name);
|
||||||
|
|
||||||
bool is_inside_class(const cppast::cpp_entity &e);
|
bool is_inside_class(const cppast::cpp_entity &e);
|
||||||
} // namespace util
|
} // namespace util
|
||||||
} // namespace cx
|
} // namespace cx
|
||||||
|
|||||||
@@ -54,8 +54,9 @@ void generator::generate_relationships(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Process it's subpackages relationships
|
// Process it's subpackages relationships
|
||||||
for (const std::unique_ptr<package> &subpackage : p) {
|
for (const auto &subpackage : p) {
|
||||||
generate_relationships(*subpackage, ostr);
|
generate_relationships(
|
||||||
|
dynamic_cast<const package &>(*subpackage), ostr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,7 +78,7 @@ void generator::generate(const package &p, std::ostream &ostr) const
|
|||||||
ostr << " {" << '\n';
|
ostr << " {" << '\n';
|
||||||
|
|
||||||
for (const auto &subpackage : p) {
|
for (const auto &subpackage : p) {
|
||||||
generate(*subpackage, ostr);
|
generate(dynamic_cast<const package &>(*subpackage), ostr);
|
||||||
}
|
}
|
||||||
|
|
||||||
ostr << "}" << '\n';
|
ostr << "}" << '\n';
|
||||||
@@ -93,14 +94,14 @@ void generator::generate(std::ostream &ostr) const
|
|||||||
|
|
||||||
if (m_config.should_include_entities("packages")) {
|
if (m_config.should_include_entities("packages")) {
|
||||||
for (const auto &p : m_model) {
|
for (const auto &p : m_model) {
|
||||||
generate(*p, ostr);
|
generate(dynamic_cast<package &>(*p), ostr);
|
||||||
ostr << '\n';
|
ostr << '\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process package relationships
|
// Process package relationships
|
||||||
for (const auto &p : m_model) {
|
for (const auto &p : m_model) {
|
||||||
generate_relationships(*p, ostr);
|
generate_relationships(dynamic_cast<package &>(*p), ostr);
|
||||||
ostr << '\n';
|
ostr << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,11 +18,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/generators/plantuml/generator.h"
|
#include "common/generators/plantuml/generator.h"
|
||||||
|
#include "common/model/package.h"
|
||||||
#include "common/model/relationship.h"
|
#include "common/model/relationship.h"
|
||||||
#include "config/config.h"
|
#include "config/config.h"
|
||||||
#include "cx/compilation_database.h"
|
#include "cx/compilation_database.h"
|
||||||
#include "package_diagram/model/diagram.h"
|
#include "package_diagram/model/diagram.h"
|
||||||
#include "package_diagram/model/package.h"
|
|
||||||
#include "package_diagram/visitor/translation_unit_visitor.h"
|
#include "package_diagram/visitor/translation_unit_visitor.h"
|
||||||
#include "util/util.h"
|
#include "util/util.h"
|
||||||
|
|
||||||
@@ -46,9 +46,9 @@ template <typename C, typename D>
|
|||||||
using common_generator =
|
using common_generator =
|
||||||
clanguml::common::generators::plantuml::generator<C, D>;
|
clanguml::common::generators::plantuml::generator<C, D>;
|
||||||
|
|
||||||
|
using clanguml::common::model::package;
|
||||||
using clanguml::common::model::relationship_t;
|
using clanguml::common::model::relationship_t;
|
||||||
using clanguml::common::model::scope_t;
|
using clanguml::common::model::scope_t;
|
||||||
using clanguml::package_diagram::model::package;
|
|
||||||
using namespace clanguml::util;
|
using namespace clanguml::util;
|
||||||
|
|
||||||
class generator : public common_generator<diagram_config, diagram_model> {
|
class generator : public common_generator<diagram_config, diagram_model> {
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ std::string diagram::to_alias(const std::string &full_name) const
|
|||||||
throw error::uml_alias_missing(
|
throw error::uml_alias_missing(
|
||||||
fmt::format("Missing alias for '{}'", full_name));
|
fmt::format("Missing alias for '{}'", full_name));
|
||||||
|
|
||||||
auto package = get_element(fn);
|
auto package = get_element<common::model::package>(fn);
|
||||||
|
|
||||||
if (!package)
|
if (!package)
|
||||||
throw error::uml_alias_missing(
|
throw error::uml_alias_missing(
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/model/diagram.h"
|
#include "common/model/diagram.h"
|
||||||
#include "package.h"
|
#include "common/model/package.h"
|
||||||
|
|
||||||
#include <type_safe/optional_ref.hpp>
|
#include <type_safe/optional_ref.hpp>
|
||||||
|
|
||||||
@@ -28,7 +28,8 @@
|
|||||||
namespace clanguml::package_diagram::model {
|
namespace clanguml::package_diagram::model {
|
||||||
|
|
||||||
class diagram : public clanguml::common::model::diagram,
|
class diagram : public clanguml::common::model::diagram,
|
||||||
public clanguml::common::model::nested_trait<package> {
|
public clanguml::common::model::nested_trait<
|
||||||
|
clanguml::common::model::element> {
|
||||||
public:
|
public:
|
||||||
diagram() = default;
|
diagram() = default;
|
||||||
|
|
||||||
|
|||||||
@@ -180,12 +180,12 @@ clanguml::package_diagram::model::diagram &translation_unit_context::diagram()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void translation_unit_context::set_current_package(
|
void translation_unit_context::set_current_package(
|
||||||
type_safe::optional_ref<model::package> p)
|
type_safe::optional_ref<common::model::package> p)
|
||||||
{
|
{
|
||||||
current_package_ = p;
|
current_package_ = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
type_safe::optional_ref<model::package>
|
type_safe::optional_ref<common::model::package>
|
||||||
translation_unit_context::get_current_package() const
|
translation_unit_context::get_current_package() const
|
||||||
{
|
{
|
||||||
return current_package_;
|
return current_package_;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/model/package.h"
|
||||||
#include "config/config.h"
|
#include "config/config.h"
|
||||||
#include "package_diagram/model/diagram.h"
|
#include "package_diagram/model/diagram.h"
|
||||||
|
|
||||||
@@ -75,9 +76,9 @@ public:
|
|||||||
|
|
||||||
clanguml::package_diagram::model::diagram &diagram();
|
clanguml::package_diagram::model::diagram &diagram();
|
||||||
|
|
||||||
void set_current_package(type_safe::optional_ref<model::package> p);
|
void set_current_package(type_safe::optional_ref<common::model::package> p);
|
||||||
|
|
||||||
type_safe::optional_ref<model::package> get_current_package() const;
|
type_safe::optional_ref<common::model::package> get_current_package() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Current visitor namespace
|
// Current visitor namespace
|
||||||
@@ -104,7 +105,7 @@ private:
|
|||||||
std::map<std::string, type_safe::object_ref<const cppast::cpp_type>>
|
std::map<std::string, type_safe::object_ref<const cppast::cpp_type>>
|
||||||
alias_template_index_;
|
alias_template_index_;
|
||||||
|
|
||||||
type_safe::optional_ref<model::package> current_package_;
|
type_safe::optional_ref<common::model::package> current_package_;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,11 +37,11 @@ namespace clanguml::package_diagram::visitor {
|
|||||||
|
|
||||||
using clanguml::class_diagram::model::type_alias;
|
using clanguml::class_diagram::model::type_alias;
|
||||||
using clanguml::common::model::access_t;
|
using clanguml::common::model::access_t;
|
||||||
|
using clanguml::common::model::package;
|
||||||
using clanguml::common::model::relationship;
|
using clanguml::common::model::relationship;
|
||||||
using clanguml::common::model::relationship_t;
|
using clanguml::common::model::relationship_t;
|
||||||
using clanguml::common::model::scope_t;
|
using clanguml::common::model::scope_t;
|
||||||
using clanguml::package_diagram::model::diagram;
|
using clanguml::package_diagram::model::diagram;
|
||||||
using clanguml::package_diagram::model::package;
|
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
scope_t cpp_access_specifier_to_scope(
|
scope_t cpp_access_specifier_to_scope(
|
||||||
@@ -98,10 +98,8 @@ void translation_unit_visitor::operator()(const cppast::cpp_entity &file)
|
|||||||
ctx.config().using_namespace()[0], "::");
|
ctx.config().using_namespace()[0], "::");
|
||||||
|
|
||||||
if (!util::starts_with(usn, package_path)) {
|
if (!util::starts_with(usn, package_path)) {
|
||||||
auto p = std::make_unique<package>(
|
auto p = std::make_unique<package>(usn);
|
||||||
ctx.config().using_namespace());
|
|
||||||
util::remove_prefix(package_path, usn);
|
util::remove_prefix(package_path, usn);
|
||||||
util::remove_prefix(package_parent, usn);
|
|
||||||
|
|
||||||
p->set_name(e.name());
|
p->set_name(e.name());
|
||||||
p->set_namespace(package_parent);
|
p->set_namespace(package_parent);
|
||||||
@@ -122,10 +120,11 @@ void translation_unit_visitor::operator()(const cppast::cpp_entity &file)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!p->skip()) {
|
if (!p->skip()) {
|
||||||
ctx.diagram().add_element(
|
auto rns = p->get_relative_namespace();
|
||||||
package_parent, std::move(p));
|
ctx.diagram().add_element(rns, std::move(p));
|
||||||
ctx.set_current_package(
|
ctx.set_current_package(
|
||||||
ctx.diagram().get_element(package_path));
|
ctx.diagram().get_element<package>(
|
||||||
|
package_path));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -352,6 +351,7 @@ bool translation_unit_visitor::find_relationships(const cppast::cpp_type &t_,
|
|||||||
const auto fn = cx::util::full_name(
|
const auto fn = cx::util::full_name(
|
||||||
resolve_alias(cppast::remove_cv(t_)), ctx.entity_index(), false);
|
resolve_alias(cppast::remove_cv(t_)), ctx.entity_index(), false);
|
||||||
auto t_ns = util::split(fn, "::");
|
auto t_ns = util::split(fn, "::");
|
||||||
|
auto t_name = t_ns.back();
|
||||||
t_ns.pop_back();
|
t_ns.pop_back();
|
||||||
|
|
||||||
const auto &t_raw = resolve_alias(cppast::remove_cv(t_));
|
const auto &t_raw = resolve_alias(cppast::remove_cv(t_));
|
||||||
@@ -464,7 +464,7 @@ bool translation_unit_visitor::find_relationships(const cppast::cpp_type &t_,
|
|||||||
found = find_relationships(args[0u].type().value(), relationships,
|
found = find_relationships(args[0u].type().value(), relationships,
|
||||||
relationship_t::kDependency);
|
relationship_t::kDependency);
|
||||||
}
|
}
|
||||||
else if (ctx.config().should_include(fn)) {
|
else if (ctx.config().should_include(t_ns, t_name)) {
|
||||||
LOG_DBG("User defined template instantiation: {} | {}",
|
LOG_DBG("User defined template instantiation: {} | {}",
|
||||||
cppast::to_string(t_), cppast::to_string(t_.canonical()));
|
cppast::to_string(t_), cppast::to_string(t_.canonical()));
|
||||||
|
|
||||||
|
|||||||
@@ -35,10 +35,10 @@
|
|||||||
#include <type_safe/reference.hpp>
|
#include <type_safe/reference.hpp>
|
||||||
|
|
||||||
#include <common/model/enums.h>
|
#include <common/model/enums.h>
|
||||||
|
#include <common/model/package.h>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <package_diagram/model/package.h>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace clanguml::package_diagram::visitor {
|
namespace clanguml::package_diagram::visitor {
|
||||||
|
|||||||
@@ -80,7 +80,8 @@ void translation_unit_visitor::process_activities(const cppast::cpp_function &e)
|
|||||||
.value();
|
.value();
|
||||||
m.from = cx::util::ns(caller) + "::" + caller.name();
|
m.from = cx::util::ns(caller) + "::" + caller.name();
|
||||||
|
|
||||||
if (!ctx.config().should_include(m.from))
|
if (!ctx.config().should_include(
|
||||||
|
util::split(cx::util::ns(caller), "::"), caller.name()))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (caller.kind() == cpp_entity_kind::function_t)
|
if (caller.kind() == cpp_entity_kind::function_t)
|
||||||
@@ -96,7 +97,8 @@ void translation_unit_visitor::process_activities(const cppast::cpp_function &e)
|
|||||||
if (callee.kind() == cpp_entity_kind::function_t)
|
if (callee.kind() == cpp_entity_kind::function_t)
|
||||||
m.to += "()";
|
m.to += "()";
|
||||||
|
|
||||||
if (!ctx.config().should_include(m.to))
|
if (!ctx.config().should_include(
|
||||||
|
util::split(cx::util::ns(callee), "::"), callee.name()))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
m.to_usr = type_safe::get(function_call.get_callee_method_id());
|
m.to_usr = type_safe::get(function_call.get_callee_method_id());
|
||||||
|
|||||||
@@ -44,23 +44,22 @@ std::vector<std::string> split(std::string str, std::string delimiter)
|
|||||||
{
|
{
|
||||||
std::vector<std::string> result;
|
std::vector<std::string> result;
|
||||||
|
|
||||||
|
if (!contains(str, delimiter))
|
||||||
|
result.push_back(str);
|
||||||
|
else
|
||||||
while (str.size()) {
|
while (str.size()) {
|
||||||
int index = str.find(delimiter);
|
int index = str.find(delimiter);
|
||||||
if (index != std::string::npos) {
|
if (index != std::string::npos) {
|
||||||
result.push_back(str.substr(0, index));
|
result.push_back(str.substr(0, index));
|
||||||
str = str.substr(index + delimiter.size());
|
str = str.substr(index + delimiter.size());
|
||||||
if (str.size() == 0)
|
|
||||||
result.push_back(str);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
if (!str.empty())
|
||||||
result.push_back(str);
|
result.push_back(str);
|
||||||
str = "";
|
str = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.empty())
|
|
||||||
result.push_back(str);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace clanguml {
|
namespace clanguml {
|
||||||
@@ -190,6 +191,9 @@ bool contains(const T &container, const E &element)
|
|||||||
[&element](const auto &e) { return *e == *element; }) !=
|
[&element](const auto &e) { return *e == *element; }) !=
|
||||||
container.end();
|
container.end();
|
||||||
}
|
}
|
||||||
|
else if constexpr (std::is_same_v<std::remove_cv_t<T>, std::string>) {
|
||||||
|
return container.find(element) != std::string::npos;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
return std::find(container.begin(), container.end(), element) !=
|
return std::find(container.begin(), container.end(), element) !=
|
||||||
container.end();
|
container.end();
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ TEST_CASE("t00002", "[test-case][class]")
|
|||||||
|
|
||||||
REQUIRE(diagram->exclude().namespaces.size() == 0);
|
REQUIRE(diagram->exclude().namespaces.size() == 0);
|
||||||
|
|
||||||
REQUIRE(diagram->should_include("clanguml::t00002::A"));
|
REQUIRE(diagram->should_include({"clanguml", "t00002"}, "A"));
|
||||||
REQUIRE(!diagram->should_include("std::vector"));
|
REQUIRE(!diagram->should_include({"std"}, "vector"));
|
||||||
|
|
||||||
auto model = generate_class_diagram(db, diagram);
|
auto model = generate_class_diagram(db, diagram);
|
||||||
|
|
||||||
|
|||||||
@@ -39,12 +39,23 @@ TEST_CASE("t00014", "[test-case][class]")
|
|||||||
REQUIRE_THAT(puml, IsClassTemplate("A", "T,std::string"));
|
REQUIRE_THAT(puml, IsClassTemplate("A", "T,std::string"));
|
||||||
REQUIRE_THAT(puml, IsClassTemplate("A", "bool,std::string"));
|
REQUIRE_THAT(puml, IsClassTemplate("A", "bool,std::string"));
|
||||||
REQUIRE_THAT(puml, IsClassTemplate("AString", "float"));
|
REQUIRE_THAT(puml, IsClassTemplate("AString", "float"));
|
||||||
|
REQUIRE_THAT(puml, IsClassTemplate("AString", "int"));
|
||||||
|
REQUIRE_THAT(puml, IsClassTemplate("AString", "std::string"));
|
||||||
REQUIRE_THAT(
|
REQUIRE_THAT(
|
||||||
puml, !IsClassTemplate("std::std::function", "void(T...,int),int)"));
|
puml, !IsClassTemplate("std::std::function", "void(T...,int),int)"));
|
||||||
|
|
||||||
REQUIRE_THAT(puml, IsInstantiation(_A("A<T,P>"), _A("A<T,std::string>")));
|
REQUIRE_THAT(puml, IsInstantiation(_A("A<T,P>"), _A("A<T,std::string>")));
|
||||||
REQUIRE_THAT(
|
REQUIRE_THAT(
|
||||||
puml, IsInstantiation(_A("A<T,std::string>"), _A("AString<float>")));
|
puml, IsInstantiation(_A("A<T,std::string>"), _A("AString<float>")));
|
||||||
|
REQUIRE_THAT(
|
||||||
|
puml, IsInstantiation(_A("A<T,std::string>"), _A("AString<int>")));
|
||||||
|
REQUIRE_THAT(
|
||||||
|
puml, !IsInstantiation(_A("AString<int>"), _A("AString<int>")));
|
||||||
|
REQUIRE_THAT(puml,
|
||||||
|
IsInstantiation(_A("A<T,std::string>"), _A("AString<std::string>")));
|
||||||
|
REQUIRE_THAT(puml,
|
||||||
|
!IsInstantiation(
|
||||||
|
_A("AString<std::string>"), _A("AString<std::string>")));
|
||||||
REQUIRE_THAT(
|
REQUIRE_THAT(
|
||||||
puml, IsAggregation(_A("R"), _A("A<bool,std::string>"), "-boolstring"));
|
puml, IsAggregation(_A("R"), _A("A<bool,std::string>"), "-boolstring"));
|
||||||
REQUIRE_THAT(
|
REQUIRE_THAT(
|
||||||
|
|||||||
13
tests/t00036/.clang-uml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
compilation_database_dir: ..
|
||||||
|
output_directory: puml
|
||||||
|
diagrams:
|
||||||
|
t00036_class:
|
||||||
|
type: class
|
||||||
|
generate_packages: true
|
||||||
|
glob:
|
||||||
|
- ../../tests/t00036/t00036.cc
|
||||||
|
using_namespace:
|
||||||
|
- clanguml::t00036
|
||||||
|
include:
|
||||||
|
namespaces:
|
||||||
|
- clanguml::t00036
|
||||||
33
tests/t00036/t00036.cc
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
namespace clanguml {
|
||||||
|
namespace t00036 {
|
||||||
|
|
||||||
|
namespace ns1 {
|
||||||
|
|
||||||
|
enum class E { blue, yellow };
|
||||||
|
|
||||||
|
namespace ns11 {
|
||||||
|
|
||||||
|
template <typename T> struct A {
|
||||||
|
T a;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace ns111 {
|
||||||
|
|
||||||
|
struct B {
|
||||||
|
A<int> a_int;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ns2 {
|
||||||
|
namespace ns22 {
|
||||||
|
|
||||||
|
struct C;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace t00036
|
||||||
|
} // namespace clanguml
|
||||||
50
tests/t00036/test_case.h
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/**
|
||||||
|
* tests/t00036/test_case.cc
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021-2022 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
TEST_CASE("t00036", "[test-case][class]")
|
||||||
|
{
|
||||||
|
auto [config, db] = load_config("t00036");
|
||||||
|
|
||||||
|
auto diagram = config.diagrams["t00036_class"];
|
||||||
|
|
||||||
|
REQUIRE(diagram->name == "t00036_class");
|
||||||
|
REQUIRE(diagram->generate_packages() == true);
|
||||||
|
|
||||||
|
auto model = generate_class_diagram(db, diagram);
|
||||||
|
|
||||||
|
REQUIRE(model.name() == "t00036_class");
|
||||||
|
|
||||||
|
auto puml = generate_class_puml(diagram, model);
|
||||||
|
AliasMatcher _A(puml);
|
||||||
|
|
||||||
|
REQUIRE_THAT(puml, StartsWith("@startuml"));
|
||||||
|
REQUIRE_THAT(puml, EndsWith("@enduml\n"));
|
||||||
|
|
||||||
|
REQUIRE_THAT(puml, IsClassTemplate("A", "T"));
|
||||||
|
REQUIRE_THAT(puml, IsClassTemplate("A", "int"));
|
||||||
|
REQUIRE_THAT(puml, IsEnum(_A("E")));
|
||||||
|
REQUIRE_THAT(puml, IsClass(_A("B")));
|
||||||
|
REQUIRE_THAT(puml, IsClass(_A("C")));
|
||||||
|
REQUIRE_THAT(puml, IsPackage("ns111"));
|
||||||
|
REQUIRE_THAT(puml, IsPackage("ns22"));
|
||||||
|
|
||||||
|
REQUIRE_THAT(puml, IsAggregation(_A("B"), _A("A<int>"), "+a_int"));
|
||||||
|
|
||||||
|
save_puml(
|
||||||
|
"./" + config.output_directory() + "/" + diagram->name + ".puml", puml);
|
||||||
|
}
|
||||||
@@ -178,6 +178,7 @@ using namespace clanguml::test::matchers;
|
|||||||
#include "t00033/test_case.h"
|
#include "t00033/test_case.h"
|
||||||
#include "t00034/test_case.h"
|
#include "t00034/test_case.h"
|
||||||
#include "t00035/test_case.h"
|
#include "t00035/test_case.h"
|
||||||
|
#include "t00036/test_case.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
// Sequence diagram tests
|
// Sequence diagram tests
|
||||||
|
|||||||
@@ -102,6 +102,9 @@ test_cases:
|
|||||||
- name: t00035
|
- name: t00035
|
||||||
title: PlantUML class diagram layout hints test case
|
title: PlantUML class diagram layout hints test case
|
||||||
description:
|
description:
|
||||||
|
- name: t00036
|
||||||
|
title: Class diagram with namespaces generated as packages
|
||||||
|
description:
|
||||||
Sequence diagrams:
|
Sequence diagrams:
|
||||||
- name: t20001
|
- name: t20001
|
||||||
title: Basic sequence diagram test case
|
title: Basic sequence diagram test case
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ TEST_CASE("Test config simple", "[unit-test]")
|
|||||||
CHECK(clanguml::util::contains(diagram.using_namespace(), "clanguml"));
|
CHECK(clanguml::util::contains(diagram.using_namespace(), "clanguml"));
|
||||||
CHECK(diagram.generate_method_arguments() ==
|
CHECK(diagram.generate_method_arguments() ==
|
||||||
clanguml::config::method_arguments::full);
|
clanguml::config::method_arguments::full);
|
||||||
|
CHECK(diagram.generate_packages() == true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Test config inherited", "[unit-test]")
|
TEST_CASE("Test config inherited", "[unit-test]")
|
||||||
@@ -46,6 +47,7 @@ TEST_CASE("Test config inherited", "[unit-test]")
|
|||||||
CHECK(def.glob()[0] == "src/**/*.cc");
|
CHECK(def.glob()[0] == "src/**/*.cc");
|
||||||
CHECK(def.glob()[1] == "src/**/*.h");
|
CHECK(def.glob()[1] == "src/**/*.h");
|
||||||
CHECK(clanguml::util::contains(def.using_namespace(), "clanguml"));
|
CHECK(clanguml::util::contains(def.using_namespace(), "clanguml"));
|
||||||
|
CHECK(def.generate_packages() == false);
|
||||||
|
|
||||||
auto &cus = *cfg.diagrams["class_custom"];
|
auto &cus = *cfg.diagrams["class_custom"];
|
||||||
CHECK(cus.type() == clanguml::config::diagram_type::class_diagram);
|
CHECK(cus.type() == clanguml::config::diagram_type::class_diagram);
|
||||||
@@ -53,6 +55,7 @@ TEST_CASE("Test config inherited", "[unit-test]")
|
|||||||
CHECK(cus.glob()[0] == "src/main.cc");
|
CHECK(cus.glob()[0] == "src/main.cc");
|
||||||
CHECK(clanguml::util::contains(cus.using_namespace(), "clanguml::ns1"));
|
CHECK(clanguml::util::contains(cus.using_namespace(), "clanguml::ns1"));
|
||||||
CHECK(cus.include_relations_also_as_members());
|
CHECK(cus.include_relations_also_as_members());
|
||||||
|
CHECK(def.generate_packages() == false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Test config includes", "[unit-test]")
|
TEST_CASE("Test config includes", "[unit-test]")
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ diagrams:
|
|||||||
using_namespace:
|
using_namespace:
|
||||||
- clanguml
|
- clanguml
|
||||||
generate_method_arguments: full
|
generate_method_arguments: full
|
||||||
|
generate_packages: true
|
||||||
include:
|
include:
|
||||||
namespaces:
|
namespaces:
|
||||||
- clanguml
|
- clanguml
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ TEST_CASE("Test split", "[unit-test]")
|
|||||||
CHECK(split("ABCD", " ") == C{"ABCD"});
|
CHECK(split("ABCD", " ") == C{"ABCD"});
|
||||||
|
|
||||||
CHECK(split("std::vector::detail", "::") == C{"std", "vector", "detail"});
|
CHECK(split("std::vector::detail", "::") == C{"std", "vector", "detail"});
|
||||||
|
|
||||||
|
CHECK(split("std::vector::detail::", "::") == C{"std", "vector", "detail"});
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Test ns_relative", "[unit-test]")
|
TEST_CASE("Test ns_relative", "[unit-test]")
|
||||||
|
|||||||