Fixed template function sequence diagram test case

This commit is contained in:
Bartek Kryza
2022-10-30 10:17:47 +01:00
parent 4f1a143a1b
commit 08d0431a14
5 changed files with 181 additions and 87 deletions

View File

@@ -19,6 +19,50 @@
#include "participant.h"
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));
}
const std::vector<class_diagram::model::template_parameter> &
template_trait::templates() const
{
return templates_;
}
class_::class_(const common::model::namespace_ &using_namespace)
: participant{using_namespace}
{
@@ -42,17 +86,6 @@ void class_::is_template_instantiation(bool is_template_instantiation)
is_template_instantiation_ = is_template_instantiation;
}
void class_::add_template(class_diagram::model::template_parameter tmplt)
{
templates_.emplace_back(std::move(tmplt));
}
const std::vector<class_diagram::model::template_parameter> &
class_::templates() const
{
return templates_;
}
std::string class_::full_name_no_ns() const
{
using namespace clanguml::util;
@@ -61,7 +94,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();
}
@@ -74,7 +107,7 @@ 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;
@@ -89,26 +122,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;
}
function::function(const common::model::namespace_ &using_namespace)
: participant{using_namespace}
{
@@ -135,4 +148,51 @@ std::string method::alias() const
return fmt::format("C_{:022}", class_id_);
}
function_template::function_template(
const common::model::namespace_ &using_namespace)
: participant{using_namespace}
{
}
std::string function_template::full_name(bool relative) const
{
using namespace clanguml::util;
using clanguml::common::model::namespace_;
std::ostringstream ostr;
ostr << name_and_ns();
render_template_params(ostr, using_namespace(), relative);
ostr << "()";
std::string res;
if (relative)
res = using_namespace().relative(ostr.str());
else
res = ostr.str();
if (res.empty())
return "<<anonymous>>";
return res;
}
std::string function_template::full_name_no_ns() const
{
using namespace clanguml::util;
std::ostringstream ostr;
ostr << name();
render_template_params(ostr, using_namespace(), false);
ostr << "()";
return ostr.str();
}
}

View File

