Merge pull request #8 from bkryza/fix-nested-templates-skipping-excluded-containers

Fix nested templates skipping excluded containers
This commit is contained in:
Bartek Kryza
2021-09-02 23:05:26 +02:00
committed by GitHub
46 changed files with 328 additions and 198 deletions

View File

@@ -10,12 +10,8 @@ jobs:
uses: actions/checkout@v2
with:
submodules: recursive
- name: Install add-apt-repository
run: sudo apt-get install software-properties-common
- name: Add llvm repository
run: sudo add-apt-repository 'deb http://apt.llvm.org/focal/ llvm-toolchain-focal-12 main' && sudo apt update
- name: Install deps
run: sudo apt-get install ccache cmake libyaml-cpp-dev libfmt-dev libspdlog-dev clang-12 libclang-12-dev libclang-cpp12-dev
run: sudo apt install ccache cmake libyaml-cpp-dev libfmt-dev libspdlog-dev clang-12 libclang-12-dev libclang-cpp12-dev
- name: Build and unit test
run: |
make debug

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 15 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: 30 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 18 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: 8.9 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 33 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: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -17,6 +17,36 @@ 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
@@ -101,36 +131,6 @@ 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: 13 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -22,25 +22,21 @@ diagrams:
```
## Source code
File t00019_layer2.h
File t00019.cc
```cpp
#pragma once
#include "t00019_base.h"
#include "t00019_layer1.h"
#include "t00019_layer2.h"
#include "t00019_layer3.h"
#include <memory>
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();
}
class A {
public:
std::unique_ptr<Layer1<Layer2<Layer3<Base>>>> layers;
};
}
}
@@ -98,26 +94,6 @@ 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
@@ -155,6 +131,30 @@ 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: 25 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 20 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: 32 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -41,7 +41,7 @@ struct D {
};
struct R {
A<B<C<D>>> abc;
A<B<std::unique_ptr<C<D>>>> abc;
};
} // namespace t00033

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 25 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

@@ -62,8 +62,9 @@ std::string full_name(const cppast::cpp_type &t,
const cppast::cpp_entity_index &idx, bool inside_class)
{
std::string t_ns;
if (!inside_class)
t_ns = ns(t, idx);
if (!inside_class) {
t_ns = ns(cppast::remove_cv(unreferenced(t)), idx);
}
auto t_name = cppast::to_string(t);
@@ -121,12 +122,13 @@ std::string ns(const cppast::cpp_type &t, const cppast::cpp_entity_index &idx)
if (static_cast<const cppast::cpp_template_instantiation_type &>(t)
.primary_template()
.get(idx)
.size() > 0)
.size() > 0) {
return ns(
static_cast<const cppast::cpp_template_instantiation_type &>(t)
.primary_template()
.get(idx)[0]
.get());
}
else
return "";
}

View File

