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::class_diagram::visitor::translation_unit_visitor Class Reference

Class diagram translation unit visitor. More...

Detailed Description

Class diagram translation unit visitor.

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

Definition at line 74 of file translation_unit_visitor.h.

#include <translation_unit_visitor.h>

Public Types

using template_builder_t = 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::class_diagram::model::diagram &diagram, const clanguml::config::class_diagram &config)
 Constructor.
 
bool shouldVisitTemplateInstantiations () const
 
bool shouldVisitImplicitCode () const
 
virtual bool VisitNamespaceDecl (clang::NamespaceDecl *ns)
 
virtual bool VisitRecordDecl (clang::RecordDecl *D)
 
virtual bool VisitCXXRecordDecl (clang::CXXRecordDecl *d)
 
virtual bool VisitTypedefDecl (clang::TypedefDecl *decl)
 
virtual bool VisitEnumDecl (clang::EnumDecl *e)
 
virtual bool VisitClassTemplateDecl (clang::ClassTemplateDecl *class_template_declaration)
 
virtual bool VisitClassTemplateSpecializationDecl (clang::ClassTemplateSpecializationDecl *cls)
 
virtual bool VisitTypeAliasTemplateDecl (clang::TypeAliasTemplateDecl *cls)
 
virtual bool TraverseConceptDecl (clang::ConceptDecl *cpt)
 
virtual bool VisitObjCCategoryDecl (clang::ObjCCategoryDecl *decl)
 
virtual bool VisitObjCProtocolDecl (clang::ObjCProtocolDecl *decl)
 
virtual bool VisitObjCInterfaceDecl (clang::ObjCInterfaceDecl *decl)
 
void finalize ()
 Finalize diagram model.
 
void add_class (std::unique_ptr< class_ > &&c)
 Add class (or template class) to the diagram.
 
void add_enum (std::unique_ptr< enum_ > &&e)
 Add enum to the diagram.
 
void add_concept (std::unique_ptr< concept_ > &&c)
 Add concept to the diagram.
 
void add_objc_interface (std::unique_ptr< objc_interface > &&c)
 
void add_diagram_element (std::unique_ptr< common::model::template_element > element) override
 
std::unique_ptr< class_create_element (const clang::NamedDecl *decl) const
 
void find_instantiation_relationships (common::model::template_element &template_instantiation_base, const std::string &full_name, eid_t templated_decl_id)
 
- 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

std::unique_ptr< clanguml::class_diagram::model::class_create_class_declaration (clang::CXXRecordDecl *cls)
 Create class element model from class declaration.
 
std::unique_ptr< clanguml::class_diagram::model::enum_create_enum_declaration (const clang::EnumDecl *enm, const clang::TypedefDecl *typedef_decl)
 Create enum element model from enum (e.g. struct) declaration.
 
std::unique_ptr< clanguml::class_diagram::model::class_create_record_declaration (clang::RecordDecl *rec)
 Create class element model from record (e.g. struct) declaration.
 
std::unique_ptr< clanguml::class_diagram::model::objc_interfacecreate_objc_protocol_declaration (clang::ObjCProtocolDecl *decl)
 Create class element model from Objective-C protocol.
 
std::unique_ptr< clanguml::class_diagram::model::objc_interfacecreate_objc_interface_declaration (clang::ObjCInterfaceDecl *decl)
 Create class element model from Objective-C interface.
 
std::unique_ptr< clanguml::class_diagram::model::objc_interfacecreate_objc_category_declaration (clang::ObjCCategoryDecl *decl)
 Create class element model from Objective-C category.
 
std::unique_ptr< clanguml::class_diagram::model::concept_create_concept_declaration (clang::ConceptDecl *cpt)
 Create concept element model from concept declaration.
 
void process_class_declaration (const clang::CXXRecordDecl &cls, clanguml::class_diagram::model::class_ &c)
 Process class declaration.
 
void process_objc_category_declaration (const clang::ObjCCategoryDecl &cls, objc_interface &c)
 Process Objective-C category declaration.
 
void process_objc_protocol_declaration (const clang::ObjCProtocolDecl &cls, objc_interface &c)
 Process Objective-C protocol declaration.
 
void process_objc_interface_declaration (const clang::ObjCInterfaceDecl &cls, objc_interface &c)
 Process Objective-C interface declaration.
 
void process_class_bases (const clang::CXXRecordDecl *cls, clanguml::class_diagram::model::class_ &c)
 Process class declaration bases (parents), if any.
 
void process_class_children (const clang::CXXRecordDecl *cls, clanguml::class_diagram::model::class_ &c)
 Process class children elements (members and methods)
 
void process_record_members (const clang::RecordDecl *cls, class_ &c)
 Process class or record data members.
 
std::unique_ptr< clanguml::class_diagram::model::class_process_template_specialization (clang::ClassTemplateSpecializationDecl *cls)
 Process class template specialization/instantiation.
 
void process_template_specialization_children (const clang::ClassTemplateSpecializationDecl *cls, class_ &c)
 Process template specialization children (members and methods)
 
void process_method (const clang::CXXMethodDecl &mf, clanguml::class_diagram::model::class_ &c)
 Process class method.
 
void process_objc_method (const clang::ObjCMethodDecl &mf, objc_interface &c)
 Process Objective-C method.
 
void process_method_properties (const clang::CXXMethodDecl &mf, const class_ &c, const std::string &method_name, class_method &method) const
 Process class method properties.
 
void process_template_method (const clang::FunctionTemplateDecl &mf, clanguml::class_diagram::model::class_ &c)
 Process class template method.
 
void process_static_field (const clang::VarDecl &field_declaration, clanguml::class_diagram::model::class_ &c)
 Process class static data member.
 
void process_field (const clang::FieldDecl &field_declaration, clanguml::class_diagram::model::class_ &c)
 Process class data member.
 
void process_objc_ivar (const clang::ObjCIvarDecl &ivar, objc_interface &c)
 Process Objective-C data member.
 
void process_objc_interface_base (const clang::ObjCInterfaceDecl &cls, objc_interface &c)
 Process Objective-C class base.
 
void process_function_parameter (const clang::ParmVarDecl &param, class_method &method, class_ &c, const std::set< std::string > &template_parameter_names={})
 Process function/method parameter.
 
void process_objc_method_parameter (const clang::ParmVarDecl &param, objc_method &method, objc_interface &c)
 Process Objective-C class method parameter.
 
void process_friend (const clang::FriendDecl &f, class_ &c)
 Process class friend.
 
bool find_relationships (const clang::Decl *decl, const clang::QualType &type, found_relationships_t &, clanguml::common::model::relationship_t relationship_hint)
 Find relationships in a specific type.
 
void add_relationships (diagram_element &c, const class_member_base &field, const found_relationships_t &relationships, bool break_on_first_aggregation=false)
 Add relationships from relationship list to a diagram element model.
 
void process_record_parent (clang::RecordDecl *cls, class_ &c, const namespace_ &ns)
 Process record parent element (e.g. for nested classes)
 
void process_function_parameter_find_relationships_in_autotype (model::class_ &c, const clang::AutoType *atsp)
 Find relationships in function parameter.
 
void find_relationships_in_constraint_expression (clanguml::common::model::element &c, const clang::Expr *expr)
 Find relationships in concept constraint expression.
 
void add_incomplete_forward_declarations ()
 Register incomplete forward declaration to be updated later.
 
void resolve_local_to_global_ids ()
 Replace any AST local ids in diagram elements with global ones.
 
void process_constraint_requirements (const clang::ConceptDecl *cpt, const clang::Expr *expr, model::concept_ &concept_model) const
 Process concept constraint requirements.
 
void process_concept_specialization_relationships (common::model::element &c, const clang::ConceptSpecializationExpr *concept_specialization)
 Find concept specializations relationships.
 
void extract_constrained_template_param_name (const clang::ConceptSpecializationExpr *concept_specialization, const clang::ConceptDecl *cpt, std::vector< std::string > &constrained_template_params, size_t argument_index, std::string &type_name) const
 Extract template contraint parameter name from raw source code.
 
void add_processed_template_class (std::string qualified_name)
 Register already processed template class name.
 
bool has_processed_template_class (const std::string &qualified_name) const
 Check if template class has already been processed.
 
template_builder_ttbuilder ()
 Get template builder reference.
 
template<typename T >
void process_record_parent_by_type (eid_t parent_id, class_ &c, namespace_ parent_ns, const clang::RecordDecl *decl)
 
void find_record_parent_id (const clang::TagDecl *decl, std::optional< eid_t > &parent_id_opt, namespace_ &parent_ns) const
 

Private Attributes

template_builder_t template_builder_
 
std::map< eid_t, std::unique_ptr< clanguml::class_diagram::model::class_ > > forward_declarations_
 
std::map< int64_t, std::tuple< std::string, common::model::relationship_t, common::model::access_t, std::optional< size_t > > > anonymous_struct_relationships_
 
std::map< const clang::EnumDecl *, const clang::TypedefDecl * > typedef_enum_decls_
 
std::set< std::string > processed_template_qualified_names_
 

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

Constructor & Destructor Documentation

◆ translation_unit_visitor()

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

Constructor.

Parameters
smCurrent source manager reference
diagramDiagram model
configDiagram configuration

Definition at line 29 of file translation_unit_visitor.cc.

Member Function Documentation

◆ add_class()

void clanguml::class_diagram::visitor::translation_unit_visitor::add_class ( std::unique_ptr< class_ > &&  c)

Add class (or template class) to the diagram.

Parameters
cClass model

Definition at line 2554 of file translation_unit_visitor.cc.

