0.6.0
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 VisitCallExpr (clang::CallExpr *expr)
 
bool VisitObjCMessageExpr (clang::ObjCMessageExpr *expr)
 
bool VisitObjCPropertyRefExpr (clang::ObjCPropertyRefExpr *expr)
 
bool TraverseVarDecl (clang::VarDecl *VD)
 
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 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 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_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 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)
 
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)
 

Private Attributes

call_expression_context call_expression_context_
 
std::map< clang::CallExpr *, std::deque< model::message > > call_expr_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 2492 of file translation_unit_visitor.cc.

2493{
2494 // Translate reverse activity call graph local ids to global ids
2495 std::map<eid_t, std::set<eid_t>> acs;
2496 for (const auto &[id, caller_ids] : activity_callers_) {
2497 auto unique_id = get_unique_id(id);
2498 if (!unique_id)
2499 continue;
2500 std::set<eid_t> unique_caller_ids;
2501 for (const auto &caller_id : caller_ids) {
2502 auto unique_caller_id = get_unique_id(caller_id);
2503 if (unique_caller_id)
2504 unique_caller_ids.emplace(*unique_caller_id);
2505 }
2506 acs.emplace(*unique_id, std::move(unique_caller_ids));
2507 }
2508
2509 // Change all message callees AST local ids to diagram global ids
2510 for (auto &[id, activity] : diagram().sequences()) {
2511 assert(id.is_global());
2512
2513 if (acs.count(id) > 0) {
2514 activity.set_callers(acs.at(id));
2515 }
2516 }
2517}

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

2209{
2210 auto function_model_ptr =
2211 std::make_unique<sequence_diagram::model::function>(
2212 config().using_namespace());
2213
2214 common::model::namespace_ ns{declaration.getQualifiedNameAsString()};
2215 function_model_ptr->set_name(ns.name());
2216 ns.pop_back();
2217 function_model_ptr->set_namespace(ns);
2218
2219 function_model_ptr->return_type(common::to_string(
2220 declaration.getReturnType(), declaration.getASTContext()));
2221
2222 for (const auto *param : declaration.parameters()) {
2223 function_model_ptr->add_parameter(
2225 param->getType(), declaration.getASTContext(), false)));
2226 }
2227
2228 if (declaration.isVariadic()) {
2229 function_model_ptr->add_parameter("...");
2230 }
2231
2232 return function_model_ptr;
2233}

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

2161{
2162 auto function_template_model_ptr =
2163 std::make_unique<sequence_diagram::model::function_template>(
2164 config().using_namespace());
2165
2166 set_qualified_name(declaration, *function_template_model_ptr);
2167
2169 *function_template_model_ptr, declaration);
2170
2171 function_template_model_ptr->return_type(
2172 common::to_string(declaration.getAsFunction()->getReturnType(),
2173 declaration.getASTContext()));
2174
2175 for (const auto *param : declaration.getTemplatedDecl()->parameters()) {
2176 function_template_model_ptr->add_parameter(
2178 param->getType(), declaration.getASTContext(), false)));
2179 }
2180
2181 return function_template_model_ptr;
2182}

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

2187{
2188 auto template_instantiation_ptr =
2189 std::make_unique<model::function_template>(config().using_namespace());
2190 auto &template_instantiation = *template_instantiation_ptr;
2191
2192 set_qualified_name(decl, template_instantiation);
2193
2194 tbuilder().build(template_instantiation, &decl, decl.getPrimaryTemplate(),
2195 decl.getTemplateSpecializationArgs()->asArray(),
2196 common::to_string(&decl));
2197
2198 // Handle function parameters
2199 for (const auto *param : decl.parameters()) {
2200 template_instantiation_ptr->add_parameter(
2201 common::to_string(param->getType(), decl.getASTContext()));
2202 }
2203
2204 return template_instantiation_ptr;
2205}

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

2022{
2023 assert(cls != nullptr);
2024
2025 auto c_ptr{std::make_unique<clanguml::sequence_diagram::model::class_>(
2026 config().using_namespace())};
2027 auto &c = *c_ptr;
2028
2029 auto qualified_name = cls->getQualifiedNameAsString();
2030
2031 if (!cls->isLambda())
2032 if (!should_include(cls))
2033 return {};
2034
2035 auto ns = common::get_tag_namespace(*cls);
2036
2037 if (cls->isLambda() && !diagram().should_include(ns | "lambda"))
2038 return {};
2039
2040 const auto *parent = cls->getParent();
2041
2042 if ((parent != nullptr) && parent->isRecord()) {
2043 // Here we have 3 options, either:
2044 // - the parent is a regular C++ class/struct
2045 // - the parent is a class template declaration/specialization
2046 // - the parent is a lambda (i.e. this is a nested lambda expression)
2047 std::optional<eid_t> id_opt;
2048 const auto *parent_record_decl =
2049 clang::dyn_cast<clang::RecordDecl>(parent);
2050
2051 assert(parent_record_decl != nullptr);
2052
2053 const eid_t ast_id{parent_record_decl->getID()};
2054
2055 // First check if the parent has been added to the diagram as
2056 // regular class
2057 id_opt = get_unique_id(ast_id);
2058
2059 // If not, check if the parent template declaration is in the model
2060 if (!id_opt &&
2061 (parent_record_decl->getDescribedTemplate() != nullptr)) {
2062 parent_record_decl->getDescribedTemplate()->getID();
2063 if (parent_record_decl->getDescribedTemplate() != nullptr)
2064 id_opt = get_unique_id(ast_id);
2065 }
2066
2067 if (!id_opt)
2068 return {};
2069
2070 auto parent_class =
2071 diagram()
2073 *id_opt);
2074
2075 if (!parent_class) {
2076 return {};
2077 }
2078
2079 c.set_namespace(ns);
2080 if (cls->getNameAsString().empty()) {
2081 // Nested structs can be anonymous
2082 if (anonymous_struct_relationships_.count(cls->getID()) > 0) {
2083 const auto &[label, hint, access] =
2084 anonymous_struct_relationships_[cls->getID()];
2085
2086 c.set_name(parent_class.value().name() +
2087 "::" + fmt::format("({})", label));
2088
2089 parent_class.value().add_relationship(
2090 {hint, common::to_id(c.full_name(false)), access, label});
2091 }
2092 else
2093 c.set_name(parent_class.value().name() + "::" +
2094 fmt::format(
2095 "(anonymous_{})", std::to_string(cls->getID())));
2096 }
2097 else {
2098 c.set_name(
2099 parent_class.value().name() + "::" + cls->getNameAsString());
2100 }
2101
2102 c.set_id(common::to_id(c.full_name(false)));
2103
2104 c.nested(true);
2105 }
2106 else if (cls->isLambda()) {
2107 c.is_lambda(true);
2108 if (cls->getParent() != nullptr) {
2109 const auto type_name = make_lambda_name(cls);
2110
2111 c.set_name(type_name);
2112 c.set_namespace(ns);
2113 c.set_id(common::to_id(c.full_name(false)));
2114 }
2115 else {
2116 LOG_WARN("Cannot find parent declaration for lambda {}",
2117 cls->getQualifiedNameAsString());
2118 return {};
2119 }
2120 }
2121 else {
2122 c.set_name(common::get_tag_name(*cls));
2123 c.set_namespace(ns);
2124 c.set_id(common::to_id(c.full_name(false)));
2125 }
2126
2127 c.is_struct(cls->isStruct());
2128
2129 process_comment(*cls, c);
2130 set_source_location(*cls, c);
2131
2132 if (c.skip())
2133 return {};
2134
2135 c.set_style(c.style_spec());
2136
2137 return c_ptr;
2138}

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

2522{
2523 auto method_model_ptr = std::make_unique<sequence_diagram::model::method>(
2524 config().using_namespace());
2525
2526 common::model::namespace_ ns{declaration->getQualifiedNameAsString()};
2527 auto method_name = ns.name();
2528 method_model_ptr->set_method_name(method_name);
2529 ns.pop_back();
2530 method_model_ptr->set_name(ns.name());
2531 ns.pop_back();
2532 method_model_ptr->set_namespace(ns);
2533
2534 method_model_ptr->is_defaulted(declaration->isDefaulted());
2535 method_model_ptr->is_assignment(declaration->isCopyAssignmentOperator() ||
2536 declaration->isMoveAssignmentOperator());
2537 method_model_ptr->is_const(declaration->isConst());
2538 method_model_ptr->is_static(declaration->isStatic());
2539 method_model_ptr->is_operator(declaration->isOverloadedOperator());
2540 method_model_ptr->is_constructor(
2541 clang::dyn_cast<clang::CXXConstructorDecl>(declaration) != nullptr);
2542
2543 method_model_ptr->is_void(declaration->getReturnType()->isVoidType());
2544
2545 method_model_ptr->return_type(common::to_string(
2546 declaration->getReturnType(), declaration->getASTContext()));
2547
2548 for (const auto *param : declaration->parameters()) {
2549 auto parameter_type =
2550 common::to_string(param->getType(), param->getASTContext());
2552 parameter_type = simplify_system_template(parameter_type);
2553 method_model_ptr->add_parameter(config().using_namespace().relative(
2554 simplify_system_template(parameter_type)));
2555 }
2556
2557 return method_model_ptr;
2558}

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

2624{
2625 auto method_model_ptr = std::make_unique<sequence_diagram::model::method>(
2626 config().using_namespace());
2627
2628 common::model::namespace_ ns{declaration->getQualifiedNameAsString()};
2629 auto method_name = ns.name();
2630 method_model_ptr->set_method_name(method_name);
2631 ns.pop_back();
2632 method_model_ptr->set_name(ns.name());
2633 ns.pop_back();
2634 method_model_ptr->set_namespace(ns);
2635
2636 method_model_ptr->is_defaulted(declaration->isDefaulted());
2637 method_model_ptr->is_assignment(declaration->isCopyAssignmentOperator() ||
2638 declaration->isMoveAssignmentOperator());
2639 method_model_ptr->is_const(declaration->isConst());
2640 method_model_ptr->is_static(declaration->isStatic());
2641 method_model_ptr->is_operator(declaration->isOverloadedOperator());
2642 method_model_ptr->is_constructor(
2643 clang::dyn_cast<clang::CXXConstructorDecl>(declaration) != nullptr);
2644
2645 clang::Decl *parent_decl = declaration->getParent();
2646
2647 if (context().current_class_template_decl_ != nullptr)
2648 parent_decl = context().current_class_template_decl_;
2649
2650 LOG_DBG("Getting method's class with local id {}", parent_decl->getID());
2651
2652 const auto maybe_method_class = get_participant<model::class_>(parent_decl);
2653
2654 if (!maybe_method_class) {
2655 LOG_DBG("Cannot find parent class_ for method {} in class {}",
2656 declaration->getQualifiedNameAsString(),
2657 declaration->getParent()->getQualifiedNameAsString());
2658 return {};
2659 }
2660
2661 const auto &method_class = maybe_method_class.value();
2662
2663 method_model_ptr->is_void(declaration->getReturnType()->isVoidType());
2664
2665 method_model_ptr->set_class_id(method_class.id());
2666 method_model_ptr->set_class_full_name(method_class.full_name(false));
2667 method_model_ptr->set_name(get_participant(method_model_ptr->class_id())
2668 .value()
2669 .full_name_no_ns() +
2670 "::" + declaration->getNameAsString());
2671
2672 method_model_ptr->return_type(common::to_string(
2673 declaration->getReturnType(), declaration->getASTContext()));
2674
2675 for (const auto *param : declaration->parameters()) {
2676 auto parameter_type =
2677 common::to_string(param->getType(), param->getASTContext());
2679 parameter_type = simplify_system_template(parameter_type);
2680 method_model_ptr->add_parameter(config().using_namespace().relative(
2681 simplify_system_template(parameter_type)));
2682 }
2683
2684 return method_model_ptr;
2685}

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

1995{
1996 assert(cls != nullptr);
1997
1998 auto c_ptr{std::make_unique<clanguml::sequence_diagram::model::class_>(
1999 config().using_namespace())};
2000 auto &c = *c_ptr;
2001
2002 auto qualified_name = cls->getQualifiedNameAsString();
2003
2004 c.is_objc_interface(true);
2005
2006 c.set_name(cls->getQualifiedNameAsString());
2007 c.set_id(common::to_id(*cls));
2008
2009 process_comment(*cls, c);
2010 set_source_location(*cls, c);
2011
2012 if (c.skip())
2013 return {};
2014
2015 c.set_style(c.style_spec());
2016
2017 return c_ptr;
2018}

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

2563{
2564 auto method_model_ptr =
2565 std::make_unique<sequence_diagram::model::objc_method>(
2566 config().using_namespace());
2567
2568 common::model::namespace_ ns{declaration->getQualifiedNameAsString()};
2569 auto method_name = ns.name();
2570 method_model_ptr->set_method_name(method_name);
2571 ns.pop_back();
2572 method_model_ptr->set_name(ns.name());
2573 method_model_ptr->set_namespace({});
2574
2575 clang::Decl *parent_decl = declaration->getClassInterface();
2576
2577 if (parent_decl == nullptr) {
2578 LOG_DBG("Cannot find ObjC interface for method, probably it is a "
2579 "protocol {} [{}]",
2580 method_name,
2581 declaration->getLocation().printToString(source_manager()));
2582 return {};
2583 }
2584
2585 LOG_DBG("Getting ObjC method's interface with local id {}",
2586 parent_decl->getID());
2587
2588 const auto maybe_method_class = get_participant<model::class_>(parent_decl);
2589
2590 if (!maybe_method_class) {
2591 LOG_DBG("Cannot find parent class_ for method {} in class {}",
2592 declaration->getQualifiedNameAsString(),
2593 declaration->getClassInterface()->getQualifiedNameAsString());
2594 return {};
2595 }
2596
2597 const auto &method_class = maybe_method_class.value();
2598
2599 method_model_ptr->is_void(declaration->getReturnType()->isVoidType());
2600
2601 method_model_ptr->set_class_id(method_class.id());
2602 method_model_ptr->set_class_full_name(method_class.full_name(false));
2603 method_model_ptr->set_name(get_participant(method_model_ptr->class_id())
2604 .value()
2605 .full_name_no_ns() +
2606 "::" + declaration->getNameAsString());
2607
2608 method_model_ptr->return_type(common::to_string(
2609 declaration->getReturnType(), declaration->getASTContext()));
2610
2611 for (const auto *param : declaration->parameters()) {
2612 auto parameter_type =
2613 common::to_string(param->getType(), param->getASTContext());
2615 parameter_type = simplify_system_template(parameter_type);
2616 method_model_ptr->add_parameter(parameter_type);
2617 }
2618
2619 return method_model_ptr;
2620}

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

1967{
1968 assert(cls != nullptr);
1969
1970 auto c_ptr{std::make_unique<clanguml::sequence_diagram::model::class_>(
1971 config().using_namespace())};
1972 auto &c = *c_ptr;
1973
1974 auto qualified_name = cls->getQualifiedNameAsString();
1975
1976 c.is_objc_interface();
1977
1978 c.set_name(cls->getQualifiedNameAsString());
1979 c.set_id(common::to_id(*cls));
1980
1981 process_comment(*cls, c);
1982 set_source_location(*cls, c);
1983
1984 if (c.skip())
1985 return {};
1986
1987 c.set_style(c.style_spec());
1988
1989 return c_ptr;
1990}

◆ ensure_activity_exists()

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

Definition at line 1513 of file translation_unit_visitor.cc.

1514{
1515 if (diagram().sequences().count(m.from()) == 0) {
1516 model::activity a{m.from()};
1517 diagram().sequences().insert({m.from(), std::move(a)});
1518 }
1519
1520 // Maintain reverse graph of activity callers
1521 activity_callers_[m.to()].emplace(m.from());
1522}

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

2444{
2445 for (auto &[id, activity] : diagram().sequences()) {
2446 for (auto &m : activity.messages()) {
2447 auto participant = diagram().get_participant<model::class_>(m.to());
2448
2449 if (participant && participant.value().is_lambda() &&
2450 participant.value().lambda_operator_id().value() != 0) {
2451 LOG_DBG("Changing lambda expression target id from {} to {}",
2452 m.to(), participant.value().lambda_operator_id());
2453
2454 m.set_to(participant.value().lambda_operator_id());
2455 m.set_message_name("operator()");
2456
2458 }
2459 }
2460 }
2461}

◆ finalize()

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

Finalize diagram model for this translation unit.

Definition at line 2427 of file translation_unit_visitor.cc.

2428{
2430
2431 // Change all messages with target set to an id of a lambda expression to
2432 // to the ID of their operator() - this is necessary, as some calls to
2433 // lambda expressions are visited before the actual lambda expressions
2434 // are visited...
2436
2438
2439 if (config().inline_lambda_messages())
2440 diagram().inline_lambda_operator_calls();
2441}

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

1526{
1527 auto generated_message_from_comment{false};
1528 for (const auto &decorator : m.decorators()) {
1529 auto call_decorator =
1530 std::dynamic_pointer_cast<decorators::call>(decorator);
1531 if (call_decorator &&
1532 call_decorator->applies_to_diagram(config().name)) {
1533 m.set_to(common::to_id(call_decorator->callee));
1534 generated_message_from_comment = true;
1535 break;
1536 }
1537 }
1538 return generated_message_from_comment;
1539}

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

2826{
2827 const auto *raw_comment =
2829
2830 if (raw_comment == nullptr)
2831 return {};
2832
2833 if (!caller_id.is_global() &&
2835 .emplace(caller_id.ast_local_value(), raw_comment)
2836 .second) {
2837 return {};
2838 }
2839
2840 const auto &[decorators, stripped_comment] = decorators::parse(
2841 raw_comment->getFormattedText(sm, sm.getDiagnostics()));
2842
2843 if (stripped_comment.empty())
2844 return {};
2845
2846 return {{raw_comment->getBeginLoc().getHashValue(), stripped_comment}};
2847}

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

183 {
184 assert(decl != nullptr);
185
186 auto unique_participant_id = get_unique_id(eid_t{decl->getID()});
187 if (!unique_participant_id.has_value())
188 return {};
189
190 return get_participant<T>(unique_participant_id.value());
191 }

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

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

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

221 {
222 if (diagram().participants().find(id) == diagram().participants().end())
223 return {};
224
225 return common::optional_ref<T>(
226 *(static_cast<T *>(diagram().participants().at(id).get())));
227 }

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

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

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

2151{
2152 if (local_id.is_global())
2153 return local_id;
2154
2155 return id_mapper().get_global_id(local_id);
2156}

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

1938{
1939 if (dependent_member_expr == nullptr)
1940 return false;
1941
1942 if (dependent_member_expr->getBaseType().isNull())
1943 return false;
1944
1945 const auto *tst = dependent_member_expr->getBaseType()
1946 ->getAs<clang::TemplateSpecializationType>();
1947
1948 if (tst == nullptr)
1949 return false;
1950
1951 return !(tst->isPointerType());
1952}

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

1956{
1957 return primary_template->getQualifiedNameAsString().find(
1958 "std::unique_ptr") == 0 ||
1959 primary_template->getQualifiedNameAsString().find("std::shared_ptr") ==
1960 0 ||
1961 primary_template->getQualifiedNameAsString().find("std::weak_ptr") == 0;
1962}

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

2280{
2281 const auto file_line =
2282 source_manager().getSpellingLineNumber(source_location);
2283 const auto file_column =
2284 source_manager().getSpellingColumnNumber(source_location);
2285 const std::string file_name =
2286 config()
2287 .make_path_relative(
2288 source_manager().getFilename(source_location).str())
2289 .string();
2290 return fmt::format("{}:{}:{}", file_name, file_line, file_column);
2291}

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

2295{
2296 std::string result;
2297 const auto location = cls->getLocation();
2298 const std::string source_location{lambda_source_location(location)};
2299
2300 const auto maybe_lambda_caller_id = context().lambda_caller_id();
2301 if (maybe_lambda_caller_id.has_value()) {
2302 // Parent is also a lambda (this id points to a lambda operator())
2303 std::string parent_lambda_class_name{"()"};
2304 if (diagram().get_participant<model::method>(
2305 maybe_lambda_caller_id.value())) {
2306 auto parent_lambda_class_id =
2307 diagram()
2308 .get_participant<model::method>(
2309 maybe_lambda_caller_id.value())
2310 .value()
2311 .class_id();
2312
2313 if (diagram().get_participant<model::class_>(
2314 parent_lambda_class_id)) {
2315 parent_lambda_class_name =
2316 diagram()
2317 .get_participant<model::class_>(parent_lambda_class_id)
2318 .value()
2319 .full_name(false);
2320 }
2321 }
2322
2323 result = fmt::format(
2324 "{}##(lambda {})", parent_lambda_class_name, source_location);
2325 }
2326 else if (context().caller_id().value() != 0 &&
2327 get_participant(context().caller_id()).has_value()) {
2328 auto parent_full_name =
2329 get_participant(context().caller_id()).value().full_name_no_ns();
2330
2331 result =
2332 fmt::format("{}##(lambda {})", parent_full_name, source_location);
2333 }
2334 else {
2335 result = fmt::format("(lambda {})", source_location);
2336 }
2337
2338 return result;
2339}

◆ pop_message_to_diagram() [1/3]

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

2360{
2361 assert(expr != nullptr);
2362
2363 // Skip if no message was generated from this expr
2364 if (call_expr_message_map_.find(expr) == call_expr_message_map_.end()) {
2365 return;
2366 }
2367
2368 if (call_expr_message_map_.at(expr).empty())
2369 return;
2370
2371 while (!call_expr_message_map_.at(expr).empty()) {
2372 auto msg = call_expr_message_map_.at(expr).front();
2373
2374 auto caller_id = msg.from();
2375
2376 if (caller_id == 0)
2377 return;
2378
2379 if (diagram().has_activity(caller_id))
2380 diagram().get_activity(caller_id).add_message(std::move(msg));
2381 else
2382 LOG_DBG("Skipping message due to missing activity: {}", caller_id);
2383
2384 call_expr_message_map_.at(expr).pop_front();
2385 }
2386
2387 call_expr_message_map_.erase(expr);
2388}

◆ pop_message_to_diagram() [2/3]

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

Definition at line 2390 of file translation_unit_visitor.cc.

2392{
2393 assert(expr != nullptr);
2394
2395 // Skip if no message was generated from this expr
2396 if (construct_expr_message_map_.find(expr) ==
2398 return;
2399 }
2400
2401 auto msg = std::move(construct_expr_message_map_.at(expr));
2402
2403 auto caller_id = msg.from();
2404 diagram().get_activity(caller_id).add_message(std::move(msg));
2405
2406 construct_expr_message_map_.erase(expr);
2407}

◆ pop_message_to_diagram() [3/3]

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

Definition at line 2409 of file translation_unit_visitor.cc.

2411{
2412 assert(expr != nullptr);
2413
2414 // Skip if no message was generated from this expr
2415 if (objc_message_map_.find(expr) == objc_message_map_.end()) {
2416 return;
2417 }
2418
2419 auto msg = std::move(objc_message_map_.at(expr));
2420
2421 auto caller_id = msg.from();
2422 diagram().get_activity(caller_id).add_message(std::move(msg));
2423
2424 objc_message_map_.erase(expr);
2425}

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

1744{
1745 // Get callee declaration as methods parent
1746 const auto *method_decl = method_call_expr->getMethodDecl();
1747
1748 if (method_decl == nullptr)
1749 return false;
1750
1751 std::string method_name = method_decl->getQualifiedNameAsString();
1752
1753 const auto *callee_decl =
1754 method_decl != nullptr ? method_decl->getParent() : nullptr;
1755
1756 if (callee_decl == nullptr)
1757 return false;
1758
1759 if (!should_include(callee_decl) || !should_include(method_decl))
1760 return false;
1761
1762 m.set_to(eid_t{method_decl->getID()});
1763 m.set_message_name(method_decl->getNameAsString());
1764 m.set_return_type(
1765 method_call_expr->getCallReturnType(*context().get_ast_context())
1766 .getAsString());
1767
1768 LOG_TRACE("Set callee method id {} for method name {}", m.to(),
1769 method_decl->getQualifiedNameAsString());
1770
1771 diagram().add_active_participant(eid_t{method_decl->getID()});
1772
1773 return true;
1774}

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

1778{
1779 const auto *dependent_member_callee =
1780 clang::dyn_cast_or_null<clang::CXXDependentScopeMemberExpr>(
1781 expr->getCallee());
1782
1783 if (dependent_member_callee == nullptr)
1784 return false;
1785
1786 if (is_callee_valid_template_specialization(dependent_member_callee)) {
1787 if (const auto *tst = dependent_member_callee->getBaseType()
1788 ->getAs<clang::TemplateSpecializationType>();
1789 tst != nullptr) {
1790 const auto *template_declaration =
1791 tst->getTemplateName().getAsTemplateDecl();
1792
1793 std::string callee_method_full_name;
1794
1795 // First check if the primary template is already in the
1796 // participants map
1797 if (get_participant(template_declaration).has_value()) {
1798 callee_method_full_name = get_participant(template_declaration)
1799 .value()
1800 .full_name(false) +
1801 "::" + dependent_member_callee->getMember().getAsString();
1802
1803 for (const auto &[id, p] : diagram().participants()) {
1804 const auto p_full_name = p->full_name(false);
1805
1806 if (p_full_name.find(callee_method_full_name + "(") == 0) {
1807 // TODO: This selects the first matching template method
1808 // without considering arguments!!!
1809 m.set_to(id);
1810 break;
1811 }
1812 }
1813 }
1814 // Otherwise check if it is a smart pointer
1815 else if (is_smart_pointer(template_declaration)) {
1816 const auto *argument_template =
1817 template_declaration->getTemplateParameters()
1818 ->asArray()
1819 .front();
1820
1821 if (get_participant(argument_template).has_value()) {
1822 callee_method_full_name = get_participant(argument_template)
1823 .value()
1824 .full_name(false) +
1825 "::" +
1826 dependent_member_callee->getMember().getAsString();
1827
1828 for (const auto &[id, p] : diagram().participants()) {
1829 const auto p_full_name = p->full_name(false);
1830 if (p_full_name.find(callee_method_full_name + "(") ==
1831 0) {
1832 // TODO: This selects the first matching template
1833 // method without considering arguments!!!
1834 m.set_to(id);
1835 break;
1836 }
1837 }
1838 }
1839 else
1840 return false;
1841 }
1842
1843 m.set_message_name(
1844 dependent_member_callee->getMember().getAsString());
1845
1846 if (const auto maybe_id =
1847 get_unique_id(eid_t{template_declaration->getID()});
1848 maybe_id.has_value())
1849 diagram().add_active_participant(maybe_id.value());
1850 }
1851 }
1852 else {
1853 LOG_DBG("Skipping call due to unresolvable "
1854 "CXXDependentScopeMemberExpr at {}",
1855 expr->getBeginLoc().printToString(source_manager()));
1856 }
1857
1858 return true;
1859}

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

2238{
2239 auto c_ptr{std::make_unique<model::class_>(config().using_namespace())};
2240
2242
2243 auto &template_instantiation = *c_ptr;
2244
2245 // TODO: refactor to method get_qualified_name()
2246 auto qualified_name = cls->getQualifiedNameAsString();
2247 util::replace_all(qualified_name, "(anonymous namespace)", "");
2248 util::replace_all(qualified_name, "::::", "::");
2249
2250 common::model::namespace_ ns{qualified_name};
2251 ns.pop_back();
2252 template_instantiation.set_name(cls->getNameAsString());
2253 template_instantiation.set_namespace(ns);
2254
2255 template_instantiation.is_struct(cls->isStruct());
2256
2257 process_comment(*cls, template_instantiation);
2258 set_source_location(*cls, template_instantiation);
2259 set_owning_module(*cls, template_instantiation);
2260
2261 if (template_instantiation.skip())
2262 return {};
2263
2264 template_instantiation.set_id(
2265 common::to_id(template_instantiation.full_name(false)));
2266
2267 set_unique_id(cls->getID(), template_instantiation.id());
2268
2269 return c_ptr;
2270}

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

1671{
1672 const auto *constructor = construct_expr->getConstructor();
1673 if (constructor == nullptr)
1674 return false;
1675
1676 const auto *constructor_parent = constructor->getParent();
1677 if (constructor_parent == nullptr)
1678 return false;
1679
1680 LOG_DBG("Constructor '{}' call expression to {} at {}",
1681 construct_expr->getConstructor()->getNameAsString(),
1682 constructor->getID(),
1683 construct_expr->getBeginLoc().printToString(source_manager()));
1684
1685 m.set_to(id_mapper().resolve_or(eid_t{constructor->getID()}));
1686 m.set_message_name(
1687 fmt::format("{}::{}", constructor_parent->getQualifiedNameAsString(),
1688 constructor_parent->getNameAsString()));
1689
1690 diagram().add_active_participant(eid_t{constructor->getID()});
1691
1692 return true;
1693}

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

1604{
1605 const auto *callee_decl = expr->getCalleeDecl();
1606
1607 if (callee_decl == nullptr)
1608 return false;
1609
1610 const auto *callee_function = callee_decl->getAsFunction();
1611
1612 if (callee_function == nullptr)
1613 return false;
1614
1615 if (!should_include(callee_function))
1616 return false;
1617
1618 // Skip free functions declared in files outside of included paths
1619 if (config().combine_free_functions_into_file_participants() &&
1620 !diagram().should_include(common::model::source_file{m.file()}))
1621 return false;
1622
1623 auto callee_name = callee_function->getQualifiedNameAsString() + "()";
1624
1625 m.set_to(id_mapper().resolve_or(eid_t{callee_function->getID()}));
1626 m.set_message_name(callee_name.substr(0, callee_name.size() - 2));
1627
1628 return true;
1629}

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

1863{
1864 const auto *callee_decl = expr->getCalleeDecl();
1865
1866 if (callee_decl == nullptr)
1867 return false;
1868
1869 const auto *callee_function = callee_decl->getAsFunction();
1870
1871 if (callee_function == nullptr)
1872 return false;
1873
1874 if (!should_include(callee_function))
1875 return false;
1876
1877 // Skip free functions declared in files outside of included paths
1878 if (config().combine_free_functions_into_file_participants() &&
1879 !diagram().should_include(common::model::source_file{m.file()}))
1880 return false;
1881
1882 auto callee_name = callee_function->getQualifiedNameAsString() + "()";
1883
1884 m.set_to(id_mapper().resolve_or(eid_t{callee_function->getID()}));
1885 m.set_message_name(callee_name.substr(0, callee_name.size() - 2));
1886
1887 return true;
1888}

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

1892{
1893 const auto *lambda_expr =
1894 clang::dyn_cast_or_null<clang::LambdaExpr>(expr->getCallee());
1895
1896 if (lambda_expr == nullptr)
1897 return true;
1898
1899 const auto lambda_class_id = eid_t{lambda_expr->getLambdaClass()->getID()};
1900 m.set_to(id_mapper().resolve_or(eid_t{lambda_class_id}));
1901
1902 return true;
1903}

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

1697{
1698 const auto *method_decl = message_expr->getMethodDecl();
1699
1700 if (method_decl == nullptr)
1701 return false;
1702
1703 std::string method_name = method_decl->getQualifiedNameAsString();
1704
1705 if (message_expr->getReceiverInterface() == nullptr)
1706 return false;
1707
1708 const auto *callee_decl = message_expr->getReceiverInterface();
1709
1710 if (callee_decl == nullptr)
1711 return false;
1712
1713 if (!should_include(callee_decl) || !should_include(method_decl))
1714 return false;
1715
1716 if (callee_decl->getImplementation() != nullptr &&
1717 callee_decl->getImplementation()->getMethod(method_decl->getSelector(),
1718 method_decl->isInstanceMethod(), true) != nullptr) {
1719 const auto *impl_method_decl =
1720 callee_decl->getImplementation()->getMethod(
1721 method_decl->getSelector(), method_decl->isInstanceMethod(),
1722 true);
1723 m.set_to(eid_t{impl_method_decl->getID()});
1724 }
1725 else {
1726 m.set_to(eid_t{method_decl->getID()});
1727 }
1728
1729 m.set_message_name(method_decl->getNameAsString());
1730 m.set_return_type(
1731 message_expr->getCallReturnType(*context().get_ast_context())
1732 .getAsString());
1733
1734 LOG_TRACE("Set callee ObjC method id {} for method name {}", m.to(),
1735 method_decl->getQualifiedNameAsString());
1736
1737 diagram().add_active_participant(eid_t{method_decl->getID()});
1738
1739 return true;
1740}

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

1633{
1634 if (operator_call_expr->getCalleeDecl() == nullptr)
1635 return false;
1636
1637 LOG_DBG("Operator '{}' call expression to {} at {}",
1638 getOperatorSpelling(operator_call_expr->getOperator()),
1639 operator_call_expr->getCalleeDecl()->getID(),
1640 operator_call_expr->getBeginLoc().printToString(source_manager()));
1641
1642 // Handle the case if the callee is a lambda
1643 if (const auto *lambda_method = clang::dyn_cast<clang::CXXMethodDecl>(
1644 operator_call_expr->getCalleeDecl());
1645 lambda_method != nullptr && lambda_method->getParent()->isLambda()) {
1646
1647 LOG_DBG("Operator callee is a lambda: {}",
1648 common::to_string(lambda_method));
1649
1650 const auto source_location{
1651 lambda_source_location(lambda_method->getParent()->getLocation())};
1652
1653 auto lambda_name = make_lambda_name(lambda_method->getParent());
1654
1655 m.set_to(eid_t{lambda_method->getParent()->getID()});
1656 }
1657 else {
1658 const auto operator_ast_id =
1659 operator_call_expr->getCalleeDecl()->getID();
1660 m.set_to(id_mapper().resolve_or(eid_t{operator_ast_id}));
1661 }
1662
1663 m.set_message_name(fmt::format(
1664 "operator{}", getOperatorSpelling(operator_call_expr->getOperator())));
1665
1666 return true;
1667}

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

1907{
1908 // This is probably a template
1909 const auto *unresolved_expr =
1910 clang::dyn_cast_or_null<clang::UnresolvedLookupExpr>(expr->getCallee());
1911
1912 if (unresolved_expr != nullptr) {
1913 for (const auto *decl : unresolved_expr->decls()) {
1914 if (clang::dyn_cast_or_null<clang::FunctionTemplateDecl>(decl) !=
1915 nullptr) {
1916 const auto *ftd =
1917 clang::dyn_cast_or_null<clang::FunctionTemplateDecl>(decl);
1918 m.set_to(id_mapper().resolve_or(eid_t{ftd->getID()}));
1919 break;
1920 }
1921
1922 if (clang::dyn_cast_or_null<clang::FunctionDecl>(decl) != nullptr) {
1923 const auto *fd =
1924 clang::dyn_cast_or_null<clang::FunctionDecl>(decl);
1925 m.set_to(id_mapper().resolve_or(eid_t{fd->getID()}));
1926 break;
1927 }
1928
1929 LOG_DBG("Unknown unresolved lookup expression");
1930 }
1931 }
1932
1933 return true;
1934}

