Added support for constructors and operators in sequence diagrams

This commit is contained in:
Bartek Kryza
2023-06-29 00:35:36 +02:00
parent 9e7b147244
commit 213483dd3b
10 changed files with 337 additions and 14 deletions

View File

@@ -488,6 +488,41 @@ bool translation_unit_visitor::TraverseCXXOperatorCallExpr(
return true;
}
bool translation_unit_visitor::TraverseCXXTemporaryObjectExpr(
clang::CXXTemporaryObjectExpr *expr)
{
context().enter_callexpr(expr);
RecursiveASTVisitor<
translation_unit_visitor>::TraverseCXXTemporaryObjectExpr(expr);
translation_unit_visitor::VisitCXXConstructExpr(
clang::dyn_cast<clang::CXXConstructExpr>(expr));
context().leave_callexpr();
pop_message_to_diagram(expr);
return true;
}
bool translation_unit_visitor::TraverseCXXConstructExpr(
clang::CXXConstructExpr *expr)
{
context().enter_callexpr(expr);
RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXConstructExpr(
expr);
translation_unit_visitor::VisitCXXConstructExpr(expr);
context().leave_callexpr();
pop_message_to_diagram(expr);
return true;
}
bool translation_unit_visitor::TraverseCompoundStmt(clang::CompoundStmt *stmt)
{
using clanguml::common::model::message_t;
@@ -862,7 +897,8 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
// message source rather then enclosing context
// Unless the lambda is declared in a function or method call
if (context().lambda_caller_id() != 0) {
if (context().current_callexpr() == nullptr) {
if (!std::holds_alternative<clang::CallExpr *>(
context().current_callexpr())) {
m.set_from(context().lambda_caller_id());
}
else {
@@ -885,6 +921,7 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
if (!process_operator_call_expression(m, operator_call_expr))
return true;
}
//
// Call to a class method
//
@@ -963,17 +1000,69 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
return true;
}
bool translation_unit_visitor::VisitCXXConstructExpr(
clang::CXXConstructExpr *expr)
{
using clanguml::common::model::message_scope_t;
using clanguml::common::model::message_t;
using clanguml::common::model::namespace_;
using clanguml::sequence_diagram::model::activity;
using clanguml::sequence_diagram::model::message;
if (!should_include(expr->getConstructor()))
return true;
LOG_TRACE("Visiting cxx construct expression at {} [caller_id = {}]",
expr->getBeginLoc().printToString(source_manager()),
context().caller_id());
message m{message_t::kCall, context().caller_id()};
set_source_location(*expr, m);
if (context().lambda_caller_id() != 0) {
if (!std::holds_alternative<clang::CallExpr *>(
context().current_callexpr())) {
m.set_from(context().lambda_caller_id());
}
else {
LOG_DBG("Current lambda declaration is passed to a method or "
"function - keep the original caller id");
}
}
if (context().is_expr_in_current_control_statement_condition(expr)) {
m.set_message_scope(common::model::message_scope_t::kCondition);
}
if (!process_construct_expression(m, expr))
return true;
if (m.from() > 0 && m.to() > 0) {
if (diagram().sequences().find(m.from()) ==
diagram().sequences().end()) {
activity a{m.from()};
diagram().sequences().insert({m.from(), std::move(a)});
}
diagram().add_active_participant(m.from());
diagram().add_active_participant(m.to());
LOG_DBG("Found constructor call {} from {} [{}] to {} [{}] ",
m.message_name(), m.from(), m.from(), m.to(), m.to());
push_message(expr, std::move(m));
}
return true;
}
bool translation_unit_visitor::process_operator_call_expression(
model::message &m, const clang::CXXOperatorCallExpr *operator_call_expr)
{
if (operator_call_expr->getCalleeDecl() == nullptr)
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 {}",
getOperatorSpelling(operator_call_expr->getOperator()),
operator_call_expr->getCalleeDecl()->getID(),
@@ -993,6 +1082,39 @@ bool translation_unit_visitor::process_operator_call_expression(
return true;
}
bool translation_unit_visitor::process_construct_expression(
model::message &m, const clang::CXXConstructExpr *construct_expr)
{
const auto *constructor = construct_expr->getConstructor();
if (constructor == nullptr)
return false;
const auto *constructor_parent = constructor->getParent();
if (constructor_parent == nullptr)
return false;
LOG_DBG("Constructor '{}' call expression to {} at {}",
construct_expr->getConstructor()->getNameAsString(),
constructor->getID(),
construct_expr->getBeginLoc().printToString(source_manager()));
auto maybe_id = get_unique_id(constructor->getID());
if (maybe_id.has_value()) {
m.set_to(maybe_id.value());
}
else {
m.set_to(constructor->getID());
}
m.set_message_name(
fmt::format("{}::{}", constructor_parent->getQualifiedNameAsString(),
constructor_parent->getNameAsString()));
diagram().add_active_participant(constructor->getID());
return true;
}
bool translation_unit_visitor::process_class_method_call_expression(
model::message &m, const clang::CXXMemberCallExpr *method_call_expr)
{
@@ -2102,6 +2224,12 @@ void translation_unit_visitor::push_message(
call_expr_message_map_.emplace(expr, std::move(m));
}
void translation_unit_visitor::push_message(
clang::CXXConstructExpr *expr, model::message &&m)
{
construct_expr_message_map_.emplace(expr, std::move(m));
}
void translation_unit_visitor::pop_message_to_diagram(clang::CallExpr *expr)
{
assert(expr != nullptr);
@@ -2119,6 +2247,25 @@ void translation_unit_visitor::pop_message_to_diagram(clang::CallExpr *expr)
call_expr_message_map_.erase(expr);
}
void translation_unit_visitor::pop_message_to_diagram(
clang::CXXConstructExpr *expr)
{
assert(expr != nullptr);
// Skip if no message was generated from this expr
if (construct_expr_message_map_.find(expr) ==
construct_expr_message_map_.end()) {
return;
}
auto msg = std::move(construct_expr_message_map_.at(expr));
auto caller_id = msg.from();
diagram().get_activity(caller_id).add_message(std::move(msg));
construct_expr_message_map_.erase(expr);
}
void translation_unit_visitor::finalize()
{
std::set<common::model::diagram_element::id_t> active_participants_unique;