Fixed template_builder handling of nested template specializations
This commit is contained in:
@@ -22,6 +22,8 @@ diagrams:
|
|||||||
include!: uml/sequence_diagram_visitor_sequence_diagram.yml
|
include!: uml/sequence_diagram_visitor_sequence_diagram.yml
|
||||||
class_diagram_generator_sequence:
|
class_diagram_generator_sequence:
|
||||||
include!: uml/class_diagram_generator_sequence_diagram.yml
|
include!: uml/class_diagram_generator_sequence_diagram.yml
|
||||||
|
template_builder_sequence:
|
||||||
|
include!: uml/template_builder_sequence_diagram.yml
|
||||||
package_model_class:
|
package_model_class:
|
||||||
include!: uml/package_model_class_diagram.yml
|
include!: uml/package_model_class_diagram.yml
|
||||||
include_graph:
|
include_graph:
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -30,6 +30,10 @@ using common::model::namespace_;
|
|||||||
using common::model::relationship_t;
|
using common::model::relationship_t;
|
||||||
using common::model::template_parameter;
|
using common::model::template_parameter;
|
||||||
|
|
||||||
|
using found_relationships_t =
|
||||||
|
std::vector<std::pair<clanguml::common::model::diagram_element::id_t,
|
||||||
|
common::model::relationship_t>>;
|
||||||
|
|
||||||
class template_builder {
|
class template_builder {
|
||||||
public:
|
public:
|
||||||
template_builder(class_diagram::model::diagram &d,
|
template_builder(class_diagram::model::diagram &d,
|
||||||
@@ -47,14 +51,13 @@ public:
|
|||||||
template_parameter &ct, const std::string &full_name) const;
|
template_parameter &ct, const std::string &full_name) const;
|
||||||
|
|
||||||
std::unique_ptr<clanguml::class_diagram::model::class_> build(
|
std::unique_ptr<clanguml::class_diagram::model::class_> build(
|
||||||
const clang::Decl *cls,
|
const clang::NamedDecl *cls,
|
||||||
const clang::TemplateSpecializationType &template_type_decl,
|
const clang::TemplateSpecializationType &template_type_decl,
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> parent = {});
|
std::optional<clanguml::class_diagram::model::class_ *> parent = {});
|
||||||
|
|
||||||
std::unique_ptr<clanguml::class_diagram::model::class_>
|
std::unique_ptr<clanguml::class_diagram::model::class_>
|
||||||
build_from_class_template_specialization(
|
build_from_class_template_specialization(
|
||||||
const clang::ClassTemplateSpecializationDecl &template_specialization,
|
const clang::ClassTemplateSpecializationDecl &template_specialization,
|
||||||
const clang::RecordType &record_type,
|
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> parent = {});
|
std::optional<clanguml::class_diagram::model::class_ *> parent = {});
|
||||||
|
|
||||||
bool add_base_classes(clanguml::class_diagram::model::class_ &tinst,
|
bool add_base_classes(clanguml::class_diagram::model::class_ &tinst,
|
||||||
@@ -64,23 +67,20 @@ public:
|
|||||||
|
|
||||||
void process_template_arguments(
|
void process_template_arguments(
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
||||||
const clang::Decl *cls,
|
const clang::NamedDecl *cls,
|
||||||
std::deque<std::tuple<std::string, int, bool>> &template_base_params,
|
std::deque<std::tuple<std::string, int, bool>> &template_base_params,
|
||||||
const clang::ArrayRef<clang::TemplateArgument> &template_args,
|
const clang::ArrayRef<clang::TemplateArgument> &template_args,
|
||||||
model::class_ &template_instantiation,
|
model::class_ &template_instantiation,
|
||||||
const std::string &full_template_specialization_name,
|
|
||||||
const clang::TemplateDecl *template_decl);
|
const clang::TemplateDecl *template_decl);
|
||||||
|
|
||||||
void argument_process_dispatch(
|
void argument_process_dispatch(
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
||||||
const clang::Decl *cls, class_ &template_instantiation,
|
const clang::NamedDecl *cls, class_ &template_instantiation,
|
||||||
const std::string &full_template_specialization_name,
|
|
||||||
const clang::TemplateDecl *template_decl,
|
const clang::TemplateDecl *template_decl,
|
||||||
const clang::TemplateArgument &arg,
|
const clang::TemplateArgument &arg, size_t argument_index,
|
||||||
std::vector<template_parameter> &argument);
|
std::vector<template_parameter> &argument);
|
||||||
|
|
||||||
void process_tag_argument(model::class_ &template_instantiation,
|
void process_tag_argument(model::class_ &template_instantiation,
|
||||||
const std::string &full_template_specialization_name,
|
|
||||||
const clang::TemplateDecl *template_decl,
|
const clang::TemplateDecl *template_decl,
|
||||||
const clang::TemplateArgument &arg,
|
const clang::TemplateArgument &arg,
|
||||||
common::model::template_parameter &argument);
|
common::model::template_parameter &argument);
|
||||||
@@ -99,23 +99,27 @@ public:
|
|||||||
|
|
||||||
std::vector<template_parameter> process_pack_argument(
|
std::vector<template_parameter> process_pack_argument(
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
||||||
const clang::Decl *cls, class_ &template_instantiation,
|
const clang::NamedDecl *cls, class_ &template_instantiation,
|
||||||
const std::string &full_template_specialization_name,
|
|
||||||
const clang::TemplateDecl *template_decl,
|
const clang::TemplateDecl *template_decl,
|
||||||
const clang::TemplateArgument &arg,
|
const clang::TemplateArgument &arg, size_t argument_index,
|
||||||
std::vector<template_parameter> &argument);
|
std::vector<template_parameter> &argument);
|
||||||
|
|
||||||
template_parameter process_type_argument(
|
template_parameter process_type_argument(
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
||||||
const clang::Decl *cls,
|
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
|
||||||
const std::string &full_template_specialization_name,
|
|
||||||
const clang::TemplateDecl *template_decl,
|
|
||||||
const clang::TemplateArgument &arg,
|
const clang::TemplateArgument &arg,
|
||||||
model::class_ &template_instantiation);
|
model::class_ &template_instantiation, size_t argument_index);
|
||||||
|
|
||||||
common::model::template_parameter process_template_argument(
|
common::model::template_parameter process_template_argument(
|
||||||
const clang::TemplateArgument &arg);
|
const clang::TemplateArgument &arg);
|
||||||
|
|
||||||
|
void process_unexposed_template_specialization_parameters(
|
||||||
|
const std::string &type_name, template_parameter &tp, class_ &c);
|
||||||
|
|
||||||
|
bool find_relationships_in_unexposed_template_params(
|
||||||
|
const template_parameter &ct,
|
||||||
|
class_diagram::visitor::found_relationships_t &relationships);
|
||||||
|
|
||||||
std::optional<template_parameter>
|
std::optional<template_parameter>
|
||||||
get_template_argument_from_type_parameter_string(
|
get_template_argument_from_type_parameter_string(
|
||||||
const clang::Decl *decl, const std::string &return_type_name) const;
|
const clang::Decl *decl, const std::string &return_type_name) const;
|
||||||
@@ -125,6 +129,8 @@ public:
|
|||||||
clang::SourceManager &source_manager() const;
|
clang::SourceManager &source_manager() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void ensure_lambda_type_is_relative(std::string ¶meter_type) const;
|
||||||
|
|
||||||
// Reference to the output diagram model
|
// Reference to the output diagram model
|
||||||
clanguml::class_diagram::model::diagram &diagram_;
|
clanguml::class_diagram::model::diagram &diagram_;
|
||||||
|
|
||||||
|
|||||||
@@ -1715,7 +1715,8 @@ std::unique_ptr<class_>
|
|||||||
translation_unit_visitor::process_template_specialization(
|
translation_unit_visitor::process_template_specialization(
|
||||||
clang::ClassTemplateSpecializationDecl *cls)
|
clang::ClassTemplateSpecializationDecl *cls)
|
||||||
{
|
{
|
||||||
auto c_ptr{std::make_unique<class_>(config_.using_namespace())};
|
auto c_ptr = tbuilder().build_from_class_template_specialization(*cls);
|
||||||
|
|
||||||
auto &template_instantiation = *c_ptr;
|
auto &template_instantiation = *c_ptr;
|
||||||
template_instantiation.is_template(true);
|
template_instantiation.is_template(true);
|
||||||
|
|
||||||
@@ -1745,374 +1746,11 @@ translation_unit_visitor::process_template_specialization(
|
|||||||
if (template_instantiation.skip())
|
if (template_instantiation.skip())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
const auto template_args_count = cls->getTemplateArgs().size();
|
|
||||||
for (auto arg_it = 0U; arg_it < template_args_count; arg_it++) {
|
|
||||||
const auto arg = cls->getTemplateArgs().get(arg_it);
|
|
||||||
process_template_specialization_argument(
|
|
||||||
cls, template_instantiation, arg, arg_it);
|
|
||||||
}
|
|
||||||
|
|
||||||
template_instantiation.set_id(
|
|
||||||
common::to_id(template_instantiation.full_name(false)));
|
|
||||||
|
|
||||||
id_mapper().add(cls->getID(), template_instantiation.id());
|
id_mapper().add(cls->getID(), template_instantiation.id());
|
||||||
|
|
||||||
return c_ptr;
|
return c_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void translation_unit_visitor::process_template_specialization_argument(
|
|
||||||
const clang::ClassTemplateSpecializationDecl *cls,
|
|
||||||
class_ &template_instantiation, const clang::TemplateArgument &arg,
|
|
||||||
size_t argument_index, bool /*in_parameter_pack*/)
|
|
||||||
{
|
|
||||||
const auto argument_kind = arg.getKind();
|
|
||||||
|
|
||||||
if (argument_kind == clang::TemplateArgument::Type) {
|
|
||||||
std::optional<template_parameter> argument;
|
|
||||||
|
|
||||||
// If this is a nested template type - add nested templates as
|
|
||||||
// template arguments
|
|
||||||
if (const auto *function_type =
|
|
||||||
arg.getAsType()->getAs<clang::FunctionProtoType>();
|
|
||||||
function_type != nullptr) {
|
|
||||||
|
|
||||||
auto a = template_parameter::make_template_type({});
|
|
||||||
|
|
||||||
a.set_function_template(true);
|
|
||||||
|
|
||||||
// Set function template return type
|
|
||||||
const auto return_type_name =
|
|
||||||
function_type->getReturnType().getAsString();
|
|
||||||
|
|
||||||
// Try to match the return type to template parameter in case
|
|
||||||
// the type name is in the form 'type-parameter-X-Y'
|
|
||||||
auto maybe_return_arg =
|
|
||||||
tbuilder().get_template_argument_from_type_parameter_string(
|
|
||||||
cls, return_type_name);
|
|
||||||
|
|
||||||
if (maybe_return_arg)
|
|
||||||
a.add_template_param(*maybe_return_arg);
|
|
||||||
else {
|
|
||||||
a.add_template_param(
|
|
||||||
template_parameter::make_argument(return_type_name));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set function template argument types
|
|
||||||
for (const auto ¶m_type : function_type->param_types()) {
|
|
||||||
auto maybe_arg =
|
|
||||||
tbuilder().get_template_argument_from_type_parameter_string(
|
|
||||||
cls, param_type.getAsString());
|
|
||||||
|
|
||||||
if (maybe_arg) {
|
|
||||||
a.add_template_param(*maybe_arg);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (param_type->isBuiltinType()) {
|
|
||||||
a.add_template_param(template_parameter::make_argument(
|
|
||||||
param_type.getAsString()));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto *param_record_type =
|
|
||||||
param_type->getAs<clang::RecordType>();
|
|
||||||
if (param_record_type == nullptr)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
argument = a;
|
|
||||||
}
|
|
||||||
else if (const auto *nested_template_type =
|
|
||||||
arg.getAsType()
|
|
||||||
->getAs<clang::TemplateSpecializationType>();
|
|
||||||
nested_template_type != nullptr) {
|
|
||||||
argument = template_parameter::make_argument({});
|
|
||||||
|
|
||||||
const auto nested_template_name =
|
|
||||||
nested_template_type->getTemplateName()
|
|
||||||
.getAsTemplateDecl()
|
|
||||||
->getQualifiedNameAsString();
|
|
||||||
|
|
||||||
argument->set_type(nested_template_name);
|
|
||||||
|
|
||||||
auto nested_template_instantiation = tbuilder().build(
|
|
||||||
cls, *nested_template_type, {&template_instantiation});
|
|
||||||
|
|
||||||
argument->set_id(nested_template_instantiation->id());
|
|
||||||
|
|
||||||
for (const auto &t :
|
|
||||||
nested_template_instantiation->template_params())
|
|
||||||
argument->add_template_param(t);
|
|
||||||
}
|
|
||||||
else if (arg.getAsType()->getAs<clang::TemplateTypeParmType>() !=
|
|
||||||
nullptr) {
|
|
||||||
argument = template_parameter::make_template_type({});
|
|
||||||
|
|
||||||
auto parameter_name =
|
|
||||||
common::to_string(arg.getAsType(), cls->getASTContext());
|
|
||||||
|
|
||||||
// clang does not provide declared template parameter/argument
|
|
||||||
// names in template specializations - so we have to extract
|
|
||||||
// them from raw source code...
|
|
||||||
if (parameter_name.find("type-parameter-") == 0) {
|
|
||||||
auto declaration_text = common::get_source_text_raw(
|
|
||||||
cls->getSourceRange(), source_manager());
|
|
||||||
|
|
||||||
declaration_text = declaration_text.substr(
|
|
||||||
declaration_text.find(cls->getNameAsString()) +
|
|
||||||
cls->getNameAsString().size() + 1);
|
|
||||||
|
|
||||||
auto template_params = common::parse_unexposed_template_params(
|
|
||||||
declaration_text, [](const auto &t) { return t; });
|
|
||||||
|
|
||||||
if (template_params.size() > argument_index)
|
|
||||||
parameter_name = template_params[argument_index].to_string(
|
|
||||||
config().using_namespace(), false);
|
|
||||||
else {
|
|
||||||
LOG_DBG("Failed to find type specialization for argument "
|
|
||||||
"{} at index {} in declaration \n===\n{}\n===\n",
|
|
||||||
parameter_name, argument_index, declaration_text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
argument->set_name(parameter_name);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
auto type_name =
|
|
||||||
common::to_string(arg.getAsType(), cls->getASTContext());
|
|
||||||
ensure_lambda_type_is_relative(type_name);
|
|
||||||
if (type_name.find('<') != std::string::npos) {
|
|
||||||
argument = template_parameter::make_argument({});
|
|
||||||
|
|
||||||
// Sometimes template instantiation is reported as
|
|
||||||
// RecordType in the AST and getAs to
|
|
||||||
// TemplateSpecializationType returns null pointer so we
|
|
||||||
// have to at least make sure it's properly formatted
|
|
||||||
// (e.g. std:integral_constant, or any template
|
|
||||||
// specialization which contains it - see t00038)
|
|
||||||
process_unexposed_template_specialization_parameters(
|
|
||||||
type_name.substr(type_name.find('<') + 1,
|
|
||||||
type_name.size() - (type_name.find('<') + 2)),
|
|
||||||
*argument, template_instantiation);
|
|
||||||
|
|
||||||
auto unexposed_type_name =
|
|
||||||
type_name.substr(0, type_name.find('<'));
|
|
||||||
ensure_lambda_type_is_relative(unexposed_type_name);
|
|
||||||
|
|
||||||
argument->set_type(unexposed_type_name);
|
|
||||||
}
|
|
||||||
else if (type_name.find("type-parameter-") == 0) {
|
|
||||||
argument = template_parameter::make_template_type({});
|
|
||||||
|
|
||||||
auto declaration_text = common::get_source_text_raw(
|
|
||||||
cls->getSourceRange(), source_manager());
|
|
||||||
|
|
||||||
declaration_text = declaration_text.substr(
|
|
||||||
declaration_text.find(cls->getNameAsString()) +
|
|
||||||
cls->getNameAsString().size() + 1);
|
|
||||||
|
|
||||||
auto template_params = common::parse_unexposed_template_params(
|
|
||||||
declaration_text, [](const auto &t) { return t; });
|
|
||||||
|
|
||||||
if (template_params.size() > argument_index)
|
|
||||||
type_name = template_params[argument_index].to_string(
|
|
||||||
config().using_namespace(), false);
|
|
||||||
else {
|
|
||||||
LOG_DBG("Failed to find type specialization for argument "
|
|
||||||
"{} at index {} in declaration \n===\n{}\n===\n",
|
|
||||||
type_name, argument_index, declaration_text);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise just set the name for the template argument to
|
|
||||||
// whatever clang says
|
|
||||||
argument->set_name(type_name);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
argument = template_parameter::make_argument({});
|
|
||||||
argument->set_type(type_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!argument)
|
|
||||||
return;
|
|
||||||
|
|
||||||
LOG_DBG("Adding template instantiation argument {}",
|
|
||||||
argument.value().to_string(config().using_namespace(), false));
|
|
||||||
|
|
||||||
tbuilder().simplify_system_template(*argument,
|
|
||||||
argument.value().to_string(config().using_namespace(), false));
|
|
||||||
|
|
||||||
template_instantiation.add_template(std::move(argument.value()));
|
|
||||||
}
|
|
||||||
else if (argument_kind == clang::TemplateArgument::Integral) {
|
|
||||||
auto argument = template_parameter::make_argument(
|
|
||||||
std::to_string(arg.getAsIntegral().getExtValue()));
|
|
||||||
template_instantiation.add_template(std::move(argument));
|
|
||||||
}
|
|
||||||
else if (argument_kind == clang::TemplateArgument::Expression) {
|
|
||||||
auto argument =
|
|
||||||
template_parameter::make_argument(common::get_source_text(
|
|
||||||
arg.getAsExpr()->getSourceRange(), source_manager()));
|
|
||||||
template_instantiation.add_template(std::move(argument));
|
|
||||||
}
|
|
||||||
else if (argument_kind == clang::TemplateArgument::TemplateExpansion) {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
else if (argument_kind == clang::TemplateArgument::Pack) {
|
|
||||||
// This will only work for now if pack is at the end
|
|
||||||
size_t argument_pack_index{argument_index};
|
|
||||||
for (const auto &template_argument : arg.getPackAsArray()) {
|
|
||||||
process_template_specialization_argument(cls,
|
|
||||||
template_instantiation, template_argument,
|
|
||||||
argument_pack_index++, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
LOG_ERROR("Unsupported template argument kind {} [{}]", arg.getKind(),
|
|
||||||
cls->getLocation().printToString(source_manager()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void translation_unit_visitor::
|
|
||||||
process_unexposed_template_specialization_parameters(
|
|
||||||
const std::string &type_name, template_parameter &tp, class_ &c)
|
|
||||||
{
|
|
||||||
auto template_params = common::parse_unexposed_template_params(
|
|
||||||
type_name, [](const std::string &t) { return t; });
|
|
||||||
|
|
||||||
found_relationships_t relationships;
|
|
||||||
for (auto ¶m : template_params) {
|
|
||||||
find_relationships_in_unexposed_template_params(param, relationships);
|
|
||||||
tp.add_template_param(param);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto &r : relationships) {
|
|
||||||
c.add_relationship({std::get<1>(r), std::get<0>(r)});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool translation_unit_visitor::find_relationships_in_unexposed_template_params(
|
|
||||||
const template_parameter &ct, found_relationships_t &relationships)
|
|
||||||
{
|
|
||||||
const auto &type = ct.type();
|
|
||||||
|
|
||||||
if (!type)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
bool found{false};
|
|
||||||
LOG_DBG("Finding relationships in user defined type: {}",
|
|
||||||
ct.to_string(config().using_namespace(), false));
|
|
||||||
|
|
||||||
auto type_with_namespace =
|
|
||||||
std::make_optional<common::model::namespace_>(type.value());
|
|
||||||
|
|
||||||
if (!type_with_namespace.has_value()) {
|
|
||||||
// Couldn't find declaration of this type
|
|
||||||
type_with_namespace = common::model::namespace_{type.value()};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto element_opt = diagram().get(type_with_namespace.value().to_string());
|
|
||||||
if (element_opt) {
|
|
||||||
relationships.emplace_back(
|
|
||||||
element_opt.value().id(), relationship_t::kDependency);
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto &nested_template_params : ct.template_params()) {
|
|
||||||
found = find_relationships_in_unexposed_template_params(
|
|
||||||
nested_template_params, relationships) ||
|
|
||||||
found;
|
|
||||||
}
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<class_>
|
|
||||||
template_builder::build_from_class_template_specialization(
|
|
||||||
const clang::ClassTemplateSpecializationDecl &template_specialization,
|
|
||||||
const clang::RecordType &record_type,
|
|
||||||
std::optional<clanguml::class_diagram::model::class_ *> parent)
|
|
||||||
{
|
|
||||||
auto template_instantiation_ptr =
|
|
||||||
std::make_unique<class_>(config_.using_namespace());
|
|
||||||
|
|
||||||
//
|
|
||||||
// Here we'll hold the template base params to replace with the
|
|
||||||
// instantiated values
|
|
||||||
//
|
|
||||||
std::deque<std::tuple</*parameter name*/ std::string, /* position */ int,
|
|
||||||
/*is variadic */ bool>>
|
|
||||||
template_base_params{};
|
|
||||||
|
|
||||||
auto &template_instantiation = *template_instantiation_ptr;
|
|
||||||
std::string full_template_specialization_name =
|
|
||||||
common::to_string(record_type, template_specialization.getASTContext());
|
|
||||||
|
|
||||||
const auto *template_decl =
|
|
||||||
template_specialization.getSpecializedTemplate();
|
|
||||||
|
|
||||||
auto qualified_name = template_decl->getQualifiedNameAsString();
|
|
||||||
|
|
||||||
namespace_ ns{qualified_name};
|
|
||||||
ns.pop_back();
|
|
||||||
template_instantiation.set_name(template_decl->getNameAsString());
|
|
||||||
template_instantiation.set_namespace(ns);
|
|
||||||
template_instantiation.set_id(template_decl->getID() +
|
|
||||||
static_cast<common::id_t>(
|
|
||||||
std::hash<std::string>{}(full_template_specialization_name) >> 4U));
|
|
||||||
|
|
||||||
process_template_arguments(parent, &template_specialization,
|
|
||||||
template_base_params,
|
|
||||||
template_specialization.getTemplateArgs().asArray(),
|
|
||||||
template_instantiation, full_template_specialization_name,
|
|
||||||
template_decl);
|
|
||||||
|
|
||||||
// First try to find the best match for this template in partially
|
|
||||||
// specialized templates
|
|
||||||
std::string destination{};
|
|
||||||
std::string best_match_full_name{};
|
|
||||||
auto full_template_name = template_instantiation.full_name(false);
|
|
||||||
int best_match{};
|
|
||||||
common::model::diagram_element::id_t best_match_id{0};
|
|
||||||
|
|
||||||
for (const auto templ : diagram().classes()) {
|
|
||||||
if (templ.get() == template_instantiation)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
auto c_full_name = templ.get().full_name(false);
|
|
||||||
auto match =
|
|
||||||
template_instantiation.calculate_template_specialization_match(
|
|
||||||
templ.get());
|
|
||||||
|
|
||||||
if (match > best_match) {
|
|
||||||
best_match = match;
|
|
||||||
best_match_full_name = c_full_name;
|
|
||||||
best_match_id = templ.get().id();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto templated_decl_id = template_specialization.getID();
|
|
||||||
auto templated_decl_local_id =
|
|
||||||
id_mapper().get_global_id(templated_decl_id).value_or(0);
|
|
||||||
|
|
||||||
if (best_match_id > 0) {
|
|
||||||
destination = best_match_full_name;
|
|
||||||
template_instantiation.add_relationship(
|
|
||||||
{relationship_t::kInstantiation, best_match_id});
|
|
||||||
}
|
|
||||||
// If we can't find optimal match for parent template specialization,
|
|
||||||
// just use whatever clang suggests
|
|
||||||
else if (diagram().has_element(templated_decl_local_id)) {
|
|
||||||
template_instantiation.add_relationship(
|
|
||||||
{relationship_t::kInstantiation, templated_decl_local_id});
|
|
||||||
}
|
|
||||||
else if (diagram().should_include(qualified_name)) {
|
|
||||||
LOG_DBG("Skipping instantiation relationship from {} to {}",
|
|
||||||
template_instantiation_ptr->full_name(false), templated_decl_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return template_instantiation_ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void translation_unit_visitor::process_field(
|
void translation_unit_visitor::process_field(
|
||||||
const clang::FieldDecl &field_declaration, class_ &c)
|
const clang::FieldDecl &field_declaration, class_ &c)
|
||||||
{
|
{
|
||||||
@@ -2333,25 +1971,6 @@ void translation_unit_visitor::finalize()
|
|||||||
resolve_local_to_global_ids();
|
resolve_local_to_global_ids();
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// void translation_unit_visitor::id_mapper().add(
|
|
||||||
// int64_t local_id, common::model::diagram_element::id_t global_id)
|
|
||||||
//{
|
|
||||||
// LOG_DBG("== Setting local element mapping {} --> {}", local_id,
|
|
||||||
// global_id);
|
|
||||||
//
|
|
||||||
// local_ast_id_map_[local_id] = global_id;
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
// std::optional<common::model::diagram_element::id_t>
|
|
||||||
// translation_unit_visitor::id_mapper().get_global_id(int64_t local_id) const
|
|
||||||
//{
|
|
||||||
// if (local_ast_id_map_.find(local_id) == local_ast_id_map_.end())
|
|
||||||
// return {};
|
|
||||||
//
|
|
||||||
// return local_ast_id_map_.at(local_id);
|
|
||||||
//}
|
|
||||||
|
|
||||||
void translation_unit_visitor::extract_constrained_template_param_name(
|
void translation_unit_visitor::extract_constrained_template_param_name(
|
||||||
const clang::ConceptSpecializationExpr *concept_specialization,
|
const clang::ConceptSpecializationExpr *concept_specialization,
|
||||||
const clang::ConceptDecl *cpt,
|
const clang::ConceptDecl *cpt,
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "class_diagram/model/class.h"
|
#include "class_diagram/model/class.h"
|
||||||
#include "class_diagram/model/concept.h"
|
#include "class_diagram/model/concept.h"
|
||||||
#include "class_diagram/model/diagram.h"
|
#include "class_diagram/model/diagram.h"
|
||||||
|
#include "class_diagram/visitor/template_builder.h"
|
||||||
#include "common/model/enums.h"
|
#include "common/model/enums.h"
|
||||||
#include "common/model/template_trait.h"
|
#include "common/model/template_trait.h"
|
||||||
#include "common/visitor/ast_id_mapper.h"
|
#include "common/visitor/ast_id_mapper.h"
|
||||||
@@ -52,10 +53,6 @@ using clanguml::common::model::relationship_t;
|
|||||||
using clanguml::common::model::template_parameter;
|
using clanguml::common::model::template_parameter;
|
||||||
using clanguml::common::model::template_trait;
|
using clanguml::common::model::template_trait;
|
||||||
|
|
||||||
using found_relationships_t =
|
|
||||||
std::vector<std::pair<clanguml::common::model::diagram_element::id_t,
|
|
||||||
common::model::relationship_t>>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Class diagram translation unit visitor
|
* @brief Class diagram translation unit visitor
|
||||||
*
|
*
|
||||||
@@ -152,12 +149,6 @@ private:
|
|||||||
clanguml::common::model::template_trait &t,
|
clanguml::common::model::template_trait &t,
|
||||||
common::optional_ref<common::model::element> templated_element = {});
|
common::optional_ref<common::model::element> templated_element = {});
|
||||||
|
|
||||||
void process_template_specialization_argument(
|
|
||||||
const clang::ClassTemplateSpecializationDecl *cls,
|
|
||||||
model::class_ &template_instantiation,
|
|
||||||
const clang::TemplateArgument &arg, size_t argument_index,
|
|
||||||
bool in_parameter_pack = false);
|
|
||||||
|
|
||||||
void process_method(const clang::CXXMethodDecl &mf,
|
void process_method(const clang::CXXMethodDecl &mf,
|
||||||
clanguml::class_diagram::model::class_ &c);
|
clanguml::class_diagram::model::class_ &c);
|
||||||
|
|
||||||
@@ -203,22 +194,10 @@ private:
|
|||||||
void find_relationships_in_constraint_expression(
|
void find_relationships_in_constraint_expression(
|
||||||
clanguml::common::model::element &c, const clang::Expr *expr);
|
clanguml::common::model::element &c, const clang::Expr *expr);
|
||||||
|
|
||||||
void process_unexposed_template_specialization_parameters(
|
|
||||||
const std::string &tspec,
|
|
||||||
clanguml::common::model::template_parameter &tp,
|
|
||||||
clanguml::class_diagram::model::class_ &c);
|
|
||||||
|
|
||||||
bool find_relationships_in_unexposed_template_params(
|
|
||||||
const clanguml::common::model::template_parameter &ct,
|
|
||||||
found_relationships_t &relationships);
|
|
||||||
|
|
||||||
void add_incomplete_forward_declarations();
|
void add_incomplete_forward_declarations();
|
||||||
|
|
||||||
void resolve_local_to_global_ids();
|
void resolve_local_to_global_ids();
|
||||||
|
|
||||||
bool simplify_system_template(common::model::template_parameter &ct,
|
|
||||||
const std::string &full_name) const;
|
|
||||||
|
|
||||||
void process_constraint_requirements(const clang::ConceptDecl *cpt,
|
void process_constraint_requirements(const clang::ConceptDecl *cpt,
|
||||||
const clang::Expr *expr, model::concept_ &concept_model) const;
|
const clang::Expr *expr, model::concept_ &concept_model) const;
|
||||||
|
|
||||||
|
|||||||
@@ -169,13 +169,14 @@ std::string to_string(const clang::RecordType &type,
|
|||||||
return to_string(type.desugar(), ctx, try_canonical);
|
return to_string(type.desugar(), ctx, try_canonical);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string to_string(const clang::TemplateArgument &arg)
|
std::string to_string(
|
||||||
|
const clang::TemplateArgument &arg, const clang::ASTContext *ctx)
|
||||||
{
|
{
|
||||||
switch (arg.getKind()) {
|
switch (arg.getKind()) {
|
||||||
case clang::TemplateArgument::Expression:
|
case clang::TemplateArgument::Expression:
|
||||||
return to_string(arg.getAsExpr());
|
return to_string(arg.getAsExpr());
|
||||||
case clang::TemplateArgument::Type:
|
case clang::TemplateArgument::Type:
|
||||||
return to_string(arg.getAsType());
|
return to_string(arg.getAsType(), *ctx, false);
|
||||||
case clang::TemplateArgument::Null:
|
case clang::TemplateArgument::Null:
|
||||||
return "";
|
return "";
|
||||||
case clang::TemplateArgument::NullPtr:
|
case clang::TemplateArgument::NullPtr:
|
||||||
@@ -428,7 +429,7 @@ std::vector<common::model::template_parameter> parse_unexposed_template_params(
|
|||||||
}
|
}
|
||||||
if (complete_class_template_argument) {
|
if (complete_class_template_argument) {
|
||||||
auto t = template_parameter::make_unexposed_argument(
|
auto t = template_parameter::make_unexposed_argument(
|
||||||
ns_resolve(clanguml::util::trim(type)));
|
ns_resolve(clanguml::util::trim_typename(type)));
|
||||||
type = "";
|
type = "";
|
||||||
for (auto &¶m : nested_params)
|
for (auto &¶m : nested_params)
|
||||||
t.add_template_param(std::move(param));
|
t.add_template_param(std::move(param));
|
||||||
@@ -441,7 +442,7 @@ std::vector<common::model::template_parameter> parse_unexposed_template_params(
|
|||||||
|
|
||||||
if (!type.empty()) {
|
if (!type.empty()) {
|
||||||
auto t = template_parameter::make_unexposed_argument(
|
auto t = template_parameter::make_unexposed_argument(
|
||||||
ns_resolve(clanguml::util::trim(type)));
|
ns_resolve(clanguml::util::trim_typename(type)));
|
||||||
type = "";
|
type = "";
|
||||||
for (auto &¶m : nested_params)
|
for (auto &¶m : nested_params)
|
||||||
t.add_template_param(std::move(param));
|
t.add_template_param(std::move(param));
|
||||||
|
|||||||
@@ -81,7 +81,8 @@ std::string to_string(const clang::QualType &type, const clang::ASTContext &ctx,
|
|||||||
std::string to_string(const clang::RecordType &type,
|
std::string to_string(const clang::RecordType &type,
|
||||||
const clang::ASTContext &ctx, bool try_canonical = true);
|
const clang::ASTContext &ctx, bool try_canonical = true);
|
||||||
|
|
||||||
std::string to_string(const clang::TemplateArgument &arg);
|
std::string to_string(
|
||||||
|
const clang::TemplateArgument &arg, const clang::ASTContext *ctx = nullptr);
|
||||||
|
|
||||||
std::string to_string(const clang::Expr *expr);
|
std::string to_string(const clang::Expr *expr);
|
||||||
|
|
||||||
|
|||||||
@@ -136,6 +136,15 @@ std::string rtrim(const std::string &s)
|
|||||||
return (end == std::string::npos) ? "" : s.substr(0, end + 1);
|
return (end == std::string::npos) ? "" : s.substr(0, end + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string trim_typename(const std::string &s)
|
||||||
|
{
|
||||||
|
auto res = trim(s);
|
||||||
|
if (res.find("typename ") == 0)
|
||||||
|
return res.substr(strlen("typename "));
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
std::string trim(const std::string &s) { return rtrim(ltrim(s)); }
|
std::string trim(const std::string &s) { return rtrim(ltrim(s)); }
|
||||||
|
|
||||||
std::vector<std::string> split(
|
std::vector<std::string> split(
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ namespace clanguml::util {
|
|||||||
std::string ltrim(const std::string &s);
|
std::string ltrim(const std::string &s);
|
||||||
std::string rtrim(const std::string &s);
|
std::string rtrim(const std::string &s);
|
||||||
std::string trim(const std::string &s);
|
std::string trim(const std::string &s);
|
||||||
|
std::string trim_typename(const std::string &s);
|
||||||
|
|
||||||
#define FILENAME_ \
|
#define FILENAME_ \
|
||||||
(strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
|
(strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
// Inspired by skypjack/entt signal handlers
|
// Inspired by skypjack/entt signal handlers
|
||||||
// This test case checks that at least clang-uml does not crash on this code
|
|
||||||
namespace clanguml::t00044 {
|
namespace clanguml::t00044 {
|
||||||
|
|
||||||
template <typename T> class sink;
|
template <typename T> class sink;
|
||||||
|
|||||||
21
uml/template_builder_sequence_diagram.yml
Normal file
21
uml/template_builder_sequence_diagram.yml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
type: sequence
|
||||||
|
combine_free_functions_into_file_participants: true
|
||||||
|
generate_method_arguments: none
|
||||||
|
glob:
|
||||||
|
- src/class_diagram/visitor/template_builder.cc
|
||||||
|
include:
|
||||||
|
namespaces:
|
||||||
|
- clanguml
|
||||||
|
paths:
|
||||||
|
- src/class_diagram/visitor/template_builder.h
|
||||||
|
- src/class_diagram/visitor/template_builder.cc
|
||||||
|
exclude:
|
||||||
|
paths:
|
||||||
|
- src/common/model/source_location.h
|
||||||
|
using_namespace:
|
||||||
|
- clanguml
|
||||||
|
plantuml:
|
||||||
|
before:
|
||||||
|
- 'title clang-uml class_diagram::visitor::template_builder::build sequence diagram'
|
||||||
|
start_from:
|
||||||
|
- function: "clanguml::class_diagram::visitor::template_builder::build(const clang::NamedDecl *,const clang::TemplateSpecializationType &,std::optional<class_diagram::model::class_ *>)"
|
||||||
Reference in New Issue
Block a user