0.6.3
C++ to UML diagram generator based on Clang
Loading...
Searching...
No Matches
Public Types | Public Member Functions | Private Member Functions | Private Attributes | List of all members
clanguml::sequence_diagram::visitor::translation_unit_visitor Class Reference

Sequence diagram translation unit visitor. More...

Detailed Description

Sequence diagram translation unit visitor.

This class implements the clang::RecursiveASTVisitor interface for selected visitors relevant to generating sequence diagrams.

Definition at line 49 of file translation_unit_visitor.h.

#include <translation_unit_visitor.h>

Public Types

using template_builder_t = common::visitor::template_builder< translation_unit_visitor >
 
using config_t = ConfigT
 
using diagram_t = DiagramT
 
- Public Types inherited from clanguml::common::visitor::translation_unit_visitor< ConfigT, DiagramT >
using config_t = ConfigT
 
using diagram_t = DiagramT
 

Public Member Functions

 translation_unit_visitor (clang::SourceManager &sm, clanguml::sequence_diagram::model::diagram &diagram, const clanguml::config::sequence_diagram &config)
 Constructor.
 
 ~translation_unit_visitor () override=default
 
bool shouldVisitTemplateInstantiations ()
 
bool VisitReturnStmt (clang::ReturnStmt *stmt)
 
bool VisitCallExpr (clang::CallExpr *expr)
 
bool VisitObjCMessageExpr (clang::ObjCMessageExpr *expr)
 
bool VisitObjCPropertyRefExpr (clang::ObjCPropertyRefExpr *expr)
 
bool TraverseVarDecl (clang::VarDecl *VD)
 
bool TraverseCoyieldExpr (clang::CoyieldExpr *expr)
 
bool TraverseCoawaitExpr (clang::CoawaitExpr *expr)
 
bool TraverseCoreturnStmt (clang::CoreturnStmt *stmt)
 
bool TraverseCallExpr (clang::CallExpr *expr)
 
bool TraverseObjCMessageExpr (clang::ObjCMessageExpr *expr)
 
bool TraverseCUDAKernelCallExpr (clang::CUDAKernelCallExpr *expr)
 
bool TraverseCXXMemberCallExpr (clang::CXXMemberCallExpr *expr)
 
bool TraverseCXXOperatorCallExpr (clang::CXXOperatorCallExpr *expr)
 
bool VisitCXXConstructExpr (clang::CXXConstructExpr *expr)
 
bool TraverseCXXConstructExpr (clang::CXXConstructExpr *expr)
 
bool TraverseCXXTemporaryObjectExpr (clang::CXXTemporaryObjectExpr *expr)
 
bool TraverseReturnStmt (clang::ReturnStmt *stmt)
 
bool VisitCoreturnStmt (clang::CoreturnStmt *stmt)
 
bool VisitCoyieldExpr (clang::CoyieldExpr *expr)
 
bool VisitCoawaitExpr (clang::CoawaitExpr *expr)
 
bool VisitLambdaExpr (clang::LambdaExpr *expr)
 
bool TraverseLambdaExpr (clang::LambdaExpr *expr)
 
bool TraverseCXXMethodDecl (clang::CXXMethodDecl *declaration)
 
bool TraverseObjCMethodDecl (clang::ObjCMethodDecl *declaration)
 
bool VisitObjCMethodDecl (clang::ObjCMethodDecl *declaration)
 
bool VisitCXXMethodDecl (clang::CXXMethodDecl *declaration)
 
bool TraverseCXXRecordDecl (clang::CXXRecordDecl *declaration)
 
bool VisitCXXRecordDecl (clang::CXXRecordDecl *declaration)
 
bool VisitClassTemplateDecl (clang::ClassTemplateDecl *declaration)
 
bool VisitClassTemplateSpecializationDecl (clang::ClassTemplateSpecializationDecl *declaration)
 
bool TraverseFunctionDecl (clang::FunctionDecl *declaration)
 
bool VisitFunctionDecl (clang::FunctionDecl *declaration)
 
bool TraverseFunctionTemplateDecl (clang::FunctionTemplateDecl *declaration)
 
bool VisitFunctionTemplateDecl (clang::FunctionTemplateDecl *function_declaration)
 
bool VisitObjCInterfaceDecl (clang::ObjCInterfaceDecl *interface_declaration)
 
bool VisitObjCProtocolDecl (clang::ObjCProtocolDecl *protocol_declaration)
 
bool TraverseCompoundStmt (clang::CompoundStmt *stmt)
 
bool TraverseIfStmt (clang::IfStmt *stmt)
 
bool TraverseWhileStmt (clang::WhileStmt *stmt)
 
bool TraverseDoStmt (clang::DoStmt *stmt)
 
bool TraverseForStmt (clang::ForStmt *stmt)
 
bool TraverseCXXForRangeStmt (clang::CXXForRangeStmt *stmt)
 
bool TraverseCXXTryStmt (clang::CXXTryStmt *stmt)
 
bool TraverseCXXCatchStmt (clang::CXXCatchStmt *stmt)
 
bool TraverseSwitchStmt (clang::SwitchStmt *stmt)
 
bool TraverseCaseStmt (clang::CaseStmt *stmt)
 
bool TraverseDefaultStmt (clang::DefaultStmt *stmt)
 
bool TraverseConditionalOperator (clang::ConditionalOperator *stmt)
 
call_expression_contextcontext ()
 Get current call expression context reference.
 
const call_expression_contextcontext () const
 Get current call expression context reference.
 
template<typename T = model::participant>
common::optional_ref< T > get_participant (const clang::Decl *decl)
 Get participant by declaration.
 
template<typename T = model::participant>
common::optional_ref< T > get_participant (const clang::Decl *decl) const
 Get participant by declaration.
 
template<typename T = model::participant>
common::optional_ref< T > get_participant (const eid_t id)
 Get participant by global element id.
 
template<typename T = model::participant>
common::optional_ref< T > get_participant (eid_t id) const
 Get participant by global element id.
 
void set_unique_id (int64_t local_id, eid_t global_id)
 Store the mapping from local clang entity id (obtained using getID()) method to clang-uml global id.
 
std::optional< eid_tget_unique_id (eid_t local_id) const
 Retrieve the global clang-uml entity id based on the Clang local id.
 
void finalize ()
 Finalize diagram model for this translation unit.
 
std::unique_ptr< sequence_diagram::model::class_create_element (const clang::NamedDecl *decl) const
 
- Public Member Functions inherited from clanguml::common::visitor::translation_unit_visitor< ConfigT, DiagramT >
 translation_unit_visitor (clang::SourceManager &sm, DiagramT &diagram, const ConfigT &config)
 Constructor.
 
virtual ~translation_unit_visitor ()=default
 
void set_tu_path (const std::string &translation_unit_path)
 
const std::filesystem::path & tu_path () const
 Return relative path to current translation unit.
 
common::visitor::ast_id_mapperid_mapper () const
 Get reference to Clang AST to clang-uml id mapper.
 
clang::SourceManager & source_manager () const
 Get clang::SourceManager.
 
void set_source_location (const clang::Decl &decl, clanguml::common::model::source_location &element)
 Set source location in diagram element.
 
void set_source_location (const clang::Expr &expr, clanguml::common::model::source_location &element)
 Set source location in diagram element.
 
void set_source_location (const clang::Stmt &stmt, clanguml::common::model::source_location &element)
 
void set_qualified_name (const clang::NamedDecl &decl, clanguml::common::model::element &element)
 
void set_source_location (const clang::SourceLocation &location, clanguml::common::model::source_location &element)
 Set source location in diagram element.
 
void set_owning_module (const clang::Decl &decl, clanguml::common::model::element &element)
 
virtual void add_diagram_element (std::unique_ptr< common::model::template_element > element)
 
void process_comment (const clang::NamedDecl &decl, clanguml::common::model::decorated_element &e)
 Process comment directives in comment attached to a declaration.
 
std::string process_comment (const clang::RawComment *comment, clang::DiagnosticsEngine &de, clanguml::common::model::decorated_element &e)
 Process comment directives in raw comment.
 
bool skip_system_header_decl (const clang::NamedDecl *decl) const
 
bool should_include (const clang::NamedDecl *decl) const
 Check if the diagram should include a declaration.
 
DiagramT & diagram ()
 Get diagram model reference.
 
const DiagramT & diagram () const
 Get diagram model reference.
 
const ConfigT & config () const
 Get diagram config instance.
 

Private Member Functions

template<typename T = sequence_diagram::model::class_>
T & get_participant (eid_t element_id, T &fallback_model)
 Get existing participant or fallback to provided model.
 
bool should_include (const clang::TagDecl *decl) const
 Check if the diagram should include a declaration.
 
bool should_include (const clang::ObjCContainerDecl *decl) const
 Check if the diagram should include an ObjC declaration.
 
bool should_include (const clang::LambdaExpr *expr) const
 Check if the diagram should include a lambda expression.
 
bool should_include (const clang::CallExpr *expr) const
 Check if the diagram should include a call expression.
 
bool should_include (const clang::ObjCMessageExpr *expr) const
 Check if the diagram should include an ObjC message expression.
 
bool should_include (const clang::CXXMethodDecl *decl) const
 Check if the diagram should include a declaration.
 
bool should_include (const clang::ObjCMethodDecl *decl) const
 
bool should_include (const clang::FunctionDecl *decl) const
 Check if the diagram should include a declaration.
 
bool should_include (const clang::FunctionTemplateDecl *decl) const
 Check if the diagram should include a declaration.
 
bool should_include (const clang::ClassTemplateDecl *decl) const
 Check if the diagram should include a declaration.
 
std::unique_ptr< clanguml::sequence_diagram::model::class_create_objc_interface_model (clang::ObjCInterfaceDecl *cls)
 
std::unique_ptr< clanguml::sequence_diagram::model::class_create_objc_protocol_model (clang::ObjCProtocolDecl *cls)
 
std::unique_ptr< clanguml::sequence_diagram::model::class_create_class_model (clang::CXXRecordDecl *cls)
 
std::unique_ptr< clanguml::sequence_diagram::model::methodcreate_method_model (clang::CXXMethodDecl *cls)
 
std::unique_ptr< clanguml::sequence_diagram::model::objc_methodcreate_objc_method_model (clang::ObjCMethodDecl *cls)
 
std::unique_ptr< clanguml::sequence_diagram::model::methodcreate_lambda_method_model (clang::CXXMethodDecl *cls)
 
std::unique_ptr< model::function_templatebuild_function_template_instantiation (const clang::FunctionDecl &pDecl)
 
std::unique_ptr< model::functionbuild_function_model (const clang::FunctionDecl &declaration)
 
std::unique_ptr< model::function_templatebuild_function_template (const clang::FunctionTemplateDecl &declaration)
 
std::unique_ptr< model::class_process_class_template_specialization (clang::ClassTemplateSpecializationDecl *cls)
 
