Fixed rendering of member variables with alias to template or alias template (t00014)

This commit is contained in:
Bartek Kryza
2022-02-22 13:02:04 +01:00
parent e8ebaad6c6
commit 1a5a7aefcb
21 changed files with 355 additions and 109 deletions

View File

@@ -89,7 +89,7 @@ void generator::generate(const class_ &c, std::ostream &ostr) const
return mp.to_string(m_config.using_namespace());
});
auto args_string = fmt::format("{}", fmt::join(params, ", "));
if (m_config.generate_method_arguments() !=
if (m_config.generate_method_arguments() ==
config::method_arguments::abbreviated) {
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")) {
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;
generate_alias(*c, ostr);
ostr << '\n';
}
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;
generate_alias(*e, ostr);
ostr << '\n';
}
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;
generate(*c, ostr);
ostr << '\n';

View File

@@ -101,10 +101,10 @@ std::string class_::full_name(bool relative) const
using namespace clanguml::util;
std::ostringstream ostr;
if (relative)
if (relative && starts_with(get_namespace(), using_namespaces()))
ostr << ns_relative(using_namespaces(), name());
else
ostr << name();
ostr << name_and_ns();
if (!templates_.empty()) {
std::vector<std::string> tnames;

View File

@@ -37,9 +37,9 @@ public:
class_(const std::vector<std::string> &using_namespaces);
class_(const class_ &) = delete;
class_(class_ &&) = default;
class_(class_ &&) noexcept = delete;
class_ &operator=(const class_ &) = delete;
class_ &operator=(class_ &&) = default;
class_ &operator=(class_ &&) = delete;
bool is_struct() const;
void is_struct(bool is_struct);

View File

@@ -21,14 +21,17 @@
#include "util/error.h"
#include "util/util.h"
#include <cassert>
#include <iostream>
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_;
}
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_;
}
@@ -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));
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)
{
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)) {
LOG_DBG("### ADDED CLASS WITH ADDRESS: {}", (void *)c.get());
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
LOG_DBG(
@@ -77,9 +96,12 @@ void diagram::add_enum(std::unique_ptr<enum_> &&e)
{
LOG_DBG("Adding enum: {}", e->name());
assert(!util::contains(e->name(), "::"));
if (!has_enum(*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
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);
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();
}
}
for (const auto &e : enums_) {
if (e->full_name() == full_name) {
if (e.get().full_name() == full_name) {
return e->alias();
}
}
@@ -104,4 +127,5 @@ std::string diagram::to_alias(const std::string &full_name) const
throw error::uml_alias_missing(
fmt::format("Missing alias for {}", full_name));
}
}

View File

@@ -40,9 +40,9 @@ public:
diagram &operator=(const diagram &) = delete;
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;
@@ -58,9 +58,11 @@ public:
std::string to_alias(const std::string &full_name) const;
friend void print_diagram_tree(const diagram &d, const int level);
private:
std::vector<type_safe::object_ref<class_>> classes_;
std::vector<type_safe::object_ref<enum_>> enums_;
std::vector<type_safe::object_ref<const class_, false>> classes_;
std::vector<type_safe::object_ref<const enum_, false>> enums_;
std::map<std::string, std::unique_ptr<type_alias>> type_aliases_;
};
}

View File

