Fixed instantiation of function template params with different namespaces
This commit is contained in:
@@ -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)
|
||||
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 "";
|
||||
}
|
||||
|
||||
@@ -231,6 +231,8 @@ public:
|
||||
destination = r.destination;
|
||||
}
|
||||
|
||||
LOG_DBG("========= Destination is: {}", destination);
|
||||
|
||||
std::string puml_relation;
|
||||
if (!r.multiplicity_source.empty())
|
||||
puml_relation += "\"" + r.multiplicity_source + "\" ";
|
||||
@@ -252,6 +254,8 @@ public:
|
||||
|
||||
relstr << '\n';
|
||||
|
||||
LOG_DBG("Adding relation {}", relstr.str());
|
||||
|
||||
all_relations_str << relstr.str();
|
||||
}
|
||||
catch (error::uml_alias_missing &e) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -736,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 ¶m : 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);
|
||||
|
||||
@@ -813,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 ¶m, class_method &m, class_ &c)
|
||||
const cppast::cpp_function_parameter ¶m, class_method &m, class_ &c,
|
||||
const std::set<std::string> &template_parameter_names)
|
||||
{
|
||||
method_parameter mp;
|
||||
mp.name = param.name();
|
||||
@@ -827,7 +833,7 @@ void tu_visitor::process_function_parameter(
|
||||
const auto ¶m_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());
|
||||
@@ -882,35 +888,74 @@ 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)) {
|
||||
class_ tinst = build_template_instantiation(
|
||||
template_instantiation_type);
|
||||
|
||||
class_relationship rr;
|
||||
rr.destination = tinst.usr;
|
||||
rr.type = relationship_t::kDependency;
|
||||
rr.label = "";
|
||||
LOG_DBG(
|
||||
"Adding field dependency relationship {} {} {} : {}",
|
||||
rr.destination,
|
||||
model::class_diagram::to_string(rr.type), c.usr,
|
||||
rr.label);
|
||||
c.add_relationship(std::move(rr));
|
||||
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);
|
||||
|
||||
ctx.d.add_class(std::move(tinst));
|
||||
class_relationship rr;
|
||||
rr.destination = tinst.usr;
|
||||
rr.type = relationship_t::kDependency;
|
||||
rr.label = "";
|
||||
LOG_DBG("Adding field dependency relationship {} {} {} "
|
||||
": {}",
|
||||
rr.destination,
|
||||
model::class_diagram::to_string(rr.type), c.usr,
|
||||
rr.label);
|
||||
c.add_relationship(std::move(rr));
|
||||
|
||||
ctx.d.add_class(std::move(tinst));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1256,10 +1301,11 @@ class_ tu_visitor::build_template_instantiation(
|
||||
full_template_name = cppast::to_string(t);
|
||||
}
|
||||
|
||||
LOG_DBG("BUILDING TEMPLATE INSTANTIATION FOR {}", full_template_name);
|
||||
LOG_DBG("Building template instantiation for {}", full_template_name);
|
||||
|
||||
// Extract namespace from base template name
|
||||
auto ns_toks = clanguml::util::split(
|
||||
std::vector<std::string> ns_toks;
|
||||
ns_toks = clanguml::util::split(
|
||||
full_template_name.substr(0, full_template_name.find('<')), "::");
|
||||
|
||||
std::string ns;
|
||||
@@ -1268,6 +1314,8 @@ 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;
|
||||
@@ -1307,18 +1355,12 @@ class_ tu_visitor::build_template_instantiation(
|
||||
if (parent)
|
||||
nnn = (*parent)->name;
|
||||
|
||||
LOG_ERROR("CALLING BTI WITH PARENT {} ### ({})",
|
||||
ctx.config.should_include(fn) ? tinst.name : nnn, fn);
|
||||
|
||||
class_ nested_tinst =
|
||||
build_template_instantiation(nested_template_parameter,
|
||||
ctx.config.should_include(tinst.usr)
|
||||
? std::make_optional(&tinst)
|
||||
: parent);
|
||||
|
||||
LOG_ERROR("++++ NESTED TEMPLATE FULL NAME IS {} ({})",
|
||||
nested_tinst.usr, fn);
|
||||
|
||||
tinst_dependency.destination =
|
||||
nested_tinst.full_name(ctx.config.using_namespace);
|
||||
|
||||
@@ -1329,16 +1371,15 @@ class_ tu_visitor::build_template_instantiation(
|
||||
}
|
||||
|
||||
if (ctx.config.should_include(tinst.usr)) {
|
||||
LOG_DBG(
|
||||
"++ Creating nested template dependency to template "
|
||||
"instantiation {}, {} -> {}",
|
||||
LOG_DBG("Creating nested template dependency to template "
|
||||
"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 "
|
||||
LOG_DBG("Creating nested template dependency to parent "
|
||||
"template "
|
||||
"instantiation {}, {} -> {}",
|
||||
fn, (*parent)->full_name(ctx.config.using_namespace),
|
||||
@@ -1347,7 +1388,7 @@ class_ tu_visitor::build_template_instantiation(
|
||||
(*parent)->add_relationship(std::move(tinst_dependency));
|
||||
}
|
||||
else {
|
||||
LOG_DBG("-- No nested template dependency to template "
|
||||
LOG_DBG("No nested template dependency to template "
|
||||
"instantiation: {}, {} -> {}",
|
||||
fn, tinst.full_name(ctx.config.using_namespace),
|
||||
tinst_dependency.destination);
|
||||
@@ -1422,6 +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;
|
||||
|
||||
@@ -195,7 +195,8 @@ public:
|
||||
|
||||
void process_function_parameter(const cppast::cpp_function_parameter ¶m,
|
||||
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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user