Refactored generator inheritance hierarchy

This commit is contained in:
Bartek Kryza
2023-07-31 23:44:56 +02:00
parent eded9f4292
commit c119a622fa
22 changed files with 535 additions and 427 deletions

View File

@@ -70,8 +70,8 @@ generator::generator(
void generator::generate_call(const message &m, nlohmann::json &parent) const
{
const auto &from = m_model.get_participant<model::participant>(m.from());
const auto &to = m_model.get_participant<model::participant>(m.to());
const auto &from = model().get_participant<model::participant>(m.from());
const auto &to = model().get_participant<model::participant>(m.to());
if (!from || !to) {
LOG_DBG("Skipping empty call from '{}' to '{}'", m.from(), m.to());
@@ -90,7 +90,7 @@ void generator::generate_call(const message &m, nlohmann::json &parent) const
message = dynamic_cast<const model::function &>(to.value())
.message_name(render_mode);
}
else if (m_config.combine_free_functions_into_file_participants()) {
else if (config().combine_free_functions_into_file_participants()) {
if (to.value().type_name() == "function") {
message = dynamic_cast<const model::function &>(to.value())
.message_name(render_mode);
@@ -113,16 +113,17 @@ void generator::generate_call(const message &m, nlohmann::json &parent) const
if (from.value().type_name() == "method") {
const auto &class_participant =
m_model.get_participant<model::method>(from.value().id()).value();
model().get_participant<model::method>(from.value().id()).value();
msg["from"]["participant_id"] =
std::to_string(class_participant.class_id());
}
else if (from.value().type_name() == "function" ||
from.value().type_name() == "function_template") {
if (m_config.combine_free_functions_into_file_participants()) {
if (config().combine_free_functions_into_file_participants()) {
const auto &file_participant =
m_model.get_participant<model::function>(from.value().id())
model()
.get_participant<model::function>(from.value().id())
.value();
msg["from"]["participant_id"] =
std::to_string(common::to_id(file_participant.file_relative()));
@@ -138,16 +139,17 @@ void generator::generate_call(const message &m, nlohmann::json &parent) const
if (to.value().type_name() == "method") {
const auto &class_participant =
m_model.get_participant<model::method>(to.value().id()).value();
model().get_participant<model::method>(to.value().id()).value();
msg["to"]["participant_id"] =
std::to_string(class_participant.class_id());
}
else if (to.value().type_name() == "function" ||
to.value().type_name() == "function_template") {
if (m_config.combine_free_functions_into_file_participants()) {
if (config().combine_free_functions_into_file_participants()) {
const auto &file_participant =
m_model.get_participant<model::function>(to.value().id())
model()
.get_participant<model::function>(to.value().id())
.value();
msg["to"]["participant_id"] =
std::to_string(common::to_id(file_participant.file_relative()));
@@ -258,14 +260,14 @@ void generator::process_call_message(const model::message &m,
generate_call(m, current_block_statement());
if (m_model.sequences().find(m.to()) != m_model.sequences().end()) {
if (model().sequences().find(m.to()) != model().sequences().end()) {
if (std::find(visited.begin(), visited.end(), m.to()) ==
visited.end()) { // break infinite recursion on recursive calls
LOG_DBG("Creating activity {} --> {} - missing sequence {}",
m.from(), m.to(), m.to());
generate_activity(m_model.get_activity(m.to()), visited);
generate_activity(model().get_activity(m.to()), visited);
}
}
else
@@ -506,7 +508,7 @@ void generator::process_if_message(const message &m) const
void generator::generate_participant(
nlohmann::json &parent, const std::string &name) const
{
auto p = m_model.get(name);
auto p = model().get(name);
if (!p.has_value()) {
LOG_WARN("Cannot find participant {} from `participants_order` option",
@@ -523,7 +525,7 @@ common::id_t generator::generate_participant(
common::id_t participant_id{0};
if (!force) {
for (const auto pid : m_model.active_participants()) {
for (const auto pid : model().active_participants()) {
if (pid == id) {
participant_id = pid;
break;
@@ -540,10 +542,11 @@ common::id_t generator::generate_participant(
return participant_id;
const auto &participant =
m_model.get_participant<model::participant>(participant_id).value();
model().get_participant<model::participant>(participant_id).value();
if (participant.type_name() == "method") {
participant_id = m_model.get_participant<model::method>(participant_id)
participant_id = model()
.get_participant<model::method>(participant_id)
.value()
.class_id();
@@ -551,21 +554,21 @@ common::id_t generator::generate_participant(
return participant_id;
const auto &class_participant =
m_model.get_participant<model::participant>(participant_id).value();
model().get_participant<model::participant>(participant_id).value();
parent["participants"].push_back(class_participant);
}
else if ((participant.type_name() == "function" ||
participant.type_name() == "function_template") &&
m_config.combine_free_functions_into_file_participants()) {
config().combine_free_functions_into_file_participants()) {
// Create a single participant for all functions declared in a
// single file
const auto &function_participant =
m_model.get_participant<model::function>(participant_id).value();
model().get_participant<model::function>(participant_id).value();
nlohmann::json j = function_participant;
j["name"] = util::path_to_url(
m_config.make_path_relative(function_participant.file()).string());
config().make_path_relative(function_participant.file()).string());
participant_id = common::to_id(function_participant.file_relative());
@@ -592,28 +595,26 @@ bool generator::is_participant_generated(common::id_t id) const
id) != generated_participants_.end();
}
void generator::generate(std::ostream &ostr) const
void generator::generate_diagram(nlohmann::json &parent) const
{
m_model.print();
model().print();
json_["name"] = m_model.name();
json_["diagram_type"] = "sequence";
if (m_config.using_namespace)
json_["using_namespace"] = m_config.using_namespace().to_string();
if (config().using_namespace)
parent["using_namespace"] = config().using_namespace().to_string();
if (m_config.participants_order.has_value) {
for (const auto &p : m_config.participants_order()) {
if (config().participants_order.has_value) {
for (const auto &p : config().participants_order()) {
LOG_DBG("Pregenerating participant {}", p);
generate_participant(json_, p);
generate_participant(parent, p);
}
}
for (const auto &sf : m_config.start_from()) {
for (const auto &sf : config().start_from()) {
if (sf.location_type == location_t::function) {
common::model::diagram_element::id_t start_from{0};
std::string start_from_str;
for (const auto &[k, v] : m_model.sequences()) {
const auto &caller = *m_model.participants().at(v.from());
for (const auto &[k, v] : model().sequences()) {
const auto &caller = *model().participants().at(v.from());
std::string vfrom = caller.full_name(false);
if (vfrom == sf.location) {
LOG_DBG("Found sequence diagram start point: {}", k);
@@ -634,7 +635,7 @@ void generator::generate(std::ostream &ostr) const
visited_participants;
const auto &from =
m_model.get_participant<model::function>(start_from);
model().get_participant<model::function>(start_from);
if (!from.has_value()) {
LOG_WARN("Failed to find participant {} for start_from "
@@ -655,12 +656,12 @@ void generator::generate(std::ostream &ostr) const
block_statements_stack_.push_back(std::ref(sequence));
generate_activity(
m_model.get_activity(start_from), visited_participants);
model().get_activity(start_from), visited_participants);
block_statements_stack_.pop_back();
if (from.value().type_name() == "method" ||
m_config.combine_free_functions_into_file_participants()) {
config().combine_free_functions_into_file_participants()) {
sequence["return_type"] = from.value().return_type();
}
@@ -673,8 +674,6 @@ void generator::generate(std::ostream &ostr) const
}
}
generate_metadata(json_);
ostr << json_;
parent.update(json_);
}
} // namespace clanguml::sequence_diagram::generators::json

View File

@@ -47,6 +47,8 @@ class generator : public common_generator<diagram_config, diagram_model> {
public:
generator(diagram_config &config, diagram_model &model);
using common_generator<diagram_config, diagram_model>::generate;
/**
* @brief Main generator method.
*
@@ -55,7 +57,7 @@ public:
*
* @param ostr Output stream.
*/
void generate(std::ostream &ostr) const override;
void generate_diagram(nlohmann::json &parent) const override;
/**
* @brief Generate sequence diagram message.

View File

@@ -45,8 +45,8 @@ std::string generator::render_name(std::string name) const
void generator::generate_call(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());
const auto &from = model().get_participant<model::participant>(m.from());
const auto &to = model().get_participant<model::participant>(m.to());
if (!from || !to) {
LOG_DBG("Skipping empty call from '{}' to '{}'", m.from(), m.to());
@@ -61,10 +61,10 @@ void generator::generate_call(const message &m, std::ostream &ostr) const
model::function::message_render_mode render_mode =
model::function::message_render_mode::full;
if (m_config.generate_method_arguments() ==
if (config().generate_method_arguments() ==
config::method_arguments::abbreviated)
render_mode = model::function::message_render_mode::abbreviated;
else if (m_config.generate_method_arguments() ==
else if (config().generate_method_arguments() ==
config::method_arguments::none)
render_mode = model::function::message_render_mode::no_arguments;
@@ -74,7 +74,7 @@ void generator::generate_call(const message &m, std::ostream &ostr) const
message =
fmt::format("{}{}{}", style, f.message_name(render_mode), style);
}
else if (m_config.combine_free_functions_into_file_participants()) {
else if (config().combine_free_functions_into_file_participants()) {
if (to.value().type_name() == "function") {
message = dynamic_cast<const model::function &>(to.value())
.message_name(render_mode);
@@ -95,7 +95,7 @@ void generator::generate_call(const message &m, std::ostream &ostr) const
ostr << to_alias;
if (m_config.generate_links) {
if (config().generate_links) {
common_generator<diagram_config, diagram_model>::generate_link(ostr, m);
}
@@ -119,8 +119,8 @@ 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 = m_model.get_participant<model::participant>(m.from());
const auto &to = m_model.get_participant<model::function>(m.to());
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()) {
const std::string from_alias = generate_alias(from.value());
@@ -130,7 +130,7 @@ void generator::generate_return(const message &m, std::ostream &ostr) const
<< common::generators::plantuml::to_plantuml(message_t::kReturn)
<< " " << from_alias;
if (m_config.generate_return_types()) {
if (config().generate_return_types()) {
ostr << " : //" << m.return_type() << "//";
}
@@ -144,7 +144,7 @@ void generator::generate_activity(const activity &a, std::ostream &ostr,
for (const auto &m : a.messages()) {
if (m.type() == message_t::kCall) {
const auto &to =
m_model.get_participant<model::participant>(m.to());
model().get_participant<model::participant>(m.to());
visited.push_back(m.from());
@@ -156,14 +156,14 @@ void generator::generate_activity(const activity &a, std::ostream &ostr,
ostr << "activate " << to_alias << std::endl;
if (m_model.sequences().find(m.to()) != m_model.sequences().end()) {
if (model().sequences().find(m.to()) != model().sequences().end()) {
if (std::find(visited.begin(), visited.end(), m.to()) ==
visited
.end()) { // break infinite recursion on recursive calls
LOG_DBG("Creating activity {} --> {} - missing sequence {}",
m.from(), m.to(), m.to());
generate_activity(
m_model.get_activity(m.to()), ostr, visited);
model().get_activity(m.to()), ostr, visited);
}
}
else
@@ -270,7 +270,7 @@ void generator::generate_activity(const activity &a, std::ostream &ostr,
void generator::generate_participant(
std::ostream &ostr, const std::string &name) const
{
auto p = m_model.get(name);
auto p = model().get(name);
if (!p.has_value()) {
LOG_WARN("Cannot find participant {} from `participants_order` option",
@@ -287,7 +287,7 @@ void generator::generate_participant(
common::id_t participant_id{0};
if (!force) {
for (const auto pid : m_model.active_participants()) {
for (const auto pid : model().active_participants()) {
if (pid == id) {
participant_id = pid;
break;
@@ -304,11 +304,12 @@ void generator::generate_participant(
return;
const auto &participant =
m_model.get_participant<model::participant>(participant_id).value();
model().get_participant<model::participant>(participant_id).value();
if (participant.type_name() == "method") {
const auto class_id =
m_model.get_participant<model::method>(participant_id)
model()
.get_participant<model::method>(participant_id)
.value()
.class_id();
@@ -316,16 +317,16 @@ void generator::generate_participant(
return;
const auto &class_participant =
m_model.get_participant<model::participant>(class_id).value();
model().get_participant<model::participant>(class_id).value();
print_debug(class_participant, ostr);
ostr << "participant \""
<< render_name(m_config.using_namespace().relative(
<< render_name(config().using_namespace().relative(
class_participant.full_name(false)))
<< "\" as " << class_participant.alias();
if (m_config.generate_links) {
if (config().generate_links) {
common_generator<diagram_config, diagram_model>::generate_link(
ostr, class_participant);
}
@@ -336,11 +337,12 @@ void generator::generate_participant(
}
else if ((participant.type_name() == "function" ||
participant.type_name() == "function_template") &&
m_config.combine_free_functions_into_file_participants()) {
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)
model()
.get_participant<model::function>(participant_id)
.value()
.file();
@@ -352,7 +354,7 @@ void generator::generate_participant(
return;
auto participant_name = util::path_to_url(std::filesystem::relative(
std::filesystem::path{file_path}, m_config.root_directory())
std::filesystem::path{file_path}, config().root_directory())
.string());
ostr << "participant \"" << render_name(participant_name) << "\" as "
@@ -366,11 +368,11 @@ void generator::generate_participant(
print_debug(participant, ostr);
ostr << "participant \""
<< m_config.using_namespace().relative(
<< config().using_namespace().relative(
participant.full_name(false))
<< "\" as " << participant.alias();
if (m_config.generate_links) {
if (config().generate_links) {
common_generator<diagram_config, diagram_model>::generate_link(
ostr, participant);
}
@@ -388,28 +390,36 @@ bool generator::is_participant_generated(common::id_t id) const
id) != generated_participants_.end();
}
void generator::generate(std::ostream &ostr) const
std::string generator::generate_alias(
const model::participant &participant) const
{
update_context();
if ((participant.type_name() == "function" ||
participant.type_name() == "function_template") &&
config().combine_free_functions_into_file_participants()) {
const auto file_id = common::to_id(participant.file());
m_model.print();
return fmt::format("C_{:022}", file_id);
}
ostr << "@startuml" << std::endl;
return participant.alias();
}
generate_plantuml_directives(ostr, m_config.puml().before);
void generator::generate_diagram(std::ostream &ostr) const
{
model().print();
if (m_config.participants_order.has_value) {
for (const auto &p : m_config.participants_order()) {
if (config().participants_order.has_value) {
for (const auto &p : config().participants_order()) {
LOG_DBG("Pregenerating participant {}", p);
generate_participant(ostr, p);
}
}
for (const auto &sf : m_config.start_from()) {
for (const auto &sf : config().start_from()) {
if (sf.location_type == location_t::function) {
common::model::diagram_element::id_t start_from{0};
for (const auto &[k, v] : m_model.sequences()) {
const auto &caller = *m_model.participants().at(v.from());
for (const auto &[k, v] : model().sequences()) {
const auto &caller = *model().participants().at(v.from());
std::string vfrom = caller.full_name(false);
if (vfrom == sf.location) {
LOG_DBG("Found sequence diagram start point: {}", k);
@@ -430,7 +440,7 @@ void generator::generate(std::ostream &ostr) const
visited_participants;
const auto &from =
m_model.get_participant<model::function>(start_from);
model().get_participant<model::function>(start_from);
if (!from.has_value()) {
LOG_WARN("Failed to find participant {} for start_from "
@@ -446,10 +456,10 @@ void generator::generate(std::ostream &ostr) const
model::function::message_render_mode render_mode =
model::function::message_render_mode::full;
if (m_config.generate_method_arguments() ==
if (config().generate_method_arguments() ==
config::method_arguments::abbreviated)
render_mode = model::function::message_render_mode::abbreviated;
else if (m_config.generate_method_arguments() ==
else if (config().generate_method_arguments() ==
config::method_arguments::none)
render_mode =
model::function::message_render_mode::no_arguments;
@@ -459,7 +469,7 @@ void generator::generate(std::ostream &ostr) const
// which method relates to the first activity for this 'start_from'
// condition
if (from.value().type_name() == "method" ||
m_config.combine_free_functions_into_file_participants()) {
config().combine_free_functions_into_file_participants()) {
ostr << "[->"
<< " " << from_alias << " : "
<< from.value().message_name(render_mode) << std::endl;
@@ -468,16 +478,16 @@ void generator::generate(std::ostream &ostr) const
ostr << "activate " << from_alias << std::endl;
generate_activity(
m_model.get_activity(start_from), ostr, visited_participants);
model().get_activity(start_from), ostr, visited_participants);
if (from.value().type_name() == "method" ||
m_config.combine_free_functions_into_file_participants()) {
config().combine_free_functions_into_file_participants()) {
if (!from.value().is_void()) {
ostr << "[<--"
<< " " << from_alias;
if (m_config.generate_return_types())
if (config().generate_return_types())
ostr << " : //" << from.value().return_type() << "//";
ostr << '\n';
@@ -491,25 +501,6 @@ void generator::generate(std::ostream &ostr) const
continue;
}
}
generate_plantuml_directives(ostr, m_config.puml().after);
generate_metadata(ostr);
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();
}
} // namespace clanguml::sequence_diagram::generators::plantuml

View File

@@ -49,6 +49,8 @@ class generator : public common_generator<diagram_config, diagram_model> {
public:
generator(diagram_config &config, diagram_model &model);
using common_generator<diagram_config, diagram_model>::generate;
/**
* @brief Main generator method.
*
@@ -57,7 +59,7 @@ public:
*
* @param ostr Output stream.
*/
void generate(std::ostream &ostr) const override;
void generate_diagram(std::ostream &ostr) const override;
/**
* @brief Generate sequence diagram message.

View File

@@ -93,6 +93,12 @@ void diagram::add_active_participant(common::model::diagram_element::id_t id)
active_participants_.emplace(id);
}
const activity &diagram::get_activity(
common::model::diagram_element::id_t id) const
{
return sequences_.at(id);
}
activity &diagram::get_activity(common::model::diagram_element::id_t id)
{
return sequences_.at(id);
@@ -173,6 +179,12 @@ std::set<common::model::diagram_element::id_t> &diagram::active_participants()
return active_participants_;
}
const std::set<common::model::diagram_element::id_t> &
diagram::active_participants() const
{
return active_participants_;
}
bool diagram::should_include(
const sequence_diagram::model::participant &p) const
{

View File

@@ -98,6 +98,14 @@ public:
*/
void add_active_participant(common::model::diagram_element::id_t id);
/**
* @brief Get reference to current activity of a participant
*
* @param id Participant id
* @return
*/
const activity &get_activity(common::model::diagram_element::id_t id) const;
/**
* @brief Get reference to current activity of a participant
*
@@ -179,6 +187,14 @@ public:
*/
std::set<common::model::diagram_element::id_t> &active_participants();
/**
* @brief Get all active participants in the diagram
*
* @return Set of all active participant ids
*/
const std::set<common::model::diagram_element::id_t> &
active_participants() const;
/**
* @brief Convert element full name to PlantUML alias.
*