Fixed rendering of member variables with alias to template or alias template (t00014)
This commit is contained in:
@@ -89,7 +89,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);
|
||||||
}
|
}
|
||||||
@@ -277,21 +277,21 @@ void generator::generate(std::ostream &ostr) const
|
|||||||
|
|
||||||
if (m_config.should_include_entities("classes")) {
|
if (m_config.should_include_entities("classes")) {
|
||||||
for (const auto &c : m_model.classes()) {
|
for (const auto &c : m_model.classes()) {
|
||||||
if (!m_config.should_include(c.get().name()))
|
if (!m_config.should_include(c->get_namespace(), c->name()))
|
||||||
continue;
|
continue;
|
||||||
generate_alias(*c, ostr);
|
generate_alias(*c, ostr);
|
||||||
ostr << '\n';
|
ostr << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &e : m_model.enums()) {
|
for (const auto &e : m_model.enums()) {
|
||||||
if (!m_config.should_include(e.get().name()))
|
if (!m_config.should_include(e->get_namespace(), e->name()))
|
||||||
continue;
|
continue;
|
||||||
generate_alias(*e, ostr);
|
generate_alias(*e, ostr);
|
||||||
ostr << '\n';
|
ostr << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &c : m_model.classes()) {
|
for (const auto &c : m_model.classes()) {
|
||||||
if (!m_config.should_include(c.get().name()))
|
if (!m_config.should_include(c->get_namespace(), c->name()))
|
||||||
continue;
|
continue;
|
||||||
generate(*c, ostr);
|
generate(*c, ostr);
|
||||||
ostr << '\n';
|
ostr << '\n';
|
||||||
|
|||||||
@@ -101,10 +101,10 @@ 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());
|
||||||
else
|
else
|
||||||
ostr << name();
|
ostr << name_and_ns();
|
||||||
|
|
||||||
if (!templates_.empty()) {
|
if (!templates_.empty()) {
|
||||||
std::vector<std::string> tnames;
|
std::vector<std::string> tnames;
|
||||||
|
|||||||
@@ -37,9 +37,9 @@ public:
|
|||||||
class_(const std::vector<std::string> &using_namespaces);
|
class_(const std::vector<std::string> &using_namespaces);
|
||||||
|
|
||||||
class_(const class_ &) = delete;
|
class_(const class_ &) = delete;
|
||||||
class_(class_ &&) = default;
|
class_(class_ &&) noexcept = delete;
|
||||||
class_ &operator=(const class_ &) = delete;
|
class_ &operator=(const class_ &) = delete;
|
||||||
class_ &operator=(class_ &&) = default;
|
class_ &operator=(class_ &&) = delete;
|
||||||
|
|
||||||
bool is_struct() const;
|
bool is_struct() const;
|
||||||
void is_struct(bool is_struct);
|
void is_struct(bool is_struct);
|
||||||
|
|||||||
@@ -21,14 +21,17 @@
|
|||||||
#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<type_safe::object_ref<class_>> diagram::classes() const
|
const std::vector<type_safe::object_ref<const class_>> diagram::classes() const
|
||||||
{
|
{
|
||||||
return classes_;
|
return classes_;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<type_safe::object_ref<enum_>> diagram::enums() const
|
const std::vector<type_safe::object_ref<const enum_>> diagram::enums() const
|
||||||
{
|
{
|
||||||
return enums_;
|
return enums_;
|
||||||
}
|
}
|
||||||
@@ -57,16 +60,32 @@ void diagram::add_package(std::unique_ptr<common::model::package> &&p)
|
|||||||
{
|
{
|
||||||
LOG_DBG("Adding namespace package: {}, {}", p->name(), p->full_name(true));
|
LOG_DBG("Adding namespace package: {}, {}", p->name(), p->full_name(true));
|
||||||
|
|
||||||
add_element(p->get_namespace(), std::move(p));
|
auto ns = p->get_namespace();
|
||||||
|
add_element(ns, std::move(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
void diagram::add_class(std::unique_ptr<class_> &&c)
|
void diagram::add_class(std::unique_ptr<class_> &&c)
|
||||||
{
|
{
|
||||||
LOG_DBG("Adding class: {}, {}", c->name(), c->full_name());
|
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)) {
|
if (!has_class(*c)) {
|
||||||
|
LOG_DBG("### ADDED CLASS WITH ADDRESS: {}", (void *)c.get());
|
||||||
classes_.emplace_back(*c);
|
classes_.emplace_back(*c);
|
||||||
add_element(c->get_namespace(), std::move(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(
|
LOG_DBG(
|
||||||
@@ -77,9 +96,12 @@ void diagram::add_enum(std::unique_ptr<enum_> &&e)
|
|||||||
{
|
{
|
||||||
LOG_DBG("Adding enum: {}", e->name());
|
LOG_DBG("Adding enum: {}", e->name());
|
||||||
|
|
||||||
|
assert(!util::contains(e->name(), "::"));
|
||||||
|
|
||||||
if (!has_enum(*e)) {
|
if (!has_enum(*e)) {
|
||||||
enums_.emplace_back(*e);
|
enums_.emplace_back(*e);
|
||||||
add_element(e->get_namespace(), std::move(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());
|
||||||
@@ -90,13 +112,14 @@ 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();
|
||||||
|
if (cc.full_name() == full_name) {
|
||||||
return c->alias();
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -104,4 +127,5 @@ 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));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,9 +40,9 @@ public:
|
|||||||
diagram &operator=(const diagram &) = delete;
|
diagram &operator=(const diagram &) = delete;
|
||||||
diagram &operator=(diagram &&) = default;
|
diagram &operator=(diagram &&) = default;
|
||||||
|
|
||||||
const std::vector<type_safe::object_ref<class_>> classes() const;
|
const std::vector<type_safe::object_ref<const class_>> classes() const;
|
||||||
|
|
||||||
const std::vector<type_safe::object_ref<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;
|
||||||
|
|
||||||
@@ -58,9 +58,11 @@ public:
|
|||||||
|
|
||||||
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<type_safe::object_ref<class_>> classes_;
|
std::vector<type_safe::object_ref<const class_, false>> classes_;
|
||||||
std::vector<type_safe::object_ref<enum_>> enums_;
|
std::vector<type_safe::object_ref<const enum_, false>> enums_;
|
||||||
std::map<std::string, std::unique_ptr<type_alias>> type_aliases_;
|
std::map<std::string, std::unique_ptr<type_alias>> type_aliases_;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,9 +106,9 @@ void translation_unit_visitor::operator()(const cppast::cpp_entity &file)
|
|||||||
|
|
||||||
if (!util::starts_with(usn, package_path)) {
|
if (!util::starts_with(usn, package_path)) {
|
||||||
auto p = std::make_unique<common::model::package>(
|
auto p = std::make_unique<common::model::package>(
|
||||||
ctx.config().using_namespace());
|
util::split(
|
||||||
|
ctx.config().using_namespace()[0], "::"));
|
||||||
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);
|
||||||
@@ -129,8 +129,7 @@ void translation_unit_visitor::operator()(const cppast::cpp_entity &file)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!p->skip()) {
|
if (!p->skip()) {
|
||||||
ctx.diagram().add_element(
|
ctx.diagram().add_package(std::move(p));
|
||||||
package_parent, std::move(p));
|
|
||||||
ctx.set_current_package(
|
ctx.set_current_package(
|
||||||
ctx.diagram()
|
ctx.diagram()
|
||||||
.get_element<common::model::package>(
|
.get_element<common::model::package>(
|
||||||
@@ -190,7 +189,9 @@ void translation_unit_visitor::operator()(const cppast::cpp_entity &file)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.config().should_include(
|
if (ctx.config().should_include(
|
||||||
cx::util::fully_prefixed(ctx.get_namespace(), cls)))
|
ctx.get_namespace(), cls.name()))
|
||||||
|
// cx::util::fully_prefixed(ctx.get_namespace(),
|
||||||
|
// cls)))
|
||||||
process_class_declaration(cls);
|
process_class_declaration(cls);
|
||||||
}
|
}
|
||||||
else if (e.kind() == cppast::cpp_entity_kind::enum_t) {
|
else if (e.kind() == cppast::cpp_entity_kind::enum_t) {
|
||||||
@@ -201,7 +202,9 @@ void translation_unit_visitor::operator()(const cppast::cpp_entity &file)
|
|||||||
auto &enm = static_cast<const cppast::cpp_enum &>(e);
|
auto &enm = static_cast<const cppast::cpp_enum &>(e);
|
||||||
|
|
||||||
if (ctx.config().should_include(
|
if (ctx.config().should_include(
|
||||||
cx::util::fully_prefixed(ctx.get_namespace(), enm)))
|
ctx.get_namespace(), enm.name()))
|
||||||
|
// cx::util::fully_prefixed(ctx.get_namespace(),
|
||||||
|
// enm)))
|
||||||
process_enum_declaration(enm);
|
process_enum_declaration(enm);
|
||||||
}
|
}
|
||||||
else if (e.kind() == cppast::cpp_entity_kind::type_alias_t) {
|
else if (e.kind() == cppast::cpp_entity_kind::type_alias_t) {
|
||||||
@@ -210,7 +213,7 @@ void translation_unit_visitor::operator()(const cppast::cpp_entity &file)
|
|||||||
cppast::to_string(e.kind()));
|
cppast::to_string(e.kind()));
|
||||||
|
|
||||||
auto &ta = static_cast<const cppast::cpp_type_alias &>(e);
|
auto &ta = static_cast<const cppast::cpp_type_alias &>(e);
|
||||||
std::unique_ptr<type_alias> t;
|
auto t = std::make_unique<type_alias>();
|
||||||
t->set_alias(cx::util::full_name(ctx.get_namespace(), ta));
|
t->set_alias(cx::util::full_name(ctx.get_namespace(), ta));
|
||||||
t->set_underlying_type(cx::util::full_name(ta.underlying_type(),
|
t->set_underlying_type(cx::util::full_name(ta.underlying_type(),
|
||||||
ctx.entity_index(), cx::util::is_inside_class(e)));
|
ctx.entity_index(), cx::util::is_inside_class(e)));
|
||||||
@@ -237,9 +240,15 @@ void translation_unit_visitor::operator()(const cppast::cpp_entity &file)
|
|||||||
else {
|
else {
|
||||||
auto tinst = build_template_instantiation(static_cast<
|
auto tinst = build_template_instantiation(static_cast<
|
||||||
const cppast::cpp_template_instantiation_type &>(
|
const cppast::cpp_template_instantiation_type &>(
|
||||||
at.type_alias().underlying_type()));
|
resolve_alias(at.type_alias().underlying_type())));
|
||||||
|
|
||||||
ctx.diagram().add_class(std::move(tinst));
|
ctx.add_type_alias_template(
|
||||||
|
cx::util::full_name(ctx.get_namespace(), at),
|
||||||
|
type_safe::ref(at.type_alias().underlying_type()));
|
||||||
|
|
||||||
|
if (ctx.config().should_include(
|
||||||
|
tinst->get_namespace(), tinst->name()))
|
||||||
|
ctx.diagram().add_class(std::move(tinst));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -254,9 +263,10 @@ void translation_unit_visitor::process_enum_declaration(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto e_ptr = std::make_unique<enum_>(ctx.config().using_namespace());
|
auto e_ptr = std::make_unique<enum_>(
|
||||||
|
util::split(ctx.config().using_namespace()[0], "::"));
|
||||||
auto &e = *e_ptr;
|
auto &e = *e_ptr;
|
||||||
e.set_name(cx::util::full_name(ctx.get_namespace(), enm));
|
e.set_name(enm.name());
|
||||||
e.set_namespace(ctx.get_namespace());
|
e.set_namespace(ctx.get_namespace());
|
||||||
|
|
||||||
if (enm.comment().has_value())
|
if (enm.comment().has_value())
|
||||||
@@ -284,7 +294,9 @@ void translation_unit_visitor::process_enum_declaration(
|
|||||||
e.add_relationship({relationship_t::kContainment,
|
e.add_relationship({relationship_t::kContainment,
|
||||||
cx::util::full_name(ctx.get_namespace(), cur.value())});
|
cx::util::full_name(ctx.get_namespace(), cur.value())});
|
||||||
|
|
||||||
LOG_DBG("Added containment relationship {} +-- {}", e.name());
|
LOG_DBG("Added containment relationship {} +-- {}",
|
||||||
|
cx::util::full_name(ctx.get_namespace(), cur.value()),
|
||||||
|
e.name());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -296,10 +308,12 @@ void translation_unit_visitor::process_class_declaration(
|
|||||||
const cppast::cpp_class &cls,
|
const cppast::cpp_class &cls,
|
||||||
type_safe::optional_ref<const cppast::cpp_template_specialization> tspec)
|
type_safe::optional_ref<const cppast::cpp_template_specialization> tspec)
|
||||||
{
|
{
|
||||||
auto c_ptr = std::make_unique<class_>(ctx.config().using_namespace());
|
auto c_ptr = std::make_unique<class_>(
|
||||||
|
util::split(ctx.config().using_namespace()[0], "::"));
|
||||||
auto &c = *c_ptr;
|
auto &c = *c_ptr;
|
||||||
c.is_struct(cls.class_kind() == cppast::cpp_class_kind::struct_t);
|
c.is_struct(cls.class_kind() == cppast::cpp_class_kind::struct_t);
|
||||||
c.set_name(cx::util::full_name(ctx.get_namespace(), cls));
|
// c.set_name(cx::util::full_name(ctx.get_namespace(), cls));
|
||||||
|
c.set_name(cls.name());
|
||||||
c.set_namespace(ctx.get_namespace());
|
c.set_namespace(ctx.get_namespace());
|
||||||
|
|
||||||
if (cls.comment().has_value())
|
if (cls.comment().has_value())
|
||||||
@@ -576,6 +590,7 @@ void translation_unit_visitor::process_class_declaration(
|
|||||||
static_cast<const char *>(cls.user_data()),
|
static_cast<const char *>(cls.user_data()),
|
||||||
fmt::ptr(reinterpret_cast<const void *>(&cls)));
|
fmt::ptr(reinterpret_cast<const void *>(&cls)));
|
||||||
|
|
||||||
|
assert(c_ptr);
|
||||||
ctx.diagram().add_class(std::move(c_ptr));
|
ctx.diagram().add_class(std::move(c_ptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -588,6 +603,8 @@ bool translation_unit_visitor::process_field_with_template_instantiation(
|
|||||||
|
|
||||||
bool res = false;
|
bool res = false;
|
||||||
|
|
||||||
|
auto tr_declaration = cppast::to_string(tr);
|
||||||
|
|
||||||
const auto &template_instantiation_type =
|
const auto &template_instantiation_type =
|
||||||
static_cast<const cppast::cpp_template_instantiation_type &>(tr);
|
static_cast<const cppast::cpp_template_instantiation_type &>(tr);
|
||||||
|
|
||||||
@@ -595,7 +612,14 @@ bool translation_unit_visitor::process_field_with_template_instantiation(
|
|||||||
static_cast<const cppast::cpp_template_instantiation_type &>(
|
static_cast<const cppast::cpp_template_instantiation_type &>(
|
||||||
resolve_alias(template_instantiation_type));
|
resolve_alias(template_instantiation_type));
|
||||||
|
|
||||||
auto tinst_ptr = build_template_instantiation(unaliased);
|
auto tr_unaliased_declaration = cppast::to_string(unaliased);
|
||||||
|
|
||||||
|
std::unique_ptr<class_> tinst_ptr;
|
||||||
|
if (util::contains(tr_declaration, "<"))
|
||||||
|
tinst_ptr = build_template_instantiation(template_instantiation_type);
|
||||||
|
else
|
||||||
|
tinst_ptr = build_template_instantiation(unaliased);
|
||||||
|
|
||||||
auto &tinst = *tinst_ptr;
|
auto &tinst = *tinst_ptr;
|
||||||
|
|
||||||
// Infer the relationship of this field to the template
|
// Infer the relationship of this field to the template
|
||||||
@@ -604,7 +628,6 @@ bool translation_unit_visitor::process_field_with_template_instantiation(
|
|||||||
if (mv.type().kind() == cppast::cpp_type_kind::pointer_t ||
|
if (mv.type().kind() == cppast::cpp_type_kind::pointer_t ||
|
||||||
mv.type().kind() == cppast::cpp_type_kind::reference_t)
|
mv.type().kind() == cppast::cpp_type_kind::reference_t)
|
||||||
relationship_type = relationship_t::kAssociation;
|
relationship_type = relationship_t::kAssociation;
|
||||||
|
|
||||||
else
|
else
|
||||||
relationship_type = relationship_t::kAggregation;
|
relationship_type = relationship_t::kAggregation;
|
||||||
|
|
||||||
@@ -623,13 +646,19 @@ bool translation_unit_visitor::process_field_with_template_instantiation(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.config().should_include(tinst.name())) {
|
if (ctx.config().should_include(tinst.get_namespace(), tinst.name())) {
|
||||||
LOG_DBG("Adding field instantiation relationship {} {} {} : {}",
|
LOG_DBG("Adding field instantiation relationship {} {} {} : {}",
|
||||||
rr.destination(), clanguml::common::model::to_string(rr.type()),
|
rr.destination(), clanguml::common::model::to_string(rr.type()),
|
||||||
c.full_name(), rr.label());
|
c.full_name(), rr.label());
|
||||||
|
|
||||||
c.add_relationship(std::move(rr));
|
c.add_relationship(std::move(rr));
|
||||||
|
|
||||||
|
if (tr_declaration != tr_unaliased_declaration) {
|
||||||
|
// Add template instantiation/specialization relationship;
|
||||||
|
tinst.add_relationship(
|
||||||
|
{relationship_t::kInstantiation, tr_unaliased_declaration});
|
||||||
|
}
|
||||||
|
|
||||||
res = true;
|
res = true;
|
||||||
|
|
||||||
LOG_DBG("Created template instantiation: {}", tinst.full_name());
|
LOG_DBG("Created template instantiation: {}", tinst.full_name());
|
||||||
@@ -668,11 +697,14 @@ void translation_unit_visitor::process_field(
|
|||||||
else if (tr.kind() == cppast::cpp_type_kind::user_defined_t) {
|
else if (tr.kind() == cppast::cpp_type_kind::user_defined_t) {
|
||||||
LOG_DBG("Processing user defined type field {} {}",
|
LOG_DBG("Processing user defined type field {} {}",
|
||||||
cppast::to_string(tr), mv.name());
|
cppast::to_string(tr), mv.name());
|
||||||
|
if (resolve_alias(tr).kind() ==
|
||||||
|
cppast::cpp_type_kind::template_instantiation_t)
|
||||||
|
template_instantiation_added_as_aggregation =
|
||||||
|
process_field_with_template_instantiation(mv, tr, c, m, as);
|
||||||
}
|
}
|
||||||
else if (tr.kind() == cppast::cpp_type_kind::template_instantiation_t) {
|
else if (tr.kind() == cppast::cpp_type_kind::template_instantiation_t) {
|
||||||
template_instantiation_added_as_aggregation =
|
template_instantiation_added_as_aggregation =
|
||||||
process_field_with_template_instantiation(
|
process_field_with_template_instantiation(mv, tr, c, m, as);
|
||||||
mv, resolve_alias(tr), c, m, as);
|
|
||||||
}
|
}
|
||||||
else if (tr.kind() == cppast::cpp_type_kind::unexposed_t) {
|
else if (tr.kind() == cppast::cpp_type_kind::unexposed_t) {
|
||||||
LOG_DBG(
|
LOG_DBG(
|
||||||
@@ -680,6 +712,8 @@ void translation_unit_visitor::process_field(
|
|||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto tr_declaration = cppast::to_string(tr);
|
||||||
|
|
||||||
if (!m.skip_relationship() &&
|
if (!m.skip_relationship() &&
|
||||||
!template_instantiation_added_as_aggregation &&
|
!template_instantiation_added_as_aggregation &&
|
||||||
(tr.kind() != cppast::cpp_type_kind::builtin_t) &&
|
(tr.kind() != cppast::cpp_type_kind::builtin_t) &&
|
||||||
@@ -929,8 +963,10 @@ void translation_unit_visitor::process_function_parameter(
|
|||||||
find_relationships(cppast::remove_cv(param.type()), relationships,
|
find_relationships(cppast::remove_cv(param.type()), relationships,
|
||||||
relationship_t::kDependency);
|
relationship_t::kDependency);
|
||||||
for (const auto &[type, relationship_type] : relationships) {
|
for (const auto &[type, relationship_type] : relationships) {
|
||||||
if ((relationship_type != relationship_t::kNone) &&
|
|
||||||
(type != c.name())) {
|
if (ctx.config().should_include(cx::util::split_ns(type)) &&
|
||||||
|
(relationship_type != relationship_t::kNone) &&
|
||||||
|
(type != c.name_and_ns())) {
|
||||||
relationship r{relationship_t::kDependency, type};
|
relationship r{relationship_t::kDependency, type};
|
||||||
|
|
||||||
LOG_DBG("Adding field relationship {} {} {} : {}",
|
LOG_DBG("Adding field relationship {} {} {} : {}",
|
||||||
@@ -954,11 +990,11 @@ void translation_unit_visitor::process_function_parameter(
|
|||||||
|
|
||||||
// Here we need the name of the primary template with full
|
// Here we need the name of the primary template with full
|
||||||
// namespace prefix to apply config inclusion filters
|
// namespace prefix to apply config inclusion filters
|
||||||
auto primary_template_name =
|
// auto primary_template_name =
|
||||||
cx::util::full_name(ctx.get_namespace(),
|
// cx::util::full_name(ctx.get_namespace(),
|
||||||
template_instantiation_type.primary_template()
|
// template_instantiation_type.primary_template()
|
||||||
.get(ctx.entity_index())[0]
|
// .get(ctx.entity_index())[0]
|
||||||
.get());
|
// .get());
|
||||||
// Now check if the template arguments of this function param
|
// Now check if the template arguments of this function param
|
||||||
// are a subset of the method template params - if yes this is
|
// are a subset of the method template params - if yes this is
|
||||||
// not an instantiation but just a reference to an existing
|
// not an instantiation but just a reference to an existing
|
||||||
@@ -987,10 +1023,15 @@ void translation_unit_visitor::process_function_parameter(
|
|||||||
// arguments string
|
// arguments string
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_DBG("Maybe building instantiation for: {}",
|
// LOG_DBG("Maybe building instantiation for:
|
||||||
primary_template_name);
|
// {}",
|
||||||
|
// primary_template_name);
|
||||||
|
|
||||||
if (ctx.config().should_include(primary_template_name)) {
|
if (ctx.config().should_include(ctx.get_namespace(),
|
||||||
|
template_instantiation_type.primary_template()
|
||||||
|
.get(ctx.entity_index())[0]
|
||||||
|
.get()
|
||||||
|
.name())) {
|
||||||
|
|
||||||
if (template_is_not_instantiation) {
|
if (template_is_not_instantiation) {
|
||||||
LOG_DBG("Template is not an instantiation - "
|
LOG_DBG("Template is not an instantiation - "
|
||||||
@@ -1073,9 +1114,11 @@ void translation_unit_visitor::process_friend(
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (f.type()) {
|
if (f.type()) {
|
||||||
auto name = cppast::to_string(f.type().value());
|
auto name_with_ns =
|
||||||
|
util::split(cppast::to_string(f.type().value()), "::");
|
||||||
if (!ctx.config().should_include(name))
|
auto name = name_with_ns.back();
|
||||||
|
name_with_ns.pop_back();
|
||||||
|
if (!ctx.config().should_include(name_with_ns, name))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
LOG_DBG("Type friend declaration {}", name);
|
LOG_DBG("Type friend declaration {}", name);
|
||||||
@@ -1113,7 +1156,7 @@ void translation_unit_visitor::process_friend(
|
|||||||
name = cx::util::full_name(ctx.get_namespace(), f.entity().value());
|
name = cx::util::full_name(ctx.get_namespace(), f.entity().value());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ctx.config().should_include(name))
|
if (!ctx.config().should_include(ctx.get_namespace(), name))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
r.set_destination(name);
|
r.set_destination(name);
|
||||||
@@ -1192,7 +1235,7 @@ bool translation_unit_visitor::find_relationships(const cppast::cpp_type &t_,
|
|||||||
else if (t.kind() == cppast::cpp_type_kind::template_instantiation_t) {
|
else if (t.kind() == cppast::cpp_type_kind::template_instantiation_t) {
|
||||||
// class_relationship r;
|
// class_relationship r;
|
||||||
|
|
||||||
auto &tinst =
|
const auto &tinst =
|
||||||
static_cast<const cppast::cpp_template_instantiation_type &>(t);
|
static_cast<const cppast::cpp_template_instantiation_type &>(t);
|
||||||
|
|
||||||
if (!tinst.arguments_exposed()) {
|
if (!tinst.arguments_exposed()) {
|
||||||
@@ -1201,28 +1244,47 @@ bool translation_unit_visitor::find_relationships(const cppast::cpp_type &t_,
|
|||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &args = tinst.arguments().value();
|
assert(tinst.arguments().has_value());
|
||||||
|
assert(tinst.arguments().value().size() > 0u);
|
||||||
|
|
||||||
|
[[maybe_unused]] const auto args_count =
|
||||||
|
tinst.arguments().value().size();
|
||||||
|
|
||||||
|
const auto args = tinst.arguments().value();
|
||||||
|
|
||||||
|
const auto [ns, base_name] = cx::util::split_ns(fn);
|
||||||
|
|
||||||
|
auto ns_and_name = ns;
|
||||||
|
ns_and_name.push_back(base_name);
|
||||||
|
|
||||||
|
auto full_name = fmt::format("{}", fmt::join(ns_and_name, "::"));
|
||||||
|
|
||||||
// Try to match common containers
|
// Try to match common containers
|
||||||
// TODO: Refactor to a separate class with configurable
|
// TODO: Refactor to a separate class with configurable
|
||||||
// container list
|
// container list
|
||||||
if (name.find("std::unique_ptr") == 0) {
|
if (full_name.find("std::unique_ptr") == 0) {
|
||||||
found = find_relationships(args[0u].type().value(), relationships,
|
found = find_relationships(args[0u].type().value(), relationships,
|
||||||
relationship_t::kAggregation);
|
relationship_t::kAggregation);
|
||||||
}
|
}
|
||||||
else if (name.find("std::shared_ptr") == 0) {
|
else if (full_name.find("std::shared_ptr") == 0) {
|
||||||
found = find_relationships(args[0u].type().value(), relationships,
|
found = find_relationships(args[0u].type().value(), relationships,
|
||||||
relationship_t::kAssociation);
|
relationship_t::kAssociation);
|
||||||
}
|
}
|
||||||
else if (name.find("std::weak_ptr") == 0) {
|
else if (full_name.find("std::weak_ptr") == 0) {
|
||||||
found = find_relationships(args[0u].type().value(), relationships,
|
found = find_relationships(args[0u].type().value(), relationships,
|
||||||
relationship_t::kAssociation);
|
relationship_t::kAssociation);
|
||||||
}
|
}
|
||||||
else if (name.find("std::vector") == 0) {
|
else if (full_name.find("std::vector") == 0) {
|
||||||
found = find_relationships(args[0u].type().value(), relationships,
|
assert(args.size() == 1u);
|
||||||
relationship_t::kAggregation);
|
if (args[0u].type().has_value())
|
||||||
|
found = find_relationships(args[0u].type().value(),
|
||||||
|
relationships, relationship_t::kAggregation);
|
||||||
|
else
|
||||||
|
LOG_WARN(
|
||||||
|
"Failed to process template argument of std::vector at: {}",
|
||||||
|
fn);
|
||||||
}
|
}
|
||||||
else if (ctx.config().should_include(fn)) {
|
else if (ctx.config().should_include(ns, 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()));
|
||||||
|
|
||||||
@@ -1245,9 +1307,12 @@ bool translation_unit_visitor::find_relationships(const cppast::cpp_type &t_,
|
|||||||
|
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
// ???
|
||||||
else {
|
else {
|
||||||
for (const auto &arg : args) {
|
for (const auto &arg : args) {
|
||||||
if (arg.type()) {
|
if (arg.type().has_value()) {
|
||||||
|
LOG_DBG("########## PROCESSING PARAMETER TYPE: {}",
|
||||||
|
cppast::to_string(arg.type().value()));
|
||||||
found = find_relationships(
|
found = find_relationships(
|
||||||
arg.type().value(), relationships, relationship_type);
|
arg.type().value(), relationships, relationship_type);
|
||||||
}
|
}
|
||||||
@@ -1262,7 +1327,8 @@ std::unique_ptr<class_> translation_unit_visitor::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)
|
||||||
{
|
{
|
||||||
auto tinst_ptr = std::make_unique<class_>(ctx.config().using_namespace());
|
auto tinst_ptr = std::make_unique<class_>(
|
||||||
|
util::split(ctx.config().using_namespace()[0], "::"));
|
||||||
auto &tinst = *tinst_ptr;
|
auto &tinst = *tinst_ptr;
|
||||||
std::string full_template_name;
|
std::string full_template_name;
|
||||||
|
|
||||||
@@ -1270,6 +1336,8 @@ std::unique_ptr<class_> translation_unit_visitor::build_template_instantiation(
|
|||||||
|
|
||||||
tinst.set_namespace(ctx.get_namespace());
|
tinst.set_namespace(ctx.get_namespace());
|
||||||
|
|
||||||
|
auto tinst_full_name = cppast::to_string(t);
|
||||||
|
|
||||||
if (t.primary_template().get(ctx.entity_index()).size()) {
|
if (t.primary_template().get(ctx.entity_index()).size()) {
|
||||||
const auto &primary_template_ref =
|
const auto &primary_template_ref =
|
||||||
static_cast<const cppast::cpp_class_template &>(
|
static_cast<const cppast::cpp_class_template &>(
|
||||||
@@ -1361,28 +1429,37 @@ std::unique_ptr<class_> translation_unit_visitor::build_template_instantiation(
|
|||||||
LOG_DBG("Building template instantiation for {}", full_template_name);
|
LOG_DBG("Building template instantiation for {}", full_template_name);
|
||||||
|
|
||||||
// Extract namespace from base template name
|
// Extract namespace from base template name
|
||||||
std::vector<std::string> ns_toks;
|
// std::vector<std::string> ns_toks;
|
||||||
ns_toks = clanguml::util::split(
|
// ns_toks = clanguml::util::split(
|
||||||
full_template_name.substr(0, full_template_name.find('<')), "::");
|
// full_template_name.substr(0, full_template_name.find('<')), "::");
|
||||||
|
//
|
||||||
|
// std::string ns;
|
||||||
|
// if (ns_toks.size() > 1) {
|
||||||
|
// ns = fmt::format(
|
||||||
|
// "{}::", fmt::join(ns_toks.begin(), ns_toks.end() - 1, "::"));
|
||||||
|
// }
|
||||||
|
|
||||||
std::string ns;
|
// LOG_DBG("Template namespace is {}", ns);
|
||||||
if (ns_toks.size() > 1) {
|
|
||||||
ns = fmt::format(
|
const auto [ns, name] = cx::util::split_ns(tinst_full_name);
|
||||||
"{}::", fmt::join(ns_toks.begin(), ns_toks.end() - 1, "::"));
|
tinst.set_name(name);
|
||||||
|
if (ns.empty())
|
||||||
|
tinst.set_namespace(ctx.get_namespace());
|
||||||
|
else
|
||||||
|
tinst.set_namespace(ns);
|
||||||
|
|
||||||
|
if (tinst_full_name.find('<') != std::string::npos) {
|
||||||
|
tinst.set_name(tinst_full_name.substr(0, tinst_full_name.find('<')));
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_DBG("Template namespace is {}", ns);
|
|
||||||
|
|
||||||
tinst.set_name(ns + util::split(cppast::to_string(t), "<")[0]);
|
|
||||||
|
|
||||||
tinst.is_template_instantiation(true);
|
tinst.is_template_instantiation(true);
|
||||||
|
|
||||||
if (tinst.full_name().substr(0, tinst.full_name().find('<')).find("::") ==
|
if (tinst.full_name().substr(0, tinst.full_name().find('<')).find("::") ==
|
||||||
std::string::npos) {
|
std::string::npos) {
|
||||||
tinst.set_name(ns + tinst.full_name());
|
tinst.set_name(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process template argumetns
|
// Process template arguments
|
||||||
int arg_index{0};
|
int arg_index{0};
|
||||||
bool variadic_params{false};
|
bool variadic_params{false};
|
||||||
if (t.arguments_exposed()) {
|
if (t.arguments_exposed()) {
|
||||||
@@ -1398,6 +1475,8 @@ std::unique_ptr<class_> translation_unit_visitor::build_template_instantiation(
|
|||||||
cx::util::unreferenced(targ.type().value())),
|
cx::util::unreferenced(targ.type().value())),
|
||||||
ctx.entity_index(), false);
|
ctx.entity_index(), false);
|
||||||
|
|
||||||
|
auto [fn_ns, fn_name] = cx::util::split_ns(fn);
|
||||||
|
|
||||||
if (targ.type().value().kind() ==
|
if (targ.type().value().kind() ==
|
||||||
cppast::cpp_type_kind::template_instantiation_t) {
|
cppast::cpp_type_kind::template_instantiation_t) {
|
||||||
|
|
||||||
@@ -1409,9 +1488,11 @@ std::unique_ptr<class_> translation_unit_visitor::build_template_instantiation(
|
|||||||
if (parent)
|
if (parent)
|
||||||
nnn = (*parent)->name();
|
nnn = (*parent)->name();
|
||||||
|
|
||||||
|
auto [tinst_ns, tinst_name] =
|
||||||
|
cx::util::split_ns(tinst.full_name(false));
|
||||||
auto nested_tinst =
|
auto nested_tinst =
|
||||||
build_template_instantiation(nested_template_parameter,
|
build_template_instantiation(nested_template_parameter,
|
||||||
ctx.config().should_include(tinst.full_name(false))
|
ctx.config().should_include(tinst_ns, tinst_name)
|
||||||
? std::make_optional(&tinst)
|
? std::make_optional(&tinst)
|
||||||
: parent);
|
: parent);
|
||||||
|
|
||||||
@@ -1420,11 +1501,13 @@ std::unique_ptr<class_> translation_unit_visitor::build_template_instantiation(
|
|||||||
|
|
||||||
auto nested_tinst_full_name = nested_tinst->full_name();
|
auto nested_tinst_full_name = nested_tinst->full_name();
|
||||||
|
|
||||||
if (ctx.config().should_include(fn)) {
|
if (ctx.config().should_include(fn_ns, fn_name)) {
|
||||||
ctx.diagram().add_class(std::move(nested_tinst));
|
ctx.diagram().add_class(std::move(nested_tinst));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.config().should_include(tinst.full_name(false))) {
|
if (ctx.config().should_include(tinst_ns, tinst_name) &&
|
||||||
|
ctx.config().should_include(cx::util::split_ns(
|
||||||
|
tinst_dependency.destination()))) {
|
||||||
LOG_DBG(
|
LOG_DBG(
|
||||||
"Creating nested template dependency to template "
|
"Creating nested template dependency to template "
|
||||||
"instantiation {}, {} -> {}",
|
"instantiation {}, {} -> {}",
|
||||||
@@ -1463,7 +1546,7 @@ std::unique_ptr<class_> translation_unit_visitor::build_template_instantiation(
|
|||||||
"type {} -> {}",
|
"type {} -> {}",
|
||||||
tinst.full_name(), tinst_dependency.destination());
|
tinst.full_name(), tinst_dependency.destination());
|
||||||
|
|
||||||
if (ctx.config().should_include(fn)) {
|
if (ctx.config().should_include(fn_ns, fn_name)) {
|
||||||
tinst.add_relationship(std::move(tinst_dependency));
|
tinst.add_relationship(std::move(tinst_dependency));
|
||||||
}
|
}
|
||||||
else if (parent) {
|
else if (parent) {
|
||||||
@@ -1547,12 +1630,32 @@ const cppast::cpp_type &translation_unit_visitor::resolve_alias(
|
|||||||
const cppast::cpp_type &type)
|
const cppast::cpp_type &type)
|
||||||
{
|
{
|
||||||
const auto &raw_type = cppast::remove_cv(cx::util::unreferenced(type));
|
const auto &raw_type = cppast::remove_cv(cx::util::unreferenced(type));
|
||||||
const auto type_full_name =
|
auto type_full_name =
|
||||||
cx::util::full_name(raw_type, ctx.entity_index(), false);
|
cx::util::full_name(raw_type, ctx.entity_index(), false);
|
||||||
if (ctx.has_type_alias(type_full_name)) {
|
|
||||||
|
if (util::contains(type_full_name, "<"))
|
||||||
|
type_full_name = util::split(type_full_name, "<")[0];
|
||||||
|
|
||||||
|
if (ctx.has_type_alias_template(type_full_name)) {
|
||||||
|
return ctx.get_type_alias(type_full_name).get();
|
||||||
|
}
|
||||||
|
else if (ctx.has_type_alias(type_full_name)) {
|
||||||
return ctx.get_type_alias_final(raw_type).get();
|
return ctx.get_type_alias_final(raw_type).get();
|
||||||
}
|
}
|
||||||
|
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const cppast::cpp_type &translation_unit_visitor::resolve_alias_template(
|
||||||
|
const cppast::cpp_type &type)
|
||||||
|
{
|
||||||
|
const auto &raw_type = cppast::remove_cv(cx::util::unreferenced(type));
|
||||||
|
const auto type_full_name =
|
||||||
|
cx::util::full_name(raw_type, ctx.entity_index(), false);
|
||||||
|
if (ctx.has_type_alias_template(type_full_name)) {
|
||||||
|
return ctx.get_type_alias_template(type_full_name).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
return type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -130,6 +130,8 @@ private:
|
|||||||
* If t does not represent an alias, returns t.
|
* If t does not represent an alias, returns t.
|
||||||
*/
|
*/
|
||||||
const cppast::cpp_type &resolve_alias(const cppast::cpp_type &t);
|
const cppast::cpp_type &resolve_alias(const cppast::cpp_type &t);
|
||||||
|
const cppast::cpp_type &resolve_alias_template(
|
||||||
|
const cppast::cpp_type &type);
|
||||||
|
|
||||||
// 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,4 +85,14 @@ bool operator==(const element &l, const element &r)
|
|||||||
{
|
{
|
||||||
return l.full_name(false) == r.full_name(false);
|
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>
|
||||||
|
|
||||||
@@ -38,10 +40,24 @@ public:
|
|||||||
|
|
||||||
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);
|
||||||
@@ -58,6 +74,8 @@ public:
|
|||||||
|
|
||||||
friend bool operator==(const element &l, const element &r);
|
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>
|
||||||
|
|
||||||
@@ -55,7 +56,7 @@ public:
|
|||||||
{
|
{
|
||||||
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()) {
|
||||||
@@ -68,9 +69,11 @@ public:
|
|||||||
if (parent && dynamic_cast<nested_trait<T> *>(&parent.value()))
|
if (parent && dynamic_cast<nested_trait<T> *>(&parent.value()))
|
||||||
dynamic_cast<nested_trait<T> &>(parent.value())
|
dynamic_cast<nested_trait<T> &>(parent.value())
|
||||||
.template add_element<V>(std::move(p));
|
.template add_element<V>(std::move(p));
|
||||||
else
|
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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename V = T>
|
template <typename V = T>
|
||||||
@@ -105,7 +108,7 @@ public:
|
|||||||
[&](const auto &p) { return name == p->name(); });
|
[&](const auto &p) { return name == p->name(); });
|
||||||
|
|
||||||
if (it == elements_.end())
|
if (it == elements_.end())
|
||||||
return type_safe::optional_ref<V>{};
|
return type_safe::optional_ref<V>{type_safe::nullopt};
|
||||||
|
|
||||||
assert(it->get() != nullptr);
|
assert(it->get() != nullptr);
|
||||||
|
|
||||||
@@ -113,7 +116,7 @@ public:
|
|||||||
return type_safe::optional_ref<V>{
|
return type_safe::optional_ref<V>{
|
||||||
type_safe::ref<V>(dynamic_cast<V &>(*it->get()))};
|
type_safe::ref<V>(dynamic_cast<V &>(*it->get()))};
|
||||||
|
|
||||||
return type_safe::optional_ref<V>{};
|
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
|
||||||
@@ -132,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_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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_);
|
||||||
|
|||||||
@@ -87,8 +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{
|
option<bool> generate_packages{"generate_packages", false};
|
||||||
"generate_packages", false};
|
|
||||||
|
|
||||||
void inherit(const inheritable_diagram_options &parent);
|
void inherit(const inheritable_diagram_options &parent);
|
||||||
};
|
};
|
||||||
@@ -104,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 {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -353,6 +353,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_));
|
||||||
@@ -465,7 +466,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()));
|
||||||
|
|
||||||
|
|||||||
@@ -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,22 +44,21 @@ std::vector<std::string> split(std::string str, std::string delimiter)
|
|||||||
{
|
{
|
||||||
std::vector<std::string> result;
|
std::vector<std::string> result;
|
||||||
|
|
||||||
while (str.size()) {
|
if (!contains(str, delimiter))
|
||||||
int index = str.find(delimiter);
|
|
||||||
if (index != std::string::npos) {
|
|
||||||
result.push_back(str.substr(0, index));
|
|
||||||
str = str.substr(index + delimiter.size());
|
|
||||||
if (str.size() == 0)
|
|
||||||
result.push_back(str);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
result.push_back(str);
|
|
||||||
str = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result.empty())
|
|
||||||
result.push_back(str);
|
result.push_back(str);
|
||||||
|
else
|
||||||
|
while (str.size()) {
|
||||||
|
int index = str.find(delimiter);
|
||||||
|
if (index != std::string::npos) {
|
||||||
|
result.push_back(str.substr(0, index));
|
||||||
|
str = str.substr(index + delimiter.size());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!str.empty())
|
||||||
|
result.push_back(str);
|
||||||
|
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(
|
||||||
|
|||||||
@@ -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]")
|
||||||
|
|||||||
Reference in New Issue
Block a user