std::string simplify_system_template (const std::string &full_name) const
 
std::string make_lambda_name (const clang::CXXRecordDecl *cls) const
 Assuming cls is a lambda, create it's full name.
 
std::string lambda_source_location (const clang::SourceLocation &source_location) const
 Render lambda source location to string.
 
bool is_smart_pointer (const clang::TemplateDecl *primary_template) const
 Check if template is a smart pointer.
 
bool is_callee_valid_template_specialization (const clang::CXXDependentScopeMemberExpr *dependent_member_expr) const
 Check, the callee is a template specialization.
 
bool process_callee (clang::CallExpr *expr, model::message &m, bool generated_message_from_comment)
 
bool process_construct_expression (model::message &m, const clang::CXXConstructExpr *construct_expr)
 Handle CXX constructor call.
 
bool process_operator_call_expression (model::message &m, const clang::CXXOperatorCallExpr *operator_call_expr)
 Handle a operator call expression.
 
bool process_cuda_kernel_call_expression (model::message &m, const clang::CUDAKernelCallExpr *cuda_call_expr)
 
bool process_class_method_call_expression (model::message &m, const clang::CXXMemberCallExpr *method_call_expr)
 Handle a class method call expresion.
 
bool process_objc_message_expression (model::message &m, const clang::ObjCMessageExpr *message_expr)
 
bool process_class_template_method_call_expression (model::message &m, const clang::CallExpr *expr)
 Handle a class template method call expresion.
 
bool process_function_call_expression (model::message &m, const clang::CallExpr *expr)
 Handle a function call expresion.
 
bool process_unresolved_lookup_call_expression (model::message &m, const clang::CallExpr *expr) const
 Handle an unresolved lookup call expresion.
 
bool process_lambda_call_expression (model::message &m, const clang::CallExpr *expr) const
 
void push_message (clang::CallExpr *expr, model::message &&m)
 Register a message model m with a call expression.
 
void push_message (clang::CXXConstructExpr *expr, model::message &&m)
 
void push_message (clang::ObjCMessageExpr *expr, model::message &&m)
 
void push_message (clang::ReturnStmt *stmt, model::message &&m)
 
void push_message (clang::CoreturnStmt *stmt, model::message &&m)
 
void push_message (clang::CoyieldExpr *stmt, model::message &&m)
 
void push_message (clang::CoawaitExpr *stmt, model::message &&m)
 
void pop_message_to_diagram (clang::CallExpr *expr)
 Move a message model to diagram.
 
void pop_message_to_diagram (clang::CXXConstructExpr *expr)
 
void pop_message_to_diagram (clang::ObjCMessageExpr *expr)
 
void pop_message_to_diagram (clang::ReturnStmt *stmt)
 
void pop_message_to_diagram (clang::CoreturnStmt *stmt)
 
void pop_message_to_diagram (clang::CoyieldExpr *expr)
 
void pop_message_to_diagram (clang::CoawaitExpr *expr)
 
std::optional< std::pair< unsigned int, std::string > > get_expression_comment (const clang::SourceManager &sm, const clang::ASTContext &context, eid_t caller_id, const clang::Stmt *stmt)
 
bool generate_message_from_comment (model::message &m) const
 Initializes model message from comment call directive.
 
template_builder_ttbuilder ()
 Get template builder reference.
 
void resolve_ids_to_global ()
 
void ensure_lambda_messages_have_operator_as_target ()
 
void add_callers_to_activities ()
 
void ensure_activity_exists (const model::message &m)
 
void process_function_parameters (const clang::FunctionDecl &declaration, model::function &method_model) const
 

Private Attributes

call_expression_context call_expression_context_
 
std::map< clang::CallExpr *, std::deque< model::message > > call_expr_message_map_
 
std::map< clang::ReturnStmt *, model::messagereturn_stmt_message_map_
 
std::map< clang::CoreturnStmt *, model::messageco_return_stmt_message_map_
 
std::map< clang::CoyieldExpr *, model::messageco_yield_stmt_message_map_
 
std::map< clang::CoawaitExpr *, model::messageco_await_stmt_message_map_
 
std::map< clang::CXXConstructExpr *, model::messageconstruct_expr_message_map_
 
std::map< clang::ObjCMessageExpr *, model::messageobjc_message_map_
 
std::map< eid_t, std::unique_ptr< clanguml::sequence_diagram::model::class_ > > forward_declarations_
 
std::map< int64_t, std::tuple< std::string, common::model::relationship_t, common::model::access_t > > anonymous_structs_
 
std::map< eid_t, std::set< eid_t > > activity_callers_
 
unsigned within_static_variable_declaration_ {0}
 
std::set< const clang::Expr * > already_visited_in_static_declaration_ {}
 
std::set< std::pair< int64_t, const clang::RawComment * > > processed_comments_by_caller_id_
 
template_builder_t template_builder_
 

Additional Inherited Members

- Protected Member Functions inherited from clanguml::common::visitor::translation_unit_visitor< ConfigT, DiagramT >
std::set< const clang::RawComment * > & processed_comments ()
 
std::string get_file_path (const std::string &file_location) const
 

Member Typedef Documentation

◆ config_t

using clanguml::common::visitor::translation_unit_visitor< ConfigT, DiagramT >::config_t = ConfigT

Definition at line 56 of file translation_unit_visitor.h.

◆ diagram_t

using clanguml::common::visitor::translation_unit_visitor< ConfigT, DiagramT >::diagram_t = DiagramT

Definition at line 57 of file translation_unit_visitor.h.

◆ template_builder_t

Definition at line 56 of file translation_unit_visitor.h.

Constructor & Destructor Documentation

◆ translation_unit_visitor()

clanguml::sequence_diagram::visitor::translation_unit_visitor::translation_unit_visitor ( clang::SourceManager &  sm,
clanguml::sequence_diagram::model::diagram diagram,
const clanguml::config::sequence_diagram config 
)

Constructor.

Parameters
smCurrent source manager reference
diagramDiagram model
configDiagram configuration

Definition at line 27 of file translation_unit_visitor.cc.

◆ ~translation_unit_visitor()

clanguml::sequence_diagram::visitor::translation_unit_visitor::~translation_unit_visitor ( )
overridevirtualdefault

Member Function Documentation

◆ add_callers_to_activities()

void clanguml::sequence_diagram::visitor::translation_unit_visitor::add_callers_to_activities ( )
private

Definition at line 2992 of file translation_unit_visitor.cc.

2993{
2994 // Translate reverse activity call graph local ids to global ids
2995 std::map<eid_t, std::set<eid_t>> acs;
2996 for (const auto &[id, caller_ids] : activity_callers_) {
2997 auto unique_id = get_unique_id(id);
2998 if (!unique_id)
2999 continue;
3000 std::set<eid_t> unique_caller_ids;
3001 for (const auto &caller_id : caller_ids) {
3002 auto unique_caller_id = get_unique_id(caller_id);
3003 if (unique_caller_id)
3004 unique_caller_ids.emplace(*unique_caller_id);
3005 }
3006 acs.emplace(*unique_id, std::move(unique_caller_ids));
3007 }
3008
3009 // Change all message callees AST local ids to diagram global ids
3010 for (auto &[id, activity] : diagram().sequences()) {
3011 assert(id.is_global());
3012
3013 if (acs.count(id) > 0) {
3014 activity.set_callers(acs.at(id));
3015 }
3016 }
3017}

◆ build_function_model()

std::unique_ptr< model::function > clanguml::sequence_diagram::visitor::translation_unit_visitor::build_function_model ( const clang::FunctionDecl &  declaration)
private

Definition at line 2616 of file translation_unit_visitor.cc.

2618{
2619 auto function_model_ptr =
2620 std::make_unique<sequence_diagram::model::function>(
2621 config().using_namespace());
2622
2623 common::model::namespace_ ns{declaration.getQualifiedNameAsString()};
2624 function_model_ptr->set_name(ns.name());
2625 ns.pop_back();
2626 function_model_ptr->set_namespace(ns);
2627
2628 function_model_ptr->return_type(common::to_string(
2629 declaration.getReturnType(), declaration.getASTContext()));
2630
2631 process_function_parameters(declaration, *function_model_ptr);
2632
2633 if (declaration.isVariadic()) {
2634 function_model_ptr->add_parameter("...");
2635 }
2636
2637 return function_model_ptr;
2638}

◆ build_function_template()

std::unique_ptr< model::function_template > clanguml::sequence_diagram::visitor::translation_unit_visitor::build_function_template ( const clang::FunctionTemplateDecl &  declaration)
private

Definition at line 2572 of file translation_unit_visitor.cc.

2574{
2575 auto function_template_model_ptr =
2576 std::make_unique<sequence_diagram::model::function_template>(
2577 config().using_namespace());
2578
2579 set_qualified_name(declaration, *function_template_model_ptr);
2580
2582 *function_template_model_ptr, declaration);
2583
2584 function_template_model_ptr->return_type(
2585 common::to_string(declaration.getAsFunction()->getReturnType(),
2586 declaration.getASTContext()));
2587
2588 if (declaration.getAsFunction() != nullptr) {
2590 *declaration.getAsFunction(), *function_template_model_ptr);
2591 }
2592
2593 return function_template_model_ptr;
2594}

◆ build_function_template_instantiation()

std::unique_ptr< model::function_template > clanguml::sequence_diagram::visitor::translation_unit_visitor::build_function_template_instantiation ( const clang::FunctionDecl &  pDecl)
private

Definition at line 2597 of file translation_unit_visitor.cc.

2599{
2600 auto template_instantiation_ptr =
2601 std::make_unique<model::function_template>(config().using_namespace());
2602 auto &template_instantiation = *template_instantiation_ptr;
2603
2604 set_qualified_name(declaration, template_instantiation);
2605
2606 tbuilder().build(declaration, template_instantiation, &declaration,
2607 declaration.getPrimaryTemplate(),
2608 declaration.getTemplateSpecializationArgs()->asArray(),
2609 common::to_string(&declaration));
2610
2611 process_function_parameters(declaration, *template_instantiation_ptr);
2612
2613 return template_instantiation_ptr;
2614}

◆ context() [1/2]

call_expression_context & clanguml::sequence_diagram::visitor::translation_unit_visitor::context ( )

Get current call expression context reference.

Returns
Reference to the current call expression context

Definition at line 48 of file translation_unit_visitor.cc.

49{
51}

◆ context() [2/2]

const call_expression_context & clanguml::sequence_diagram::visitor::translation_unit_visitor::context ( ) const

Get current call expression context reference.

Returns
Reference to the current call expression context

Definition at line 53 of file translation_unit_visitor.cc.

54{
56}

◆ create_class_model()

std::unique_ptr< clanguml::sequence_diagram::model::class_ > clanguml::sequence_diagram::visitor::translation_unit_visitor::create_class_model ( clang::CXXRecordDecl *  cls)
private

Definition at line 2405 of file translation_unit_visitor.cc.

