Added function and method arguments in sequence diagrams
This commit is contained in:
@@ -39,8 +39,13 @@ public:
|
||||
|
||||
void set_line(const unsigned line) { line_ = line; }
|
||||
|
||||
unsigned int location_id() const { return hash_; }
|
||||
|
||||
void set_location_id(unsigned int h) { hash_ = h; }
|
||||
|
||||
private:
|
||||
std::string file_;
|
||||
unsigned int line_{0};
|
||||
unsigned int hash_;
|
||||
};
|
||||
}
|
||||
@@ -70,6 +70,7 @@ void translation_unit_visitor::set_source_location(
|
||||
element.set_file(source_manager_.getFilename(decl.getLocation()).str());
|
||||
element.set_line(
|
||||
source_manager_.getSpellingLineNumber(decl.getLocation()));
|
||||
element.set_location_id(decl.getLocation().getHashValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -56,10 +56,11 @@ void generator::generate_call(const message &m, std::ostream &ostr) const
|
||||
generate_participant(ostr, m.from);
|
||||
generate_participant(ostr, m.to);
|
||||
|
||||
auto message = m.message_name;
|
||||
if (!message.empty()) {
|
||||
message = m_config.using_namespace().relative(message);
|
||||
message += "()";
|
||||
std::string message;
|
||||
|
||||
if (to.value().type_name() == "method") {
|
||||
message = dynamic_cast<const model::function &>(to.value())
|
||||
.message_name(model::function::message_render_mode::full);
|
||||
}
|
||||
|
||||
ostr << from.value().alias() << " "
|
||||
@@ -133,7 +134,7 @@ void generator::generate_participant(std::ostream &ostr, common::id_t id) const
|
||||
m_model.get_participant<model::participant>(participant_id).value();
|
||||
|
||||
if (participant.type_name() == "method") {
|
||||
const auto &class_id =
|
||||
const auto class_id =
|
||||
m_model.get_participant<model::method>(participant_id)
|
||||
.value()
|
||||
.class_id();
|
||||
@@ -197,6 +198,13 @@ void generator::generate(std::ostream &ostr) const
|
||||
const auto &from =
|
||||
m_model.get_participant<model::participant>(start_from);
|
||||
|
||||
if (!from.has_value()) {
|
||||
LOG_WARN(
|
||||
"Failed to find participant {} for start_from condition",
|
||||
sf.location);
|
||||
continue;
|
||||
}
|
||||
|
||||
generate_participant(ostr, start_from);
|
||||
|
||||
ostr << "activate " << from.value().alias() << std::endl;
|
||||
|
||||
@@ -163,16 +163,18 @@ function::function(const common::model::namespace_ &using_namespace)
|
||||
|
||||
std::string function::full_name(bool relative) const
|
||||
{
|
||||
return element::full_name(relative) + "()";
|
||||
return fmt::format("{}({}){}", element::full_name(relative),
|
||||
fmt::join(parameters_, ","), is_const() ? " const" : "");
|
||||
}
|
||||
|
||||
std::string function::full_name_no_ns() const
|
||||
{
|
||||
return element::full_name_no_ns() + "()";
|
||||
return fmt::format("{}({}){}", element::full_name_no_ns(),
|
||||
fmt::join(parameters_, ","), is_const() ? " const" : "");
|
||||
}
|
||||
|
||||
method::method(const common::model::namespace_ &using_namespace)
|
||||
: participant{using_namespace}
|
||||
: function{using_namespace}
|
||||
{
|
||||
}
|
||||
|
||||
@@ -185,7 +187,7 @@ std::string method::alias() const
|
||||
|
||||
function_template::function_template(
|
||||
const common::model::namespace_ &using_namespace)
|
||||
: participant{using_namespace}
|
||||
: function{using_namespace}
|
||||
{
|
||||
}
|
||||
|
||||
@@ -199,7 +201,8 @@ std::string function_template::full_name(bool relative) const
|
||||
ostr << name_and_ns();
|
||||
render_template_params(ostr, using_namespace(), relative);
|
||||
|
||||
ostr << "()";
|
||||
ostr << fmt::format(
|
||||
"({}){}", fmt::join(parameters(), ","), is_const() ? " const" : "");
|
||||
|
||||
std::string res;
|
||||
|
||||
@@ -224,7 +227,8 @@ std::string function_template::full_name_no_ns() const
|
||||
|
||||
render_template_params(ostr, using_namespace(), false);
|
||||
|
||||
ostr << "()";
|
||||
ostr << fmt::format(
|
||||
"({}){}", fmt::join(parameters(), ","), is_const() ? " const" : "");
|
||||
|
||||
return ostr.str();
|
||||
}
|
||||
|
||||
@@ -139,6 +139,8 @@ struct lambda : public class_ {
|
||||
};
|
||||
|
||||
struct function : public participant {
|
||||
enum class message_render_mode { full, no_arguments };
|
||||
|
||||
function(const common::model::namespace_ &using_namespace);
|
||||
|
||||
function(const function &) = delete;
|
||||
@@ -151,9 +153,31 @@ struct function : public participant {
|
||||
std::string full_name(bool relative = true) const override;
|
||||
|
||||
std::string full_name_no_ns() const override;
|
||||
|
||||
virtual std::string message_name(message_render_mode mode) const
|
||||
{
|
||||
if (mode == message_render_mode::no_arguments) {
|
||||
return fmt::format("{}(){}", name(), is_const() ? " const" : "");
|
||||
}
|
||||
|
||||
return fmt::format("{}({}){}", name(), fmt::join(parameters_, ","),
|
||||
is_const() ? " const" : "");
|
||||
}
|
||||
|
||||
bool is_const() const { return is_const_; }
|
||||
|
||||
void is_const(bool c) { is_const_ = c; }
|
||||
|
||||
void add_parameter(const std::string &a) { parameters_.push_back(a); }
|
||||
|
||||
const std::vector<std::string> ¶meters() const { return parameters_; }
|
||||
|
||||
private:
|
||||
bool is_const_{false};
|
||||
std::vector<std::string> parameters_;
|
||||
};
|
||||
|
||||
struct method : public participant {
|
||||
struct method : public function {
|
||||
method(const common::model::namespace_ &using_namespace);
|
||||
|
||||
method(const function &) = delete;
|
||||
@@ -180,7 +204,19 @@ struct method : public participant {
|
||||
|
||||
std::string full_name(bool /*relative*/) const override
|
||||
{
|
||||
return class_full_name() + "::" + method_name();
|
||||
return fmt::format("{}::{}({}){}", class_full_name(), method_name(),
|
||||
fmt::join(parameters(), ","), is_const() ? " const" : "");
|
||||
}
|
||||
|
||||
std::string message_name(message_render_mode mode) const override
|
||||
{
|
||||
if (mode == message_render_mode::no_arguments) {
|
||||
return fmt::format(
|
||||
"{}(){}", method_name(), is_const() ? " const" : "");
|
||||
}
|
||||
|
||||
return fmt::format("{}({}){}", method_name(),
|
||||
fmt::join(parameters(), ","), is_const() ? " const" : "");
|
||||
}
|
||||
|
||||
diagram_element::id_t class_id() const { return class_id_; }
|
||||
@@ -197,7 +233,7 @@ private:
|
||||
std::string class_full_name_;
|
||||
};
|
||||
|
||||
struct function_template : public participant, public template_trait {
|
||||
struct function_template : public function, public template_trait {
|
||||
function_template(const common::model::namespace_ &using_namespace);
|
||||
|
||||
function_template(const function_template &) = delete;
|
||||
|
||||
@@ -293,8 +293,6 @@ bool translation_unit_visitor::VisitCXXMethodDecl(clang::CXXMethodDecl *m)
|
||||
|
||||
LOG_DBG("Getting method's class with local id {}", parent_decl->getID());
|
||||
|
||||
set_unique_id(m->getID(), m_ptr->id());
|
||||
|
||||
const auto &method_class =
|
||||
get_participant<model::class_>(parent_decl).value();
|
||||
|
||||
@@ -304,13 +302,20 @@ bool translation_unit_visitor::VisitCXXMethodDecl(clang::CXXMethodDecl *m)
|
||||
get_participant(m_ptr->class_id()).value().full_name_no_ns() +
|
||||
"::" + m->getNameAsString());
|
||||
|
||||
m_ptr->set_id(common::to_id(
|
||||
get_participant(m_ptr->class_id()).value().full_name(false) +
|
||||
"::" + m->getNameAsString()));
|
||||
for (const auto *param : m->parameters()) {
|
||||
m_ptr->add_parameter(simplify_system_template(
|
||||
common::to_string(param->getType(), m->getASTContext())));
|
||||
}
|
||||
|
||||
LOG_DBG("Set id {} for method name {}", m_ptr->id(),
|
||||
get_participant(m_ptr->class_id()).value().full_name(false) +
|
||||
"::" + m->getNameAsString());
|
||||
set_source_location(*m, *m_ptr);
|
||||
|
||||
const auto method_full_name = m_ptr->full_name(false);
|
||||
|
||||
m_ptr->set_id(common::to_id(method_full_name));
|
||||
|
||||
set_unique_id(m->getID(), m_ptr->id());
|
||||
|
||||
LOG_DBG("Set id {} for method name {}", m_ptr->id(), method_full_name);
|
||||
|
||||
context().update(m);
|
||||
|
||||
@@ -365,7 +370,13 @@ bool translation_unit_visitor::VisitFunctionDecl(clang::FunctionDecl *f)
|
||||
f_ptr->set_name(ns.name());
|
||||
ns.pop_back();
|
||||
f_ptr->set_namespace(ns);
|
||||
f_ptr->set_id(common::to_id(function_name));
|
||||
|
||||
for (const auto *param : f->parameters()) {
|
||||
f_ptr->add_parameter(simplify_system_template(
|
||||
common::to_string(param->getType(), f->getASTContext())));
|
||||
}
|
||||
|
||||
f_ptr->set_id(common::to_id(f_ptr->full_name(false)));
|
||||
|
||||
context().update(f);
|
||||
|
||||
@@ -401,9 +412,16 @@ bool translation_unit_visitor::VisitFunctionTemplateDecl(
|
||||
|
||||
process_template_parameters(*function_template, *f_ptr);
|
||||
|
||||
for (const auto *param :
|
||||
function_template->getTemplatedDecl()->parameters()) {
|
||||
f_ptr->add_parameter(simplify_system_template(common::to_string(
|
||||
param->getType(), function_template->getASTContext())));
|
||||
}
|
||||
|
||||
f_ptr->set_id(common::to_id(f_ptr->full_name(false)));
|
||||
|
||||
context().update(function_template);
|
||||
|
||||
context().set_caller_id(f_ptr->id());
|
||||
|
||||
set_unique_id(function_template->getID(), f_ptr->id());
|
||||
@@ -633,33 +651,9 @@ bool translation_unit_visitor::process_class_method_call_expression(
|
||||
diagram().should_include(callee_decl->getQualifiedNameAsString())))
|
||||
return false;
|
||||
|
||||
const auto *callee_template_specialization =
|
||||
clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(callee_decl);
|
||||
m.to = method_decl->getID();
|
||||
m.message_name = method_decl->getNameAsString();
|
||||
|
||||
if (callee_template_specialization) {
|
||||
LOG_DBG("Callee is a template specialization declaration {}",
|
||||
callee_template_specialization->getQualifiedNameAsString());
|
||||
|
||||
const auto &specialization_participant =
|
||||
diagram()
|
||||
.get_participant<model::class_>(
|
||||
get_unique_id(callee_template_specialization->getID())
|
||||
.value())
|
||||
.value();
|
||||
const auto specialization_method_name =
|
||||
specialization_participant.full_name(false) +
|
||||
"::" + method_decl->getNameAsString();
|
||||
|
||||
m.to = common::to_id(specialization_method_name);
|
||||
m.message_name = method_decl->getNameAsString();
|
||||
}
|
||||
else {
|
||||
// TODO: The method can be called before it's declaration has been
|
||||
// encountered by the visitor - for now it's not a problem
|
||||
// as overloaded methods are not supported
|
||||
m.to = common::to_id(method_decl->getQualifiedNameAsString());
|
||||
m.message_name = method_decl->getNameAsString();
|
||||
}
|
||||
m.return_type =
|
||||
method_call_expr->getCallReturnType(*context().get_ast_context())
|
||||
.getAsString();
|
||||
@@ -682,8 +676,7 @@ bool translation_unit_visitor::process_class_template_method_call_expression(
|
||||
expr->getCallee());
|
||||
|
||||
if (is_callee_valid_template_specialization(dependent_member_callee)) {
|
||||
|
||||
const auto *primary_template =
|
||||
const auto *template_declaration =
|
||||
dependent_member_callee->getBaseType()
|
||||
->getAs<clang::TemplateSpecializationType>()
|
||||
->getTemplateName()
|
||||
@@ -693,33 +686,52 @@ bool translation_unit_visitor::process_class_template_method_call_expression(
|
||||
|
||||
// First check if the primary template is already in the
|
||||
// participants map
|
||||
if (get_participant(primary_template).has_value()) {
|
||||
if (get_participant(template_declaration).has_value()) {
|
||||
callee_method_full_name =
|
||||
get_participant(primary_template).value().full_name(false) +
|
||||
get_participant(template_declaration).value().full_name(false) +
|
||||
"::" + dependent_member_callee->getMember().getAsString();
|
||||
}
|
||||
else if (is_smart_pointer(primary_template)) {
|
||||
// Otherwise check if it a smart pointer
|
||||
primary_template->getTemplateParameters()->asArray().front();
|
||||
|
||||
if (get_participant(primary_template).has_value()) {
|
||||
callee_method_full_name =
|
||||
get_participant(primary_template).value().full_name(false) +
|
||||
for (const auto &[id, p] : diagram().participants) {
|
||||
const auto p_full_name = p->full_name(false);
|
||||
|
||||
if (p_full_name.find(callee_method_full_name + "(") == 0) {
|
||||
// TODO: This selects the first matching template method
|
||||
// without considering arguments!!!
|
||||
m.to = id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (is_smart_pointer(template_declaration)) {
|
||||
// Otherwise check if it is a smart pointer
|
||||
template_declaration->getTemplateParameters()->asArray().front();
|
||||
|
||||
if (get_participant(template_declaration).has_value()) {
|
||||
callee_method_full_name = get_participant(template_declaration)
|
||||
.value()
|
||||
.full_name(false) +
|
||||
"::" + dependent_member_callee->getMember().getAsString();
|
||||
|
||||
for (const auto &[id, p] : diagram().participants) {
|
||||
const auto p_full_name = p->full_name(false);
|
||||
if (p_full_name.find(callee_method_full_name + "(") == 0) {
|
||||
// TODO: This selects the first matching template method
|
||||
// without considering arguments!!!
|
||||
m.to = id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
auto callee_id = common::to_id(callee_method_full_name);
|
||||
m.to = callee_id;
|
||||
|
||||
m.message_name = dependent_member_callee->getMember().getAsString();
|
||||
m.return_type = "";
|
||||
|
||||
if (get_unique_id(primary_template->getID()))
|
||||
if (get_unique_id(template_declaration->getID()))
|
||||
diagram().add_active_participant(
|
||||
get_unique_id(primary_template->getID()).value());
|
||||
get_unique_id(template_declaration->getID()).value());
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -744,7 +756,7 @@ bool translation_unit_visitor::process_function_call_expression(
|
||||
|
||||
if (!get_unique_id(callee_function->getID()).has_value()) {
|
||||
// This is hopefully not an interesting call...
|
||||
return false;
|
||||
m.to = callee_function->getID();
|
||||
}
|
||||
else {
|
||||
m.to = get_unique_id(callee_function->getID()).value();
|
||||
@@ -774,17 +786,10 @@ bool translation_unit_visitor::process_unresolved_lookup_call_expression(
|
||||
clang::dyn_cast_or_null<clang::FunctionTemplateDecl>(decl);
|
||||
|
||||
if (!get_unique_id(ftd->getID()).has_value())
|
||||
continue;
|
||||
|
||||
m.to = get_unique_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);
|
||||
m.to = ftd->getID();
|
||||
else {
|
||||
m.to = get_unique_id(ftd->getID()).value();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -1038,6 +1043,11 @@ translation_unit_visitor::build_function_template_instantiation(
|
||||
template_base_params, decl.getTemplateSpecializationArgs()->asArray(),
|
||||
template_instantiation, "", decl.getPrimaryTemplate());
|
||||
|
||||
for (const auto *param : decl.parameters()) {
|
||||
template_instantiation_ptr->add_parameter(
|
||||
common::to_string(param->getType(), decl.getASTContext()));
|
||||
}
|
||||
|
||||
return template_instantiation_ptr;
|
||||
}
|
||||
|
||||
@@ -1644,6 +1654,16 @@ bool translation_unit_visitor::simplify_system_template(
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string translation_unit_visitor::simplify_system_template(
|
||||
const std::string &full_name) const
|
||||
{
|
||||
if (config().type_aliases().count(full_name) > 0) {
|
||||
return config().type_aliases().at(full_name);
|
||||
}
|
||||
|
||||
return full_name;
|
||||
}
|
||||
|
||||
std::string translation_unit_visitor::make_lambda_name(
|
||||
const clang::CXXRecordDecl *cls) const
|
||||
{
|
||||
@@ -1672,6 +1692,19 @@ std::string translation_unit_visitor::make_lambda_name(
|
||||
|
||||
void translation_unit_visitor::finalize()
|
||||
{
|
||||
decltype(diagram().active_participants_) active_participants_unique;
|
||||
|
||||
for (auto id : diagram().active_participants_) {
|
||||
if (local_ast_id_map_.find(id) != local_ast_id_map_.end()) {
|
||||
active_participants_unique.emplace(local_ast_id_map_.at(id));
|
||||
}
|
||||
else {
|
||||
active_participants_unique.emplace(id);
|
||||
}
|
||||
}
|
||||
|
||||
diagram().active_participants_ = std::move(active_participants_unique);
|
||||
|
||||
for (auto &[id, activity] : diagram().sequences) {
|
||||
for (auto &m : activity.messages) {
|
||||
if (local_ast_id_map_.find(m.to) != local_ast_id_map_.end()) {
|
||||
|
||||
@@ -195,6 +195,8 @@ private:
|
||||
bool simplify_system_template(class_diagram::model::template_parameter &ct,
|
||||
const std::string &full_name);
|
||||
|
||||
std::string simplify_system_template(const std::string &full_name) const;
|
||||
|
||||
std::string make_lambda_name(const clang::CXXRecordDecl *cls) const;
|
||||
|
||||
bool is_smart_pointer(const clang::TemplateDecl *primary_template) const;
|
||||
|
||||
@@ -38,11 +38,11 @@ TEST_CASE("t20001", "[test-case][sequence]")
|
||||
REQUIRE_THAT(puml, StartsWith("@startuml"));
|
||||
REQUIRE_THAT(puml, EndsWith("@enduml\n"));
|
||||
|
||||
REQUIRE_THAT(puml, HasCall(_A("A"), "log_result"));
|
||||
REQUIRE_THAT(puml, HasCall(_A("B"), _A("A"), "log_result"));
|
||||
REQUIRE_THAT(puml, HasCallWithResponse(_A("B"), _A("A"), "add3"));
|
||||
REQUIRE_THAT(puml, HasCall(_A("A"), "add"));
|
||||
REQUIRE_THAT(puml, !HasCall(_A("A"), _A("detail::C"), "add"));
|
||||
REQUIRE_THAT(puml, HasCall(_A("A"), "log_result(int)"));
|
||||
REQUIRE_THAT(puml, HasCall(_A("B"), _A("A"), "log_result(int)"));
|
||||
REQUIRE_THAT(puml, HasCallWithResponse(_A("B"), _A("A"), "add3(int,int,int)"));
|
||||
REQUIRE_THAT(puml, HasCall(_A("A"), "add(int,int)"));
|
||||
REQUIRE_THAT(puml, !HasCall(_A("A"), _A("detail::C"), "add(int,int)"));
|
||||
|
||||
save_puml(
|
||||
"./" + config.output_directory() + "/" + diagram->name + ".puml", puml);
|
||||
|
||||
@@ -34,9 +34,9 @@ TEST_CASE("t20002", "[test-case][sequence]")
|
||||
REQUIRE_THAT(puml, StartsWith("@startuml"));
|
||||
REQUIRE_THAT(puml, EndsWith("@enduml\n"));
|
||||
|
||||
REQUIRE_THAT(puml, HasCall(_A("m1()"), _A("m2()"), "m2"));
|
||||
REQUIRE_THAT(puml, HasCall(_A("m2()"), _A("m3()"), "m3"));
|
||||
REQUIRE_THAT(puml, HasCall(_A("m3()"), _A("m4()"), "m4"));
|
||||
REQUIRE_THAT(puml, HasCall(_A("m1()"), _A("m2()"), ""));
|
||||
REQUIRE_THAT(puml, HasCall(_A("m2()"), _A("m3()"), ""));
|
||||
REQUIRE_THAT(puml, HasCall(_A("m3()"), _A("m4()"), ""));
|
||||
|
||||
save_puml(
|
||||
"./" + config.output_directory() + "/" + diagram->name + ".puml", puml);
|
||||
|
||||
@@ -11,4 +11,4 @@ diagrams:
|
||||
using_namespace:
|
||||
- clanguml::t20003
|
||||
start_from:
|
||||
- function: "clanguml::t20003::m1<T>()"
|
||||
- function: "clanguml::t20003::m1<T>(T)"
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
|
||||
namespace clanguml {
|
||||
namespace t20003 {
|
||||
|
||||
|
||||
@@ -34,9 +34,9 @@ TEST_CASE("t20003", "[test-case][sequence]")
|
||||
REQUIRE_THAT(puml, StartsWith("@startuml"));
|
||||
REQUIRE_THAT(puml, EndsWith("@enduml\n"));
|
||||
|
||||
REQUIRE_THAT(puml, HasCall(_A("m1<T>()"), _A("m2<T>()"), "m2<T>"));
|
||||
REQUIRE_THAT(puml, HasCall(_A("m2<T>()"), _A("m3<T>()"), "m3<T>"));
|
||||
REQUIRE_THAT(puml, HasCall(_A("m3<T>()"), _A("m4<T>()"), "m4<T>"));
|
||||
REQUIRE_THAT(puml, HasCall(_A("m1<T>(T)"), _A("m2<T>(T)"), ""));
|
||||
REQUIRE_THAT(puml, HasCall(_A("m2<T>(T)"), _A("m3<T>(T)"), ""));
|
||||
REQUIRE_THAT(puml, HasCall(_A("m3<T>(T)"), _A("m4<T>(T)"), ""));
|
||||
|
||||
save_puml(
|
||||
"./" + config.output_directory() + "/" + diagram->name + ".puml", puml);
|
||||
|
||||
@@ -32,22 +32,28 @@ TEST_CASE("t20004", "[test-case][sequence]")
|
||||
AliasMatcher _A(puml);
|
||||
|
||||
REQUIRE_THAT(puml, StartsWith("@startuml"));
|
||||
REQUIRE_THAT(puml, HasCall(_A("main()"), _A("m1<float>()"), "m1"));
|
||||
REQUIRE_THAT(puml, !HasCall(_A("m1<float>()"), _A("m1<float>()"), "m2"));
|
||||
REQUIRE_THAT(puml, !HasCall(_A("m1<float>()"), _A("m1<float>()"), "m2"));
|
||||
|
||||
REQUIRE_THAT(puml, HasCall(_A("main()"), _A("m1<unsigned long>()"), "m1"));
|
||||
REQUIRE_THAT(puml,
|
||||
HasCall(_A("m1<unsigned long>()"), _A("m4<unsigned long>()"), "m4"));
|
||||
|
||||
REQUIRE_THAT(puml, HasCall(_A("main()"), _A("m1<std::string>()"), "m1"));
|
||||
REQUIRE_THAT(puml, HasCall(_A("main()"), _A("m1<float>(float)"), ""));
|
||||
REQUIRE_THAT(
|
||||
puml, HasCall(_A("m1<std::string>()"), _A("m2<std::string>()"), "m2"));
|
||||
puml, !HasCall(_A("m1<float>(float)"), _A("m1<float>(float)"), ""));
|
||||
REQUIRE_THAT(
|
||||
puml, !HasCall(_A("m1<float>(float)"), _A("m1<float>(float)"), ""));
|
||||
|
||||
REQUIRE_THAT(puml, HasCall(_A("main()"), _A("m1<int>()"), "m1"));
|
||||
REQUIRE_THAT(puml, HasCall(_A("m1<int>()"), _A("m2<int>()"), "m2"));
|
||||
REQUIRE_THAT(puml, HasCall(_A("m2<int>()"), _A("m3<int>()"), "m3"));
|
||||
REQUIRE_THAT(puml, HasCall(_A("m3<int>()"), _A("m4<int>()"), "m4"));
|
||||
REQUIRE_THAT(puml,
|
||||
HasCall(_A("main()"), _A("m1<unsigned long>(unsigned long)"), ""));
|
||||
REQUIRE_THAT(puml,
|
||||
HasCall(_A("m1<unsigned long>(unsigned long)"),
|
||||
_A("m4<unsigned long>(unsigned long)"), ""));
|
||||
|
||||
REQUIRE_THAT(
|
||||
puml, HasCall(_A("main()"), _A("m1<std::string>(std::string)"), ""));
|
||||
REQUIRE_THAT(puml,
|
||||
HasCall(_A("m1<std::string>(std::string)"),
|
||||
_A("m2<std::string>(std::string)"), ""));
|
||||
|
||||
REQUIRE_THAT(puml, HasCall(_A("main()"), _A("m1<int>(int)"), ""));
|
||||
REQUIRE_THAT(puml, HasCall(_A("m1<int>(int)"), _A("m2<int>(int)"), ""));
|
||||
REQUIRE_THAT(puml, HasCall(_A("m2<int>(int)"), _A("m3<int>(int)"), ""));
|
||||
REQUIRE_THAT(puml, HasCall(_A("m3<int>(int)"), _A("m4<int>(int)"), ""));
|
||||
REQUIRE_THAT(puml, EndsWith("@enduml\n"));
|
||||
|
||||
save_puml(
|
||||
|
||||
@@ -11,4 +11,4 @@ diagrams:
|
||||
using_namespace:
|
||||
- clanguml::t20005
|
||||
start_from:
|
||||
- function: "clanguml::t20005::C<T>::c"
|
||||
- function: "clanguml::t20005::C<T>::c(T)"
|
||||
@@ -35,8 +35,8 @@ TEST_CASE("t20005", "[test-case][sequence]")
|
||||
REQUIRE_THAT(puml, EndsWith("@enduml\n"));
|
||||
|
||||
// Check if all calls exist
|
||||
REQUIRE_THAT(puml, HasCall(_A("C<T>"), _A("B<T>"), "b"));
|
||||
REQUIRE_THAT(puml, HasCall(_A("B<T>"), _A("A<T>"), "a"));
|
||||
REQUIRE_THAT(puml, HasCall(_A("C<T>"), _A("B<T>"), "b(T)"));
|
||||
REQUIRE_THAT(puml, HasCall(_A("B<T>"), _A("A<T>"), "a(T)"));
|
||||
|
||||
save_puml(
|
||||
"./" + config.output_directory() + "/" + diagram->name + ".puml", puml);
|
||||
|
||||
@@ -35,10 +35,10 @@ TEST_CASE("t20006", "[test-case][sequence]")
|
||||
REQUIRE_THAT(puml, EndsWith("@enduml\n"));
|
||||
|
||||
// Check if all calls exist
|
||||
REQUIRE_THAT(puml, HasCall(_A("tmain()"), _A("B<int>"), "b"));
|
||||
REQUIRE_THAT(puml, HasCall(_A("B<int>"), _A("A<int>"), "a1"));
|
||||
REQUIRE_THAT(puml, HasCall(_A("tmain()"), _A("B<int>"), "b(int)"));
|
||||
REQUIRE_THAT(puml, HasCall(_A("B<int>"), _A("A<int>"), "a1(int)"));
|
||||
|
||||
REQUIRE_THAT(puml, HasCall(_A("tmain()"), _A("B<std::string>"), "b"));
|
||||
REQUIRE_THAT(puml, HasCall(_A("tmain()"), _A("B<std::string>"), "b(std::string)"));
|
||||
REQUIRE_THAT(
|
||||
puml, HasCall(_A("B<std::string>"), _A("A<std::string>"), "a2"));
|
||||
|
||||
|
||||
14
tests/t20013/.clang-uml
Normal file
14
tests/t20013/.clang-uml
Normal file
@@ -0,0 +1,14 @@
|
||||
compilation_database_dir: ..
|
||||
output_directory: puml
|
||||
diagrams:
|
||||
t20013_sequence:
|
||||
type: sequence
|
||||
glob:
|
||||
- ../../tests/t20013/t20013.cc
|
||||
include:
|
||||
namespaces:
|
||||
- clanguml::t20013
|
||||
using_namespace:
|
||||
- clanguml::t20013
|
||||
start_from:
|
||||
- function: "clanguml::t20013::tmain(int,char **)"
|
||||
27
tests/t20013/t20013.cc
Normal file
27
tests/t20013/t20013.cc
Normal file
@@ -0,0 +1,27 @@
|
||||
namespace clanguml {
|
||||
namespace t20013 {
|
||||
|
||||
struct A {
|
||||
int a1(int i) { return i; }
|
||||
double a2(double d) { return d; }
|
||||
const char *a3(const char *s) { return s; }
|
||||
};
|
||||
|
||||
struct B {
|
||||
int b(int i) { return a.a1(i); }
|
||||
double b(double d) { return a.a2(d); }
|
||||
const char *b(const char *s) { return a.a3(s); }
|
||||
|
||||
A a;
|
||||
};
|
||||
|
||||
void tmain(int argc, char **argv)
|
||||
{
|
||||
B b;
|
||||
|
||||
b.b(1);
|
||||
b.b(2.0);
|
||||
b.b("three");
|
||||
}
|
||||
}
|
||||
}
|
||||
50
tests/t20013/test_case.h
Normal file
50
tests/t20013/test_case.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* tests/t20013/test_case.h
|
||||
*
|
||||
* Copyright (c) 2021-2022 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("t20013", "[test-case][sequence]")
|
||||
{
|
||||
auto [config, db] = load_config("t20013");
|
||||
|
||||
auto diagram = config.diagrams["t20013_sequence"];
|
||||
|
||||
REQUIRE(diagram->name == "t20013_sequence");
|
||||
|
||||
auto model = generate_sequence_diagram(*db, diagram);
|
||||
|
||||
REQUIRE(model->name() == "t20013_sequence");
|
||||
|
||||
auto puml = generate_sequence_puml(diagram, *model);
|
||||
AliasMatcher _A(puml);
|
||||
|
||||
REQUIRE_THAT(puml, StartsWith("@startuml"));
|
||||
REQUIRE_THAT(puml, EndsWith("@enduml\n"));
|
||||
|
||||
// Check if all calls exist
|
||||
REQUIRE_THAT(puml, HasCall(_A("tmain(int,char **)"), _A("B"), "b(int)"));
|
||||
REQUIRE_THAT(puml, HasCall(_A("B"), _A("A"), "a1(int)"));
|
||||
|
||||
REQUIRE_THAT(puml, HasCall(_A("tmain(int,char **)"), _A("B"), "b(double)"));
|
||||
REQUIRE_THAT(puml, HasCall(_A("B"), _A("A"), "a2(double)"));
|
||||
|
||||
REQUIRE_THAT(
|
||||
puml, HasCall(_A("tmain(int,char **)"), _A("B"), "b(const char *)"));
|
||||
REQUIRE_THAT(puml, HasCall(_A("B"), _A("A"), "a3(const char *)"));
|
||||
|
||||
save_puml(
|
||||
"./" + config.output_directory() + "/" + diagram->name + ".puml", puml);
|
||||
}
|
||||
@@ -259,6 +259,7 @@ using namespace clanguml::test::matchers;
|
||||
#include "t20010/test_case.h"
|
||||
#include "t20011/test_case.h"
|
||||
#include "t20012/test_case.h"
|
||||
#include "t20013/test_case.h"
|
||||
|
||||
///
|
||||
/// Package diagram tests
|
||||
|
||||
@@ -123,7 +123,7 @@ ContainsMatcher HasCall(std::string const &from, std::string const &message,
|
||||
CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
|
||||
{
|
||||
return ContainsMatcher(CasedString(
|
||||
fmt::format("{} -> {} : {}()", from, from, message), caseSensitivity));
|
||||
fmt::format("{} -> {} : {}", from, from, message), caseSensitivity));
|
||||
}
|
||||
|
||||
ContainsMatcher HasCall(std::string const &from, std::string const &to,
|
||||
@@ -131,7 +131,7 @@ ContainsMatcher HasCall(std::string const &from, std::string const &to,
|
||||
CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
|
||||
{
|
||||
return ContainsMatcher(CasedString(
|
||||
fmt::format("{} -> {} : {}()", from, to, message), caseSensitivity));
|
||||
fmt::format("{} -> {} : {}", from, to, message), caseSensitivity));
|
||||
}
|
||||
|
||||
auto HasCallWithResponse(std::string const &from, std::string const &to,
|
||||
@@ -140,7 +140,7 @@ auto HasCallWithResponse(std::string const &from, std::string const &to,
|
||||
{
|
||||
return HasCallWithResultMatcher(
|
||||
CasedString(
|
||||
fmt::format("{} -> {} : {}()", from, to, message), caseSensitivity),
|
||||
fmt::format("{} -> {} : {}", from, to, message), caseSensitivity),
|
||||
CasedString(fmt::format("{} --> {}", to, from), caseSensitivity));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user