0.6.2
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

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_struct_relationships_
 
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 3030 of file translation_unit_visitor.cc.

3031{
3032 // Translate reverse activity call graph local ids to global ids
3033 std::map<eid_t, std::set<eid_t>> acs;
3034 for (const auto &[id, caller_ids] : activity_callers_) {
3035 auto unique_id = get_unique_id(id);
3036 if (!unique_id)
3037 continue;
3038 std::set<eid_t> unique_caller_ids;
3039 for (const auto &caller_id : caller_ids) {
3040 auto unique_caller_id = get_unique_id(caller_id);
3041 if (unique_caller_id)
3042 unique_caller_ids.emplace(*unique_caller_id);
3043 }
3044 acs.emplace(*unique_id, std::move(unique_caller_ids));
3045 }
3046
3047 // Change all message callees AST local ids to diagram global ids
3048 for (auto &[id, activity] : diagram().sequences()) {
3049 assert(id.is_global());
3050
3051 if (acs.count(id) > 0) {
3052 activity.set_callers(acs.at(id));
3053 }
3054 }
3055}

◆ 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 2654 of file translation_unit_visitor.cc.

2656{
2657 auto function_model_ptr =
2658 std::make_unique<sequence_diagram::model::function>(
2659 config().using_namespace());
2660
2661 common::model::namespace_ ns{declaration.getQualifiedNameAsString()};
2662 function_model_ptr->set_name(ns.name());
2663 ns.pop_back();
2664 function_model_ptr->set_namespace(ns);
2665
2666 function_model_ptr->return_type(common::to_string(
2667 declaration.getReturnType(), declaration.getASTContext()));
2668
2669 process_function_parameters(declaration, *function_model_ptr);
2670
2671 if (declaration.isVariadic()) {
2672 function_model_ptr->add_parameter("...");
2673 }
2674
2675 return function_model_ptr;
2676}

◆ 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 2610 of file translation_unit_visitor.cc.

2612{
2613 auto function_template_model_ptr =
2614 std::make_unique<sequence_diagram::model::function_template>(
2615 config().using_namespace());
2616
2617 set_qualified_name(declaration, *function_template_model_ptr);
2618
2620 *function_template_model_ptr, declaration);
2621
2622 function_template_model_ptr->return_type(
2623 common::to_string(declaration.getAsFunction()->getReturnType(),
2624 declaration.getASTContext()));
2625
2626 if (declaration.getAsFunction() != nullptr) {
2628 *declaration.getAsFunction(), *function_template_model_ptr);
2629 }
2630
2631 return function_template_model_ptr;
2632}

◆ 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 2635 of file translation_unit_visitor.cc.

2637{
2638 auto template_instantiation_ptr =
2639 std::make_unique<model::function_template>(config().using_namespace());
2640 auto &template_instantiation = *template_instantiation_ptr;
2641
2642 set_qualified_name(declaration, template_instantiation);
2643
2644 tbuilder().build(declaration, template_instantiation, &declaration,
2645 declaration.getPrimaryTemplate(),
2646 declaration.getTemplateSpecializationArgs()->asArray(),
2647 common::to_string(&declaration));
2648
2649 process_function_parameters(declaration, *template_instantiation_ptr);
2650
2651 return template_instantiation_ptr;
2652}

◆ 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 2430 of file translation_unit_visitor.cc.