2406{
2407 assert(cls != nullptr);
2408
2409 auto c_ptr{std::make_unique<clanguml::sequence_diagram::model::class_>(
2410 config().using_namespace())};
2411 auto &c = *c_ptr;
2412
2413 auto qualified_name = cls->getQualifiedNameAsString();
2414
2415 if (!cls->isLambda())
2416 if (!should_include(cls))
2417 return {};
2418
2419 auto ns = common::get_tag_namespace(*cls);
2420
2421 if (cls->isLambda() && !diagram().should_include(ns | "lambda"))
2422 return {};
2423
2424 const auto *parent = cls->getParent();
2425
2426 if ((parent != nullptr) && parent->isRecord()) {
2427 // Here we have 3 options, either:
2428 // - the parent is a regular C++ class/struct
2429 // - the parent is a class template declaration/specialization
2430 // - the parent is a lambda (i.e. this is a nested lambda expression)
2431 std::optional<eid_t> id_opt;
2432 const auto *parent_record_decl =
2433 clang::dyn_cast<clang::RecordDecl>(parent);
2434
2435 assert(parent_record_decl != nullptr);
2436
2437 const eid_t ast_id{parent_record_decl->getID()};
2438
2439 // First check if the parent has been added to the diagram as
2440 // regular class
2441 id_opt = get_unique_id(ast_id);
2442
2443 // If not, check if the parent template declaration is in the model
2444 if (!id_opt &&
2445 (parent_record_decl->getDescribedTemplate() != nullptr)) {
2446 parent_record_decl->getDescribedTemplate()->getID();
2447 if (parent_record_decl->getDescribedTemplate() != nullptr)
2448 id_opt = get_unique_id(ast_id);
2449 }
2450
2451 if (!id_opt)
2452 return {};
2453
2454 auto parent_class =
2455 diagram()
2457 *id_opt);
2458
2459 if (!parent_class) {
2460 return {};
2461 }
2462
2463 c.set_namespace(ns);
2464 if (cls->getNameAsString().empty()) {
2465 c.set_name(parent_class.value().name() + "::" +
2466 fmt::format("(anonymous_{})", std::to_string(cls->getID())));
2467 }
2468 else {
2469 c.set_name(
2470 parent_class.value().name() + "::" + cls->getNameAsString());
2471 }
2472
2473 c.set_id(common::to_id(c.full_name(false)));
2474
2475 c.nested(true);
2476 }
2477 else if (cls->isLambda()) {
2478 c.is_lambda(true);
2479 if (cls->getParent() != nullptr) {
2480 const auto type_name = make_lambda_name(cls);
2481
2482 c.set_name(type_name);
2483 c.set_namespace(ns);
2484 c.set_id(common::to_id(c.full_name(false)));
2485 }
2486 else {
2487 LOG_WARN("Cannot find parent declaration for lambda {}",
2488 cls->getQualifiedNameAsString());
2489 return {};
2490 }
2491 }
2492 // This is equivalent to parent != nullptr and parent->isFunctionDecl()
2493 else if (cls->isLocalClass() != nullptr) {
2494 const auto *func_declaration = cls->isLocalClass();
2495
2496 eid_t local_parent_id{int64_t{}};
2497
2498 if (common::is_lambda_method(func_declaration)) {
2499 LOG_DBG("The local class is defined in a lambda operator()");
2500 const auto *method_declaration =
2501 clang::dyn_cast<clang::CXXMethodDecl>(func_declaration);
2502
2503 if (method_declaration != nullptr &&
2504 method_declaration->getParent() != nullptr) {
2505 local_parent_id = method_declaration->getParent()->getID();
2506 }
2507 }
2508 else {
2509 local_parent_id = func_declaration->getID();
2510 }
2511
2512 eid_t parent_id = get_unique_id(local_parent_id).has_value()
2513 ? *get_unique_id(local_parent_id) // NOLINT
2514 : local_parent_id;
2515
2516 const auto &func_model =
2517 diagram().get_participant<model::participant>(parent_id);
2518
2519 if (!func_model.has_value())
2520 return {};
2521
2522 LOG_DBG("Visiting local class declaration: {} in {}",
2523 cls->getQualifiedNameAsString(),
2524 func_model.value().full_name(false));
2525
2526 auto local_cls_ns = func_model.value().get_namespace();
2527
2528 c.set_name(
2529 func_model.value().full_name_no_ns(), common::get_tag_name(*cls));
2530 c.set_namespace(local_cls_ns);
2531 c.set_id(common::to_id(c.full_name(false)));
2532 c.nested(true);
2533 }
2534 else {
2535 c.set_name(common::get_tag_name(*cls));
2536 c.set_namespace(ns);
2537 c.set_id(common::to_id(c.full_name(false)));
2538 }
2539
2540 c.is_struct(cls->isStruct());
2541
2542 process_comment(*cls, c);
2543 set_source_location(*cls, c);
2544
2545 if (c.skip())
2546 return {};
2547
2548 c.set_style(c.style_spec());
2549
2550 return c_ptr;
2551}

◆ create_element()

std::unique_ptr< sequence_diagram::model::class_ > clanguml::sequence_diagram::visitor::translation_unit_visitor::create_element ( const clang::NamedDecl *  decl) const

Definition at line 36 of file translation_unit_visitor.cc.

38{
39 return std::make_unique<sequence_diagram::model::class_>(
40 config().using_namespace());
41}

◆ create_lambda_method_model()

std::unique_ptr< clanguml::sequence_diagram::model::method > clanguml::sequence_diagram::visitor::translation_unit_visitor::create_lambda_method_model ( clang::CXXMethodDecl *  cls)
private

Definition at line 3020 of file translation_unit_visitor.cc.

3022{
3023 auto method_model_ptr = std::make_unique<sequence_diagram::model::method>(
3024 config().using_namespace());
3025
3026 common::model::namespace_ ns{declaration->getQualifiedNameAsString()};
3027 auto method_name = ns.name();
3028 method_model_ptr->set_method_name(method_name);
3029 ns.pop_back();
3030 method_model_ptr->set_name(ns.name());
3031 ns.pop_back();
3032 method_model_ptr->set_namespace(ns);
3033
3034 method_model_ptr->is_defaulted(declaration->isDefaulted());
3035 method_model_ptr->is_assignment(declaration->isCopyAssignmentOperator() ||
3036 declaration->isMoveAssignmentOperator());
3037 method_model_ptr->is_const(declaration->isConst());
3038 method_model_ptr->is_static(declaration->isStatic());
3039 method_model_ptr->is_operator(declaration->isOverloadedOperator());
3040 method_model_ptr->is_constructor(
3041 clang::dyn_cast<clang::CXXConstructorDecl>(declaration) != nullptr);
3042
3043 method_model_ptr->is_void(declaration->getReturnType()->isVoidType());
3044
3045 method_model_ptr->return_type(common::to_string(
3046 declaration->getReturnType(), declaration->getASTContext()));
3047
3048 process_function_parameters(*declaration, *method_model_ptr);
3049
3050 return method_model_ptr;
3051}

◆ create_method_model()

std::unique_ptr< clanguml::sequence_diagram::model::method > clanguml::sequence_diagram::visitor::translation_unit_visitor::create_method_model ( clang::CXXMethodDecl *  cls)
private

Definition at line 3122 of file translation_unit_visitor.cc.

3123{
3124 auto method_model_ptr = std::make_unique<sequence_diagram::model::method>(
3125 config().using_namespace());
3126
3127 common::model::namespace_ ns{declaration->getQualifiedNameAsString()};
3128 auto method_name = ns.name();
3129 method_model_ptr->set_method_name(method_name);
3130 ns.pop_back();
3131 method_model_ptr->set_name(ns.name());
3132 ns.pop_back();
3133 method_model_ptr->set_namespace(ns);
3134
3135 method_model_ptr->is_defaulted(declaration->isDefaulted());
3136 method_model_ptr->is_assignment(declaration->isCopyAssignmentOperator() ||
3137 declaration->isMoveAssignmentOperator());
3138 method_model_ptr->is_const(declaration->isConst());
3139 method_model_ptr->is_static(declaration->isStatic());
3140 method_model_ptr->is_operator(declaration->isOverloadedOperator());
3141 method_model_ptr->is_constructor(
3142 clang::dyn_cast<clang::CXXConstructorDecl>(declaration) != nullptr);
3143 method_model_ptr->is_coroutine(common::is_coroutine(*declaration));
3144
3145 clang::Decl *parent_decl = declaration->getParent();
3146
3147 if (context().current_class_template_decl_ != nullptr)
3148 parent_decl = context().current_class_template_decl_;
3149
3150 LOG_DBG("Getting method's class with local id {}", parent_decl->getID());
3151
3152 const auto maybe_method_class = get_participant<model::class_>(parent_decl);
3153
3154 if (!maybe_method_class) {
3155 LOG_DBG("Cannot find parent class_ for method {} in class {}",
3156 declaration->getQualifiedNameAsString(),
3157 declaration->getParent()->getQualifiedNameAsString());
3158 return {};
3159 }
3160
3161 LOG_DBG(
3162 "Found method class: {}", maybe_method_class.value().full_name(false));
3163
3164 const auto &method_class = maybe_method_class.value();
3165
3166 method_model_ptr->is_void(declaration->getReturnType()->isVoidType());
3167
3168 method_model_ptr->set_class_id(method_class.id());
3169 method_model_ptr->set_class_full_name(method_class.full_name(false));
3170 method_model_ptr->set_name(get_participant(method_model_ptr->class_id())
3171 .value()
3172 .full_name_no_ns() +
3173 "::" + declaration->getNameAsString());
3174
3175 method_model_ptr->return_type(common::to_string(
3176 declaration->getReturnType(), declaration->getASTContext()));
3177
3178 process_function_parameters(*declaration, *method_model_ptr);
3179
3180 return method_model_ptr;
3181}

◆ create_objc_interface_model()

std::unique_ptr< clanguml::sequence_diagram::model::class_ > clanguml::sequence_diagram::visitor::translation_unit_visitor::create_objc_interface_model ( clang::ObjCInterfaceDecl *  cls)
private

Definition at line 2377 of file translation_unit_visitor.cc.

2379{
2380 assert(cls != nullptr);
2381
2382 auto c_ptr{std::make_unique<clanguml::sequence_diagram::model::class_>(
2383 config().using_namespace())};
2384 auto &c = *c_ptr;
2385
2386 auto qualified_name = cls->getQualifiedNameAsString();
2387
2388 c.is_objc_interface(true);
2389
2390 c.set_name(cls->getQualifiedNameAsString());
2391 c.set_id(common::to_id(*cls));
2392
2393 process_comment(*cls, c);
2394 set_source_location(*cls, c);
2395
2396 if (c.skip())
2397 return {};
2398
2399 c.set_style(c.style_spec());
2400
2401 return c_ptr;
2402}

◆ create_objc_method_model()

