Added combine_free_functions_into_file_participants sequence diagram option

This commit is contained in:
Bartek Kryza
2022-12-09 00:10:38 +01:00
parent 6478cffa27
commit caf0ae7928
14 changed files with 212 additions and 12 deletions

View File

@@ -101,6 +101,8 @@ void inheritable_diagram_options::inherit(
base_directory.override(parent.base_directory);
relative_to.override(parent.relative_to);
comment_parser.override(parent.comment_parser);
combine_free_functions_into_file_participants.override(
combine_free_functions_into_file_participants);
}
std::string inheritable_diagram_options::simplify_template_type(
@@ -589,6 +591,8 @@ template <> struct convert<sequence_diagram> {
return false;
get_option(node, rhs.start_from);
get_option(node, rhs.combine_free_functions_into_file_participants);
get_option(node, rhs.relative_to);
rhs.initialize_type_aliases();

View File

@@ -142,6 +142,8 @@ struct inheritable_diagram_options {
option<type_aliases_t> type_aliases{"type_aliases"};
option<comment_parser_t> comment_parser{
"comment_parser", comment_parser_t::plain};
option<bool> combine_free_functions_into_file_participants{
"combine_free_functions_into_file_participants", false};
void inherit(const inheritable_diagram_options &parent);

View File

@@ -62,10 +62,25 @@ void generator::generate_call(const message &m, std::ostream &ostr) const
message = dynamic_cast<const model::function &>(to.value())
.message_name(model::function::message_render_mode::full);
}
else if (m_config.combine_free_functions_into_file_participants()) {
if (to.value().type_name() == "function") {
message =
dynamic_cast<const model::function &>(to.value())
.message_name(model::function::message_render_mode::full);
}
else if (to.value().type_name() == "function_template") {
message =
dynamic_cast<const model::function_template &>(to.value())
.message_name(model::function::message_render_mode::full);
}
}
ostr << from.value().alias() << " "
const std::string from_alias = generate_alias(from.value());
const std::string to_alias = generate_alias(to.value());
ostr << from_alias << " "
<< common::generators::plantuml::to_plantuml(message_t::kCall) << " "
<< to.value().alias() << " : " << message << std::endl;
<< to_alias << " : " << message << std::endl;
LOG_DBG("Generated call '{}' from {} [{}] to {} [{}]", message, from,
m.from, to, m.to);
@@ -79,9 +94,13 @@ void generator::generate_return(const message &m, std::ostream &ostr) const
const auto &from = m_model.get_participant<model::participant>(m.from);
const auto &to = m_model.get_participant<model::participant>(m.to);
ostr << to.value().alias() << " "
const std::string from_alias = generate_alias(from.value());
const std::string to_alias = generate_alias(to.value());
ostr << to_alias << " "
<< common::generators::plantuml::to_plantuml(message_t::kReturn)
<< " " << from.value().alias() << '\n';
<< " " << from_alias << '\n';
}
}
@@ -99,7 +118,9 @@ void generator::generate_activity(const activity &a, std::ostream &ostr,
generate_call(m, ostr);
ostr << "activate " << to.value().alias() << std::endl;
std::string to_alias = generate_alias(to.value());
ostr << "activate " << to_alias << std::endl;
if (m_model.sequences.find(m.to) != m_model.sequences.end()) {
if (std::find(visited.begin(), visited.end(), m.to) ==
@@ -117,7 +138,7 @@ void generator::generate_activity(const activity &a, std::ostream &ostr,
visited.pop_back();
ostr << "deactivate " << to.value().alias() << std::endl;
ostr << "deactivate " << to_alias << std::endl;
}
}
@@ -152,6 +173,35 @@ void generator::generate_participant(std::ostream &ostr, common::id_t id) const
generated_participants_.emplace(class_id);
}
else if ((participant.type_name() == "function" ||
participant.type_name() == "function_template") &&
m_config.combine_free_functions_into_file_participants()) {
// Create a single participant for all functions declared in a
// single file
const auto &file_path =
m_model.get_participant<model::function>(participant_id)
.value()
.file();
assert(!file_path.empty());
const auto file_id = common::to_id(file_path);
if (is_participant_generated(file_id))
return;
[[maybe_unused]] const auto &relative_to =
std::filesystem::canonical(m_config.relative_to());
auto participant_name = std::filesystem::relative(
std::filesystem::path{file_path}, relative_to)
.string();
ostr << "participant \"" << render_name(participant_name)
<< "\" as " << fmt::format("C_{:022}", file_id) << '\n';
generated_participants_.emplace(file_id);
}
else {
ostr << "participant \""
<< m_config.using_namespace().relative(
@@ -192,6 +242,8 @@ void generator::generate(std::ostream &ostr) const
break;
}
}
// Use this to break out of recurrent loops
std::vector<common::model::diagram_element::id_t>
visited_participants;
@@ -199,20 +251,22 @@ void generator::generate(std::ostream &ostr) const
m_model.get_participant<model::participant>(start_from);
if (!from.has_value()) {
LOG_WARN(
"Failed to find participant {} for start_from condition",
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;
std::string from_alias = generate_alias(from.value());
ostr << "activate " << from_alias << std::endl;
generate_activity(
m_model.sequences[start_from], ostr, visited_participants);
ostr << "deactivate " << from.value().alias() << std::endl;
ostr << "deactivate " << from_alias << std::endl;
}
else {
// TODO: Add support for other sequence start location types
@@ -225,4 +279,17 @@ void generator::generate(std::ostream &ostr) const
ostr << "@enduml" << std::endl;
}
std::string generator::generate_alias(
const model::participant &participant) const
{
if ((participant.type_name() == "function" ||
participant.type_name() == "function_template") &&
m_config.combine_free_functions_into_file_participants()) {
const auto file_id = common::to_id(participant.file());
return fmt::format("C_{:022}", file_id);
}
return participant.alias();
}
}

View File

@@ -66,6 +66,7 @@ private:
std::string render_name(std::string name) const;
mutable std::set<common::id_t> generated_participants_;
std::string generate_alias(const model::participant &participant) const;
};
}