2431{
2432 assert(cls != nullptr);
2433
2434 auto c_ptr{std::make_unique<clanguml::sequence_diagram::model::class_>(
2435 config().using_namespace())};
2436 auto &c = *c_ptr;
2437
2438 auto qualified_name = cls->getQualifiedNameAsString();
2439
2440 if (!cls->isLambda())
2441 if (!should_include(cls))
2442 return {};
2443
2444 auto ns = common::get_tag_namespace(*cls);
2445
2446 if (cls->isLambda() && !diagram().should_include(ns | "lambda"))
2447 return {};
2448
2449 const auto *parent = cls->getParent();
2450
2451 if ((parent != nullptr) && parent->isRecord()) {
2452 // Here we have 3 options, either:
2453 // - the parent is a regular C++ class/struct
2454 // - the parent is a class template declaration/specialization
2455 // - the parent is a lambda (i.e. this is a nested lambda expression)
2456 std::optional<eid_t> id_opt;
2457 const auto *parent_record_decl =
2458 clang::dyn_cast<clang::RecordDecl>(parent);
2459
2460 assert(parent_record_decl != nullptr);
2461
2462 const eid_t ast_id{parent_record_decl->getID()};
2463
2464 // First check if the parent has been added to the diagram as
2465 // regular class
2466 id_opt = get_unique_id(ast_id);
2467
2468 // If not, check if the parent template declaration is in the model
2469 if (!id_opt &&
2470 (parent_record_decl->getDescribedTemplate() != nullptr)) {
2471 parent_record_decl->getDescribedTemplate()->getID();
2472 if (parent_record_decl->getDescribedTemplate() != nullptr)
2473 id_opt = get_unique_id(ast_id);
2474 }
2475
2476 if (!id_opt)
2477 return {};
2478
2479 auto parent_class =
2480 diagram()
2482 *id_opt);
2483
2484 if (!parent_class) {
2485 return {};
2486 }
2487
2488 c.set_namespace(ns);
2489 if (cls->getNameAsString().empty()) {
2490 // Nested structs can be anonymous
2491 if (anonymous_struct_relationships_.count(cls->getID()) > 0) {
2492 const auto &[label, hint, access] =
2493 anonymous_struct_relationships_[cls->getID()];
2494
2495 c.set_name(parent_class.value().name() +
2496 "::" + fmt::format("({})", label));
2497
2498 parent_class.value().add_relationship(
2499 {hint, common::to_id(c.full_name(false)), access, label});
2500 }
2501 else
2502 c.set_name(parent_class.value().name() + "::" +
2503 fmt::format(
2504 "(anonymous_{})", std::to_string(cls->getID())));
2505 }
2506 else {
2507 c.set_name(
2508 parent_class.value().name() + "::" + cls->getNameAsString());
2509 }
2510
2511 c.set_id(common::to_id(c.full_name(false)));
2512
2513 c.nested(true);
2514 }
2515 else if (cls->isLambda()) {
2516 c.is_lambda(true);
2517 if (cls->getParent() != nullptr) {
2518 const auto type_name = make_lambda_name(cls);
2519
2520 c.set_name(type_name);
2521 c.set_namespace(ns);
2522 c.set_id(common::to_id(c.full_name(false)));
2523 }
2524 else {
2525 LOG_WARN("Cannot find parent declaration for lambda {}",
2526 cls->getQualifiedNameAsString());
2527 return {};
2528 }
2529 }
2530 // This is equivalent to parent != nullptr and parent->isFunctionDecl()
2531 else if (cls->isLocalClass() != nullptr) {
2532 const auto *func_declaration = cls->isLocalClass();
2533
2534 eid_t local_parent_id{int64_t{}};
2535
2536 if (common::is_lambda_method(func_declaration)) {
2537 LOG_DBG("The local class is defined in a lambda operator()");
2538 const auto *method_declaration =
2539 clang::dyn_cast<clang::CXXMethodDecl>(func_declaration);
2540
2541 if (method_declaration != nullptr &&
2542 method_declaration->getParent() != nullptr) {
2543 local_parent_id = method_declaration->getParent()->getID();
2544 }
2545 }
2546 else {
2547 local_parent_id = func_declaration->getID();
2548 }
2549
2550 eid_t parent_id = get_unique_id(local_parent_id).has_value()
2551 ? *get_unique_id(local_parent_id) // NOLINT
2552 : local_parent_id;
2553
2554 const auto &func_model =
2555 diagram().get_participant<model::participant>(parent_id);
2556
2557 if (!func_model.has_value())
2558 return {};
2559
2560 LOG_DBG("Visiting local class declaration: {} in {}",
2561 cls->getQualifiedNameAsString(),
2562 func_model.value().full_name(false));
2563
2564 auto local_cls_ns = func_model.value().get_namespace();
2565
2566 c.set_name(
2567 func_model.value().full_name_no_ns(), common::get_tag_name(*cls));
2568 c.set_namespace(local_cls_ns);
2569 c.set_id(common::to_id(c.full_name(false)));
2570 c.nested(true);
2571 }
2572 else {
2573 c.set_name(common::get_tag_name(*cls));
2574 c.set_namespace(ns);
2575 c.set_id(common::to_id(c.full_name(false)));
2576 }
2577
2578 c.is_struct(cls->isStruct());
2579
2580 process_comment(*cls, c);
2581 set_source_location(*cls, c);
2582
2583 if (c.skip())
2584 return {};
2585
2586 c.set_style(c.style_spec());
2587
2588 return c_ptr;
2589}

◆ 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 3058 of file translation_unit_visitor.cc.

3060{
3061 auto method_model_ptr = std::make_unique<sequence_diagram::model::method>(
3062 config().using_namespace());
3063
3064 common::model::namespace_ ns{declaration->getQualifiedNameAsString()};
3065 auto method_name = ns.name();
3066 method_model_ptr->set_method_name(method_name);
3067 ns.pop_back();
3068 method_model_ptr->set_name(ns.name());
3069 ns.pop_back();
3070 method_model_ptr->set_namespace(ns);
3071
3072 method_model_ptr->is_defaulted(declaration->isDefaulted());
3073 method_model_ptr->is_assignment(declaration->isCopyAssignmentOperator() ||
3074 declaration->isMoveAssignmentOperator());
3075 method_model_ptr->is_const(declaration->isConst());
3076 method_model_ptr->is_static(declaration->isStatic());
3077 method_model_ptr->is_operator(declaration->isOverloadedOperator());
3078 method_model_ptr->is_constructor(
3079 clang::dyn_cast<clang::CXXConstructorDecl>(declaration) != nullptr);
3080
3081 method_model_ptr->is_void(declaration->getReturnType()->isVoidType());
3082
3083 method_model_ptr->return_type(common::to_string(
3084 declaration->getReturnType(), declaration->getASTContext()));
3085
3086 process_function_parameters(*declaration, *method_model_ptr);
3087
3088 return method_model_ptr;
3089}

◆ 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 3160 of file translation_unit_visitor.cc.