std::unique_ptr< clanguml::sequence_diagram::model::objc_method > clanguml::sequence_diagram::visitor::translation_unit_visitor::create_objc_method_model ( clang::ObjCMethodDecl *  cls)
private

Definition at line 3054 of file translation_unit_visitor.cc.

3056{
3057 auto method_model_ptr =
3058 std::make_unique<sequence_diagram::model::objc_method>(
3059 config().using_namespace());
3060
3061 common::model::namespace_ ns{declaration->getQualifiedNameAsString()};
3062 auto method_name = ns.name();
3063 method_model_ptr->set_method_name(method_name);
3064 ns.pop_back();
3065 method_model_ptr->set_name(ns.name());
3066 method_model_ptr->set_namespace({});
3067
3068 clang::Decl *parent_decl = declaration->getClassInterface();
3069
3070 if (parent_decl == nullptr) {
3071 LOG_DBG("Cannot find ObjC interface for method, probably it is a "
3072 "protocol {} [{}]",
3073 method_name,
3074 declaration->getLocation().printToString(source_manager()));
3075 return {};
3076 }
3077
3078 LOG_DBG("Getting ObjC method's interface with local id {}",
3079 parent_decl->getID());
3080
3081 const auto maybe_method_class = get_participant<model::class_>(parent_decl);
3082
3083 if (!maybe_method_class) {
3084 LOG_DBG("Cannot find parent class_ for method {} in class {}",
3085 declaration->getQualifiedNameAsString(),
3086 declaration->getClassInterface()->getQualifiedNameAsString());
3087 return {};
3088 }
3089
3090 const auto &method_class = maybe_method_class.value();
3091
3092 method_model_ptr->is_void(declaration->getReturnType()->isVoidType());
3093
3094 method_model_ptr->set_class_id(method_class.id());
3095 method_model_ptr->set_class_full_name(method_class.full_name(false));
3096 method_model_ptr->set_name(get_participant(method_model_ptr->class_id())
3097 .value()
3098 .full_name_no_ns() +
3099 "::" + declaration->getNameAsString());
3100
3101 method_model_ptr->return_type(common::to_string(
3102 declaration->getReturnType(), declaration->getASTContext()));
3103
3104 for (const auto *param : declaration->parameters()) {
3105 auto parameter_type =
3106 common::to_string(param->getType(), param->getASTContext());
3108 parameter_type = simplify_system_template(parameter_type);
3109
3110 std::string parameter_str = parameter_type;
3111 if (config().generate_method_argument_names()) {
3112 parameter_str += " " + param->getNameAsString();
3113 }
3114
3115 method_model_ptr->add_parameter(parameter_type);
3116 }
3117
3118 return method_model_ptr;
3119}

◆ create_objc_protocol_model()

std::unique_ptr< clanguml::sequence_diagram::model::class_ > clanguml::sequence_diagram::visitor::translation_unit_visitor::create_objc_protocol_model ( clang::ObjCProtocolDecl *  cls)
private

Definition at line 2349 of file translation_unit_visitor.cc.

2351{
2352 assert(cls != nullptr);
2353
2354 auto c_ptr{std::make_unique<clanguml::sequence_diagram::model::class_>(
2355 config().using_namespace())};
2356 auto &c = *c_ptr;
2357
2358 auto qualified_name = cls->getQualifiedNameAsString();
2359
2360 c.is_objc_interface();
2361
2362 c.set_name(cls->getQualifiedNameAsString());
2363 c.set_id(common::to_id(*cls));
2364
2365 process_comment(*cls, c);
2366 set_source_location(*cls, c);
2367
2368 if (c.skip())
2369 return {};
2370
2371 c.set_style(c.style_spec());
2372
2373 return c_ptr;
2374}

◆ ensure_activity_exists()

void clanguml::sequence_diagram::visitor::translation_unit_visitor::ensure_activity_exists ( const model::message m)
private

Definition at line 1897 of file translation_unit_visitor.cc.

1898{
1899 if (diagram().sequences().count(m.from()) == 0) {
1900 model::activity a{m.from()};
1901 diagram().sequences().insert({m.from(), std::move(a)});
1902 }
1903
1904 // Maintain reverse graph of activity callers
1905 activity_callers_[m.to()].emplace(m.from());
1906}

◆ ensure_lambda_messages_have_operator_as_target()

void clanguml::sequence_diagram::visitor::translation_unit_visitor::ensure_lambda_messages_have_operator_as_target ( )
private

Definition at line 2943 of file translation_unit_visitor.cc.

2944{
2945 for (auto &[id, activity] : diagram().sequences()) {
2946 for (auto &m : activity.messages()) {
2947 auto participant = diagram().get_participant<model::class_>(m.to());
2948
2949 if (participant && participant.value().is_lambda() &&
2950 participant.value().lambda_operator_id().value() != 0) {
2951 LOG_DBG("Changing lambda expression target id from {} to {}",
2952 m.to(), participant.value().lambda_operator_id());
2953
2954 m.set_to(participant.value().lambda_operator_id());
2955 m.set_message_name("operator()");
2956
2958 }
2959 }
2960 }
2961}

◆ finalize()

void clanguml::sequence_diagram::visitor::translation_unit_visitor::finalize ( )

Finalize diagram model for this translation unit.

Definition at line 2927 of file translation_unit_visitor.cc.

2928{
2930
2931 // Change all messages with target set to an id of a lambda expression to
2932 // to the ID of their operator() - this is necessary, as some calls to
2933 // lambda expressions are visited before the actual lambda expressions
2934 // are visited...
2936
2938
2939 if (config().inline_lambda_messages())
2940 diagram().inline_lambda_operator_calls();
2941}

◆ generate_message_from_comment()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::generate_message_from_comment ( model::message m) const
private

Initializes model message from comment call directive.

Parameters
mMessage instance
Returns
True, if the comment associated with the call expression contained a call directive and it was parsed correctly.

Definition at line 1908 of file translation_unit_visitor.cc.

1910{
1911 auto generated_message_from_comment{false};
1912 for (const auto &decorator : m.decorators()) {
1913 auto call_decorator =
1914 std::dynamic_pointer_cast<decorators::call>(decorator);
1915 if (call_decorator &&
1916 call_decorator->applies_to_diagram(config().name)) {
1917 m.set_to(common::to_id(call_decorator->callee));
1918 generated_message_from_comment = true;
1919 break;
1920 }
1921 }
1922 return generated_message_from_comment;
1923}

◆ get_expression_comment()

std::optional< std::pair< unsigned int, std::string > > clanguml::sequence_diagram::visitor::translation_unit_visitor::get_expression_comment ( const clang::SourceManager &  sm,
const clang::ASTContext &  context,
eid_t  caller_id,
const clang::Stmt *  stmt 
)
private

Definition at line 3338 of file translation_unit_visitor.cc.

3341{
3342 const auto *raw_comment =
3344
3345 if (raw_comment == nullptr)
3346 return {};
3347
3348 if (!caller_id.is_global() &&
3350 .emplace(caller_id.ast_local_value(), raw_comment)
3351 .second) {
3352 return {};
3353 }
3354
3355 const auto &[decorators, stripped_comment] = decorators::parse(
3356 raw_comment->getFormattedText(sm, sm.getDiagnostics()));
3357
3358 if (stripped_comment.empty())
3359 return {};
3360
3361 return {{raw_comment->getBeginLoc().getHashValue(), stripped_comment}};
3362}

◆ get_participant() [1/5]

template<typename T = model::participant>
common::optional_ref< T > clanguml::sequence_diagram::visitor::translation_unit_visitor::get_participant ( const clang::Decl *  decl)
inline

Get participant by declaration.

Template Parameters
TParticipant type
Parameters
declClang entity declaration
Returns
Optional reference to participant diagram element

Definition at line 200 of file translation_unit_visitor.h.

201 {
202 assert(decl != nullptr);
203
204 auto unique_participant_id = get_unique_id(eid_t{decl->getID()});
205 if (!unique_participant_id.has_value())
206 return {};
207
208 return get_participant<T>(unique_participant_id.value());
209 }

◆ get_participant() [2/5]

template<typename T = model::participant>
common::optional_ref< T > clanguml::sequence_diagram::visitor::translation_unit_visitor::get_participant ( const clang::Decl *  decl) const
inline

Get participant by declaration.

Template Parameters
TParticipant type
Parameters
declClang entity declaration
Returns
Optional reference to participant diagram element

Definition at line 219 of file translation_unit_visitor.h.

220 {
221 assert(decl != nullptr);
222
223 auto unique_participant_id = get_unique_id(eid_t{decl->getID()});
224 if (!unique_participant_id.has_value())
225 return {};
226
227 return get_participant<T>(unique_participant_id.value());
228 }

◆ get_participant() [3/5]

template<typename T = model::participant>
common::optional_ref< T > clanguml::sequence_diagram::visitor::translation_unit_visitor::get_participant ( const eid_t  id)
inline

Get participant by global element id.

Template Parameters
TParticipant type
Parameters
idGlobal element id
Returns
Optional reference to participant diagram element

Definition at line 238 of file translation_unit_visitor.h.

239 {
240 if (diagram().participants().find(id) == diagram().participants().end())
241 return {};
242
243 return common::optional_ref<T>(
244 *(static_cast<T *>(diagram().participants().at(id).get())));
245 }

◆ get_participant() [4/5]

template<typename T = sequence_diagram::model::class_>
T & clanguml::sequence_diagram::visitor::translation_unit_visitor::get_participant ( eid_t  element_id,
T &  fallback_model 
)
inlineprivate

Get existing participant or fallback to provided model.

Parameters
element_idID of the participant to lookup
fallback_modelFallback model to use if participant doesn't exist
Returns
Reference to existing participant or fallback model

Definition at line 300 of file translation_unit_visitor.h.

301 {
302 return diagram().get_participant<T>(element_id).has_value()
303 ? *diagram().get_participant<T>(element_id).get()
304 : fallback_model;
305 }

◆ get_participant() [5/5]

template<typename T = model::participant>
common::optional_ref< T > clanguml::sequence_diagram::visitor::translation_unit_visitor::get_participant ( eid_t  id) const
inline

Get participant by global element id.

Template Parameters
TParticipant type
Parameters
idGlobal element id
Returns
Optional reference to participant diagram element

Definition at line 255 of file translation_unit_visitor.h.

256 {
257 if (diagram().participants().find(id) == diagram().participants().end())
258 return {};
259
260 return common::optional_ref<T>(
261 *(static_cast<T *>(diagram().participants().at(id).get())));
262 }

◆ get_unique_id()

std::optional< eid_t > clanguml::sequence_diagram::visitor::translation_unit_visitor::get_unique_id ( eid_t  local_id) const

Retrieve the global clang-uml entity id based on the Clang local id.

Parameters
local_idAST local element id
Returns
Global diagram element id

Definition at line 2562 of file translation_unit_visitor.cc.