@@ -26,6 +26,24 @@
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;
private:
std::vector<class_diagram::model::template_parameter> templates_;
std::string base_template_full_name_;
};
struct participant : public common::model::element,
public common::model::stylable_element {
enum class stereotype_t {
@@ -50,30 +68,8 @@ struct participant : public common::model::element,
stereotype_t stereotype_{stereotype_t::participant};
};
//
// struct template_trait {
// void set_base_template(const std::string &full_name)
// {
// base_template_full_name_ = full_name;
// }
// std::string base_template() const { return base_template_full_name_; }
//
// void add_template(class_diagram::model::template_parameter tmplt)
// {
// templates_.push_back(std::move(tmplt));
// }
//
// const std::vector<class_diagram::model::template_parameter> &
// templates() const
// {
// return templates_;
// }
//
// std::vector<class_diagram::model::template_parameter> templates_;
// std::string base_template_full_name_;
//};
struct class_ : public participant {
struct class_ : public participant, public template_trait {
public:
class_(const common::model::namespace_ &using_namespace);
@@ -93,14 +89,6 @@ public:
bool is_template_instantiation() const;
void is_template_instantiation(bool is_template_instantiation);
void add_template(class_diagram::model::template_parameter tmplt);
const std::vector<class_diagram::model::template_parameter> &
templates() const;
void set_base_template(const std::string &full_name);
std::string base_template() const;
friend bool operator==(const class_ &l, const class_ &r);
std::string full_name(bool relative = true) const override;
@@ -113,19 +101,12 @@ public:
void is_alias(bool alias) { is_alias_ = alias; }
int calculate_template_specialization_match(
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};
bool is_alias_{false};
std::vector<class_diagram::model::template_parameter> templates_;
std::string base_template_full_name_;
std::map<std::string, clanguml::class_diagram::model::type_alias>
type_aliases_;
@@ -172,6 +153,19 @@ private:
std::string method_name_;
};
struct function_template : public participant { };
struct function_template : public participant, public template_trait {
function_template(const common::model::namespace_ &using_namespace);
function_template(const function_template &) = delete;
function_template(function_template &&) noexcept = delete;
function_template &operator=(const function_template &) = delete;
function_template &operator=(function_template &&) = delete;
std::string type_name() const override { return "function_template"; }
std::string full_name(bool relative = true) const override;
std::string full_name_no_ns() const override;
};
}

View File

@@ -243,6 +243,13 @@ bool translation_unit_visitor::VisitFunctionDecl(clang::FunctionDecl *f)
LOG_DBG("Visiting function declaration {}", function_name);
if (f->isTemplated() && f->getDescribedTemplate()) {
// If the described templated of this function is already in the model
// skip it:
if (get_ast_local_id(f->getDescribedTemplate()->getID()))
return true;
}
auto f_ptr = std::make_unique<sequence_diagram::model::function>(
config().using_namespace());
@@ -272,9 +279,28 @@ bool translation_unit_visitor::VisitFunctionTemplateDecl(
if (!diagram().should_include(function_name))
return true;
LOG_DBG("Visiting function template declaration {}", function_name);
LOG_DBG("Visiting function template declaration {} at {}", function_name,
function_template->getLocation().printToString(source_manager()));
auto f_ptr = std::make_unique<sequence_diagram::model::function_template>(
config().using_namespace());
common::model::namespace_ ns{function_name};
f_ptr->set_name(ns.name());
ns.pop_back();
f_ptr->set_namespace(ns);
process_template_parameters(*function_template, *f_ptr);
f_ptr->set_id(common::to_id(f_ptr->full_name(false)));
call_expression_context_.update(function_template);
call_expression_context_.set_caller_id(f_ptr->id());
set_ast_local_id(function_template->getID(), f_ptr->id());
// TODO: Handle overloaded functions with different arguments
diagram().add_participant(std::move(f_ptr));
return true;
}
@@ -305,7 +331,7 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
m.from_name = diagram().participants.at(m.from)->full_name(false);
const auto &current_ast_context =
call_expression_context_.get_ast_context();
*call_expression_context_.get_ast_context();
if (const auto *operator_call_expr =
clang::dyn_cast_or_null<clang::CXXOperatorCallExpr>(expr);
@@ -372,8 +398,17 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
clang::FunctionTemplateDecl>(decl);
m.to_name = to_string(ftd);
m.message_name = to_string(ftd);
m.to = get_ast_local_id(ftd->getID()).value();
auto message_name =
diagram()
.get_participant<model::function_template>(
m.to)
.value()
.full_name(false)
.substr();
m.message_name =
message_name.substr(0, message_name.size() - 2);
break;
}
}
@@ -392,7 +427,7 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
if (!callee_function)
return true;
m.to_name = callee_function->getQualifiedNameAsString() + "()";
m.to_name = callee_function->getQualifiedNameAsString();
m.message_name = callee_function->getNameAsString();
m.to = get_ast_local_id(callee_function->getID()).value();
}
@@ -523,8 +558,8 @@ translation_unit_visitor::create_class_declaration(clang::CXXRecordDecl *cls)
}
bool translation_unit_visitor::process_template_parameters(
const clang::ClassTemplateDecl &template_declaration,
sequence_diagram::model::class_ &c)
const clang::TemplateDecl &template_declaration,
sequence_diagram::model::template_trait &c)
{
using class_diagram::model::template_parameter;

View File

@@ -61,10 +61,15 @@ struct call_expression_context {
current_class_template_decl_ = clst;
}
auto &get_ast_context()
clang::ASTContext *get_ast_context()
{
return current_class_decl_ ? current_class_decl_->getASTContext()
: current_function_decl_->getASTContext();
if(current_class_decl_)
return &current_class_decl_->getASTContext();
if(current_function_template_decl_)
return &current_function_template_decl_->getASTContext();
return &current_function_decl_->getASTContext();
}
void update(clang::CXXMethodDecl *method) { current_method_decl_ = method; }
@@ -241,8 +246,8 @@ private:
create_class_declaration(clang::CXXRecordDecl *cls);
bool process_template_parameters(
const clang::ClassTemplateDecl &template_declaration,
sequence_diagram::model::class_ &c);
const clang::TemplateDecl &template_declaration,
sequence_diagram::model::template_trait &c);
// Reference to the output diagram model
clanguml::sequence_diagram::model::diagram &diagram_;