3161{
3162 auto method_model_ptr = std::make_unique<sequence_diagram::model::method>(
3163 config().using_namespace());
3164
3165 common::model::namespace_ ns{declaration->getQualifiedNameAsString()};
3166 auto method_name = ns.name();
3167 method_model_ptr->set_method_name(method_name);
3168 ns.pop_back();
3169 method_model_ptr->set_name(ns.name());
3170 ns.pop_back();
3171 method_model_ptr->set_namespace(ns);
3172
3173 method_model_ptr->is_defaulted(declaration->isDefaulted());
3174 method_model_ptr->is_assignment(declaration->isCopyAssignmentOperator() ||
3175 declaration->isMoveAssignmentOperator());
3176 method_model_ptr->is_const(declaration->isConst());
3177 method_model_ptr->is_static(declaration->isStatic());
3178 method_model_ptr->is_operator(declaration->isOverloadedOperator());
3179 method_model_ptr->is_constructor(
3180 clang::dyn_cast<clang::CXXConstructorDecl>(declaration) != nullptr);
3181 method_model_ptr->is_coroutine(common::is_coroutine(*declaration));
3182
3183 clang::Decl *parent_decl = declaration->getParent();
3184
3185 if (context().current_class_template_decl_ != nullptr)
3186 parent_decl = context().current_class_template_decl_;
3187
3188 LOG_DBG("Getting method's class with local id {}", parent_decl->getID());
3189
3190 const auto maybe_method_class = get_participant<model::class_>(parent_decl);
3191
3192 if (!maybe_method_class) {
3193 LOG_DBG("Cannot find parent class_ for method {} in class {}",
3194 declaration->getQualifiedNameAsString(),
3195 declaration->getParent()->getQualifiedNameAsString());
3196 return {};
3197 }
3198
3199 LOG_DBG(
3200 "Found method class: {}", maybe_method_class.value().full_name(false));
3201
3202 const auto &method_class = maybe_method_class.value();
3203
3204 method_model_ptr->is_void(declaration->getReturnType()->isVoidType());
3205
3206 method_model_ptr->set_class_id(method_class.id());
3207 method_model_ptr->set_class_full_name(method_class.full_name(false));
3208 method_model_ptr->set_name(get_participant(method_model_ptr->class_id())
3209 .value()
3210 .full_name_no_ns() +
3211 "::" + declaration->getNameAsString());
3212
3213 method_model_ptr->return_type(common::to_string(
3214 declaration->getReturnType(), declaration->getASTContext()));
3215
3216 process_function_parameters(*declaration, *method_model_ptr);
3217
3218 return method_model_ptr;
3219}

◆ 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 2402 of file translation_unit_visitor.cc.

2404{
2405 assert(cls != nullptr);
2406
2407 auto c_ptr{std::make_unique<clanguml::sequence_diagram::model::class_>(
2408 config().using_namespace())};
2409 auto &c = *c_ptr;
2410
2411 auto qualified_name = cls->getQualifiedNameAsString();
2412
2413 c.is_objc_interface(true);
2414
2415 c.set_name(cls->getQualifiedNameAsString());
2416 c.set_id(common::to_id(*cls));
2417
2418 process_comment(*cls, c);
2419 set_source_location(*cls, c);
2420
2421 if (c.skip())
2422 return {};
2423
2424 c.set_style(c.style_spec());
2425
2426 return c_ptr;
2427}

◆ 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 3092 of file translation_unit_visitor.cc.

3094{
3095 auto method_model_ptr =
3096 std::make_unique<sequence_diagram::model::objc_method>(
3097 config().using_namespace());
3098
3099 common::model::namespace_ ns{declaration->getQualifiedNameAsString()};
3100 auto method_name = ns.name();
3101 method_model_ptr->set_method_name(method_name);
3102 ns.pop_back();
3103 method_model_ptr->set_name(ns.name());
3104 method_model_ptr->set_namespace({});
3105
3106 clang::Decl *parent_decl = declaration->getClassInterface();
3107
3108 if (parent_decl == nullptr) {
3109 LOG_DBG("Cannot find ObjC interface for method, probably it is a "
3110 "protocol {} [{}]",
3111 method_name,
3112 declaration->getLocation().printToString(source_manager()));
3113 return {};
3114 }
3115
3116 LOG_DBG("Getting ObjC method's interface with local id {}",
3117 parent_decl->getID());
3118
3119 const auto maybe_method_class = get_participant<model::class_>(parent_decl);
3120
3121 if (!maybe_method_class) {
3122 LOG_DBG("Cannot find parent class_ for method {} in class {}",
3123 declaration->getQualifiedNameAsString(),
3124 declaration->getClassInterface()->getQualifiedNameAsString());
3125 return {};
3126 }
3127
3128 const auto &method_class = maybe_method_class.value();
3129
3130 method_model_ptr->is_void(declaration->getReturnType()->isVoidType());
3131
3132 method_model_ptr->set_class_id(method_class.id());
3133 method_model_ptr->set_class_full_name(method_class.full_name(false));
3134 method_model_ptr->set_name(get_participant(method_model_ptr->class_id())
3135 .value()
3136 .full_name_no_ns() +
3137 "::" + declaration->getNameAsString());
3138
3139 method_model_ptr->return_type(common::to_string(
3140 declaration->getReturnType(), declaration->getASTContext()));
3141
3142 for (const auto *param : declaration->parameters()) {
3143 auto parameter_type =
3144 common::to_string(param->getType(), param->getASTContext());
3146 parameter_type = simplify_system_template(parameter_type);
3147
3148 std::string parameter_str = parameter_type;
3149 if (config().generate_method_argument_names()) {
3150 parameter_str += " " + param->getNameAsString();
3151 }
3152
3153 method_model_ptr->add_parameter(parameter_type);
3154 }
3155
3156 return method_model_ptr;
3157}

◆ 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 2374 of file translation_unit_visitor.cc.

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

◆ ensure_activity_exists()

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

Definition at line 1922 of file translation_unit_visitor.cc.

1923{
1924 if (diagram().sequences().count(m.from()) == 0) {
1925 model::activity a{m.from()};
1926 diagram().sequences().insert({m.from(), std::move(a)});
1927 }
1928
1929 // Maintain reverse graph of activity callers
1930 activity_callers_[m.to()].emplace(m.from());
1931}

◆ 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 2981 of file translation_unit_visitor.cc.

