WIP
This commit is contained in:
@@ -370,6 +370,21 @@ void template_builder::process_template_arguments(
|
|||||||
// arguments
|
// arguments
|
||||||
std::vector<template_parameter> arguments;
|
std::vector<template_parameter> arguments;
|
||||||
|
|
||||||
|
// For now ignore the default template arguments to make the system
|
||||||
|
// templates 'nicer' - i.e. skipping the allocators and comparators
|
||||||
|
// TODO: Change this to ignore only when the arguments are set to
|
||||||
|
// default values, and add them when they are specifically
|
||||||
|
// overriden
|
||||||
|
const auto *maybe_type_parm_decl =
|
||||||
|
clang::dyn_cast<clang::TemplateTypeParmDecl>(
|
||||||
|
template_decl->getTemplateParameters()->getParam(
|
||||||
|
std::min<int>(arg_index,
|
||||||
|
template_decl->getTemplateParameters()->size() - 1)));
|
||||||
|
if (maybe_type_parm_decl &&
|
||||||
|
maybe_type_parm_decl->hasDefaultArgument()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
argument_process_dispatch(parent, cls, template_instantiation,
|
argument_process_dispatch(parent, cls, template_instantiation,
|
||||||
template_decl, arg, arg_index, arguments);
|
template_decl, arg, arg_index, arguments);
|
||||||
|
|
||||||
@@ -394,7 +409,7 @@ void template_builder::process_template_arguments(
|
|||||||
|
|
||||||
for (auto &argument : arguments) {
|
for (auto &argument : arguments) {
|
||||||
simplify_system_template(
|
simplify_system_template(
|
||||||
argument, argument.to_string(using_namespace(), false));
|
argument, argument.to_string(using_namespace(), false, true));
|
||||||
|
|
||||||
LOG_DBG("Adding template argument {} to template "
|
LOG_DBG("Adding template argument {} to template "
|
||||||
"specialization/instantiation {}",
|
"specialization/instantiation {}",
|
||||||
@@ -469,13 +484,19 @@ template_parameter template_builder::process_type_argument(
|
|||||||
|
|
||||||
auto type_name = common::to_string(arg, &cls->getASTContext());
|
auto type_name = common::to_string(arg, &cls->getASTContext());
|
||||||
|
|
||||||
LOG_DBG("Processing template {} type argument: {}",
|
|
||||||
template_decl->getQualifiedNameAsString(), type_name);
|
|
||||||
|
|
||||||
auto argument = template_parameter::make_argument({});
|
auto argument = template_parameter::make_argument({});
|
||||||
|
|
||||||
if (const auto *function_type =
|
auto type = arg.getAsType().getNonReferenceType().getUnqualifiedType();
|
||||||
arg.getAsType()->getAs<clang::FunctionProtoType>();
|
if (type->isPointerType())
|
||||||
|
type = type->getPointeeType();
|
||||||
|
// if (type->isMemberPointerType())
|
||||||
|
// type = type->getPointeeType();
|
||||||
|
|
||||||
|
LOG_DBG("Processing template {} type argument: {}, {}, {}",
|
||||||
|
template_decl->getQualifiedNameAsString(), type_name,
|
||||||
|
type->getTypeClassName(), common::to_string(type, cls->getASTContext()));
|
||||||
|
|
||||||
|
if (const auto *function_type = type->getAs<clang::FunctionProtoType>();
|
||||||
function_type != nullptr) {
|
function_type != nullptr) {
|
||||||
|
|
||||||
argument.set_function_template(true);
|
argument.set_function_template(true);
|
||||||
@@ -553,7 +574,7 @@ template_parameter template_builder::process_type_argument(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (const auto *nested_template_type =
|
else if (const auto *nested_template_type =
|
||||||
arg.getAsType()->getAs<clang::TemplateSpecializationType>();
|
type->getAs<clang::TemplateSpecializationType>();
|
||||||
nested_template_type != nullptr) {
|
nested_template_type != nullptr) {
|
||||||
|
|
||||||
const auto nested_type_name = nested_template_type->getTemplateName()
|
const auto nested_type_name = nested_template_type->getTemplateName()
|
||||||
@@ -601,11 +622,10 @@ template_parameter template_builder::process_type_argument(
|
|||||||
diagram().add_class(std::move(nested_template_instantiation));
|
diagram().add_class(std::move(nested_template_instantiation));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (arg.getAsType()->getAs<clang::TemplateTypeParmType>() != nullptr) {
|
else if (type->getAs<clang::TemplateTypeParmType>() != nullptr) {
|
||||||
argument = template_parameter::make_template_type({});
|
argument = template_parameter::make_template_type({});
|
||||||
|
|
||||||
auto parameter_name =
|
auto parameter_name = common::to_string(type, cls->getASTContext());
|
||||||
common::to_string(arg.getAsType(), cls->getASTContext());
|
|
||||||
|
|
||||||
ensure_lambda_type_is_relative(parameter_name);
|
ensure_lambda_type_is_relative(parameter_name);
|
||||||
|
|
||||||
@@ -617,14 +637,16 @@ template_parameter template_builder::process_type_argument(
|
|||||||
cls, parameter_name);
|
cls, parameter_name);
|
||||||
|
|
||||||
if (maybe_arg) {
|
if (maybe_arg) {
|
||||||
return *maybe_arg;
|
argument = *maybe_arg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
argument.set_name(parameter_name);
|
argument.set_name(parameter_name);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
// Case for unexposed template
|
// Case for unexposed template
|
||||||
else if ((type_name.find('<') != std::string::npos) ||
|
else if ((type_name.find('<') != std::string::npos) &&
|
||||||
(type_name.find("type-parameter-") == 0)) {
|
(type_name.find("type-parameter-") == 0)) {
|
||||||
|
|
||||||
ensure_lambda_type_is_relative(type_name);
|
ensure_lambda_type_is_relative(type_name);
|
||||||
@@ -660,8 +682,11 @@ template_parameter template_builder::process_type_argument(
|
|||||||
return template_parameter::make_template_type(type_name);
|
return template_parameter::make_template_type(type_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
else if (const auto maybe_arg =
|
else if (type_name.find("type-parameter-") != std::string::npos) {
|
||||||
|
// This is some sort of template parameter with unexposed type
|
||||||
|
// parameters in the form 'type-parameter-X-Y'
|
||||||
|
if (const auto maybe_arg =
|
||||||
get_template_argument_from_type_parameter_string(
|
get_template_argument_from_type_parameter_string(
|
||||||
cls, arg.getAsType().getAsString());
|
cls, arg.getAsType().getAsString());
|
||||||
maybe_arg) {
|
maybe_arg) {
|
||||||
@@ -669,6 +694,13 @@ template_parameter template_builder::process_type_argument(
|
|||||||
// to match it to a template parameter name in the 'cls' template
|
// to match it to a template parameter name in the 'cls' template
|
||||||
argument = *maybe_arg;
|
argument = *maybe_arg;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
// fallback - just put whatever clang returns
|
||||||
|
argument.is_template_parameter(false);
|
||||||
|
argument.set_type(
|
||||||
|
common::to_string(type, template_decl->getASTContext()));
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (type_name.find("(lambda at ") == 0) {
|
else if (type_name.find("(lambda at ") == 0) {
|
||||||
// This is just a lambda reference
|
// This is just a lambda reference
|
||||||
ensure_lambda_type_is_relative(type_name);
|
ensure_lambda_type_is_relative(type_name);
|
||||||
@@ -677,7 +709,26 @@ template_parameter template_builder::process_type_argument(
|
|||||||
else {
|
else {
|
||||||
// This is just a regular record type
|
// This is just a regular record type
|
||||||
process_tag_argument(
|
process_tag_argument(
|
||||||
template_instantiation, template_decl, arg, argument);
|
template_instantiation, template_decl, type, argument);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg.getAsType()->isLValueReferenceType()) {
|
||||||
|
argument.is_lvalue_reference(true);
|
||||||
|
}
|
||||||
|
if (arg.getAsType()->isRValueReferenceType()) {
|
||||||
|
argument.is_rvalue_reference(true);
|
||||||
|
}
|
||||||
|
if (arg.getAsType()->isPointerType()) {
|
||||||
|
argument.is_pointer(true);
|
||||||
|
}
|
||||||
|
if (arg.getAsType()->isMemberPointerType()) {
|
||||||
|
argument.set_method_template(true);
|
||||||
|
}
|
||||||
|
if (arg.getAsType().isConstQualified()) {
|
||||||
|
argument.set_qualifier(template_parameter::cvqualifier::kConst);
|
||||||
|
}
|
||||||
|
if (arg.getAsType().isVolatileQualified()) {
|
||||||
|
argument.set_qualifier(template_parameter::cvqualifier::kVolatile);
|
||||||
}
|
}
|
||||||
|
|
||||||
return argument;
|
return argument;
|
||||||
@@ -798,6 +849,7 @@ template_parameter map_type_parameter_to_template_parameter(
|
|||||||
std::string arg = tp;
|
std::string arg = tp;
|
||||||
if (arg == "_Bool")
|
if (arg == "_Bool")
|
||||||
arg = "bool";
|
arg = "bool";
|
||||||
|
|
||||||
return template_parameter::make_argument(arg);
|
return template_parameter::make_argument(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -809,14 +861,12 @@ std::optional<template_parameter> build_template_parameter(
|
|||||||
|
|
||||||
auto res = template_parameter::make_template_type({});
|
auto res = template_parameter::make_template_type({});
|
||||||
|
|
||||||
std::string param_qualifier{}; // e.g. const& or &&
|
|
||||||
|
|
||||||
auto it = begin;
|
auto it = begin;
|
||||||
auto it_next = it;
|
auto it_next = it;
|
||||||
it_next++;
|
it_next++;
|
||||||
|
|
||||||
if (*it == "const") {
|
if (*it == "const") {
|
||||||
param_qualifier = "const";
|
res.set_qualifier(template_parameter::cvqualifier::kConst);
|
||||||
it++;
|
it++;
|
||||||
it_next++;
|
it_next++;
|
||||||
}
|
}
|
||||||
@@ -832,8 +882,8 @@ std::optional<template_parameter> build_template_parameter(
|
|||||||
// template parameter with qualifier at the end
|
// template parameter with qualifier at the end
|
||||||
else if (common::is_type_token(*it) && common::is_qualifier(*it_next)) {
|
else if (common::is_type_token(*it) && common::is_qualifier(*it_next)) {
|
||||||
res = map_type_parameter_to_template_parameter(decl, *it);
|
res = map_type_parameter_to_template_parameter(decl, *it);
|
||||||
param_qualifier += *it_next;
|
// param_qualifier += *it_next;
|
||||||
res.set_qualifier(param_qualifier);
|
// res.set_qualifier(param_qualifier);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
// method template parameter
|
// method template parameter
|
||||||
@@ -851,8 +901,8 @@ std::optional<template_parameter> build_template_parameter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (it != end && common::is_qualifier(*it)) {
|
if (it != end && common::is_qualifier(*it)) {
|
||||||
param_qualifier += *it;
|
// param_qualifier += *it;
|
||||||
res.set_qualifier(param_qualifier);
|
// res.set_qualifier(param_qualifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@@ -884,6 +934,13 @@ std::optional<template_parameter> build_template_parameter(
|
|||||||
// handle args
|
// handle args
|
||||||
if (*it == "(") {
|
if (*it == "(") {
|
||||||
it++;
|
it++;
|
||||||
|
|
||||||
|
if(it != end && *it == "...") {
|
||||||
|
// handle elipssis arg
|
||||||
|
res.is_elipssis(true);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
// This will break on more complex args
|
// This will break on more complex args
|
||||||
auto arg_separator = std::find(it, end, ",");
|
auto arg_separator = std::find(it, end, ",");
|
||||||
@@ -906,14 +963,15 @@ std::optional<template_parameter> build_template_parameter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(*it == ")");
|
//if(it!=end)
|
||||||
|
//assert(*it == ")");
|
||||||
|
|
||||||
it++;
|
it++;
|
||||||
|
|
||||||
if (it != end && common::is_qualifier(*it)) {
|
//if (it != end && common::is_qualifier(*it)) {
|
||||||
param_qualifier += *it;
|
// param_qualifier += *it;
|
||||||
res.set_qualifier(param_qualifier);
|
// res.set_qualifier(param_qualifier);
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@@ -941,8 +999,11 @@ template_parameter template_builder::process_integral_argument(
|
|||||||
{
|
{
|
||||||
assert(arg.getKind() == clang::TemplateArgument::Integral);
|
assert(arg.getKind() == clang::TemplateArgument::Integral);
|
||||||
|
|
||||||
return template_parameter::make_argument(
|
std::string result;
|
||||||
std::to_string(arg.getAsIntegral().getExtValue()));
|
llvm::raw_string_ostream ostream(result);
|
||||||
|
arg.dump(ostream);
|
||||||
|
|
||||||
|
return template_parameter::make_argument(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
template_parameter template_builder::process_null_argument(
|
template_parameter template_builder::process_null_argument(
|
||||||
@@ -993,56 +1054,70 @@ std::vector<template_parameter> template_builder::process_pack_argument(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void template_builder::process_tag_argument(class_ &template_instantiation,
|
void template_builder::process_tag_argument(class_ &template_instantiation,
|
||||||
const clang::TemplateDecl *template_decl,
|
const clang::TemplateDecl *template_decl, const clang::QualType type,
|
||||||
const clang::TemplateArgument &arg, template_parameter &argument)
|
template_parameter &argument)
|
||||||
{
|
{
|
||||||
assert(arg.getKind() == clang::TemplateArgument::Type);
|
[[maybe_unused]] auto current_instantiation_name =
|
||||||
|
template_instantiation.full_name(false);
|
||||||
|
|
||||||
argument.is_template_parameter(false);
|
argument.is_template_parameter(false);
|
||||||
|
auto type_name = common::to_string(type, template_decl->getASTContext());
|
||||||
|
argument.set_type(type_name);
|
||||||
|
const auto type_id = common::to_id(type_name);
|
||||||
|
argument.set_id(type_id);
|
||||||
|
|
||||||
argument.set_type(
|
if (const auto *tsp = type->getAs<clang::TemplateSpecializationType>();
|
||||||
common::to_string(arg.getAsType(), template_decl->getASTContext()));
|
|
||||||
|
|
||||||
if (const auto *tsp =
|
|
||||||
arg.getAsType()->getAs<clang::TemplateSpecializationType>();
|
|
||||||
tsp != nullptr) {
|
tsp != nullptr) {
|
||||||
if (const auto *record_type_decl = tsp->getAsRecordDecl();
|
if (const auto *record_type_decl = tsp->getAsRecordDecl();
|
||||||
record_type_decl != nullptr) {
|
record_type_decl != nullptr) {
|
||||||
|
|
||||||
argument.set_id(common::to_id(arg));
|
|
||||||
if (diagram().should_include(
|
if (diagram().should_include(
|
||||||
template_decl->getQualifiedNameAsString())) {
|
template_decl->getQualifiedNameAsString())) {
|
||||||
// Add dependency relationship to the parent
|
// Add dependency relationship to the parent
|
||||||
// template
|
// template
|
||||||
template_instantiation.add_relationship(
|
template_instantiation.add_relationship(
|
||||||
{relationship_t::kDependency, common::to_id(arg)});
|
{relationship_t::kDependency, type_id});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (const auto *record_type =
|
else if (const auto *record_type = type->getAs<clang::RecordType>();
|
||||||
arg.getAsType()->getAs<clang::RecordType>();
|
|
||||||
record_type != nullptr) {
|
record_type != nullptr) {
|
||||||
if (const auto *record_type_decl = record_type->getAsRecordDecl();
|
|
||||||
record_type_decl != nullptr) {
|
|
||||||
|
|
||||||
argument.set_id(common::to_id(arg));
|
const auto *class_template_specialization =
|
||||||
|
clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(
|
||||||
|
record_type->getAsRecordDecl());
|
||||||
|
|
||||||
|
if (class_template_specialization != nullptr) {
|
||||||
|
auto tag_argument = build_from_class_template_specialization(
|
||||||
|
*class_template_specialization);
|
||||||
|
|
||||||
|
if (tag_argument) {
|
||||||
|
argument.set_type(tag_argument->name_and_ns());
|
||||||
|
for (const auto &p : tag_argument->template_params())
|
||||||
|
argument.add_template_param(p);
|
||||||
|
for (auto &r : tag_argument->relationships()) {
|
||||||
|
template_instantiation.add_relationship(std::move(r));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (const auto *record_type_decl = record_type->getAsRecordDecl();
|
||||||
|
record_type_decl != nullptr) {
|
||||||
#if LLVM_VERSION_MAJOR >= 16
|
#if LLVM_VERSION_MAJOR >= 16
|
||||||
argument.set_type(record_type_decl->getQualifiedNameAsString());
|
argument.set_type(record_type_decl->getQualifiedNameAsString());
|
||||||
#endif
|
#endif
|
||||||
if (diagram().should_include(
|
if (diagram().should_include(type_name)) {
|
||||||
template_decl->getQualifiedNameAsString())) {
|
|
||||||
// Add dependency relationship to the parent
|
// Add dependency relationship to the parent
|
||||||
// template
|
// template
|
||||||
template_instantiation.add_relationship(
|
template_instantiation.add_relationship(
|
||||||
{relationship_t::kDependency, common::to_id(arg)});
|
{relationship_t::kDependency, type_id});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (const auto *enum_type = arg.getAsType()->getAs<clang::EnumType>();
|
else if (const auto *enum_type = type->getAs<clang::EnumType>();
|
||||||
enum_type != nullptr) {
|
enum_type != nullptr) {
|
||||||
if (enum_type->getAsTagDecl() != nullptr) {
|
if (enum_type->getAsTagDecl() != nullptr) {
|
||||||
template_instantiation.add_relationship(
|
template_instantiation.add_relationship(
|
||||||
{relationship_t::kDependency, common::to_id(arg)});
|
{relationship_t::kDependency, type_id});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ public:
|
|||||||
|
|
||||||
void process_tag_argument(model::class_ &template_instantiation,
|
void process_tag_argument(model::class_ &template_instantiation,
|
||||||
const clang::TemplateDecl *template_decl,
|
const clang::TemplateDecl *template_decl,
|
||||||
const clang::TemplateArgument &arg,
|
const clang::QualType type,
|
||||||
common::model::template_parameter &argument);
|
common::model::template_parameter &argument);
|
||||||
|
|
||||||
template_parameter process_expression_argument(
|
template_parameter process_expression_argument(
|
||||||
|
|||||||
@@ -1875,7 +1875,7 @@ void translation_unit_visitor::process_field(
|
|||||||
template_specialization.template_params()) {
|
template_specialization.template_params()) {
|
||||||
|
|
||||||
LOG_DBG("Looking for nested relationships from {}::{} in "
|
LOG_DBG("Looking for nested relationships from {}::{} in "
|
||||||
"template {}",
|
"template argument {}",
|
||||||
c.full_name(false), field_name,
|
c.full_name(false), field_name,
|
||||||
template_argument.to_string(
|
template_argument.to_string(
|
||||||
config().using_namespace(), false));
|
config().using_namespace(), false));
|
||||||
|
|||||||
@@ -67,6 +67,10 @@ public:
|
|||||||
clanguml::class_diagram::model::diagram &diagram,
|
clanguml::class_diagram::model::diagram &diagram,
|
||||||
const clanguml::config::class_diagram &config);
|
const clanguml::config::class_diagram &config);
|
||||||
|
|
||||||
|
bool shouldVisitTemplateInstantiations() const { return false; }
|
||||||
|
|
||||||
|
bool shouldVisitImplicitCode() const { return false; }
|
||||||
|
|
||||||
virtual bool VisitNamespaceDecl(clang::NamespaceDecl *ns);
|
virtual bool VisitNamespaceDecl(clang::NamespaceDecl *ns);
|
||||||
|
|
||||||
virtual bool VisitRecordDecl(clang::RecordDecl *D);
|
virtual bool VisitRecordDecl(clang::RecordDecl *D);
|
||||||
|
|||||||
@@ -306,6 +306,10 @@ template <> id_t to_id(const std::string &full_name)
|
|||||||
return static_cast<id_t>(std::hash<std::string>{}(full_name) >> 3U);
|
return static_cast<id_t>(std::hash<std::string>{}(full_name) >> 3U);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
id_t to_id(const clang::QualType &type, const clang::ASTContext &ctx) {
|
||||||
|
return to_id(common::to_string(type, ctx));
|
||||||
|
}
|
||||||
|
|
||||||
template <> id_t to_id(const clang::NamespaceDecl &declaration)
|
template <> id_t to_id(const clang::NamespaceDecl &declaration)
|
||||||
{
|
{
|
||||||
return to_id(get_qualified_name(declaration));
|
return to_id(get_qualified_name(declaration));
|
||||||
@@ -533,7 +537,7 @@ std::vector<std::string> tokenize_unexposed_template_parameter(
|
|||||||
std::string tok;
|
std::string tok;
|
||||||
|
|
||||||
for (const char c : word) {
|
for (const char c : word) {
|
||||||
if (c == '(' || c == ')' || c == '[' || c == ']') {
|
if (c == '(' || c == ')' || c == '[' || c == ']' || c == '<' || c == '>') {
|
||||||
if (!tok.empty())
|
if (!tok.empty())
|
||||||
result.push_back(tok);
|
result.push_back(tok);
|
||||||
result.push_back(std::string{c});
|
result.push_back(std::string{c});
|
||||||
@@ -544,6 +548,10 @@ std::vector<std::string> tokenize_unexposed_template_parameter(
|
|||||||
result.push_back(tok);
|
result.push_back(tok);
|
||||||
tok = ":";
|
tok = ":";
|
||||||
}
|
}
|
||||||
|
else if (tok == ":") {
|
||||||
|
result.push_back("::");
|
||||||
|
tok = "";
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
tok += ':';
|
tok += ':';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,6 +129,8 @@ template <typename T> id_t to_id(const T &declaration);
|
|||||||
|
|
||||||
template <> id_t to_id(const std::string &full_name);
|
template <> id_t to_id(const std::string &full_name);
|
||||||
|
|
||||||
|
id_t to_id(const clang::QualType &type, const clang::ASTContext &ctx);
|
||||||
|
|
||||||
template <> id_t to_id(const clang::NamespaceDecl &declaration);
|
template <> id_t to_id(const clang::NamespaceDecl &declaration);
|
||||||
|
|
||||||
template <> id_t to_id(const clang::CXXRecordDecl &declaration);
|
template <> id_t to_id(const clang::CXXRecordDecl &declaration);
|
||||||
|
|||||||
@@ -46,12 +46,13 @@ void diagram_element::add_relationship(relationship &&cr)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!util::contains(relationships_, cr)) {
|
||||||
LOG_DBG("Adding relationship from: '{}' ({}) - {} - '{}'", id(),
|
LOG_DBG("Adding relationship from: '{}' ({}) - {} - '{}'", id(),
|
||||||
full_name(true), to_string(cr.type()), cr.destination());
|
full_name(true), to_string(cr.type()), cr.destination());
|
||||||
|
|
||||||
if (!util::contains(relationships_, cr))
|
|
||||||
relationships_.emplace_back(std::move(cr));
|
relationships_.emplace_back(std::move(cr));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<relationship> &diagram_element::relationships()
|
std::vector<relationship> &diagram_element::relationships()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -113,7 +113,10 @@ int template_parameter::calculate_specialization_match(
|
|||||||
{
|
{
|
||||||
int res{0};
|
int res{0};
|
||||||
|
|
||||||
if (qualifier() != base_template_parameter.qualifier())
|
// If the potential base template has a qualifier, the current template
|
||||||
|
// must match it
|
||||||
|
if (!base_template_parameter.qualifiers().empty() &&
|
||||||
|
(qualifiers() != base_template_parameter.qualifiers()))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (is_template_parameter() &&
|
if (is_template_parameter() &&
|
||||||
@@ -211,10 +214,33 @@ bool operator!=(const template_parameter &l, const template_parameter &r)
|
|||||||
return !(l == r);
|
return !(l == r);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string template_parameter::to_string(
|
std::string template_parameter::qualifiers_str() const
|
||||||
const clanguml::common::model::namespace_ &using_namespace,
|
|
||||||
bool relative) const
|
|
||||||
{
|
{
|
||||||
|
std::string res;
|
||||||
|
if (qualifiers_.count(cvqualifier::kConst) == 1)
|
||||||
|
res += "const";
|
||||||
|
|
||||||
|
if (is_rvalue_reference())
|
||||||
|
res += "&&";
|
||||||
|
else if (is_lvalue_reference())
|
||||||
|
res += "&";
|
||||||
|
|
||||||
|
if (is_pointer())
|
||||||
|
res += "*";
|
||||||
|
|
||||||
|
if(res.empty())
|
||||||
|
return res;
|
||||||
|
|
||||||
|
return " " + res;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string template_parameter::to_string(
|
||||||
|
const clanguml::common::model::namespace_ &using_namespace, bool relative,
|
||||||
|
bool skip_qualifiers) const
|
||||||
|
{
|
||||||
|
if(is_elipssis())
|
||||||
|
return "...";
|
||||||
|
|
||||||
using clanguml::common::model::namespace_;
|
using clanguml::common::model::namespace_;
|
||||||
|
|
||||||
assert(!(type().has_value() && concept_constraint().has_value()));
|
assert(!(type().has_value() && concept_constraint().has_value()));
|
||||||
@@ -235,11 +261,11 @@ std::string template_parameter::to_string(
|
|||||||
if (is_method_template()) {
|
if (is_method_template()) {
|
||||||
assert(template_params().size() > 1);
|
assert(template_params().size() > 1);
|
||||||
|
|
||||||
|
std::string unqualified;
|
||||||
if (template_params().size() == 2) {
|
if (template_params().size() == 2) {
|
||||||
return fmt::format("{} {}::*{}",
|
unqualified = fmt::format("{} {}::*",
|
||||||
template_params().at(0).to_string(using_namespace, relative),
|
template_params().at(0).to_string(using_namespace, relative),
|
||||||
template_params().at(1).to_string(using_namespace, relative),
|
template_params().at(1).to_string(using_namespace, relative));
|
||||||
qualifier());
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
auto it = template_params().begin();
|
auto it = template_params().begin();
|
||||||
@@ -253,9 +279,14 @@ std::string template_parameter::to_string(
|
|||||||
args.push_back(it->to_string(using_namespace, relative));
|
args.push_back(it->to_string(using_namespace, relative));
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt::format("{} ({}::*)({}){}", return_type, class_type,
|
unqualified = fmt::format("{} ({}::*)({})", return_type, class_type,
|
||||||
fmt::join(args, ","), qualifier());
|
fmt::join(args, ","));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (skip_qualifiers)
|
||||||
|
return unqualified;
|
||||||
|
else
|
||||||
|
return unqualified + qualifiers_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string res;
|
std::string res;
|
||||||
@@ -307,8 +338,8 @@ std::string template_parameter::to_string(
|
|||||||
res += fmt::format("<{}>", fmt::join(params, ","));
|
res += fmt::format("<{}>", fmt::join(params, ","));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!qualifier().empty())
|
if (!skip_qualifiers)
|
||||||
res += " " + qualifier();
|
res += qualifiers_str();
|
||||||
|
|
||||||
const auto &maybe_default_value = default_value();
|
const auto &maybe_default_value = default_value();
|
||||||
if (maybe_default_value) {
|
if (maybe_default_value) {
|
||||||
@@ -332,6 +363,9 @@ bool template_parameter::find_nested_relationships(
|
|||||||
// just add it and skip recursion (e.g. this is a user defined type)
|
// just add it and skip recursion (e.g. this is a user defined type)
|
||||||
const auto maybe_type = type();
|
const auto maybe_type = type();
|
||||||
if (maybe_type && should_include(maybe_type.value())) {
|
if (maybe_type && should_include(maybe_type.value())) {
|
||||||
|
if (is_pointer() || is_lvalue_reference() || is_rvalue_reference())
|
||||||
|
hint = common::model::relationship_t::kAssociation;
|
||||||
|
|
||||||
const auto maybe_id = id();
|
const auto maybe_id = id();
|
||||||
if (maybe_id) {
|
if (maybe_id) {
|
||||||
nested_relationships.emplace_back(maybe_id.value(), hint);
|
nested_relationships.emplace_back(maybe_id.value(), hint);
|
||||||
@@ -349,6 +383,11 @@ bool template_parameter::find_nested_relationships(
|
|||||||
|
|
||||||
if (maybe_id && maybe_arg_type && should_include(*maybe_arg_type)) {
|
if (maybe_id && maybe_arg_type && should_include(*maybe_arg_type)) {
|
||||||
|
|
||||||
|
if (template_argument.is_pointer() ||
|
||||||
|
template_argument.is_lvalue_reference() ||
|
||||||
|
template_argument.is_rvalue_reference())
|
||||||
|
hint = common::model::relationship_t::kAssociation;
|
||||||
|
|
||||||
nested_relationships.emplace_back(maybe_id.value(), hint);
|
nested_relationships.emplace_back(maybe_id.value(), hint);
|
||||||
|
|
||||||
added_aggregation_relationship =
|
added_aggregation_relationship =
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#include "common/model/namespace.h"
|
#include "common/model/namespace.h"
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -44,6 +45,13 @@ std::string to_string(template_parameter_kind_t k);
|
|||||||
/// nested templates
|
/// nested templates
|
||||||
class template_parameter {
|
class template_parameter {
|
||||||
public:
|
public:
|
||||||
|
enum class cvqualifier {
|
||||||
|
kConst,
|
||||||
|
kVolatile,
|
||||||
|
kLValueReference,
|
||||||
|
kRValueReference
|
||||||
|
};
|
||||||
|
|
||||||
static template_parameter make_template_type(const std::string &name,
|
static template_parameter make_template_type(const std::string &name,
|
||||||
const std::optional<std::string> &default_value = {},
|
const std::optional<std::string> &default_value = {},
|
||||||
bool is_variadic = false)
|
bool is_variadic = false)
|
||||||
@@ -149,7 +157,7 @@ public:
|
|||||||
|
|
||||||
std::string to_string(
|
std::string to_string(
|
||||||
const clanguml::common::model::namespace_ &using_namespace,
|
const clanguml::common::model::namespace_ &using_namespace,
|
||||||
bool relative) const;
|
bool relative, bool skip_qualifiers = false) const;
|
||||||
|
|
||||||
void add_template_param(template_parameter &&ct);
|
void add_template_param(template_parameter &&ct);
|
||||||
|
|
||||||
@@ -186,13 +194,26 @@ public:
|
|||||||
|
|
||||||
bool is_method_template() const { return is_method_template_; }
|
bool is_method_template() const { return is_method_template_; }
|
||||||
|
|
||||||
void set_qualifier(const std::string &q) { qualifier_ = q; }
|
void set_qualifier(const cvqualifier q) { qualifiers_.emplace(q); }
|
||||||
|
|
||||||
const std::string &qualifier() const { return qualifier_; }
|
const std::set<cvqualifier> &qualifiers() const { return qualifiers_; }
|
||||||
|
|
||||||
|
void is_pointer(bool p) { is_pointer_ = p; }
|
||||||
|
bool is_pointer() const { return is_pointer_; }
|
||||||
|
|
||||||
|
void is_lvalue_reference(bool p) { is_lvalue_reference_ = p; }
|
||||||
|
bool is_lvalue_reference() const { return is_lvalue_reference_; }
|
||||||
|
|
||||||
|
void is_rvalue_reference(bool p) { is_rvalue_reference_ = p; }
|
||||||
|
bool is_rvalue_reference() const { return is_rvalue_reference_; }
|
||||||
|
|
||||||
|
void is_elipssis(bool e) { is_elipssis_ = e; }
|
||||||
|
bool is_elipssis() const { return is_elipssis_; }
|
||||||
private:
|
private:
|
||||||
template_parameter() = default;
|
template_parameter() = default;
|
||||||
|
|
||||||
|
std::string qualifiers_str() const;
|
||||||
|
|
||||||
template_parameter_kind_t kind_{template_parameter_kind_t::template_type};
|
template_parameter_kind_t kind_{template_parameter_kind_t::template_type};
|
||||||
|
|
||||||
/// Represents the type of non-type template parameters
|
/// Represents the type of non-type template parameters
|
||||||
@@ -213,14 +234,20 @@ private:
|
|||||||
/// Can only be true when is_template_parameter_ is true
|
/// Can only be true when is_template_parameter_ is true
|
||||||
bool is_template_template_parameter_{false};
|
bool is_template_template_parameter_{false};
|
||||||
|
|
||||||
|
bool is_elipssis_{false};
|
||||||
|
|
||||||
/// Whether the template parameter is variadic
|
/// Whether the template parameter is variadic
|
||||||
bool is_variadic_{false};
|
bool is_variadic_{false};
|
||||||
|
|
||||||
|
bool is_pointer_{false};
|
||||||
|
bool is_lvalue_reference_{false};
|
||||||
|
bool is_rvalue_reference_{false};
|
||||||
|
|
||||||
bool is_function_template_{false};
|
bool is_function_template_{false};
|
||||||
|
|
||||||
bool is_method_template_{false};
|
bool is_method_template_{false};
|
||||||
|
|
||||||
std::string qualifier_;
|
std::set<cvqualifier> qualifiers_;
|
||||||
|
|
||||||
/// Stores optional fully qualified name of constraint for this template
|
/// Stores optional fully qualified name of constraint for this template
|
||||||
/// parameter
|
/// parameter
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ set(TEST_CASES
|
|||||||
test_config
|
test_config
|
||||||
test_cli_handler
|
test_cli_handler
|
||||||
test_filters
|
test_filters
|
||||||
|
test_template_parser
|
||||||
test_thread_pool_executor)
|
test_thread_pool_executor)
|
||||||
|
|
||||||
foreach(TEST_NAME ${TEST_CASES})
|
foreach(TEST_NAME ${TEST_CASES})
|
||||||
|
|||||||
@@ -60,20 +60,16 @@ TEST_CASE("t00051", "[test-case][class]")
|
|||||||
|
|
||||||
REQUIRE_THAT(puml,
|
REQUIRE_THAT(puml,
|
||||||
IsClassTemplate("B",
|
IsClassTemplate("B",
|
||||||
"(lambda at ../../tests/t00051/t00051.cc:43:18),(lambda at "
|
"(lambda at ../../tests/t00051/t00051.cc:43:18)"));
|
||||||
"../../tests/t00051/t00051.cc:43:27)"));
|
//,(lambda at ../../tests/t00051/t00051.cc:43:27)"));
|
||||||
|
|
||||||
REQUIRE_THAT(puml,
|
REQUIRE_THAT(puml,
|
||||||
IsInstantiation(_A("B<F,FF=F>"),
|
IsInstantiation(_A("B<F,FF=F>"),
|
||||||
_A("B<(lambda at ../../tests/t00051/t00051.cc:43:18),(lambda "
|
_A("B<(lambda at ../../tests/t00051/t00051.cc:43:18)>")));
|
||||||
"at "
|
|
||||||
"../../tests/t00051/t00051.cc:43:27)>")));
|
|
||||||
|
|
||||||
REQUIRE_THAT(puml,
|
REQUIRE_THAT(puml,
|
||||||
IsDependency(_A("A"),
|
IsDependency(_A("A"),
|
||||||
_A("B<(lambda at ../../tests/t00051/t00051.cc:43:18),(lambda "
|
_A("B<(lambda at ../../tests/t00051/t00051.cc:43:18)>")));
|
||||||
"at "
|
|
||||||
"../../tests/t00051/t00051.cc:43:27)>")));
|
|
||||||
|
|
||||||
save_puml(
|
save_puml(
|
||||||
config.output_directory() + "/" + diagram->name + ".puml", puml);
|
config.output_directory() + "/" + diagram->name + ".puml", puml);
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace clanguml {
|
namespace clanguml {
|
||||||
@@ -8,6 +10,17 @@ template <typename U> struct A<U &> {
|
|||||||
U &u;
|
U &u;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename U> struct A<std::map<std::string, U> &> {
|
||||||
|
U &u;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct A<std::map<std::string, std::map<std::string, std::string>> &> { };
|
||||||
|
|
||||||
|
template <typename U> struct A<U ***> {
|
||||||
|
U ***u;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename U> struct A<U &&> {
|
template <typename U> struct A<U &&> {
|
||||||
U &&u;
|
U &&u;
|
||||||
};
|
};
|
||||||
@@ -58,5 +71,6 @@ template <int N> struct A<char[N]> {
|
|||||||
template <> struct A<char[1000]> {
|
template <> struct A<char[1000]> {
|
||||||
std::vector<char> n;
|
std::vector<char> n;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -36,7 +36,7 @@ TEST_CASE("t00062", "[test-case][class]")
|
|||||||
REQUIRE_THAT(puml, EndsWith("@enduml\n"));
|
REQUIRE_THAT(puml, EndsWith("@enduml\n"));
|
||||||
|
|
||||||
// Check if all classes exist
|
// Check if all classes exist
|
||||||
REQUIRE_THAT(puml, IsClassTemplate("A", "T"));
|
REQUIRE_THAT(puml, IsClassTemplate("A", "TTTT"));
|
||||||
REQUIRE_THAT(puml, IsClassTemplate("A", "U &"));
|
REQUIRE_THAT(puml, IsClassTemplate("A", "U &"));
|
||||||
REQUIRE_THAT(puml, IsClassTemplate("A", "U &&"));
|
REQUIRE_THAT(puml, IsClassTemplate("A", "U &&"));
|
||||||
REQUIRE_THAT(puml, IsClassTemplate("A", "U const&"));
|
REQUIRE_THAT(puml, IsClassTemplate("A", "U const&"));
|
||||||
|
|||||||
Reference in New Issue
Block a user