2555{
2556 c->complete(true);
2557
2558 if ((config().generate_packages() &&
2559 config().package_type() == config::package_type_t::kDirectory)) {
2560 assert(!c->file().empty());
2561
2562 const auto file = config().make_path_relative(c->file());
2563
2564 common::model::path p{
2566 p.pop_back();
2567
2568 diagram().add(p, std::move(c));
2569 }
2570 else if ((config().generate_packages() &&
2571 config().package_type() == config::package_type_t::kModule)) {
2572
2573 const auto module_path = config().make_module_relative(c->module());
2574
2575 common::model::path p{module_path, common::model::path_type::kModule};
2576
2577 diagram().add(p, std::move(c));
2578 }
2579 else {
2580 diagram().add(c->path(), std::move(c));
2581 }
2582}

◆ add_concept()

void clanguml::class_diagram::visitor::translation_unit_visitor::add_concept ( std::unique_ptr< concept_ > &&  c)

Add concept to the diagram.

Parameters
cConcept model

Definition at line 2636 of file translation_unit_visitor.cc.

2637{
2638 c->complete(true);
2639
2640 if ((config().generate_packages() &&
2641 config().package_type() == config::package_type_t::kDirectory)) {
2642 assert(!c->file().empty());
2643
2644 const auto file = config().make_path_relative(c->file());
2645
2646 common::model::path p{
2648 p.pop_back();
2649
2650 diagram().add(p, std::move(c));
2651 }
2652 else if ((config().generate_packages() &&
2653 config().package_type() == config::package_type_t::kModule)) {
2654
2655 const auto module_path = config().make_module_relative(c->module());
2656
2657 common::model::path p{module_path, common::model::path_type::kModule};
2658
2659 diagram().add(p, std::move(c));
2660 }
2661 else {
2662 diagram().add(c->path(), std::move(c));
2663 }
2664}

◆ add_diagram_element()

void clanguml::class_diagram::visitor::translation_unit_visitor::add_diagram_element ( std::unique_ptr< common::model::template_element element)
overridevirtual

Reimplemented from clanguml::common::visitor::translation_unit_visitor< ConfigT, DiagramT >.

Definition at line 2548 of file translation_unit_visitor.cc.

2550{
2551 add_class(util::unique_pointer_cast<class_>(std::move(element)));
2552}

◆ add_enum()

void clanguml::class_diagram::visitor::translation_unit_visitor::add_enum ( std::unique_ptr< enum_ > &&  e)

Add enum to the diagram.

Parameters
eEnum model

Definition at line 2606 of file translation_unit_visitor.cc.

2607{
2608 e->complete(true);
2609
2610 if ((config().generate_packages() &&
2611 config().package_type() == config::package_type_t::kDirectory)) {
2612 assert(!e->file().empty());
2613
2614 const auto file = config().make_path_relative(e->file());
2615
2616 common::model::path p{
2618 p.pop_back();
2619
2620 diagram().add(p, std::move(e));
2621 }
2622 else if ((config().generate_packages() &&
2623 config().package_type() == config::package_type_t::kModule)) {
2624
2625 const auto module_path = config().make_module_relative(e->module());
2626
2627 common::model::path p{module_path, common::model::path_type::kModule};
2628
2629 diagram().add(p, std::move(e));
2630 }
2631 else {
2632 diagram().add(e->path(), std::move(e));
2633 }
2634}

◆ add_incomplete_forward_declarations()

void clanguml::class_diagram::visitor::translation_unit_visitor::add_incomplete_forward_declarations ( )
private

Register incomplete forward declaration to be updated later.

Definition at line 2468 of file translation_unit_visitor.cc.

2469{
2470 for (auto &[id, c] : forward_declarations_) {
2471 if (diagram().should_include(c->get_namespace())) {
2472 add_class(std::move(c));
2473 }
2474 }
2475 forward_declarations_.clear();
2476}

◆ add_objc_interface()

void clanguml::class_diagram::visitor::translation_unit_visitor::add_objc_interface ( std::unique_ptr< objc_interface > &&  c)

Definition at line 2584 of file translation_unit_visitor.cc.

2586{
2587 c->complete(true);
2588
2589 if ((config().generate_packages() &&
2590 config().package_type() == config::package_type_t::kDirectory)) {
2591 assert(!c->file().empty());
2592
2593 const auto file = config().make_path_relative(c->file());
2594
2595 common::model::path p{
2597 p.pop_back();
2598
2599 diagram().add(p, std::move(c));
2600 }
2601 else {
2602 diagram().add(c->path(), std::move(c));
2603 }
2604}

◆ add_processed_template_class()

void clanguml::class_diagram::visitor::translation_unit_visitor::add_processed_template_class ( std::string  qualified_name)
private

Register already processed template class name.

Parameters
qualified_nameFully qualified template class name

Definition at line 2536 of file translation_unit_visitor.cc.

2538{
2539 processed_template_qualified_names_.emplace(std::move(qualified_name));
2540}

◆ add_relationships()

void clanguml::class_diagram::visitor::translation_unit_visitor::add_relationships ( diagram_element c,
const class_member_base field,
const found_relationships_t &  relationships,
bool  break_on_first_aggregation = false 
)
private

Add relationships from relationship list to a diagram element model.

This method takes a list of relationships whose originating element is class c and adds them to it, ignoring any duplicates and skipping relationships that should be excluded from the diagram.

Parameters
cDiagram element model
fieldClass member model
relationshipsList of found relationships
break_on_first_aggregationStop adding relatinoships, after first aggregation is found

Definition at line 2083 of file translation_unit_visitor.cc.

2086{
2087 auto [decorator_rtype, decorator_rmult] = field.get_relationship();
2088
2089 for (const auto &[target, relationship_type, source_decl] : relationships) {
2090 if (relationship_type != relationship_t::kNone) {
2091 relationship r{relationship_type, target};
2092 r.set_label(field.name());
2093 r.set_access(field.access());
2094 if (source_decl != nullptr) {
2095 set_source_location(*source_decl, r);
2096 }
2097 bool mulitplicity_provided_in_comment{false};
2098 if (decorator_rtype != relationship_t::kNone) {
2099 r.set_type(decorator_rtype);
2100 auto mult = util::split(decorator_rmult, ":", false);
2101 if (mult.size() == 2) {
2102 mulitplicity_provided_in_comment = true;
2103 r.set_multiplicity_source(mult[0]);
2104 r.set_multiplicity_destination(mult[1]);
2105 }
2106 }
2107 if (!mulitplicity_provided_in_comment &&
2108 field.destination_multiplicity().has_value()) {
2109 r.set_multiplicity_destination(
2110 std::to_string(*field.destination_multiplicity()));
2111 }
2112
2113 r.set_style(field.style_spec());
2114
2115 LOG_DBG("Adding relationship from {} to {} with label {}", c,
2116 r.destination(), r.type(), r.label());
2117
2118 c.add_relationship(std::move(r));
2119
2120 if (break_on_first_aggregation &&
2121 relationship_type == relationship_t::kAggregation)
2122 break;
2123 }
2124 }
2125}

◆ create_class_declaration()

std::unique_ptr< class_ > clanguml::class_diagram::visitor::translation_unit_visitor::create_class_declaration ( clang::CXXRecordDecl *  cls)
private

Create class element model from class declaration.

Parameters
clsClass declaration
Returns
Class diagram element model

Definition at line 983 of file translation_unit_visitor.cc.

985{
986 assert(cls != nullptr);
987
988 if (!should_include(cls))
989 return {};
990
991 auto c_ptr{std::make_unique<class_>(config().using_namespace())};
992 auto &c = *c_ptr;
993
994 auto ns{common::get_tag_namespace(*cls)};
995
996 process_record_parent(cls, c, ns);
997
998 if (!c.is_nested()) {
999 c.set_name(common::get_tag_name(*cls));
1000 c.set_namespace(ns);
1001 c.set_id(common::to_id(c.full_name(false)));
1002 }
1003
1004 c.is_struct(cls->isStruct());
1005
1006 process_comment(*cls, c);
1007 set_source_location(*cls, c);
1008 set_owning_module(*cls, c);
1009
1010 if (c.skip())
1011 return {};
1012
1013 c.set_style(c.style_spec());
1014
1015 return c_ptr;
1016}

◆ create_concept_declaration()

std::unique_ptr< clanguml::class_diagram::model::concept_ > clanguml::class_diagram::visitor::translation_unit_visitor::create_concept_declaration ( clang::ConceptDecl *  cpt)
private

Create concept element model from concept declaration.

Parameters
cptConcept declaration
Returns
Concept diagram element model

Definition at line 908 of file translation_unit_visitor.cc.

909{
910 assert(cpt != nullptr);
911
912 if (!should_include(cpt))
913 return {};
914
915 auto concept_ptr{
916 std::make_unique<model::concept_>(config().using_namespace())};
917 auto &concept_model = *concept_ptr;
918
919 auto ns = common::get_template_namespace(*cpt);
920
921 concept_model.set_name(cpt->getNameAsString());
922 concept_model.set_namespace(ns);
923 concept_model.set_id(common::to_id(concept_model.full_name(false)));
924
925 process_comment(*cpt, concept_model);
926 set_source_location(*cpt, concept_model);
927 set_owning_module(*cpt, concept_model);
928
929 if (concept_model.skip())
930 return {};
931
932 concept_model.set_style(concept_model.style_spec());
933
934 return concept_ptr;
935}

◆ create_element()

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

Definition at line 37 of file translation_unit_visitor.cc.

39{
40 auto cls = std::make_unique<class_>(config().using_namespace());
41 cls->is_struct(common::is_struct(decl));
42 return cls;
43}

◆ create_enum_declaration()

std::unique_ptr< clanguml::class_diagram::model::enum_ > clanguml::class_diagram::visitor::translation_unit_visitor::create_enum_declaration ( const clang::EnumDecl *  enm,
const clang::TypedefDecl *  typedef_decl 
)
private

Create enum element model from enum (e.g. struct) declaration.

Parameters
recEnum declaration
Returns
Enum diagram element model

Definition at line 153 of file translation_unit_visitor.cc.

155{
156 auto e_ptr = std::make_unique<enum_>(config().using_namespace());
157 auto &e = *e_ptr;
158
159 auto ns{common::get_tag_namespace(*enm)};
160
161 // Id of parent class or struct in which this enum is potentially nested
162 std::optional<eid_t> parent_id_opt;
163 [[maybe_unused]] namespace_ parent_ns;
164 find_record_parent_id(enm, parent_id_opt, parent_ns);
165
166 std::string enm_name;
167 if (enm->getNameAsString().empty() && typedef_decl != nullptr)
168 enm_name = typedef_decl->getNameAsString();
169 else if (parent_id_opt)
170 enm_name = enm->getNameAsString();
171 else
172 enm_name = common::get_tag_name(*enm);
173
174 if (parent_id_opt && diagram().find<class_>(*parent_id_opt)) {
175 auto parent_class = diagram().find<class_>(*parent_id_opt);
176
177 e.set_namespace(ns);
178 e.set_name(parent_class.value().name(), enm_name);
179 e.set_id(common::to_id(e.full_name(false)));
180 e.add_relationship({relationship_t::kContainment, *parent_id_opt});
181 e.nested(true);
182 }
183 else if (parent_id_opt && diagram().find<objc_interface>(*parent_id_opt)) {
184 auto parent_class = diagram().find<objc_interface>(*parent_id_opt);
185
186 e.set_namespace(ns);
187 e.set_name(parent_class.value().name(), enm_name);
188 e.set_id(common::to_id(e.full_name(false)));
189 e.add_relationship({relationship_t::kContainment, *parent_id_opt});
190 e.nested(true);
191 }
192 else {
193 e.set_name(enm_name);
194 e.set_namespace(ns);
195 e.set_id(common::to_id(e.full_name(false)));
196 }
197
198 id_mapper().add(enm->getID(), e.id());
199
200 process_comment(*enm, e);
201 set_source_location(*enm, e);
202 set_owning_module(*enm, e);
203
204 if (e.skip())
205 return {};
206
207 e.set_style(e.style_spec());
208
209 for (const auto &ev : enm->enumerators()) {
210 e.constants().push_back(ev->getNameAsString());
211 }
212
213 return e_ptr;
214}

◆ create_objc_category_declaration()

std::unique_ptr< clanguml::class_diagram::model::objc_interface > clanguml::class_diagram::visitor::translation_unit_visitor::create_objc_category_declaration ( clang::ObjCCategoryDecl *  decl)
private

Create class element model from Objective-C category.

Parameters
declObjective-C protocol declaration
Returns
Class diagram element model

Definition at line 1019 of file translation_unit_visitor.cc.

1021{
1022 assert(decl != nullptr);
1023
1024 if (!should_include(decl))
1025 return {};
1026
1027 auto c_ptr{std::make_unique<class_diagram::model::objc_interface>(
1028 config().using_namespace())};
1029 auto &c = *c_ptr;
1030
1031 decl->getClassInterface()->getNameAsString();
1032 c.set_name(fmt::format("{}({})",
1033 decl->getClassInterface()->getNameAsString(), decl->getNameAsString()));
1034 c.set_id(common::to_id(fmt::format("__objc__category__{}", c.name())));
1035 c.is_category(true);
1036
1037 process_comment(*decl, c);
1038 set_source_location(*decl, c);
1039
1040 if (c.skip())
1041 return {};
1042
1043 c.set_style(c.style_spec());
1044
1045 return c_ptr;
1046}

◆ create_objc_interface_declaration()

std::unique_ptr< clanguml::class_diagram::model::objc_interface > clanguml::class_diagram::visitor::translation_unit_visitor::create_objc_interface_declaration ( clang::ObjCInterfaceDecl *  decl)
private

Create class element model from Objective-C interface.

Parameters
declObjective-C protocol declaration
Returns
Class diagram element model

Definition at line 1077 of file translation_unit_visitor.cc.

1079{
1080 assert(decl != nullptr);
1081
1082 if (!should_include(decl))
1083 return {};
1084
1085 auto c_ptr{std::make_unique<class_diagram::model::objc_interface>(
1086 config().using_namespace())};
1087 auto &c = *c_ptr;
1088
1089 c.set_name(decl->getNameAsString());
1090 c.set_id(common::to_id(*decl));
1091
1092 process_comment(*decl, c);
1093 set_source_location(*decl, c);
1094
1095 if (c.skip())
1096 return {};
1097
1098 c.set_style(c.style_spec());
1099
1100 return c_ptr;
1101}

◆ create_objc_protocol_declaration()

std::unique_ptr< clanguml::class_diagram::model::objc_interface > clanguml::class_diagram::visitor::translation_unit_visitor::create_objc_protocol_declaration ( clang::ObjCProtocolDecl *  decl)
private

Create class element model from Objective-C protocol.

Parameters
declObjective-C protocol declaration
Returns
Class diagram element model

Definition at line 1049 of file translation_unit_visitor.cc.

1051{
1052 assert(decl != nullptr);
1053
1054 if (!should_include(decl))
1055 return {};
1056
1057 auto c_ptr{std::make_unique<class_diagram::model::objc_interface>(
1058 config().using_namespace())};
1059 auto &c = *c_ptr;
1060
1061 c.set_name(decl->getNameAsString());
1062 c.set_id(common::to_id(*decl));
1063 c.is_protocol(true);
1064
1065 process_comment(*decl, c);
1066 set_source_location(*decl, c);
1067
1068 if (c.skip())
1069 return {};
1070
1071 c.set_style(c.style_spec());
1072
1073 return c_ptr;
1074}

◆ create_record_declaration()

std::unique_ptr< class_ > clanguml::class_diagram::visitor::translation_unit_visitor::create_record_declaration ( clang::RecordDecl *  rec)
private

Create class element model from record (e.g. struct) declaration.

Parameters
recRecord declaration
Returns
Class diagram element model

Definition at line 937 of file translation_unit_visitor.cc.

939{
940 assert(rec != nullptr);
941
942 if (!should_include(rec))
943 return {};
944
945 auto record_ptr{std::make_unique<class_>(config().using_namespace())};
946 auto &record = *record_ptr;
947
948 process_record_parent(rec, record, namespace_{});
949
950 if (!record.is_nested()) {
951 auto record_name = rec->getQualifiedNameAsString();
952
953#if LLVM_VERSION_MAJOR < 16
954 if (record_name == "(anonymous)") {
955 util::if_not_null(rec->getTypedefNameForAnonDecl(),
956 [&record_name](const clang::TypedefNameDecl *name) {
957 record_name = name->getNameAsString();
958 });
959 }
960#endif
961
962 record.set_name(record_name);
963 record.set_id(common::to_id(record.full_name(false)));
964 }
965
966 process_comment(*rec, record);
967 set_source_location(*rec, record);
968 set_owning_module(*rec, record);
969
970 const auto record_full_name = record_ptr->full_name(false);
971
972 record.is_struct(rec->isStruct());
973 record.is_union(rec->isUnion());
974
975 if (record.skip())
976 return {};
977
978 record.set_style(record.style_spec());
979
980 return record_ptr;
981}

◆ extract_constrained_template_param_name()

void clanguml::class_diagram::visitor::translation_unit_visitor::extract_constrained_template_param_name ( const clang::ConceptSpecializationExpr *  concept_specialization,
const clang::ConceptDecl *  cpt,
std::vector< std::string > &  constrained_template_params,
size_t  argument_index,
std::string &  type_name 
) const
private

Extract template contraint parameter name from raw source code.

Parameters
concept_specializationConcept specialization expression
cptConcept declaration
constrained_template_paramsFound constraint template param names
argument_indexArgument index
type_nameType parameter name - used if extraction fails

Definition at line 2509 of file translation_unit_visitor.cc.

2514{
2515 const auto full_declaration_text = common::get_source_text_raw(
2516 concept_specialization->getSourceRange(), source_manager());
2517
2518 if (!full_declaration_text.empty()) {
2519 // Handle typename constraint in requires clause
2520 if (type_name.find("type-parameter-") == 0) {
2521 const auto concept_declaration_text = full_declaration_text.substr(
2522 full_declaration_text.find(cpt->getNameAsString()) +
2523 cpt->getNameAsString().size() + 1);
2524
2525 auto template_params = common::parse_unexposed_template_params(
2526 concept_declaration_text, [](const auto &t) { return t; });
2527
2528 if (template_params.size() > argument_index)
2529 type_name = template_params[argument_index].to_string(
2530 config().using_namespace(), false);
2531 }
2532 constrained_template_params.push_back(type_name);
2533 }
2534}

◆ finalize()

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

Finalize diagram model.

This method is called after the entire AST has been visited by this visitor. It is used to perform necessary post processing on the diagram (e.g. resolve translation unit local element ID's into global ID's based on elements full names).

Definition at line 2500 of file translation_unit_visitor.cc.

2501{
2504 if (config().skip_redundant_dependencies()) {
2505 diagram().remove_redundant_dependencies();
2506 }
2507}

◆ find_instantiation_relationships()

void clanguml::class_diagram::visitor::translation_unit_visitor::find_instantiation_relationships ( common::model::template_element template_instantiation_base,
const std::string &  full_name,
eid_t  templated_decl_id 
)

Definition at line 2666 of file translation_unit_visitor.cc.

2669{
2670 auto &template_instantiation = dynamic_cast<class_diagram::model::class_ &>(
2671 template_instantiation_base);
2672
2673 // First try to find the best match for this template in partially
2674 // specialized templates
2675 std::string destination{};
2676 std::string best_match_full_name{};
2677 auto full_template_name = template_instantiation.full_name(false);
2678 int best_match{};
2679 eid_t best_match_id{};
2680
2681 for (const auto templ : diagram().classes()) {
2682 if (templ.get() == template_instantiation)
2683 continue;
2684
2685 auto c_full_name = templ.get().full_name(false);
2686 auto match =
2687 template_instantiation.calculate_template_specialization_match(
2688 templ.get());
2689
2690 if (match > best_match) {
2691 best_match = match;
2692 best_match_full_name = c_full_name;
2693 best_match_id = templ.get().id();
2694 }
2695 }
2696
2697 auto templated_decl_global_id =
2698 id_mapper().get_global_id(templated_decl_id).value_or(eid_t{});
2699
2700 if (best_match_id.value() > 0) {
2701 destination = best_match_full_name;
2702 template_instantiation.add_relationship(
2704 template_instantiation.template_specialization_found(true);
2705 }
2706 // If we can't find optimal match for parent template specialization,
2707 // just use whatever clang suggests
2708 else if (diagram().has_element(templated_decl_global_id)) {
2709 template_instantiation.add_relationship(
2711 templated_decl_global_id});
2712 template_instantiation.template_specialization_found(true);
2713 }
2714 else if (diagram().should_include(common::model::namespace_{full_name})) {
2715 LOG_DBG("Skipping instantiation relationship from {} to {}",
2716 template_instantiation, templated_decl_global_id);
2717 }
2718 else {
2719 LOG_DBG("== Cannot determine global id for specialization template {} "
2720 "- delaying until the translation unit is complete ",
2721 templated_decl_global_id);
2722
2723 template_instantiation.add_relationship(
2725 }
2726}

◆ find_record_parent_id()

void clanguml::class_diagram::visitor::translation_unit_visitor::find_record_parent_id ( const clang::TagDecl *  decl,
std::optional< eid_t > &  parent_id_opt,
namespace_ &  parent_ns 
) const
private

Definition at line 2422 of file translation_unit_visitor.cc.

2424{
2425 const auto *parent = decl->getParent();
2426
2427 if (parent != nullptr) {
2428 if (const auto *parent_record_decl =
2429 clang::dyn_cast<clang::RecordDecl>(parent);
2430 parent_record_decl != nullptr) {
2431 parent_ns = common::get_tag_namespace(*parent_record_decl);
2432
2433 eid_t local_id{parent_record_decl->getID()};
2434
2435 // First check if the parent has been added to the diagram as
2436 // regular class
2437 parent_id_opt = id_mapper().get_global_id(local_id);
2438
2439 // If not, check if the parent template declaration is in the model
2440 if (!parent_id_opt) {
2441 if (parent_record_decl->getDescribedTemplate() != nullptr) {
2442 local_id =
2443 parent_record_decl->getDescribedTemplate()->getID();
2444 parent_id_opt = id_mapper().get_global_id(local_id);
2445 }
2446 }
2447 }
2448 }
2449
2450 if (parent_id_opt)
2451 return;
2452
2453 const auto *lexical_parent = decl->getLexicalParent();
2454 if (lexical_parent != nullptr) {
2455 if (const auto *parent_interface_decl =
2456 clang::dyn_cast<clang::ObjCInterfaceDecl>(lexical_parent);
2457 parent_interface_decl != nullptr) {
2458
2459 eid_t ast_id{parent_interface_decl->getID()};
2460
2461 // First check if the parent has been added to the diagram as
2462 // regular class
2463 parent_id_opt = id_mapper().get_global_id(ast_id);
2464 }
2465 }
2466}

◆ find_relationships()

bool clanguml::class_diagram::visitor::translation_unit_visitor::find_relationships ( const clang::Decl *  decl,
const clang::QualType &  type,
found_relationships_t &  relationships,
clanguml::common::model::relationship_t  relationship_hint 
)
private

Find relationships in a specific type.

Parameters
declSource declaration from which this relationship originates
typeType to search for relationships
relationship_hintDefault relationship type to infer from this type
Returns
True, if any relationships were found

Definition at line 1789 of file translation_unit_visitor.cc.

1792{
1793 bool result{false};
1794
1795 if (type->isPointerType()) {
1796 relationship_hint = relationship_t::kAssociation;
1798 decl, type->getPointeeType(), relationships, relationship_hint);
1799 }
1800 else if (type->isRValueReferenceType()) {
1801 relationship_hint = relationship_t::kAggregation;
1803 decl, type.getNonReferenceType(), relationships, relationship_hint);
1804 }
1805 else if (type->isLValueReferenceType()) {
1806 relationship_hint = relationship_t::kAssociation;
1808 decl, type.getNonReferenceType(), relationships, relationship_hint);
1809 }
1810 else if (type->isArrayType()) {
1811 find_relationships(decl, type->getAsArrayTypeUnsafe()->getElementType(),
1812 relationships, relationship_t::kAggregation);
1813 }
1814 else if (type->isEnumeralType()) {
1815 if (const auto *enum_type = type->getAs<clang::EnumType>();
1816 enum_type != nullptr) {
1817 // Use AST's local ID here for relationship target, as we can't
1818 // calculate here properly the ID for nested enums. It will be
1819 // resolved properly in finalize().
1820 relationships.emplace_back(
1821 enum_type->getDecl()->getID(), relationship_hint, decl);
1822 }
1823 }
1824 // TODO: Objc support
1825 else if (type->isRecordType()) {
1826 const auto *type_instantiation_decl =
1827 type->getAs<clang::TemplateSpecializationType>();
1828
1829 if (type_instantiation_decl != nullptr) {
1830 // If this template should be included in the diagram
1831 // add it - and then process recursively its arguments
1832 if (should_include(type_instantiation_decl->getTemplateName()
1833 .getAsTemplateDecl())) {
1834 relationships.emplace_back(
1835 type_instantiation_decl->getTemplateName()
1836 .getAsTemplateDecl()
1837 ->getID(),
1838 relationship_hint, decl);
1839 }
1840 for (const auto &template_argument :
1841 type_instantiation_decl->template_arguments()) {
1842 const auto template_argument_kind = template_argument.getKind();
1843 if (template_argument_kind ==
1844 clang::TemplateArgument::ArgKind::Integral) {
1845 // pass
1846 }
1847 else if (template_argument_kind ==
1848 clang::TemplateArgument::ArgKind::Null) {
1849 // pass
1850 }
1851 else if (template_argument_kind ==
1852 clang::TemplateArgument::ArgKind::Expression) {
1853 // pass
1854 }
1855 else if (template_argument.getKind() ==
1856 clang::TemplateArgument::ArgKind::NullPtr) {
1857 // pass
1858 }
1859 else if (template_argument_kind ==
1860 clang::TemplateArgument::ArgKind::Template) {
1861 // pass
1862 }
1863 else if (template_argument_kind ==
1864 clang::TemplateArgument::ArgKind::TemplateExpansion) {
1865 // pass
1866 }
1867 else if (const auto *function_type =
1868 template_argument.getAsType()
1869 ->getAs<clang::FunctionProtoType>();
1870 function_type != nullptr) {
1871 for (const auto &param_type :
1872 function_type->param_types()) {
1873 result = find_relationships(decl, param_type,
1874 relationships, relationship_t::kDependency);
1875 }
1876 }
1877 else if (template_argument_kind ==
1878 clang::TemplateArgument::ArgKind::Type) {
1879 result =
1880 find_relationships(decl, template_argument.getAsType(),
1881 relationships, relationship_hint);
1882 }
1883 }
1884 }
1885 else if (type->getAsCXXRecordDecl() != nullptr) {
1886 relationships.emplace_back(
1887 type->getAsCXXRecordDecl()->getID(), relationship_hint, decl);
1888 result = true;
1889 }
1890 else {
1891 relationships.emplace_back(
1892 type->getAsRecordDecl()->getID(), relationship_hint, decl);
1893 result = true;
1894 }
1895 }
1896 else if (const auto *template_specialization_type =
1897 type->getAs<clang::TemplateSpecializationType>();
1898 template_specialization_type != nullptr) {
1899 if (should_include(template_specialization_type->getTemplateName()
1900 .getAsTemplateDecl())) {
1901 relationships.emplace_back(
1902 template_specialization_type->getTemplateName()
1903 .getAsTemplateDecl()
1904 ->getID(),
1905 relationship_hint, decl);
1906 }
1907 for (const auto &template_argument :
1908 template_specialization_type->template_arguments()) {
1909 const auto template_argument_kind = template_argument.getKind();
1910 if (template_argument_kind ==
1911 clang::TemplateArgument::ArgKind::Integral) {
1912 // pass
1913 }
1914 else if (template_argument_kind ==
1915 clang::TemplateArgument::ArgKind::Null) {
1916 // pass
1917 }
1918 else if (template_argument_kind ==
1919 clang::TemplateArgument::ArgKind::Expression) {
1920 // pass
1921 }
1922 else if (template_argument.getKind() ==
1923 clang::TemplateArgument::ArgKind::NullPtr) {
1924 // pass
1925 }
1926 else if (template_argument_kind ==
1927 clang::TemplateArgument::ArgKind::Template) {
1928 // pass
1929 }
1930 else if (template_argument_kind ==
1931 clang::TemplateArgument::ArgKind::TemplateExpansion) {
1932 // pass
1933 }
1934 else if (const auto *function_type =
1935 template_argument.getAsType()
1936 ->getAs<clang::FunctionProtoType>();
1937 function_type != nullptr) {
1938 for (const auto &param_type : function_type->param_types()) {
1939 result = find_relationships(decl, param_type, relationships,
1940 relationship_t::kDependency);
1941 }
1942 }
1943 else if (template_argument_kind ==
1944 clang::TemplateArgument::ArgKind::Type) {
1945 result = find_relationships(decl, template_argument.getAsType(),
1946 relationships, relationship_hint);
1947 }
1948 }
1949 }
1950
1951 return result;
1952}

◆ find_relationships_in_constraint_expression()

void clanguml::class_diagram::visitor::translation_unit_visitor::find_relationships_in_constraint_expression ( clanguml::common::model::element c,
const clang::Expr *  expr 
)
private

Find relationships in concept constraint expression.

Parameters
cDiagram element model (concept)
exprConcept constraint expression

Definition at line 722 of file translation_unit_visitor.cc.

724{
725 if (expr == nullptr)
726 return;
727 found_relationships_t relationships;
728
729 common::if_dyn_cast<clang::UnresolvedLookupExpr>(
730 expr, [&](const clang::UnresolvedLookupExpr *ul) {
731 for (const auto ta : ul->template_arguments()) {
732 if (ta.getArgument().getKind() !=
733 clang::TemplateArgument::ArgKind::Type)
734 continue;
735 find_relationships({}, ta.getArgument().getAsType(),
736 relationships, relationship_t::kConstraint);
737 }
738 });
739
740 common::if_dyn_cast<clang::ConceptSpecializationExpr>(
741 expr, [&](const auto *cs) {
743 });
744
745 common::if_dyn_cast<clang::RequiresExpr>(expr, [&](const auto *re) {
746 // TODO
747 });
748
749 common::if_dyn_cast<clang::BinaryOperator>(expr, [&](const auto *op) {
752 });
753
754 common::if_dyn_cast<clang::UnaryOperator>(expr, [&](const auto *op) {
756 });
757
758 for (const auto &[type_element_id, relationship_type, source_decl] :
759 relationships) {
760 if (type_element_id != c.id() &&
761 (relationship_type != relationship_t::kNone)) {
762
763 relationship r{relationship_type, type_element_id};
764
765 if (source_decl != nullptr) {
766 set_source_location(*source_decl, r);
767 }
768
769 c.add_relationship(std::move(r));
770 }
771 }
772}

◆ has_processed_template_class()

bool clanguml::class_diagram::visitor::translation_unit_visitor::has_processed_template_class ( const std::string &  qualified_name) const
private

Check if template class has already been processed.

Parameters
qualified_nameFully qualified template class name
Returns
True, if template class has already been processed

Definition at line 2542 of file translation_unit_visitor.cc.

2544{
2546}

◆ process_class_bases()

void clanguml::class_diagram::visitor::translation_unit_visitor::process_class_bases ( const clang::CXXRecordDecl *  cls,
clanguml::class_diagram::model::class_ c 
)
private

Process class declaration bases (parents), if any.

Parameters
clsClass declaration
cClass diagram element model

Definition at line 1331 of file translation_unit_visitor.cc.

1333{
1334 for (const auto &base : cls->bases()) {
1335 eid_t parent_id;
1336 if (const auto *tsp =
1337 base.getType()->getAs<clang::TemplateSpecializationType>();
1338 tsp != nullptr) {
1339 auto template_specialization_ptr =
1340 std::make_unique<class_>(config().using_namespace());
1342 *template_specialization_ptr, cls, *tsp, {});
1343
1344 parent_id = template_specialization_ptr->id();
1345
1346 if (diagram().should_include(*template_specialization_ptr)) {
1347 add_class(std::move(template_specialization_ptr));
1348 }
1349 }
1350 else if (const auto *record_type =
1351 base.getType()->getAs<clang::RecordType>();
1352 record_type != nullptr) {
1353 parent_id = common::to_id(*record_type->getDecl());
1354 }
1355 else
1356 // This could be a template parameter - we don't want it here
1357 continue;
1358
1359 common::model::relationship cp{parent_id,
1360 common::access_specifier_to_access_t(base.getAccessSpecifier()),
1361 base.isVirtual()};
1362
1363 LOG_DBG("Found base class {} [{}] for class {}",
1364 common::to_string(base.getType(), cls->getASTContext()),
1365 parent_id.value(), c.name());
1366
1367 c.add_relationship(std::move(cp));
1368 }
1369}

◆ process_class_children()

void clanguml::class_diagram::visitor::translation_unit_visitor::process_class_children ( const clang::CXXRecordDecl *  cls,
clanguml::class_diagram::model::class_ c 
)
private

Process class children elements (members and methods)

Parameters
clsClass declaration
cClass diagram element model

Definition at line 1381 of file translation_unit_visitor.cc.

1383{
1384 assert(cls != nullptr);
1385
1386 // Iterate over class methods (both regular and static)
1387 for (const auto *method : cls->methods()) {
1388 if (method != nullptr) {
1389 process_method(*method, c);
1390 }
1391 }
1392
1393 // Iterate over class template methods
1394 if (const auto *cls_decl_context =
1395 clang::dyn_cast_or_null<clang::DeclContext>(cls);
1396 cls_decl_context != nullptr) {
1397 for (auto const *decl_iterator : cls_decl_context->decls()) {
1398 auto const *method_template =
1399 llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>(
1400 decl_iterator);
1401 if (method_template == nullptr)
1402 continue;
1403
1404 process_template_method(*method_template, c);
1405 }
1406 }
1407
1408 // Iterate over regular class fields
1409 for (const auto *field : cls->fields()) {
1410 if (field != nullptr)
1411 process_field(*field, c);
1412 }
1413
1414 // First we have to collect any `typedef enum` declarations, which should
1415 // not be rendered as members (typedefs are visited here after enums)
1416 std::set<const clang::EnumDecl *> typedeffed_enums;
1417 for (const auto *decl : cls->decls()) {
1418 if (decl->getKind() == clang::Decl::Typedef) {
1419 const auto *typedeffed_enum = common::get_typedef_enum_decl(
1420 clang::dyn_cast<clang::TypedefDecl>(decl));
1421 if (typedeffed_enum != nullptr)
1422 typedeffed_enums.emplace(typedeffed_enum);
1423 }
1424 }
1425
1426 // Static fields have to be processed by iterating over variable
1427 // declarations
1428 for (const auto *decl : cls->decls()) {
1429 if (decl->getKind() == clang::Decl::Var) {
1430 const clang::VarDecl *variable_declaration{
1431 clang::dyn_cast_or_null<clang::VarDecl>(decl)};
1432 if ((variable_declaration != nullptr) &&
1433 variable_declaration->isStaticDataMember()) {
1434 process_static_field(*variable_declaration, c);
1435 }
1436 }
1437 else if (decl->getKind() == clang::Decl::Enum &&
1438 typedeffed_enums.count(
1439 clang::dyn_cast_or_null<clang::EnumDecl>(decl)) == 0) {
1440 const auto *enum_decl =
1441 clang::dyn_cast_or_null<clang::EnumDecl>(decl);
1442 if (enum_decl == nullptr)
1443 continue;
1444
1445 if (enum_decl->getNameAsString().empty()) {
1446 for (const auto *enum_const : enum_decl->enumerators()) {
1448 enum_decl->getAccess()),
1449 enum_const->getNameAsString(), "enum"};
1450 c.add_member(std::move(m));
1451 }
1452 }
1453 }
1454 }
1455
1456 if (cls->isCompleteDefinition())
1457 for (const auto *friend_declaration : cls->friends()) {
1458 if (friend_declaration != nullptr)
1459 process_friend(*friend_declaration, c);
1460 }
1461}

◆ process_class_declaration()

void clanguml::class_diagram::visitor::translation_unit_visitor::process_class_declaration ( const clang::CXXRecordDecl &  cls,
clanguml::class_diagram::model::class_ c 
)
private

Process class declaration.

Parameters
clsClass declaration
cClass diagram element returned from create_class_declaration

Definition at line 1121 of file translation_unit_visitor.cc.

1123{
1124 // Process class child entities
1125 process_class_children(&cls, c);
1126
1127 // Process class bases
1128 process_class_bases(&cls, c);
1129
1130 c.complete(true);
1131}

◆ process_concept_specialization_relationships()

void clanguml::class_diagram::visitor::translation_unit_visitor::process_concept_specialization_relationships ( common::model::element c,
const clang::ConceptSpecializationExpr *  concept_specialization 
)
private

Find concept specializations relationships.

Parameters
cConcept element model
concept_specializationConcept specialization expression

Definition at line 774 of file translation_unit_visitor.cc.

777{
778
779 if (const auto *cpt = concept_specialization->getNamedConcept();
780 should_include(cpt)) {
781
782 const auto cpt_name = cpt->getNameAsString();
783 const eid_t ast_id{cpt->getID()};
784 const auto maybe_id = id_mapper().get_global_id(ast_id);
785 if (!maybe_id)
786 return;
787
788 const auto target_id = maybe_id.value();
789
790 std::vector<std::string> constrained_template_params;
791
792 size_t argument_index{};
793
794 for (const auto ta : concept_specialization->getTemplateArguments()) {
795 if (ta.getKind() == clang::TemplateArgument::Type) {
796 auto type_name =
797 common::to_string(ta.getAsType(), cpt->getASTContext());
798 extract_constrained_template_param_name(concept_specialization,
799 cpt, constrained_template_params, argument_index,
800 type_name);
801 }
802 else if (ta.getKind() == clang::TemplateArgument::Pack) {
803 if (!ta.getPackAsArray().empty() &&
804 ta.getPackAsArray().front().isPackExpansion()) {
805 const auto &pack_head =
806 ta.getPackAsArray().front().getAsType();
807 auto type_name =
808 common::to_string(pack_head, cpt->getASTContext());
810 concept_specialization, cpt,
811 constrained_template_params, argument_index, type_name);
812 }
813 }
814 else {
815 LOG_DBG("Unsupported concept type parameter in concept: {}",
816 cpt_name);
817 }
818 argument_index++;
819 }
820
821 if (!constrained_template_params.empty())
822 c.add_relationship(
823 {relationship_t::kConstraint, target_id, access_t::kNone,
824 fmt::format(
825 "{}", fmt::join(constrained_template_params, ","))});
826 }
827}