2982{
2983 for (auto &[id, activity] : diagram().sequences()) {
2984 for (auto &m : activity.messages()) {
2985 auto participant = diagram().get_participant<model::class_>(m.to());
2986
2987 if (participant && participant.value().is_lambda() &&
2988 participant.value().lambda_operator_id().value() != 0) {
2989 LOG_DBG("Changing lambda expression target id from {} to {}",
2990 m.to(), participant.value().lambda_operator_id());
2991
2992 m.set_to(participant.value().lambda_operator_id());
2993 m.set_message_name("operator()");
2994
2996 }
2997 }
2998 }
2999}

◆ finalize()

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

Finalize diagram model for this translation unit.

Definition at line 2965 of file translation_unit_visitor.cc.

2966{
2968
2969 // Change all messages with target set to an id of a lambda expression to
2970 // to the ID of their operator() - this is necessary, as some calls to
2971 // lambda expressions are visited before the actual lambda expressions
2972 // are visited...
2974
2976
2977 if (config().inline_lambda_messages())
2978 diagram().inline_lambda_operator_calls();
2979}

◆ 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 1933 of file translation_unit_visitor.cc.

1935{
1936 auto generated_message_from_comment{false};
1937 for (const auto &decorator : m.decorators()) {
1938 auto call_decorator =
1939 std::dynamic_pointer_cast<decorators::call>(decorator);
1940 if (call_decorator &&
1941 call_decorator->applies_to_diagram(config().name)) {
1942 m.set_to(common::to_id(call_decorator->callee));
1943 generated_message_from_comment = true;
1944 break;
1945 }
1946 }
1947 return generated_message_from_comment;
1948}

◆ 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 3376 of file translation_unit_visitor.cc.

3379{
3380 const auto *raw_comment =
3382
3383 if (raw_comment == nullptr)
3384 return {};
3385
3386 if (!caller_id.is_global() &&
3388 .emplace(caller_id.ast_local_value(), raw_comment)
3389 .second) {
3390 return {};
3391 }
3392
3393 const auto &[decorators, stripped_comment] = decorators::parse(
3394 raw_comment->getFormattedText(sm, sm.getDiagnostics()));
3395
3396 if (stripped_comment.empty())
3397 return {};
3398
3399 return {{raw_comment->getBeginLoc().getHashValue(), stripped_comment}};
3400}

◆ get_participant() [1/4]

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/4]

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/4]

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/4]

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 2600 of file translation_unit_visitor.cc.

2602{
2603 if (local_id.is_global())
2604 return local_id;
2605
2606 return id_mapper().get_global_id(local_id);
2607}

◆ 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 2345 of file translation_unit_visitor.cc.

2347{
2348 if (dependent_member_expr == nullptr)
2349 return false;
2350
2351 if (dependent_member_expr->getBaseType().isNull())
2352 return false;
2353
2354 const auto *tst = dependent_member_expr->getBaseType()
2355 ->getAs<clang::TemplateSpecializationType>();
2356
2357 if (tst == nullptr)
2358 return false;
2359
2360 return !(tst->isPointerType());
2361}

◆ 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 2363 of file translation_unit_visitor.cc.

2365{
2366 return primary_template->getQualifiedNameAsString().find(
2367 "std::unique_ptr") == 0 ||
2368 primary_template->getQualifiedNameAsString().find("std::shared_ptr") ==
2369 0 ||
2370 primary_template->getQualifiedNameAsString().find("std::weak_ptr") == 0;
2371}

◆ 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 2721 of file translation_unit_visitor.cc.

2723{
2724 const auto file_line =
2725 source_manager().getSpellingLineNumber(source_location);
2726 const auto file_column =
2727 source_manager().getSpellingColumnNumber(source_location);
2728 const std::string file_name =
2729 config()
2730 .make_path_relative(
2731 source_manager().getFilename(source_location).str())
2732 .string();
2733 return fmt::format("{}:{}:{}", file_name, file_line, file_column);
2734}

◆ 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 2736 of file translation_unit_visitor.cc.

2738{
2739 std::string result;
2740 const auto location = cls->getLocation();
2741 const std::string source_location{lambda_source_location(location)};
2742
2743 const auto maybe_lambda_caller_id = context().lambda_caller_id();
2744 if (maybe_lambda_caller_id.has_value()) {
2745 // Parent is also a lambda (this id points to a lambda operator())
2746 std::string parent_lambda_class_name{"()"};
2747 if (diagram().get_participant<model::method>(
2748 maybe_lambda_caller_id.value())) {
2749 auto parent_lambda_class_id =
2750 diagram()
2751 .get_participant<model::method>(
2752 maybe_lambda_caller_id.value())
2753 .value()
2754 .class_id();
2755
2756 if (diagram().get_participant<model::class_>(
2757 parent_lambda_class_id)) {
2758 parent_lambda_class_name =
2759 diagram()
2760 .get_participant<model::class_>(parent_lambda_class_id)
2761 .value()
2762 .full_name(false);
2763 }
2764 }
2765
2766 result = fmt::format(
2767 "{}##(lambda {})", parent_lambda_class_name, source_location);
2768 }
2769 else if (context().caller_id().value() != 0 &&
2770 get_participant(context().caller_id()).has_value()) {
2771 auto parent_full_name =
2772 get_participant(context().caller_id()).value().full_name_no_ns();
2773
2774 result =
2775 fmt::format("{}##(lambda {})", parent_full_name, source_location);
2776 }
2777 else {
2778 result = fmt::format("(lambda {})", source_location);
2779 }
2780
2781 return result;
2782}