@@ -206,10 +206,13 @@ public:
std::set<std::string> rendered_relations;
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)))
continue;
LOG_DBG("== Processing relationship {}", to_string(r.type));
std::stringstream relstr;
std::string destination;
try {
@@ -229,6 +232,8 @@ public:
destination = r.destination;
}
LOG_DBG("=== Destination is: {}", destination);
std::string puml_relation;
if (!r.multiplicity_source.empty())
puml_relation += "\"" + r.multiplicity_source + "\" ";
@@ -248,12 +253,18 @@ public:
rendered_relations.emplace(r.label);
}
if (unique_relations.count(relstr.str()) == 0) {
unique_relations.emplace(relstr.str());
relstr << '\n';
LOG_DBG("=== Adding relation {}", relstr.str());
all_relations_str << relstr.str();
}
}
catch (error::uml_alias_missing &e) {
LOG_ERROR("Skipping {} relation from {} to {} due "
LOG_ERROR("=== Skipping {} relation from {} to {} due "
"to: {}",
to_string(r.type), c.full_name(uns), destination, e.what());
}
@@ -291,7 +302,8 @@ public:
ostr << relstr.str();
}
catch (error::uml_alias_missing &e) {
LOG_ERROR("Skipping inheritance relation from {} to {} due "
LOG_ERROR(
"=== Skipping inheritance relation from {} to {} due "
"to: {}",
b.name, c.name, e.what());
}

View File

@@ -334,7 +334,7 @@ struct diagram {
if (!has_class(c.usr))
classes.emplace_back(std::move(c));
else
LOG_DBG("Class {} already in the model", c.name);
LOG_DBG("Class {} ({}) already in the model", c.name, c.usr);
}
void add_enum(enum_ &&e)
@@ -350,6 +350,8 @@ struct diagram {
std::string 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();

View File

@@ -513,36 +513,25 @@ bool tu_visitor::process_field_with_template_instantiation(
const cppast::cpp_member_variable &mv, const cppast::cpp_type &tr,
class_ &c, class_member &m, cppast::cpp_access_specifier_kind as)
{
LOG_DBG("Processing field with template instatiation type {}",
LOG_DBG("Processing field with template instantiation type {}",
cppast::to_string(tr));
bool res = false;
const auto &template_instantiation_type =
static_cast<const cppast::cpp_template_instantiation_type &>(tr);
if (template_instantiation_type.primary_template()
.get(ctx.entity_index)
.size()) {
// Here we need the name of the primary template with full namespace
// prefix to apply config inclusion filters
auto primary_template_name = cx::util::full_name(ctx.namespace_,
template_instantiation_type.primary_template()
.get(ctx.entity_index)[0]
.get());
LOG_DBG("Maybe building instantiation for: {}{}", primary_template_name,
cppast::to_string(tr));
if (ctx.config.should_include(primary_template_name)) {
const auto &unaliased =
static_cast<const cppast::cpp_template_instantiation_type &>(
resolve_alias(template_instantiation_type));
class_ tinst = build_template_instantiation(unaliased);
tinst.usr = tinst.full_name(ctx.config.using_namespace);
// Infer the relationship of this field to the template
// instantiation
class_relationship rr;
rr.destination = tinst.usr;
rr.destination = tinst.full_name(ctx.config.using_namespace);
if (mv.type().kind() == cppast::cpp_type_kind::pointer_t ||
mv.type().kind() == cppast::cpp_type_kind::reference_t)
rr.type = relationship_t::kAssociation;
@@ -563,6 +552,7 @@ bool tu_visitor::process_field_with_template_instantiation(
}
}
if (ctx.config.should_include(tinst.name)) {
LOG_DBG("Adding field instantiation relationship {} {} {} : {}",
rr.destination, model::class_diagram::to_string(rr.type), c.usr,
rr.label);
@@ -571,12 +561,11 @@ bool tu_visitor::process_field_with_template_instantiation(
res = true;
LOG_DBG("Created template instantiation: {}, {}", tinst.name,
tinst.usr);
LOG_DBG(
"Created template instantiation: {}, {}", tinst.name, tinst.usr);
ctx.d.add_class(std::move(tinst));
}
}
return res;
}
@@ -747,8 +736,13 @@ void tu_visitor::process_template_method(
if (m.skip())
return;
std::set<std::string> template_parameter_names;
for (const auto &template_parameter : mf.parameters()) {
template_parameter_names.emplace(template_parameter.name());
}
for (auto &param : mf.function().parameters())
process_function_parameter(param, m, c);
process_function_parameter(param, m, c, template_parameter_names);
LOG_DBG("Adding template method: {}", m.name);
@@ -824,7 +818,8 @@ void tu_visitor::process_destructor(const cppast::cpp_destructor &mf, class_ &c,
}
void tu_visitor::process_function_parameter(
const cppast::cpp_function_parameter &param, class_method &m, class_ &c)
const cppast::cpp_function_parameter &param, class_method &m, class_ &c,
const std::set<std::string> &template_parameter_names)
{
method_parameter mp;
mp.name = param.name();
@@ -838,7 +833,7 @@ void tu_visitor::process_function_parameter(
const auto &param_type =
cppast::remove_cv(cx::util::unreferenced(param.type()));
if (param_type.kind() == cppast::cpp_type_kind::template_instantiation_t) {
// Template instantiation parameters are not fully prefixed
// TODO: Template instantiation parameters are not fully prefixed
// so we have to deduce the correct namespace prefix of the
// template which is being instantiated
mp.type = cppast::to_string(param.type());
@@ -893,20 +888,58 @@ void tu_visitor::process_function_parameter(
if (t.kind() == cppast::cpp_type_kind::template_instantiation_t) {
auto &template_instantiation_type =
static_cast<const cppast::cpp_template_instantiation_type &>(t);
if (template_instantiation_type.primary_template()
.get(ctx.entity_index)
.size()) {
// Here we need the name of the primary template with full
// namespace prefix to apply config inclusion filters
auto primary_template_name = cx::util::full_name(ctx.namespace_,
template_instantiation_type.primary_template()
.get(ctx.entity_index)[0]
.get());
// Now check if the template arguments of this function param
// are a subset of the method template params - if yes this is
// not an instantiation but just a reference to an existing
// template
bool template_is_not_instantiation{false};
for (const auto &template_argument :
template_instantiation_type.arguments().value()) {
const auto template_argument_name =
cppast::to_string(template_argument.type().value());
if (template_parameter_names.count(template_argument_name) >
0) {
template_is_not_instantiation = true;
break;
}
}
LOG_DBG("Maybe building instantiation for: {}",
primary_template_name);
if (ctx.config.should_include(primary_template_name)) {
if (template_is_not_instantiation) {
LOG_DBG("Template is not an instantiation - "
"only adding reference to template {}",
cx::util::full_name(
cppast::remove_cv(t), ctx.entity_index, false));
class_relationship rr;
rr.destination = cx::util::full_name(
cppast::remove_cv(t), ctx.entity_index, false);
rr.type = relationship_t::kDependency;
rr.label = "";
LOG_DBG("Adding field template dependency relationship "
"{} {} {} "
": {}",
rr.destination,
model::class_diagram::to_string(rr.type), c.usr,
rr.label);
c.add_relationship(std::move(rr));
}
else {
// First check if tinst already exists
class_ tinst = build_template_instantiation(
template_instantiation_type);
@@ -914,8 +947,8 @@ void tu_visitor::process_function_parameter(
rr.destination = tinst.usr;
rr.type = relationship_t::kDependency;
rr.label = "";
LOG_DBG(
"Adding field dependency relationship {} {} {} : {}",
LOG_DBG("Adding field dependency relationship {} {} {} "
": {}",
rr.destination,
model::class_diagram::to_string(rr.type), c.usr,
rr.label);
@@ -926,6 +959,7 @@ void tu_visitor::process_function_parameter(
}
}
}
}
m.parameters.emplace_back(std::move(mp));
}
@@ -1045,8 +1079,11 @@ bool tu_visitor::find_relationships(const cppast::cpp_type &t_,
{
bool found{false};
LOG_DBG("Finding relationships for type {}, {}", cppast::to_string(t_),
t_.kind());
const auto fn =
cx::util::full_name(cppast::remove_cv(t_), ctx.entity_index, false);
LOG_DBG("Finding relationships for type {}, {}, {}", cppast::to_string(t_),
t_.kind(), fn);
relationship_t relationship_type = relationship_hint;
const auto &t = cppast::remove_cv(cx::util::unreferenced(t_));
@@ -1088,8 +1125,6 @@ bool tu_visitor::find_relationships(const cppast::cpp_type &t_,
cppast::to_string(t), relationship_t::kAggregation);
// Check if t_ has an alias in the alias index
const auto fn =
cx::util::full_name(cppast::remove_cv(t_), ctx.entity_index, false);
if (ctx.has_type_alias(fn)) {
LOG_DBG("Find relationship in alias of {} | {}", fn,
cppast::to_string(ctx.get_type_alias(fn).get()));
@@ -1132,6 +1167,29 @@ bool tu_visitor::find_relationships(const cppast::cpp_type &t_,
found = find_relationships(args[0u].type().value(), relationships,
relationship_t::kAggregation);
}
else if (ctx.config.should_include(fn)) {
LOG_DBG("User defined template instantiation: {} | {}",
cppast::to_string(t_), cppast::to_string(t_.canonical()));
if (relationship_type != relationship_t::kNone)
relationships.emplace_back(
cppast::to_string(t), relationship_type);
else
relationships.emplace_back(
cppast::to_string(t), relationship_t::kAggregation);
// Check if t_ has an alias in the alias index
if (ctx.has_type_alias(fn)) {
LOG_DBG("Find relationship in alias of {} | {}", fn,
cppast::to_string(ctx.get_type_alias(fn).get()));
found = find_relationships(ctx.get_type_alias(fn).get(),
relationships, relationship_type);
if (found)
return found;
}
return found;
}
else {
for (const auto &arg : args) {
if (arg.type()) {
@@ -1146,23 +1204,33 @@ bool tu_visitor::find_relationships(const cppast::cpp_type &t_,
}
class_ tu_visitor::build_template_instantiation(
const cppast::cpp_template_instantiation_type &t)
const cppast::cpp_template_instantiation_type &t,
std::optional<clanguml::model::class_diagram::class_ *> parent)
{
class_ tinst;
std::string full_template_name;
std::deque<std::tuple<std::string, int, bool>> template_base_params{};
// Determine the full template name
if (t.primary_template().get(ctx.entity_index).size()) {
const auto &primary_template_ref =
static_cast<const cppast::cpp_class_template &>(
t.primary_template().get(ctx.entity_index)[0].get())
.class_();
if (parent)
LOG_DBG("Template parent is {}",
(*parent)->full_name(ctx.config.using_namespace));
else
LOG_DBG("Template parent is empty");
full_template_name =
cx::util::full_name(ctx.namespace_, primary_template_ref);
LOG_DBG("Found template instantiation: {} ({}) ..|> {}, {}",
LOG_DBG("Found template instantiation: "
"type={}, canonical={}, primary_template={}, full_"
"template={}",
cppast::to_string(t), cppast::to_string(t.canonical()),
t.primary_template().name(), full_template_name);
@@ -1233,10 +1301,12 @@ class_ tu_visitor::build_template_instantiation(
full_template_name = cppast::to_string(t);
}
LOG_DBG("Building template instantiation for {}", full_template_name);
// Extract namespace from base template name
auto ns_toks = clanguml::util::split(
tinst.base_template_usr.substr(0, tinst.base_template_usr.find('<')),
"::");
std::vector<std::string> ns_toks;
ns_toks = clanguml::util::split(
full_template_name.substr(0, full_template_name.find('<')), "::");
std::string ns;
if (ns_toks.size() > 1) {
@@ -1244,10 +1314,18 @@ class_ tu_visitor::build_template_instantiation(
"{}::", fmt::join(ns_toks.begin(), ns_toks.end() - 1, "::"));
}
LOG_DBG("Template namespace is {}", ns);
tinst.name = ns + util::split(cppast::to_string(t), "<")[0];
tinst.is_template_instantiation = true;
tinst.usr = tinst.full_name(ctx.config.using_namespace);
if (tinst.usr.substr(0, tinst.usr.find('<')).find("::") ==
std::string::npos) {
tinst.usr = ns + tinst.usr;
}
// Process template argumetns
int arg_index{0};
bool variadic_params{false};
@@ -1258,37 +1336,63 @@ class_ tu_visitor::build_template_instantiation(
ct.type = cppast::to_string(targ.type().value());
LOG_DBG("Template argument is a type {}", ct.type);
auto fn = cx::util::full_name(
cppast::remove_cv(cx::util::unreferenced(targ.type().value())),
ctx.entity_index, false);
if (ctx.config.should_include(fn)) {
if (targ.type().value().kind() ==
cppast::cpp_type_kind::template_instantiation_t) {
class_ nested_tinst =
build_template_instantiation(static_cast<
const cppast::cpp_template_instantiation_type &>(
targ.type().value()));
fn = util::split(fn, "<")[0];
const auto &nested_template_parameter = static_cast<
const cppast::cpp_template_instantiation_type &>(
targ.type().value());
class_relationship tinst_dependency;
tinst_dependency.type = relationship_t::kDependency;
tinst_dependency.label = "";
std::string nnn{"empty"};
if (parent)
nnn = (*parent)->name;
class_ nested_tinst =
build_template_instantiation(nested_template_parameter,
ctx.config.should_include(tinst.usr)
? std::make_optional(&tinst)
: parent);
tinst_dependency.destination =
nested_tinst.full_name(ctx.config.using_namespace);
auto nested_tinst_usr = nested_tinst.usr;
if (ctx.config.should_include(fn)) {
ctx.d.add_class(std::move(nested_tinst));
}
if (ctx.config.should_include(tinst.usr)) {
LOG_DBG("Creating nested template dependency to template "
"instantiation {} -> {}",
tinst.full_name(ctx.config.using_namespace),
"instantiation {}, {} -> {}",
fn, tinst.full_name(ctx.config.using_namespace),
tinst_dependency.destination);
tinst.add_relationship(std::move(tinst_dependency));
}
else if (parent) {
LOG_DBG("Creating nested template dependency to parent "
"template "
"instantiation {}, {} -> {}",
fn, (*parent)->full_name(ctx.config.using_namespace),
tinst_dependency.destination);
ctx.d.add_class(std::move(nested_tinst));
(*parent)->add_relationship(std::move(tinst_dependency));
}
else {
LOG_DBG("No nested template dependency to template "
"instantiation: {}, {} -> {}",
fn, tinst.full_name(ctx.config.using_namespace),
tinst_dependency.destination);
}
}
else if (targ.type().value().kind() ==
cppast::cpp_type_kind::user_defined_t) {
@@ -1301,14 +1405,17 @@ class_ tu_visitor::build_template_instantiation(
cx::util::unreferenced(targ.type().value())),
ctx.entity_index, false);
LOG_DBG(
"Creating nested template dependency to user defined "
LOG_DBG("Creating nested template dependency to user defined "
"type {} -> {}",
tinst.full_name(ctx.config.using_namespace),
tinst_dependency.destination);
if (ctx.config.should_include(fn)) {
tinst.add_relationship(std::move(tinst_dependency));
}
else if (parent) {
(*parent)->add_relationship(std::move(tinst_dependency));
}
}
}
else if (targ.expression()) {
@@ -1356,12 +1463,16 @@ class_ tu_visitor::build_template_instantiation(
tinst.templates.emplace_back(std::move(ct));
}
// Now update usr with the template arguments of the
// instantiations... (there must be a better way)
tinst.usr = tinst.full_name(ctx.config.using_namespace);
if (tinst.usr.substr(0, tinst.usr.find('<')).find("::") ==
std::string::npos) {
tinst.usr = ns + tinst.usr;
}
LOG_DBG("Setting tinst usr to {}", tinst.usr);
// Add instantiation relationship to primary template of this
// instantiation
class_relationship r;

View File

@@ -195,7 +195,8 @@ public:
void process_function_parameter(const cppast::cpp_function_parameter &param,
clanguml::model::class_diagram::class_method &m,
clanguml::model::class_diagram::class_ &c);
clanguml::model::class_diagram::class_ &c,
const std::set<std::string> &template_parameter_names = {});
bool find_relationships(const cppast::cpp_type &t,
std::vector<std::pair<std::string,
@@ -220,7 +221,8 @@ public:
private:
clanguml::model::class_diagram::class_ build_template_instantiation(
const cppast::cpp_template_instantiation_type &t);
const cppast::cpp_template_instantiation_type &t,
std::optional<clanguml::model::class_diagram::class_ *> parent = {});
const cppast::cpp_type &resolve_alias(const cppast::cpp_type &t);

View File

@@ -59,8 +59,8 @@ TEST_CASE("t00013", "[test-case][class]")
REQUIRE_THAT(
puml, IsAggregation(_A("R"), _A("E<std::string>"), "-estring"));
REQUIRE_THAT(puml, IsDependency(_A("R"), _A("ABCD::F<T>")));
REQUIRE_THAT(puml, IsInstantiation(_A("ABCD::F<T>"), _A("ABCD::F<int>")));
REQUIRE_THAT(puml, IsDependency(_A("R"), _A("ABCD::F<int>")));
REQUIRE_THAT(puml, IsInstantiation(_A("ABCD::F<T>"), _A("F<int>")));
REQUIRE_THAT(puml, IsDependency(_A("R"), _A("F<int>")));
save_puml(
"./" + config.output_directory + "/" + diagram->name + ".puml", puml);

View File

@@ -21,7 +21,7 @@ struct D {
};
struct R {
A<B<C<D>>> abc;
A<B<std::unique_ptr<C<D>>>> abc;
};
} // namespace t00033

View File

@@ -48,13 +48,18 @@ TEST_CASE("t00033", "[test-case][class]")
REQUIRE_THAT(puml, IsClass(_A("D")));
REQUIRE_THAT(puml, IsClass(_A("R")));
REQUIRE_THAT(puml, IsDependency(_A("A<B<C<D>>>"), _A("B<C<D>>")));
REQUIRE_THAT(puml, IsDependency(_A("B<C<D>>"), _A("C<D>")));
REQUIRE_THAT(puml,
IsDependency(
_A("A<B<std::unique_ptr<C<D>>>>"), _A("B<std::unique_ptr<C<D>>>")));
REQUIRE_THAT(
puml, IsDependency(_A("B<std::unique_ptr<C<D>>>"), _A("C<D>")));
REQUIRE_THAT(puml, IsDependency(_A("C<D>"), _A("D")));
REQUIRE_THAT(puml, IsInstantiation(_A("C<T>"), _A("C<D>")));
REQUIRE_THAT(puml, IsInstantiation(_A("B<T>"), _A("B<C<D>>")));
REQUIRE_THAT(puml, IsInstantiation(_A("A<T>"), _A("A<B<C<D>>>")));
REQUIRE_THAT(
puml, IsInstantiation(_A("B<T>"), _A("B<std::unique_ptr<C<D>>>")));
REQUIRE_THAT(
puml, IsInstantiation(_A("A<T>"), _A("A<B<std::unique_ptr<C<D>>>>")));
save_puml(
"./" + config.output_directory + "/" + diagram->name + ".puml", puml);