Fixed nested call expressions order in sequence diagrams
This commit is contained in:
@@ -214,7 +214,7 @@ void call_expression_context::enter_elseifstmt(clang::IfStmt *stmt)
|
|||||||
|
|
||||||
void call_expression_context::leave_elseifstmt()
|
void call_expression_context::leave_elseifstmt()
|
||||||
{
|
{
|
||||||
if (elseif_stmt_stack_.empty())
|
if (!elseif_stmt_stack_.empty())
|
||||||
elseif_stmt_stack_.pop();
|
elseif_stmt_stack_.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,10 +241,30 @@ void call_expression_context::enter_loopstmt(clang::Stmt *stmt)
|
|||||||
|
|
||||||
void call_expression_context::leave_loopstmt()
|
void call_expression_context::leave_loopstmt()
|
||||||
{
|
{
|
||||||
if (loop_stmt_stack_.empty())
|
if (!loop_stmt_stack_.empty())
|
||||||
return loop_stmt_stack_.pop();
|
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
|
clang::Stmt *call_expression_context::current_trystmt() const
|
||||||
{
|
{
|
||||||
if (try_stmt_stack_.empty())
|
if (try_stmt_stack_.empty())
|
||||||
@@ -300,7 +320,7 @@ void call_expression_context::enter_conditionaloperator(
|
|||||||
|
|
||||||
void call_expression_context::leave_conditionaloperator()
|
void call_expression_context::leave_conditionaloperator()
|
||||||
{
|
{
|
||||||
if (conditional_operator_stack_.empty())
|
if (!conditional_operator_stack_.empty())
|
||||||
conditional_operator_stack_.pop();
|
conditional_operator_stack_.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -92,6 +92,10 @@ struct call_expression_context {
|
|||||||
void enter_conditionaloperator(clang::ConditionalOperator *stmt);
|
void enter_conditionaloperator(clang::ConditionalOperator *stmt);
|
||||||
void leave_conditionaloperator();
|
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(
|
bool is_expr_in_current_control_statement_condition(
|
||||||
const clang::Stmt *stmt) const;
|
const clang::Stmt *stmt) const;
|
||||||
|
|
||||||
@@ -103,11 +107,12 @@ struct call_expression_context {
|
|||||||
clang::FunctionDecl *current_function_decl_;
|
clang::FunctionDecl *current_function_decl_;
|
||||||
clang::FunctionTemplateDecl *current_function_template_decl_;
|
clang::FunctionTemplateDecl *current_function_template_decl_;
|
||||||
|
|
||||||
clang::CallExpr *current_function_call_expr_{nullptr};
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::int64_t current_caller_id_;
|
std::int64_t current_caller_id_;
|
||||||
std::stack<std::int64_t> current_lambda_caller_id_;
|
std::stack<std::int64_t> current_lambda_caller_id_;
|
||||||
|
|
||||||
|
std::stack<clang::CallExpr *> call_expr_stack_;
|
||||||
|
|
||||||
std::stack<clang::IfStmt *> if_stmt_stack_;
|
std::stack<clang::IfStmt *> if_stmt_stack_;
|
||||||
std::stack<clang::IfStmt *> elseif_stmt_stack_;
|
std::stack<clang::IfStmt *> elseif_stmt_stack_;
|
||||||
|
|
||||||
|
|||||||
@@ -528,11 +528,35 @@ bool translation_unit_visitor::TraverseLambdaExpr(clang::LambdaExpr *expr)
|
|||||||
|
|
||||||
bool translation_unit_visitor::TraverseCallExpr(clang::CallExpr *expr)
|
bool translation_unit_visitor::TraverseCallExpr(clang::CallExpr *expr)
|
||||||
{
|
{
|
||||||
context().current_function_call_expr_ = expr;
|
context().enter_callexpr(expr);
|
||||||
|
|
||||||
RecursiveASTVisitor<translation_unit_visitor>::TraverseCallExpr(expr);
|
RecursiveASTVisitor<translation_unit_visitor>::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<translation_unit_visitor>::TraverseCXXMemberCallExpr(
|
||||||
|
expr);
|
||||||
|
|
||||||
|
pop_message_to_diagram(expr);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool translation_unit_visitor::TraverseCXXOperatorCallExpr(
|
||||||
|
clang::CXXOperatorCallExpr *expr)
|
||||||
|
{
|
||||||
|
RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXOperatorCallExpr(
|
||||||
|
expr);
|
||||||
|
|
||||||
|
pop_message_to_diagram(expr);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -874,7 +898,7 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
|
|||||||
// message source rather then enclosing context
|
// message source rather then enclosing context
|
||||||
// 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_callexpr() == nullptr) {
|
||||||
m.set_from(context().lambda_caller_id());
|
m.set_from(context().lambda_caller_id());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -969,7 +993,7 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
|
|||||||
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().get_activity(m.from()).add_message(std::move(m));
|
push_message(expr, std::move(m));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -2090,6 +2114,29 @@ std::string translation_unit_visitor::make_lambda_name(
|
|||||||
return result;
|
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()
|
void translation_unit_visitor::finalize()
|
||||||
{
|
{
|
||||||
std::set<common::model::diagram_element::id_t> active_participants_unique;
|
std::set<common::model::diagram_element::id_t> active_participants_unique;
|
||||||
|
|||||||
@@ -46,6 +46,13 @@ public:
|
|||||||
|
|
||||||
bool TraverseCallExpr(clang::CallExpr *expr);
|
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 VisitLambdaExpr(clang::LambdaExpr *expr);
|
||||||
|
|
||||||
bool TraverseLambdaExpr(clang::LambdaExpr *expr);
|
bool TraverseLambdaExpr(clang::LambdaExpr *expr);
|
||||||
@@ -245,6 +252,10 @@ private:
|
|||||||
bool process_unresolved_lookup_call_expression(
|
bool process_unresolved_lookup_call_expression(
|
||||||
model::message &m, const clang::CallExpr *expr);
|
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
|
// Reference to the output diagram model
|
||||||
clanguml::sequence_diagram::model::diagram &diagram_;
|
clanguml::sequence_diagram::model::diagram &diagram_;
|
||||||
|
|
||||||
@@ -253,6 +264,12 @@ private:
|
|||||||
|
|
||||||
call_expression_context call_expression_context_;
|
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<clang::CallExpr *, model::message> call_expr_message_map_;
|
||||||
|
|
||||||
std::map<common::model::diagram_element::id_t,
|
std::map<common::model::diagram_element::id_t,
|
||||||
std::unique_ptr<clanguml::sequence_diagram::model::class_>>
|
std::unique_ptr<clanguml::sequence_diagram::model::class_>>
|
||||||
forward_declarations_;
|
forward_declarations_;
|
||||||
|
|||||||
@@ -6,23 +6,17 @@
|
|||||||
|
|
||||||
namespace clanguml {
|
namespace clanguml {
|
||||||
namespace t20029 {
|
namespace t20029 {
|
||||||
using encoder_function_t = std::function<std::string(std::string &&)>;
|
|
||||||
|
|
||||||
std::string encode_b64(std::string &&content) { return std::move(content); }
|
std::string encode_b64(std::string &&content) { return std::move(content); }
|
||||||
|
|
||||||
template <typename T> class Encoder : public T {
|
template <typename T> class Encoder : public T {
|
||||||
public:
|
public:
|
||||||
bool send(std::string &&msg)
|
bool send(std::string &&msg)
|
||||||
{
|
{
|
||||||
auto encoded = encode(std::move(msg));
|
return T::send(std::move(encode(std::move(msg))));
|
||||||
return T::send(std::move(encoded));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string encode(std::string &&msg) { return encode_b64(std::move(msg)); }
|
std::string encode(std::string &&msg) { return encode_b64(std::move(msg)); }
|
||||||
|
|
||||||
private:
|
|
||||||
encoder_function_t f_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T> class Retrier : public T {
|
template <typename T> class Retrier : public T {
|
||||||
|
|||||||
@@ -319,7 +319,7 @@ int main(int argc, char *argv[])
|
|||||||
if (returnCode != 0)
|
if (returnCode != 0)
|
||||||
return returnCode;
|
return returnCode;
|
||||||
|
|
||||||
clanguml::util::setup_logging(debug_log);
|
clanguml::util::setup_logging(debug_log ? 3 : 1);
|
||||||
|
|
||||||
return session.run();
|
return session.run();
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user