◆ 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 2826 of file translation_unit_visitor.cc.

2827{
2828 assert(expr != nullptr);
2829
2830 // Skip if no message was generated from this expr
2831 if (call_expr_message_map_.find(expr) == call_expr_message_map_.end()) {
2832 return;
2833 }
2834
2835 if (call_expr_message_map_.at(expr).empty())
2836 return;
2837
2838 while (!call_expr_message_map_.at(expr).empty()) {
2839 auto msg = call_expr_message_map_.at(expr).front();
2840
2841 auto caller_id = msg.from();
2842
2843 if (caller_id == 0)
2844 return;
2845
2846 if (diagram().has_activity(caller_id))
2847 diagram().get_activity(caller_id).add_message(std::move(msg));
2848 else
2849 LOG_DBG("Skipping message due to missing activity: {}", caller_id);
2850
2851 call_expr_message_map_.at(expr).pop_front();
2852 }
2853
2854 call_expr_message_map_.erase(expr);
2855}

◆ 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 2929 of file translation_unit_visitor.cc.

2930{
2931 assert(expr != nullptr);
2932
2933 // Skip if no message was generated from this expr
2934 if (co_await_stmt_message_map_.find(expr) ==
2936 return;
2937 }
2938
2939 auto msg = std::move(co_await_stmt_message_map_.at(expr));
2940
2941 auto caller_id = msg.from();
2942 diagram().get_activity(caller_id).add_message(std::move(msg));
2943
2944 co_await_stmt_message_map_.erase(expr);
2945}

◆ 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 2893 of file translation_unit_visitor.cc.

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

◆ 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 2911 of file translation_unit_visitor.cc.

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

◆ 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 2857 of file translation_unit_visitor.cc.

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

◆ 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 2947 of file translation_unit_visitor.cc.

2949{
2950 assert(expr != nullptr);
2951
2952 // Skip if no message was generated from this expr
2953 if (objc_message_map_.find(expr) == objc_message_map_.end()) {
2954 return;
2955 }
2956
2957 auto msg = std::move(objc_message_map_.at(expr));
2958
2959 auto caller_id = msg.from();
2960 diagram().get_activity(caller_id).add_message(std::move(msg));
2961
2962 objc_message_map_.erase(expr);
2963}

◆ 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 2876 of file translation_unit_visitor.cc.

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

◆ 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 1525 of file translation_unit_visitor.cc.

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

◆ 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 2151 of file translation_unit_visitor.cc.

2153{
2154 // Get callee declaration as methods parent
2155 const auto *method_decl = method_call_expr->getMethodDecl();
2156
2157 if (method_decl == nullptr)
2158 return false;
2159
2160 std::string method_name = method_decl->getQualifiedNameAsString();
2161
2162 const auto *callee_decl =
2163 method_decl != nullptr ? method_decl->getParent() : nullptr;
2164
2165 if (callee_decl == nullptr)
2166 return false;
2167
2168 if (!should_include(callee_decl) || !should_include(method_decl))
2169 return false;
2170
2171 m.set_to(eid_t{method_decl->getID()});
2172 m.set_message_name(method_decl->getNameAsString());
2173 m.set_return_type(
2174 method_call_expr->getCallReturnType(*context().get_ast_context())
2175 .getAsString());
2176
2177 LOG_TRACE("Set callee method id {} for method name {}", m.to(),
2178 method_decl->getQualifiedNameAsString());
2179
2180 diagram().add_active_participant(eid_t{method_decl->getID()});
2181
2182 return true;
2183}

◆ 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 2185 of file translation_unit_visitor.cc.

2187{
2188 const auto *dependent_member_callee =
2189 clang::dyn_cast_or_null<clang::CXXDependentScopeMemberExpr>(
2190 expr->getCallee());
2191
2192 if (dependent_member_callee == nullptr)
2193 return false;
2194
2195 if (is_callee_valid_template_specialization(dependent_member_callee)) {
2196 if (const auto *tst = dependent_member_callee->getBaseType()
2197 ->getAs<clang::TemplateSpecializationType>();
2198 tst != nullptr) {
2199 const auto *template_declaration =
2200 tst->getTemplateName().getAsTemplateDecl();
2201
2202 std::string callee_method_full_name;
2203
2204 // First check if the primary template is already in the
2205 // participants map
2206 if (get_participant(template_declaration).has_value()) {
2207 callee_method_full_name = get_participant(template_declaration)
2208 .value()
2209 .full_name(false) +
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
2215 if (p_full_name.find(callee_method_full_name + "(") == 0) {
2216 // TODO: This selects the first matching template method
2217 // without considering arguments!!!
2218 m.set_to(id);
2219 break;
2220 }
2221 }
2222 }
2223 // Otherwise check if it is a smart pointer
2224 else if (is_smart_pointer(template_declaration)) {
2225 const auto *argument_template =
2226 template_declaration->getTemplateParameters()
2227 ->asArray()
2228 .front();
2229
2230 if (get_participant(argument_template).has_value()) {
2231 callee_method_full_name = get_participant(argument_template)
2232 .value()
2233 .full_name(false) +
2234 "::" +
2235 dependent_member_callee->getMember().getAsString();
2236
2237 for (const auto &[id, p] : diagram().participants()) {
2238 const auto p_full_name = p->full_name(false);
2239 if (p_full_name.find(callee_method_full_name + "(") ==
2240 0) {
2241 // TODO: This selects the first matching template
2242 // method without considering arguments!!!
2243 m.set_to(id);
2244 break;
2245 }
2246 }
2247 }
2248 else
2249 return false;
2250 }
2251
2252 m.set_message_name(
2253 dependent_member_callee->getMember().getAsString());
2254
2255 if (const auto maybe_id =
2256 get_unique_id(eid_t{template_declaration->getID()});
2257 maybe_id.has_value())
2258 diagram().add_active_participant(maybe_id.value());
2259 }
2260 }
2261 else {
2262 LOG_DBG("Skipping call due to unresolvable "
2263 "CXXDependentScopeMemberExpr at {}",
2264 expr->getBeginLoc().printToString(source_manager()));
2265 }
2266
2267 return true;
2268}