2564{
2565 if (local_id.is_global())
2566 return local_id;
2567
2568 return id_mapper().get_global_id(local_id);
2569}

◆ is_callee_valid_template_specialization()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::is_callee_valid_template_specialization ( const clang::CXXDependentScopeMemberExpr *  dependent_member_expr) const
private

Check, the callee is a template specialization.

Parameters
dependent_member_exprDependent member expression
Returns
True, if the callee is a template specialization

Definition at line 2320 of file translation_unit_visitor.cc.

2322{
2323 if (dependent_member_expr == nullptr)
2324 return false;
2325
2326 if (dependent_member_expr->getBaseType().isNull())
2327 return false;
2328
2329 const auto *tst = dependent_member_expr->getBaseType()
2330 ->getAs<clang::TemplateSpecializationType>();
2331
2332 if (tst == nullptr)
2333 return false;
2334
2335 return !(tst->isPointerType());
2336}

◆ is_smart_pointer()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::is_smart_pointer ( const clang::TemplateDecl *  primary_template) const
private

Check if template is a smart pointer.

Parameters
primary_templateTemplate declaration
Returns
True, if template declaration is a smart pointer

Definition at line 2338 of file translation_unit_visitor.cc.

2340{
2341 return primary_template->getQualifiedNameAsString().find(
2342 "std::unique_ptr") == 0 ||
2343 primary_template->getQualifiedNameAsString().find("std::shared_ptr") ==
2344 0 ||
2345 primary_template->getQualifiedNameAsString().find("std::weak_ptr") == 0;
2346}

◆ lambda_source_location()

std::string clanguml::sequence_diagram::visitor::translation_unit_visitor::lambda_source_location ( const clang::SourceLocation &  source_location) const
private

Render lambda source location to string.

Returns exact source code location of the lambda expression in the form <filepath>:<line>:<column>.

The filepath is relative to the relative_to config option.

Parameters
source_locationClang SourceLocation instance associated with lambda expression
Returns
String representation of the location

Definition at line 2683 of file translation_unit_visitor.cc.

2685{
2686 const auto file_line =
2687 source_manager().getSpellingLineNumber(source_location);
2688 const auto file_column =
2689 source_manager().getSpellingColumnNumber(source_location);
2690 const std::string file_name =
2691 config()
2692 .make_path_relative(
2693 source_manager().getFilename(source_location).str())
2694 .string();
2695 return fmt::format("{}:{}:{}", file_name, file_line, file_column);
2696}

◆ make_lambda_name()

std::string clanguml::sequence_diagram::visitor::translation_unit_visitor::make_lambda_name ( const clang::CXXRecordDecl *  cls) const
private

Assuming cls is a lambda, create it's full name.

Note
Currently, lambda names are generated using their source code location including file path, line and column to ensure unique names.
Parameters
clsLambda declaration
Returns
Full lambda unique name

Definition at line 2698 of file translation_unit_visitor.cc.

2700{
2701 std::string result;
2702 const auto location = cls->getLocation();
2703 const std::string source_location{lambda_source_location(location)};
2704
2705 const auto maybe_lambda_caller_id = context().lambda_caller_id();
2706 if (maybe_lambda_caller_id.has_value()) {
2707 // Parent is also a lambda (this id points to a lambda operator())
2708 std::string parent_lambda_class_name{"()"};
2709 if (diagram().get_participant<model::method>(
2710 maybe_lambda_caller_id.value())) {
2711 auto parent_lambda_class_id =
2712 diagram()
2713 .get_participant<model::method>(
2714 maybe_lambda_caller_id.value())
2715 .value()
2716 .class_id();
2717
2718 if (diagram().get_participant<model::class_>(
2719 parent_lambda_class_id)) {
2720 parent_lambda_class_name =
2721 diagram()
2722 .get_participant<model::class_>(parent_lambda_class_id)
2723 .value()
2724 .full_name(false);
2725 }
2726 }
2727
2728 result = fmt::format(
2729 "{}##(lambda {})", parent_lambda_class_name, source_location);
2730 }
2731 else if (context().caller_id().value() != 0 &&
2732 get_participant(context().caller_id()).has_value()) {
2733 auto parent_full_name =
2734 get_participant(context().caller_id()).value().full_name_no_ns();
2735
2736 result =
2737 fmt::format("{}##(lambda {})", parent_full_name, source_location);
2738 }
2739 else {
2740 result = fmt::format("(lambda {})", source_location);
2741 }
2742
2743 return result;
2744}

◆ pop_message_to_diagram() [1/7]

void clanguml::sequence_diagram::visitor::translation_unit_visitor::pop_message_to_diagram ( clang::CallExpr *  expr)
private

Move a message model to diagram.

Parameters
exprCall expression

Definition at line 2788 of file translation_unit_visitor.cc.

2789{
2790 assert(expr != nullptr);
2791
2792 // Skip if no message was generated from this expr
2793 if (call_expr_message_map_.find(expr) == call_expr_message_map_.end()) {
2794 return;
2795 }
2796
2797 if (call_expr_message_map_.at(expr).empty())
2798 return;
2799
2800 while (!call_expr_message_map_.at(expr).empty()) {
2801 auto msg = call_expr_message_map_.at(expr).front();
2802
2803 auto caller_id = msg.from();
2804
2805 if (caller_id == 0)
2806 return;
2807
2808 if (diagram().has_activity(caller_id))
2809 diagram().get_activity(caller_id).add_message(std::move(msg));
2810 else
2811 LOG_DBG("Skipping message due to missing activity: {}", caller_id);
2812
2813 call_expr_message_map_.at(expr).pop_front();
2814 }
2815
2816 call_expr_message_map_.erase(expr);
2817}

◆ pop_message_to_diagram() [2/7]

void clanguml::sequence_diagram::visitor::translation_unit_visitor::pop_message_to_diagram ( clang::CoawaitExpr *  expr)
private

Definition at line 2891 of file translation_unit_visitor.cc.

2892{
2893 assert(expr != nullptr);
2894
2895 // Skip if no message was generated from this expr
2896 if (co_await_stmt_message_map_.find(expr) ==
2898 return;
2899 }
2900
2901 auto msg = std::move(co_await_stmt_message_map_.at(expr));
2902
2903 auto caller_id = msg.from();
2904 diagram().get_activity(caller_id).add_message(std::move(msg));
2905
2906 co_await_stmt_message_map_.erase(expr);
2907}

◆ pop_message_to_diagram() [3/7]

void clanguml::sequence_diagram::visitor::translation_unit_visitor::pop_message_to_diagram ( clang::CoreturnStmt *  stmt)
private

Definition at line 2855 of file translation_unit_visitor.cc.

2856{
2857 assert(stmt != nullptr);
2858
2859 // Skip if no message was generated from this expr
2860 if (co_return_stmt_message_map_.find(stmt) ==
2862 return;
2863 }
2864
2865 auto msg = std::move(co_return_stmt_message_map_.at(stmt));
2866
2867 auto caller_id = msg.from();
2868 diagram().get_activity(caller_id).add_message(std::move(msg));
2869
2870 co_return_stmt_message_map_.erase(stmt);
2871}

◆ pop_message_to_diagram() [4/7]

void clanguml::sequence_diagram::visitor::translation_unit_visitor::pop_message_to_diagram ( clang::CoyieldExpr *  expr)
private

Definition at line 2873 of file translation_unit_visitor.cc.

2874{
2875 assert(expr != nullptr);
2876
2877 // Skip if no message was generated from this expr
2878 if (co_yield_stmt_message_map_.find(expr) ==
2880 return;
2881 }
2882
2883 auto msg = std::move(co_yield_stmt_message_map_.at(expr));
2884
2885 auto caller_id = msg.from();
2886 diagram().get_activity(caller_id).add_message(std::move(msg));
2887
2888 co_yield_stmt_message_map_.erase(expr);
2889}

◆ pop_message_to_diagram() [5/7]

void clanguml::sequence_diagram::visitor::translation_unit_visitor::pop_message_to_diagram ( clang::CXXConstructExpr *  expr)
private

Definition at line 2819 of file translation_unit_visitor.cc.

2821{
2822 assert(expr != nullptr);
2823
2824 // Skip if no message was generated from this expr
2825 if (construct_expr_message_map_.find(expr) ==
2827 return;
2828 }
2829
2830 auto msg = std::move(construct_expr_message_map_.at(expr));
2831
2832 auto caller_id = msg.from();
2833 diagram().get_activity(caller_id).add_message(std::move(msg));
2834
2835 construct_expr_message_map_.erase(expr);
2836}

◆ pop_message_to_diagram() [6/7]

void clanguml::sequence_diagram::visitor::translation_unit_visitor::pop_message_to_diagram ( clang::ObjCMessageExpr *  expr)
private

Definition at line 2909 of file translation_unit_visitor.cc.

2911{
2912 assert(expr != nullptr);
2913
2914 // Skip if no message was generated from this expr
2915 if (objc_message_map_.find(expr) == objc_message_map_.end()) {
2916 return;
2917 }
2918
2919 auto msg = std::move(objc_message_map_.at(expr));
2920
2921 auto caller_id = msg.from();
2922 diagram().get_activity(caller_id).add_message(std::move(msg));
2923
2924 objc_message_map_.erase(expr);
2925}

◆ pop_message_to_diagram() [7/7]

void clanguml::sequence_diagram::visitor::translation_unit_visitor::pop_message_to_diagram ( clang::ReturnStmt *  stmt)
private

Definition at line 2838 of file translation_unit_visitor.cc.

2839{
2840 assert(stmt != nullptr);
2841
2842 // Skip if no message was generated from this expr
2843 if (return_stmt_message_map_.find(stmt) == return_stmt_message_map_.end()) {
2844 return;
2845 }
2846
2847 auto msg = std::move(return_stmt_message_map_.at(stmt));
2848
2849 auto caller_id = msg.from();
2850 diagram().get_activity(caller_id).add_message(std::move(msg));
2851
2852 return_stmt_message_map_.erase(stmt);
2853}

◆ process_callee()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::process_callee ( clang::CallExpr *  expr,
model::message m,
bool  generated_message_from_comment 
)
private

Definition at line 1504 of file translation_unit_visitor.cc.

