diff --git a/src/sequence_diagram/visitor/call_expression_context.cc b/src/sequence_diagram/visitor/call_expression_context.cc index 10990308..dc8afcc2 100644 --- a/src/sequence_diagram/visitor/call_expression_context.cc +++ b/src/sequence_diagram/visitor/call_expression_context.cc @@ -214,7 +214,7 @@ void call_expression_context::enter_elseifstmt(clang::IfStmt *stmt) void call_expression_context::leave_elseifstmt() { - if (elseif_stmt_stack_.empty()) + if (!elseif_stmt_stack_.empty()) elseif_stmt_stack_.pop(); } @@ -241,10 +241,30 @@ void call_expression_context::enter_loopstmt(clang::Stmt *stmt) void call_expression_context::leave_loopstmt() { - if (loop_stmt_stack_.empty()) + if (!loop_stmt_stack_.empty()) return loop_stmt_stack_.pop(); } +clang::CallExpr *call_expression_context::current_callexpr() const +{ + if (call_expr_stack_.empty()) + return nullptr; + + return call_expr_stack_.top(); +} + +void call_expression_context::enter_callexpr(clang::CallExpr *expr) +{ + call_expr_stack_.push(expr); +} + +void call_expression_context::leave_callexpr() +{ + if (!call_expr_stack_.empty()) { + return call_expr_stack_.pop(); + } +} + clang::Stmt *call_expression_context::current_trystmt() const { if (try_stmt_stack_.empty()) @@ -300,7 +320,7 @@ void call_expression_context::enter_conditionaloperator( void call_expression_context::leave_conditionaloperator() { - if (conditional_operator_stack_.empty()) + if (!conditional_operator_stack_.empty()) conditional_operator_stack_.pop(); } diff --git a/src/sequence_diagram/visitor/call_expression_context.h b/src/sequence_diagram/visitor/call_expression_context.h index a1c247a2..cde69033 100644 --- a/src/sequence_diagram/visitor/call_expression_context.h +++ b/src/sequence_diagram/visitor/call_expression_context.h @@ -92,6 +92,10 @@ struct call_expression_context { void enter_conditionaloperator(clang::ConditionalOperator *stmt); void leave_conditionaloperator(); + clang::CallExpr *current_callexpr() const; + void enter_callexpr(clang::CallExpr *expr); + void leave_callexpr(); + bool is_expr_in_current_control_statement_condition( const clang::Stmt *stmt) const; @@ -103,11 +107,12 @@ struct call_expression_context { clang::FunctionDecl *current_function_decl_; clang::FunctionTemplateDecl *current_function_template_decl_; - clang::CallExpr *current_function_call_expr_{nullptr}; - private: std::int64_t current_caller_id_; std::stack current_lambda_caller_id_; + + std::stack call_expr_stack_; + std::stack if_stmt_stack_; std::stack elseif_stmt_stack_; diff --git a/src/sequence_diagram/visitor/translation_unit_visitor.cc b/src/sequence_diagram/visitor/translation_unit_visitor.cc index af73c10e..b0691110 100644 --- a/src/sequence_diagram/visitor/translation_unit_visitor.cc +++ b/src/sequence_diagram/visitor/translation_unit_visitor.cc @@ -528,11 +528,35 @@ bool translation_unit_visitor::TraverseLambdaExpr(clang::LambdaExpr *expr) bool translation_unit_visitor::TraverseCallExpr(clang::CallExpr *expr) { - context().current_function_call_expr_ = expr; + context().enter_callexpr(expr); RecursiveASTVisitor::TraverseCallExpr(expr); - context().current_function_call_expr_ = nullptr; + context().leave_callexpr(); + + pop_message_to_diagram(expr); + + return true; +} + +bool translation_unit_visitor::TraverseCXXMemberCallExpr( + clang::CXXMemberCallExpr *expr) +{ + RecursiveASTVisitor::TraverseCXXMemberCallExpr( + expr); + + pop_message_to_diagram(expr); + + return true; +} + +bool translation_unit_visitor::TraverseCXXOperatorCallExpr( + clang::CXXOperatorCallExpr *expr) +{ + RecursiveASTVisitor::TraverseCXXOperatorCallExpr( + expr); + + pop_message_to_diagram(expr); return true; } @@ -874,7 +898,7 @@ 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_function_call_expr_ == nullptr) { + if (context().current_callexpr() == nullptr) { m.set_from(context().lambda_caller_id()); } else { @@ -969,7 +993,7 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr) LOG_DBG("Found call {} from {} [{}] to {} [{}] ", m.message_name(), m.from(), m.from(), m.to(), m.to()); - diagram().get_activity(m.from()).add_message(std::move(m)); + push_message(expr, std::move(m)); } return true; @@ -2090,6 +2114,29 @@ std::string translation_unit_visitor::make_lambda_name( return result; } +void translation_unit_visitor::push_message( + clang::CallExpr *expr, model::message &&m) +{ + call_expr_message_map_.emplace(expr, std::move(m)); +} + +void translation_unit_visitor::pop_message_to_diagram(clang::CallExpr *expr) +{ + assert(expr != nullptr); + + // Skip if no message was generated from this expr + if (call_expr_message_map_.find(expr) == call_expr_message_map_.end()) { + return; + } + + auto msg = std::move(call_expr_message_map_.at(expr)); + + auto caller_id = msg.from(); + diagram().get_activity(caller_id).add_message(std::move(msg)); + + call_expr_message_map_.erase(expr); +} + void translation_unit_visitor::finalize() { std::set active_participants_unique; diff --git a/src/sequence_diagram/visitor/translation_unit_visitor.h b/src/sequence_diagram/visitor/translation_unit_visitor.h index 8748a670..8fb09c45 100644 --- a/src/sequence_diagram/visitor/translation_unit_visitor.h +++ b/src/sequence_diagram/visitor/translation_unit_visitor.h @@ -46,6 +46,13 @@ public: bool TraverseCallExpr(clang::CallExpr *expr); + bool TraverseCXXMemberCallExpr(clang::CXXMemberCallExpr *expr); + + bool TraverseCXXOperatorCallExpr(clang::CXXOperatorCallExpr *expr); + + // TODO + // bool TraverseCXXConstructExpr(clang::CXXConstructExpr *expr); + bool VisitLambdaExpr(clang::LambdaExpr *expr); bool TraverseLambdaExpr(clang::LambdaExpr *expr); @@ -245,6 +252,10 @@ private: bool process_unresolved_lookup_call_expression( model::message &m, const clang::CallExpr *expr); + void push_message(clang::CallExpr *expr, model::message &&m); + + void pop_message_to_diagram(clang::CallExpr *expr); + // Reference to the output diagram model clanguml::sequence_diagram::model::diagram &diagram_; @@ -253,6 +264,12 @@ private: call_expression_context call_expression_context_; + /// This is used to generate messages in proper order in case of + /// nested call expressions (e.g. a(b(c(), d())), as they need to + /// be added to the diagram sequence after the visitor leaves the + /// call expression AST node + std::map call_expr_message_map_; + std::map> forward_declarations_; diff --git a/tests/t20029/t20029.cc b/tests/t20029/t20029.cc index e61a0ce5..3c89144e 100644 --- a/tests/t20029/t20029.cc +++ b/tests/t20029/t20029.cc @@ -6,23 +6,17 @@ namespace clanguml { namespace t20029 { -using encoder_function_t = std::function; - std::string encode_b64(std::string &&content) { return std::move(content); } template class Encoder : public T { public: bool send(std::string &&msg) { - auto encoded = encode(std::move(msg)); - return T::send(std::move(encoded)); + return T::send(std::move(encode(std::move(msg)))); } protected: std::string encode(std::string &&msg) { return encode_b64(std::move(msg)); } - -private: - encoder_function_t f_; }; template class Retrier : public T { diff --git a/tests/test_cases.cc b/tests/test_cases.cc index 11c74630..ce863832 100644 --- a/tests/test_cases.cc +++ b/tests/test_cases.cc @@ -319,7 +319,7 @@ int main(int argc, char *argv[]) if (returnCode != 0) return returnCode; - clanguml::util::setup_logging(debug_log); + clanguml::util::setup_logging(debug_log ? 3 : 1); return session.run(); } \ No newline at end of file