◆ 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 2679 of file translation_unit_visitor.cc.

2681{
2682 auto c_ptr{std::make_unique<model::class_>(config().using_namespace())};
2683
2685
2686 auto &template_instantiation = *c_ptr;
2687
2688 // TODO: refactor to method get_qualified_name()
2689 auto qualified_name = cls->getQualifiedNameAsString();
2690 util::replace_all(qualified_name, "(anonymous namespace)", "");
2691 util::replace_all(qualified_name, "::::", "::");
2692
2693 common::model::namespace_ ns{qualified_name};
2694 ns.pop_back();
2695 template_instantiation.set_name(cls->getNameAsString());
2696 template_instantiation.set_namespace(ns);
2697
2698 template_instantiation.is_struct(cls->isStruct());
2699
2700 process_comment(*cls, template_instantiation);
2701 set_source_location(*cls, template_instantiation);
2702 set_owning_module(*cls, template_instantiation);
2703
2704 if (template_instantiation.skip())
2705 return {};
2706
2707 template_instantiation.set_id(
2708 common::to_id(template_instantiation.full_name(false)));
2709
2710 set_unique_id(cls->getID(), template_instantiation.id());
2711
2712 return c_ptr;
2713}

◆ 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 2078 of file translation_unit_visitor.cc.

2080{
2081 const auto *constructor = construct_expr->getConstructor();
2082 if (constructor == nullptr)
2083 return false;
2084
2085 const auto *constructor_parent = constructor->getParent();
2086 if (constructor_parent == nullptr)
2087 return false;
2088
2089 LOG_DBG("Constructor '{}' call expression to {} at {}",
2090 construct_expr->getConstructor()->getNameAsString(),
2091 constructor->getID(),
2092 construct_expr->getBeginLoc().printToString(source_manager()));
2093
2094 m.set_to(id_mapper().resolve_or(eid_t{constructor->getID()}));
2095 m.set_message_name(
2096 fmt::format("{}::{}", constructor_parent->getQualifiedNameAsString(),
2097 constructor_parent->getNameAsString()));
2098
2099 diagram().add_active_participant(eid_t{constructor->getID()});
2100
2101 return true;
2102}

◆ 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 2011 of file translation_unit_visitor.cc.

2013{
2014 const auto *callee_decl = expr->getCalleeDecl();
2015
2016 if (callee_decl == nullptr)
2017 return false;
2018
2019 const auto *callee_function = callee_decl->getAsFunction();
2020
2021 if (callee_function == nullptr)
2022 return false;
2023
2024 if (!should_include(callee_function))
2025 return false;
2026
2027 // Skip free functions declared in files outside of included paths
2028 if (config().combine_free_functions_into_file_participants() &&
2029 !diagram().should_include(common::model::source_file{m.file()}))
2030 return false;
2031
2032 auto callee_name = callee_function->getQualifiedNameAsString() + "()";
2033
2034 m.set_to(id_mapper().resolve_or(eid_t{callee_function->getID()}));
2035 m.set_message_name(callee_name.substr(0, callee_name.size() - 2));
2036
2037 return true;
2038}

◆ 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 2270 of file translation_unit_visitor.cc.

2272{
2273 const auto *callee_decl = expr->getCalleeDecl();
2274
2275 if (callee_decl == nullptr)
2276 return false;
2277
2278 const auto *callee_function = callee_decl->getAsFunction();
2279
2280 if (callee_function == nullptr)
2281 return false;
2282
2283 if (!should_include(callee_function))
2284 return false;
2285
2286 // Skip free functions declared in files outside of included paths
2287 if (config().combine_free_functions_into_file_participants() &&
2288 !diagram().should_include(common::model::source_file{m.file()}))
2289 return false;
2290
2291 auto callee_name = callee_function->getQualifiedNameAsString() + "()";
2292
2293 m.set_to(id_mapper().resolve_or(eid_t{callee_function->getID()}));
2294 m.set_message_name(callee_name.substr(0, callee_name.size() - 2));
2295
2296 return true;
2297}

◆ 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 3221 of file translation_unit_visitor.cc.

3223{
3224 for (const auto *param : declaration.parameters()) {
3225 auto parameter_type =
3226 common::to_string(param->getType(), param->getASTContext());
3228 parameter_type = simplify_system_template(parameter_type);
3229
3230 std::string parameter_str = config().using_namespace().relative(
3231 simplify_system_template(parameter_type));
3232 if (config().generate_method_argument_names()) {
3233 parameter_str += " " + param->getNameAsString();
3234 }
3235
3236 method_model.add_parameter(parameter_str);
3237 }
3238}

◆ 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 2299 of file translation_unit_visitor.cc.

2301{
2302 const auto *lambda_expr =
2303 clang::dyn_cast_or_null<clang::LambdaExpr>(expr->getCallee());
2304
2305 if (lambda_expr == nullptr)
2306 return true;
2307
2308 const auto lambda_class_id = eid_t{lambda_expr->getLambdaClass()->getID()};
2309 m.set_to(id_mapper().resolve_or(eid_t{lambda_class_id}));
2310
2311 return true;
2312}