View File

@@ -246,6 +246,21 @@ struct function_template : public function, public template_trait {
std::string full_name(bool relative = true) const override;
std::string full_name_no_ns() const override;
std::string message_name(message_render_mode mode) const override
{
std::ostringstream s;
render_template_params(s, using_namespace(), true);
std::string template_params = s.str();
if (mode == message_render_mode::no_arguments) {
return fmt::format("{}{}(){}", name(), template_params,
is_const() ? " const" : "");
}
return fmt::format("{}{}({}){}", name(), template_params,
fmt::join(parameters(), ","), is_const() ? " const" : "");
}
};
}

View File

@@ -376,6 +376,8 @@ bool translation_unit_visitor::VisitFunctionDecl(clang::FunctionDecl *f)
set_unique_id(f->getID(), f_ptr->id());
set_source_location(*f, *f_ptr);
// TODO: Handle overloaded functions with different arguments
diagram().add_participant(std::move(f_ptr));
}
@@ -401,6 +403,8 @@ bool translation_unit_visitor::VisitFunctionDecl(clang::FunctionDecl *f)
set_unique_id(f->getID(), f_ptr->id());
set_source_location(*f, *f_ptr);
// TODO: Handle overloaded functions with different arguments
diagram().add_participant(std::move(f_ptr));
}
@@ -437,6 +441,8 @@ bool translation_unit_visitor::VisitFunctionTemplateDecl(
f_ptr->set_id(common::to_id(f_ptr->full_name(false)));
set_source_location(*function_template, *f_ptr);
context().update(function_template);
context().set_caller_id(f_ptr->id());
@@ -784,8 +790,9 @@ bool translation_unit_visitor::process_class_template_method_call_expression(
get_unique_id(template_declaration->getID()).value());
}
else {
LOG_WARN("Cannot generate call due to unresolvable "
"CXXDependentScopeMemberExpr");
LOG_DBG("Skipping call due to unresolvable "
"CXXDependentScopeMemberExpr at {}",
expr->getBeginLoc().printToString(source_manager()));
}
return true;