Fixed handling of template function specialization arguments
This commit is contained in:
@@ -126,9 +126,19 @@ int class_::calculate_template_specialization_match(
|
||||
{
|
||||
int res{};
|
||||
|
||||
LOG_DBG("### Comparing {} with {}", this->full_name(false),
|
||||
other.full_name(false));
|
||||
|
||||
if (this->full_name(false) ==
|
||||
"clanguml::t00044::signal_handler<Ret(Args...),A>" &&
|
||||
other.full_name(false) ==
|
||||
"clanguml::t00044::signal_handler<void(int),bool>") {
|
||||
LOG_DBG("AAAAAAAAA");
|
||||
}
|
||||
|
||||
const std::string left = name_and_ns();
|
||||
// TODO: handle variadic templates
|
||||
if ((name_and_ns() != full_name) ||
|
||||
if ((left != full_name) ||
|
||||
(templates().size() != other.templates().size())) {
|
||||
return res;
|
||||
}
|
||||
@@ -142,6 +152,10 @@ int class_::calculate_template_specialization_match(
|
||||
res++;
|
||||
}
|
||||
else if (other_template_arg.is_specialization_of(template_arg)) {
|
||||
if (template_arg.is_function_template() &&
|
||||
other_template_arg.is_function_template()) {
|
||||
res++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -250,7 +250,7 @@ bool translation_unit_visitor::VisitTypeAliasTemplateDecl(
|
||||
return true;
|
||||
|
||||
auto template_specialization_ptr =
|
||||
build_template_instantiation(*template_type_specialization_ptr);
|
||||
build_template_instantiation(cls, *template_type_specialization_ptr);
|
||||
|
||||
if (!template_specialization_ptr)
|
||||
return true;
|
||||
@@ -630,8 +630,8 @@ void translation_unit_visitor::process_concept_specialization_relationships(
|
||||
std::vector<std::string> constrained_template_params;
|
||||
|
||||
size_t argument_index{};
|
||||
for (const auto ta : concept_specialization->getTemplateArguments()) {
|
||||
|
||||
for (const auto ta : concept_specialization->getTemplateArguments()) {
|
||||
if (ta.getKind() == clang::TemplateArgument::Type) {
|
||||
auto type_name =
|
||||
common::to_string(ta.getAsType(), cpt->getASTContext());
|
||||
@@ -1092,7 +1092,7 @@ void translation_unit_visitor::process_class_bases(
|
||||
base.getType()->getAs<clang::TemplateSpecializationType>();
|
||||
tsp != nullptr) {
|
||||
auto template_specialization_ptr =
|
||||
build_template_instantiation(*tsp, {});
|
||||
build_template_instantiation(cls, *tsp, {});
|
||||
if (template_specialization_ptr) {
|
||||
cp.set_id(template_specialization_ptr->id());
|
||||
}
|
||||
@@ -1350,7 +1350,7 @@ void translation_unit_visitor::process_method(
|
||||
}
|
||||
else if (const auto *atsp = underlying_type->getAs<clang::AutoType>();
|
||||
atsp != nullptr) {
|
||||
process_function_parameter_find_relatinoships_in_autotype(c, atsp);
|
||||
process_function_parameter_find_relationships_in_autotype(c, atsp);
|
||||
}
|
||||
|
||||
LOG_DBG("Adding method: {}", method.name());
|
||||
@@ -1359,7 +1359,7 @@ void translation_unit_visitor::process_method(
|
||||
}
|
||||
|
||||
void translation_unit_visitor::
|
||||
process_function_parameter_find_relatinoships_in_autotype(
|
||||
process_function_parameter_find_relationships_in_autotype(
|
||||
class_ &c, const clang::AutoType *atsp)
|
||||
{
|
||||
auto desugared_atsp = atsp->getDeducedType();
|
||||
@@ -1665,8 +1665,9 @@ void translation_unit_visitor::
|
||||
template_instantiation_type.getTemplateName().getAsTemplateDecl()))
|
||||
return;
|
||||
|
||||
auto template_specialization_ptr =
|
||||
build_template_instantiation(template_instantiation_type, &c);
|
||||
auto template_specialization_ptr = build_template_instantiation(
|
||||
template_instantiation_type.getTemplateName().getAsTemplateDecl(),
|
||||
template_instantiation_type, &c);
|
||||
|
||||
if (template_instantiation_type.isDependentType()) {
|
||||
if (template_specialization_ptr) {
|
||||
@@ -1816,9 +1817,93 @@ void translation_unit_visitor::process_template_specialization_argument(
|
||||
|
||||
// If this is a nested template type - add nested templates as
|
||||
// template arguments
|
||||
if (const auto *nested_template_type =
|
||||
arg.getAsType()->getAs<clang::TemplateSpecializationType>();
|
||||
nested_template_type != nullptr) {
|
||||
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 =
|
||||
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 = 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;
|
||||
|
||||
// auto *classTemplateSpecialization =
|
||||
// llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(
|
||||
// param_type->getAsRecordDecl());
|
||||
/*
|
||||
if (classTemplateSpecialization != nullptr) {
|
||||
// Read arg info as needed.
|
||||
auto nested_template_instantiation =
|
||||
build_template_instantiation_from_class_template_specialization(
|
||||
*classTemplateSpecialization, *param_record_type,
|
||||
diagram().should_include(
|
||||
full_template_specialization_name)
|
||||
? std::make_optional(&template_instantiation)
|
||||
: parent);
|
||||
|
||||
const auto nested_template_name =
|
||||
classTemplateSpecialization->getQualifiedNameAsString();
|
||||
|
||||
if (nested_template_instantiation) {
|
||||
if (parent.has_value())
|
||||
parent.value()->add_relationship(
|
||||
{relationship_t::kDependency,
|
||||
nested_template_instantiation->id()});
|
||||
}
|
||||
|
||||
auto nested_template_instantiation_full_name =
|
||||
nested_template_instantiation->full_name(false);
|
||||
if (diagram().should_include(
|
||||
nested_template_instantiation_full_name)) {
|
||||
diagram().add_class(
|
||||
std::move(nested_template_instantiation));
|
||||
}
|
||||
}*/
|
||||
|
||||
}
|
||||
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 =
|
||||
@@ -1829,7 +1914,7 @@ void translation_unit_visitor::process_template_specialization_argument(
|
||||
argument->set_type(nested_template_name);
|
||||
|
||||
auto nested_template_instantiation = build_template_instantiation(
|
||||
*nested_template_type, {&template_instantiation});
|
||||
cls, *nested_template_type, {&template_instantiation});
|
||||
|
||||
argument->set_id(nested_template_instantiation->id());
|
||||
|
||||
@@ -2054,7 +2139,7 @@ std::unique_ptr<class_> translation_unit_visitor::
|
||||
std::hash<std::string>{}(full_template_specialization_name) >> 4U));
|
||||
|
||||
build_template_instantiation_process_template_arguments(parent,
|
||||
template_base_params,
|
||||
&template_specialization, template_base_params,
|
||||
template_specialization.getTemplateArgs().asArray(),
|
||||
template_instantiation, full_template_specialization_name,
|
||||
template_decl);
|
||||
@@ -2106,6 +2191,7 @@ std::unique_ptr<class_> translation_unit_visitor::
|
||||
}
|
||||
|
||||
std::unique_ptr<class_> translation_unit_visitor::build_template_instantiation(
|
||||
const clang::Decl *cls,
|
||||
const clang::TemplateSpecializationType &template_type_decl,
|
||||
std::optional<clanguml::class_diagram::model::class_ *> parent)
|
||||
{
|
||||
@@ -2136,7 +2222,9 @@ std::unique_ptr<class_> translation_unit_visitor::build_template_instantiation(
|
||||
//
|
||||
auto template_instantiation_ptr =
|
||||
std::make_unique<class_>(config_.using_namespace());
|
||||
|
||||
auto &template_instantiation = *template_instantiation_ptr;
|
||||
|
||||
std::string full_template_specialization_name = common::to_string(
|
||||
template_type.desugar(),
|
||||
template_type.getTemplateName().getAsTemplateDecl()->getASTContext());
|
||||
@@ -2240,7 +2328,7 @@ std::unique_ptr<class_> translation_unit_visitor::build_template_instantiation(
|
||||
base_index++;
|
||||
}
|
||||
|
||||
build_template_instantiation_process_template_arguments(parent,
|
||||
build_template_instantiation_process_template_arguments(parent, cls,
|
||||
template_base_params, template_type.template_arguments(),
|
||||
template_instantiation, full_template_specialization_name,
|
||||
template_decl);
|
||||
@@ -2302,6 +2390,7 @@ std::unique_ptr<class_> translation_unit_visitor::build_template_instantiation(
|
||||
void translation_unit_visitor::
|
||||
build_template_instantiation_process_template_arguments(
|
||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
||||
const clang::Decl *cls,
|
||||
std::deque<std::tuple<std::string, int, bool>> &template_base_params,
|
||||
const clang::ArrayRef<clang::TemplateArgument> &template_args,
|
||||
class_ &template_instantiation,
|
||||
@@ -2318,8 +2407,8 @@ void translation_unit_visitor::
|
||||
}
|
||||
else if (argument_kind == clang::TemplateArgument::Type) {
|
||||
argument = build_template_instantiation_process_type_argument(
|
||||
parent, full_template_specialization_name, template_decl, arg,
|
||||
template_instantiation);
|
||||
parent, cls, full_template_specialization_name, template_decl,
|
||||
arg, template_instantiation);
|
||||
}
|
||||
else if (argument_kind == clang::TemplateArgument::Integral) {
|
||||
argument =
|
||||
@@ -2374,6 +2463,7 @@ template_parameter translation_unit_visitor::
|
||||
template_parameter
|
||||
translation_unit_visitor::build_template_instantiation_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::TemplateArgument &arg, class_ &template_instantiation)
|
||||
@@ -2382,13 +2472,45 @@ translation_unit_visitor::build_template_instantiation_process_type_argument(
|
||||
|
||||
auto argument = template_parameter::make_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) {
|
||||
|
||||
argument.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 =
|
||||
get_template_argument_from_type_parameter_string(
|
||||
cls, return_type_name);
|
||||
|
||||
if (maybe_return_arg)
|
||||
argument.add_template_param(*maybe_return_arg);
|
||||
else {
|
||||
argument.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 = get_template_argument_from_type_parameter_string(
|
||||
cls, param_type.getAsString());
|
||||
|
||||
if (maybe_arg) {
|
||||
argument.add_template_param(*maybe_arg);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (param_type->isBuiltinType()) {
|
||||
argument.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)
|
||||
@@ -2428,6 +2550,14 @@ translation_unit_visitor::build_template_instantiation_process_type_argument(
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (const auto maybe_arg =
|
||||
get_template_argument_from_type_parameter_string(
|
||||
cls, arg.getAsType().getAsString());
|
||||
maybe_arg) {
|
||||
// The type is only in the form 'type-parameter-X-Y' so we have
|
||||
// to match it to a template parameter name in the 'cls' template
|
||||
argument = *maybe_arg;
|
||||
}
|
||||
else if (const auto *nested_template_type =
|
||||
arg.getAsType()->getAs<clang::TemplateSpecializationType>();
|
||||
nested_template_type != nullptr) {
|
||||
@@ -2439,7 +2569,7 @@ translation_unit_visitor::build_template_instantiation_process_type_argument(
|
||||
argument.set_type(nested_type_name);
|
||||
|
||||
auto nested_template_instantiation =
|
||||
build_template_instantiation(*nested_template_type,
|
||||
build_template_instantiation(cls, *nested_template_type,
|
||||
diagram().should_include(full_template_specialization_name)
|
||||
? std::make_optional(&template_instantiation)
|
||||
: parent);
|
||||
@@ -2492,6 +2622,40 @@ translation_unit_visitor::build_template_instantiation_process_type_argument(
|
||||
return argument;
|
||||
}
|
||||
|
||||
std::optional<template_parameter>
|
||||
translation_unit_visitor::get_template_argument_from_type_parameter_string(
|
||||
const clang::Decl *decl, const std::string &return_type_name) const
|
||||
{
|
||||
if (const auto *template_decl =
|
||||
llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(decl);
|
||||
template_decl && return_type_name.find("type-parameter-") == 0) {
|
||||
|
||||
[[maybe_unused]] const auto [depth, index] =
|
||||
common::extract_template_parameter_index(return_type_name);
|
||||
|
||||
std::string param_name = return_type_name;
|
||||
|
||||
for (auto i = 0U;
|
||||
i < template_decl->getDescribedTemplateParams()->size(); i++) {
|
||||
const auto *param =
|
||||
template_decl->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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
template_parameter translation_unit_visitor::
|
||||
build_template_instantiation_process_integral_argument(
|
||||
const clang::TemplateArgument &arg) const
|
||||
@@ -2690,8 +2854,8 @@ void translation_unit_visitor::process_field(
|
||||
!field_type_is_template_template_parameter) {
|
||||
|
||||
// Build the template instantiation for the field type
|
||||
auto template_specialization_ptr =
|
||||
build_template_instantiation(*template_field_type, {&c});
|
||||
auto template_specialization_ptr = build_template_instantiation(
|
||||
&field_declaration, *template_field_type, {&c});
|
||||
|
||||
if (!field.skip_relationship() && template_specialization_ptr) {
|
||||
const auto &template_specialization = *template_specialization_ptr;
|
||||
|
||||
@@ -187,7 +187,7 @@ private:
|
||||
bool break_on_first_aggregation = false);
|
||||
|
||||
std::unique_ptr<clanguml::class_diagram::model::class_>
|
||||
build_template_instantiation(
|
||||
build_template_instantiation(const clang::Decl *cls,
|
||||
const clang::TemplateSpecializationType &template_type,
|
||||
std::optional<clanguml::class_diagram::model::class_ *> parent = {});
|
||||
|
||||
@@ -205,6 +205,7 @@ private:
|
||||
|
||||
void build_template_instantiation_process_template_arguments(
|
||||
std::optional<clanguml::class_diagram::model::class_ *> &parent,
|
||||
const clang::Decl *cls,
|
||||
std::deque<std::tuple<std::string, int, bool>> &template_base_params,
|
||||
const clang::ArrayRef<clang::TemplateArgument> &template_args,
|
||||
model::class_ &template_instantiation,
|
||||
@@ -226,6 +227,7 @@ private:
|
||||
|
||||
template_parameter build_template_instantiation_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::TemplateArgument &arg,
|
||||
@@ -240,7 +242,7 @@ private:
|
||||
void process_record_parent(
|
||||
clang::RecordDecl *cls, class_ &c, const namespace_ &ns);
|
||||
|
||||
void process_function_parameter_find_relatinoships_in_autotype(
|
||||
void process_function_parameter_find_relationships_in_autotype(
|
||||
model::class_ &c, const clang::AutoType *atsp);
|
||||
|
||||
void process_function_parameter_find_relationships_in_template(
|
||||
@@ -279,6 +281,10 @@ private:
|
||||
std::vector<std::string> &constrained_template_params,
|
||||
size_t argument_index, std::string &type_name) const;
|
||||
|
||||
std::optional<template_parameter>
|
||||
get_template_argument_from_type_parameter_string(
|
||||
const clang::Decl *decl, const std::string &return_type_name) const;
|
||||
|
||||
/// Store the mapping from local clang entity id (obtained using
|
||||
/// getID()) method to clang-uml global id
|
||||
void set_ast_local_id(
|
||||
|
||||
@@ -250,6 +250,19 @@ std::string get_source_text(
|
||||
return get_source_text_raw(printable_range, sm);
|
||||
}
|
||||
|
||||
std::pair<unsigned int, unsigned int> extract_template_parameter_index(
|
||||
const std::string &type_parameter)
|
||||
{
|
||||
assert(type_parameter.find("type-parameter-") == 0);
|
||||
|
||||
auto toks =
|
||||
util::split(type_parameter.substr(strlen("type-parameter-")), "-");
|
||||
|
||||
assert(toks.size() == 2);
|
||||
|
||||
return {std::stoi(toks.at(0)), std::stoi(toks.at(1))};
|
||||
}
|
||||
|
||||
bool is_subexpr_of(const clang::Stmt *parent_stmt, const clang::Stmt *sub_stmt)
|
||||
{
|
||||
if (parent_stmt == nullptr || sub_stmt == nullptr)
|
||||
|
||||
@@ -95,6 +95,9 @@ std::string get_source_text_raw(
|
||||
std::string get_source_text(
|
||||
clang::SourceRange range, const clang::SourceManager &sm);
|
||||
|
||||
std::pair<unsigned int, unsigned int> extract_template_parameter_index(
|
||||
const std::string &type_parameter);
|
||||
|
||||
/**
|
||||
* @brief Check if an expression is contained in another expression
|
||||
*
|
||||
|
||||
@@ -111,6 +111,11 @@ bool template_parameter::is_variadic() const noexcept { return is_variadic_; }
|
||||
bool template_parameter::is_specialization_of(
|
||||
const template_parameter &ct) const
|
||||
{
|
||||
if(is_function_template() && ct.is_function_template()) {
|
||||
bool res{true};
|
||||
|
||||
}
|
||||
|
||||
return (ct.is_template_parameter() ||
|
||||
ct.is_template_template_parameter()) &&
|
||||
!is_template_parameter();
|
||||
@@ -139,6 +144,9 @@ bool operator==(const template_parameter &l, const template_parameter &r)
|
||||
if (l.is_template_parameter() != r.is_template_parameter())
|
||||
return res;
|
||||
|
||||
if (l.is_function_template() != r.is_function_template())
|
||||
return res;
|
||||
|
||||
if (l.is_template_parameter()) {
|
||||
// If this is a template parameter (e.g. 'typename T' or 'typename U'
|
||||
// we don't actually care what it is called
|
||||
@@ -165,6 +173,19 @@ std::string template_parameter::to_string(
|
||||
|
||||
assert(!(type().has_value() && concept_constraint().has_value()));
|
||||
|
||||
if (is_function_template()) {
|
||||
auto it = template_params_.begin();
|
||||
auto return_type = it->to_string(using_namespace, relative);
|
||||
std::advance(it, 1);
|
||||
|
||||
std::vector<std::string> function_args;
|
||||
for (; it != template_params_.end(); it++)
|
||||
function_args.push_back(it->to_string(using_namespace, relative));
|
||||
|
||||
return fmt::format(
|
||||
"{}({})", return_type, fmt::join(function_args, ","));
|
||||
}
|
||||
|
||||
std::string res;
|
||||
const auto maybe_type = type();
|
||||
if (maybe_type) {
|
||||
|
||||
@@ -176,6 +176,10 @@ public:
|
||||
|
||||
void set_unexposed(bool unexposed) { is_unexposed_ = unexposed; }
|
||||
|
||||
void set_function_template(bool ft) { is_function_template_ = ft; }
|
||||
|
||||
bool is_function_template() const { return is_function_template_; }
|
||||
|
||||
private:
|
||||
template_parameter() = default;
|
||||
|
||||
@@ -202,11 +206,14 @@ private:
|
||||
/// Whether the template parameter is variadic
|
||||
bool is_variadic_{false};
|
||||
|
||||
bool is_function_template_{false};
|
||||
|
||||
/// Stores optional fully qualified name of constraint for this template
|
||||
/// parameter
|
||||
std::optional<std::string> concept_constraint_;
|
||||
|
||||
// Nested template parameters
|
||||
// If this is a function template, the first element is the return type
|
||||
std::vector<template_parameter> template_params_;
|
||||
|
||||
std::optional<int64_t> id_;
|
||||
|
||||
@@ -29,6 +29,8 @@ sink(signal_handler<Ret(Args...), A> &)
|
||||
|
||||
signal_handler<void(int), bool> int_handler;
|
||||
|
||||
sink sink1{int_handler};
|
||||
struct R {
|
||||
sink<signal_handler<void(int), bool>> sink1{int_handler};
|
||||
};
|
||||
|
||||
} // namespace clanguml::t00044
|
||||
|
||||
@@ -35,10 +35,28 @@ TEST_CASE("t00044", "[test-case][class]")
|
||||
REQUIRE_THAT(puml, StartsWith("@startuml"));
|
||||
REQUIRE_THAT(puml, EndsWith("@enduml\n"));
|
||||
|
||||
// TODO:
|
||||
// Check dependants filter<void(int), bool>
|
||||
// REQUIRE_THAT(puml, IsClassTemplate("signal_handler",
|
||||
// "Ret,Args...,A"));
|
||||
REQUIRE_THAT(puml, IsClassTemplate("sink", "T"));
|
||||
REQUIRE_THAT(puml, IsClassTemplate("signal_handler", "T,A"));
|
||||
|
||||
REQUIRE_THAT(puml, IsClassTemplate("signal_handler", "Ret(Args...),A"));
|
||||
REQUIRE_THAT(puml, IsClassTemplate("signal_handler", "void(int),bool"));
|
||||
|
||||
REQUIRE_THAT(puml,
|
||||
IsClassTemplate(
|
||||
"sink", "clanguml::t00044::signal_handler<Ret(Args...),A>"));
|
||||
|
||||
REQUIRE_THAT(puml,
|
||||
IsInstantiation(_A("sink<T>"),
|
||||
_A("sink<clanguml::t00044::signal_handler<Ret(Args...),A>>")));
|
||||
|
||||
REQUIRE_THAT(puml, IsClassTemplate("signal_handler", "T,A"));
|
||||
REQUIRE_THAT(puml,
|
||||
IsInstantiation(_A("signal_handler<T,A>"),
|
||||
_A("signal_handler<Ret(Args...),A>")));
|
||||
|
||||
REQUIRE_THAT(puml,
|
||||
IsInstantiation(_A("signal_handler<Ret(Args...),A>"),
|
||||
_A("signal_handler<void(int),bool>")));
|
||||
|
||||
save_puml(
|
||||
config.output_directory() + "/" + diagram->name + ".puml", puml);
|
||||
|
||||
Reference in New Issue
Block a user