Improved handling of method template deductions
This commit is contained in:
@@ -72,8 +72,6 @@ std::unique_ptr<class_> template_builder::build(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)
|
||||||
{
|
{
|
||||||
// TODO: Make sure we only build instantiation once
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Here we'll hold the template base class params to replace with the
|
// Here we'll hold the template base class params to replace with the
|
||||||
// instantiated values
|
// instantiated values
|
||||||
@@ -641,7 +639,6 @@ template_parameter template_builder::process_type_argument(
|
|||||||
argument.set_type(unexposed_type_name);
|
argument.set_type(unexposed_type_name);
|
||||||
}
|
}
|
||||||
else if (type_name.find("type-parameter-") == 0) {
|
else if (type_name.find("type-parameter-") == 0) {
|
||||||
// argument = template_parameter::make_template_type({});
|
|
||||||
auto maybe_arg = get_template_argument_from_type_parameter_string(
|
auto maybe_arg = get_template_argument_from_type_parameter_string(
|
||||||
cls, type_name);
|
cls, type_name);
|
||||||
|
|
||||||
@@ -651,7 +648,7 @@ template_parameter template_builder::process_type_argument(
|
|||||||
|
|
||||||
// Otherwise just set the name for the template argument to
|
// Otherwise just set the name for the template argument to
|
||||||
// whatever clang says
|
// whatever clang says
|
||||||
argument.set_name(type_name);
|
return template_parameter::make_template_type(type_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -732,22 +729,146 @@ bool template_builder::find_relationships_in_unexposed_template_params(
|
|||||||
|
|
||||||
std::optional<template_parameter>
|
std::optional<template_parameter>
|
||||||
template_builder::get_template_argument_from_type_parameter_string(
|
template_builder::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 &type_name) const
|
||||||
{
|
{
|
||||||
if (const auto *template_decl =
|
if (const auto *template_decl =
|
||||||
llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(decl);
|
llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(decl);
|
||||||
template_decl != nullptr &&
|
template_decl != nullptr && type_name.find("type-parameter-") == 0) {
|
||||||
return_type_name.find("type-parameter-") == 0) {
|
|
||||||
|
|
||||||
[[maybe_unused]] const auto [depth, index] =
|
if (type_name.rfind("type-parameter-") > 0 &&
|
||||||
common::extract_template_parameter_index(return_type_name);
|
type_name.find("::*") != std::string::npos) {
|
||||||
|
if (type_name.find("::*)") == std::string::npos) {
|
||||||
|
// This is a method invocation template, e.g.
|
||||||
|
// template <typename M, typename C>
|
||||||
|
// struct invocable<type-parameter-0-0 type-parameter-0-1::*>
|
||||||
|
// {};
|
||||||
|
const auto [depth0, index0, qualifier0] =
|
||||||
|
common::extract_template_parameter_index(
|
||||||
|
type_name.substr(0, type_name.find(' ')));
|
||||||
|
|
||||||
std::string param_name = return_type_name;
|
const auto [depth1, index1, qualifier1] =
|
||||||
|
common::extract_template_parameter_index(type_name.substr(
|
||||||
|
type_name.find(' ') + 1, type_name.find(':')));
|
||||||
|
|
||||||
|
auto template_param =
|
||||||
|
template_parameter::make_template_type({});
|
||||||
|
template_param.set_method_template(true);
|
||||||
|
|
||||||
|
std::string param_name = type_name;
|
||||||
|
|
||||||
|
for (auto i = 0U;
|
||||||
|
i < template_decl->getDescribedTemplateParams()->size();
|
||||||
|
i++) {
|
||||||
|
const auto *param =
|
||||||
|
template_decl->getDescribedTemplateParams()->getParam(
|
||||||
|
i);
|
||||||
|
|
||||||
|
if (i == index0) {
|
||||||
|
param_name = param->getNameAsString();
|
||||||
|
|
||||||
|
template_param.add_template_param(
|
||||||
|
template_parameter::make_template_type(param_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == index1) {
|
||||||
|
param_name = param->getNameAsString();
|
||||||
|
|
||||||
|
template_param.add_template_param(
|
||||||
|
template_parameter::make_template_type(param_name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template_param.set_method_qualifier(
|
||||||
|
type_name.substr(type_name.find("::*") + 3));
|
||||||
|
|
||||||
|
return template_param;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Here we're dealing with method type with args, e.g.:
|
||||||
|
// type-parameter-0-0
|
||||||
|
// (type-parameter-0-1::*)(type-parameter-0-2)
|
||||||
|
const auto [depth0, index0, qualifier0] =
|
||||||
|
common::extract_template_parameter_index(
|
||||||
|
type_name.substr(0, type_name.find(' ')));
|
||||||
|
|
||||||
|
const auto [depth1, index1, qualifier1] =
|
||||||
|
common::extract_template_parameter_index(type_name.substr(
|
||||||
|
type_name.find(" (") + 2, type_name.find(':')));
|
||||||
|
|
||||||
|
auto template_param =
|
||||||
|
template_parameter::make_template_type({});
|
||||||
|
template_param.set_method_template(true);
|
||||||
|
|
||||||
|
// TODO: Handle args
|
||||||
|
for (auto i = 0U;
|
||||||
|
i < template_decl->getDescribedTemplateParams()->size();
|
||||||
|
i++) {
|
||||||
|
const auto *param =
|
||||||
|
template_decl->getDescribedTemplateParams()->getParam(
|
||||||
|
i);
|
||||||
|
|
||||||
|
if (i == index0) {
|
||||||
|
template_param.add_template_param(
|
||||||
|
template_parameter::make_template_type(
|
||||||
|
param->getNameAsString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == index1) {
|
||||||
|
template_param.add_template_param(
|
||||||
|
template_parameter::make_template_type(
|
||||||
|
param->getNameAsString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return template_param;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const auto [depth, index, qualifier] =
|
||||||
|
common::extract_template_parameter_index(type_name);
|
||||||
|
|
||||||
|
std::string param_name = type_name;
|
||||||
|
|
||||||
|
clang::ClassTemplateSpecializationDecl *template_decl_at_depth =
|
||||||
|
const_cast<clang::ClassTemplateSpecializationDecl *>(
|
||||||
|
template_decl);
|
||||||
|
|
||||||
|
for (auto i = 0U; i <
|
||||||
|
template_decl_at_depth->getDescribedTemplateParams()->size();
|
||||||
|
i++) {
|
||||||
|
const auto *param =
|
||||||
|
template_decl_at_depth->getDescribedTemplateParams()
|
||||||
|
->getParam(i);
|
||||||
|
|
||||||
|
if (i == index) {
|
||||||
|
param_name = param->getNameAsString();
|
||||||
|
|
||||||
|
auto template_param =
|
||||||
|
template_parameter::make_template_type(param_name);
|
||||||
|
|
||||||
|
template_param.is_variadic(param->isParameterPack());
|
||||||
|
|
||||||
|
return template_param;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (const auto *alias_decl =
|
||||||
|
llvm::dyn_cast<clang::TypeAliasTemplateDecl>(decl);
|
||||||
|
alias_decl != nullptr && type_name.find("type-parameter-") == 0) {
|
||||||
|
const auto [depth, index, qualifier] =
|
||||||
|
common::extract_template_parameter_index(type_name);
|
||||||
|
|
||||||
|
std::string param_name = type_name;
|
||||||
|
|
||||||
|
const auto *template_decl_at_depth = alias_decl;
|
||||||
|
|
||||||
|
template_decl_at_depth->dump();
|
||||||
|
|
||||||
for (auto i = 0U;
|
for (auto i = 0U;
|
||||||
i < template_decl->getDescribedTemplateParams()->size(); i++) {
|
i < template_decl_at_depth->getTemplateParameters()->size(); i++) {
|
||||||
const auto *param =
|
const auto *param =
|
||||||
template_decl->getDescribedTemplateParams()->getParam(i);
|
template_decl_at_depth->getTemplateParameters()->getParam(i);
|
||||||
|
|
||||||
if (i == index) {
|
if (i == index) {
|
||||||
param_name = param->getNameAsString();
|
param_name = param->getNameAsString();
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ public:
|
|||||||
|
|
||||||
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 &type_name) const;
|
||||||
|
|
||||||
common::visitor::ast_id_mapper &id_mapper();
|
common::visitor::ast_id_mapper &id_mapper();
|
||||||
|
|
||||||
|
|||||||
@@ -269,17 +269,24 @@ std::string get_source_text(
|
|||||||
return get_source_text_raw(printable_range, sm);
|
return get_source_text_raw(printable_range, sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<unsigned int, unsigned int> extract_template_parameter_index(
|
std::tuple<unsigned int, unsigned int, std::string>
|
||||||
const std::string &type_parameter)
|
extract_template_parameter_index(const std::string &type_parameter)
|
||||||
{
|
{
|
||||||
assert(type_parameter.find("type-parameter-") == 0);
|
assert(type_parameter.find("type-parameter-") == 0);
|
||||||
|
|
||||||
auto toks =
|
auto type_parameter_and_suffix = util::split(type_parameter, " ");
|
||||||
util::split(type_parameter.substr(strlen("type-parameter-")), "-");
|
|
||||||
|
|
||||||
assert(toks.size() == 2);
|
auto toks = util::split(
|
||||||
|
type_parameter_and_suffix.front().substr(strlen("type-parameter-")),
|
||||||
|
"-");
|
||||||
|
|
||||||
return {std::stoi(toks.at(0)), std::stoi(toks.at(1))};
|
std::string qualifier;
|
||||||
|
|
||||||
|
if (type_parameter_and_suffix.size() > 1) {
|
||||||
|
qualifier = type_parameter_and_suffix.at(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {std::stoi(toks.at(0)), std::stoi(toks.at(1)), std::move(qualifier)};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_subexpr_of(const clang::Stmt *parent_stmt, const clang::Stmt *sub_stmt)
|
bool is_subexpr_of(const clang::Stmt *parent_stmt, const clang::Stmt *sub_stmt)
|
||||||
|
|||||||
@@ -98,8 +98,8 @@ std::string get_source_text_raw(
|
|||||||
std::string get_source_text(
|
std::string get_source_text(
|
||||||
clang::SourceRange range, const clang::SourceManager &sm);
|
clang::SourceRange range, const clang::SourceManager &sm);
|
||||||
|
|
||||||
std::pair<unsigned int, unsigned int> extract_template_parameter_index(
|
std::tuple<unsigned int, unsigned int, std::string>
|
||||||
const std::string &type_parameter);
|
extract_template_parameter_index(const std::string &type_parameter);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Check if an expression is contained in another expression
|
* @brief Check if an expression is contained in another expression
|
||||||
|
|||||||
@@ -215,6 +215,13 @@ std::string template_parameter::to_string(
|
|||||||
"{}({})", return_type, fmt::join(function_args, ","));
|
"{}({})", return_type, fmt::join(function_args, ","));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_method_template()) {
|
||||||
|
assert(template_params().size() == 2);
|
||||||
|
|
||||||
|
return fmt::format("{} {}::*{}", template_params().at(0).name().value(),
|
||||||
|
template_params().at(1).name().value(), method_qualifier());
|
||||||
|
}
|
||||||
|
|
||||||
std::string res;
|
std::string res;
|
||||||
const auto maybe_type = type();
|
const auto maybe_type = type();
|
||||||
if (maybe_type) {
|
if (maybe_type) {
|
||||||
|
|||||||
@@ -182,6 +182,14 @@ public:
|
|||||||
|
|
||||||
bool is_function_template() const { return is_function_template_; }
|
bool is_function_template() const { return is_function_template_; }
|
||||||
|
|
||||||
|
void set_method_template(bool mt) { is_method_template_ = mt; }
|
||||||
|
|
||||||
|
bool is_method_template() const { return is_method_template_; }
|
||||||
|
|
||||||
|
void set_method_qualifier(const std::string &q) { method_qualifier_ = q; }
|
||||||
|
|
||||||
|
const std::string &method_qualifier() const { return method_qualifier_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template_parameter() = default;
|
template_parameter() = default;
|
||||||
|
|
||||||
@@ -210,6 +218,10 @@ private:
|
|||||||
|
|
||||||
bool is_function_template_{false};
|
bool is_function_template_{false};
|
||||||
|
|
||||||
|
bool is_method_template_{false};
|
||||||
|
|
||||||
|
std::string method_qualifier_;
|
||||||
|
|
||||||
/// Stores optional fully qualified name of constraint for this template
|
/// Stores optional fully qualified name of constraint for this template
|
||||||
/// parameter
|
/// parameter
|
||||||
std::optional<std::string> concept_constraint_;
|
std::optional<std::string> concept_constraint_;
|
||||||
|
|||||||
@@ -94,6 +94,35 @@ TEST_CASE("Test replace_all", "[unit-test]")
|
|||||||
CHECK(text == orig);
|
CHECK(text == orig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test extract_template_parameter_index", "[unit-test]")
|
||||||
|
{
|
||||||
|
using namespace clanguml::common;
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto [depth, index, qualifier] =
|
||||||
|
extract_template_parameter_index("type-parameter-0-0");
|
||||||
|
CHECK(depth == 0);
|
||||||
|
CHECK(index == 0);
|
||||||
|
CHECK(qualifier.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto [depth, index, qualifier] =
|
||||||
|
extract_template_parameter_index("type-parameter-0-0 &&");
|
||||||
|
CHECK(depth == 0);
|
||||||
|
CHECK(index == 0);
|
||||||
|
CHECK(qualifier == "&&");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto [depth, index, qualifier] =
|
||||||
|
extract_template_parameter_index("type-parameter-12-678 const&");
|
||||||
|
CHECK(depth == 12);
|
||||||
|
CHECK(index == 678);
|
||||||
|
CHECK(qualifier == "const&");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("Test parse_unexposed_template_params", "[unit-test]")
|
TEST_CASE("Test parse_unexposed_template_params", "[unit-test]")
|
||||||
{
|
{
|
||||||
using namespace clanguml::common;
|
using namespace clanguml::common;
|
||||||
|
|||||||
Reference in New Issue
Block a user