Fixed handling of decltype cxxmember type aliases with dependend parameters

This commit is contained in:
Bartek Kryza
2023-05-14 16:34:59 +02:00
parent 4b0fcd631d
commit 0fbf491dfe
10 changed files with 374 additions and 144 deletions

View File

@@ -452,10 +452,11 @@ void template_builder::argument_process_dispatch(
case clang::TemplateArgument::Template:
argument.push_back(process_template_argument(arg));
break;
case clang::TemplateArgument::Type:
case clang::TemplateArgument::Type: {
argument.push_back(process_type_argument(parent, cls, template_decl,
arg.getAsType(), template_instantiation, argument_index));
break;
}
case clang::TemplateArgument::Declaration:
break;
case clang::TemplateArgument::NullPtr:
@@ -509,79 +510,11 @@ template_parameter template_builder::process_template_expansion(
clang::QualType template_builder::consume_context(
clang::QualType type, template_parameter &tp) const
{
while (true) {
bool try_again{false};
common::model::context ctx;
auto [unqualified_type, context] = common::consume_type_context(type);
if (type->isPointerType() || type->isReferenceType()) {
if (type.isConstQualified() || type.isVolatileQualified()) {
ctx.is_ref_const = type.isConstQualified();
ctx.is_ref_volatile = type.isVolatileQualified();
tp.deduced_context(std::move(context));
try_again = true;
}
}
if (type->isLValueReferenceType()) {
ctx.pr = common::model::rpqualifier::kLValueReference;
try_again = true;
}
else if (type->isRValueReferenceType()) {
ctx.pr = common::model::rpqualifier::kRValueReference;
try_again = true;
}
else if (type->isMemberFunctionPointerType() &&
type->getPointeeType()->getAs<clang::FunctionProtoType>() !=
nullptr) {
const auto ref_qualifier =
type->getPointeeType() // NOLINT
->getAs<clang::FunctionProtoType>() // NOLINT
->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 (try_again) {
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(ctx);
if (type->isMemberFunctionPointerType())
return type;
}
else
return type;
}
return unqualified_type;
}
template_parameter template_builder::process_type_argument(
@@ -626,6 +559,16 @@ template_parameter template_builder::process_type_argument(
if (argument)
return *argument;
argument = try_as_decl_type(parent, cls, template_decl, type,
template_instantiation, argument_index);
if (argument)
return *argument;
argument = try_as_typedef_type(parent, cls, template_decl, type,
template_instantiation, argument_index);
if (argument)
return *argument;
argument = try_as_lambda(cls, template_decl, type);
if (argument)
return *argument;
@@ -940,6 +883,8 @@ std::optional<template_parameter> template_builder::try_as_function_prototype(
if (function_type == nullptr)
return {};
LOG_DBG("Template argument is a function prototype");
auto argument = template_parameter::make_template_type("");
type = consume_context(type, argument);
@@ -969,6 +914,57 @@ std::optional<template_parameter> template_builder::try_as_function_prototype(
return argument;
}
std::optional<template_parameter> template_builder::try_as_decl_type(
std::optional<clanguml::class_diagram::model::class_ *> &parent,
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
clang::QualType &type, class_ &template_instantiation,
size_t argument_index)
{
const auto *decl_type =
common::dereference(type)->getAs<clang::DecltypeType>();
if (decl_type == nullptr) {
return {};
}
LOG_DBG("Template argument is a decltype()");
// TODO
return {};
}
std::optional<template_parameter> template_builder::try_as_typedef_type(
std::optional<clanguml::class_diagram::model::class_ *> &parent,
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
clang::QualType &type, class_ &template_instantiation,
size_t argument_index)
{
const auto *typedef_type =
common::dereference(type)->getAs<clang::TypedefType>();
if (typedef_type == nullptr) {
return {};
}
LOG_DBG("Template argument is a typedef/using");
// If this is a typedef/using alias to a decltype - we're not able
// to figure out anything out of it probably
if (typedef_type->getAs<clang::DecltypeType>() != nullptr) {
// Here we need to figure out the parent context of this alias,
// it can be a:
// - class/struct
if (typedef_type->getDecl()->isCXXClassMember() && parent) {
return template_parameter::make_argument(
fmt::format("{}::{}", parent.value()->full_name(false),
typedef_type->getDecl()->getNameAsString()));
}
// - namespace
return template_parameter::make_argument(
typedef_type->getDecl()->getQualifiedNameAsString());
}
return {};
}
std::optional<template_parameter>
template_builder::try_as_template_specialization_type(
std::optional<clanguml::class_diagram::model::class_ *> &parent,
@@ -978,8 +974,11 @@ template_builder::try_as_template_specialization_type(
{
const auto *nested_template_type =
common::dereference(type)->getAs<clang::TemplateSpecializationType>();
if (nested_template_type == nullptr)
if (nested_template_type == nullptr) {
return {};
}
LOG_DBG("Template argument is a template specialization type");
auto argument = template_parameter::make_argument("");
type = consume_context(type, argument);
@@ -1074,6 +1073,8 @@ std::optional<template_parameter> template_builder::try_as_template_parm_type(
if (type_parameter == nullptr)
return {};
LOG_DBG("Template argument is a template parameter type");
auto argument = template_parameter::make_template_type("");
type = consume_context(type, argument);
@@ -1100,6 +1101,8 @@ std::optional<template_parameter> template_builder::try_as_lambda(
if (type_name.find("(lambda at ") != 0)
return {};
LOG_DBG("Template argument is a lambda");
auto argument = template_parameter::make_argument("");
type = consume_context(type, argument);
@@ -1120,6 +1123,8 @@ std::optional<template_parameter> template_builder::try_as_record_type(
if (record_type == nullptr)
return {};
LOG_DBG("Template argument is a c++ record");
auto argument = template_parameter::make_argument({});
type = consume_context(type, argument);
@@ -1176,6 +1181,8 @@ std::optional<template_parameter> template_builder::try_as_enum_type(
if (enum_type == nullptr)
return {};
LOG_DBG("Template argument is a an enum");
auto argument = template_parameter::make_argument({});
type = consume_context(type, argument);
@@ -1200,6 +1207,8 @@ std::optional<template_parameter> template_builder::try_as_builtin_type(
if (builtin_type == nullptr)
return {};
LOG_DBG("Template argument is a builtin type");
auto type_name = common::to_string(type, template_decl->getASTContext());
auto argument = template_parameter::make_argument(type_name);

View File

@@ -157,6 +157,18 @@ public:
clang::QualType &type, class_ &template_instantiation,
size_t argument_index);
std::optional<template_parameter> try_as_decl_type(
std::optional<clanguml::class_diagram::model::class_ *> &parent,
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
clang::QualType &type, class_ &template_instantiation,
size_t argument_index);
std::optional<template_parameter> try_as_typedef_type(
std::optional<clanguml::class_diagram::model::class_ *> &parent,
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
clang::QualType &type, class_ &template_instantiation,
size_t argument_index);
clang::QualType consume_context(
clang::QualType type, template_parameter &tp) const;

View File

@@ -1291,6 +1291,30 @@ void translation_unit_visitor::process_method(
// find relationship for return type
found_relationships_t relationships;
// Move dereferencing to build() method of template_builder
if (const auto *templ = mf.getReturnType()
.getNonReferenceType()
.getUnqualifiedType()
->getAs<clang::TemplateSpecializationType>();
templ != nullptr) {
auto *unaliased_type = templ;
if (unaliased_type->isTypeAlias())
unaliased_type = unaliased_type->getAliasedType()
->getAs<clang::TemplateSpecializationType>();
auto template_specialization_ptr = tbuilder().build(
unaliased_type->getTemplateName().getAsTemplateDecl(),
*unaliased_type, &c);
if (diagram().should_include(
template_specialization_ptr->full_name(false))) {
relationships.emplace_back(
template_specialization_ptr->id(), relationship_t::kDependency);
diagram().add_class(std::move(template_specialization_ptr));
}
}
find_relationships(
mf.getReturnType(), relationships, relationship_t::kDependency);
@@ -1317,13 +1341,8 @@ void translation_unit_visitor::process_method(
if (underlying_type->isPointerType())
underlying_type = underlying_type->getPointeeType();
if (const auto *tsp =
underlying_type->getAs<clang::TemplateSpecializationType>();
tsp != nullptr) {
process_function_parameter_find_relationships_in_template(c, {}, *tsp);
}
else if (const auto *atsp = underlying_type->getAs<clang::AutoType>();
atsp != nullptr) {
if (const auto *atsp = underlying_type->getAs<clang::AutoType>();
atsp != nullptr) {
process_function_parameter_find_relationships_in_autotype(c, atsp);
}
@@ -1521,6 +1540,60 @@ bool translation_unit_visitor::find_relationships(const clang::QualType &type,
result = true;
}
}
else if (const auto *template_specialization_type =
type->getAs<clang::TemplateSpecializationType>();
template_specialization_type != nullptr) {
if (should_include(template_specialization_type->getTemplateName()
.getAsTemplateDecl())) {
relationships.emplace_back(
template_specialization_type->getTemplateName()
.getAsTemplateDecl()
->getID(),
relationship_hint);
}
for (const auto &template_argument :
template_specialization_type->template_arguments()) {
const auto template_argument_kind = template_argument.getKind();
if (template_argument_kind ==
clang::TemplateArgument::ArgKind::Integral) {
// pass
}
else if (template_argument_kind ==
clang::TemplateArgument::ArgKind::Null) {
// pass
}
else if (template_argument_kind ==
clang::TemplateArgument::ArgKind::Expression) {
// pass
}
else if (template_argument.getKind() ==
clang::TemplateArgument::ArgKind::NullPtr) {
// pass
}
else if (template_argument_kind ==
clang::TemplateArgument::ArgKind::Template) {
// pass
}
else if (template_argument_kind ==
clang::TemplateArgument::ArgKind::TemplateExpansion) {
// pass
}
else if (const auto *function_type =
template_argument.getAsType()
->getAs<clang::FunctionProtoType>();
function_type != nullptr) {
for (const auto &param_type : function_type->param_types()) {
result = find_relationships(
param_type, relationships, relationship_t::kDependency);
}
}
else if (template_argument_kind ==
clang::TemplateArgument::ArgKind::Type) {
result = find_relationships(template_argument.getAsType(),
relationships, relationship_hint);
}
}
}
return result;
}
@@ -1557,6 +1630,27 @@ void translation_unit_visitor::process_function_parameter(
// find relationship for the type
found_relationships_t relationships;
LOG_DBG("Looking for relationships in type: {}",
common::to_string(p.getType(), p.getASTContext()));
if (const auto *templ =
p.getType()
.getNonReferenceType()
.getUnqualifiedType()
->getAs<clang::TemplateSpecializationType>();
templ != nullptr) {
auto template_specialization_ptr = tbuilder().build(
templ->getTemplateName().getAsTemplateDecl(), *templ, &c);
if (diagram().should_include(
template_specialization_ptr->full_name(false))) {
relationships.emplace_back(template_specialization_ptr->id(),
relationship_t::kDependency);
diagram().add_class(std::move(template_specialization_ptr));
}
}
find_relationships(
p.getType(), relationships, relationship_t::kDependency);
@@ -1573,22 +1667,6 @@ void translation_unit_visitor::process_function_parameter(
c.add_relationship(std::move(r));
}
}
// Also consider the container itself if it is a template
// instantiation it's arguments could count as reference to relevant
// types
auto underlying_type = p.getType();
if (underlying_type->isReferenceType())
underlying_type = underlying_type.getNonReferenceType();
if (underlying_type->isPointerType())
underlying_type = underlying_type->getPointeeType();
if (const auto *tsp =
underlying_type->getAs<clang::TemplateSpecializationType>();
tsp != nullptr) {
process_function_parameter_find_relationships_in_template(
c, template_parameter_names, *tsp);
}
}
method.add_parameter(std::move(parameter));
@@ -1630,40 +1708,6 @@ void translation_unit_visitor::ensure_lambda_type_is_relative(
}
}
void translation_unit_visitor::
process_function_parameter_find_relationships_in_template(class_ &c,
const std::set<std::string> & /*template_parameter_names*/,
const clang::TemplateSpecializationType &template_instantiation_type)
{
if (!should_include(
template_instantiation_type.getTemplateName().getAsTemplateDecl()))
return;
auto template_specialization_ptr = tbuilder().build(
template_instantiation_type.getTemplateName().getAsTemplateDecl(),
template_instantiation_type, &c);
if (template_instantiation_type.isDependentType()) {
if (template_specialization_ptr) {
relationship r{
relationship_t::kDependency, template_specialization_ptr->id()};
c.add_relationship(std::move(r));
}
}
else {
if (template_specialization_ptr) {
relationship r{
relationship_t::kDependency, template_specialization_ptr->id()};
if (!diagram().has_element(template_specialization_ptr->id()))
diagram().add_class(std::move(template_specialization_ptr));
c.add_relationship(std::move(r));
}
}
}
void translation_unit_visitor::add_relationships(class_ &c,
const class_member &field, const found_relationships_t &relationships,
bool break_on_first_aggregation)

View File

@@ -190,11 +190,6 @@ private:
void process_function_parameter_find_relationships_in_autotype(
model::class_ &c, const clang::AutoType *atsp);
void process_function_parameter_find_relationships_in_template(
clanguml::class_diagram::model::class_ &c,
const std::set<std::string> &template_parameter_names,
const clang::TemplateSpecializationType &template_instantiation_type);
void find_relationships_in_constraint_expression(
clanguml::common::model::element &c, const clang::Expr *expr);