Improved rendering of template methods in class diagrams
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -61,4 +61,5 @@ void class_method::add_parameter(method_parameter &¶meter)
|
||||
{
|
||||
parameters_.emplace_back(std::move(parameter));
|
||||
}
|
||||
|
||||
} // namespace clanguml::class_diagram::model
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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 ¶meter_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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
97
src/common/model/template_trait.cc
Normal file
97
src/common/model/template_trait.cc
Normal 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
|
||||
54
src/common/model/template_trait.h
Normal file
54
src/common/model/template_trait.h
Normal 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
|
||||
@@ -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 ¶ms,
|
||||
std::vector<common::model::template_parameter> parse_unexposed_template_params(
|
||||
const std::string ¶ms,
|
||||
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;
|
||||
|
||||
|
||||
@@ -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 ¶ms,
|
||||
std::vector<common::model::template_parameter> parse_unexposed_template_params(
|
||||
const std::string ¶ms,
|
||||
const std::function<std::string(const std::string &)> &ns_resolve,
|
||||
int depth = 0);
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
12
tests/t00052/.clang-uml
Normal 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
19
tests/t00052/t00052.cc
Normal 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
50
tests/t00052/test_case.h
Normal 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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user