Refactored sequence diagram model classes

This commit is contained in:
Bartek Kryza
2022-12-11 21:21:27 +01:00
parent 29b679b0a4
commit e5e7df43e8
12 changed files with 377 additions and 233 deletions

View File

@@ -74,6 +74,26 @@ std::string to_string(message_t r)
return "call"; return "call";
case message_t::kReturn: case message_t::kReturn:
return "return"; return "return";
case message_t::kIf:
return "if";
case message_t::kElse:
return "else";
case message_t::kElseIf:
return "else if";
case message_t::kIfEnd:
return "end if";
case message_t::kWhile:
return "while";
case message_t::kWhileEnd:
return "end while";
case message_t::kDo:
return "do";
case message_t::kDoEnd:
return "end do";
case message_t::kFor:
return "for";
case message_t::kForEnd:
return "end for";
default: default:
assert(false); assert(false);
return ""; return "";

View File

@@ -51,14 +51,15 @@ enum class message_t {
kDo, kDo,
kDoEnd, kDoEnd,
kFor, kFor,
kForEnd kForEnd,
kNone
}; };
std::string to_string(relationship_t r); std::string to_string(relationship_t r);
std::string to_string(access_t r); std::string to_string(access_t r);
std::string to_string(message_t r); std::string to_string(message_t m);
std::string to_string(diagram_t r); std::string to_string(diagram_t r);

View File

@@ -42,8 +42,6 @@ public:
clang::SourceManager &source_manager() const; clang::SourceManager &source_manager() const;
void finalize();
protected: protected:
void set_source_location(const clang::Decl &decl, void set_source_location(const clang::Decl &decl,
clanguml::common::model::source_location &element); clanguml::common::model::source_location &element);

View File