◆ 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 2104 of file translation_unit_visitor.cc.

2106{
2107 const auto *method_decl = message_expr->getMethodDecl();
2108
2109 if (method_decl == nullptr)
2110 return false;
2111
2112 std::string method_name = method_decl->getQualifiedNameAsString();
2113
2114 if (message_expr->getReceiverInterface() == nullptr)
2115 return false;
2116
2117 const auto *callee_decl = message_expr->getReceiverInterface();
2118
2119 if (callee_decl == nullptr)
2120 return false;
2121
2122 if (!should_include(callee_decl) || !should_include(method_decl))
2123 return false;
2124
2125 if (callee_decl->getImplementation() != nullptr &&
2126 callee_decl->getImplementation()->getMethod(method_decl->getSelector(),
2127 method_decl->isInstanceMethod(), true) != nullptr) {
2128 const auto *impl_method_decl =
2129 callee_decl->getImplementation()->getMethod(
2130 method_decl->getSelector(), method_decl->isInstanceMethod(),
2131 true);
2132 m.set_to(eid_t{impl_method_decl->getID()});
2133 }
2134 else {
2135 m.set_to(eid_t{method_decl->getID()});
2136 }
2137
2138 m.set_message_name(method_decl->getNameAsString());
2139 m.set_return_type(
2140 message_expr->getCallReturnType(*context().get_ast_context())
2141 .getAsString());
2142
2143 LOG_TRACE("Set callee ObjC method id {} for method name {}", m.to(),
2144 method_decl->getQualifiedNameAsString());
2145
2146 diagram().add_active_participant(eid_t{method_decl->getID()});
2147
2148 return true;
2149}

◆ 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 2040 of file translation_unit_visitor.cc.

2042{
2043 if (operator_call_expr->getCalleeDecl() == nullptr)
2044 return false;
2045
2046 LOG_DBG("Operator '{}' call expression to {} at {}",
2047 getOperatorSpelling(operator_call_expr->getOperator()),
2048 operator_call_expr->getCalleeDecl()->getID(),
2049 operator_call_expr->getBeginLoc().printToString(source_manager()));
2050
2051 // Handle the case if the callee is a lambda
2052 if (const auto *lambda_method = clang::dyn_cast<clang::CXXMethodDecl>(
2053 operator_call_expr->getCalleeDecl());
2054 lambda_method != nullptr && lambda_method->getParent()->isLambda()) {
2055
2056 LOG_DBG("Operator callee is a lambda: {}",
2057 common::to_string(lambda_method));
2058
2059 const auto source_location{
2060 lambda_source_location(lambda_method->getParent()->getLocation())};
2061
2062 auto lambda_name = make_lambda_name(lambda_method->getParent());
2063
2064 m.set_to(eid_t{lambda_method->getParent()->getID()});
2065 }
2066 else {
2067 const auto operator_ast_id =
2068 operator_call_expr->getCalleeDecl()->getID();
2069 m.set_to(id_mapper().resolve_or(eid_t{operator_ast_id}));
2070 }
2071
2072 m.set_message_name(fmt::format(
2073 "operator{}", getOperatorSpelling(operator_call_expr->getOperator())));
2074
2075 return true;
2076}

◆ 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 2314 of file translation_unit_visitor.cc.

2316{
2317 // This is probably a template
2318 const auto *unresolved_expr =
2319 clang::dyn_cast_or_null<clang::UnresolvedLookupExpr>(expr->getCallee());
2320
2321 if (unresolved_expr != nullptr) {
2322 for (const auto *decl : unresolved_expr->decls()) {
2323 if (clang::dyn_cast_or_null<clang::FunctionTemplateDecl>(decl) !=
2324 nullptr) {
2325 const auto *ftd =
2326 clang::dyn_cast_or_null<clang::FunctionTemplateDecl>(decl);
2327 m.set_to(id_mapper().resolve_or(eid_t{ftd->getID()}));
2328 break;
2329 }
2330
2331 if (clang::dyn_cast_or_null<clang::FunctionDecl>(decl) != nullptr) {
2332 const auto *fd =
2333 clang::dyn_cast_or_null<clang::FunctionDecl>(decl);
2334 m.set_to(id_mapper().resolve_or(eid_t{fd->getID()}));
2335 break;
2336 }
2337
2338 LOG_DBG("Unknown unresolved lookup expression");
2339 }
2340 }
2341
2342 return true;
2343}

◆ 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 2784 of file translation_unit_visitor.cc.

2786{
2787 call_expr_message_map_[expr].push_back(std::move(m));
2788}

◆ push_message() [2/7]

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

Definition at line 2820 of file translation_unit_visitor.cc.

2822{
2823 co_await_stmt_message_map_.emplace(expr, std::move(m));
2824}

◆ push_message() [3/7]

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

Definition at line 2808 of file translation_unit_visitor.cc.

2810{
2811 co_return_stmt_message_map_.emplace(stmt, std::move(m));
2812}

◆ push_message() [4/7]

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

Definition at line 2814 of file translation_unit_visitor.cc.

2816{
2817 co_yield_stmt_message_map_.emplace(expr, std::move(m));
2818}

◆ push_message() [5/7]

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

Definition at line 2790 of file translation_unit_visitor.cc.

2792{
2793 construct_expr_message_map_.emplace(expr, std::move(m));
2794}

◆ push_message() [6/7]

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

Definition at line 2796 of file translation_unit_visitor.cc.

2798{
2799 objc_message_map_.emplace(expr, std::move(m));
2800}

