Skip to content

Commit

Permalink
Added proper generation of return statements from all branches (#375)
Browse files Browse the repository at this point in the history
  • Loading branch information
bkryza committed Jan 22, 2025
1 parent e8a744e commit c1d3962
Show file tree
Hide file tree
Showing 25 changed files with 572 additions and 133 deletions.
1 change: 1 addition & 0 deletions src/config/config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ void inheritable_diagram_options::inherit(
parent.combine_free_functions_into_file_participants);
inline_lambda_messages.override(parent.inline_lambda_messages);
generate_return_types.override(parent.generate_return_types);
generate_return_values.override(parent.generate_return_values);
generate_condition_statements.override(
parent.generate_condition_statements);
debug_mode.override(parent.debug_mode);
Expand Down
1 change: 1 addition & 0 deletions src/config/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,7 @@ struct inheritable_diagram_options {
"combine_free_functions_into_file_participants", false};
option<bool> inline_lambda_messages{"inline_lambda_messages", false};
option<bool> generate_return_types{"generate_return_types", false};
option<bool> generate_return_values{"generate_return_values", false};
option<bool> generate_condition_statements{
"generate_condition_statements", false};
option<std::vector<std::string>> participants_order{"participants_order"};
Expand Down
2 changes: 2 additions & 0 deletions src/config/schema.h
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ const std::string schema_str = R"(
combine_free_functions_into_file_participants: !optional bool
inline_lambda_messages: !optional bool
generate_return_types: !optional bool
generate_return_values: !optional bool
generate_condition_statements: !optional bool
generate_message_comments: !optional bool
fold_repeated_activities: !optional bool
Expand Down Expand Up @@ -402,6 +403,7 @@ const std::string schema_str = R"(
inline_lambda_messages: !optional bool
generate_concept_requirements: !optional bool
generate_return_types: !optional bool
generate_return_values: !optional bool
generate_condition_statements: !optional bool
generate_message_comments: !optional bool
fold_repeated_activities: !optional bool
Expand Down
2 changes: 2 additions & 0 deletions src/config/yaml_decoders.cc
Original file line number Diff line number Diff line change
Expand Up @@ -856,6 +856,7 @@ template <> struct convert<sequence_diagram> {
get_option(node, rhs.combine_free_functions_into_file_participants);
get_option(node, rhs.inline_lambda_messages);
get_option(node, rhs.generate_return_types);
get_option(node, rhs.generate_return_values);
get_option(node, rhs.generate_condition_statements);
get_option(node, rhs.participants_order);
get_option(node, rhs.generate_method_arguments);
Expand Down Expand Up @@ -1065,6 +1066,7 @@ template <> struct convert<config> {
get_option(node, rhs.combine_free_functions_into_file_participants);
get_option(node, rhs.inline_lambda_messages);
get_option(node, rhs.generate_return_types);
get_option(node, rhs.generate_return_values);
get_option(node, rhs.generate_condition_statements);
get_option(node, rhs.generate_message_comments);
get_option(node, rhs.fold_repeated_activities);
Expand Down
1 change: 1 addition & 0 deletions src/config/yaml_emitters.cc
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,7 @@ YAML::Emitter &operator<<(
out << c.generate_condition_statements;
out << c.generate_method_arguments;
out << c.generate_return_types;
out << c.generate_return_values;
out << c.participants_order;
out << c.generate_message_comments;
out << c.fold_repeated_activities;
Expand Down
163 changes: 116 additions & 47 deletions src/sequence_diagram/generators/json/sequence_diagram_generator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -115,47 +115,29 @@ void generator::generate_call(const message &m, nlohmann::json &parent) const

msg["name"] = message;
msg["type"] = "message";
msg["from"]["activity_id"] = std::to_string(from.value().id().value());
msg["to"]["activity_id"] = std::to_string(to.value().id().value());
if (const auto &cmt = m.comment(); cmt.has_value())
msg["comment"] = cmt.value().at("comment");

if (from.value().type_name() == "method") {
const auto &class_participant =
model().get_participant<model::method>(from.value().id()).value();
generate_from_activity(m, from, msg);

msg["from"]["participant_id"] =
std::to_string(class_participant.class_id().value());
}
else if (from.value().type_name() == "objc_method") {
const auto &class_participant =
model()
.get_participant<model::objc_method>(from.value().id())
.value();
generate_to_activity(to, msg);

msg["from"]["participant_id"] =
std::to_string(class_participant.class_id().value());
}
else if (from.value().type_name() == "function" ||
from.value().type_name() == "function_template") {
if (config().combine_free_functions_into_file_participants()) {
const auto &file_participant =
model()
.get_participant<model::function>(from.value().id())
.value();
msg["from"]["participant_id"] = std::to_string(
common::to_id(file_participant.file_relative()).value());
}
else {
msg["from"]["participant_id"] =
std::to_string(from.value().id().value());
}
}
else if (from.value().type_name() == "lambda") {
msg["from"]["participant_id"] =
std::to_string(from.value().id().value());
}
msg["source_location"] =
dynamic_cast<const clanguml::common::model::source_location &>(m);

msg["scope"] = to_string(m.message_scope());
msg["return_type"] = config().simplify_template_type(m.return_type());

parent["messages"].push_back(std::move(msg));

LOG_DBG("Generated call '{}' from {} [{}] to {} [{}]", message,
from.value().full_name(false), m.from(), to.value().full_name(false),
m.to());
}

void generator::generate_to_activity(
const common::optional_ref<model::participant> &to,
nlohmann::json &msg) const
{
msg["to"]["activity_id"] = std::to_string(to.value().id().value());
if (to.value().type_name() == "method") {
const auto &class_participant =
model().get_participant<model::method>(to.value().id()).value();
Expand Down Expand Up @@ -190,18 +172,51 @@ void generator::generate_call(const message &m, nlohmann::json &parent) const
else if (to.value().type_name() == "lambda") {
msg["to"]["participant_id"] = std::to_string(to.value().id().value());
}
}

msg["source_location"] =
dynamic_cast<const clanguml::common::model::source_location &>(m);
void generator::generate_from_activity(const message &m,
const common::optional_ref<model::participant> &from,
nlohmann::json &msg) const
{
msg["from"]["activity_id"] = std::to_string(from.value().id().value());
if (const auto &cmt = m.comment(); cmt.has_value())
msg["comment"] = cmt.value().at("comment");

msg["scope"] = to_string(m.message_scope());
msg["return_type"] = config().simplify_template_type(m.return_type());
if (from.value().type_name() == "method") {
const auto &class_participant =
model().get_participant<model::method>(from.value().id()).value();

parent["messages"].push_back(std::move(msg));
msg["from"]["participant_id"] =
std::to_string(class_participant.class_id().value());
}
else if (from.value().type_name() == "objc_method") {
const auto &class_participant =
model()
.get_participant<model::objc_method>(from.value().id())
.value();

LOG_DBG("Generated call '{}' from {} [{}] to {} [{}]", message,
from.value().full_name(false), m.from(), to.value().full_name(false),
m.to());
msg["from"]["participant_id"] =
std::to_string(class_participant.class_id().value());
}
else if (from.value().type_name() == "function" ||
from.value().type_name() == "function_template") {
if (config().combine_free_functions_into_file_participants()) {
const auto &file_participant =
model()
.get_participant<model::function>(from.value().id())
.value();
msg["from"]["participant_id"] = std::to_string(
common::to_id(file_participant.file_relative()).value());
}
else {
msg["from"]["participant_id"] =
std::to_string(from.value().id().value());
}
}
else if (from.value().type_name() == "lambda") {
msg["from"]["participant_id"] =
std::to_string(from.value().id().value());
}
}

void generator::generate_activity(
Expand Down Expand Up @@ -268,8 +283,14 @@ void generator::generate_activity(
case message_t::kConditionalEnd:
process_end_conditional_message();
break;
case message_t::kNone:
case message_t::kReturn:; // noop
case message_t::kReturn: {
auto return_message = m;
if (!visited.empty()) {
return_message.set_to(visited.back());
}
process_return_message(return_message);
}
case message_t::kNone:;
}
}
}
Expand Down Expand Up @@ -316,6 +337,54 @@ void generator::process_call_message(
visited.pop_back();
}

void generator::process_return_message(const message &m) const
{
const auto &from = model().get_participant<model::participant>(m.from());
const auto &to = model().get_participant<model::participant>(m.to());

if (!from) {
LOG_DBG("Skipping return call - no participant for id {}", m.from());
return;
}

if (!to) {
LOG_DBG("Skipping return call - no participant for id {}", m.to());
return;
}

generate_participant(json_, m.from());
generate_participant(json_, m.to());

std::string message;

if (config().generate_return_types()) {
message = m.return_type();
}
else if (config().generate_return_values()) {
message = m.message_name();
}

nlohmann::json msg;
msg["name"] = message;
msg["type"] = "return";

generate_from_activity(m, from, msg);

generate_to_activity(to, msg);

msg["source_location"] =
dynamic_cast<const clanguml::common::model::source_location &>(m);

msg["scope"] = to_string(m.message_scope());
msg["return_type"] = config().simplify_template_type(m.return_type());

current_block_statement()["messages"].push_back(std::move(msg));

LOG_DBG("Generated return call '{}' from {} [{}] to {} [{}]", message,
from.value().full_name(false), m.from(), to.value().full_name(false),
m.to());
}

void generator::process_while_message(const message &m) const
{
nlohmann::json while_block;
Expand Down
15 changes: 15 additions & 0 deletions src/sequence_diagram/generators/json/sequence_diagram_generator.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,13 @@ class generator : public common_generator<diagram_config, diagram_model> {
void process_call_message(
const model::message &m, std::vector<eid_t> &visited) const;

/**
* @brief Process return message
*
* @param m Message model
*/
void process_return_message(const model::message &m) const;

/**
* @brief Process `if` statement message
*
Expand Down Expand Up @@ -245,6 +252,14 @@ class generator : public common_generator<diagram_config, diagram_model> {

void generate_from_sequences(nlohmann::json &parent) const;

void generate_from_activity(const model::message &m,
const common::optional_ref<model::participant> &from,
nlohmann::json &msg) const;

void generate_to_activity(
const common::optional_ref<model::participant> &to,
nlohmann::json &msg) const;

std::vector<eid_t> find_from_activities() const;

mutable std::set<eid_t> generated_participants_;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,22 +171,47 @@ void generator::generate_call(const message &m, std::ostream &ostr) const

void generator::generate_return(const message &m, std::ostream &ostr) const
{
// Add return activity only for messages between different actors and
// only if the return type is different than void
const auto &from = model().get_participant<model::participant>(m.from());
const auto &to = model().get_participant<model::function>(m.to());
if ((m.from() != m.to()) && !to.value().is_void()) {
assert(m.type() == message_t::kReturn);

// Add return activity only for messages between different actors
// and only if the return type is different than void
if (m.from() == m.to())
return;

const auto &from = model().get_participant<model::function>(m.from());
const auto &to = model().get_participant<model::participant>(m.to());
if (to.has_value() && from.has_value() && !from.value().is_void()) {
const std::string from_alias = generate_alias(from.value());

const std::string to_alias = generate_alias(to.value());

ostr << indent(1) << to_alias << " "
ostr << indent(1) << from_alias << " "
<< common::generators::mermaid::to_mermaid(message_t::kReturn)
<< " " << from_alias << " : ";
<< " " << to_alias << " : ";

if (config().generate_return_types()) {
ostr << m.return_type();
}
else if (config().generate_return_values()) {
ostr << m.message_name();
}

ostr << '\n';
}
else if (from.has_value() && !from.value().is_void() &&
(from.value().type_name() == "method" ||
from.value().type_name() == "objc_method" ||
config().combine_free_functions_into_file_participants())) {
const std::string from_alias = generate_alias(from.value());

ostr << indent(1) << from_alias << " "
<< common::generators::mermaid::to_mermaid(message_t::kReturn)
<< " * : ";

if (config().generate_return_types())
ostr << from.value().return_type();
else if (config().generate_return_values())
ostr << m.message_name();

ostr << '\n';
}
Expand Down Expand Up @@ -247,12 +272,19 @@ void generator::generate_activity(
LOG_DBG("Skipping activity {} --> {} - missing sequence {}",
m.from(), m.to(), m.to());

generate_return(m, ostr);

ostr << indent(1) << "deactivate " << to_alias << '\n';

visited.pop_back();
}
else if (m.type() == message_t::kReturn) {
print_debug(m, ostr);
generate_message_comment(ostr, m);
auto return_message = m;
if (!visited.empty()) {
return_message.set_to(visited.back());
}
generate_return(return_message, ostr);
}
else if (m.type() == message_t::kIf) {
print_debug(m, ostr);
generate_message_comment(ostr, m);
Expand Down Expand Up @@ -575,6 +607,7 @@ void generator::generate_from_sequences(std::ostream &ostr) const
// which method relates to the first activity for this 'start_from'
// condition
if (from.value().type_name() == "method" ||
from.value().type_name() == "objc_method" ||
config().combine_free_functions_into_file_participants()) {
ostr << indent(1) << "* "
<< common::generators::mermaid::to_mermaid(message_t::kCall)
Expand All @@ -586,22 +619,6 @@ void generator::generate_from_sequences(std::ostream &ostr) const

generate_activity(from_id, ostr, visited_participants);

if (from.value().type_name() == "method" ||
config().combine_free_functions_into_file_participants()) {

if (!from.value().is_void()) {
ostr << indent(1) << from_alias << " "
<< common::generators::mermaid::to_mermaid(
message_t::kReturn)
<< " *" << " : ";

if (config().generate_return_types())
ostr << from.value().return_type();

ostr << '\n';
}
}

ostr << indent(1) << "deactivate " << from_alias << '\n';
}
}
Expand Down
Loading

0 comments on commit c1d3962

Please sign in to comment.