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
|
||||
class_diagram_generator_sequence:
|
||||
include!: uml/class_diagram_generator_sequence_diagram.yml
|
||||
template_builder_sequence:
|
||||
include!: uml/template_builder_sequence_diagram.yml
|
||||
package_model_class:
|
||||
include!: uml/package_model_class_diagram.yml
|
||||
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::template_parameter;
|
||||
|
||||
using found_relationships_t =
|
||||
std::vector<std::pair<clanguml::common::model::diagram_element::id_t,
|
||||
common::model::relationship_t>>;
|
||||
|
||||
class template_builder {
|
||||
public:
|
||||
template_builder(class_diagram::model::diagram &d,
|
||||
@@ -47,14 +51,13 @@ public:
|
||||
template_parameter &ct, const std::string &full_name) const;
|
||||
|
||||
std::unique_ptr<clanguml::class_diagram::model::class_> build(
|
||||
const clang::Decl *cls,
|
||||
const clang::NamedDecl *cls,
|
||||
const clang::TemplateSpecializationType &template_type_decl,
|
||||
std::optional<clanguml::class_diagram::model::class_ *> parent = {});
|
||||
|
||||
std::unique_ptr<clanguml::class_diagram::model::class_>
|
||||
build_from_class_template_specialization(
|
||||
const clang::ClassTemplateSpecializationDecl &template_specialization,
|
||||
const clang::RecordType &record_type,
|
||||
std::optional<clanguml::class_diagram::model::class_ *> parent = {});
|
||||
|
||||
bool add_base_classes(clanguml::class_diagram::model::class_ &tinst,
|
||||
@@ -64,23 +67,20 @@ public:
|
||||
|
||||
void process_template_arguments(
|
||||
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,
|
||||
const clang::ArrayRef<clang::TemplateArgument> &template_args,
|
||||
model::class_ &template_instantiation,
|
||||
const std::string &full_template_specialization_name,
|
||||
const clang::TemplateDecl *template_decl);
|
||||
|
||||
void argument_process_dispatch(
|
||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
||||
const clang::Decl *cls, class_ &template_instantiation,
|
||||
const std::string &full_template_specialization_name,
|
||||
const clang::NamedDecl *cls, class_ &template_instantiation,
|
||||
const clang::TemplateDecl *template_decl,
|
||||
const clang::TemplateArgument &arg,
|
||||
const clang::TemplateArgument &arg, size_t argument_index,
|
||||
std::vector<template_parameter> &argument);
|
||||
|
||||
void process_tag_argument(model::class_ &template_instantiation,
|
||||
const std::string &full_template_specialization_name,
|
||||
const clang::TemplateDecl *template_decl,
|
||||
const clang::TemplateArgument &arg,
|
||||
common::model::template_parameter &argument);
|
||||
@@ -99,23 +99,27 @@ public:
|
||||
|
||||
std::vector<template_parameter> process_pack_argument(
|
||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
||||
const clang::Decl *cls, class_ &template_instantiation,
|
||||
const std::string &full_template_specialization_name,
|
||||
const clang::NamedDecl *cls, class_ &template_instantiation,
|
||||
const clang::TemplateDecl *template_decl,
|
||||
const clang::TemplateArgument &arg,
|
||||
const clang::TemplateArgument &arg, size_t argument_index,
|
||||
std::vector<template_parameter> &argument);
|
||||
|
||||
template_parameter process_type_argument(
|
||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
||||
const clang::Decl *cls,
|
||||
const std::string &full_template_specialization_name,
|
||||
const clang::TemplateDecl *template_decl,
|
||||
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
|
||||
const clang::TemplateArgument &arg,
|
||||
model::class_ &template_instantiation);
|
||||
model::class_ &template_instantiation, size_t argument_index);
|
||||
|
||||
common::model::template_parameter process_template_argument(
|
||||
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>
|
||||
get_template_argument_from_type_parameter_string(
|
||||
const clang::Decl *decl, const std::string &return_type_name) const;
|
||||
@@ -125,6 +129,8 @@ public:
|
||||
clang::SourceManager &source_manager() const;
|
||||
|
||||
private:
|
||||
void ensure_lambda_type_is_relative(std::string ¶meter_type) const;
|
||||
|
||||
// Reference to the output diagram model
|
||||
clanguml::class_diagram::model::diagram &diagram_;
|
||||
|
||||
|
||||
@@ -1715,7 +1715,8 @@ std::unique_ptr<class_>
|
||||
translation_unit_visitor::process_template_specialization(
|
||||
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;
|
||||
template_instantiation.is_template(true);
|
||||
|
||||
@@ -1745,374 +1746,11 @@ translation_unit_visitor::process_template_specialization(
|
||||
if (template_instantiation.skip())
|
||||
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());
|
||||
|
||||
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(
|
||||
const clang::FieldDecl &field_declaration, class_ &c)
|
||||
{
|
||||
@@ -2333,25 +1971,6 @@ void translation_unit_visitor::finalize()
|
||||
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(
|
||||
const clang::ConceptSpecializationExpr *concept_specialization,
|
||||
const clang::ConceptDecl *cpt,
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "class_diagram/model/class.h"
|
||||
#include "class_diagram/model/concept.h"
|
||||
#include "class_diagram/model/diagram.h"
|
||||
#include "class_diagram/visitor/template_builder.h"
|
||||
#include "common/model/enums.h"
|
||||
#include "common/model/template_trait.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_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
|
||||
*
|
||||
@@ -152,12 +149,6 @@ private:
|
||||
clanguml::common::model::template_trait &t,
|
||||
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,
|
||||
clanguml::class_diagram::model::class_ &c);
|
||||
|
||||
@@ -203,22 +194,10 @@ private:
|
||||
void find_relationships_in_constraint_expression(
|
||||
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 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,
|
||||
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);
|
||||
}
|
||||
|
||||
std::string to_string(const clang::TemplateArgument &arg)
|
||||
std::string to_string(
|
||||
const clang::TemplateArgument &arg, const clang::ASTContext *ctx)
|
||||
{
|
||||
switch (arg.getKind()) {
|
||||
case clang::TemplateArgument::Expression:
|
||||
return to_string(arg.getAsExpr());
|
||||
case clang::TemplateArgument::Type:
|
||||
return to_string(arg.getAsType());
|
||||
return to_string(arg.getAsType(), *ctx, false);
|
||||
case clang::TemplateArgument::Null:
|
||||
return "";
|
||||
case clang::TemplateArgument::NullPtr:
|
||||
@@ -428,7 +429,7 @@ std::vector<common::model::template_parameter> parse_unexposed_template_params(
|
||||
}
|
||||
if (complete_class_template_argument) {
|
||||
auto t = template_parameter::make_unexposed_argument(
|
||||
ns_resolve(clanguml::util::trim(type)));
|
||||
ns_resolve(clanguml::util::trim_typename(type)));
|
||||
type = "";
|
||||
for (auto &¶m : nested_params)
|
||||
t.add_template_param(std::move(param));
|
||||
@@ -441,7 +442,7 @@ std::vector<common::model::template_parameter> parse_unexposed_template_params(
|
||||
|
||||
if (!type.empty()) {
|
||||
auto t = template_parameter::make_unexposed_argument(
|
||||
ns_resolve(clanguml::util::trim(type)));
|
||||
ns_resolve(clanguml::util::trim_typename(type)));
|
||||
type = "";
|
||||
for (auto &¶m : nested_params)
|
||||
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,
|
||||
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);
|
||||
|
||||
|
||||
@@ -136,6 +136,15 @@ std::string rtrim(const std::string &s)
|
||||
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::vector<std::string> split(
|
||||
|
||||
@@ -57,6 +57,7 @@ namespace clanguml::util {
|
||||
std::string ltrim(const std::string &s);
|
||||
std::string rtrim(const std::string &s);
|
||||
std::string trim(const std::string &s);
|
||||
std::string trim_typename(const std::string &s);
|
||||
|
||||
#define FILENAME_ \
|
||||
(strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// Inspired by skypjack/entt signal handlers
|
||||
// This test case checks that at least clang-uml does not crash on this code
|
||||
namespace clanguml::t00044 {
|
||||
|
||||
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