Fixed handling of template template specialization parameters in instantiation deduction
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
#include "template_builder.h"
|
||||
#include "common/clang_utils.h"
|
||||
#include "translation_unit_visitor.h"
|
||||
#include <clang/Lex/Lexer.h>
|
||||
|
||||
namespace clanguml::class_diagram::visitor {
|
||||
|
||||
@@ -289,7 +290,7 @@ template_builder::build_from_class_template_specialization(
|
||||
auto &template_instantiation = *template_instantiation_ptr;
|
||||
template_instantiation.is_struct(template_specialization.isStruct());
|
||||
|
||||
const auto *template_decl =
|
||||
const clang::ClassTemplateDecl *template_decl =
|
||||
template_specialization.getSpecializedTemplate();
|
||||
|
||||
auto qualified_name = template_decl->getQualifiedNameAsString();
|
||||
@@ -364,27 +365,36 @@ void template_builder::process_template_arguments(
|
||||
const clang::ArrayRef<clang::TemplateArgument> &template_args,
|
||||
class_ &template_instantiation, const clang::TemplateDecl *template_decl)
|
||||
{
|
||||
auto arg_index = 0;
|
||||
auto arg_index{0};
|
||||
|
||||
for (const auto &arg : template_args) {
|
||||
// Argument can be a parameter pack in which case it gives multiple
|
||||
// arguments
|
||||
std::vector<template_parameter> arguments;
|
||||
|
||||
// For now ignore the default template arguments to make the system
|
||||
// For now ignore the default template arguments of templates which
|
||||
// do not match the inclusion filters, to make the system
|
||||
// templates 'nicer' - i.e. skipping the allocators and comparators
|
||||
// TODO: Change this to ignore only when the arguments are set to
|
||||
// default values, and add them when they are specifically
|
||||
// overriden
|
||||
// overridden
|
||||
if (!diagram().should_include(
|
||||
template_decl->getQualifiedNameAsString())) {
|
||||
const auto *maybe_type_parm_decl =
|
||||
clang::dyn_cast<clang::TemplateTypeParmDecl>(
|
||||
template_decl->getTemplateParameters()->getParam(
|
||||
std::min<int>(arg_index,
|
||||
template_decl->getTemplateParameters()->size() - 1)));
|
||||
template_decl->getTemplateParameters()->size() -
|
||||
1)));
|
||||
if (maybe_type_parm_decl &&
|
||||
maybe_type_parm_decl->hasDefaultArgument()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Handle the template parameter/argument based on its kind
|
||||
//
|
||||
argument_process_dispatch(parent, cls, template_instantiation,
|
||||
template_decl, arg, arg_index, arguments);
|
||||
|
||||
@@ -430,10 +440,16 @@ void template_builder::argument_process_dispatch(
|
||||
const clang::TemplateArgument &arg, size_t argument_index,
|
||||
std::vector<template_parameter> &argument)
|
||||
{
|
||||
LOG_DBG("Processing argument {} in template class: {}", argument_index,
|
||||
cls->getQualifiedNameAsString());
|
||||
|
||||
switch (arg.getKind()) {
|
||||
case clang::TemplateArgument::Null:
|
||||
argument.push_back(process_null_argument(arg));
|
||||
break;
|
||||
case clang::TemplateArgument::Template:
|
||||
argument.push_back(process_template_argument(arg));
|
||||
break;
|
||||
case clang::TemplateArgument::Type:
|
||||
argument.push_back(process_type_argument(parent, cls, template_decl,
|
||||
arg.getAsType(), template_instantiation, argument_index));
|
||||
@@ -446,9 +462,6 @@ void template_builder::argument_process_dispatch(
|
||||
case clang::TemplateArgument::Integral:
|
||||
argument.push_back(process_integral_argument(arg));
|
||||
break;
|
||||
case clang::TemplateArgument::Template:
|
||||
argument.push_back(process_template_argument(arg));
|
||||
break;
|
||||
case clang::TemplateArgument::TemplateExpansion:
|
||||
argument.push_back(process_template_expansion(arg));
|
||||
break;
|
||||
@@ -576,8 +589,8 @@ template_parameter template_builder::process_type_argument(
|
||||
|
||||
std::optional<template_parameter> argument;
|
||||
|
||||
LOG_DBG("Processing template {} type argument: {}, {}, {}",
|
||||
template_decl->getQualifiedNameAsString(), type_name,
|
||||
LOG_DBG("Processing template {} type argument {}: {}, {}, {}",
|
||||
template_decl->getQualifiedNameAsString(), argument_index, type_name,
|
||||
type->getTypeClassName(),
|
||||
common::to_string(type, cls->getASTContext()));
|
||||
|
||||
@@ -596,12 +609,12 @@ template_parameter template_builder::process_type_argument(
|
||||
if (argument)
|
||||
return *argument;
|
||||
|
||||
argument = try_as_template_specialization_type(parent, cls, template_decl,
|
||||
type, template_instantiation, argument_index);
|
||||
argument = try_as_template_parm_type(cls, template_decl, type);
|
||||
if (argument)
|
||||
return *argument;
|
||||
|
||||
argument = try_as_template_parm_type(cls, template_decl, type);
|
||||
argument = try_as_template_specialization_type(parent, cls, template_decl,
|
||||
type, template_instantiation, argument_index);
|
||||
if (argument)
|
||||
return *argument;
|
||||
|
||||
@@ -619,6 +632,10 @@ template_parameter template_builder::process_type_argument(
|
||||
if (argument)
|
||||
return *argument;
|
||||
|
||||
argument = try_as_builtin_type(parent, type, template_decl);
|
||||
if (argument)
|
||||
return *argument;
|
||||
|
||||
// fallback
|
||||
return template_parameter::make_argument(type_name);
|
||||
}
|
||||
@@ -952,10 +969,29 @@ template_builder::try_as_template_specialization_type(
|
||||
auto argument = template_parameter::make_argument("");
|
||||
type = consume_context(type, argument);
|
||||
|
||||
const auto nested_type_name = nested_template_type->getTemplateName()
|
||||
auto nested_type_name = nested_template_type->getTemplateName()
|
||||
.getAsTemplateDecl()
|
||||
->getQualifiedNameAsString();
|
||||
|
||||
if (clang::dyn_cast<clang::TemplateTemplateParmDecl>(
|
||||
nested_template_type->getTemplateName().getAsTemplateDecl()) !=
|
||||
nullptr) {
|
||||
if (const auto *template_specialization_decl =
|
||||
clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(cls);
|
||||
template_specialization_decl != nullptr) {
|
||||
nested_type_name =
|
||||
template_specialization_decl->getDescribedTemplateParams()
|
||||
->getParam(argument_index)
|
||||
->getNameAsString();
|
||||
}
|
||||
else {
|
||||
// fallback
|
||||
nested_type_name = "template";
|
||||
}
|
||||
|
||||
argument.is_template_template_parameter(true);
|
||||
}
|
||||
|
||||
argument.set_type(nested_type_name);
|
||||
|
||||
auto nested_template_instantiation = build(cls, *nested_template_type,
|
||||
@@ -1008,6 +1044,8 @@ std::optional<template_parameter> template_builder::try_as_template_parm_type(
|
||||
auto type_parameter =
|
||||
common::dereference(type)->getAs<clang::TemplateTypeParmType>();
|
||||
|
||||
auto type_name = common::to_string(type, &cls->getASTContext());
|
||||
|
||||
if (type_parameter == nullptr) {
|
||||
if (common::dereference(type)->getAs<clang::PackExpansionType>()) {
|
||||
is_variadic = true;
|
||||
@@ -1026,8 +1064,6 @@ std::optional<template_parameter> template_builder::try_as_template_parm_type(
|
||||
|
||||
argument.is_variadic(is_variadic);
|
||||
|
||||
auto type_name = common::to_string(type, &cls->getASTContext());
|
||||
|
||||
auto type_parameter_name = common::to_string(type, cls->getASTContext());
|
||||
|
||||
ensure_lambda_type_is_relative(type_parameter_name);
|
||||
@@ -1141,6 +1177,23 @@ std::optional<template_parameter> template_builder::try_as_enum_type(
|
||||
return argument;
|
||||
}
|
||||
|
||||
std::optional<template_parameter> template_builder::try_as_builtin_type(
|
||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
||||
clang::QualType &type, const clang::TemplateDecl *template_decl)
|
||||
{
|
||||
const auto *builtin_type = type->getAs<clang::BuiltinType>();
|
||||
if (builtin_type == nullptr)
|
||||
return {};
|
||||
|
||||
auto type_name = common::to_string(type, template_decl->getASTContext());
|
||||
auto argument = template_parameter::make_argument(type_name);
|
||||
|
||||
type = consume_context(type, argument);
|
||||
argument.set_type(type_name);
|
||||
|
||||
return argument;
|
||||
}
|
||||
|
||||
bool template_builder::add_base_classes(class_ &tinst,
|
||||
std::deque<std::tuple<std::string, int, bool>> &template_base_params,
|
||||
int arg_index, bool variadic_params, const template_parameter &ct)
|
||||
|
||||
@@ -149,6 +149,10 @@ public:
|
||||
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
|
||||
clang::QualType &type, class_ &template_instantiation);
|
||||
|
||||
std::optional<template_parameter> try_as_builtin_type(
|
||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
||||
clang::QualType &type, const clang::TemplateDecl *template_decl);
|
||||
|
||||
std::optional<template_parameter> try_as_member_pointer(
|
||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
||||
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
|
||||
|
||||
@@ -59,17 +59,19 @@ TEST_CASE("t00051", "[test-case][class]")
|
||||
REQUIRE_THAT(puml, (IsMethod<Public>("ff", "void")));
|
||||
|
||||
REQUIRE_THAT(puml,
|
||||
IsClassTemplate(
|
||||
"B", "(lambda at ../../tests/t00051/t00051.cc:43:18)"));
|
||||
//,(lambda at ../../tests/t00051/t00051.cc:43:27)"));
|
||||
IsClassTemplate("B",
|
||||
"(lambda at ../../tests/t00051/t00051.cc:43:18),(lambda at "
|
||||
"../../tests/t00051/t00051.cc:43:27)"));
|
||||
|
||||
REQUIRE_THAT(puml,
|
||||
IsInstantiation(_A("B<F,FF=F>"),
|
||||
_A("B<(lambda at ../../tests/t00051/t00051.cc:43:18)>")));
|
||||
_A("B<(lambda at ../../tests/t00051/t00051.cc:43:18),(lambda "
|
||||
"at ../../tests/t00051/t00051.cc:43:27)>")));
|
||||
|
||||
REQUIRE_THAT(puml,
|
||||
IsDependency(_A("A"),
|
||||
_A("B<(lambda at ../../tests/t00051/t00051.cc:43:18)>")));
|
||||
_A("B<(lambda at ../../tests/t00051/t00051.cc:43:18),(lambda "
|
||||
"at ../../tests/t00051/t00051.cc:43:27)>")));
|
||||
|
||||
save_puml(
|
||||
config.output_directory() + "/" + diagram->name + ".puml", puml);
|
||||
|
||||
@@ -86,14 +86,16 @@ template <typename U> struct A<U(...)> {
|
||||
bool u;
|
||||
};
|
||||
|
||||
//
|
||||
// template <typename T> struct eval;
|
||||
//
|
||||
// template <template <typename, typename...> class TT, typename T1,
|
||||
// typename... Rest>
|
||||
// struct eval<TT<T1, Rest...>> { };
|
||||
//
|
||||
// eval<A<int>> eA;
|
||||
// eval<std::map<int, float>> eB;
|
||||
template <template <typename> class C, typename T> struct A<C<T>> {
|
||||
C<T> c;
|
||||
};
|
||||
|
||||
template <template <typename, typename...> class C, typename T,
|
||||
typename... Args>
|
||||
struct A<C<T, Args...>> {
|
||||
C<T> c;
|
||||
std::tuple<Args...> args;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
@@ -52,6 +52,8 @@ TEST_CASE("t00062", "[test-case][class]")
|
||||
REQUIRE_THAT(puml, IsClassTemplate("A", "char[1000]"));
|
||||
|
||||
REQUIRE_THAT(puml, IsClassTemplate("A", "U(...)"));
|
||||
REQUIRE_THAT(puml, IsClassTemplate("A", "C<T>"));
|
||||
REQUIRE_THAT(puml, IsClassTemplate("A", "C<T,Args...>"));
|
||||
|
||||
REQUIRE_THAT(puml, IsInstantiation(_A("A<T>"), _A("A<U &>")));
|
||||
REQUIRE_THAT(puml, IsInstantiation(_A("A<T>"), _A("A<U &&>")));
|
||||
@@ -67,6 +69,9 @@ TEST_CASE("t00062", "[test-case][class]")
|
||||
puml, IsInstantiation(_A("A<char[N]>"), _A("A<char[1000]>")));
|
||||
|
||||
REQUIRE_THAT(puml, IsInstantiation(_A("A<T>"), _A("A<U(...)>")));
|
||||
REQUIRE_THAT(puml, IsInstantiation(_A("A<T>"), _A("A<U(...)>")));
|
||||
REQUIRE_THAT(puml, IsInstantiation(_A("A<T>"), _A("A<C<T>>")));
|
||||
REQUIRE_THAT(puml, IsInstantiation(_A("A<T>"), _A("A<C<T,Args...>>")));
|
||||
|
||||
save_puml(
|
||||
config.output_directory() + "/" + diagram->name + ".puml", puml);
|
||||
|
||||
Reference in New Issue
Block a user