From 425a13ec5b1acfac2e75fb2eb0eb1fff18dc2b59 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Wed, 5 Apr 2023 00:22:29 +0200 Subject: [PATCH] Fixed t00044 --- src/class_diagram/model/class.cc | 36 +--- .../visitor/translation_unit_visitor.cc | 42 +---- src/common/model/template_parameter.cc | 56 +++++- src/common/model/template_parameter.h | 3 +- src/common/model/template_trait.cc | 19 +- tests/t00044/test_case.h | 5 + tests/test_model.cc | 162 +++++++++++++++++- 7 files changed, 235 insertions(+), 88 deletions(-) diff --git a/src/class_diagram/model/class.cc b/src/class_diagram/model/class.cc index 45fb018f..754741e3 100644 --- a/src/class_diagram/model/class.cc +++ b/src/class_diagram/model/class.cc @@ -124,17 +124,7 @@ bool class_::is_abstract() const int class_::calculate_template_specialization_match( const class_ &other, const std::string &full_name) const { - int res{}; - - LOG_DBG("### Comparing {} with {}", this->full_name(false), - other.full_name(false)); - - if (this->full_name(false) == - "clanguml::t00044::signal_handler" && - other.full_name(false) == - "clanguml::t00044::signal_handler") { - LOG_DBG("AAAAAAAAA"); - } + int res{0}; const std::string left = name_and_ns(); // TODO: handle variadic templates @@ -143,27 +133,7 @@ int class_::calculate_template_specialization_match( return res; } - // Iterate over all template arguments - for (auto i = 0U; i < other.templates().size(); i++) { - const auto &template_arg = templates().at(i); - const auto &other_template_arg = other.templates().at(i); - - if (template_arg == other_template_arg) { - 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 { - res = 0; - break; - } - } - - return res; + return template_trait::calculate_template_specialization_match( + other, full_name); } } // namespace clanguml::class_diagram::model diff --git a/src/class_diagram/visitor/translation_unit_visitor.cc b/src/class_diagram/visitor/translation_unit_visitor.cc index c3e2fb03..77fc8bae 100644 --- a/src/class_diagram/visitor/translation_unit_visitor.cc +++ b/src/class_diagram/visitor/translation_unit_visitor.cc @@ -1836,7 +1836,7 @@ void translation_unit_visitor::process_template_specialization_argument( cls, return_type_name); if (maybe_return_arg) - a .add_template_param(*maybe_return_arg); + a.add_template_param(*maybe_return_arg); else { a.add_template_param( template_parameter::make_argument(return_type_name)); @@ -1844,8 +1844,9 @@ void translation_unit_visitor::process_template_specialization_argument( // 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()); + auto maybe_arg = + get_template_argument_from_type_parameter_string( + cls, param_type.getAsString()); if (maybe_arg) { a.add_template_param(*maybe_arg); @@ -1862,43 +1863,8 @@ void translation_unit_visitor::process_template_specialization_argument( param_type->getAs(); if (param_record_type == nullptr) continue; - -// auto *classTemplateSpecialization = -// llvm::dyn_cast( -// 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() diff --git a/src/common/model/template_parameter.cc b/src/common/model/template_parameter.cc index 213ed51b..166b3b06 100644 --- a/src/common/model/template_parameter.cc +++ b/src/common/model/template_parameter.cc @@ -108,17 +108,59 @@ void template_parameter::is_variadic(bool is_variadic) noexcept bool template_parameter::is_variadic() const noexcept { return is_variadic_; } -bool template_parameter::is_specialization_of( +int template_parameter::calculate_specialization_match( const template_parameter &ct) const { - if(is_function_template() && ct.is_function_template()) { - bool res{true}; - + int res{0}; + + if (ct.type().has_value() && type().has_value() && + !ct.is_template_parameter() && !is_template_parameter() && + ct.type().value() != type().value()) + return 0; + + if (ct.is_function_template() && !is_function_template()) + return 0; + + if (template_params().size() > 0 && ct.template_params().size() > 0) { + // More generic template params + const auto &template_params = ct.template_params(); + const auto &specialization_params = this->template_params(); + auto template_index{0U}; + auto arg_index{0U}; + + while (arg_index < specialization_params.size() && + template_index < template_params.size()) { + auto match = specialization_params.at(arg_index) + .calculate_specialization_match( + template_params.at(template_index)); + + if (match == 0) { + return 0; + } + + if (!template_params.at(template_index).is_variadic()) + template_index++; + + res += match; + + // Add 1 point for argument match + if (!specialization_params.at(arg_index).is_template_parameter()) + res++; + + arg_index++; + } + + if (arg_index == specialization_params.size()) + return res; + else + return 0; } - return (ct.is_template_parameter() || - ct.is_template_template_parameter()) && - !is_template_parameter(); + if ((ct.is_template_parameter() || ct.is_template_template_parameter()) && + !is_template_parameter()) + return 1; + + return 0; } void template_parameter::add_template_param(template_parameter &&ct) diff --git a/src/common/model/template_parameter.h b/src/common/model/template_parameter.h index fe9a1c74..005e3688 100644 --- a/src/common/model/template_parameter.h +++ b/src/common/model/template_parameter.h @@ -52,6 +52,7 @@ public: p.set_kind(template_parameter_kind_t::template_type); p.set_name(name); p.is_variadic(is_variadic); + p.is_template_parameter(true); if (default_value) p.set_default_value(default_value.value()); return p; @@ -121,7 +122,7 @@ public: void is_variadic(bool is_variadic) noexcept; bool is_variadic() const noexcept; - bool is_specialization_of(const template_parameter &ct) const; + int calculate_specialization_match(const template_parameter &ct) const; friend bool operator==( const template_parameter &l, const template_parameter &r); diff --git a/src/common/model/template_trait.cc b/src/common/model/template_trait.cc index 31e7ad2e..626ff5f2 100644 --- a/src/common/model/template_trait.cc +++ b/src/common/model/template_trait.cc @@ -66,12 +66,7 @@ const std::vector &template_trait::templates() const int template_trait::calculate_template_specialization_match( const template_trait &other, const std::string & /*full_name*/) const { - int res{}; - - // TODO: handle variadic templates - if (templates().size() != other.templates().size()) { - return res; - } + int res{0}; // Iterate over all template arguments for (auto i = 0U; i < other.templates().size(); i++) { @@ -80,9 +75,17 @@ int template_trait::calculate_template_specialization_match( if (template_arg == other_template_arg) { res++; + + if (!template_arg.is_template_parameter()) + res++; + + if (!other_template_arg.is_template_parameter()) + res++; } - else if (other_template_arg.is_specialization_of(template_arg)) { - continue; + else if (auto match = other_template_arg.calculate_specialization_match( + template_arg); + match > 0) { + res += match; } else { res = 0; diff --git a/tests/t00044/test_case.h b/tests/t00044/test_case.h index 425502b0..aea3c283 100644 --- a/tests/t00044/test_case.h +++ b/tests/t00044/test_case.h @@ -49,6 +49,11 @@ TEST_CASE("t00044", "[test-case][class]") IsInstantiation(_A("sink"), _A("sink>"))); + REQUIRE_THAT(puml, + IsInstantiation( + _A("sink>"), + _A("sink>"))); + REQUIRE_THAT(puml, IsClassTemplate("signal_handler", "T,A")); REQUIRE_THAT(puml, IsInstantiation(_A("signal_handler"), diff --git a/tests/test_model.cc b/tests/test_model.cc index 05ebd01e..b234a78a 100644 --- a/tests/test_model.cc +++ b/tests/test_model.cc @@ -20,6 +20,7 @@ #include "catch.h" #include "common/model/namespace.h" +#include "common/model/template_parameter.h" TEST_CASE("Test namespace_", "[unit-test]") { @@ -69,4 +70,163 @@ TEST_CASE("Test namespace_", "[unit-test]") namespace_ ns8{"aaa::bbb"}; const std::string name{"aaa::bbb::ccc>"}; CHECK(ns8.relative(name) == "ccc>"); -} \ No newline at end of file +} + +TEST_CASE( + "Test template_parameter::calculate_specialization_match", "[unit-test]") +{ + using clanguml::common::model::template_parameter; + + { + auto tp1 = template_parameter::make_template_type("T"); + auto tp2 = template_parameter::make_argument("int"); + + CHECK(tp2.calculate_specialization_match(tp1)); + } + + { + auto tp1 = template_parameter::make_template_type("T"); + auto tp2 = template_parameter::make_argument("vector"); + tp2.add_template_param(template_parameter::make_argument("int")); + + CHECK(tp2.calculate_specialization_match(tp1)); + } + + { + auto tp1 = template_parameter::make_argument("vector"); + tp1.add_template_param(template_parameter::make_template_type("T")); + + auto tp2 = template_parameter::make_argument("vector"); + tp2.add_template_param(template_parameter::make_argument("int")); + + CHECK(tp2.calculate_specialization_match(tp1)); + } + + { + auto tp1 = template_parameter::make_argument("vector"); + tp1.add_template_param(template_parameter::make_template_type("T")); + + auto tp2 = template_parameter::make_argument("string"); + tp2.add_template_param(template_parameter::make_argument("char")); + + CHECK(!tp2.calculate_specialization_match(tp1)); + } + + { + auto tp1 = template_parameter::make_argument("tuple"); + tp1.add_template_param( + template_parameter::make_template_type("Args", {}, true)); + + auto tp2 = template_parameter::make_argument("tuple"); + tp2.add_template_param(template_parameter::make_argument("char")); + tp2.add_template_param(template_parameter::make_argument("int")); + tp2.add_template_param(template_parameter::make_argument("double")); + + CHECK(tp2.calculate_specialization_match(tp1)); + } + + { + auto tp1 = template_parameter::make_argument("tuple"); + tp1.add_template_param( + template_parameter::make_template_type("Args", {}, true)); + tp1.add_template_param(template_parameter::make_argument("int")); + + auto tp2 = template_parameter::make_argument("tuple"); + tp2.add_template_param(template_parameter::make_argument("char")); + tp2.add_template_param(template_parameter::make_argument("int")); + tp2.add_template_param(template_parameter::make_argument("double")); + + CHECK(!tp2.calculate_specialization_match(tp1)); + } + + { + auto tp1 = template_parameter::make_argument("tuple"); + tp1.add_template_param(template_parameter::make_template_type("T1")); + tp1.add_template_param(template_parameter::make_template_type("T2")); + + auto tp2 = template_parameter::make_argument("tuple"); + tp2.add_template_param(template_parameter::make_argument("char")); + tp2.add_template_param(template_parameter::make_argument("int")); + tp2.add_template_param(template_parameter::make_argument("double")); + + CHECK(!tp2.calculate_specialization_match(tp1)); + } + + { + auto tp1 = template_parameter::make_template_type({}); + tp1.set_function_template(true); + tp1.add_template_param(template_parameter::make_template_type("Ret")); + tp1.add_template_param(template_parameter::make_template_type("Arg1")); + tp1.add_template_param(template_parameter::make_template_type("Arg2")); + + auto tp2 = template_parameter::make_argument({}); + tp2.set_function_template(true); + tp2.add_template_param(template_parameter::make_argument("char")); + tp2.add_template_param(template_parameter::make_argument("int")); + tp2.add_template_param(template_parameter::make_argument("double")); + + CHECK(tp2.calculate_specialization_match(tp1)); + } + + { + auto tp1 = template_parameter::make_template_type({}); + tp1.set_function_template(true); + tp1.add_template_param(template_parameter::make_template_type("Ret")); + tp1.add_template_param(template_parameter::make_template_type("Arg1")); + tp1.add_template_param(template_parameter::make_template_type("Arg2")); + + auto tp2 = template_parameter::make_argument({}); + tp2.set_function_template(false); + tp2.add_template_param(template_parameter::make_argument("char")); + tp2.add_template_param(template_parameter::make_argument("int")); + tp2.add_template_param(template_parameter::make_argument("double")); + + CHECK(!tp2.calculate_specialization_match(tp1)); + } + + { + auto tp1 = template_parameter::make_template_type({}); + tp1.set_function_template(true); + tp1.add_template_param(template_parameter::make_template_type("Ret")); + tp1.add_template_param( + template_parameter::make_template_type("Args", {}, true)); + + auto tp2 = template_parameter::make_argument({}); + tp2.set_function_template(true); + tp2.add_template_param(template_parameter::make_argument("char")); + tp2.add_template_param(template_parameter::make_argument("int")); + tp2.add_template_param(template_parameter::make_argument("double")); + + CHECK(tp2.calculate_specialization_match(tp1)); + } + + { + auto sink_t = template_parameter::make_argument("sink"); + auto sh1 = + template_parameter::make_argument("ns1::ns2::signal_handler"); + auto sh1_t1 = template_parameter::make_template_type({}); + sh1_t1.set_function_template(true); + sh1_t1.add_template_param( + template_parameter::make_template_type("Ret")); + sh1_t1.add_template_param( + template_parameter::make_template_type("Args", {}, true)); + auto sh1_t2 = template_parameter::make_template_type("A"); + sh1.add_template_param(sh1_t1); + sh1.add_template_param(sh1_t2); + sink_t.add_template_param(sh1); + + auto sink_s = template_parameter::make_argument("sink"); + auto sh2 = + template_parameter::make_argument("ns1::ns2::signal_handler"); + auto sh2_a1 = template_parameter::make_argument({}); + sh2_a1.set_function_template(true); + sh2_a1.add_template_param(template_parameter::make_argument("void")); + sh2_a1.add_template_param(template_parameter::make_argument("int")); + auto sh2_a2 = template_parameter::make_argument("bool"); + sh2.add_template_param(sh2_a1); + sh2.add_template_param(sh2_a2); + sink_s.add_template_param(sh2); + + CHECK(sink_s.calculate_specialization_match(sink_t)); + } +}