@@ -45,16 +45,16 @@ std::string generator::render_name(std::string name) const
void generator::generate_call(const message &m, std::ostream &ostr) 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 &from = m_model.get_participant<model::participant>(m.from());
const auto &to = m_model.get_participant<model::participant>(m.to); const auto &to = m_model.get_participant<model::participant>(m.to());
if (!from || !to) { if (!from || !to) {
LOG_DBG("Skipping empty call from '{}' to '{}'", m.from, m.to); LOG_DBG("Skipping empty call from '{}' to '{}'", m.from(), m.to());
return; return;
} }
generate_participant(ostr, m.from); generate_participant(ostr, m.from());
generate_participant(ostr, m.to); generate_participant(ostr, m.to());
std::string message; std::string message;
@@ -89,16 +89,16 @@ void generator::generate_call(const message &m, std::ostream &ostr) const
ostr << " : " << message << std::endl; ostr << " : " << message << std::endl;
LOG_DBG("Generated call '{}' from {} [{}] to {} [{}]", message, from, LOG_DBG("Generated call '{}' from {} [{}] to {} [{}]", message, from,
m.from, to, m.to); m.from(), to, m.to());
} }
void generator::generate_return(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 // Add return activity only for messages between different actors and
// only if the return type is different than void // only if the return type is different than void
const auto &from = m_model.get_participant<model::participant>(m.from); const auto &from = m_model.get_participant<model::participant>(m.from());
const auto &to = m_model.get_participant<model::function>(m.to); const auto &to = m_model.get_participant<model::function>(m.to());
if ((m.from != m.to) && !to.value().is_void()) { if ((m.from() != m.to()) && !to.value().is_void()) {
const std::string from_alias = generate_alias(from.value()); const std::string from_alias = generate_alias(from.value());
const std::string to_alias = generate_alias(to.value()); const std::string to_alias = generate_alias(to.value());
@@ -112,15 +112,16 @@ void generator::generate_return(const message &m, std::ostream &ostr) const
void generator::generate_activity(const activity &a, std::ostream &ostr, void generator::generate_activity(const activity &a, std::ostream &ostr,
std::vector<common::model::diagram_element::id_t> &visited) const std::vector<common::model::diagram_element::id_t> &visited) const
{ {
for (const auto &m : a.messages) { for (const auto &m : a.messages()) {
if (m.type == message_t::kCall) { if (m.type() == message_t::kCall) {
const auto &to = m_model.get_participant<model::participant>(m.to); const auto &to =
m_model.get_participant<model::participant>(m.to());
if (!to) if (!to)
continue; continue;
visited.push_back(m.from); visited.push_back(m.from());
LOG_DBG("Generating message {} --> {}", m.from, m.to); LOG_DBG("Generating message {} --> {}", m.from(), m.to());
generate_call(m, ostr); generate_call(m, ostr);
@@ -128,18 +129,19 @@ void generator::generate_activity(const activity &a, std::ostream &ostr,
ostr << "activate " << to_alias << std::endl; ostr << "activate " << to_alias << std::endl;
if (m_model.sequences.find(m.to) != m_model.sequences.end()) { if (m_model.sequences().find(m.to()) != m_model.sequences().end()) {
if (std::find(visited.begin(), visited.end(), m.to) == if (std::find(visited.begin(), visited.end(), m.to()) ==
visited visited
.end()) { // break infinite recursion on recursive calls .end()) { // break infinite recursion on recursive calls
LOG_DBG("Creating activity {} --> {} - missing sequence {}", LOG_DBG("Creating activity {} --> {} - missing sequence {}",
m.from, m.to, m.to); m.from(), m.to(), m.to());
generate_activity(m_model.sequences[m.to], ostr, visited); generate_activity(
m_model.get_activity(m.to()), ostr, visited);
} }
} }
else else
LOG_DBG("Skipping activity {} --> {} - missing sequence {}", LOG_DBG("Skipping activity {} --> {} - missing sequence {}",
m.from, m.to, m.to); m.from(), m.to(), m.to());
generate_return(m, ostr); generate_return(m, ostr);
@@ -147,34 +149,34 @@ void generator::generate_activity(const activity &a, std::ostream &ostr,
visited.pop_back(); visited.pop_back();
} }
else if (m.type == message_t::kIf) { else if (m.type() == message_t::kIf) {
ostr << "alt\n"; ostr << "alt\n";
} }
else if (m.type == message_t::kElseIf) { else if (m.type() == message_t::kElseIf) {
ostr << "else\n"; ostr << "else\n";
} }
else if (m.type == message_t::kElse) { else if (m.type() == message_t::kElse) {
ostr << "else\n"; ostr << "else\n";
} }
else if (m.type == message_t::kIfEnd) { else if (m.type() == message_t::kIfEnd) {
ostr << "end\n"; ostr << "end\n";
} }
else if (m.type == message_t::kWhile) { else if (m.type() == message_t::kWhile) {
ostr << "loop\n"; ostr << "loop\n";
} }
else if (m.type == message_t::kWhileEnd) { else if (m.type() == message_t::kWhileEnd) {
ostr << "end\n"; ostr << "end\n";
} }
else if (m.type == message_t::kFor) { else if (m.type() == message_t::kFor) {
ostr << "loop\n"; ostr << "loop\n";
} }
else if (m.type == message_t::kForEnd) { else if (m.type() == message_t::kForEnd) {
ostr << "end\n"; ostr << "end\n";
} }
else if (m.type == message_t::kDo) { else if (m.type() == message_t::kDo) {
ostr << "loop\n"; ostr << "loop\n";
} }
else if (m.type == message_t::kDoEnd) { else if (m.type() == message_t::kDoEnd) {
ostr << "end\n"; ostr << "end\n";
} }
} }
@@ -182,7 +184,7 @@ void generator::generate_activity(const activity &a, std::ostream &ostr,
void generator::generate_participant(std::ostream &ostr, common::id_t id) const void generator::generate_participant(std::ostream &ostr, common::id_t id) const
{ {
for (const auto participant_id : m_model.active_participants_) { for (const auto participant_id : m_model.active_participants()) {
if (participant_id != id) if (participant_id != id)
continue; continue;
@@ -287,8 +289,8 @@ void generator::generate(std::ostream &ostr) const
for (const auto &sf : m_config.start_from()) { for (const auto &sf : m_config.start_from()) {
if (sf.location_type == source_location::location_t::function) { if (sf.location_type == source_location::location_t::function) {
common::model::diagram_element::id_t start_from; common::model::diagram_element::id_t start_from;
for (const auto &[k, v] : m_model.sequences) { for (const auto &[k, v] : m_model.sequences()) {
const auto &caller = *m_model.participants.at(v.from); const auto &caller = *m_model.participants().at(v.from());
std::string vfrom = caller.full_name(false); std::string vfrom = caller.full_name(false);
if (vfrom == sf.location) { if (vfrom == sf.location) {
LOG_DBG("Found sequence diagram start point: {}", k); LOG_DBG("Found sequence diagram start point: {}", k);
@@ -327,7 +329,7 @@ void generator::generate(std::ostream &ostr) const
ostr << "activate " << from_alias << std::endl; ostr << "activate " << from_alias << std::endl;
generate_activity( generate_activity(
m_model.sequences[start_from], ostr, visited_participants); m_model.get_activity(start_from), ostr, visited_participants);
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()) {

View File

@@ -20,4 +20,19 @@
namespace clanguml::sequence_diagram::model { namespace clanguml::sequence_diagram::model {
activity::activity(common::model::diagram_element::id_t id)
: from_{id}
{
}
void activity::add_message(message m) { messages_.emplace_back(std::move(m)); }
std::vector<message> &activity::messages() { return messages_; }
const std::vector<message> &activity::messages() const { return messages_; }
void activity::set_from(common::model::diagram_element::id_t f) { from_ = f; }
common::model::diagram_element::id_t activity::from() const { return from_; }
} }

View File

@@ -25,9 +25,23 @@
namespace clanguml::sequence_diagram::model { namespace clanguml::sequence_diagram::model {
struct activity { class activity {
common::model::diagram_element::id_t from; public:
std::vector<message> messages; activity(common::model::diagram_element::id_t id);
void add_message(message m);
std::vector<message> &messages();
const std::vector<message> &messages() const;
void set_from(common::model::diagram_element::id_t f);
common::model::diagram_element::id_t from() const;
private:
common::model::diagram_element::id_t from_;
std::vector<message> messages_;
}; };
} }

View File

@@ -31,7 +31,7 @@ common::model::diagram_t diagram::type() const
common::optional_ref<common::model::diagram_element> diagram::get( common::optional_ref<common::model::diagram_element> diagram::get(
const std::string &full_name) const const std::string &full_name) const
{ {
for (const auto &[id, participant] : participants) { for (const auto &[id, participant] : participants_) {
if (participant->full_name(false) == full_name) if (participant->full_name(false) == full_name)
return {*participant}; return {*participant};
} }
@@ -42,8 +42,8 @@ common::optional_ref<common::model::diagram_element> diagram::get(
common::optional_ref<common::model::diagram_element> diagram::get( common::optional_ref<common::model::diagram_element> diagram::get(
const common::model::diagram_element::id_t id) const const common::model::diagram_element::id_t id) const
{ {
if (participants.find(id) != participants.end()) if (participants_.find(id) != participants_.end())
return {*participants.at(id)}; return {*participants_.at(id)};
return {}; return {};
} }
@@ -62,7 +62,7 @@ inja::json diagram::context() const
inja::json::array_t elements{}; inja::json::array_t elements{};
// Add classes // Add classes
for (const auto &[id, p] : participants) { for (const auto &[id, p] : participants_) {
elements.emplace_back(p->context()); elements.emplace_back(p->context());
} }
@@ -71,46 +71,29 @@ inja::json diagram::context() const
return ctx; return ctx;
} }
void diagram::print() const void diagram::add_participant(std::unique_ptr<participant> p)
{ {
LOG_DBG(" --- Participants ---"); const auto participant_id = p->id();
for (const auto &[id, participant] : participants) {
LOG_DBG("{} - {}", id, participant->to_string()); if (participants_.find(participant_id) == participants_.end()) {
LOG_DBG("Adding '{}' participant: {}, {} [{}]", p->type_name(),
p->full_name(false), p->id(),
p->type_name() == "method"
? dynamic_cast<method *>(p.get())->method_name()
: "");
participants_.emplace(participant_id, std::move(p));
} }
}
LOG_DBG(" --- Activities ---"); void diagram::add_active_participant(common::model::diagram_element::id_t id)
for (const auto &[from_id, act] : sequences) { {
active_participants_.emplace(id);
}
LOG_DBG("Sequence id={}:", from_id); activity &diagram::get_activity(common::model::diagram_element::id_t id)
{
const auto &from_activity = *(participants.at(from_id)); return sequences_.at(id);
LOG_DBG(" Activity id={}, from={}:", act.from,
from_activity.full_name(false));
for (const auto &message : act.messages) {
if (participants.find(message.from) == participants.end())
continue;
const auto &from_participant = *participants.at(message.from);
if (participants.find(message.to) == participants.end()) {
LOG_DBG(" Message from={}, from_id={}, "
"to={}, to_id={}, name={}",
from_participant.full_name(false), from_participant.id(),
"__UNRESOLVABLE_ID__", message.to, message.message_name);
}
else {
const auto &to_participant = *participants.at(message.to);
LOG_DBG(" Message from={}, from_id={}, "
"to={}, to_id={}, name={}",
from_participant.full_name(false), from_participant.id(),
to_participant.full_name(false), to_participant.id(),
message.message_name);
}
}
}
} }
void diagram::add_for_stmt( void diagram::add_for_stmt(
@@ -158,17 +141,12 @@ void diagram::add_loop_stmt(
if (current_caller_id == 0) if (current_caller_id == 0)
return; return;
if (sequences.find(current_caller_id) == sequences.end()) { if (sequences_.find(current_caller_id) == sequences_.end()) {
activity a; activity a{current_caller_id};
a.from = current_caller_id; sequences_.insert({current_caller_id, std::move(a)});
sequences.insert({current_caller_id, std::move(a)});
} }
message m; get_activity(current_caller_id).add_message({type, current_caller_id});
m.from = current_caller_id;
m.type = type;
sequences[current_caller_id].messages.emplace_back(std::move(m));
} }
void diagram::end_loop_stmt( void diagram::end_loop_stmt(
@@ -180,9 +158,7 @@ void diagram::end_loop_stmt(
if (current_caller_id == 0) if (current_caller_id == 0)
return; return;
message m; message m{type, current_caller_id};
m.from = current_caller_id;
m.type = type;
message_t loop_type = message_t::kWhile; message_t loop_type = message_t::kWhile;
@@ -191,10 +167,10 @@ void diagram::end_loop_stmt(
else if (type == message_t::kDoEnd) else if (type == message_t::kDoEnd)
loop_type = message_t::kDo; loop_type = message_t::kDo;
if (sequences.find(current_caller_id) != sequences.end()) { if (sequences_.find(current_caller_id) != sequences_.end()) {
auto &current_messages = sequences[current_caller_id].messages; auto &current_messages = get_activity(current_caller_id).messages();
if (current_messages.back().type == loop_type) { if (current_messages.back().type() == loop_type) {
current_messages.pop_back(); current_messages.pop_back();
} }
else { else {
@@ -209,16 +185,12 @@ void diagram::add_if_stmt(
{ {
using clanguml::common::model::message_t; using clanguml::common::model::message_t;
if (sequences.find(current_caller_id) == sequences.end()) { if (sequences_.find(current_caller_id) == sequences_.end()) {
activity a; activity a{current_caller_id};
a.from = current_caller_id; sequences_.insert({current_caller_id, std::move(a)});
sequences.insert({current_caller_id, std::move(a)});
} }
message m;
m.from = current_caller_id;
m.type = type;
sequences[current_caller_id].messages.emplace_back(std::move(m)); get_activity(current_caller_id).add_message({type, current_caller_id});
} }
void diagram::end_if_stmt( void diagram::end_if_stmt(
@@ -227,22 +199,20 @@ void diagram::end_if_stmt(
{ {
using clanguml::common::model::message_t; using clanguml::common::model::message_t;
message m; message m{message_t::kIfEnd, current_caller_id};
m.from = current_caller_id;
m.type = message_t::kIfEnd;
if (sequences.find(current_caller_id) != sequences.end()) { if (sequences_.find(current_caller_id) != sequences_.end()) {
auto &current_messages = sequences[current_caller_id].messages; auto &current_messages = get_activity(current_caller_id).messages();
// Remove the if/else messages if there were no calls // Remove the if/else messages if there were no calls
// added to the diagram between them // added to the diagram between them
auto last_if_it = auto last_if_it =
std::find_if(current_messages.rbegin(), current_messages.rend(), std::find_if(current_messages.rbegin(), current_messages.rend(),
[](const message &m) { return m.type == message_t::kIf; }); [](const message &m) { return m.type() == message_t::kIf; });
bool last_if_block_is_empty = bool last_if_block_is_empty =
std::none_of(current_messages.rbegin(), last_if_it, std::none_of(current_messages.rbegin(), last_if_it,
[](const message &m) { return m.type == message_t::kCall; }); [](const message &m) { return m.type() == message_t::kCall; });
if (!last_if_block_is_empty) { if (!last_if_block_is_empty) {
current_messages.emplace_back(std::move(m)); current_messages.emplace_back(std::move(m));
@@ -254,6 +224,88 @@ void diagram::end_if_stmt(
} }
} }
bool diagram::started() const { return started_; }
void diagram::started(bool s) { started_ = s; }
std::map<common::model::diagram_element::id_t, activity> &diagram::sequences()
{
return sequences_;
}
const std::map<common::model::diagram_element::id_t, activity> &
diagram::sequences() const
{
return sequences_;
}
std::map<common::model::diagram_element::id_t, std::unique_ptr<participant>> &
diagram::participants()
{
return participants_;
}
const std::map<common::model::diagram_element::id_t,
std::unique_ptr<participant>> &
diagram::participants() const
{
return participants_;
}
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_;
};
void diagram::print() const
{
LOG_DBG(" --- Participants ---");
for (const auto &[id, participant] : participants_) {
LOG_DBG("{} - {}", id, participant->to_string());
}
LOG_DBG(" --- Activities ---");
for (const auto &[from_id, act] : sequences_) {
LOG_DBG("Sequence id={}:", from_id);
const auto &from_activity = *(participants_.at(from_id));
LOG_DBG(" Activity id={}, from={}:", act.from(),
from_activity.full_name(false));
for (const auto &message : act.messages()) {
if (participants_.find(message.from()) == participants_.end())
continue;
const auto &from_participant = *participants_.at(message.from());
if (participants_.find(message.to()) == participants_.end()) {
LOG_DBG(" Message from={}, from_id={}, "
"to={}, to_id={}, name={}, type={}",
from_participant.full_name(false), from_participant.id(),
"__UNRESOLVABLE_ID__", message.to(), message.message_name(),
to_string(message.type()));
}
else {
const auto &to_participant = *participants_.at(message.to());
LOG_DBG(" Message from={}, from_id={}, "
"to={}, to_id={}, name={}, type={}",
from_participant.full_name(false), from_participant.id(),
to_participant.full_name(false), to_participant.id(),
message.message_name(), to_string(message.type()));
}
}
}
}
} }
namespace clanguml::common::model { namespace clanguml::common::model {

View File

@@ -50,81 +50,84 @@ public:
void print() const; void print() const;
bool started{false};
template <typename T> template <typename T>
common::optional_ref<T> get_participant( common::optional_ref<T> get_participant(
common::model::diagram_element::id_t id) common::model::diagram_element::id_t id)
{ {
if (participants.find(id) == participants.end()) { if (participants_.find(id) == participants_.end()) {
return {}; return {};
} }
return common::optional_ref<T>( return common::optional_ref<T>(
static_cast<T *>(participants.at(id).get())); static_cast<T *>(participants_.at(id).get()));
} }
template <typename T> template <typename T>
const common::optional_ref<T> get_participant( const common::optional_ref<T> get_participant(
common::model::diagram_element::id_t id) const common::model::diagram_element::id_t id) const
{ {
if (participants.find(id) == participants.end()) { if (participants_.find(id) == participants_.end()) {
return {}; return {};
} }
return common::optional_ref<T>( return common::optional_ref<T>(
static_cast<T *>(participants.at(id).get())); static_cast<T *>(participants_.at(id).get()));
} }
void add_participant(std::unique_ptr<participant> p) void add_participant(std::unique_ptr<participant> p);
{
const auto participant_id = p->id();
if (participants.find(participant_id) == participants.end()) { void add_active_participant(common::model::diagram_element::id_t id);
LOG_DBG("Adding '{}' participant: {}, {} [{}]", p->type_name(),
p->full_name(false), p->id(),
p->type_name() == "method"
? dynamic_cast<method *>(p.get())->method_name()
: "");
participants.emplace(participant_id, std::move(p)); activity& get_activity(common::model::diagram_element::id_t id);
}
}
void add_active_participant(common::model::diagram_element::id_t id) void add_if_stmt(common::model::diagram_element::id_t current_caller_id,
{ common::model::message_t type);
active_participants_.emplace(id); void end_if_stmt(common::model::diagram_element::id_t current_caller_id,
} common::model::message_t type);
std::map<common::model::diagram_element::id_t, activity> sequences; void add_loop_stmt(common::model::diagram_element::id_t current_caller_id,
common::model::message_t type);
void end_loop_stmt(common::model::diagram_element::id_t current_caller_id,
common::model::message_t type);
void add_while_stmt(common::model::diagram_element::id_t i);
void end_while_stmt(common::model::diagram_element::id_t i);
void add_do_stmt(common::model::diagram_element::id_t i);
void end_do_stmt(common::model::diagram_element::id_t i);
void add_for_stmt(common::model::diagram_element::id_t i);
void end_for_stmt(common::model::diagram_element::id_t i);
bool started() const;
void started(bool s);
std::map<common::model::diagram_element::id_t, activity> &sequences();
const std::map<common::model::diagram_element::id_t, activity> &
sequences() const;
std::map<common::model::diagram_element::id_t, std::unique_ptr<participant>> std::map<common::model::diagram_element::id_t, std::unique_ptr<participant>>
participants; &participants();
const std::map<common::model::diagram_element::id_t,
std::unique_ptr<participant>> &
participants() const;
std::set<common::model::diagram_element::id_t> &active_participants();
const std::set<common::model::diagram_element::id_t> &
active_participants() const;
private:
bool started_{false};
std::map<common::model::diagram_element::id_t, activity> sequences_;
std::map<common::model::diagram_element::id_t, std::unique_ptr<participant>>
participants_;
std::set<common::model::diagram_element::id_t> active_participants_; std::set<common::model::diagram_element::id_t> active_participants_;
void add_if_stmt(
const common::model::diagram_element::id_t current_caller_id,
common::model::message_t type);
void end_if_stmt(
const common::model::diagram_element::id_t current_caller_id,
common::model::message_t type);
void add_loop_stmt(
const common::model::diagram_element::id_t current_caller_id,
common::model::message_t type);
void end_loop_stmt(
const common::model::diagram_element::id_t current_caller_id,
common::model::message_t type);
void add_while_stmt(const common::model::diagram_element::id_t i);
void end_while_stmt(const common::model::diagram_element::id_t i);
void add_do_stmt(const common::model::diagram_element::id_t i);
void end_do_stmt(const common::model::diagram_element::id_t i);
void add_for_stmt(const common::model::diagram_element::id_t i);
void end_for_stmt(const common::model::diagram_element::id_t i);
}; };
} }

View File

@@ -20,4 +20,34 @@
namespace clanguml::sequence_diagram::model { namespace clanguml::sequence_diagram::model {
message::message(
common::model::message_t type, common::model::diagram_element::id_t from)
: type_{type}
, from_{from}
{
}
void message::set_type(common::model::message_t t) { type_ = t; }
common::model::message_t message::type() const { return type_; }
void message::set_from(common::model::diagram_element::id_t f) { from_ = f; }
common::model::diagram_element::id_t message::from() const { return from_; }
void message::set_to(common::model::diagram_element::id_t t) { to_ = t; }
common::model::diagram_element::id_t message::to() const { return to_; }
void message::set_message_name(std::string name)
{
message_name_ = std::move(name);
}
const std::string &message::message_name() const { return message_name_; }
void message::set_return_type(std::string t) { return_type_ = std::move(t); }
const std::string &message::return_type() const { return return_type_; }
} }

View File

@@ -25,22 +25,40 @@
namespace clanguml::sequence_diagram::model { namespace clanguml::sequence_diagram::model {
struct message : public common::model::diagram_element { class message : public common::model::diagram_element {
message() public:
: from{} message() = default;
, to{}
, message_name{}
, return_type{}
{
}
common::model::message_t type; message(common::model::message_t type,
common::model::diagram_element::id_t from; common::model::diagram_element::id_t from);
common::model::diagram_element::id_t to;
std::string message_name; void set_type(common::model::message_t t);
common::model::message_t type() const;
std::string return_type; void set_from(common::model::diagram_element::id_t f);
common::model::diagram_element::id_t from() const;
void set_to(common::model::diagram_element::id_t t);
common::model::diagram_element::id_t to() const;
void set_message_name(std::string name);
const std::string &message_name() const;
void set_return_type(std::string t);
const std::string &return_type() const;
private:
common::model::message_t type_{common::model::message_t::kNone};
common::model::diagram_element::id_t from_{};
common::model::diagram_element::id_t to_{};
// This is only for better verbose messages, we cannot rely on this
// always
std::string message_name_{};
std::string return_type_{};
}; };
} }

View File

@@ -571,12 +571,9 @@ bool translation_unit_visitor::TraverseCompoundStmt(clang::CompoundStmt *stmt)
const auto current_caller_id = context().caller_id(); const auto current_caller_id = context().caller_id();
if (current_caller_id) { if (current_caller_id) {
message m; diagram()
m.from = current_caller_id; .get_activity(current_caller_id)
m.type = message_t::kElse; .add_message({message_t::kElse, current_caller_id});
diagram().sequences[current_caller_id].messages.emplace_back(
std::move(m));
} }
} }
} }
@@ -585,12 +582,9 @@ bool translation_unit_visitor::TraverseCompoundStmt(clang::CompoundStmt *stmt)
const auto current_caller_id = context().caller_id(); const auto current_caller_id = context().caller_id();
if (current_caller_id) { if (current_caller_id) {
message m; diagram()
m.from = current_caller_id; .get_activity(current_caller_id)
m.type = message_t::kElse; .add_message({message_t::kElse, current_caller_id});
diagram().sequences[current_caller_id].messages.emplace_back(
std::move(m));
} }
} }
} }
@@ -763,9 +757,7 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
expr->getBeginLoc().printToString(source_manager()), expr->getBeginLoc().printToString(source_manager()),
context().caller_id()); context().caller_id());
message m; message m{message_t::kCall, context().caller_id()};
m.type = message_t::kCall;
m.from = context().caller_id();
set_source_location(*expr, m); set_source_location(*expr, m);
@@ -774,7 +766,7 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
// Unless the lambda is declared in a function or method call // Unless the lambda is declared in a function or method call
if (context().lambda_caller_id() != 0) { if (context().lambda_caller_id() != 0) {
if (context().current_function_call_expr_ == nullptr) { if (context().current_function_call_expr_ == nullptr) {
m.from = context().lambda_caller_id(); m.set_from(context().lambda_caller_id());
} }
else { else {
LOG_DBG("Current lambda declaration is passed to a method or " LOG_DBG("Current lambda declaration is passed to a method or "
@@ -847,24 +839,21 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
// const auto &return_type = // const auto &return_type =
// function_call_expr->getCallReturnType(current_ast_context); // function_call_expr->getCallReturnType(current_ast_context);
// m.return_type = return_type.getAsString(); // m.return_type = return_type.getAsString();
m.return_type = "";
if (m.from > 0 && m.to > 0) { if (m.from() > 0 && m.to() > 0) {
if (diagram().sequences.find(m.from) == diagram().sequences.end()) { if (diagram().sequences().find(m.from()) ==
activity a; diagram().sequences().end()) {
a.from = m.from; activity a{m.from()};
diagram().sequences.insert({m.from, std::move(a)}); diagram().sequences().insert({m.from(), std::move(a)});
} }
diagram().add_active_participant(m.from); diagram().add_active_participant(m.from());
diagram().add_active_participant(m.to); diagram().add_active_participant(m.to());
LOG_DBG("Found call {} from {} [{}] to {} [{}] ", m.message_name, LOG_DBG("Found call {} from {} [{}] to {} [{}] ", m.message_name(),
m.from, m.from, m.to, m.to); m.from(), m.from(), m.to(), m.to());
diagram().sequences[m.from].messages.emplace_back(std::move(m)); diagram().get_activity(m.from()).add_message(std::move(m));
assert(!diagram().sequences.empty());
} }
return true; return true;
@@ -876,6 +865,11 @@ bool translation_unit_visitor::process_operator_call_expression(
if (operator_call_expr->getCalleeDecl() == nullptr) if (operator_call_expr->getCalleeDecl() == nullptr)
return false; return false;
// For now we only handle call overloaded operators
if (operator_call_expr->getOperator() !=
clang::OverloadedOperatorKind::OO_Call)
return false;
LOG_DBG("Operator '{}' call expression to {} at {}", LOG_DBG("Operator '{}' call expression to {} at {}",
getOperatorSpelling(operator_call_expr->getOperator()), getOperatorSpelling(operator_call_expr->getOperator()),
operator_call_expr->getCalleeDecl()->getID(), operator_call_expr->getCalleeDecl()->getID(),
@@ -883,14 +877,14 @@ bool translation_unit_visitor::process_operator_call_expression(
auto maybe_id = get_unique_id(operator_call_expr->getCalleeDecl()->getID()); auto maybe_id = get_unique_id(operator_call_expr->getCalleeDecl()->getID());
if (maybe_id.has_value()) { if (maybe_id.has_value()) {
m.to = maybe_id.value(); m.set_to(maybe_id.value());
} }
else { else {
m.to = operator_call_expr->getCalleeDecl()->getID(); m.set_to(operator_call_expr->getCalleeDecl()->getID());
} }
m.message_name = fmt::format( m.set_message_name(fmt::format(
"operator{}", getOperatorSpelling(operator_call_expr->getOperator())); "operator{}", getOperatorSpelling(operator_call_expr->getOperator())));
return true; return true;
} }
@@ -912,15 +906,13 @@ bool translation_unit_visitor::process_class_method_call_expression(
diagram().should_include(callee_decl->getQualifiedNameAsString()))) diagram().should_include(callee_decl->getQualifiedNameAsString())))
return false; return false;
m.to = method_decl->getID(); m.set_to(method_decl->getID());
m.set_message_name(method_decl->getNameAsString());
m.message_name = method_decl->getNameAsString(); m.set_return_type(
m.return_type =
method_call_expr->getCallReturnType(*context().get_ast_context()) method_call_expr->getCallReturnType(*context().get_ast_context())
.getAsString(); .getAsString());
LOG_DBG("Set callee method id {} for method name {}", m.to, LOG_DBG("Set callee method id {} for method name {}", m.to(),
method_decl->getQualifiedNameAsString()); method_decl->getQualifiedNameAsString());
diagram().add_active_participant(method_decl->getID()); diagram().add_active_participant(method_decl->getID());
@@ -951,13 +943,13 @@ bool translation_unit_visitor::process_class_template_method_call_expression(
get_participant(template_declaration).value().full_name(false) + get_participant(template_declaration).value().full_name(false) +
"::" + dependent_member_callee->getMember().getAsString(); "::" + dependent_member_callee->getMember().getAsString();
for (const auto &[id, p] : diagram().participants) { for (const auto &[id, p] : diagram().participants()) {
const auto p_full_name = p->full_name(false); const auto p_full_name = p->full_name(false);
if (p_full_name.find(callee_method_full_name + "(") == 0) { if (p_full_name.find(callee_method_full_name + "(") == 0) {
// TODO: This selects the first matching template method // TODO: This selects the first matching template method
// without considering arguments!!! // without considering arguments!!!
m.to = id; m.set_to(id);
break; break;
} }
} }
@@ -975,12 +967,12 @@ bool translation_unit_visitor::process_class_template_method_call_expression(
.full_name(false) + .full_name(false) +
"::" + dependent_member_callee->getMember().getAsString(); "::" + dependent_member_callee->getMember().getAsString();
for (const auto &[id, p] : diagram().participants) { for (const auto &[id, p] : diagram().participants()) {
const auto p_full_name = p->full_name(false); const auto p_full_name = p->full_name(false);
if (p_full_name.find(callee_method_full_name + "(") == 0) { if (p_full_name.find(callee_method_full_name + "(") == 0) {
// TODO: This selects the first matching template method // TODO: This selects the first matching template method
// without considering arguments!!! // without considering arguments!!!
m.to = id; m.set_to(id);
break; break;
} }
} }
@@ -989,8 +981,7 @@ bool translation_unit_visitor::process_class_template_method_call_expression(
return false; return false;
} }
m.message_name = dependent_member_callee->getMember().getAsString(); m.set_message_name(dependent_member_callee->getMember().getAsString());
m.return_type = "";
if (get_unique_id(template_declaration->getID())) if (get_unique_id(template_declaration->getID()))
diagram().add_active_participant( diagram().add_active_participant(
@@ -1027,14 +1018,14 @@ bool translation_unit_visitor::process_function_call_expression(
if (!get_unique_id(callee_function->getID()).has_value()) { if (!get_unique_id(callee_function->getID()).has_value()) {
// This is hopefully not an interesting call... // This is hopefully not an interesting call...
m.to = callee_function->getID(); m.set_to(callee_function->getID());
} }
else { else {
m.to = get_unique_id(callee_function->getID()).value(); m.set_to(get_unique_id(callee_function->getID()).value());
} }
auto message_name = callee_name; auto message_name = callee_name;
m.message_name = message_name.substr(0, message_name.size() - 2); m.set_message_name(message_name.substr(0, message_name.size() - 2));
if (f_ptr) if (f_ptr)
diagram().add_participant(std::move(f_ptr)); diagram().add_participant(std::move(f_ptr));
@@ -1057,9 +1048,9 @@ bool translation_unit_visitor::process_unresolved_lookup_call_expression(
clang::dyn_cast_or_null<clang::FunctionTemplateDecl>(decl); clang::dyn_cast_or_null<clang::FunctionTemplateDecl>(decl);
if (!get_unique_id(ftd->getID()).has_value()) if (!get_unique_id(ftd->getID()).has_value())
m.to = ftd->getID(); m.set_to(ftd->getID());
else { else {
m.to = get_unique_id(ftd->getID()).value(); m.set_to(get_unique_id(ftd->getID()).value());
} }
break; break;
@@ -1878,7 +1869,7 @@ translation_unit_visitor::build_template_instantiation(
int best_match{}; int best_match{};
common::model::diagram_element::id_t best_match_id{0}; common::model::diagram_element::id_t best_match_id{0};
for (const auto &[id, c] : diagram().participants) { for (const auto &[id, c] : diagram().participants()) {
const auto *participant_as_class = const auto *participant_as_class =
dynamic_cast<model::class_ *>(c.get()); dynamic_cast<model::class_ *>(c.get());
if ((participant_as_class != nullptr) && if ((participant_as_class != nullptr) &&
@@ -1981,9 +1972,9 @@ std::string translation_unit_visitor::make_lambda_name(
void translation_unit_visitor::finalize() void translation_unit_visitor::finalize()
{ {
decltype(diagram().active_participants_) active_participants_unique; std::set<common::model::diagram_element::id_t> active_participants_unique;
for (auto id : diagram().active_participants_) { for (auto id : diagram().active_participants()) {
if (local_ast_id_map_.find(id) != local_ast_id_map_.end()) { if (local_ast_id_map_.find(id) != local_ast_id_map_.end()) {
active_participants_unique.emplace(local_ast_id_map_.at(id)); active_participants_unique.emplace(local_ast_id_map_.at(id));
} }
@@ -1992,12 +1983,12 @@ void translation_unit_visitor::finalize()
} }
} }
diagram().active_participants_ = std::move(active_participants_unique); diagram().active_participants() = std::move(active_participants_unique);
for (auto &[id, activity] : diagram().sequences) { for (auto &[id, activity] : diagram().sequences()) {
for (auto &m : activity.messages) { for (auto &m : activity.messages()) {
if (local_ast_id_map_.find(m.to) != local_ast_id_map_.end()) { if (local_ast_id_map_.find(m.to()) != local_ast_id_map_.end()) {
m.to = local_ast_id_map_.at(m.to); m.set_to(local_ast_id_map_.at(m.to()));
} }
} }
} }

View File

@@ -116,22 +116,22 @@ public:
common::optional_ref<T> get_participant( common::optional_ref<T> get_participant(
const common::model::diagram_element::id_t id) const common::model::diagram_element::id_t id)
{ {
if (diagram().participants.find(id) == diagram().participants.end()) if (diagram().participants().find(id) == diagram().participants().end())
return {}; return {};
return common::optional_ref<T>( return common::optional_ref<T>(
*(static_cast<T *>(diagram().participants.at(id).get()))); *(static_cast<T *>(diagram().participants().at(id).get())));
} }
template <typename T = model::participant> template <typename T = model::participant>
const common::optional_ref<T> get_participant( const common::optional_ref<T> get_participant(
const common::model::diagram_element::id_t id) const const common::model::diagram_element::id_t id) const
{ {
if (diagram().participants.find(id) == diagram().participants.end()) if (diagram().participants().find(id) == diagram().participants().end())
return {}; return {};
return common::optional_ref<T>( return common::optional_ref<T>(
*(static_cast<T *>(diagram().participants.at(id).get()))); *(static_cast<T *>(diagram().participants().at(id).get())));
} }
/// Store the mapping from local clang entity id (obtained using /// Store the mapping from local clang entity id (obtained using