1506{
1507 bool result = true;
1508
1509 if (expr == nullptr)
1510 return false;
1511
1512 if (generated_message_from_comment) {
1513 LOG_DBG(
1514 "Message for this call expression is taken from comment directive");
1515 }
1516 //
1517 // Call to a CUDA kernel function
1518 //
1519 else if (const auto *cuda_call_expr =
1520 llvm::dyn_cast_or_null<clang::CUDAKernelCallExpr>(expr);
1521 cuda_call_expr != nullptr) {
1522 result = process_cuda_kernel_call_expression(m, cuda_call_expr);
1523 }
1524 //
1525 // Call to an overloaded operator
1526 //
1527 else if (const auto *operator_call_expr =
1528 llvm::dyn_cast_or_null<clang::CXXOperatorCallExpr>(expr);
1529 operator_call_expr != nullptr) {
1530
1531 result = process_operator_call_expression(m, operator_call_expr);
1532 }
1533 //
1534 // Call to a class method
1535 //
1536 else if (const auto *method_call_expr =
1537 llvm::dyn_cast_or_null<clang::CXXMemberCallExpr>(expr);
1538 method_call_expr != nullptr) {
1539
1540 result = process_class_method_call_expression(m, method_call_expr);
1541 }
1542 //
1543 // Call to function or template
1544 //
1545 else {
1546 auto *callee_decl = expr->getCalleeDecl();
1547
1548 if (callee_decl == nullptr) {
1549 LOG_DBG("Cannot get callee declaration - trying direct function "
1550 "callee...");
1551
1552 callee_decl = expr->getDirectCallee();
1553
1554 if (callee_decl != nullptr)
1555 LOG_DBG("Found function/method callee in: {}",
1556 common::to_string(expr));
1557 }
1558
1559 if (callee_decl == nullptr) {
1560 //
1561 // Call to a method of a class template
1562 //
1563 if (llvm::dyn_cast_or_null<clang::CXXDependentScopeMemberExpr>(
1564 expr->getCallee()) != nullptr) {
1566 }
1567 //
1568 // Unresolved lookup expression are sometimes calls to template
1569 // functions
1570 //
1571 else if (llvm::dyn_cast_or_null<clang::UnresolvedLookupExpr>(
1572 expr->getCallee()) != nullptr) {
1574 }
1575 else if (common::is_lambda_call(expr)) {
1576 LOG_DBG("Processing lambda expression callee");
1577 result = process_lambda_call_expression(m, expr);
1578 }
1579 else if (llvm::dyn_cast_or_null<clang::DependentScopeDeclRefExpr>(
1580 expr->getCallee()) != nullptr) {
1581 LOG_DBG("Processing dependent scope declaration expression "
1582 "callee - not able to infer the template parameter "
1583 "type at this point: {}",
1584 expr->getBeginLoc().printToString(source_manager()));
1585 }
1586 else {
1587 LOG_DBG("Found unsupported callee decl type for: {} at {}",
1588 common::to_string(expr),
1589 expr->getBeginLoc().printToString(source_manager()));
1590 }
1591 }
1592 else {
1593 auto success = process_function_call_expression(m, expr);
1594
1595 if (!success) {
1596 LOG_DBG("Skipping call expression at: {}",
1597 expr->getBeginLoc().printToString(source_manager()));
1598
1599 result = false;
1600 }
1601 }
1602 }
1603
1604 return result;
1605}

◆ process_class_method_call_expression()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::process_class_method_call_expression ( model::message m,
const clang::CXXMemberCallExpr *  method_call_expr 
)
private

Handle a class method call expresion.

Parameters
mMessage model
method_call_exprOperator call expression
Returns
True, if m contains now a valid call expression model

Definition at line 2126 of file translation_unit_visitor.cc.

2128{
2129 // Get callee declaration as methods parent
2130 const auto *method_decl = method_call_expr->getMethodDecl();
2131
2132 if (method_decl == nullptr)
2133 return false;
2134
2135 std::string method_name = method_decl->getQualifiedNameAsString();
2136
2137 const auto *callee_decl =
2138 method_decl != nullptr ? method_decl->getParent() : nullptr;
2139
2140 if (callee_decl == nullptr)
2141 return false;
2142
2143 if (!should_include(callee_decl) || !should_include(method_decl))
2144 return false;
2145
2146 m.set_to(eid_t{method_decl->getID()});
2147 m.set_message_name(method_decl->getNameAsString());
2148 m.set_return_type(
2149 method_call_expr->getCallReturnType(*context().get_ast_context())
2150 .getAsString());
2151
2152 LOG_TRACE("Set callee method id {} for method name {}", m.to(),
2153 method_decl->getQualifiedNameAsString());
2154
2155 diagram().add_active_participant(eid_t{method_decl->getID()});
2156
2157 return true;
2158}

◆ process_class_template_method_call_expression()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::process_class_template_method_call_expression ( model::message m,
const clang::CallExpr *  expr 
)
private

Handle a class template method call expresion.

Parameters
mMessage model
exprClass template method call expression
Returns
True, if m contains now a valid call expression model

Definition at line 2160 of file translation_unit_visitor.cc.

2162{
2163 const auto *dependent_member_callee =
2164 clang::dyn_cast_or_null<clang::CXXDependentScopeMemberExpr>(
2165 expr->getCallee());
2166
2167 if (dependent_member_callee == nullptr)
2168 return false;
2169
2170 if (is_callee_valid_template_specialization(dependent_member_callee)) {
2171 if (const auto *tst = dependent_member_callee->getBaseType()
2172 ->getAs<clang::TemplateSpecializationType>();
2173 tst != nullptr) {
2174 const auto *template_declaration =
2175 tst->getTemplateName().getAsTemplateDecl();
2176
2177 std::string callee_method_full_name;
2178
2179 // First check if the primary template is already in the
2180 // participants map
2181 if (get_participant(template_declaration).has_value()) {
2182 callee_method_full_name = get_participant(template_declaration)
2183 .value()
2184 .full_name(false) +
2185 "::" + dependent_member_callee->getMember().getAsString();
2186
2187 for (const auto &[id, p] : diagram().participants()) {
2188 const auto p_full_name = p->full_name(false);
2189
2190 if (p_full_name.find(callee_method_full_name + "(") == 0) {
2191 // TODO: This selects the first matching template method
2192 // without considering arguments!!!
2193 m.set_to(id);
2194 break;
2195 }
2196 }
2197 }
2198 // Otherwise check if it is a smart pointer
2199 else if (is_smart_pointer(template_declaration)) {
2200 const auto *argument_template =
2201 template_declaration->getTemplateParameters()
2202 ->asArray()
2203 .front();
2204
2205 if (get_participant(argument_template).has_value()) {
2206 callee_method_full_name = get_participant(argument_template)
2207 .value()
2208 .full_name(false) +
2209 "::" +
2210 dependent_member_callee->getMember().getAsString();
2211
2212 for (const auto &[id, p] : diagram().participants()) {
2213 const auto p_full_name = p->full_name(false);
2214 if (p_full_name.find(callee_method_full_name + "(") ==
2215 0) {
2216 // TODO: This selects the first matching template
2217 // method without considering arguments!!!
2218 m.set_to(id);
2219 break;
2220 }
2221 }
2222 }
2223 else
2224 return false;
2225 }
2226
2227 m.set_message_name(
2228 dependent_member_callee->getMember().getAsString());
2229
2230 if (const auto maybe_id =
2231 get_unique_id(eid_t{template_declaration->getID()});
2232 maybe_id.has_value())
2233 diagram().add_active_participant(maybe_id.value());
2234 }
2235 }
2236 else {
2237 LOG_DBG("Skipping call due to unresolvable "
2238 "CXXDependentScopeMemberExpr at {}",
2239 expr->getBeginLoc().printToString(source_manager()));
2240 }
2241
2242 return true;
2243}

◆ process_class_template_specialization()

std::unique_ptr< model::class_ > clanguml::sequence_diagram::visitor::translation_unit_visitor::process_class_template_specialization ( clang::ClassTemplateSpecializationDecl *  cls)
private

Definition at line 2641 of file translation_unit_visitor.cc.

2643{
2644 auto c_ptr{std::make_unique<model::class_>(config().using_namespace())};
2645
2647
2648 auto &template_instantiation = *c_ptr;
2649
2650 // TODO: refactor to method get_qualified_name()
2651 auto qualified_name = cls->getQualifiedNameAsString();
2652 util::replace_all(qualified_name, "(anonymous namespace)", "");
2653 util::replace_all(qualified_name, "::::", "::");
2654
2655 common::model::namespace_ ns{qualified_name};
2656 ns.pop_back();
2657 template_instantiation.set_name(cls->getNameAsString());
2658 template_instantiation.set_namespace(ns);
2659
2660 template_instantiation.is_struct(cls->isStruct());
2661
2662 process_comment(*cls, template_instantiation);
2663 set_source_location(*cls, template_instantiation);
2664 set_owning_module(*cls, template_instantiation);
2665
2666 if (template_instantiation.skip())
2667 return {};
2668
2669 template_instantiation.set_id(
2670 common::to_id(template_instantiation.full_name(false)));
2671
2672 set_unique_id(cls->getID(), template_instantiation.id());
2673
2674 return c_ptr;
2675}

◆ process_construct_expression()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::process_construct_expression ( model::message m,
const clang::CXXConstructExpr *  construct_expr 
)
private

Handle CXX constructor call.

Parameters
mMessage model
construct_exprCXX Construct expression
Returns
True, if m contains a valid constructor call

Definition at line 2053 of file translation_unit_visitor.cc.

2055{
2056 const auto *constructor = construct_expr->getConstructor();
2057 if (constructor == nullptr)
2058 return false;
2059
2060 const auto *constructor_parent = constructor->getParent();
2061 if (constructor_parent == nullptr)
2062 return false;
2063
2064 LOG_DBG("Constructor '{}' call expression to {} at {}",
2065 construct_expr->getConstructor()->getNameAsString(),
2066 constructor->getID(),
2067 construct_expr->getBeginLoc().printToString(source_manager()));
2068
2069 m.set_to(id_mapper().resolve_or(eid_t{constructor->getID()}));
2070 m.set_message_name(
2071 fmt::format("{}::{}", constructor_parent->getQualifiedNameAsString(),
2072 constructor_parent->getNameAsString()));
2073
2074 diagram().add_active_participant(eid_t{constructor->getID()});
2075
2076 return true;
2077}

◆ process_cuda_kernel_call_expression()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::process_cuda_kernel_call_expression ( model::message m,
const clang::CUDAKernelCallExpr *  cuda_call_expr 
)
private

Definition at line 1986 of file translation_unit_visitor.cc.

1988{
1989 const auto *callee_decl = expr->getCalleeDecl();
1990
1991 if (callee_decl == nullptr)
1992 return false;
1993
1994 const auto *callee_function = callee_decl->getAsFunction();
1995
1996 if (callee_function == nullptr)
1997 return false;
1998
1999 if (!should_include(callee_function))
2000 return false;
2001
2002 // Skip free functions declared in files outside of included paths
2003 if (config().combine_free_functions_into_file_participants() &&
2004 !diagram().should_include(common::model::source_file{m.file()}))
2005 return false;
2006
2007 auto callee_name = callee_function->getQualifiedNameAsString() + "()";
2008
2009 m.set_to(id_mapper().resolve_or(eid_t{callee_function->getID()}));
2010 m.set_message_name(callee_name.substr(0, callee_name.size() - 2));
2011
2012 return true;
2013}

◆ process_function_call_expression()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::process_function_call_expression ( model::message m,
const clang::CallExpr *  expr 
)
private

