From 640c5263ce13672626ad00ab1422e27b0e6c75c5 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Mon, 1 May 2023 12:39:45 +0200 Subject: [PATCH] Fixed handling of qualifiers in template parameter deduced contexts --- src/class_diagram/visitor/template_builder.cc | 61 ++++-- src/class_diagram/visitor/template_builder.h | 2 +- src/common/model/template_parameter.cc | 177 ++++++++++++++++++ src/common/model/template_parameter.h | 172 +++++------------ tests/t00062/t00062.cc | 4 + 5 files changed, 276 insertions(+), 140 deletions(-) diff --git a/src/class_diagram/visitor/template_builder.cc b/src/class_diagram/visitor/template_builder.cc index e66efe0b..62cca1d3 100644 --- a/src/class_diagram/visitor/template_builder.cc +++ b/src/class_diagram/visitor/template_builder.cc @@ -498,8 +498,14 @@ clang::QualType template_builder::consume_context( bool try_again{false}; common::model::context ctx; - ctx.is_const = type.isConstQualified(); - ctx.is_volatile = type.isVolatileQualified(); + if (type->isPointerType() || type->isReferenceType()) { + if (type.isConstQualified() || type.isVolatileQualified()) { + ctx.is_ref_const = type.isConstQualified(); + ctx.is_ref_volatile = type.isVolatileQualified(); + + try_again = true; + } + } if (type->isLValueReferenceType()) { ctx.pr = common::model::rpqualifier::kLValueReference; @@ -509,24 +515,51 @@ clang::QualType template_builder::consume_context( ctx.pr = common::model::rpqualifier::kRValueReference; try_again = true; } + else if (type->isMemberFunctionPointerType()) { + const auto ref_qualifier = type->getPointeeType() + ->getAs() + ->getRefQualifier(); + + if (ref_qualifier == clang::RefQualifierKind::RQ_RValue) { + ctx.pr = common::model::rpqualifier::kRValueReference; + try_again = true; + } + else if (ref_qualifier == clang::RefQualifierKind::RQ_LValue) { + ctx.pr = common::model::rpqualifier::kLValueReference; + try_again = true; + } + } else if (type->isPointerType()) { ctx.pr = common::model::rpqualifier::kPointer; try_again = true; } - if (type.isConstQualified() || type.isVolatileQualified()) { - ctx.is_const = type.isConstQualified(); - ctx.is_volatile = type.isVolatileQualified(); - - try_again = true; - } - if (try_again) { - type = type.getNonReferenceType().getUnqualifiedType(); - if (type->isPointerType()) - type = type->getPointeeType(); + if (type->isPointerType()) { + if (type->getPointeeType().isConstQualified()) + ctx.is_const = true; + if (type->getPointeeType().isVolatileQualified()) + ctx.is_volatile = true; + + type = type->getPointeeType().getUnqualifiedType(); + } + else if (type->isReferenceType()) { + if (type.getNonReferenceType().isConstQualified()) + ctx.is_const = true; + if (type.getNonReferenceType().isVolatileQualified()) + ctx.is_volatile = true; + + type = type.getNonReferenceType().getUnqualifiedType(); + } + else if (type.isConstQualified() || type.isVolatileQualified()) { + ctx.is_const = type.isConstQualified(); + ctx.is_volatile = type.isVolatileQualified(); + } tp.push_context(std::move(ctx)); + + if (type->isMemberFunctionPointerType()) + return type; } else return type; @@ -571,7 +604,7 @@ template_parameter template_builder::process_type_argument( if (argument) return *argument; - argument = try_as_lamda(cls, template_decl, type); + argument = try_as_lambda(cls, template_decl, type); if (argument) return *argument; @@ -998,7 +1031,7 @@ std::optional template_builder::try_as_template_parm_type( return argument; } -std::optional template_builder::try_as_lamda( +std::optional template_builder::try_as_lambda( const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl, clang::QualType &type) { diff --git a/src/class_diagram/visitor/template_builder.h b/src/class_diagram/visitor/template_builder.h index 999a024a..f3ec2985 100644 --- a/src/class_diagram/visitor/template_builder.h +++ b/src/class_diagram/visitor/template_builder.h @@ -135,7 +135,7 @@ public: const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl, clang::QualType &type); - std::optional try_as_lamda(const clang::NamedDecl *cls, + std::optional try_as_lambda(const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl, clang::QualType &type); std::optional try_as_record_type( diff --git a/src/common/model/template_parameter.cc b/src/common/model/template_parameter.cc index 386858f3..bd210681 100644 --- a/src/common/model/template_parameter.cc +++ b/src/common/model/template_parameter.cc @@ -23,6 +23,41 @@ #include namespace clanguml::common::model { + +std::string context::to_string() const +{ + std::vector cv_qualifiers; + if (is_const) + cv_qualifiers.push_back("const"); + if (is_volatile) + cv_qualifiers.push_back("volatile"); + + auto res = fmt::format("{}", fmt::join(cv_qualifiers, " ")); + + if (pr == rpqualifier::kPointer) + res += "*"; + else if (pr == rpqualifier::kLValueReference) + res += "&"; + else if (pr == rpqualifier::kRValueReference) + res += "&&"; + + if (is_ref_const) + res += " const"; + if (is_ref_volatile) + res += " volatile"; + + return res; +} + +bool context::operator==(const context &rhs) const +{ + return is_const == rhs.is_const && is_volatile == rhs.is_volatile && + is_ref_const == rhs.is_ref_const && + is_ref_volatile == rhs.is_ref_volatile && pr == rhs.pr; +} + +bool context::operator!=(const context &rhs) const { return !(rhs == *this); } + std::string to_string(template_parameter_kind_t k) { switch (k) { @@ -42,6 +77,67 @@ std::string to_string(template_parameter_kind_t k) } } +template_parameter template_parameter::make_template_type( + const std::string &name, const std::optional &default_value, + bool is_variadic) +{ + template_parameter p; + 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; +} + +template_parameter template_parameter::make_template_template_type( + const std::string &name, const std::optional &default_value, + bool is_variadic) +{ + template_parameter p; + p.set_kind(template_parameter_kind_t::template_template_type); + p.set_name(name + "<>"); + if (default_value) + p.set_default_value(default_value.value()); + p.is_variadic(is_variadic); + return p; +} + +template_parameter template_parameter::make_non_type_template( + const std::string &type, const std::optional &name, + const std::optional &default_value, bool is_variadic) +{ + template_parameter p; + p.set_kind(template_parameter_kind_t::non_type_template); + p.set_type(type); + if (name) + p.set_name(name.value()); + if (default_value) + p.set_default_value(default_value.value()); + p.is_variadic(is_variadic); + return p; +} + +template_parameter template_parameter::make_argument( + const std::string &type, const std::optional &default_value) +{ + template_parameter p; + p.set_kind(template_parameter_kind_t::argument); + p.set_type(type); + if (default_value) + p.set_default_value(default_value.value()); + return p; +} + +template_parameter template_parameter::make_unexposed_argument( + const std::string &type, const std::optional &default_value) +{ + template_parameter p = make_argument(type, default_value); + p.set_unexposed(true); + return p; +} + void template_parameter::set_type(const std::string &type) { assert(kind_ != template_parameter_kind_t::template_type); @@ -410,6 +506,27 @@ bool template_parameter::find_nested_relationships( return added_aggregation_relationship; } +bool template_parameter::is_template_parameter() const +{ + return is_template_parameter_; +} + +void template_parameter::is_template_parameter(bool is_template_parameter) +{ + is_template_parameter_ = is_template_parameter; +} + +bool template_parameter::is_template_template_parameter() const +{ + return is_template_template_parameter_; +} + +void template_parameter::is_template_template_parameter( + bool is_template_template_parameter) +{ + is_template_template_parameter_ = is_template_template_parameter; +} + void template_parameter::set_concept_constraint(std::string constraint) { concept_constraint_ = std::move(constraint); @@ -420,6 +537,66 @@ const std::optional &template_parameter::concept_constraint() const return concept_constraint_; } +bool template_parameter::is_association() const +{ + return std::any_of( + deduced_context().begin(), deduced_context().end(), [](const auto &c) { + return c.pr == rpqualifier::kPointer || + c.pr == rpqualifier::kLValueReference; + }); +} + +template_parameter_kind_t template_parameter::kind() const { return kind_; } + +void template_parameter::set_kind(template_parameter_kind_t kind) +{ + kind_ = kind; +} + +bool template_parameter::is_unexposed() const { return is_unexposed_; } + +void template_parameter::set_unexposed(bool unexposed) +{ + is_unexposed_ = unexposed; +} + +void template_parameter::is_function_template(bool ft) +{ + is_function_template_ = ft; +} +bool template_parameter::is_function_template() const +{ + return is_function_template_; +} + +void template_parameter::is_member_pointer(bool m) { is_member_pointer_ = m; } +bool template_parameter::is_member_pointer() const +{ + return is_member_pointer_; +} + +void template_parameter::is_data_pointer(bool m) { is_data_pointer_ = m; } +bool template_parameter::is_data_pointer() const { return is_data_pointer_; } + +void template_parameter::is_array(bool a) { is_array_ = a; } +bool template_parameter::is_array() const { return is_array_; } + +void template_parameter::push_context(const context q) +{ + context_.push_front(q); +} +const std::deque &template_parameter::deduced_context() const +{ + return context_; +} +void template_parameter::deduced_context(const std::deque &c) +{ + context_ = c; +} + +void template_parameter::is_elipssis(bool e) { is_elipssis_ = e; } +bool template_parameter::is_elipssis() const { return is_elipssis_; } + int calculate_template_params_specialization_match( const std::vector &specialization_params, const std::vector &template_params) diff --git a/src/common/model/template_parameter.h b/src/common/model/template_parameter.h index 5729f9ff..b209aa11 100644 --- a/src/common/model/template_parameter.h +++ b/src/common/model/template_parameter.h @@ -35,118 +35,56 @@ enum class template_parameter_kind_t { argument, concept_constraint }; - -// TODO: rename to include the pointer and reference -enum class cvqualifier { kConst, kVolatile }; +std::string to_string(template_parameter_kind_t k); enum class rpqualifier { kLValueReference, kRValueReference, kPointer, kNone }; +/** + * This struct manages a single level of template deduced context, e.g. + * & or const* + */ struct context { - bool is_const; - bool is_volatile; + bool is_const{false}; + bool is_volatile{false}; + bool is_ref_const{false}; + bool is_ref_volatile{false}; rpqualifier pr{rpqualifier::kNone}; - std::string to_string() const - { - std::vector cv_qualifiers; - if (is_const) - cv_qualifiers.push_back("const"); - if (is_volatile) - cv_qualifiers.push_back("volatile"); + std::string to_string() const; - auto res = fmt::format("{}", fmt::join(cv_qualifiers, " ")); - - if (pr == rpqualifier::kPointer) - res += "*"; - else if (pr == rpqualifier::kLValueReference) - res += "&"; - else if (pr == rpqualifier::kRValueReference) - res += "&&"; - - return res; - } - - bool operator==(const context &rhs) const - { - return is_const == rhs.is_const && is_volatile == rhs.is_volatile && - pr == rhs.pr; - } - - bool operator!=(const context &rhs) const { return !(rhs == *this); } + bool operator==(const context &rhs) const; + bool operator!=(const context &rhs) const; }; -std::string to_string(template_parameter_kind_t k); - -/// @brief Represents template parameter, template arguments or concept -/// constraints -/// -/// This class can represent both template parameter and template arguments, -/// including variadic parameters and instantiations with -/// nested templates +/** + * @brief Represents template parameter, template arguments or concept + * constraints + * + * This class can represent both template parameter and template arguments, + * including variadic parameters and instantiations with + * nested templates + */ class template_parameter { public: static template_parameter make_template_type(const std::string &name, const std::optional &default_value = {}, - bool is_variadic = false) - { - template_parameter p; - 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; - } + bool is_variadic = false); static template_parameter make_template_template_type( const std::string &name, const std::optional &default_value = {}, - bool is_variadic = false) - { - template_parameter p; - p.set_kind(template_parameter_kind_t::template_template_type); - p.set_name(name + "<>"); - if (default_value) - p.set_default_value(default_value.value()); - p.is_variadic(is_variadic); - return p; - } + bool is_variadic = false); static template_parameter make_non_type_template(const std::string &type, const std::optional &name, const std::optional &default_value = {}, - bool is_variadic = false) - { - template_parameter p; - p.set_kind(template_parameter_kind_t::non_type_template); - p.set_type(type); - if (name) - p.set_name(name.value()); - if (default_value) - p.set_default_value(default_value.value()); - p.is_variadic(is_variadic); - return p; - } + bool is_variadic = false); static template_parameter make_argument(const std::string &type, - const std::optional &default_value = {}) - { - template_parameter p; - p.set_kind(template_parameter_kind_t::argument); - p.set_type(type); - if (default_value) - p.set_default_value(default_value.value()); - return p; - } + const std::optional &default_value = {}); static template_parameter make_unexposed_argument(const std::string &type, - const std::optional &default_value = {}) - { - template_parameter p = make_argument(type, default_value); - p.set_unexposed(true); - return p; - } + const std::optional &default_value = {}); void set_type(const std::string &type); std::optional type() const; @@ -171,22 +109,13 @@ public: friend bool operator!=( const template_parameter &l, const template_parameter &r); - bool is_template_parameter() const { return is_template_parameter_; } + bool is_template_parameter() const; - void is_template_parameter(bool is_template_parameter) - { - is_template_parameter_ = is_template_parameter; - } + void is_template_parameter(bool is_template_parameter); - bool is_template_template_parameter() const - { - return is_template_template_parameter_; - } + bool is_template_template_parameter() const; - void is_template_template_parameter(bool is_template_template_parameter) - { - is_template_template_parameter_ = is_template_template_parameter; - } + void is_template_template_parameter(bool is_template_template_parameter); std::string to_string( const clanguml::common::model::namespace_ &using_namespace, @@ -200,14 +129,7 @@ public: void clear_params() { template_params_.clear(); } - bool is_association() const - { - return std::any_of(deduced_context().begin(), deduced_context().end(), - [](const auto &c) { - return c.pr == rpqualifier::kPointer || - c.pr == rpqualifier::kLValueReference; - }); - } + bool is_association() const; bool find_nested_relationships( std::vector> @@ -220,32 +142,32 @@ public: const std::optional &concept_constraint() const; - template_parameter_kind_t kind() const { return kind_; } + template_parameter_kind_t kind() const; - void set_kind(template_parameter_kind_t kind) { kind_ = kind; } + void set_kind(template_parameter_kind_t kind); - bool is_unexposed() const { return is_unexposed_; } + bool is_unexposed() const; - void set_unexposed(bool unexposed) { is_unexposed_ = unexposed; } + void set_unexposed(bool unexposed); - void is_function_template(bool ft) { is_function_template_ = ft; } - bool is_function_template() const { return is_function_template_; } + void is_function_template(bool ft); + bool is_function_template() const; - void is_member_pointer(bool m) { is_member_pointer_ = m; } - bool is_member_pointer() const { return is_member_pointer_; } + void is_member_pointer(bool m); + bool is_member_pointer() const; - void is_data_pointer(bool m) { is_data_pointer_ = m; } - bool is_data_pointer() const { return is_data_pointer_; } + void is_data_pointer(bool m); + bool is_data_pointer() const; - void is_array(bool a) { is_array_ = a; } - bool is_array() const { return is_array_; } + void is_array(bool a); + bool is_array() const; - void push_context(const context q) { context_.push_front(q); } - const std::deque &deduced_context() const { return context_; } - void deduced_context(const std::deque &c) { context_ = c; } + void push_context(const context q); + const std::deque &deduced_context() const; + void deduced_context(const std::deque &c); - void is_elipssis(bool e) { is_elipssis_ = e; } - bool is_elipssis() const { return is_elipssis_; } + void is_elipssis(bool e); + bool is_elipssis() const; private: template_parameter() = default; diff --git a/tests/t00062/t00062.cc b/tests/t00062/t00062.cc index d1f81e85..4d17c4f6 100644 --- a/tests/t00062/t00062.cc +++ b/tests/t00062/t00062.cc @@ -21,6 +21,10 @@ template struct A { U ***u; }; +template struct A { + U ***u; +}; + template struct A { U &&u; };