@@ -106,9 +106,9 @@ void translation_unit_visitor::operator()(const cppast::cpp_entity &file)
if (!util::starts_with(usn, package_path)) {
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_parent, usn);
p->set_name(e.name());
p->set_namespace(package_parent);
@@ -129,8 +129,7 @@ void translation_unit_visitor::operator()(const cppast::cpp_entity &file)
}
if (!p->skip()) {
ctx.diagram().add_element(
package_parent, std::move(p));
ctx.diagram().add_package(std::move(p));
ctx.set_current_package(
ctx.diagram()
.get_element<common::model::package>(
@@ -190,7 +189,9 @@ void translation_unit_visitor::operator()(const cppast::cpp_entity &file)
}
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);
}
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);
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);
}
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()));
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_underlying_type(cx::util::full_name(ta.underlying_type(),
ctx.entity_index(), cx::util::is_inside_class(e)));
@@ -237,9 +240,15 @@ void translation_unit_visitor::operator()(const cppast::cpp_entity &file)
else {
auto tinst = build_template_instantiation(static_cast<
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;
}
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;
e.set_name(cx::util::full_name(ctx.get_namespace(), enm));
e.set_name(enm.name());
e.set_namespace(ctx.get_namespace());
if (enm.comment().has_value())
@@ -284,7 +294,9 @@ void translation_unit_visitor::process_enum_declaration(
e.add_relationship({relationship_t::kContainment,
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;
}
}
@@ -296,10 +308,12 @@ void translation_unit_visitor::process_class_declaration(
const cppast::cpp_class &cls,
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;
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());
if (cls.comment().has_value())
@@ -576,6 +590,7 @@ void translation_unit_visitor::process_class_declaration(
static_cast<const char *>(cls.user_data()),
fmt::ptr(reinterpret_cast<const void *>(&cls)));
assert(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;
auto tr_declaration = cppast::to_string(tr);
const auto &template_instantiation_type =
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 &>(
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;
// 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 ||
mv.type().kind() == cppast::cpp_type_kind::reference_t)
relationship_type = relationship_t::kAssociation;
else
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 {} {} {} : {}",
rr.destination(), clanguml::common::model::to_string(rr.type()),
c.full_name(), rr.label());
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;
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) {
LOG_DBG("Processing user defined type field {} {}",
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) {
template_instantiation_added_as_aggregation =
process_field_with_template_instantiation(
mv, resolve_alias(tr), c, m, as);
process_field_with_template_instantiation(mv, tr, c, m, as);
}
else if (tr.kind() == cppast::cpp_type_kind::unexposed_t) {
LOG_DBG(
@@ -680,6 +712,8 @@ void translation_unit_visitor::process_field(
// TODO
}
auto tr_declaration = cppast::to_string(tr);
if (!m.skip_relationship() &&
!template_instantiation_added_as_aggregation &&
(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,
relationship_t::kDependency);
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};
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
// namespace prefix to apply config inclusion filters
auto primary_template_name =
cx::util::full_name(ctx.get_namespace(),
template_instantiation_type.primary_template()
.get(ctx.entity_index())[0]
.get());
// auto primary_template_name =
// cx::util::full_name(ctx.get_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
@@ -987,10 +1023,15 @@ void translation_unit_visitor::process_function_parameter(
// arguments string
}
LOG_DBG("Maybe building instantiation for: {}",
primary_template_name);
// LOG_DBG("Maybe building instantiation for:
// {}",
// 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) {
LOG_DBG("Template is not an instantiation - "
@@ -1073,9 +1114,11 @@ void translation_unit_visitor::process_friend(
return;
if (f.type()) {
auto name = cppast::to_string(f.type().value());
if (!ctx.config().should_include(name))
auto name_with_ns =
util::split(cppast::to_string(f.type().value()), "::");
auto name = name_with_ns.back();
name_with_ns.pop_back();
if (!ctx.config().should_include(name_with_ns, name))
return;
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());
}
if (!ctx.config().should_include(name))
if (!ctx.config().should_include(ctx.get_namespace(), name))
return;
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) {
// class_relationship r;
auto &tinst =
const auto &tinst =
static_cast<const cppast::cpp_template_instantiation_type &>(t);
if (!tinst.arguments_exposed()) {
@@ -1201,28 +1244,47 @@ bool translation_unit_visitor::find_relationships(const cppast::cpp_type &t_,
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
// TODO: Refactor to a separate class with configurable
// 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,
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,
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,
relationship_t::kAssociation);
}
else if (name.find("std::vector") == 0) {
found = find_relationships(args[0u].type().value(), relationships,
relationship_t::kAggregation);
else if (full_name.find("std::vector") == 0) {
assert(args.size() == 1u);
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: {} | {}",
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;
}
// ???
else {
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(
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,
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;
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());
auto tinst_full_name = cppast::to_string(t);
if (t.primary_template().get(ctx.entity_index()).size()) {
const auto &primary_template_ref =
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);
// Extract namespace from base template name
std::vector<std::string> ns_toks;
ns_toks = clanguml::util::split(
full_template_name.substr(0, full_template_name.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) {
// ns = fmt::format(
// "{}::", fmt::join(ns_toks.begin(), ns_toks.end() - 1, "::"));
// }
std::string ns;
if (ns_toks.size() > 1) {
ns = fmt::format(
"{}::", fmt::join(ns_toks.begin(), ns_toks.end() - 1, "::"));
// LOG_DBG("Template namespace is {}", ns);
const auto [ns, name] = cx::util::split_ns(tinst_full_name);
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);
if (tinst.full_name().substr(0, tinst.full_name().find('<')).find("::") ==
std::string::npos) {
tinst.set_name(ns + tinst.full_name());
tinst.set_name(name);
}
// Process template argumetns
// Process template arguments
int arg_index{0};
bool variadic_params{false};
if (t.arguments_exposed()) {
@@ -1398,6 +1475,8 @@ std::unique_ptr<class_> translation_unit_visitor::build_template_instantiation(
cx::util::unreferenced(targ.type().value())),
ctx.entity_index(), false);
auto [fn_ns, fn_name] = cx::util::split_ns(fn);
if (targ.type().value().kind() ==
cppast::cpp_type_kind::template_instantiation_t) {
@@ -1409,9 +1488,11 @@ std::unique_ptr<class_> translation_unit_visitor::build_template_instantiation(
if (parent)
nnn = (*parent)->name();
auto [tinst_ns, tinst_name] =
cx::util::split_ns(tinst.full_name(false));
auto nested_tinst =
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)
: parent);
@@ -1420,11 +1501,13 @@ std::unique_ptr<class_> translation_unit_visitor::build_template_instantiation(
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));
}
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(
"Creating nested template dependency to template "
"instantiation {}, {} -> {}",
@@ -1463,7 +1546,7 @@ std::unique_ptr<class_> translation_unit_visitor::build_template_instantiation(
"type {} -> {}",
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));
}
else if (parent) {
@@ -1547,12 +1630,32 @@ const cppast::cpp_type &translation_unit_visitor::resolve_alias(
const cppast::cpp_type &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);
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 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;
}
}

View File

@@ -130,6 +130,8 @@ private:
* 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_template(
const cppast::cpp_type &type);
// ctx allows to track current visitor context, e.g. current namespace
translation_unit_context ctx;