Handle a function call expresion.

Parameters
mMessage model
exprFunction call expression
Returns
True, if m contains now a valid call expression model

Definition at line 2245 of file translation_unit_visitor.cc.

2247{
2248 const auto *callee_decl = expr->getCalleeDecl();
2249
2250 if (callee_decl == nullptr)
2251 return false;
2252
2253 const auto *callee_function = callee_decl->getAsFunction();
2254
2255 if (callee_function == nullptr)
2256 return false;
2257
2258 if (!should_include(callee_function))
2259 return false;
2260
2261 // Skip free functions declared in files outside of included paths
2262 if (config().combine_free_functions_into_file_participants() &&
2263 !diagram().should_include(common::model::source_file{m.file()}))
2264 return false;
2265
2266 auto callee_name = callee_function->getQualifiedNameAsString() + "()";
2267
2268 m.set_to(id_mapper().resolve_or(eid_t{callee_function->getID()}));
2269 m.set_message_name(callee_name.substr(0, callee_name.size() - 2));
2270
2271 return true;
2272}

◆ process_function_parameters()

void clanguml::sequence_diagram::visitor::translation_unit_visitor::process_function_parameters ( const clang::FunctionDecl &  declaration,
model::function method_model 
) const
private

Definition at line 3183 of file translation_unit_visitor.cc.

3185{
3186 for (const auto *param : declaration.parameters()) {
3187 auto parameter_type =
3188 common::to_string(param->getType(), param->getASTContext());
3190 parameter_type = simplify_system_template(parameter_type);
3191
3192 std::string parameter_str = config().using_namespace().relative(
3193 simplify_system_template(parameter_type));
3194 if (config().generate_method_argument_names()) {
3195 parameter_str += " " + param->getNameAsString();
3196 }
3197
3198 method_model.add_parameter(parameter_str);
3199 }
3200}

◆ process_lambda_call_expression()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::process_lambda_call_expression ( model::message m,
const clang::CallExpr *  expr 
) const
private

Definition at line 2274 of file translation_unit_visitor.cc.

2276{
2277 const auto *lambda_expr =
2278 clang::dyn_cast_or_null<clang::LambdaExpr>(expr->getCallee());
2279
2280 if (lambda_expr == nullptr)
2281 return true;
2282
2283 const auto lambda_class_id = eid_t{lambda_expr->getLambdaClass()->getID()};
2284 m.set_to(id_mapper().resolve_or(eid_t{lambda_class_id}));
2285
2286 return true;
2287}

◆ process_objc_message_expression()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::process_objc_message_expression ( model::message m,
const clang::ObjCMessageExpr *  message_expr 
)
private

Definition at line 2079 of file translation_unit_visitor.cc.

2081{
2082 const auto *method_decl = message_expr->getMethodDecl();
2083
2084 if (method_decl == nullptr)
2085 return false;
2086
2087 std::string method_name = method_decl->getQualifiedNameAsString();
2088
2089 if (message_expr->getReceiverInterface() == nullptr)
2090 return false;
2091
2092 const auto *callee_decl = message_expr->getReceiverInterface();
2093
2094 if (callee_decl == nullptr)
2095 return false;
2096
2097 if (!should_include(callee_decl) || !should_include(method_decl))
2098 return false;
2099
2100 if (callee_decl->getImplementation() != nullptr &&
2101 callee_decl->getImplementation()->getMethod(method_decl->getSelector(),
2102 method_decl->isInstanceMethod(), true) != nullptr) {
2103 const auto *impl_method_decl =
2104 callee_decl->getImplementation()->getMethod(
2105 method_decl->getSelector(), method_decl->isInstanceMethod(),
2106 true);
2107 m.set_to(eid_t{impl_method_decl->getID()});
2108 }
2109 else {
2110 m.set_to(eid_t{method_decl->getID()});
2111 }
2112
2113 m.set_message_name(method_decl->getNameAsString());
2114 m.set_return_type(
2115 message_expr->getCallReturnType(*context().get_ast_context())
2116 .getAsString());
2117
2118 LOG_TRACE("Set callee ObjC method id {} for method name {}", m.to(),
2119 method_decl->getQualifiedNameAsString());
2120
2121 diagram().add_active_participant(eid_t{method_decl->getID()});
2122
2123 return true;
2124}

◆ process_operator_call_expression()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::process_operator_call_expression ( model::message m,
const clang::CXXOperatorCallExpr *  operator_call_expr 
)
private

Handle a operator call expression.

Parameters
mMessage model
operator_call_exprOperator call expression
Returns
True, if m contains now a valid call expression model

Definition at line 2015 of file translation_unit_visitor.cc.

2017{
2018 if (operator_call_expr->getCalleeDecl() == nullptr)
2019 return false;
2020
2021 LOG_DBG("Operator '{}' call expression to {} at {}",
2022 getOperatorSpelling(operator_call_expr->getOperator()),
2023 operator_call_expr->getCalleeDecl()->getID(),
2024 operator_call_expr->getBeginLoc().printToString(source_manager()));
2025
2026 // Handle the case if the callee is a lambda
2027 if (const auto *lambda_method = clang::dyn_cast<clang::CXXMethodDecl>(
2028 operator_call_expr->getCalleeDecl());
2029 lambda_method != nullptr && lambda_method->getParent()->isLambda()) {
2030
2031 LOG_DBG("Operator callee is a lambda: {}",
2032 common::to_string(lambda_method));
2033
2034 const auto source_location{
2035 lambda_source_location(lambda_method->getParent()->getLocation())};
2036
2037 auto lambda_name = make_lambda_name(lambda_method->getParent());
2038
2039 m.set_to(eid_t{lambda_method->getParent()->getID()});
2040 }
2041 else {
2042 const auto operator_ast_id =
2043 operator_call_expr->getCalleeDecl()->getID();
2044 m.set_to(id_mapper().resolve_or(eid_t{operator_ast_id}));
2045 }
2046
2047 m.set_message_name(fmt::format(
2048 "operator{}", getOperatorSpelling(operator_call_expr->getOperator())));
2049
2050 return true;
2051}

◆ process_unresolved_lookup_call_expression()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::process_unresolved_lookup_call_expression ( model::message m,
const clang::CallExpr *  expr 
) const
private

Handle an unresolved lookup call expresion.

Unresolved lookup expression is a reference to a name which Clang was not able to look up during parsing but could not resolve to a specific declaration.

Parameters
mMessage model
exprCall expression
Returns
True, if m contains now a valid call expression model

Definition at line 2289 of file translation_unit_visitor.cc.

2291{
2292 // This is probably a template
2293 const auto *unresolved_expr =
2294 clang::dyn_cast_or_null<clang::UnresolvedLookupExpr>(expr->getCallee());
2295
2296 if (unresolved_expr != nullptr) {
2297 for (const auto *decl : unresolved_expr->decls()) {
2298 if (clang::dyn_cast_or_null<clang::FunctionTemplateDecl>(decl) !=
2299 nullptr) {
2300 const auto *ftd =
2301 clang::dyn_cast_or_null<clang::FunctionTemplateDecl>(decl);
2302 m.set_to(id_mapper().resolve_or(eid_t{ftd->getID()}));
2303 break;
2304 }
2305
2306 if (clang::dyn_cast_or_null<clang::FunctionDecl>(decl) != nullptr) {
2307 const auto *fd =
2308 clang::dyn_cast_or_null<clang::FunctionDecl>(decl);
2309 m.set_to(id_mapper().resolve_or(eid_t{fd->getID()}));
2310 break;
2311 }
2312
2313 LOG_DBG("Unknown unresolved lookup expression");
2314 }
2315 }
2316
2317 return true;
2318}

◆ push_message() [1/7]

void clanguml::sequence_diagram::visitor::translation_unit_visitor::push_message ( clang::CallExpr *  expr,
model::message &&  m 
)
private

Register a message model m with a call expression.

This is used to know whether a model for a specific call expression has already been created, but not yet added to the diagram.

Parameters
exprCall expresion
mMessage model

Definition at line 2746 of file translation_unit_visitor.cc.

2748{
2749 call_expr_message_map_[expr].push_back(std::move(m));
2750}

◆ push_message() [2/7]

void clanguml::sequence_diagram::visitor::translation_unit_visitor::push_message ( clang::CoawaitExpr *  stmt,
model::message &&  m 
)
private

Definition at line 2782 of file translation_unit_visitor.cc.

2784{
2785 co_await_stmt_message_map_.emplace(expr, std::move(m));
2786}

◆ push_message() [3/7]

void clanguml::sequence_diagram::visitor::translation_unit_visitor::push_message ( clang::CoreturnStmt *  stmt,
model::message &&  m 
)
private

Definition at line 2770 of file translation_unit_visitor.cc.

2772{
2773 co_return_stmt_message_map_.emplace(stmt, std::move(m));
2774}

◆ push_message() [4/7]

void clanguml::sequence_diagram::visitor::translation_unit_visitor::push_message ( clang::CoyieldExpr *  stmt,
model::message &&  m 
)
private

Definition at line 2776 of file translation_unit_visitor.cc.

2778{
2779 co_yield_stmt_message_map_.emplace(expr, std::move(m));
2780}

◆ push_message() [5/7]

void clanguml::sequence_diagram::visitor::translation_unit_visitor::push_message ( clang::CXXConstructExpr *  expr,
model::message &&  m 
)
private

Definition at line 2752 of file translation_unit_visitor.cc.

2754{
2755 construct_expr_message_map_.emplace(expr, std::move(m));
2756}

◆ push_message() [6/7]

void clanguml::sequence_diagram::visitor::translation_unit_visitor::push_message ( clang::ObjCMessageExpr *  expr,
model::message &&  m 
)
private

Definition at line 2758 of file translation_unit_visitor.cc.

2760{
2761 objc_message_map_.emplace(expr, std::move(m));
2762}

◆ push_message() [7/7]

void clanguml::sequence_diagram::visitor::translation_unit_visitor::push_message ( clang::ReturnStmt *  stmt,
model::message &&  m 
)
private

Definition at line 2764 of file translation_unit_visitor.cc.

2766{
2767 return_stmt_message_map_.emplace(stmt, std::move(m));
2768}

◆ resolve_ids_to_global()

void clanguml::sequence_diagram::visitor::translation_unit_visitor::resolve_ids_to_global ( )
private

Definition at line 2963 of file translation_unit_visitor.cc.

2964{
2965 std::set<eid_t> active_participants_unique;
2966
2967 // Change all active participants AST local ids to diagram global ids
2968 for (auto id : diagram().active_participants()) {
2969 if (const auto unique_id = get_unique_id(id);
2970 !id.is_global() && unique_id.has_value()) {
2971 active_participants_unique.emplace(unique_id.value());
2972 }
2973 else if (id.is_global()) {
2974 active_participants_unique.emplace(id);
2975 }
2976 }
2977
2978 diagram().active_participants() = std::move(active_participants_unique);
2979
2980 // Change all message callees AST local ids to diagram global ids
2981 for (auto &[id, activity] : diagram().sequences()) {
2982 for (auto &m : activity.messages()) {
2983 if (const auto unique_id = get_unique_id(m.to());
2984 !m.to().is_global() && unique_id.has_value()) {
2985 m.set_to(unique_id.value());
2986 assert(m.to().is_global());
2987 }
2988 }
2989 }
2990}

