Added option to enable rendering return types in sequence diagrams (fixes #93)
This commit is contained in:
@@ -7,6 +7,7 @@
|
|||||||
* [Grouping free functions by file](#grouping-free-functions-by-file)
|
* [Grouping free functions by file](#grouping-free-functions-by-file)
|
||||||
* [Lambda expressions in sequence diagrams](#lambda-expressions-in-sequence-diagrams)
|
* [Lambda expressions in sequence diagrams](#lambda-expressions-in-sequence-diagrams)
|
||||||
* [Customizing participants order](#customizing-participants-order)
|
* [Customizing participants order](#customizing-participants-order)
|
||||||
|
* [Generating return types](#generating-return-types)
|
||||||
|
|
||||||
<!-- tocstop -->
|
<!-- tocstop -->
|
||||||
|
|
||||||
@@ -247,3 +248,18 @@ diagrams:
|
|||||||
- clanguml::t20029::encode_b64(std::string &&)
|
- clanguml::t20029::encode_b64(std::string &&)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Generating return types
|
||||||
|
By default, return messages do not contain the return type information from
|
||||||
|
the function or method. Instead, if the result is void there is no return
|
||||||
|
arrow from the activity representing the function body.
|
||||||
|
|
||||||
|
It is however possible to enable rendering of return types, by adding the
|
||||||
|
following configuration option:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
generate_return_types: true
|
||||||
|
```
|
||||||
|
|
||||||
|
This option only affects the `plantuml` generation, in `json` generator
|
||||||
|
`return_type` property is always present in the message nodes.
|
||||||
|
|
||||||
|
|||||||
@@ -166,7 +166,8 @@ void inheritable_diagram_options::inherit(
|
|||||||
relative_to.override(parent.relative_to);
|
relative_to.override(parent.relative_to);
|
||||||
comment_parser.override(parent.comment_parser);
|
comment_parser.override(parent.comment_parser);
|
||||||
combine_free_functions_into_file_participants.override(
|
combine_free_functions_into_file_participants.override(
|
||||||
combine_free_functions_into_file_participants);
|
parent.combine_free_functions_into_file_participants);
|
||||||
|
generate_return_types.override(parent.generate_return_types);
|
||||||
debug_mode.override(parent.debug_mode);
|
debug_mode.override(parent.debug_mode);
|
||||||
generate_metadata.override(parent.generate_metadata);
|
generate_metadata.override(parent.generate_metadata);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -445,6 +445,7 @@ struct inheritable_diagram_options {
|
|||||||
"comment_parser", comment_parser_t::plain};
|
"comment_parser", comment_parser_t::plain};
|
||||||
option<bool> combine_free_functions_into_file_participants{
|
option<bool> combine_free_functions_into_file_participants{
|
||||||
"combine_free_functions_into_file_participants", false};
|
"combine_free_functions_into_file_participants", false};
|
||||||
|
option<bool> generate_return_types{"generate_return_types", false};
|
||||||
option<std::vector<std::string>> participants_order{"participants_order"};
|
option<std::vector<std::string>> participants_order{"participants_order"};
|
||||||
option<bool> debug_mode{"debug_mode", false};
|
option<bool> debug_mode{"debug_mode", false};
|
||||||
option<bool> generate_metadata{"generate_metadata", true};
|
option<bool> generate_metadata{"generate_metadata", true};
|
||||||
|
|||||||
@@ -513,6 +513,7 @@ template <> struct convert<git_config> {
|
|||||||
|
|
||||||
template <typename T> bool decode_diagram(const Node &node, T &rhs)
|
template <typename T> bool decode_diagram(const Node &node, T &rhs)
|
||||||
{
|
{
|
||||||
|
// Decode options common for all diagrams
|
||||||
get_option(node, rhs.glob);
|
get_option(node, rhs.glob);
|
||||||
get_option(node, rhs.using_namespace);
|
get_option(node, rhs.using_namespace);
|
||||||
get_option(node, rhs.include);
|
get_option(node, rhs.include);
|
||||||
@@ -566,6 +567,7 @@ template <> struct convert<sequence_diagram> {
|
|||||||
|
|
||||||
get_option(node, rhs.start_from);
|
get_option(node, rhs.start_from);
|
||||||
get_option(node, rhs.combine_free_functions_into_file_participants);
|
get_option(node, rhs.combine_free_functions_into_file_participants);
|
||||||
|
get_option(node, rhs.generate_return_types);
|
||||||
get_option(node, rhs.relative_to);
|
get_option(node, rhs.relative_to);
|
||||||
get_option(node, rhs.participants_order);
|
get_option(node, rhs.participants_order);
|
||||||
get_option(node, rhs.generate_method_arguments);
|
get_option(node, rhs.generate_method_arguments);
|
||||||
@@ -752,6 +754,9 @@ template <> struct convert<config> {
|
|||||||
get_option(node, rhs.comment_parser);
|
get_option(node, rhs.comment_parser);
|
||||||
get_option(node, rhs.debug_mode);
|
get_option(node, rhs.debug_mode);
|
||||||
get_option(node, rhs.generate_metadata);
|
get_option(node, rhs.generate_metadata);
|
||||||
|
get_option(node, rhs.combine_free_functions_into_file_participants);
|
||||||
|
get_option(node, rhs.generate_return_types);
|
||||||
|
|
||||||
rhs.base_directory.set(node["__parent_path"].as<std::string>());
|
rhs.base_directory.set(node["__parent_path"].as<std::string>());
|
||||||
get_option(node, rhs.relative_to);
|
get_option(node, rhs.relative_to);
|
||||||
|
|
||||||
|
|||||||
@@ -289,6 +289,7 @@ YAML::Emitter &operator<<(
|
|||||||
}
|
}
|
||||||
out << c.comment_parser;
|
out << c.comment_parser;
|
||||||
out << c.combine_free_functions_into_file_participants;
|
out << c.combine_free_functions_into_file_participants;
|
||||||
|
out << c.generate_return_types;
|
||||||
out << c.participants_order;
|
out << c.participants_order;
|
||||||
out << c.debug_mode;
|
out << c.debug_mode;
|
||||||
|
|
||||||
|
|||||||
@@ -645,16 +645,15 @@ void generator::generate(std::ostream &ostr) const
|
|||||||
generate_activity(
|
generate_activity(
|
||||||
m_model.get_activity(start_from), visited_participants);
|
m_model.get_activity(start_from), visited_participants);
|
||||||
|
|
||||||
json_["sequences"].push_back(std::move(sequence));
|
|
||||||
|
|
||||||
block_statements_stack_.pop_back();
|
block_statements_stack_.pop_back();
|
||||||
|
|
||||||
if (from.value().type_name() == "method" ||
|
if (from.value().type_name() == "method" ||
|
||||||
m_config.combine_free_functions_into_file_participants()) {
|
m_config.combine_free_functions_into_file_participants()) {
|
||||||
|
|
||||||
// TODO
|
sequence["return_type"] = from.value().return_type();
|
||||||
// sequence["return_type"] = from.value().id()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
json_["sequences"].push_back(std::move(sequence));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// TODO: Add support for other sequence start location types
|
// TODO: Add support for other sequence start location types
|
||||||
|
|||||||
@@ -128,7 +128,13 @@ void generator::generate_return(const message &m, std::ostream &ostr) const
|
|||||||
|
|
||||||
ostr << to_alias << " "
|
ostr << to_alias << " "
|
||||||
<< common::generators::plantuml::to_plantuml(message_t::kReturn)
|
<< common::generators::plantuml::to_plantuml(message_t::kReturn)
|
||||||
<< " " << from_alias << '\n';
|
<< " " << from_alias;
|
||||||
|
|
||||||
|
if (m_config.generate_return_types()) {
|
||||||
|
ostr << " : //" << m.return_type() << "//";
|
||||||
|
}
|
||||||
|
|
||||||
|
ostr << '\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -451,7 +457,12 @@ void generator::generate(std::ostream &ostr) const
|
|||||||
|
|
||||||
if (!from.value().is_void()) {
|
if (!from.value().is_void()) {
|
||||||
ostr << "[<--"
|
ostr << "[<--"
|
||||||
<< " " << from_alias << std::endl;
|
<< " " << from_alias;
|
||||||
|
|
||||||
|
if (m_config.generate_return_types())
|
||||||
|
ostr << " : //" << from.value().return_type() << "//";
|
||||||
|
|
||||||
|
ostr << '\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -312,6 +312,16 @@ void diagram::finalize()
|
|||||||
assert(block_nest_level >= 0);
|
assert(block_nest_level >= 0);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
if (m.type() == message_t::kCall) {
|
||||||
|
// Set the message return type based on the callee return
|
||||||
|
// type
|
||||||
|
auto to_participant =
|
||||||
|
get_participant<sequence_diagram::model::function>(
|
||||||
|
m.to());
|
||||||
|
if (to_participant.has_value()) {
|
||||||
|
m.set_return_type(to_participant.value().return_type());
|
||||||
|
}
|
||||||
|
}
|
||||||
block_message_stack.back().push_back(m);
|
block_message_stack.back().push_back(m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -147,6 +147,10 @@ bool function::is_operator() const { return is_operator_; }
|
|||||||
|
|
||||||
void function::is_operator(bool o) { is_operator_ = o; }
|
void function::is_operator(bool o) { is_operator_ = o; }
|
||||||
|
|
||||||
|
void function::return_type(const std::string &rt) { return_type_ = rt; }
|
||||||
|
|
||||||
|
const std::string &function::return_type() const { return return_type_; }
|
||||||
|
|
||||||
void function::add_parameter(const std::string &a) { parameters_.push_back(a); }
|
void function::add_parameter(const std::string &a) { parameters_.push_back(a); }
|
||||||
|
|
||||||
const std::vector<std::string> &function::parameters() const
|
const std::vector<std::string> &function::parameters() const
|
||||||
|
|||||||
@@ -291,6 +291,20 @@ struct function : public participant {
|
|||||||
*/
|
*/
|
||||||
void is_operator(bool o);
|
void is_operator(bool o);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set functions return type
|
||||||
|
*
|
||||||
|
* @param rt Return type
|
||||||
|
*/
|
||||||
|
void return_type(const std::string &rt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get function return type
|
||||||
|
*
|
||||||
|
* @return Return type
|
||||||
|
*/
|
||||||
|
const std::string &return_type() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Add a function parameter
|
* @brief Add a function parameter
|
||||||
*
|
*
|
||||||
@@ -313,6 +327,7 @@ private:
|
|||||||
bool is_void_{false};
|
bool is_void_{false};
|
||||||
bool is_static_{false};
|
bool is_static_{false};
|
||||||
bool is_operator_{false};
|
bool is_operator_{false};
|
||||||
|
std::string return_type_;
|
||||||
std::vector<std::string> parameters_;
|
std::vector<std::string> parameters_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -972,13 +972,6 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// This crashes on LLVM <= 12, for now just return empty type
|
|
||||||
//
|
|
||||||
// const auto &return_type =
|
|
||||||
// function_call_expr->getCallReturnType(current_ast_context);
|
|
||||||
// m.return_type = return_type.getAsString();
|
|
||||||
|
|
||||||
if (m.from() > 0 && m.to() > 0) {
|
if (m.from() > 0 && m.to() > 0) {
|
||||||
if (diagram().sequences().find(m.from()) ==
|
if (diagram().sequences().find(m.from()) ==
|
||||||
diagram().sequences().end()) {
|
diagram().sequences().end()) {
|
||||||
@@ -1550,6 +1543,10 @@ translation_unit_visitor::build_function_template(
|
|||||||
|
|
||||||
process_template_parameters(declaration, *function_template_model_ptr);
|
process_template_parameters(declaration, *function_template_model_ptr);
|
||||||
|
|
||||||
|
function_template_model_ptr->return_type(
|
||||||
|
common::to_string(declaration.getAsFunction()->getReturnType(),
|
||||||
|
declaration.getASTContext()));
|
||||||
|
|
||||||
for (const auto *param : declaration.getTemplatedDecl()->parameters()) {
|
for (const auto *param : declaration.getTemplatedDecl()->parameters()) {
|
||||||
function_template_model_ptr->add_parameter(
|
function_template_model_ptr->add_parameter(
|
||||||
simplify_system_template(common::to_string(
|
simplify_system_template(common::to_string(
|
||||||
@@ -1612,6 +1609,9 @@ std::unique_ptr<model::function> translation_unit_visitor::build_function_model(
|
|||||||
ns.pop_back();
|
ns.pop_back();
|
||||||
function_model_ptr->set_namespace(ns);
|
function_model_ptr->set_namespace(ns);
|
||||||
|
|
||||||
|
function_model_ptr->return_type(common::to_string(
|
||||||
|
declaration.getReturnType(), declaration.getASTContext()));
|
||||||
|
|
||||||
for (const auto *param : declaration.parameters()) {
|
for (const auto *param : declaration.parameters()) {
|
||||||
function_model_ptr->add_parameter(
|
function_model_ptr->add_parameter(
|
||||||
simplify_system_template(common::to_string(
|
simplify_system_template(common::to_string(
|
||||||
@@ -2337,6 +2337,9 @@ translation_unit_visitor::create_method_model(clang::CXXMethodDecl *declaration)
|
|||||||
"::" + declaration->getNameAsString());
|
"::" + declaration->getNameAsString());
|
||||||
method_model_ptr->is_static(declaration->isStatic());
|
method_model_ptr->is_static(declaration->isStatic());
|
||||||
|
|
||||||
|
method_model_ptr->return_type(common::to_string(
|
||||||
|
declaration->getReturnType(), declaration->getASTContext()));
|
||||||
|
|
||||||
for (const auto *param : declaration->parameters()) {
|
for (const auto *param : declaration->parameters()) {
|
||||||
method_model_ptr->add_parameter(config().using_namespace().relative(
|
method_model_ptr->add_parameter(config().using_namespace().relative(
|
||||||
simplify_system_template(common::to_string(
|
simplify_system_template(common::to_string(
|
||||||
|
|||||||
15
tests/t20032/.clang-uml
Normal file
15
tests/t20032/.clang-uml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
compilation_database_dir: ..
|
||||||
|
output_directory: puml
|
||||||
|
diagrams:
|
||||||
|
t20032_sequence:
|
||||||
|
type: sequence
|
||||||
|
glob:
|
||||||
|
- ../../tests/t20032/t20032.cc
|
||||||
|
include:
|
||||||
|
namespaces:
|
||||||
|
- clanguml::t20032
|
||||||
|
using_namespace:
|
||||||
|
- clanguml::t20032
|
||||||
|
generate_return_types: true
|
||||||
|
start_from:
|
||||||
|
- function: "clanguml::t20032::tmain(int,char **)"
|
||||||
27
tests/t20032/t20032.cc
Normal file
27
tests/t20032/t20032.cc
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
namespace clanguml {
|
||||||
|
namespace t20032 {
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
79
tests/t20032/test_case.h
Normal file
79
tests/t20032/test_case.h
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
/**
|
||||||
|
* tests/t20032/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("t20032", "[test-case][sequence]")
|
||||||
|
{
|
||||||
|
auto [config, db] = load_config("t20032");
|
||||||
|
|
||||||
|
auto diagram = config.diagrams["t20032_sequence"];
|
||||||
|
|
||||||
|
REQUIRE(diagram->name == "t20032_sequence");
|
||||||
|
|
||||||
|
auto model = generate_sequence_diagram(*db, diagram);
|
||||||
|
|
||||||
|
REQUIRE(model->name() == "t20032_sequence");
|
||||||
|
|
||||||
|
REQUIRE(model->name() == "t20032_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, HasResponse(_A("tmain(int,char **)"), _A("B"), "int"));
|
||||||
|
|
||||||
|
REQUIRE_THAT(puml, HasCall(_A("B"), _A("A"), "a1(int)"));
|
||||||
|
REQUIRE_THAT(puml, HasResponse(_A("B"), _A("A"), "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, HasResponse(_A("B"), _A("A"), "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 *)"));
|
||||||
|
REQUIRE_THAT(puml, HasResponse(_A("B"), _A("A"), "const char *"));
|
||||||
|
|
||||||
|
save_puml(
|
||||||
|
config.output_directory() + "/" + diagram->name + ".puml", puml);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto j = generate_sequence_json(diagram, *model);
|
||||||
|
|
||||||
|
using namespace json;
|
||||||
|
|
||||||
|
std::vector<int> messages = {
|
||||||
|
FindMessage(j, "tmain(int,char **)", "B", "b(int)", "int"),
|
||||||
|
FindMessage(j, "B", "A", "a1(int)", "int"),
|
||||||
|
FindMessage(j, "tmain(int,char **)", "B", "b(double)"),
|
||||||
|
FindMessage(j, "B", "A", "a2(double)"),
|
||||||
|
FindMessage(j, "tmain(int,char **)", "B", "b(const char *)"),
|
||||||
|
FindMessage(j, "B", "A", "a3(const char *)")};
|
||||||
|
|
||||||
|
REQUIRE(std::is_sorted(messages.begin(), messages.end()));
|
||||||
|
|
||||||
|
save_json(config.output_directory() + "/" + diagram->name + ".json", j);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -345,6 +345,7 @@ using namespace clanguml::test::matchers;
|
|||||||
#include "t20029/test_case.h"
|
#include "t20029/test_case.h"
|
||||||
#include "t20030/test_case.h"
|
#include "t20030/test_case.h"
|
||||||
#include "t20031/test_case.h"
|
#include "t20031/test_case.h"
|
||||||
|
#include "t20032/test_case.h"
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Package diagram tests
|
/// Package diagram tests
|
||||||
|
|||||||
@@ -134,12 +134,15 @@ struct HasCallWithResultMatcher : ContainsMatcher {
|
|||||||
|
|
||||||
template <typename T> class HasCallMatcher : public Catch::MatcherBase<T> {
|
template <typename T> class HasCallMatcher : public Catch::MatcherBase<T> {
|
||||||
T m_from, m_to, m_message;
|
T m_from, m_to, m_message;
|
||||||
|
bool m_is_response;
|
||||||
|
std::string call_pattern, response_pattern;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HasCallMatcher(T from, T to, T message)
|
HasCallMatcher(T from, T to, T message, bool is_response = false)
|
||||||
: m_from(from)
|
: m_from(from)
|
||||||
, m_to{to}
|
, m_to{to}
|
||||||
, m_message{message}
|
, m_message{message}
|
||||||
|
, m_is_response{is_response}
|
||||||
{
|
{
|
||||||
util::replace_all(m_message, "(", "\\(");
|
util::replace_all(m_message, "(", "\\(");
|
||||||
util::replace_all(m_message, ")", "\\)");
|
util::replace_all(m_message, ")", "\\)");
|
||||||
@@ -147,15 +150,22 @@ public:
|
|||||||
util::replace_all(m_message, "[", "\\[");
|
util::replace_all(m_message, "[", "\\[");
|
||||||
util::replace_all(m_message, "]", "\\]");
|
util::replace_all(m_message, "]", "\\]");
|
||||||
util::replace_all(m_message, "+", "\\+");
|
util::replace_all(m_message, "+", "\\+");
|
||||||
|
|
||||||
|
call_pattern = fmt::format("{} -> {} "
|
||||||
|
"(\\[\\[.*\\]\\] )?: {}",
|
||||||
|
m_from, m_to, m_message);
|
||||||
|
|
||||||
|
response_pattern =
|
||||||
|
fmt::format("{} --> {} : //{}//", m_from, m_to, m_message);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool match(T const &in) const override
|
bool match(T const &in) const override
|
||||||
{
|
{
|
||||||
std::istringstream fin(in);
|
std::istringstream fin(in);
|
||||||
std::string line;
|
std::string line;
|
||||||
std::regex r{fmt::format("{} -> {} "
|
|
||||||
"(\\[\\[.*\\]\\] )?: {}",
|
std::regex r{m_is_response ? response_pattern : call_pattern};
|
||||||
m_from, m_to, m_message)};
|
|
||||||
while (std::getline(fin, line)) {
|
while (std::getline(fin, line)) {
|
||||||
std::smatch base_match;
|
std::smatch base_match;
|
||||||
std::regex_search(in, base_match, r);
|
std::regex_search(in, base_match, r);
|
||||||
@@ -182,6 +192,13 @@ auto HasCall(std::string const &from, std::string const &to,
|
|||||||
return HasCallMatcher(from, to, message);
|
return HasCallMatcher(from, to, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto HasResponse(std::string const &from, std::string const &to,
|
||||||
|
std::string const &message,
|
||||||
|
CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
|
||||||
|
{
|
||||||
|
return HasCallMatcher(to, from, message, true);
|
||||||
|
}
|
||||||
|
|
||||||
auto HasCallInControlCondition(std::string const &from, std::string const &to,
|
auto HasCallInControlCondition(std::string const &from, std::string const &to,
|
||||||
std::string const &message,
|
std::string const &message,
|
||||||
CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
|
CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
|
||||||
@@ -955,7 +972,8 @@ bool IsFileParticipant(const nlohmann::json &j, const std::string &name)
|
|||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
int find_message_nested(const nlohmann::json &j, const std::string &from,
|
int find_message_nested(const nlohmann::json &j, const std::string &from,
|
||||||
const std::string &to, const std::string &msg, const nlohmann::json &from_p,
|
const std::string &to, const std::string &msg,
|
||||||
|
std::optional<std::string> return_type, const nlohmann::json &from_p,
|
||||||
const nlohmann::json &to_p, int &count)
|
const nlohmann::json &to_p, int &count)
|
||||||
{
|
{
|
||||||
const auto &messages = j["messages"];
|
const auto &messages = j["messages"];
|
||||||
@@ -965,23 +983,25 @@ int find_message_nested(const nlohmann::json &j, const std::string &from,
|
|||||||
for (const auto &m : messages) {
|
for (const auto &m : messages) {
|
||||||
if (m.contains("branches")) {
|
if (m.contains("branches")) {
|
||||||
for (const auto &b : m["branches"]) {
|
for (const auto &b : m["branches"]) {
|
||||||
auto nested_res =
|
auto nested_res = find_message_nested(
|
||||||
find_message_nested(b, from, to, msg, from_p, to_p, count);
|
b, from, to, msg, return_type, from_p, to_p, count);
|
||||||
|
|
||||||
if (nested_res >= 0)
|
if (nested_res >= 0)
|
||||||
return nested_res;
|
return nested_res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (m.contains("messages")) {
|
else if (m.contains("messages")) {
|
||||||
auto nested_res =
|
auto nested_res = find_message_nested(
|
||||||
find_message_nested(m, from, to, msg, from_p, to_p, count);
|
m, from, to, msg, return_type, from_p, to_p, count);
|
||||||
|
|
||||||
if (nested_res >= 0)
|
if (nested_res >= 0)
|
||||||
return nested_res;
|
return nested_res;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if ((m["from"]["participant_id"] == from_p["id"]) &&
|
if ((m["from"]["participant_id"] == from_p["id"]) &&
|
||||||
(m["to"]["participant_id"] == to_p["id"]) && (m["name"] == msg))
|
(m["to"]["participant_id"] == to_p["id"]) &&
|
||||||
|
(m["name"] == msg) &&
|
||||||
|
(!return_type || m["return_type"] == *return_type))
|
||||||
return count;
|
return count;
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
@@ -992,7 +1012,8 @@ int find_message_nested(const nlohmann::json &j, const std::string &from,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int find_message_impl(const nlohmann::json &j, const std::string &from,
|
int find_message_impl(const nlohmann::json &j, const std::string &from,
|
||||||
const std::string &to, const std::string &msg)
|
const std::string &to, const std::string &msg,
|
||||||
|
std::optional<std::string> return_type)
|
||||||
{
|
{
|
||||||
|
|
||||||
auto from_p = get_participant(j, from);
|
auto from_p = get_participant(j, from);
|
||||||
@@ -1004,7 +1025,7 @@ int find_message_impl(const nlohmann::json &j, const std::string &from,
|
|||||||
int count{0};
|
int count{0};
|
||||||
|
|
||||||
auto res = detail::find_message_nested(
|
auto res = detail::find_message_nested(
|
||||||
sequence_0, from, to, msg, *from_p, *to_p, count);
|
sequence_0, from, to, msg, return_type, *from_p, *to_p, count);
|
||||||
|
|
||||||
if (res >= 0)
|
if (res >= 0)
|
||||||
return res;
|
return res;
|
||||||
@@ -1018,14 +1039,15 @@ int find_message_impl(const nlohmann::json &j, const std::string &from,
|
|||||||
int FindMessage(const nlohmann::json &j, const File &from, const File &to,
|
int FindMessage(const nlohmann::json &j, const File &from, const File &to,
|
||||||
const std::string &msg)
|
const std::string &msg)
|
||||||
{
|
{
|
||||||
return detail::find_message_impl(j, from.file, to.file, msg);
|
return detail::find_message_impl(j, from.file, to.file, msg, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
int FindMessage(const nlohmann::json &j, const std::string &from,
|
int FindMessage(const nlohmann::json &j, const std::string &from,
|
||||||
const std::string &to, const std::string &msg)
|
const std::string &to, const std::string &msg,
|
||||||
|
std::optional<std::string> return_type = {})
|
||||||
{
|
{
|
||||||
return detail::find_message_impl(
|
return detail::find_message_impl(
|
||||||
j, expand_name(j, from), expand_name(j, to), msg);
|
j, expand_name(j, from), expand_name(j, to), msg, return_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace json
|
} // namespace json
|
||||||
|
|||||||
@@ -292,6 +292,9 @@ test_cases:
|
|||||||
- name: t20031
|
- name: t20031
|
||||||
title: Callee type sequence diagram filter test case
|
title: Callee type sequence diagram filter test case
|
||||||
description:
|
description:
|
||||||
|
- name: t20032
|
||||||
|
title: Return type generation option sequence diagram test case
|
||||||
|
description:
|
||||||
Package diagrams:
|
Package diagrams:
|
||||||
- name: t30001
|
- name: t30001
|
||||||
title: Basic package diagram test case
|
title: Basic package diagram test case
|
||||||
|
|||||||
@@ -323,3 +323,20 @@ TEST_CASE("Test config diagram_templates", "[unit-test]")
|
|||||||
REQUIRE(cfg.diagram_templates()["main_sequence_tmpl"].type ==
|
REQUIRE(cfg.diagram_templates()["main_sequence_tmpl"].type ==
|
||||||
clanguml::common::model::diagram_t::kSequence);
|
clanguml::common::model::diagram_t::kSequence);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test config sequence inherited", "[unit-test]")
|
||||||
|
{
|
||||||
|
auto cfg = clanguml::config::load(
|
||||||
|
"./test_config_data/sequence_inheritable_options.yml");
|
||||||
|
|
||||||
|
CHECK(cfg.diagrams.size() == 2);
|
||||||
|
auto &def = *cfg.diagrams["sequence_default"];
|
||||||
|
CHECK(def.type() == clanguml::common::model::diagram_t::kSequence);
|
||||||
|
CHECK(def.combine_free_functions_into_file_participants() == true);
|
||||||
|
CHECK(def.generate_return_types() == true);
|
||||||
|
|
||||||
|
def = *cfg.diagrams["sequence_default2"];
|
||||||
|
CHECK(def.type() == clanguml::common::model::diagram_t::kSequence);
|
||||||
|
CHECK(def.combine_free_functions_into_file_participants() == false);
|
||||||
|
CHECK(def.generate_return_types() == false);
|
||||||
|
}
|
||||||
15
tests/test_config_data/sequence_inheritable_options.yml
Normal file
15
tests/test_config_data/sequence_inheritable_options.yml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
compilation_database_dir: debug
|
||||||
|
output_directory: output
|
||||||
|
combine_free_functions_into_file_participants: true
|
||||||
|
generate_return_types: true
|
||||||
|
diagrams:
|
||||||
|
sequence_default:
|
||||||
|
type: sequence
|
||||||
|
glob:
|
||||||
|
- src/*.cc
|
||||||
|
sequence_default2:
|
||||||
|
type: sequence
|
||||||
|
glob:
|
||||||
|
- src/*.cc
|
||||||
|
combine_free_functions_into_file_participants: false
|
||||||
|
generate_return_types: false
|
||||||
Reference in New Issue
Block a user