◆ process_constraint_requirements()

void clanguml::class_diagram::visitor::translation_unit_visitor::process_constraint_requirements ( const clang::ConceptDecl *  cpt,
const clang::Expr *  expr,
model::concept_ concept_model 
) const
private

Process concept constraint requirements.

Parameters
cptConcept declaration
exprRequires expression
concept_modelConcept diagram element model

Definition at line 593 of file translation_unit_visitor.cc.

596{
597 if (const auto *constraint = llvm::dyn_cast<clang::RequiresExpr>(expr);
598 constraint) {
599
600 auto constraint_source = common::to_string(constraint);
601
602 LOG_DBG("== Processing constraint: '{}'", constraint_source);
603
604 for ([[maybe_unused]] const auto *requirement :
605 constraint->getRequirements()) {
606 // TODO
607 }
608
609 // process 'requires (...)' declaration
610 for (const auto *decl : constraint->getBody()->decls()) {
611 if (const auto *parm_var_decl =
612 llvm::dyn_cast<clang::ParmVarDecl>(decl);
613 parm_var_decl) {
614 parm_var_decl->getQualifiedNameAsString();
615
616 auto param_name = parm_var_decl->getNameAsString();
617 auto param_type = common::to_string(
618 parm_var_decl->getType(), cpt->getASTContext());
619
620 LOG_DBG("=== Processing parameter variable declaration: {}, {}",
621 param_type, param_name);
622
623 concept_model.add_parameter(
624 {std::move(param_type), std::move(param_name)});
625 }
626 else {
627 LOG_DBG("=== Processing some other concept declaration: {}",
628 decl->getID());
629 }
630 }
631
632 // process concept body requirements '{ }' if any
633 for (const auto *req : constraint->getRequirements()) {
634 if (req->getKind() == clang::concepts::Requirement::RK_Simple) {
635 const auto *simple_req =
636 llvm::dyn_cast<clang::concepts::ExprRequirement>(req);
637
638 if (simple_req != nullptr) {
640 simple_req->getExpr(), [&concept_model](const auto *e) {
641 auto simple_expr = common::to_string(e);
642
643 LOG_DBG("=== Processing expression requirement: {}",
644 simple_expr);
645
646 concept_model.add_statement(std::move(simple_expr));
647 });
648 }
649 }
650 else if (req->getKind() == clang::concepts::Requirement::RK_Type) {
652 llvm::dyn_cast<clang::concepts::TypeRequirement>(req),
653 [&concept_model, cpt](const auto *t) {
654 auto type_name = common::to_string(
655 t->getType()->getType(), cpt->getASTContext());
656
657 LOG_DBG(
658 "=== Processing type requirement: {}", type_name);
659
660 concept_model.add_statement(std::move(type_name));
661 });
662 }
663 else if (req->getKind() ==
664 clang::concepts::Requirement::RK_Nested) {
665 const auto *nested_req =
666 llvm::dyn_cast<clang::concepts::NestedRequirement>(req);
667
668 if (nested_req != nullptr) {
670 nested_req->getConstraintExpr(), [](const auto *e) {
671 LOG_DBG("=== Processing nested requirement: {}",
672 common::to_string(e));
673 });
674 }
675 }
676 else if (req->getKind() ==
677 clang::concepts::Requirement::RK_Compound) {
678 const auto *compound_req =
679 llvm::dyn_cast<clang::concepts::ExprRequirement>(req);
680
681 if (compound_req != nullptr) {
682 const auto *compound_expr_ptr = compound_req->getExpr();
683
684 if (compound_expr_ptr != nullptr) {
685 auto compound_expr =
686 common::to_string(compound_expr_ptr);
687
688 auto req_return_type =
689 compound_req->getReturnTypeRequirement();
690
691 if (!req_return_type.isEmpty()) {
692 compound_expr =
693 fmt::format("{{{}}} -> {}", compound_expr,
695 req_return_type.getTypeConstraint()));
696 }
697 else if (compound_req->hasNoexceptRequirement()) {
698 compound_expr =
699 fmt::format("{{{}}} noexcept", compound_expr);
700 }
701
702 LOG_DBG("=== Processing compound requirement: {}",
703 compound_expr);
704
705 concept_model.add_statement(std::move(compound_expr));
706 }
707 }
708 }
709 }
710 }
711 else if (const auto *binop = llvm::dyn_cast<clang::BinaryOperator>(expr);
712 binop) {
713 process_constraint_requirements(cpt, binop->getLHS(), concept_model);
714 process_constraint_requirements(cpt, binop->getRHS(), concept_model);
715 }
716 else if (const auto *unop = llvm::dyn_cast<clang::UnaryOperator>(expr);
717 unop) {
718 process_constraint_requirements(cpt, unop->getSubExpr(), concept_model);
719 }
720}

◆ process_field()

void clanguml::class_diagram::visitor::translation_unit_visitor::process_field ( const clang::FieldDecl &  field_declaration,
clanguml::class_diagram::model::class_ c 
)
private

Process class data member.

Parameters
field_declarationData member declaration
cClass diagram element model

Definition at line 2206 of file translation_unit_visitor.cc.

2208{
2209 LOG_DBG(
2210 "== Visiting record member {}", field_declaration.getNameAsString());
2211
2212 // Default hint for relationship is aggregation
2213 auto relationship_hint = relationship_t::kAggregation;
2214 // If the first type of the template instantiation of this field type
2215 // has been added as aggregation relationship with class 'c', don't
2216 // add it's nested template types as aggregation
2217 [[maybe_unused]] bool template_instantiation_added_as_aggregation{false};
2218 // The actual field type
2219 auto field_type = field_declaration.getType();
2220
2221 // String representation of the field type
2222 auto type_name =
2223 common::to_string(field_type, field_declaration.getASTContext());
2224 // The field name
2225 const auto field_name = field_declaration.getNameAsString();
2226
2227 auto field_type_str =
2228 common::to_string(field_type, field_declaration.getASTContext(), false);
2229
2231
2232 class_member field{
2233 common::access_specifier_to_access_t(field_declaration.getAccess()),
2234 field_name, config().simplify_template_type(field_type_str)};
2235
2236 field.set_qualified_name(field_declaration.getQualifiedNameAsString());
2237
2238 // Parse the field comment
2239 process_comment(field_declaration, field);
2240 // Register the source location of the field declaration
2241 set_source_location(field_declaration, field);
2242
2243 // If the comment contains a skip directive, just return
2244 if (field.skip())
2245 return;
2246
2247 if (field_type->isPointerType()) {
2248 relationship_hint = relationship_t::kAssociation;
2249 field_type = field_type->getPointeeType();
2250 }
2251 else if (field_type->isLValueReferenceType()) {
2252 relationship_hint = relationship_t::kAssociation;
2253 field_type = field_type.getNonReferenceType();
2254 }
2255 else if (field_type->isArrayType()) {
2256 relationship_hint = relationship_t::kAggregation;
2257 while (field_type->isArrayType()) {
2258 auto current_multiplicity = field.destination_multiplicity();
2259 if (!current_multiplicity)
2260 field.set_destination_multiplicity(common::get_array_size(
2261 *field_type->getAsArrayTypeUnsafe()));
2262 else {
2263 auto maybe_array_size =
2264 common::get_array_size(*field_type->getAsArrayTypeUnsafe());
2265 if (maybe_array_size.has_value()) {
2266 field.set_destination_multiplicity(
2267 current_multiplicity.value() *
2268 maybe_array_size.value());
2269 }
2270 }
2271
2272 field_type = field_type->getAsArrayTypeUnsafe()->getElementType();
2273 }
2274 }
2275 else if (field_type->isRValueReferenceType()) {
2276 field_type = field_type.getNonReferenceType();
2277 }
2278
2279 if (type_name.find("std::shared_ptr") == 0)
2280 relationship_hint = relationship_t::kAssociation;
2281 if (type_name.find("std::weak_ptr") == 0)
2282 relationship_hint = relationship_t::kAssociation;
2283
2284 found_relationships_t relationships;
2285
2286 const auto *template_field_type =
2287 field_type->getAs<clang::TemplateSpecializationType>();
2288 // TODO: Refactor to an unalias_type() method
2289 if (template_field_type != nullptr)
2290 if (template_field_type->isTypeAlias())
2291 template_field_type =
2292 template_field_type->getAliasedType()
2293 ->getAs<clang::TemplateSpecializationType>();
2294
2295 bool field_type_is_template_template_parameter{false};
2296 if (template_field_type != nullptr) {
2297 // Skip types which are template template parameters of the parent
2298 // template
2299 for (const auto &class_template_param : c.template_params()) {
2300 if (class_template_param.name() ==
2301 template_field_type->getTemplateName()
2302 .getAsTemplateDecl()
2303 ->getNameAsString() +
2304 "<>") {
2305 field_type_is_template_template_parameter = true;
2306 }
2307 }
2308 }
2309
2310 // Process the type which is template instantiation of some sort
2311 if (template_field_type != nullptr &&
2312 !field_type_is_template_template_parameter) {
2313 // Build the template instantiation for the field type
2314 auto template_specialization_ptr =
2315 std::make_unique<class_>(config().using_namespace());
2317 *template_specialization_ptr,
2318 field_type->getAs<clang::TemplateSpecializationType>()
2319 ->getTemplateName()
2320 .getAsTemplateDecl(),
2321 *template_field_type, {&c});
2322 template_specialization_ptr->is_template(true);
2323
2324 if (!field.skip_relationship() && template_specialization_ptr) {
2325 const auto &template_specialization = *template_specialization_ptr;
2326
2327 // Check if this template instantiation should be added to the
2328 // current diagram. Even if the top level template type for
2329 // this instantiation should not be part of the diagram, e.g.
2330 // it's a std::vector<>, it's nested types might be added
2331 bool add_template_instantiation_to_diagram{false};
2332 if (diagram().should_include(template_specialization)) {
2333
2334 found_relationships_t::value_type r{
2335 template_specialization.id(), relationship_hint,
2336 &field_declaration};
2337
2338 add_template_instantiation_to_diagram = true;
2339
2340 // If the template instantiation for the build type has been
2341 // added as aggregation, skip its nested templates
2342 template_instantiation_added_as_aggregation =
2343 relationship_hint == relationship_t::kAggregation;
2344 relationships.emplace_back(std::move(r));
2345 }
2346
2347 // Try to find relationships to types nested in the template
2348 // instantiation
2349 found_relationships_t nested_relationships;
2350 if (!template_instantiation_added_as_aggregation) {
2351 for (const auto &template_argument :
2352 template_specialization.template_params()) {
2353
2354 LOG_DBG("Looking for nested relationships from {}::{} in "
2355 "template argument {}",
2356 c, field_name,
2357 template_argument.to_string(
2358 config().using_namespace(), false));
2359
2360 template_instantiation_added_as_aggregation =
2361 template_argument.find_nested_relationships(
2362 &field_declaration, nested_relationships,
2363 relationship_hint,
2364 [&d = diagram()](const std::string &full_name) {
2365 if (full_name.empty())
2366 return false;
2367 auto [ns, name] = common::split_ns(full_name);
2368 return d.should_include(ns, name);
2369 });
2370 }
2371
2372 // Add any relationships to the class 'c' to the diagram,
2373 // unless the top level type has been added as aggregation
2374 add_relationships(c, field, nested_relationships,
2375 /* break on first aggregation */ false);
2376 }
2377
2378 // Add the template instantiation object to the diagram if it
2379 // matches the include pattern
2380 if (add_template_instantiation_to_diagram)
2381 add_class(std::move(template_specialization_ptr));
2382 }
2383 }
2384
2385 if (!field.skip_relationship()) {
2386 // Find relationship for the type if the type has not been added
2387 // as aggregation
2388 if (!template_instantiation_added_as_aggregation) {
2389 if ((field_type->getAsRecordDecl() != nullptr) &&
2390 field_type->getAsRecordDecl()->getNameAsString().empty()) {
2391 // Relationships to fields whose type is an anonymous nested
2392 // struct have to be handled separately here
2393 anonymous_struct_relationships_[field_type->getAsRecordDecl()
2394 ->getID()] =
2395 std::make_tuple(field.name(), relationship_hint,
2396 field.access(), field.destination_multiplicity());
2397 }
2398 else
2399 find_relationships(&field_declaration, field_type,
2400 relationships, relationship_hint);
2401 }
2402
2403 add_relationships(c, field, relationships);
2404 }
2405
2406 // If this is an anonymous struct - replace the anonymous_XYZ part with
2407 // field name
2408 if ((field_type->getAsRecordDecl() != nullptr) &&
2409 field_type->getAsRecordDecl()->getNameAsString().empty()) {
2410 if (util::contains(field.type(), "(anonymous_")) {
2411 std::regex anonymous_re("anonymous_(\\d*)");
2412 field.set_type(
2413 std::regex_replace(field.type(), anonymous_re, field_name));
2414 }
2415 }
2416
2417 if (diagram().should_include(field)) {
2418 c.add_member(std::move(field));
2419 }
2420}

◆ process_friend()

void clanguml::class_diagram::visitor::translation_unit_visitor::process_friend ( const clang::FriendDecl &  f,
class_ c 
)
private

Process class friend.

Parameters
fFriend declaration
cClass diagram element model

Definition at line 1463 of file translation_unit_visitor.cc.

1465{
1466 if (const auto *friend_type_info = f.getFriendType()) {
1467 const auto friend_type = friend_type_info->getType();
1468 if (friend_type->getAs<clang::TemplateSpecializationType>() !=
1469 nullptr) {
1470 // TODO: handle template friend
1471 }
1472 else if (friend_type->getAs<clang::RecordType>() != nullptr) {
1473 if (should_include(friend_type->getAsRecordDecl())) {
1474 relationship r{relationship_t::kFriendship,
1475 common::to_id(*friend_type->getAsRecordDecl()),
1477 "<<friend>>"};
1478
1479 c.add_relationship(std::move(r));
1480 }
1481 }
1482 }
1483}

◆ process_function_parameter()

void clanguml::class_diagram::visitor::translation_unit_visitor::process_function_parameter ( const clang::ParmVarDecl &  param,
class_method method,
class_ c,
const std::set< std::string > &  template_parameter_names = {} 
)
private

Process function/method parameter.

Parameters
paramParameter declaration
methodClass method model
cClass diagram element model
template_parameter_namesIgnored

Definition at line 2001 of file translation_unit_visitor.cc.

2004{
2005 method_parameter parameter;
2006 parameter.set_name(p.getNameAsString());
2007
2008 process_comment(p, parameter);
2009
2010 if (parameter.skip())
2011 return;
2012
2013 auto parameter_type = common::to_string(p.getType(), p.getASTContext());
2014
2015 // Is there no better way to determine that 'type' is a lambda?
2017
2018 parameter.set_type(parameter_type);
2019
2020 if (p.hasDefaultArg()) {
2021 const auto *default_arg = p.getDefaultArg();
2022 if (default_arg != nullptr) {
2023 auto default_arg_str = common::get_source_text(
2024 default_arg->getSourceRange(), source_manager());
2025 parameter.set_default_value(default_arg_str);
2026 }
2027 }
2028
2029 if (!parameter.skip_relationship()) {
2030 // find relationship for the type
2031 found_relationships_t relationships;
2032
2033 LOG_DBG("Looking for relationships in type: {}",
2034 common::to_string(p.getType(), p.getASTContext()));
2035
2036 if (const auto *templ =
2037 p.getType()
2038 .getNonReferenceType()
2039 .getUnqualifiedType()
2040 ->getAs<clang::TemplateSpecializationType>();
2041 templ != nullptr) {
2042 auto template_specialization_ptr =
2043 std::make_unique<class_>(config().using_namespace());
2045 *template_specialization_ptr,
2046 templ->getTemplateName().getAsTemplateDecl(), *templ, &c);
2047
2048 template_specialization_ptr->is_template(true);
2049
2050 if (diagram().should_include(*template_specialization_ptr)) {
2051 relationships.emplace_back(template_specialization_ptr->id(),
2052 relationship_t::kDependency, &p);
2053
2054 add_class(std::move(template_specialization_ptr));
2055 }
2056 }
2057
2059 &p, p.getType(), relationships, relationship_t::kDependency);
2060
2061 for (const auto &[type_element_id, relationship_type, source_decl] :
2062 relationships) {
2063 if (type_element_id != c.id() &&
2064 (relationship_type != relationship_t::kNone)) {
2065 relationship r{relationship_t::kDependency, type_element_id};
2066
2067 if (source_decl != nullptr) {
2068 set_source_location(*source_decl, r);
2069 }
2070
2071 LOG_DBG("Adding function parameter relationship from {} to "
2072 "{}: {}",
2073 c, r.type(), r.label());
2074
2075 c.add_relationship(std::move(r));
2076 }
2077 }
2078 }
2079
2080 method.add_parameter(std::move(parameter));
2081}

◆ process_function_parameter_find_relationships_in_autotype()

void clanguml::class_diagram::visitor::translation_unit_visitor::process_function_parameter_find_relationships_in_autotype ( model::class_ c,
const clang::AutoType *  atsp 
)
private

Find relationships in function parameter.

Parameters
cClass diagram element model
atspauto type

Definition at line 1691 of file translation_unit_visitor.cc.

1694{
1695 auto desugared_atsp = atsp->getDeducedType();
1696
1697 if (atsp->isSugared()) {
1698 const auto *deduced_type =
1699 atsp->desugar()->getAs<clang::DeducedTemplateSpecializationType>();
1700
1701 if (deduced_type != nullptr)
1702 desugared_atsp = deduced_type->getDeducedType();
1703 }
1704
1705 if (desugared_atsp.isNull())
1706 return;
1707
1708 const auto *deduced_record_type = desugared_atsp->isRecordType()
1709 ? desugared_atsp->getAs<clang::RecordType>()
1710 : nullptr;
1711
1712 if (deduced_record_type != nullptr) {
1713 if (auto *deduced_auto_decl =
1714 llvm::dyn_cast_or_null<clang::ClassTemplateSpecializationDecl>(
1715 deduced_record_type->getDecl());
1716 deduced_auto_decl != nullptr) {
1717
1718 const auto diagram_class_count_before_visit =
1719 diagram().classes().size();
1720
1721 VisitClassTemplateSpecializationDecl(deduced_auto_decl);
1722
1723 const bool visitor_added_new_template_specialization =
1724 (diagram().classes().size() -
1725 diagram_class_count_before_visit) > 0;
1726
1727 if (visitor_added_new_template_specialization) {
1728 const auto &template_specialization_model =
1729 diagram().classes().back();
1730
1731 if (should_include(deduced_auto_decl)) {
1732 relationship r{relationship_t::kDependency,
1733 template_specialization_model.get().id()};
1734
1735 c.add_relationship(std::move(r));
1736 }
1737 }
1738 }
1739 }
1740}

◆ process_method()

void clanguml::class_diagram::visitor::translation_unit_visitor::process_method ( const clang::CXXMethodDecl &  mf,
clanguml::class_diagram::model::class_ c 
)
private

Process class method.

Parameters
mfMethod declaration
cClass diagram element model

Definition at line 1485 of file translation_unit_visitor.cc.

1487{
1488 // TODO: For now skip implicitly default methods
1489 // in the future, add config option to choose
1490 if (mf.isDefaulted() && !mf.isExplicitlyDefaulted())
1491 return;
1492
1493 auto method_return_type =
1494 common::to_string(mf.getReturnType(), mf.getASTContext());
1495
1496 common::ensure_lambda_type_is_relative(config(), method_return_type);
1497
1498 auto method_name = mf.getNameAsString();
1499 if (mf.isTemplated()) {
1500 // Sometimes in template specializations method names contain the
1501 // template parameters for some reason - drop them
1502 // Is there a better way to do this?
1503 method_name = method_name.substr(0, method_name.find('<'));
1504 }
1505
1506 class_method method{common::access_specifier_to_access_t(mf.getAccess()),
1507 util::trim(method_name),
1508 config().simplify_template_type(method_return_type)};
1509
1510 method.set_qualified_name(mf.getQualifiedNameAsString());
1511
1512 process_method_properties(mf, c, method_name, method);
1513
1514 process_comment(mf, method);
1515
1516 // Register the source location of the field declaration
1517 set_source_location(mf, method);
1518
1519 if (method.skip())
1520 return;
1521
1522 for (const auto *param : mf.parameters()) {
1523 if (param != nullptr)
1524 process_function_parameter(*param, method, c);
1525 }
1526
1527 // find relationship for return type
1528 found_relationships_t relationships;
1529
1530 // Move dereferencing to build() method of template_builder
1531 if (const auto *templ = mf.getReturnType()
1532 .getNonReferenceType()
1533 .getUnqualifiedType()
1534 ->getAs<clang::TemplateSpecializationType>();
1535 templ != nullptr) {
1536 const auto *unaliased_type = templ;
1537 if (unaliased_type->isTypeAlias())
1538 unaliased_type = unaliased_type->getAliasedType()
1539 ->getAs<clang::TemplateSpecializationType>();
1540
1541 if (unaliased_type != nullptr) {
1542 auto template_specialization_ptr =
1543 std::make_unique<class_>(config().using_namespace());
1545 *template_specialization_ptr,
1546 unaliased_type->getTemplateName().getAsTemplateDecl(),
1547 *unaliased_type, &c);
1548
1549 template_specialization_ptr->is_template();
1550
1551 if (diagram().should_include(*template_specialization_ptr)) {
1552 relationships.emplace_back(template_specialization_ptr->id(),
1553 relationship_t::kDependency, &mf);
1554
1555 add_class(std::move(template_specialization_ptr));
1556 }
1557 }
1558 }
1559
1561 &mf, mf.getReturnType(), relationships, relationship_t::kDependency);
1562
1563 for (const auto &[type_element_id, relationship_type, source_decl] :
1564 relationships) {
1565 if (type_element_id != c.id() &&
1566 (relationship_type != relationship_t::kNone)) {
1567 relationship r{relationship_t::kDependency, type_element_id};
1568
1569 if (source_decl != nullptr) {
1570 set_source_location(*source_decl, r);
1571 }
1572
1573 LOG_DBG("Adding method return type relationship from {}::{} to "
1574 "{}: {}",
1575 c, mf.getNameAsString(), r.type(), r.label());
1576
1577 c.add_relationship(std::move(r));
1578 }
1579 }
1580
1581 // Also consider the container itself if it is a template
1582 // instantiation it's arguments could count as reference to relevant
1583 // types
1584 auto underlying_type = mf.getReturnType();
1585 if (underlying_type->isReferenceType())
1586 underlying_type = underlying_type.getNonReferenceType();
1587 if (underlying_type->isPointerType())
1588 underlying_type = underlying_type->getPointeeType();
1589
1590 if (const auto *atsp = underlying_type->getAs<clang::AutoType>();
1591 atsp != nullptr) {
1593 }
1594
1595 method.update(config().using_namespace());
1596
1597 if (diagram().should_include(method)) {
1598 LOG_DBG("Adding method: {}", method.name());
1599
1600 c.add_method(std::move(method));
1601 }
1602}

◆ process_method_properties()

void clanguml::class_diagram::visitor::translation_unit_visitor::process_method_properties ( const clang::CXXMethodDecl &  mf,
const class_ c,
const std::string &  method_name,
class_method method 
) const
private

Process class method properties.

Parameters
mfMethod declaration
cClass diagram element model
method_nameMethod name
methodMethod model

Definition at line 1663 of file translation_unit_visitor.cc.

1666{
1667 const bool is_constructor = c.name() == method_name;
1668 const bool is_destructor = fmt::format("~{}", c.name()) == method_name;
1669
1670#if LLVM_VERSION_MAJOR > 17
1671 method.is_pure_virtual(mf.isPureVirtual());
1672#else
1673 method.is_pure_virtual(mf.isPure());
1674#endif
1675 method.is_virtual(mf.isVirtual());
1676 method.is_const(mf.isConst());
1677 method.is_defaulted(mf.isDefaulted());
1678 method.is_deleted(mf.isDeleted());
1679 method.is_static(mf.isStatic());
1680 method.is_operator(mf.isOverloadedOperator());
1681 method.is_constexpr(mf.isConstexprSpecified() && !is_constructor);
1682 method.is_consteval(mf.isConsteval());
1683 method.is_constructor(is_constructor);
1684 method.is_destructor(is_destructor);
1685 method.is_move_assignment(mf.isMoveAssignmentOperator());
1686 method.is_copy_assignment(mf.isCopyAssignmentOperator());
1687 method.is_noexcept(isNoexceptExceptionSpec(mf.getExceptionSpecType()));
1688 method.is_coroutine(common::is_coroutine(mf));
1689}

◆ process_objc_category_declaration()

void clanguml::class_diagram::visitor::translation_unit_visitor::process_objc_category_declaration ( const clang::ObjCCategoryDecl &  cls,
objc_interface c 
)
private

Process Objective-C category declaration.

Parameters
clsObjective-C category declaration
cClass diagram element returned from create_objc_category_declaration

Definition at line 1133 of file translation_unit_visitor.cc.

1135{
1136 assert(c.is_category());
1137
1138 // Iterate over class methods (both regular and static)
1139 for (const auto *method : cls.methods()) {
1140 if (method != nullptr) {
1141 process_objc_method(*method, c);
1142 }
1143 }
1144
1145 // Add relationship to the ObjC Interface being extended by this
1146 // category
1147 if (cls.getClassInterface() != nullptr) {
1148 eid_t objc_interface_id = common::to_id(*cls.getClassInterface());
1149 common::model::relationship r{
1150 relationship_t::kInstantiation, objc_interface_id, access_t::kNone};
1151
1152 LOG_DBG("Found protocol {} [{}] for ObjC interface {}",
1153 cls.getClassInterface()->getNameAsString(),
1154 objc_interface_id.value(), c.name());
1155
1156 c.add_relationship(std::move(r));
1157 }
1158
1159 c.complete(true);
1160}

◆ process_objc_interface_base()

void clanguml::class_diagram::visitor::translation_unit_visitor::process_objc_interface_base ( const clang::ObjCInterfaceDecl &  cls,
objc_interface c 
)
private

Process Objective-C class base.

Parameters
clsObjective-C interface declaration
cClass diagram element model

Definition at line 1199 of file translation_unit_visitor.cc.

1201{
1202 if (const auto *base = cls.getSuperClass(); base != nullptr) {
1203 eid_t parent_id = common::to_id(*base);
1204 common::model::relationship cp{parent_id, access_t::kNone, false};
1205
1206 LOG_DBG("Found base class {} [{}] for ObjC interface {}",
1207 base->getNameAsString(), parent_id.value(), c.name());
1208
1209 c.add_relationship(std::move(cp));
1210 }
1211
1212 for (const auto *protocol : cls.protocols()) {
1213 eid_t parent_id = common::to_id(*protocol);
1214 common::model::relationship cp{
1215 relationship_t::kInstantiation, parent_id, access_t::kNone};
1216
1217 LOG_DBG("Found protocol {} [{}] for ObjC interface {}",
1218 protocol->getNameAsString(), parent_id.value(), c.name());
1219
1220 c.add_relationship(std::move(cp));
1221 }
1222}

◆ process_objc_interface_declaration()

void clanguml::class_diagram::visitor::translation_unit_visitor::process_objc_interface_declaration ( const clang::ObjCInterfaceDecl &  cls,
objc_interface c 
)
private

Process Objective-C interface declaration.

Parameters
clsObjective-C interface declaration
cClass diagram element returned from create_objc_interface_declaration

Definition at line 1177 of file translation_unit_visitor.cc.

1179{
1180 assert(!c.is_protocol() && !c.is_category());
1181
1182 // Iterate over class methods (both regular and static)
1183 for (const auto *method : cls.methods()) {
1184 if (method != nullptr) {
1185 process_objc_method(*method, c);
1186 }
1187 }
1188
1189 for (const auto *ivar : cls.ivars()) {
1190 if (ivar != nullptr) {
1191 process_objc_ivar(*ivar, c);
1192 }
1193 }
1194
1196
1197 c.complete(true);
1198}

◆ process_objc_ivar()

void clanguml::class_diagram::visitor::translation_unit_visitor::process_objc_ivar ( const clang::ObjCIvarDecl &  ivar,
objc_interface c 
)
private

Process Objective-C data member.

Parameters
field_declarationData member declaration
cClass diagram element model

Definition at line 1224 of file translation_unit_visitor.cc.

1226{
1227 LOG_DBG("== Visiting ObjC ivar {}", ivar.getNameAsString());
1228
1229 // Default hint for relationship is aggregation
1230 auto relationship_hint = relationship_t::kAggregation;
1231
1232 auto field_type = ivar.getType();
1233 auto field_type_str =
1234 common::to_string(field_type, ivar.getASTContext(), false);
1235
1236 auto type_name = common::to_string(field_type, ivar.getASTContext());
1237
1238 const auto field_name = ivar.getNameAsString();
1239
1240 objc_member field{
1241 common::access_specifier_to_access_t(ivar.getAccessControl()),
1242 field_name, field_type_str};
1243
1244 field.set_qualified_name(ivar.getQualifiedNameAsString());
1245
1246 process_comment(ivar, field);
1247 set_source_location(ivar, field);
1248
1249 if (field.skip())
1250 return;
1251
1252 if (field_type->isObjCObjectPointerType()) {
1253 relationship_hint = relationship_t::kAggregation;
1254 field_type = field_type->getPointeeType();
1255 }
1256 else if (field_type->isPointerType()) {
1257 relationship_hint = relationship_t::kAssociation;
1258 field_type = field_type->getPointeeType();
1259 }
1260 else if (field_type->isLValueReferenceType()) {
1261 relationship_hint = relationship_t::kAssociation;
1262 field_type = field_type.getNonReferenceType();
1263 }
1264 else if (field_type->isArrayType()) {
1265 relationship_hint = relationship_t::kAggregation;
1266 while (field_type->isArrayType()) {
1267 auto current_multiplicity = field.destination_multiplicity();
1268 if (!current_multiplicity)
1269 field.set_destination_multiplicity(common::get_array_size(
1270 *field_type->getAsArrayTypeUnsafe()));
1271 else {
1272 auto maybe_array_size =
1273 common::get_array_size(*field_type->getAsArrayTypeUnsafe());
1274 if (maybe_array_size.has_value()) {
1275 field.set_destination_multiplicity(
1276 current_multiplicity.value() *
1277 maybe_array_size.value());
1278 }
1279 }
1280
1281 field_type = field_type->getAsArrayTypeUnsafe()->getElementType();
1282 }
1283 }
1284 else if (field_type->isRValueReferenceType()) {
1285 field_type = field_type.getNonReferenceType();
1286 }
1287
1288 found_relationships_t relationships;
1289
1290 if (!field.skip_relationship()) {
1291 // Find relationship for the type if the type has not been added
1292 // as aggregation
1293 if (field_type->getAsObjCInterfaceType() != nullptr &&
1294 field_type->getAsObjCInterfaceType()->getInterface() != nullptr) {
1295 const auto *objc_iface =
1296 field_type->getAsObjCInterfaceType()->getInterface();
1297
1298 relationships.emplace_back(common::to_id(*objc_iface),
1299 relationship_t::kAggregation, &ivar);
1300 }
1301 else if ((field_type->getAsRecordDecl() != nullptr) &&
1302 field_type->getAsRecordDecl()->getNameAsString().empty()) {
1303 // Relationships to fields whose type is an anonymous and nested
1304 // struct have to be handled separately here
1305 anonymous_struct_relationships_[field_type->getAsRecordDecl()
1306 ->getID()] =
1307 std::make_tuple(field.name(), relationship_hint, field.access(),
1308 field.destination_multiplicity());
1309 }
1310 else
1312 &ivar, field_type, relationships, relationship_hint);
1313
1314 add_relationships(c, field, relationships);
1315 }
1316
1317 // If this is an anonymous struct - replace the anonymous_XYZ part with
1318 // field name
1319 if ((field_type->getAsRecordDecl() != nullptr) &&
1320 field_type->getAsRecordDecl()->getNameAsString().empty()) {
1321 if (util::contains(field.type(), "(anonymous_")) {
1322 std::regex anonymous_re("anonymous_(\\d*)");
1323 field.set_type(
1324 std::regex_replace(field.type(), anonymous_re, field_name));
1325 }
1326 }
1327
1328 c.add_member(std::move(field));
1329}

◆ process_objc_method()

void clanguml::class_diagram::visitor::translation_unit_visitor::process_objc_method ( const clang::ObjCMethodDecl &  mf,
objc_interface c 
)
private

Process Objective-C method.

Parameters
mfMethod declaration
cClass diagram element model

Definition at line 1604 of file translation_unit_visitor.cc.

1606{
1607 auto method_return_type =
1608 common::to_string(mf.getReturnType(), mf.getASTContext());
1609
1610 objc_method method{common::access_specifier_to_access_t(mf.getAccess()),
1611 util::trim(mf.getNameAsString()), method_return_type};
1612
1613 method.set_qualified_name(mf.getQualifiedNameAsString());
1614
1615 process_comment(mf, method);
1616
1617 // Register the source location of the field declaration
1618 set_source_location(mf, method);
1619
1620 if (method.skip())
1621 return;
1622
1623 method.is_static(mf.isClassMethod());
1624 method.is_optional(mf.isOptional());
1625
1626 for (const auto *param : mf.parameters()) {
1627 if (param != nullptr)
1628 process_objc_method_parameter(*param, method, c);
1629 }
1630
1631 // find relationship for return type
1632 found_relationships_t relationships;
1633
1635 &mf, mf.getReturnType(), relationships, relationship_t::kDependency);
1636
1637 for (const auto &[type_element_id, relationship_type, source_decl] :
1638 relationships) {
1639 if (type_element_id != c.id() &&
1640 (relationship_type != relationship_t::kNone)) {
1641 relationship r{relationship_t::kDependency, type_element_id};
1642
1643 if (source_decl != nullptr) {
1644 set_source_location(*source_decl, r);
1645 }
1646
1647 LOG_DBG("Adding method return type relationship from {}::{} to "
1648 "{}: {}",
1649 c, mf.getNameAsString(), r.type(), r.label());
1650
1651 c.add_relationship(std::move(r));
1652 }
1653 }
1654
1655 // TODO
1656 if (diagram().should_include(method)) {
1657 LOG_DBG("Adding ObjC method: {}", method.name());
1658
1659 c.add_method(std::move(method));
1660 }
1661}

◆ process_objc_method_parameter()

void clanguml::class_diagram::visitor::translation_unit_visitor::process_objc_method_parameter ( const clang::ParmVarDecl &  param,
objc_method method,
objc_interface c 
)
private

Process Objective-C class method parameter.

Parameters
paramParameter declaration
methodClass method model
cClass diagram element model
template_parameter_namesIgnored

Definition at line 1954 of file translation_unit_visitor.cc.

1956{
1957 method_parameter parameter;
1958 parameter.set_name(param.getNameAsString());
1959
1960 process_comment(param, parameter);
1961
1962 if (parameter.skip())
1963 return;
1964
1965 auto parameter_type =
1966 common::to_string(param.getType(), param.getASTContext());
1967 parameter.set_type(parameter_type);
1968
1969 if (!parameter.skip_relationship()) {
1970 // find relationship for the type
1971 found_relationships_t relationships;
1972
1973 LOG_DBG("Looking for relationships in type: {}",
1974 common::to_string(param.getType(), param.getASTContext()));
1975
1976 find_relationships(&param, param.getType(), relationships,
1977 relationship_t::kDependency);
1978
1979 for (const auto &[type_element_id, relationship_type, source_decl] :
1980 relationships) {
1981 if (type_element_id != c.id() &&
1982 (relationship_type != relationship_t::kNone)) {
1983 relationship r{relationship_t::kDependency, type_element_id};
1984
1985 if (source_decl != nullptr) {
1986 set_source_location(*source_decl, r);
1987 }
1988
1989 LOG_DBG("Adding ObjC method parameter relationship from {} to "
1990 "{}: {}",
1991 c, r.type(), r.label());
1992
1993 c.add_relationship(std::move(r));
1994 }
1995 }
1996 }
1997
1998 method.add_parameter(std::move(parameter));
1999}