◆ set_unique_id()

void clanguml::sequence_diagram::visitor::translation_unit_visitor::set_unique_id ( int64_t  local_id,
eid_t  global_id 
)

Store the mapping from local clang entity id (obtained using getID()) method to clang-uml global id.

Todo:
Refactor to ast_id_mapper
Parameters
local_idLocal AST element id
global_idGloba diagram element id

Definition at line 2553 of file translation_unit_visitor.cc.

2554{
2555 LOG_TRACE("Setting local element mapping {} --> {}", local_id, global_id);
2556
2557 assert(global_id.is_global());
2558
2559 id_mapper().add(local_id, global_id);
2560}

◆ should_include() [1/10]

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::should_include ( const clang::CallExpr *  expr) const
private

Check if the diagram should include a call expression.

Parameters
exprCall expression.
Returns
True, if the expression should be included in the diagram.

Definition at line 3251 of file translation_unit_visitor.cc.

3252{
3253 if (context().caller_id() == 0)
3254 return false;
3255
3256 // Skip casts, moves and such
3257 if (expr->isCallToStdMove())
3258 return false;
3259
3260 if (expr->isImplicitCXXThis())
3261 return false;
3262
3263 if (clang::dyn_cast_or_null<clang::ImplicitCastExpr>(expr) != nullptr)
3264 return false;
3265
3266 if (!context().valid())
3267 return false;
3268
3269 const auto expr_file = expr->getBeginLoc().printToString(source_manager());
3270
3271 if (!diagram().should_include(
3272 common::model::source_file{get_file_path(expr_file)}))
3273 return false;
3274
3275 const auto *callee_decl = expr->getCalleeDecl();
3276
3277 if (callee_decl != nullptr) {
3278 const auto *callee_function = callee_decl->getAsFunction();
3279
3280 if ((callee_function == nullptr) || !should_include(callee_function)) {
3281 LOG_DBG("Skipping call expression at {}",
3282 expr->getBeginLoc().printToString(source_manager()));
3283 return false;
3284 }
3285
3286 return should_include(callee_function);
3287 }
3288
3289 return true;
3290}

◆ should_include() [2/10]

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::should_include ( const clang::ClassTemplateDecl *  decl) const
private

Check if the diagram should include a declaration.

Parameters
declClang declaration.
Returns
True, if the entity should be included in the diagram.

Definition at line 3331 of file translation_unit_visitor.cc.

3333{
3335}

◆ should_include() [3/10]

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::should_include ( const clang::CXXMethodDecl *  decl) const
private

Check if the diagram should include a declaration.

Parameters
declClang declaration.
Returns
True, if the entity should be included in the diagram.

Definition at line 3292 of file translation_unit_visitor.cc.

3294{
3295 if (!should_include(decl->getParent()))
3296 return false;
3297
3298 if (!diagram().should_include(
3299 common::access_specifier_to_access_t(decl->getAccess())))
3300 return false;
3301
3302 LOG_DBG("Including method {}", decl->getQualifiedNameAsString());
3303
3304 return true;
3305}

◆ should_include() [4/10]

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::should_include ( const clang::FunctionDecl *  decl) const
private

Check if the diagram should include a declaration.

Parameters
declClang declaration.
Returns
True, if the entity should be included in the diagram.

Definition at line 3319 of file translation_unit_visitor.cc.

3321{
3323}

◆ should_include() [5/10]

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::should_include ( const clang::FunctionTemplateDecl *  decl) const
private

Check if the diagram should include a declaration.

Parameters
declClang declaration.
Returns
True, if the entity should be included in the diagram.

Definition at line 3325 of file translation_unit_visitor.cc.

3327{
3328 return visitor_specialization_t::should_include(decl->getAsFunction());
3329}

◆ should_include() [6/10]

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::should_include ( const clang::LambdaExpr *  expr) const
private

Check if the diagram should include a lambda expression.

Parameters
exprLambda expression.
Returns
True, if the expression should be included in the diagram.

Definition at line 3215 of file translation_unit_visitor.cc.

3217{
3218 if (context().caller_id() == 0)
3219 return false;
3220
3221 if (!context().valid())
3222 return false;
3223
3224 const auto expr_file = expr->getBeginLoc().printToString(source_manager());
3225
3226 if (!diagram().should_include(
3227 common::model::source_file{get_file_path(expr_file)}))
3228 return false;
3229
3230 return true;
3231}

◆ should_include() [7/10]

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::should_include ( const clang::ObjCContainerDecl *  decl) const
private

Check if the diagram should include an ObjC declaration.

Parameters
declClang declaration.
Returns
True, if the entity should be included in the diagram.

Definition at line 3208 of file translation_unit_visitor.cc.

3210{
3212 dynamic_cast<const clang::NamedDecl *>(decl));
3213}

◆ should_include() [8/10]

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::should_include ( const clang::ObjCMessageExpr *  expr) const
private

Check if the diagram should include an ObjC message expression.

Parameters
exprObjC message expression.
Returns
True, if the expression should be included in the diagram.

Definition at line 3233 of file translation_unit_visitor.cc.

3235{
3236 if (context().caller_id() == 0)
3237 return false;
3238
3239 if (!context().valid())
3240 return false;
3241
3242 const auto expr_file = expr->getBeginLoc().printToString(source_manager());
3243
3244 if (!diagram().should_include(
3245 common::model::source_file{get_file_path(expr_file)}))
3246 return false;
3247
3248 return true;
3249}

◆ should_include() [9/10]

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::should_include ( const clang::ObjCMethodDecl *  decl) const
private

Definition at line 3307 of file translation_unit_visitor.cc.

3309{
3310 if (!diagram().should_include(
3311 common::access_specifier_to_access_t(decl->getAccess())))
3312 return false;
3313
3314 LOG_DBG("Including ObjC method {}", decl->getQualifiedNameAsString());
3315
3316 return true;
3317}

◆ should_include() [10/10]

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::should_include ( const clang::TagDecl *  decl) const
private

Check if the diagram should include a declaration.

Parameters
declClang declaration.
Returns
True, if the entity should be included in the diagram.

Definition at line 3202 of file translation_unit_visitor.cc.

3203{
3205 dynamic_cast<const clang::NamedDecl *>(decl));
3206}

◆ simplify_system_template()

std::string clanguml::sequence_diagram::visitor::translation_unit_visitor::simplify_system_template ( const std::string &  full_name) const
private

Definition at line 2677 of file translation_unit_visitor.cc.

2679{
2680 return config().simplify_template_type(full_name);
2681}

◆ tbuilder()

template_builder_t & clanguml::sequence_diagram::visitor::translation_unit_visitor::tbuilder ( )
inlineprivate

Get template builder reference.

Returns
Reference to 'template_builder' instance

Definition at line 581 of file translation_unit_visitor.h.

581{ return template_builder_; }

Member Data Documentation

◆ activity_callers_

std::map<eid_t, std::set<eid_t> > clanguml::sequence_diagram::visitor::translation_unit_visitor::activity_callers_
private

Definition at line 620 of file translation_unit_visitor.h.

◆ already_visited_in_static_declaration_

std::set<const clang::Expr *> clanguml::sequence_diagram::visitor::translation_unit_visitor::already_visited_in_static_declaration_ {}
mutableprivate

Definition at line 624 of file translation_unit_visitor.h.

◆ anonymous_structs_

std::map<int64_t , std::tuple<std::string , common::model::relationship_t, common::model::access_t> > clanguml::sequence_diagram::visitor::translation_unit_visitor::anonymous_structs_
private

Definition at line 618 of file translation_unit_visitor.h.

◆ call_expr_message_map_

std::map<clang::CallExpr *, std::deque<model::message> > clanguml::sequence_diagram::visitor::translation_unit_visitor::call_expr_message_map_
private

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

Definition at line 602 of file translation_unit_visitor.h.

◆ call_expression_context_

call_expression_context clanguml::sequence_diagram::visitor::translation_unit_visitor::call_expression_context_
private

Definition at line 594 of file translation_unit_visitor.h.

◆ co_await_stmt_message_map_

std::map<clang::CoawaitExpr *, model::message> clanguml::sequence_diagram::visitor::translation_unit_visitor::co_await_stmt_message_map_
private

Definition at line 606 of file translation_unit_visitor.h.

◆ co_return_stmt_message_map_

std::map<clang::CoreturnStmt *, model::message> clanguml::sequence_diagram::visitor::translation_unit_visitor::co_return_stmt_message_map_
private

Definition at line 604 of file translation_unit_visitor.h.

◆ co_yield_stmt_message_map_

std::map<clang::CoyieldExpr *, model::message> clanguml::sequence_diagram::visitor::translation_unit_visitor::co_yield_stmt_message_map_
private

Definition at line 605 of file translation_unit_visitor.h.

◆ construct_expr_message_map_

std::map<clang::CXXConstructExpr *, model::message> clanguml::sequence_diagram::visitor::translation_unit_visitor::construct_expr_message_map_
private

Definition at line 609 of file translation_unit_visitor.h.

◆ forward_declarations_

std::map<eid_t, std::unique_ptr<clanguml::sequence_diagram::model::class_> > clanguml::sequence_diagram::visitor::translation_unit_visitor::forward_declarations_
private

Definition at line 613 of file translation_unit_visitor.h.

◆ objc_message_map_

std::map<clang::ObjCMessageExpr *, model::message> clanguml::sequence_diagram::visitor::translation_unit_visitor::objc_message_map_
private

Definition at line 610 of file translation_unit_visitor.h.

◆ processed_comments_by_caller_id_

std::set<std::pair<int64_t, const clang::RawComment *> > clanguml::sequence_diagram::visitor::translation_unit_visitor::processed_comments_by_caller_id_
mutableprivate

Definition at line 627 of file translation_unit_visitor.h.

◆ return_stmt_message_map_

std::map<clang::ReturnStmt *, model::message> clanguml::sequence_diagram::visitor::translation_unit_visitor::return_stmt_message_map_
private

Definition at line 603 of file translation_unit_visitor.h.

◆ template_builder_

template_builder_t clanguml::sequence_diagram::visitor::translation_unit_visitor::template_builder_
private

Definition at line 629 of file translation_unit_visitor.h.

◆ within_static_variable_declaration_

unsigned clanguml::sequence_diagram::visitor::translation_unit_visitor::within_static_variable_declaration_ {0}
mutableprivate

Definition at line 622 of file translation_unit_visitor.h.


The documentation for this class was generated from the following files: