Added support for constructors and operators in sequence diagrams
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user