◆ process_objc_protocol_declaration()

void clanguml::class_diagram::visitor::translation_unit_visitor::process_objc_protocol_declaration ( const clang::ObjCProtocolDecl &  cls,
objc_interface c 
)
private

Process Objective-C protocol declaration.

Parameters
clsObjective-C protocol declaration
cClass diagram element returned from create_objc_protocol_declaration

Definition at line 1162 of file translation_unit_visitor.cc.

1164{
1165 assert(c.is_protocol());
1166
1167 // Iterate over class methods (both regular and static)
1168 for (const auto *method : cls.methods()) {
1169 if (method != nullptr) {
1170 process_objc_method(*method, c);
1171 }
1172 }
1173
1174 c.complete(true);
1175}

◆ process_record_members()

void clanguml::class_diagram::visitor::translation_unit_visitor::process_record_members ( const clang::RecordDecl *  cls,
class_ c 
)
private

Process class or record data members.

Parameters
clsClass declaration
cClass diagram element model

Definition at line 1371 of file translation_unit_visitor.cc.

1373{
1374 // Iterate over regular class fields
1375 for (const auto *field : cls->fields()) {
1376 if (field != nullptr)
1377 process_field(*field, c);
1378 }
1379}

◆ process_record_parent()

void clanguml::class_diagram::visitor::translation_unit_visitor::process_record_parent ( clang::RecordDecl *  cls,
class_ c,
const namespace_ &  ns 
)
private

Process record parent element (e.g. for nested classes)

This method handles nested classes or structs.

Parameters
clsRecord declaration
cClass diagram element model
nsPackage in the diagram to which the class c should belong

Definition at line 1103 of file translation_unit_visitor.cc.

1105{
1106 std::optional<eid_t> id_opt;
1107 namespace_ parent_ns = ns;
1108
1109 find_record_parent_id(cls, id_opt, parent_ns);
1110
1111 if (id_opt && diagram().find<class_>(*id_opt)) {
1112 process_record_parent_by_type<class_>(*id_opt, c, parent_ns, cls);
1113 }
1114
1115 if (id_opt && diagram().find<objc_interface>(*id_opt)) {
1116 process_record_parent_by_type<objc_interface>(
1117 *id_opt, c, parent_ns, cls);
1118 }
1119}

◆ process_record_parent_by_type()

template<typename T >
void clanguml::class_diagram::visitor::translation_unit_visitor::process_record_parent_by_type ( eid_t  parent_id,
class_ c,
namespace_  parent_ns,
const clang::RecordDecl *  decl 
)
private

Definition at line 585 of file translation_unit_visitor.h.

587{
588 // Here we have 2 options, either:
589 // - the parent is a regular C++ class/struct
590 // - the parent is a class template declaration/specialization
591 auto parent_class = diagram().find<T>(parent_id);
592
593 c.set_namespace(parent_ns);
594 const auto cls_name = decl->getNameAsString();
595 if (cls_name.empty()) {
596 // Nested structs can be anonymous
597 if (anonymous_struct_relationships_.count(decl->getID()) > 0) {
598 const auto &[label, hint, access, destination_multiplicity] =
599 anonymous_struct_relationships_[decl->getID()];
600
601 c.set_name(parent_class.value().name() + "##" +
602 fmt::format("({})", label));
603
604 std::string destination_multiplicity_str{};
605 if (destination_multiplicity.has_value()) {
606 destination_multiplicity_str =
607 std::to_string(*destination_multiplicity);
608 }
609
610 parent_class.value().add_relationship(
611 {hint, common::to_id(c.full_name(false)), access, label, "",
612 destination_multiplicity_str});
613 }
614 else
615 c.set_name(parent_class.value().name() + "##" +
616 fmt::format("(anonymous_{})", std::to_string(decl->getID())));
617 }
618 else {
619 c.set_name(
620 parent_class.value().name() + "##" + decl->getNameAsString());
621 }
622
623 c.set_id(common::to_id(c.full_name(false)));
624
625 if (!(decl->getNameAsString().empty())) {
626 // Don't add anonymous structs as contained in the class
627 // as they are already added as aggregations
628 c.add_relationship({relationship_t::kContainment, parent_id});
629 }
630
631 c.nested(true);
632}

◆ process_static_field()

void clanguml::class_diagram::visitor::translation_unit_visitor::process_static_field ( const clang::VarDecl &  field_declaration,
clanguml::class_diagram::model::class_ c 
)
private

Process class static data member.

Parameters
field_declarationStatic data member declaration
cClass diagram element model

Definition at line 2127 of file translation_unit_visitor.cc.

2129{
2130 const auto field_type = field_declaration.getType();
2131 auto type_name =
2132 common::to_string(field_type, field_declaration.getASTContext());
2133 if (type_name.empty())
2134 type_name = "<<anonymous>>";
2135
2136 class_member field{
2137 common::access_specifier_to_access_t(field_declaration.getAccess()),
2138 field_declaration.getNameAsString(),
2139 config().simplify_template_type(type_name)};
2140
2141 field.set_qualified_name(field_declaration.getQualifiedNameAsString());
2142
2143 field.is_static(true);
2144
2145 process_comment(field_declaration, field);
2146 set_source_location(field_declaration, field);
2147
2148 if (field.skip() || !diagram().should_include(field))
2149 return;
2150
2151 if (!field.skip_relationship()) {
2152 found_relationships_t relationships;
2153
2154 // find relationship for the type
2155 find_relationships(&field_declaration, field_declaration.getType(),
2156 relationships, relationship_t::kAssociation);
2157
2158 add_relationships(c, field, relationships);
2159 }
2160
2161 c.add_member(std::move(field));
2162}

◆ process_template_method()

void clanguml::class_diagram::visitor::translation_unit_visitor::process_template_method ( const clang::FunctionTemplateDecl &  mf,
clanguml::class_diagram::model::class_ c 
)
private

Process class template method.

Parameters
mfMethod declaration
cClass diagram element model

Definition at line 1742 of file translation_unit_visitor.cc.

1744{
1745 // TODO: For now skip implicitly default methods
1746 // in the future, add config option to choose
1747 if (mf.getTemplatedDecl()->isDefaulted() &&
1748 !mf.getTemplatedDecl()->isExplicitlyDefaulted())
1749 return;
1750
1751 auto method_name = mf.getNameAsString();
1752 if (mf.isTemplated()) {
1753 // Sometimes in template specializations method names contain the
1754 // template parameters for some reason - drop them
1755 // Is there a better way to do this?
1756 method_name = util::trim(method_name.substr(0, method_name.find('<')));
1757 }
1758
1759 class_method method{common::access_specifier_to_access_t(mf.getAccess()),
1760 method_name, mf.getTemplatedDecl()->getReturnType().getAsString()};
1761
1763 clang::dyn_cast<clang::CXXMethodDecl>(mf.getTemplatedDecl()),
1764 [&](const auto *decl) {
1765 process_method_properties(*decl, c, method_name, method);
1766 });
1767
1769
1770 process_comment(mf, method);
1771
1772 if (method.skip())
1773 return;
1774
1775 for (const auto *param : mf.getTemplatedDecl()->parameters()) {
1776 if (param != nullptr)
1777 process_function_parameter(*param, method, c);
1778 }
1779
1780 method.update(config().using_namespace());
1781
1782 if (diagram().should_include(method)) {
1783 LOG_DBG("Adding method: {}", method.name());
1784
1785 c.add_method(std::move(method));
1786 }
1787}

◆ process_template_specialization()

std::unique_ptr< class_ > clanguml::class_diagram::visitor::translation_unit_visitor::process_template_specialization ( clang::ClassTemplateSpecializationDecl *  cls)
private

Process class template specialization/instantiation.

Parameters
clsClass template specialization declaration
Returns
Class diagram element model

Definition at line 2165 of file translation_unit_visitor.cc.

2167{
2168 auto c_ptr = std::make_unique<class_>(config().using_namespace());
2170
2171 auto &template_instantiation = *c_ptr;
2172 template_instantiation.is_template(true);
2173
2174 // TODO: refactor to method get_qualified_name()
2175 auto qualified_name = cls->getQualifiedNameAsString();
2176 util::replace_all(qualified_name, "(anonymous namespace)", "");
2177 util::replace_all(qualified_name, "::::", "::");
2178
2179 namespace_ ns{qualified_name};
2180 ns.pop_back();
2181 template_instantiation.set_name(cls->getNameAsString());
2182 template_instantiation.set_namespace(ns);
2183
2184 template_instantiation.is_struct(cls->isStruct());
2185
2186 process_record_parent(cls, template_instantiation, ns);
2187
2188 if (!template_instantiation.is_nested()) {
2189 template_instantiation.set_name(common::get_tag_name(*cls));
2190 template_instantiation.set_id(
2191 common::to_id(template_instantiation.full_name(false)));
2192 }
2193
2194 process_comment(*cls, template_instantiation);
2195 set_source_location(*cls, template_instantiation);
2196 set_owning_module(*cls, template_instantiation);
2197
2198 if (template_instantiation.skip())
2199 return {};
2200
2201 id_mapper().add(cls->getID(), template_instantiation.id());
2202
2203 return c_ptr;
2204}

◆ process_template_specialization_children()

void clanguml::class_diagram::visitor::translation_unit_visitor::process_template_specialization_children ( const clang::ClassTemplateSpecializationDecl *  cls,
class_ c 
)
private

Process template specialization children (members and methods)

Parameters
clsClass template specialization declaration
cClass diagram element model

◆ resolve_local_to_global_ids()

void clanguml::class_diagram::visitor::translation_unit_visitor::resolve_local_to_global_ids ( )
private

Replace any AST local ids in diagram elements with global ones.

Not all elements global ids can be set in relationships during traversal of the AST. In such cases, a local id (obtained from getID()) and at after the traversal is complete, the id is replaced with the global diagram id.

Definition at line 2478 of file translation_unit_visitor.cc.

2479{
2480 diagram().for_all_elements([&](auto &element_view) {
2481 for (const auto &el : element_view) {
2482 for (auto &rel : el.get().relationships()) {
2483 if (!rel.destination().is_global()) {
2484 const auto maybe_id =
2485 id_mapper().get_global_id(rel.destination());
2486 if (maybe_id) {
2487 LOG_TRACE(
2488 "= Resolved instantiation destination from local "
2489 "id {} to global id {}",
2490 rel.destination(), *maybe_id);
2491 rel.set_destination(*maybe_id);
2492 }
2493 }
2494 }
2495 el.get().remove_duplicate_relationships();
2496 }
2497 });
2498}

◆ tbuilder()

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

Get template builder reference.

Returns
Reference to 'template_builder' instance

Definition at line 551 of file translation_unit_visitor.h.

551{ return template_builder_; }

Member Data Documentation

◆ anonymous_struct_relationships_

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

Definition at line 569 of file translation_unit_visitor.h.

◆ forward_declarations_

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

Definition at line 563 of file translation_unit_visitor.h.

◆ processed_template_qualified_names_

std::set<std::string> clanguml::class_diagram::visitor::translation_unit_visitor::processed_template_qualified_names_
private

When visiting CXX records we need to know if they have already been process in VisitClassTemplateDecl or VisitClassTemplateSpecializationDecl. If yes, then we need to skip it

Todo:
There must be a better way to do this...

Definition at line 581 of file translation_unit_visitor.h.

◆ template_builder_

template_builder_t clanguml::class_diagram::visitor::translation_unit_visitor::template_builder_
private

Definition at line 560 of file translation_unit_visitor.h.

◆ typedef_enum_decls_

std::map<const clang::EnumDecl *, const clang::TypedefDecl *> clanguml::class_diagram::visitor::translation_unit_visitor::typedef_enum_decls_
private

Definition at line 572 of file translation_unit_visitor.h.


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