◆ push_message() [1/3]

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

2343{
2344 call_expr_message_map_[expr].push_back(std::move(m));
2345}

◆ push_message() [2/3]

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

Definition at line 2347 of file translation_unit_visitor.cc.

2349{
2350 construct_expr_message_map_.emplace(expr, std::move(m));
2351}

◆ push_message() [3/3]

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

Definition at line 2353 of file translation_unit_visitor.cc.

2355{
2356 objc_message_map_.emplace(expr, std::move(m));
2357}

◆ resolve_ids_to_global()

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

Definition at line 2463 of file translation_unit_visitor.cc.

2464{
2465 std::set<eid_t> active_participants_unique;
2466
2467 // Change all active participants AST local ids to diagram global ids
2468 for (auto id : diagram().active_participants()) {
2469 if (const auto unique_id = get_unique_id(id);
2470 !id.is_global() && unique_id.has_value()) {
2471 active_participants_unique.emplace(unique_id.value());
2472 }
2473 else if (id.is_global()) {
2474 active_participants_unique.emplace(id);
2475 }
2476 }
2477
2478 diagram().active_participants() = std::move(active_participants_unique);
2479
2480 // Change all message callees AST local ids to diagram global ids
2481 for (auto &[id, activity] : diagram().sequences()) {
2482 for (auto &m : activity.messages()) {
2483 if (const auto unique_id = get_unique_id(m.to());
2484 !m.to().is_global() && unique_id.has_value()) {
2485 m.set_to(unique_id.value());
2486 assert(m.to().is_global());
2487 }
2488 }
2489 }
2490}

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

2141{
2142 LOG_TRACE("Setting local element mapping {} --> {}", local_id, global_id);
2143
2144 assert(global_id.is_global());
2145
2146 id_mapper().add(local_id, global_id);
2147}

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

2737{
2738 if (context().caller_id() == 0)
2739 return false;
2740
2741 // Skip casts, moves and such
2742 if (expr->isCallToStdMove())
2743 return false;
2744
2745 if (expr->isImplicitCXXThis())
2746 return false;
2747
2748 if (clang::dyn_cast_or_null<clang::ImplicitCastExpr>(expr) != nullptr)
2749 return false;
2750
2751 if (!context().valid())
2752 return false;
2753
2754 const auto expr_file = expr->getBeginLoc().printToString(source_manager());
2755
2756 if (!diagram().should_include(
2757 common::model::source_file{get_file_path(expr_file)}))
2758 return false;
2759
2760 const auto *callee_decl = expr->getCalleeDecl();
2761
2762 if (callee_decl != nullptr) {
2763 const auto *callee_function = callee_decl->getAsFunction();
2764
2765 if ((callee_function == nullptr) || !should_include(callee_function)) {
2766 LOG_DBG("Skipping call expression at {}",
2767 expr->getBeginLoc().printToString(source_manager()));
2768 return false;
2769 }
2770
2771 return should_include(callee_function);
2772 }
2773
2774 return true;
2775}

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

2818{
2820}

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

2779{
2780 if (!should_include(decl->getParent()))
2781 return false;
2782
2783 if (!diagram().should_include(
2784 common::access_specifier_to_access_t(decl->getAccess())))
2785 return false;
2786
2787 LOG_DBG("Including method {}", decl->getQualifiedNameAsString());
2788
2789 return true;
2790}

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

2806{
2808}

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

2812{
2813 return visitor_specialization_t::should_include(decl->getAsFunction());
2814}

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

2702{
2703 if (context().caller_id() == 0)
2704 return false;
2705
2706 if (!context().valid())
2707 return false;
2708
2709 const auto expr_file = expr->getBeginLoc().printToString(source_manager());
2710
2711 if (!diagram().should_include(
2712 common::model::source_file{get_file_path(expr_file)}))
2713 return false;
2714
2715 return true;
2716}

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

2695{
2697 dynamic_cast<const clang::NamedDecl *>(decl));
2698}

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

2720{
2721 if (context().caller_id() == 0)
2722 return false;
2723
2724 if (!context().valid())
2725 return false;
2726
2727 const auto expr_file = expr->getBeginLoc().printToString(source_manager());
2728
2729 if (!diagram().should_include(
2730 common::model::source_file{get_file_path(expr_file)}))
2731 return false;
2732
2733 return true;
2734}

◆ should_include() [9/10]

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

Definition at line 2792 of file translation_unit_visitor.cc.

2794{
2795 if (!diagram().should_include(
2796 common::access_specifier_to_access_t(decl->getAccess())))
2797 return false;
2798
2799 LOG_DBG("Including ObjC method {}", decl->getQualifiedNameAsString());
2800
2801 return true;
2802}

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

2688{
2690 dynamic_cast<const clang::NamedDecl *>(decl));
2691}

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

2274{
2275 return config().simplify_template_type(full_name);
2276}

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

537{ 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 566 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 570 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 564 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 553 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 545 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 555 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 559 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 556 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 573 of file translation_unit_visitor.h.

◆ template_builder_

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

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


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