Improved rendering of template methods in class diagrams

This commit is contained in:
Bartek Kryza
2023-01-25 00:56:33 +01:00
parent 0e6532f66c
commit 9a7d66f93f
24 changed files with 335 additions and 226 deletions

View File

@@ -144,6 +144,10 @@ void generator::generate(const class_ &c, std::ostream &ostr) const
ostr << plantuml_common::to_plantuml(m.access()) << m.name();
if (!m.templates().empty()) {
m.render_template_params(ostr, m_config.using_namespace(), false);
}
ostr << "(";
if (m_config.generate_method_arguments() !=
config::method_arguments::none) {

View File

@@ -68,29 +68,12 @@ void class_::add_parent(class_parent &&parent)
bases_.emplace_back(std::move(parent));
}
void class_::add_template(template_parameter &&tmplt)
{
templates_.emplace_back(std::move(tmplt));
}
const std::vector<class_member> &class_::members() const { return members_; }
const std::vector<class_method> &class_::methods() const { return methods_; }
const std::vector<class_parent> &class_::parents() const { return bases_; }
const std::vector<template_parameter> &class_::templates() const
{
return templates_;
}
void class_::set_base_template(const std::string &full_name)
{
base_template_full_name_ = full_name;
}
std::string class_::base_template() const { return base_template_full_name_; }
bool operator==(const class_ &l, const class_ &r) { return l.id() == r.id(); }
std::string class_::full_name_no_ns() const
@@ -101,7 +84,7 @@ std::string class_::full_name_no_ns() const
ostr << name();
render_template_params(ostr, false);
render_template_params(ostr, using_namespace(), false);
return ostr.str();
}
@@ -114,7 +97,8 @@ std::string class_::full_name(bool relative) const
std::ostringstream ostr;
ostr << name_and_ns();
render_template_params(ostr, relative);
render_template_params(ostr, using_namespace(), relative);
std::string res;
@@ -129,26 +113,6 @@ std::string class_::full_name(bool relative) const
return res;
}
std::ostringstream &class_::render_template_params(
std::ostringstream &ostr, bool relative) const
{
using clanguml::common::model::namespace_;
if (!templates_.empty()) {
std::vector<std::string> tnames;
std::vector<std::string> tnames_simplified;
std::transform(templates_.cbegin(), templates_.cend(),
std::back_inserter(tnames),
[ns = using_namespace(), relative](
const auto &tmplt) { return tmplt.to_string(ns, relative); });
ostr << fmt::format("<{}>", fmt::join(tnames, ","));
}
return ostr;
}
bool class_::is_abstract() const
{
// TODO check if all base abstract methods are overriden

View File

@@ -23,8 +23,9 @@
#include "common/model/element.h"
#include "common/model/enums.h"
#include "common/model/stylable_element.h"
#include "common/model/template_parameter.h"
#include "common/model/template_trait.h"
#include "common/types.h"
#include "template_parameter.h"
#include <string>
#include <vector>
@@ -32,7 +33,8 @@
namespace clanguml::class_diagram::model {
class class_ : public common::model::element,
public common::model::stylable_element {
public common::model::stylable_element,
public template_trait {
public:
class_(const common::model::namespace_ &using_namespace);
@@ -55,12 +57,10 @@ public:
void add_member(class_member &&member);
void add_method(class_method &&method);
void add_parent(class_parent &&parent);
void add_template(template_parameter &&tmplt);
const std::vector<class_member> &members() const;
const std::vector<class_method> &methods() const;
const std::vector<class_parent> &parents() const;
const std::vector<template_parameter> &templates() const;
void set_base_template(const std::string &full_name);
std::string base_template() const;
@@ -85,9 +85,6 @@ public:
const class_ &other, const std::string &full_name) const;
private:
std::ostringstream &render_template_params(
std::ostringstream &ostr, bool relative) const;
bool is_struct_{false};
bool is_template_{false};
bool is_template_instantiation_{false};
@@ -95,7 +92,6 @@ private:
std::vector<class_member> members_;
std::vector<class_method> methods_;
std::vector<class_parent> bases_;
std::vector<template_parameter> templates_;
std::string base_template_full_name_;
std::string full_name_;

View File

@@ -61,4 +61,5 @@ void class_method::add_parameter(method_parameter &&parameter)
{
parameters_.emplace_back(std::move(parameter));
}
} // namespace clanguml::class_diagram::model

View File

@@ -18,6 +18,8 @@
#pragma once
#include "class_element.h"
#include "common/model/template_parameter.h"
#include "common/model/template_trait.h"
#include "method_parameter.h"
#include <string>
@@ -25,7 +27,9 @@
namespace clanguml::class_diagram::model {
class class_method : public class_element {
using clanguml::common::model::template_trait;
class class_method : public class_element, public template_trait {
public:
class_method(common::model::access_t access, const std::string &name,
const std::string &type);
@@ -52,6 +56,7 @@ public:
private:
std::vector<method_parameter> parameters_;
bool is_pure_virtual_{false};
bool is_virtual_{false};
bool is_const_{false};

View File

@@ -26,19 +26,6 @@
namespace clanguml::class_diagram::visitor {
using clanguml::class_diagram::model::class_;
using clanguml::class_diagram::model::class_member;
using clanguml::class_diagram::model::class_method;
using clanguml::class_diagram::model::class_parent;
using clanguml::class_diagram::model::diagram;
using clanguml::class_diagram::model::enum_;
using clanguml::class_diagram::model::method_parameter;
using clanguml::class_diagram::model::template_parameter;
using clanguml::common::model::access_t;
using clanguml::common::model::namespace_;
using clanguml::common::model::relationship;
using clanguml::common::model::relationship_t;
translation_unit_visitor::translation_unit_visitor(clang::SourceManager &sm,
clanguml::class_diagram::model::diagram &diagram,
const clanguml::config::class_diagram &config)
@@ -513,7 +500,8 @@ void translation_unit_visitor::process_class_declaration(
}
bool translation_unit_visitor::process_template_parameters(
const clang::ClassTemplateDecl &template_declaration, class_ &c)
const clang::TemplateDecl &template_declaration,
common::model::template_trait &c)
{
LOG_DBG("Processing class {} template parameters...",
common::get_qualified_name(template_declaration));
@@ -966,6 +954,8 @@ void translation_unit_visitor::process_template_method(
method.is_defaulted(mf.getTemplatedDecl()->isDefaulted());
method.is_static(mf.getTemplatedDecl()->isStatic());
process_template_parameters(mf, method);
process_comment(mf, method);
if (method.skip())

View File

@@ -20,6 +20,7 @@
#include "class_diagram/model/class.h"
#include "class_diagram/model/diagram.h"
#include "common/model/enums.h"
#include "common/model/template_trait.h"
#include "common/visitor/translation_unit_visitor.h"
#include "config/config.h"
@@ -34,6 +35,20 @@
namespace clanguml::class_diagram::visitor {
using clanguml::class_diagram::model::class_;
using clanguml::class_diagram::model::class_member;
using clanguml::class_diagram::model::class_method;
using clanguml::class_diagram::model::class_parent;
using clanguml::class_diagram::model::diagram;
using clanguml::class_diagram::model::enum_;
using clanguml::class_diagram::model::method_parameter;
using clanguml::common::model::access_t;
using clanguml::common::model::namespace_;
using clanguml::common::model::relationship;
using clanguml::common::model::relationship_t;
using clanguml::common::model::template_parameter;
using clanguml::common::model::template_trait;
using found_relationships_t =
std::vector<std::pair<clanguml::common::model::diagram_element::id_t,
common::model::relationship_t>>;
@@ -108,12 +123,11 @@ private:
clang::ClassTemplateSpecializationDecl *cls);
void process_template_specialization_children(
const clang::ClassTemplateSpecializationDecl *cls,
clanguml::class_diagram::model::class_ &c);
const clang::ClassTemplateSpecializationDecl *cls, class_ &c);
bool process_template_parameters(
const clang::ClassTemplateDecl &template_declaration,
clanguml::class_diagram::model::class_ &c);
const clang::TemplateDecl &template_declaration,
clanguml::common::model::template_trait &t);
void process_template_specialization_argument(
const clang::ClassTemplateSpecializationDecl *cls,
@@ -171,7 +185,7 @@ private:
clanguml::class_diagram::model::class_ &tinst,
std::deque<std::tuple<std::string, int, bool>> &template_base_params,
int arg_index, bool variadic_params,
const clanguml::class_diagram::model::template_parameter &ct) const;
const clanguml::common::model::template_parameter &ct) const;
void build_template_instantiation_process_template_arguments(
std::optional<clanguml::class_diagram::model::class_ *> &parent,
@@ -186,15 +200,15 @@ private:
const std::string &full_template_specialization_name,
const clang::TemplateDecl *template_decl,
const clang::TemplateArgument &arg,
model::template_parameter &argument);
common::model::template_parameter &argument);
void build_template_instantiation_process_expression_argument(
const clang::TemplateArgument &arg,
model::template_parameter &argument) const;
common::model::template_parameter &argument) const;
void build_template_instantiation_process_integral_argument(
const clang::TemplateArgument &arg,
model::template_parameter &argument) const;
common::model::template_parameter &argument) const;
void build_template_instantiation_process_type_argument(
std::optional<clanguml::class_diagram::model::class_ *> &parent,
@@ -202,11 +216,11 @@ private:
const clang::TemplateDecl *template_decl,
const clang::TemplateArgument &arg,
model::class_ &template_instantiation,
model::template_parameter &argument);
common::model::template_parameter &argument);
void build_template_instantiation_process_template_argument(
const clang::TemplateArgument &arg,
model::template_parameter &argument) const;
common::model::template_parameter &argument) const;
void ensure_lambda_type_is_relative(std::string &parameter_type) const;
@@ -220,19 +234,19 @@ private:
void process_unexposed_template_specialization_parameters(
const std::string &tspec,
clanguml::class_diagram::model::template_parameter &tp,
clanguml::common::model::template_parameter &tp,
clanguml::class_diagram::model::class_ &c);
bool find_relationships_in_unexposed_template_params(
const clanguml::class_diagram::model::template_parameter &ct,
const clanguml::common::model::template_parameter &ct,
found_relationships_t &relationships);
void add_incomplete_forward_declarations();
void resolve_local_to_global_ids();
bool simplify_system_template(
model::template_parameter &ct, const std::string &full_name) const;
bool simplify_system_template(common::model::template_parameter &ct,
const std::string &full_name) const;
/// Store the mapping from local clang entity id (obtained using
/// getID()) method to clang-uml global id