◆ push_message() [7/7]

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

Definition at line 2802 of file translation_unit_visitor.cc.

2804{
2805 return_stmt_message_map_.emplace(stmt, std::move(m));
2806}

◆ resolve_ids_to_global()

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

Definition at line 3001 of file translation_unit_visitor.cc.

3002{
3003 std::set<eid_t> active_participants_unique;
3004
3005 // Change all active participants AST local ids to diagram global ids
3006 for (auto id : diagram().active_participants()) {
3007 if (const auto unique_id = get_unique_id(id);
3008 !id.is_global() && unique_id.has_value()) {
3009 active_participants_unique.emplace(unique_id.value());
3010 }
3011 else if (id.is_global()) {
3012 active_participants_unique.emplace(id);
3013 }
3014 }
3015
3016 diagram().active_participants() = std::move(active_participants_unique);
3017
3018 // Change all message callees AST local ids to diagram global ids
3019 for (auto &[id, activity] : diagram().sequences()) {
3020 for (auto &m : activity.messages()) {
3021 if (const auto unique_id = get_unique_id(m.to());
3022 !m.to().is_global() && unique_id.has_value()) {
3023 m.set_to(unique_id.value());
3024 assert(m.to().is_global());
3025 }
3026 }
3027 }
3028}

◆ 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 2591 of file translation_unit_visitor.cc.

2592{
2593 LOG_TRACE("Setting local element mapping {} --> {}", local_id, global_id);
2594
2595 assert(global_id.is_global());
2596
2597 id_mapper().add(local_id, global_id);
2598}

◆ 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 3289 of file translation_unit_visitor.cc.

3290{
3291 if (context().caller_id() == 0)
3292 return false;
3293
3294 // Skip casts, moves and such
3295 if (expr->isCallToStdMove())
3296 return false;
3297
3298 if (expr->isImplicitCXXThis())
3299 return false;
3300
3301 if (clang::dyn_cast_or_null<clang::ImplicitCastExpr>(expr) != nullptr)
3302 return false;
3303
3304 if (!context().valid())
3305 return false;
3306
3307 const auto expr_file = expr->getBeginLoc().printToString(source_manager());
3308
3309 if (!diagram().should_include(
3310 common::model::source_file{get_file_path(expr_file)}))
3311 return false;
3312
3313 const auto *callee_decl = expr->getCalleeDecl();
3314
3315 if (callee_decl != nullptr) {
3316 const auto *callee_function = callee_decl->getAsFunction();
3317
3318 if ((callee_function == nullptr) || !should_include(callee_function)) {
3319 LOG_DBG("Skipping call expression at {}",
3320 expr->getBeginLoc().printToString(source_manager()));
3321 return false;
3322 }
3323
3324 return should_include(callee_function);
3325 }
3326
3327 return true;
3328}

◆ 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 3369 of file translation_unit_visitor.cc.

3371{
3373}

◆ 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 3330 of file translation_unit_visitor.cc.

3332{
3333 if (!should_include(decl->getParent()))
3334 return false;
3335
3336 if (!diagram().should_include(
3337 common::access_specifier_to_access_t(decl->getAccess())))
3338 return false;
3339
3340 LOG_DBG("Including method {}", decl->getQualifiedNameAsString());
3341
3342 return true;
3343}

◆ 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 3357 of file translation_unit_visitor.cc.

3359{
3361}

◆ 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 3363 of file translation_unit_visitor.cc.

3365{
3366 return visitor_specialization_t::should_include(decl->getAsFunction());
3367}

◆ 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 3253 of file translation_unit_visitor.cc.

3255{
3256 if (context().caller_id() == 0)
3257 return false;
3258
3259 if (!context().valid())
3260 return false;
3261
3262 const auto expr_file = expr->getBeginLoc().printToString(source_manager());
3263
3264 if (!diagram().should_include(
3265 common::model::source_file{get_file_path(expr_file)}))
3266 return false;
3267
3268 return true;
3269}

◆ 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 3246 of file translation_unit_visitor.cc.

3248{
3250 dynamic_cast<const clang::NamedDecl *>(decl));
3251}

◆ 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 3271 of file translation_unit_visitor.cc.

3273{
3274 if (context().caller_id() == 0)
3275 return false;
3276
3277 if (!context().valid())
3278 return false;
3279
3280 const auto expr_file = expr->getBeginLoc().printToString(source_manager());
3281
3282 if (!diagram().should_include(
3283 common::model::source_file{get_file_path(expr_file)}))
3284 return false;
3285
3286 return true;
3287}

◆ should_include() [9/10]

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

Definition at line 3345 of file translation_unit_visitor.cc.

3347{
3348 if (!diagram().should_include(
3349 common::access_specifier_to_access_t(decl->getAccess())))
3350 return false;
3351
3352 LOG_DBG("Including ObjC method {}", decl->getQualifiedNameAsString());
3353
3354 return true;
3355}

◆ 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 3240 of file translation_unit_visitor.cc.

3241{
3243 dynamic_cast<const clang::NamedDecl *>(decl));
3244}

◆ 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 2715 of file translation_unit_visitor.cc.

2717{
2718 return config().simplify_template_type(full_name);
2719}

◆ 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 566 of file translation_unit_visitor.h.

566{ 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 605 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 609 of file translation_unit_visitor.h.

◆ anonymous_struct_relationships_

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

Definition at line 603 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 587 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 579 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 591 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 589 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 590 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 594 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 598 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 595 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 612 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 588 of file translation_unit_visitor.h.

◆ template_builder_

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

Definition at line 614 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 607 of file translation_unit_visitor.h.


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