View File

@@ -1,5 +1,5 @@
/**
* src/class_diagram/model/template_parameter.cc
* src/common/model/template_parameter.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -22,7 +22,7 @@
#include <utility>
namespace clanguml::class_diagram::model {
namespace clanguml::common::model {
template_parameter::template_parameter(const std::string &type,
const std::string &name, std::string default_value, bool is_variadic)
@@ -216,4 +216,4 @@ bool template_parameter::find_nested_relationships(
return added_aggregation_relationship;
}
} // namespace clanguml::class_diagram::model
} // namespace clanguml::common::model

View File

@@ -1,5 +1,5 @@
/**
* src/class_diagram/model/template_parameter.h
* src/common/model/template_parameter.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -24,7 +24,7 @@
#include <string>
#include <vector>
namespace clanguml::class_diagram::model {
namespace clanguml::common::model {
/// @brief Represents template parameter or template argument
///
@@ -130,4 +130,4 @@ private:
std::optional<int64_t> id_;
};
} // namespace clanguml::class_diagram::model
} // namespace clanguml::common::model

View File

@@ -0,0 +1,97 @@
/**
* src/common/model/template_trait.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "common/model/template_trait.h"
namespace clanguml::common::model {
std::ostream &template_trait::render_template_params(std::ostream &ostr,
const common::model::namespace_ &using_namespace, bool relative) const
{
using clanguml::common::model::namespace_;
if (!templates_.empty()) {
std::vector<std::string> tnames;
std::vector<std::string> tnames_simplified;
std::transform(templates_.cbegin(), templates_.cend(),
std::back_inserter(tnames),
[ns = using_namespace, relative](
const auto &tmplt) { return tmplt.to_string(ns, relative); });
ostr << fmt::format("<{}>", fmt::join(tnames, ","));
}
return ostr;
}
void template_trait::set_base_template(const std::string &full_name)
{
base_template_full_name_ = full_name;
}
std::string template_trait::base_template() const
{
return base_template_full_name_;
}
void template_trait::add_template(template_parameter &&tmplt)
{
templates_.push_back(std::move(tmplt));
}
bool template_trait::is_implicit() const { return is_implicit_; }
void template_trait::set_implicit(bool implicit) { is_implicit_ = implicit; }
const std::vector<template_parameter> &template_trait::templates() const
{
return templates_;
}
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;
}
// 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)) {
continue;
}
else {
res = 0;
break;
}
}
return res;
}
} // namespace clanguml::common::model

View File

@@ -0,0 +1,54 @@
/**
* src/common/model/template_trait.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "common/model/element.h"
#include "common/model/template_parameter.h"
#include <string>
#include <vector>
namespace clanguml::common::model {
class template_trait {
public:
std::ostream &render_template_params(std::ostream &ostr,
const common::model::namespace_ &using_namespace, bool relative) const;
void set_base_template(const std::string &full_name);
std::string base_template() const;
void add_template(template_parameter &&tmplt);
const std::vector<template_parameter> &templates() const;
int calculate_template_specialization_match(
const template_trait &other, const std::string &full_name) const;
bool is_implicit() const;
void set_implicit(bool implicit);
private:
std::vector<template_parameter> templates_;
std::string base_template_full_name_;
bool is_implicit_{false};
};
} // namespace clanguml::common::model

View File

@@ -21,7 +21,6 @@
#include <spdlog/spdlog.h>
#include <class_diagram/model/template_parameter.h>
#include <list>
namespace clanguml::cx::util {
@@ -39,12 +38,12 @@ std::pair<common::model::namespace_, std::string> split_ns(
return {ns, name};
}
std::vector<class_diagram::model::template_parameter>
parse_unexposed_template_params(const std::string &params,
std::vector<common::model::template_parameter> parse_unexposed_template_params(
const std::string &params,
const std::function<std::string(const std::string &)> &ns_resolve,
int depth)
{
using class_diagram::model::template_parameter;
using common::model::template_parameter;
std::vector<template_parameter> res;

View File

@@ -19,7 +19,8 @@
#include "common/model/namespace.h"
#include <class_diagram/model/template_parameter.h>
#include "common/model/template_parameter.h"
#include <string>
namespace clanguml::cx::util {
@@ -27,8 +28,8 @@ namespace clanguml::cx::util {
std::pair<common::model::namespace_, std::string> split_ns(
const std::string &full_name);
std::vector<class_diagram::model::template_parameter>
parse_unexposed_template_params(const std::string &params,
std::vector<common::model::template_parameter> parse_unexposed_template_params(
const std::string &params,
const std::function<std::string(const std::string &)> &ns_resolve,
int depth = 0);

View File

@@ -20,83 +20,6 @@
namespace clanguml::sequence_diagram::model {
std::ostringstream &template_trait::render_template_params(
std::ostringstream &ostr, const common::model::namespace_ &using_namespace,
bool relative) const
{
using clanguml::common::model::namespace_;
if (!templates_.empty()) {
std::vector<std::string> tnames;
std::vector<std::string> tnames_simplified;
std::transform(templates_.cbegin(), templates_.cend(),
std::back_inserter(tnames),
[ns = using_namespace, relative](
const auto &tmplt) { return tmplt.to_string(ns, relative); });
ostr << fmt::format("<{}>", fmt::join(tnames, ","));
}
return ostr;
}
void template_trait::set_base_template(const std::string &full_name)
{
base_template_full_name_ = full_name;
}
std::string template_trait::base_template() const
{
return base_template_full_name_;
}
void template_trait::add_template(
class_diagram::model::template_parameter tmplt)
{
templates_.push_back(std::move(tmplt));
}
bool template_trait::is_implicit() const { return is_implicit_; }
void template_trait::set_implicit(bool implicit) { is_implicit_ = implicit; }
const std::vector<class_diagram::model::template_parameter> &
template_trait::templates() const
{
return templates_;
}
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;
}
// 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)) {
continue;
}
else {
res = 0;
break;
}
}
return res;
}
std::string participant::to_string() const
{
return fmt::format(

View File

@@ -17,39 +17,16 @@
*/
#pragma once
#include "class_diagram/model/template_parameter.h"
#include "common/model/element.h"
#include "common/model/template_parameter.h"
#include "common/model/template_trait.h"
#include <string>
#include <vector>
namespace clanguml::sequence_diagram::model {
struct template_trait {
std::ostringstream &render_template_params(std::ostringstream &ostr,
const common::model::namespace_ &using_namespace, bool relative) const;
void set_base_template(const std::string &full_name);
std::string base_template() const;
void add_template(class_diagram::model::template_parameter tmplt);
const std::vector<class_diagram::model::template_parameter> &
templates() const;
int calculate_template_specialization_match(
const template_trait &other, const std::string &full_name) const;
bool is_implicit() const;
void set_implicit(bool implicit);
private:
std::vector<class_diagram::model::template_parameter> templates_;
std::string base_template_full_name_;
bool is_implicit_{false};
};
using clanguml::common::model::template_trait;
struct participant : public common::model::element,
public common::model::stylable_element {

View File

@@ -1336,7 +1336,7 @@ bool translation_unit_visitor::process_template_parameters(
const clang::TemplateDecl &template_declaration,
sequence_diagram::model::template_trait &c)
{
using class_diagram::model::template_parameter;
using common::model::template_parameter;
LOG_TRACE("Processing class {} template parameters...",
common::get_qualified_name(template_declaration));
@@ -1357,7 +1357,7 @@ bool translation_unit_visitor::process_template_parameters(
ct.set_default_value("");
ct.is_variadic(template_type_parameter->isParameterPack());
c.add_template(ct);
c.add_template(std::move(ct));
}
else if (clang::dyn_cast_or_null<clang::NonTypeTemplateParmDecl>(
parameter) != nullptr) {
@@ -1371,7 +1371,7 @@ bool translation_unit_visitor::process_template_parameters(
ct.set_default_value("");
ct.is_variadic(template_nontype_parameter->isParameterPack());
c.add_template(ct);
c.add_template(std::move(ct));
}
else if (clang::dyn_cast_or_null<clang::TemplateTemplateParmDecl>(
parameter) != nullptr) {
@@ -1385,7 +1385,7 @@ bool translation_unit_visitor::process_template_parameters(
ct.set_default_value("");
ct.is_variadic(template_template_parameter->isParameterPack());
c.add_template(ct);
c.add_template(std::move(ct));
}
else {
// pass
@@ -1510,7 +1510,7 @@ void translation_unit_visitor::
{
for (const auto &arg : template_args) {
const auto argument_kind = arg.getKind();
class_diagram::model::template_parameter argument;
common::model::template_parameter argument;
if (argument_kind == clang::TemplateArgument::Template) {
build_template_instantiation_process_template_argument(
arg, argument);
@@ -1535,14 +1535,14 @@ void translation_unit_visitor::
simplify_system_template(
argument, argument.to_string(config().using_namespace(), false));
template_instantiation.add_template(argument);
template_instantiation.add_template(std::move(argument));
}
}
void translation_unit_visitor::
build_template_instantiation_process_template_argument(
const clang::TemplateArgument &arg,
class_diagram::model::template_parameter &argument) const
common::model::template_parameter &argument) const
{
argument.is_template_parameter(true);
auto arg_name =
@@ -1553,7 +1553,7 @@ void translation_unit_visitor::
void translation_unit_visitor::
build_template_instantiation_process_integral_argument(
const clang::TemplateArgument &arg,
class_diagram::model::template_parameter &argument) const
common::model::template_parameter &argument) const
{
assert(arg.getKind() == clang::TemplateArgument::Integral);
@@ -1564,7 +1564,7 @@ void translation_unit_visitor::
void translation_unit_visitor::
build_template_instantiation_process_expression_argument(
const clang::TemplateArgument &arg,
class_diagram::model::template_parameter &argument) const
common::model::template_parameter &argument) const
{
assert(arg.getKind() == clang::TemplateArgument::Expression);
@@ -1579,7 +1579,7 @@ void translation_unit_visitor::
const std::string & /*full_template_specialization_name*/,
const clang::TemplateDecl *template_decl,
const clang::TemplateArgument &arg,
class_diagram::model::template_parameter &argument) const
common::model::template_parameter &argument) const
{
assert(arg.getKind() == clang::TemplateArgument::Type);
@@ -1596,7 +1596,7 @@ void translation_unit_visitor::
const clang::TemplateDecl *template_decl,
const clang::TemplateArgument &arg,
model::template_trait &template_instantiation,
class_diagram::model::template_parameter &argument)
common::model::template_parameter &argument)
{
assert(arg.getKind() == clang::TemplateArgument::Type);
@@ -1685,7 +1685,7 @@ void translation_unit_visitor::process_template_specialization_argument(
const auto argument_kind = arg.getKind();
if (argument_kind == clang::TemplateArgument::Type) {
class_diagram::model::template_parameter argument;
common::model::template_parameter argument;
argument.is_template_parameter(false);
// If this is a nested template type - add nested templates as
@@ -1816,23 +1816,23 @@ void translation_unit_visitor::process_template_specialization_argument(
simplify_system_template(
argument, argument.to_string(config().using_namespace(), false));
template_instantiation.add_template(argument);
template_instantiation.add_template(std::move(argument));
}
else if (argument_kind == clang::TemplateArgument::Integral) {
class_diagram::model::template_parameter argument;
common::model::template_parameter argument;
argument.is_template_parameter(false);
argument.set_type(std::to_string(arg.getAsIntegral().getExtValue()));
template_instantiation.add_template(argument);
template_instantiation.add_template(std::move(argument));
}
else if (argument_kind == clang::TemplateArgument::Expression) {
class_diagram::model::template_parameter argument;
common::model::template_parameter argument;
argument.is_template_parameter(false);
argument.set_type(common::get_source_text(
arg.getAsExpr()->getSourceRange(), source_manager()));
template_instantiation.add_template(argument);
template_instantiation.add_template(std::move(argument));
}
else if (argument_kind == clang::TemplateArgument::TemplateExpansion) {
class_diagram::model::template_parameter argument;
common::model::template_parameter argument;
argument.is_template_parameter(true);
cls->getLocation().dump(source_manager());
@@ -2040,8 +2040,7 @@ translation_unit_visitor::build_template_instantiation(
void translation_unit_visitor::
process_unexposed_template_specialization_parameters(
const std::string &type_name,
class_diagram::model::template_parameter &tp,
const std::string &type_name, common::model::template_parameter &tp,
model::class_ & /*c*/) const
{
auto template_params = cx::util::parse_unexposed_template_params(
@@ -2053,8 +2052,7 @@ void translation_unit_visitor::
}
bool translation_unit_visitor::simplify_system_template(
class_diagram::model::template_parameter &ct,
const std::string &full_name) const
common::model::template_parameter &ct, const std::string &full_name) const
{
if (config().type_aliases().count(full_name) > 0) {
ct.set_name(config().type_aliases().at(full_name));

View File

@@ -30,6 +30,8 @@
namespace clanguml::sequence_diagram::visitor {
using common::model::template_parameter;
std::string to_string(const clang::FunctionTemplateDecl *decl);
class translation_unit_visitor
@@ -179,7 +181,7 @@ private:
bool process_template_parameters(
const clang::TemplateDecl &template_declaration,
sequence_diagram::model::template_trait &c);
common::model::template_trait &c);
std::unique_ptr<model::function_template>
build_function_template_instantiation(const clang::FunctionDecl &pDecl);
@@ -200,22 +202,22 @@ private:
void build_template_instantiation_process_template_argument(
const clang::TemplateArgument &arg,
class_diagram::model::template_parameter &argument) const;
common::model::template_parameter &argument) const;
void build_template_instantiation_process_integral_argument(
const clang::TemplateArgument &arg,
class_diagram::model::template_parameter &argument) const;
common::model::template_parameter &argument) const;
void build_template_instantiation_process_expression_argument(
const clang::TemplateArgument &arg,
class_diagram::model::template_parameter &argument) const;
common::model::template_parameter &argument) const;
void build_template_instantiation_process_tag_argument(
model::template_trait &template_instantiation,
const std::string &full_template_specialization_name,
const clang::TemplateDecl *template_decl,
const clang::TemplateArgument &arg,
class_diagram::model::template_parameter &argument) const;
common::model::template_parameter &argument) const;
void build_template_instantiation_process_type_argument(
model::template_trait *parent,
@@ -223,7 +225,7 @@ private:
const clang::TemplateDecl *template_decl,
const clang::TemplateArgument &arg,
model::template_trait &template_instantiation,
class_diagram::model::template_parameter &argument);
common::model::template_parameter &argument);
std::unique_ptr<model::class_> process_template_specialization(
clang::ClassTemplateSpecializationDecl *cls);
@@ -235,14 +237,14 @@ private:
bool in_parameter_pack = false);
void process_unexposed_template_specialization_parameters(
const std::string &type_name,
class_diagram::model::template_parameter &tp, model::class_ &c) const;
const std::string &type_name, common::model::template_parameter &tp,
model::class_ &c) const;
std::unique_ptr<model::class_> build_template_instantiation(
const clang::TemplateSpecializationType &template_type_decl,
model::class_ *parent);
bool simplify_system_template(class_diagram::model::template_parameter &ct,
bool simplify_system_template(common::model::template_parameter &ct,
const std::string &full_name) const;
std::string simplify_system_template(const std::string &full_name) const;

View File

@@ -19,7 +19,6 @@ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} ${LIBCLANG_CXXFLAGS} ${TEST_DISAB
if(APPLE)
# Without this, clang-uml test cases fail with error saying that clang cannot find stdarg.h
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I${LLVM_LIBRARY_DIR}/clang/${LLVM_PACKAGE_VERSION}/include")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -I${LLVM_LIBRARY_DIR}/clang/${LLVM_PACKAGE_VERSION}/include")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -I${LLVM_LIBRARY_DIR}/clang/${LLVM_PACKAGE_VERSION}/include")
endif(APPLE)

View File

@@ -40,8 +40,8 @@ TEST_CASE("t00051", "[test-case][class]")
REQUIRE_THAT(puml, IsInnerClass(_A("A"), _A("A::custom_thread2")));
REQUIRE_THAT(puml,
(IsMethod<Public>(
"custom_thread1", "void", "Function && f, Args &&... args")));
(IsMethod<Public>("custom_thread1<Function,Args...>", "void",
"Function && f, Args &&... args")));
REQUIRE_THAT(puml,
(IsMethod<Public>("thread", "void",
"(lambda at ../../tests/t00051/t00051.cc:59:27) && ")));

12
tests/t00052/.clang-uml Normal file
View File

@@ -0,0 +1,12 @@
compilation_database_dir: ..
output_directory: puml
diagrams:
t00052_class:
type: class
glob:
- ../../tests/t00052/t00052.cc
include:
namespaces:
- clanguml::t00052
using_namespace:
- clanguml::t00052

19
tests/t00052/t00052.cc Normal file
View File

@@ -0,0 +1,19 @@
namespace clanguml {
namespace t00052 {
class A {
public:
template <typename T> T a(T p) { return p; }
template <typename F, typename Q> void aa(F &&f, Q q) { f(q); }
};
template <typename T> class B {
public:
T b(T t) { return t; }
template <typename F> T bb(F &&f, T t) { return f(t); }
};
}
}

50
tests/t00052/test_case.h Normal file
View File

@@ -0,0 +1,50 @@
/**
* tests/t00052/test_case.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
TEST_CASE("t00052", "[test-case][class]")
{
auto [config, db] = load_config("t00052");
auto diagram = config.diagrams["t00052_class"];
REQUIRE(diagram->name == "t00052_class");
auto model = generate_class_diagram(*db, diagram);
REQUIRE(model->name() == "t00052_class");
auto puml = generate_class_puml(diagram, *model);
AliasMatcher _A(puml);
REQUIRE_THAT(puml, StartsWith("@startuml"));
REQUIRE_THAT(puml, EndsWith("@enduml\n"));
// Check if all classes exist
REQUIRE_THAT(puml, IsClass(_A("A")));
// Check if class templates exist
REQUIRE_THAT(puml, IsClassTemplate("B", "T"));
// Check if all methods exist
REQUIRE_THAT(puml, (IsMethod<Public>("a<T>", "T", "T p")));
REQUIRE_THAT(puml, (IsMethod<Public>("aa<F,Q>", "void", "F && f, Q q")));
REQUIRE_THAT(puml, (IsMethod<Public>("b", "T", "T t")));
REQUIRE_THAT(puml, (IsMethod<Public>("bb<F>", "T", "F && f, T t")));
save_puml(config.output_directory() + "/" + diagram->name + ".puml", puml);
}

View File

@@ -245,6 +245,7 @@ using namespace clanguml::test::matchers;
#include "t00049/test_case.h"
#include "t00050/test_case.h"
#include "t00051/test_case.h"
#include "t00052/test_case.h"
///
/// Sequence diagram tests

View File

@@ -150,6 +150,9 @@ test_cases:
- name: t00051
title: Test case for relative paths in lambda names
description:
- name: t00052
title: Test case for template methods rendering
description:
Sequence diagrams:
- name: t20001
title: Basic sequence diagram test case