0.5.4
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 68 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 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)
 
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_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::class_create_record_declaration (clang::RecordDecl *rec)
 Create class element model from record (e.g. struct) declaration.
 
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_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_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_function_parameter (const clang::ParmVarDecl &param, clanguml::class_diagram::model::class_method &method, clanguml::class_diagram::model::class_ &c, const std::set< std::string > &template_parameter_names={})
 Process function/method parameter.
 
void process_friend (const clang::FriendDecl &f, clanguml::class_diagram::model::class_ &c)
 Process class friend.
 
bool find_relationships (const clang::QualType &type, found_relationships_t &, clanguml::common::model::relationship_t relationship_hint)
 Find relationships in a specific type.
 
void add_relationships (clanguml::class_diagram::model::class_ &c, const clanguml::class_diagram::model::class_member &field, const found_relationships_t &relationships, bool break_on_first_aggregation=false)
 Add relationships from relationship list to a class 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.
 

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::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 ()
 

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

2019{
2020 if ((config().generate_packages() &&
2021 config().package_type() == config::package_type_t::kDirectory)) {
2022 assert(!c->file().empty());
2023
2024 const auto file = config().make_path_relative(c->file());
2025
2026 common::model::path p{
2028 p.pop_back();
2029
2030 diagram().add(p, std::move(c));
2031 }
2032 else if ((config().generate_packages() &&
2033 config().package_type() == config::package_type_t::kModule)) {
2034
2035 const auto module_path = config().make_module_relative(c->module());
2036
2037 common::model::path p{module_path, common::model::path_type::kModule};
2038
2039 diagram().add(p, std::move(c));
2040 }
2041 else {
2042 diagram().add(c->path(), std::move(c));
2043 }
2044}

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

2075{
2076 if ((config().generate_packages() &&
2077 config().package_type() == config::package_type_t::kDirectory)) {
2078 assert(!c->file().empty());
2079
2080 const auto file = config().make_path_relative(c->file());
2081
2082 common::model::path p{
2084 p.pop_back();
2085
2086 diagram().add(p, std::move(c));
2087 }
2088 else if ((config().generate_packages() &&
2089 config().package_type() == config::package_type_t::kModule)) {
2090
2091 const auto module_path = config().make_module_relative(c->module());
2092
2093 common::model::path p{module_path, common::model::path_type::kModule};
2094
2095 diagram().add(p, std::move(c));
2096 }
2097 else {
2098 diagram().add(c->path(), std::move(c));
2099 }
2100}

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

2014{
2015 add_class(util::unique_pointer_cast<class_>(std::move(element)));
2016}

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

2047{
2048 if ((config().generate_packages() &&
2049 config().package_type() == config::package_type_t::kDirectory)) {
2050 assert(!e->file().empty());
2051
2052 const auto file = config().make_path_relative(e->file());
2053
2054 common::model::path p{
2056 p.pop_back();
2057
2058 diagram().add(p, std::move(e));
2059 }
2060 else if ((config().generate_packages() &&
2061 config().package_type() == config::package_type_t::kModule)) {
2062
2063 const auto module_path = config().make_module_relative(e->module());
2064
2065 common::model::path p{module_path, common::model::path_type::kModule};
2066
2067 diagram().add(p, std::move(e));
2068 }
2069 else {
2070 diagram().add(e->path(), std::move(e));
2071 }
2072}

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

1907{
1908 for (auto &[id, c] : forward_declarations_) {
1909 if (diagram().should_include(c->get_namespace())) {
1910 add_class(std::move(c));
1911 }
1912 }
1913 forward_declarations_.clear();
1914}

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

2002{
2003 processed_template_qualified_names_.emplace(std::move(qualified_name));
2004}

◆ add_relationships()

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

Add relationships from relationship list to a class 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
cClass diagram element model
fieldClass member model
relationshipsList of found relationships
break_on_first_aggregationStop adding relatinoships, after first aggregation is found

Definition at line 1578 of file translation_unit_visitor.cc.

1581{
1582 auto [decorator_rtype, decorator_rmult] = field.get_relationship();
1583
1584 for (const auto &[target, relationship_type] : relationships) {
1585 if (relationship_type != relationship_t::kNone) {
1586 relationship r{relationship_type, target};
1587 r.set_label(field.name());
1588 r.set_access(field.access());
1589 bool mulitplicity_provided_in_comment{false};
1590 if (decorator_rtype != relationship_t::kNone) {
1591 r.set_type(decorator_rtype);
1592 auto mult = util::split(decorator_rmult, ":", false);
1593 if (mult.size() == 2) {
1594 mulitplicity_provided_in_comment = true;
1595 r.set_multiplicity_source(mult[0]);
1596 r.set_multiplicity_destination(mult[1]);
1597 }
1598 }
1599 if (!mulitplicity_provided_in_comment &&
1600 field.destination_multiplicity().has_value()) {
1601 r.set_multiplicity_destination(
1602 std::to_string(*field.destination_multiplicity()));
1603 }
1604
1605 r.set_style(field.style_spec());
1606
1607 LOG_DBG("Adding relationship from {} to {} with label {}",
1608 c.full_name(false), r.destination(),
1609 clanguml::common::model::to_string(r.type()), r.label());
1610
1611 c.add_relationship(std::move(r));
1612
1613 if (break_on_first_aggregation &&
1614 relationship_type == relationship_t::kAggregation)
1615 break;
1616 }
1617 }
1618}

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

828{
829 assert(cls != nullptr);
830
831 if (!should_include(cls))
832 return {};
833
834 auto c_ptr{std::make_unique<class_>(config().using_namespace())};
835 auto &c = *c_ptr;
836
837 auto ns{common::get_tag_namespace(*cls)};
838
839 process_record_parent(cls, c, ns);
840
841 if (!c.is_nested()) {
842 c.set_name(common::get_tag_name(*cls));
843 c.set_namespace(ns);
844 c.set_id(common::to_id(c.full_name(false)));
845 }
846
847 c.is_struct(cls->isStruct());
848
849 process_comment(*cls, c);
850 set_source_location(*cls, c);
851 set_owning_module(*cls, c);
852
853 if (c.skip())
854 return {};
855
856 c.set_style(c.style_spec());
857
858 return c_ptr;
859}

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

752{
753 assert(cpt != nullptr);
754
755 if (!should_include(cpt))
756 return {};
757
758 auto concept_ptr{
759 std::make_unique<model::concept_>(config().using_namespace())};
760 auto &concept_model = *concept_ptr;
761
762 auto ns = common::get_template_namespace(*cpt);
763
764 concept_model.set_name(cpt->getNameAsString());
765 concept_model.set_namespace(ns);
766 concept_model.set_id(common::to_id(concept_model.full_name(false)));
767
768 process_comment(*cpt, concept_model);
769 set_source_location(*cpt, concept_model);
770 set_owning_module(*cpt, concept_model);
771
772 if (concept_model.skip())
773 return {};
774
775 concept_model.set_style(concept_model.style_spec());
776
777 return concept_ptr;
778}

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

782{
783 assert(rec != nullptr);
784
785 if (!should_include(rec))
786 return {};
787
788 auto record_ptr{std::make_unique<class_>(config().using_namespace())};
789 auto &record = *record_ptr;
790
791 process_record_parent(rec, record, namespace_{});
792
793 if (!record.is_nested()) {
794 auto record_name = rec->getQualifiedNameAsString();
795
796#if LLVM_VERSION_MAJOR < 16
797 if (record_name == "(anonymous)") {
798 util::if_not_null(rec->getTypedefNameForAnonDecl(),
799 [&record_name](const clang::TypedefNameDecl *name) {
800 record_name = name->getNameAsString();
801 });
802 }
803#endif
804
805 record.set_name(record_name);
806 record.set_id(common::to_id(record.full_name(false)));
807 }
808
809 process_comment(*rec, record);
810 set_source_location(*rec, record);
811 set_owning_module(*rec, record);
812
813 const auto record_full_name = record_ptr->full_name(false);
814
815 record.is_struct(rec->isStruct());
816 record.is_union(rec->isUnion());
817
818 if (record.skip())
819 return {};
820
821 record.set_style(record.style_spec());
822
823 return record_ptr;
824}

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

1978{
1979 const auto full_declaration_text = common::get_source_text_raw(
1980 concept_specialization->getSourceRange(), source_manager());
1981
1982 if (!full_declaration_text.empty()) {
1983 // Handle typename constraint in requires clause
1984 if (type_name.find("type-parameter-") == 0) {
1985 const auto concept_declaration_text = full_declaration_text.substr(
1986 full_declaration_text.find(cpt->getNameAsString()) +
1987 cpt->getNameAsString().size() + 1);
1988
1989 auto template_params = common::parse_unexposed_template_params(
1990 concept_declaration_text, [](const auto &t) { return t; });
1991
1992 if (template_params.size() > argument_index)
1993 type_name = template_params[argument_index].to_string(
1994 config().using_namespace(), false);
1995 }
1996 constrained_template_params.push_back(type_name);
1997 }
1998}

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

1965{
1968 if (config().skip_redundant_dependencies()) {
1969 diagram().remove_redundant_dependencies();
1970 }
1971}

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

2105{
2106 auto &template_instantiation = dynamic_cast<class_diagram::model::class_ &>(
2107 template_instantiation_base);
2108
2109 // First try to find the best match for this template in partially
2110 // specialized templates
2111 std::string destination{};
2112 std::string best_match_full_name{};
2113 auto full_template_name = template_instantiation.full_name(false);
2114 int best_match{};
2115 eid_t best_match_id{};
2116
2117 for (const auto templ : diagram().classes()) {
2118 if (templ.get() == template_instantiation)
2119 continue;
2120
2121 auto c_full_name = templ.get().full_name(false);
2122 auto match =
2123 template_instantiation.calculate_template_specialization_match(
2124 templ.get());
2125
2126 if (match > best_match) {
2127 best_match = match;
2128 best_match_full_name = c_full_name;
2129 best_match_id = templ.get().id();
2130 }
2131 }
2132
2133 auto templated_decl_global_id =
2134 id_mapper().get_global_id(templated_decl_id).value_or(eid_t{});
2135
2136 if (best_match_id.value() > 0) {
2137 destination = best_match_full_name;
2138 template_instantiation.add_relationship(
2140 template_instantiation.template_specialization_found(true);
2141 }
2142 // If we can't find optimal match for parent template specialization,
2143 // just use whatever clang suggests
2144 else if (diagram().has_element(templated_decl_global_id)) {
2145 template_instantiation.add_relationship(
2147 templated_decl_global_id});
2148 template_instantiation.template_specialization_found(true);
2149 }
2150 else if (diagram().should_include(common::model::namespace_{full_name})) {
2151 LOG_DBG("Skipping instantiation relationship from {} to {}",
2152 template_instantiation.full_name(false), templated_decl_global_id);
2153 }
2154 else {
2155 LOG_DBG("== Cannot determine global id for specialization template {} "
2156 "- delaying until the translation unit is complete ",
2157 templated_decl_global_id);
2158
2159 template_instantiation.add_relationship(
2161 }
2162}

◆ find_relationships()

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

Find relationships in a specific type.

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

Definition at line 1339 of file translation_unit_visitor.cc.

1342{
1343 bool result{false};
1344
1345 if (type->isPointerType()) {
1346 relationship_hint = relationship_t::kAssociation;
1348 type->getPointeeType(), relationships, relationship_hint);
1349 }
1350 else if (type->isRValueReferenceType()) {
1351 relationship_hint = relationship_t::kAggregation;
1353 type.getNonReferenceType(), relationships, relationship_hint);
1354 }
1355 else if (type->isLValueReferenceType()) {
1356 relationship_hint = relationship_t::kAssociation;
1358 type.getNonReferenceType(), relationships, relationship_hint);
1359 }
1360 else if (type->isArrayType()) {
1361 find_relationships(type->getAsArrayTypeUnsafe()->getElementType(),
1362 relationships, relationship_t::kAggregation);
1363 }
1364 else if (type->isEnumeralType()) {
1365 if (const auto *enum_type = type->getAs<clang::EnumType>();
1366 enum_type != nullptr) {
1367 // Use AST's local ID here for relationship target, as we can't
1368 // calculate here properly the ID for nested enums. It will be
1369 // resolved properly in finalize().
1370 relationships.emplace_back(
1371 enum_type->getDecl()->getID(), relationship_hint);
1372 }
1373 }
1374 else if (type->isRecordType()) {
1375 const auto *type_instantiation_decl =
1376 type->getAs<clang::TemplateSpecializationType>();
1377
1378 if (type_instantiation_decl != nullptr) {
1379 // If this template should be included in the diagram
1380 // add it - and then process recursively its arguments
1381 if (should_include(type_instantiation_decl->getTemplateName()
1382 .getAsTemplateDecl())) {
1383 relationships.emplace_back(
1384 type_instantiation_decl->getTemplateName()
1385 .getAsTemplateDecl()
1386 ->getID(),
1387 relationship_hint);
1388 }
1389 for (const auto &template_argument :
1390 type_instantiation_decl->template_arguments()) {
1391 const auto template_argument_kind = template_argument.getKind();
1392 if (template_argument_kind ==
1393 clang::TemplateArgument::ArgKind::Integral) {
1394 // pass
1395 }
1396 else if (template_argument_kind ==
1397 clang::TemplateArgument::ArgKind::Null) {
1398 // pass
1399 }
1400 else if (template_argument_kind ==
1401 clang::TemplateArgument::ArgKind::Expression) {
1402 // pass
1403 }
1404 else if (template_argument.getKind() ==
1405 clang::TemplateArgument::ArgKind::NullPtr) {
1406 // pass
1407 }
1408 else if (template_argument_kind ==
1409 clang::TemplateArgument::ArgKind::Template) {
1410 // pass
1411 }
1412 else if (template_argument_kind ==
1413 clang::TemplateArgument::ArgKind::TemplateExpansion) {
1414 // pass
1415 }
1416 else if (const auto *function_type =
1417 template_argument.getAsType()
1418 ->getAs<clang::FunctionProtoType>();
1419 function_type != nullptr) {
1420 for (const auto &param_type :
1421 function_type->param_types()) {
1422 result = find_relationships(param_type, relationships,
1423 relationship_t::kDependency);
1424 }
1425 }
1426 else if (template_argument_kind ==
1427 clang::TemplateArgument::ArgKind::Type) {
1428 result = find_relationships(template_argument.getAsType(),
1429 relationships, relationship_hint);
1430 }
1431 }
1432 }
1433 else if (type->getAsCXXRecordDecl() != nullptr) {
1434 relationships.emplace_back(
1435 type->getAsCXXRecordDecl()->getID(), relationship_hint);
1436 result = true;
1437 }
1438 else {
1439 relationships.emplace_back(
1440 type->getAsRecordDecl()->getID(), relationship_hint);
1441 result = true;
1442 }
1443 }
1444 else if (const auto *template_specialization_type =
1445 type->getAs<clang::TemplateSpecializationType>();
1446 template_specialization_type != nullptr) {
1447 if (should_include(template_specialization_type->getTemplateName()
1448 .getAsTemplateDecl())) {
1449 relationships.emplace_back(
1450 template_specialization_type->getTemplateName()
1451 .getAsTemplateDecl()
1452 ->getID(),
1453 relationship_hint);
1454 }
1455 for (const auto &template_argument :
1456 template_specialization_type->template_arguments()) {
1457 const auto template_argument_kind = template_argument.getKind();
1458 if (template_argument_kind ==
1459 clang::TemplateArgument::ArgKind::Integral) {
1460 // pass
1461 }
1462 else if (template_argument_kind ==
1463 clang::TemplateArgument::ArgKind::Null) {
1464 // pass
1465 }
1466 else if (template_argument_kind ==
1467 clang::TemplateArgument::ArgKind::Expression) {
1468 // pass
1469 }
1470 else if (template_argument.getKind() ==
1471 clang::TemplateArgument::ArgKind::NullPtr) {
1472 // pass
1473 }
1474 else if (template_argument_kind ==
1475 clang::TemplateArgument::ArgKind::Template) {
1476 // pass
1477 }
1478 else if (template_argument_kind ==
1479 clang::TemplateArgument::ArgKind::TemplateExpansion) {
1480 // pass
1481 }
1482 else if (const auto *function_type =
1483 template_argument.getAsType()
1484 ->getAs<clang::FunctionProtoType>();
1485 function_type != nullptr) {
1486 for (const auto &param_type : function_type->param_types()) {
1487 result = find_relationships(
1488 param_type, relationships, relationship_t::kDependency);
1489 }
1490 }
1491 else if (template_argument_kind ==
1492 clang::TemplateArgument::ArgKind::Type) {
1493 result = find_relationships(template_argument.getAsType(),
1494 relationships, relationship_hint);
1495 }
1496 }
1497 }
1498
1499 return result;
1500}

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

572{
573 if (expr == nullptr)
574 return;
575 found_relationships_t relationships;
576
577 common::if_dyn_cast<clang::UnresolvedLookupExpr>(expr, [&](const auto *ul) {
578 for (const auto ta : ul->template_arguments()) {
579 find_relationships(ta.getArgument().getAsType(), relationships,
580 relationship_t::kConstraint);
581 }
582 });
583
584 common::if_dyn_cast<clang::ConceptSpecializationExpr>(
585 expr, [&](const auto *cs) {
587 });
588
589 common::if_dyn_cast<clang::RequiresExpr>(expr, [&](const auto *re) {
590 // TODO
591 });
592
593 common::if_dyn_cast<clang::BinaryOperator>(expr, [&](const auto *op) {
596 });
597
598 common::if_dyn_cast<clang::UnaryOperator>(expr, [&](const auto *op) {
600 });
601
602 for (const auto &[type_element_id, relationship_type] : relationships) {
603 if (type_element_id != c.id() &&
604 (relationship_type != relationship_t::kNone)) {
605
606 relationship r{relationship_type, type_element_id};
607
608 c.add_relationship(std::move(r));
609 }
610 }
611}

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

2008{
2010}

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

957{
958 for (const auto &base : cls->bases()) {
959 class_parent cp;
960 auto name_and_ns = common::model::namespace_{
961 common::to_string(base.getType(), cls->getASTContext())};
962
963 cp.set_name(name_and_ns.to_string());
964
965 if (const auto *tsp =
966 base.getType()->getAs<clang::TemplateSpecializationType>();
967 tsp != nullptr) {
968 auto template_specialization_ptr =
969 std::make_unique<class_>(config().using_namespace());
971 *template_specialization_ptr, cls, *tsp, {});
972
973 cp.set_id(template_specialization_ptr->id());
974 cp.set_name(template_specialization_ptr->full_name(false));
975
976 if (diagram().should_include(*template_specialization_ptr)) {
977 add_class(std::move(template_specialization_ptr));
978 }
979 }
980 else if (const auto *record_type =
981 base.getType()->getAs<clang::RecordType>();
982 record_type != nullptr) {
983 cp.set_name(record_type->getDecl()->getQualifiedNameAsString());
984 cp.set_id(common::to_id(*record_type->getDecl()));
985 }
986 else
987 // This could be a template parameter - we don't want it here
988 continue;
989
990 cp.is_virtual(base.isVirtual());
991
992 cp.set_access(
993 common::access_specifier_to_access_t(base.getAccessSpecifier()));
994
995 LOG_DBG("Found base class {} [{}] for class {}", cp.name(), cp.id(),
996 c.name());
997
998 c.add_parent(std::move(cp));
999 }
1000}

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

1014{
1015 assert(cls != nullptr);
1016
1017 // Iterate over class methods (both regular and static)
1018 for (const auto *method : cls->methods()) {
1019 if (method != nullptr) {
1020 process_method(*method, c);
1021 }
1022 }
1023
1024 // Iterate over class template methods
1025 if (const auto *cls_decl_context =
1026 clang::dyn_cast_or_null<clang::DeclContext>(cls);
1027 cls_decl_context != nullptr) {
1028 for (auto const *decl_iterator : cls_decl_context->decls()) {
1029 auto const *method_template =
1030 llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>(
1031 decl_iterator);
1032 if (method_template == nullptr)
1033 continue;
1034
1035 process_template_method(*method_template, c);
1036 }
1037 }
1038
1039 // Iterate over regular class fields
1040 for (const auto *field : cls->fields()) {
1041 if (field != nullptr)
1042 process_field(*field, c);
1043 }
1044
1045 // Static fields have to be processed by iterating over variable
1046 // declarations
1047 for (const auto *decl : cls->decls()) {
1048 if (decl->getKind() == clang::Decl::Var) {
1049 const clang::VarDecl *variable_declaration{
1050 clang::dyn_cast_or_null<clang::VarDecl>(decl)};
1051 if ((variable_declaration != nullptr) &&
1052 variable_declaration->isStaticDataMember()) {
1053 process_static_field(*variable_declaration, c);
1054 }
1055 }
1056 else if (decl->getKind() == clang::Decl::Enum) {
1057 const auto *enum_decl =
1058 clang::dyn_cast_or_null<clang::EnumDecl>(decl);
1059 if (enum_decl == nullptr)
1060 continue;
1061
1062 if (enum_decl->getNameAsString().empty()) {
1063 for (const auto *enum_const : enum_decl->enumerators()) {
1065 enum_decl->getAccess()),
1066 enum_const->getNameAsString(), "enum"};
1067 c.add_member(std::move(m));
1068 }
1069 }
1070 }
1071 }
1072
1073 if (cls->isCompleteDefinition())
1074 for (const auto *friend_declaration : cls->friends()) {
1075 if (friend_declaration != nullptr)
1076 process_friend(*friend_declaration, c);
1077 }
1078}

◆ 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 return from create_class_declaration

Definition at line 943 of file translation_unit_visitor.cc.

945{
946 // Process class child entities
947 process_class_children(&cls, c);
948
949 // Process class bases
950 process_class_bases(&cls, c);
951
952 c.complete(true);
953}

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

616{
617
618 if (const auto *cpt = concept_specialization->getNamedConcept();
619 should_include(cpt)) {
620
621 const auto cpt_name = cpt->getNameAsString();
622 const eid_t ast_id{cpt->getID()};
623 const auto maybe_id = id_mapper().get_global_id(ast_id);
624 if (!maybe_id)
625 return;
626
627 const auto target_id = maybe_id.value();
628
629 std::vector<std::string> constrained_template_params;
630
631 size_t argument_index{};
632
633 for (const auto ta : concept_specialization->getTemplateArguments()) {
634 if (ta.getKind() == clang::TemplateArgument::Type) {
635 auto type_name =
636 common::to_string(ta.getAsType(), cpt->getASTContext());
637 extract_constrained_template_param_name(concept_specialization,
638 cpt, constrained_template_params, argument_index,
639 type_name);
640 }
641 else if (ta.getKind() == clang::TemplateArgument::Pack) {
642 if (!ta.getPackAsArray().empty() &&
643 ta.getPackAsArray().front().isPackExpansion()) {
644 const auto &pack_head =
645 ta.getPackAsArray().front().getAsType();
646 auto type_name =
647 common::to_string(pack_head, cpt->getASTContext());
649 concept_specialization, cpt,
650 constrained_template_params, argument_index, type_name);
651 }
652 }
653 else {
654 auto type_name =
655 common::to_string(ta.getAsType(), cpt->getASTContext());
656 LOG_DBG(
657 "=== Unsupported concept type parameter: {}", type_name);
658 }
659 argument_index++;
660 }
661
662 if (!constrained_template_params.empty())
663 c.add_relationship(
664 {relationship_t::kConstraint, target_id, access_t::kNone,
665 fmt::format(
666 "{}", fmt::join(constrained_template_params, ","))});
667 }
668}

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

444{
445 if (const auto *constraint = llvm::dyn_cast<clang::RequiresExpr>(expr);
446 constraint) {
447
448 auto constraint_source = common::to_string(constraint);
449
450 LOG_DBG("== Processing constraint: '{}'", constraint_source);
451
452 for ([[maybe_unused]] const auto *requirement :
453 constraint->getRequirements()) {
454 // TODO
455 }
456
457 // process 'requires (...)' declaration
458 for (const auto *decl : constraint->getBody()->decls()) {
459 if (const auto *parm_var_decl =
460 llvm::dyn_cast<clang::ParmVarDecl>(decl);
461 parm_var_decl) {
462 parm_var_decl->getQualifiedNameAsString();
463
464 auto param_name = parm_var_decl->getNameAsString();
465 auto param_type = common::to_string(
466 parm_var_decl->getType(), cpt->getASTContext());
467
468 LOG_DBG("=== Processing parameter variable declaration: {}, {}",
469 param_type, param_name);
470
471 concept_model.add_parameter(
472 {std::move(param_type), std::move(param_name)});
473 }
474 else {
475 LOG_DBG("=== Processing some other concept declaration: {}",
476 decl->getID());
477 }
478 }
479
480 // process concept body requirements '{ }' if any
481 for (const auto *req : constraint->getRequirements()) {
482 if (req->getKind() == clang::concepts::Requirement::RK_Simple) {
483 const auto *simple_req =
484 llvm::dyn_cast<clang::concepts::ExprRequirement>(req);
485
486 if (simple_req != nullptr) {
488 simple_req->getExpr(), [&concept_model](const auto *e) {
489 auto simple_expr = common::to_string(e);
490
491 LOG_DBG("=== Processing expression requirement: {}",
492 simple_expr);
493
494 concept_model.add_statement(std::move(simple_expr));
495 });
496 }
497 }
498 else if (req->getKind() == clang::concepts::Requirement::RK_Type) {
500 llvm::dyn_cast<clang::concepts::TypeRequirement>(req),
501 [&concept_model, cpt](const auto *t) {
502 auto type_name = common::to_string(
503 t->getType()->getType(), cpt->getASTContext());
504
505 LOG_DBG(
506 "=== Processing type requirement: {}", type_name);
507
508 concept_model.add_statement(std::move(type_name));
509 });
510 }
511 else if (req->getKind() ==
512 clang::concepts::Requirement::RK_Nested) {
513 const auto *nested_req =
514 llvm::dyn_cast<clang::concepts::NestedRequirement>(req);
515
516 if (nested_req != nullptr) {
518 nested_req->getConstraintExpr(), [](const auto *e) {
519 LOG_DBG("=== Processing nested requirement: {}",
520 common::to_string(e));
521 });
522 }
523 }
524 else if (req->getKind() ==
525 clang::concepts::Requirement::RK_Compound) {
526 const auto *compound_req =
527 llvm::dyn_cast<clang::concepts::ExprRequirement>(req);
528
529 if (compound_req != nullptr) {
530 const auto *compound_expr_ptr = compound_req->getExpr();
531
532 if (compound_expr_ptr != nullptr) {
533 auto compound_expr =
534 common::to_string(compound_expr_ptr);
535
536 auto req_return_type =
537 compound_req->getReturnTypeRequirement();
538
539 if (!req_return_type.isEmpty()) {
540 compound_expr =
541 fmt::format("{{{}}} -> {}", compound_expr,
543 req_return_type.getTypeConstraint()));
544 }
545 else if (compound_req->hasNoexceptRequirement()) {
546 compound_expr =
547 fmt::format("{{{}}} noexcept", compound_expr);
548 }
549
550 LOG_DBG("=== Processing compound requirement: {}",
551 compound_expr);
552
553 concept_model.add_statement(std::move(compound_expr));
554 }
555 }
556 }
557 }
558 }
559 else if (const auto *binop = llvm::dyn_cast<clang::BinaryOperator>(expr);
560 binop) {
561 process_constraint_requirements(cpt, binop->getLHS(), concept_model);
562 process_constraint_requirements(cpt, binop->getRHS(), concept_model);
563 }
564 else if (const auto *unop = llvm::dyn_cast<clang::UnaryOperator>(expr);
565 unop) {
566 process_constraint_requirements(cpt, unop->getSubExpr(), concept_model);
567 }
568}

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

1699{
1700 LOG_DBG(
1701 "== Visiting record member {}", field_declaration.getNameAsString());
1702
1703 // Default hint for relationship is aggregation
1704 auto relationship_hint = relationship_t::kAggregation;
1705 // If the first type of the template instantiation of this field type
1706 // has been added as aggregation relationship with class 'c', don't
1707 // add it's nested template types as aggregation
1708 [[maybe_unused]] bool template_instantiation_added_as_aggregation{false};
1709 // The actual field type
1710 auto field_type = field_declaration.getType();
1711 // String representation of the field type
1712 auto type_name =
1713 common::to_string(field_type, field_declaration.getASTContext());
1714 // The field name
1715 const auto field_name = field_declaration.getNameAsString();
1716
1717 auto field_type_str =
1718 common::to_string(field_type, field_declaration.getASTContext(), false);
1719
1721
1722 class_member field{
1723 common::access_specifier_to_access_t(field_declaration.getAccess()),
1724 field_name, config().simplify_template_type(field_type_str)};
1725
1726 // Parse the field comment
1727 process_comment(field_declaration, field);
1728 // Register the source location of the field declaration
1729 set_source_location(field_declaration, field);
1730
1731 // If the comment contains a skip directive, just return
1732 if (field.skip())
1733 return;
1734
1735 if (field_type->isPointerType()) {
1736 relationship_hint = relationship_t::kAssociation;
1737 field_type = field_type->getPointeeType();
1738 }
1739 else if (field_type->isLValueReferenceType()) {
1740 relationship_hint = relationship_t::kAssociation;
1741 field_type = field_type.getNonReferenceType();
1742 }
1743 else if (field_type->isArrayType()) {
1744 relationship_hint = relationship_t::kAggregation;
1745 while (field_type->isArrayType()) {
1746 auto current_multiplicity = field.destination_multiplicity();
1747 if (!current_multiplicity)
1748 field.set_destination_multiplicity(common::get_array_size(
1749 *field_type->getAsArrayTypeUnsafe()));
1750 else {
1751 auto maybe_array_size =
1752 common::get_array_size(*field_type->getAsArrayTypeUnsafe());
1753 if (maybe_array_size.has_value()) {
1754 field.set_destination_multiplicity(
1755 current_multiplicity.value() *
1756 maybe_array_size.value());
1757 }
1758 }
1759
1760 field_type = field_type->getAsArrayTypeUnsafe()->getElementType();
1761 }
1762 }
1763 else if (field_type->isRValueReferenceType()) {
1764 field_type = field_type.getNonReferenceType();
1765 }
1766
1767 if (type_name.find("std::shared_ptr") == 0)
1768 relationship_hint = relationship_t::kAssociation;
1769 if (type_name.find("std::weak_ptr") == 0)
1770 relationship_hint = relationship_t::kAssociation;
1771
1772 found_relationships_t relationships;
1773
1774 const auto *template_field_type =
1775 field_type->getAs<clang::TemplateSpecializationType>();
1776 // TODO: Refactor to an unalias_type() method
1777 if (template_field_type != nullptr)
1778 if (template_field_type->isTypeAlias())
1779 template_field_type =
1780 template_field_type->getAliasedType()
1781 ->getAs<clang::TemplateSpecializationType>();
1782
1783 bool field_type_is_template_template_parameter{false};
1784 if (template_field_type != nullptr) {
1785 // Skip types which are template template parameters of the parent
1786 // template
1787 for (const auto &class_template_param : c.template_params()) {
1788 if (class_template_param.name() ==
1789 template_field_type->getTemplateName()
1790 .getAsTemplateDecl()
1791 ->getNameAsString() +
1792 "<>") {
1793 field_type_is_template_template_parameter = true;
1794 }
1795 }
1796 }
1797
1798 // Process the type which is template instantiation of some sort
1799 if (template_field_type != nullptr &&
1800 !field_type_is_template_template_parameter) {
1801 // Build the template instantiation for the field type
1802 auto template_specialization_ptr =
1803 std::make_unique<class_>(config().using_namespace());
1805 *template_specialization_ptr,
1806 field_type->getAs<clang::TemplateSpecializationType>()
1807 ->getTemplateName()
1808 .getAsTemplateDecl(),
1809 *template_field_type, {&c});
1810
1811 if (!field.skip_relationship() && template_specialization_ptr) {
1812 const auto &template_specialization = *template_specialization_ptr;
1813
1814 // Check if this template instantiation should be added to the
1815 // current diagram. Even if the top level template type for
1816 // this instantiation should not be part of the diagram, e.g.
1817 // it's a std::vector<>, it's nested types might be added
1818 bool add_template_instantiation_to_diagram{false};
1819 if (diagram().should_include(
1820 template_specialization.get_namespace())) {
1821
1822 found_relationships_t::value_type r{
1823 template_specialization.id(), relationship_hint};
1824
1825 add_template_instantiation_to_diagram = true;
1826
1827 // If the template instantiation for the build type has been
1828 // added as aggregation, skip its nested templates
1829 template_instantiation_added_as_aggregation =
1830 relationship_hint == relationship_t::kAggregation;
1831 relationships.emplace_back(std::move(r));
1832 }
1833
1834 // Try to find relationships to types nested in the template
1835 // instantiation
1836 found_relationships_t nested_relationships;
1837 if (!template_instantiation_added_as_aggregation) {
1838 for (const auto &template_argument :
1839 template_specialization.template_params()) {
1840
1841 LOG_DBG("Looking for nested relationships from {}::{} in "
1842 "template argument {}",
1843 c.full_name(false), field_name,
1844 template_argument.to_string(
1845 config().using_namespace(), false));
1846
1847 template_instantiation_added_as_aggregation =
1848 template_argument.find_nested_relationships(
1849 nested_relationships, relationship_hint,
1850 [&d = diagram()](const std::string &full_name) {
1851 if (full_name.empty())
1852 return false;
1853 auto [ns, name] = common::split_ns(full_name);
1854 return d.should_include(ns, name);
1855 });
1856 }
1857
1858 // Add any relationships to the class 'c' to the diagram,
1859 // unless the top level type has been added as aggregation
1860 add_relationships(c, field, nested_relationships,
1861 /* break on first aggregation */ false);
1862 }
1863
1864 // Add the template instantiation object to the diagram if it
1865 // matches the include pattern
1866 if (add_template_instantiation_to_diagram)
1867 add_class(std::move(template_specialization_ptr));
1868 }
1869 }
1870
1871 if (!field.skip_relationship()) {
1872 // Find relationship for the type if the type has not been added
1873 // as aggregation
1874 if (!template_instantiation_added_as_aggregation) {
1875 if ((field_type->getAsRecordDecl() != nullptr) &&
1876 field_type->getAsRecordDecl()->getNameAsString().empty()) {
1877 // Relationships to fields whose type is an anonymous nested
1878 // struct have to be handled separately here
1879 anonymous_struct_relationships_[field_type->getAsRecordDecl()
1880 ->getID()] =
1881 std::make_tuple(field.name(), relationship_hint,
1882 field.access(), field.destination_multiplicity());
1883 }
1884 else
1886 field_type, relationships, relationship_hint);
1887 }
1888
1889 add_relationships(c, field, relationships);
1890 }
1891
1892 // If this is an anonymous struct - replace the anonymous_XYZ part with
1893 // field name
1894 if ((field_type->getAsRecordDecl() != nullptr) &&
1895 field_type->getAsRecordDecl()->getNameAsString().empty()) {
1896 if (util::contains(field.type(), "(anonymous_")) {
1897 std::regex anonymous_re("anonymous_(\\d*)");
1898 field.set_type(
1899 std::regex_replace(field.type(), anonymous_re, field_name));
1900 }
1901 }
1902
1903 c.add_member(std::move(field));
1904}

◆ process_friend()

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

Process class friend.

Parameters
fFriend declaration
cClass diagram element model

Definition at line 1080 of file translation_unit_visitor.cc.

1082{
1083 if (const auto *friend_type_info = f.getFriendType()) {
1084 const auto friend_type = friend_type_info->getType();
1085 if (friend_type->getAs<clang::TemplateSpecializationType>() !=
1086 nullptr) {
1087 // TODO: handle template friend
1088 }
1089 else if (friend_type->getAs<clang::RecordType>() != nullptr) {
1090 if (should_include(friend_type->getAsRecordDecl())) {
1091 relationship r{relationship_t::kFriendship,
1092 common::to_id(*friend_type->getAsRecordDecl()),
1094 "<<friend>>"};
1095
1096 c.add_relationship(std::move(r));
1097 }
1098 }
1099 }
1100}

◆ process_function_parameter()

void clanguml::class_diagram::visitor::translation_unit_visitor::process_function_parameter ( const clang::ParmVarDecl &  param,
clanguml::class_diagram::model::class_method method,
clanguml::class_diagram::model::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 1502 of file translation_unit_visitor.cc.

1505{
1506 method_parameter parameter;
1507 parameter.set_name(p.getNameAsString());
1508
1509 process_comment(p, parameter);
1510
1511 if (parameter.skip())
1512 return;
1513
1514 auto parameter_type = common::to_string(p.getType(), p.getASTContext());
1515
1516 // Is there no better way to determine that 'type' is a lambda?
1518
1519 parameter.set_type(parameter_type);
1520
1521 if (p.hasDefaultArg()) {
1522 const auto *default_arg = p.getDefaultArg();
1523 if (default_arg != nullptr) {
1524 auto default_arg_str = common::get_source_text(
1525 default_arg->getSourceRange(), source_manager());
1526 parameter.set_default_value(default_arg_str);
1527 }
1528 }
1529
1530 if (!parameter.skip_relationship()) {
1531 // find relationship for the type
1532 found_relationships_t relationships;
1533
1534 LOG_DBG("Looking for relationships in type: {}",
1535 common::to_string(p.getType(), p.getASTContext()));
1536
1537 if (const auto *templ =
1538 p.getType()
1539 .getNonReferenceType()
1540 .getUnqualifiedType()
1541 ->getAs<clang::TemplateSpecializationType>();
1542 templ != nullptr) {
1543 auto template_specialization_ptr =
1544 std::make_unique<class_>(config().using_namespace());
1546 *template_specialization_ptr,
1547 templ->getTemplateName().getAsTemplateDecl(), *templ, &c);
1548
1549 if (diagram().should_include(*template_specialization_ptr)) {
1550 relationships.emplace_back(template_specialization_ptr->id(),
1551 relationship_t::kDependency);
1552
1553 add_class(std::move(template_specialization_ptr));
1554 }
1555 }
1556
1558 p.getType(), relationships, relationship_t::kDependency);
1559
1560 for (const auto &[type_element_id, relationship_type] : relationships) {
1561 if (type_element_id != c.id() &&
1562 (relationship_type != relationship_t::kNone)) {
1563 relationship r{relationship_t::kDependency, type_element_id};
1564
1565 LOG_DBG("Adding function parameter relationship from {} to "
1566 "{}: {}",
1568 r.label());
1569
1570 c.add_relationship(std::move(r));
1571 }
1572 }
1573 }
1574
1575 method.add_parameter(std::move(parameter));
1576}

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

1244{
1245 auto desugared_atsp = atsp->getDeducedType();
1246
1247 if (atsp->isSugared()) {
1248 const auto *deduced_type =
1249 atsp->desugar()->getAs<clang::DeducedTemplateSpecializationType>();
1250
1251 if (deduced_type != nullptr)
1252 desugared_atsp = deduced_type->getDeducedType();
1253 }
1254
1255 if (desugared_atsp.isNull())
1256 return;
1257
1258 const auto *deduced_record_type = desugared_atsp->isRecordType()
1259 ? desugared_atsp->getAs<clang::RecordType>()
1260 : nullptr;
1261
1262 if (deduced_record_type != nullptr) {
1263 if (auto *deduced_auto_decl =
1264 llvm::dyn_cast_or_null<clang::ClassTemplateSpecializationDecl>(
1265 deduced_record_type->getDecl());
1266 deduced_auto_decl != nullptr) {
1267
1268 const auto diagram_class_count_before_visit =
1269 diagram().classes().size();
1270
1271 VisitClassTemplateSpecializationDecl(deduced_auto_decl);
1272
1273 const bool visitor_added_new_template_specialization =
1274 (diagram().classes().size() -
1275 diagram_class_count_before_visit) > 0;
1276
1277 if (visitor_added_new_template_specialization) {
1278 const auto &template_specialization_model =
1279 diagram().classes().back();
1280
1281 if (should_include(deduced_auto_decl)) {
1282 relationship r{relationship_t::kDependency,
1283 template_specialization_model.get().id()};
1284
1285 c.add_relationship(std::move(r));
1286 }
1287 }
1288 }
1289 }
1290}

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

1104{
1105 // TODO: For now skip implicitly default methods
1106 // in the future, add config option to choose
1107 if (mf.isDefaulted() && !mf.isExplicitlyDefaulted())
1108 return;
1109
1110 auto method_return_type =
1111 common::to_string(mf.getReturnType(), mf.getASTContext());
1112
1113 common::ensure_lambda_type_is_relative(config(), method_return_type);
1114
1115 auto method_name = mf.getNameAsString();
1116 if (mf.isTemplated()) {
1117 // Sometimes in template specializations method names contain the
1118 // template parameters for some reason - drop them
1119 // Is there a better way to do this?
1120 method_name = method_name.substr(0, method_name.find('<'));
1121 }
1122
1123 class_method method{common::access_specifier_to_access_t(mf.getAccess()),
1124 util::trim(method_name),
1125 config().simplify_template_type(method_return_type)};
1126
1127 process_method_properties(mf, c, method_name, method);
1128
1129 process_comment(mf, method);
1130
1131 // Register the source location of the field declaration
1132 set_source_location(mf, method);
1133
1134 if (method.skip())
1135 return;
1136
1137 for (const auto *param : mf.parameters()) {
1138 if (param != nullptr)
1139 process_function_parameter(*param, method, c);
1140 }
1141
1142 // find relationship for return type
1143 found_relationships_t relationships;
1144
1145 // Move dereferencing to build() method of template_builder
1146 if (const auto *templ = mf.getReturnType()
1147 .getNonReferenceType()
1148 .getUnqualifiedType()
1149 ->getAs<clang::TemplateSpecializationType>();
1150 templ != nullptr) {
1151 const auto *unaliased_type = templ;
1152 if (unaliased_type->isTypeAlias())
1153 unaliased_type = unaliased_type->getAliasedType()
1154 ->getAs<clang::TemplateSpecializationType>();
1155
1156 if (unaliased_type != nullptr) {
1157 auto template_specialization_ptr =
1158 std::make_unique<class_>(config().using_namespace());
1160 *template_specialization_ptr,
1161 unaliased_type->getTemplateName().getAsTemplateDecl(),
1162 *unaliased_type, &c);
1163
1164 if (diagram().should_include(*template_specialization_ptr)) {
1165 relationships.emplace_back(template_specialization_ptr->id(),
1166 relationship_t::kDependency);
1167
1168 add_class(std::move(template_specialization_ptr));
1169 }
1170 }
1171 }
1172
1174 mf.getReturnType(), relationships, relationship_t::kDependency);
1175
1176 for (const auto &[type_element_id, relationship_type] : relationships) {
1177 if (type_element_id != c.id() &&
1178 (relationship_type != relationship_t::kNone)) {
1179 relationship r{relationship_t::kDependency, type_element_id};
1180
1181 LOG_DBG("Adding method return type relationship from {}::{} to "
1182 "{}: {}",
1183 c.full_name(), mf.getNameAsString(),
1184 clanguml::common::model::to_string(r.type()), r.label());
1185
1186 c.add_relationship(std::move(r));
1187 }
1188 }
1189
1190 // Also consider the container itself if it is a template
1191 // instantiation it's arguments could count as reference to relevant
1192 // types
1193 auto underlying_type = mf.getReturnType();
1194 if (underlying_type->isReferenceType())
1195 underlying_type = underlying_type.getNonReferenceType();
1196 if (underlying_type->isPointerType())
1197 underlying_type = underlying_type->getPointeeType();
1198
1199 if (const auto *atsp = underlying_type->getAs<clang::AutoType>();
1200 atsp != nullptr) {
1202 }
1203
1204 method.update(config().using_namespace());
1205
1206 if (diagram().should_include(method)) {
1207 LOG_DBG("Adding method: {}", method.name());
1208
1209 c.add_method(std::move(method));
1210 }
1211}

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

1216{
1217 const bool is_constructor = c.name() == method_name;
1218 const bool is_destructor = fmt::format("~{}", c.name()) == method_name;
1219
1220#if LLVM_VERSION_MAJOR > 17
1221 method.is_pure_virtual(mf.isPureVirtual());
1222#else
1223 method.is_pure_virtual(mf.isPure());
1224#endif
1225 method.is_virtual(mf.isVirtual());
1226 method.is_const(mf.isConst());
1227 method.is_defaulted(mf.isDefaulted());
1228 method.is_deleted(mf.isDeleted());
1229 method.is_static(mf.isStatic());
1230 method.is_operator(mf.isOverloadedOperator());
1231 method.is_constexpr(mf.isConstexprSpecified() && !is_constructor);
1232 method.is_consteval(mf.isConsteval());
1233 method.is_constructor(is_constructor);
1234 method.is_destructor(is_destructor);
1235 method.is_move_assignment(mf.isMoveAssignmentOperator());
1236 method.is_copy_assignment(mf.isCopyAssignmentOperator());
1237 method.is_noexcept(isNoexceptExceptionSpec(mf.getExceptionSpecType()));
1238 method.is_coroutine(common::is_coroutine(mf));
1239}

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

1004{
1005 // Iterate over regular class fields
1006 for (const auto *field : cls->fields()) {
1007 if (field != nullptr)
1008 process_field(*field, c);
1009 }
1010}

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

863{
864 const auto *parent = cls->getParent();
865
866 std::optional<eid_t> id_opt;
867
868 auto parent_ns = ns;
869 if (parent != nullptr) {
870 const auto *parent_record_decl =
871 clang::dyn_cast<clang::RecordDecl>(parent);
872
873 if (parent_record_decl != nullptr) {
874 parent_ns = common::get_tag_namespace(*parent_record_decl);
875
876 eid_t ast_id{parent_record_decl->getID()};
877
878 // First check if the parent has been added to the diagram as
879 // regular class
880 id_opt = id_mapper().get_global_id(ast_id);
881
882 // If not, check if the parent template declaration is in the
883 // model
884 if (!id_opt) {
885 if (parent_record_decl->getDescribedTemplate() != nullptr) {
886 ast_id =
887 parent_record_decl->getDescribedTemplate()->getID();
888 id_opt = id_mapper().get_global_id(ast_id);
889 }
890 }
891 }
892 }
893
894 if (id_opt && diagram().find<class_>(*id_opt)) {
895 // Here we have 2 options, either:
896 // - the parent is a regular C++ class/struct
897 // - the parent is a class template declaration/specialization
898 auto parent_class = diagram().find<class_>(*id_opt);
899
900 c.set_namespace(parent_ns);
901 const auto cls_name = cls->getNameAsString();
902 if (cls_name.empty()) {
903 // Nested structs can be anonymous
904 if (anonymous_struct_relationships_.count(cls->getID()) > 0) {
905 const auto &[label, hint, access, destination_multiplicity] =
907
908 c.set_name(parent_class.value().name() + "##" +
909 fmt::format("({})", label));
910
911 std::string destination_multiplicity_str{};
912 if (destination_multiplicity.has_value()) {
913 destination_multiplicity_str =
914 std::to_string(*destination_multiplicity);
915 }
916
917 parent_class.value().add_relationship(
918 {hint, common::to_id(c.full_name(false)), access, label, "",
919 destination_multiplicity_str});
920 }
921 else
922 c.set_name(parent_class.value().name() + "##" +
923 fmt::format(
924 "(anonymous_{})", std::to_string(cls->getID())));
925 }
926 else {
927 c.set_name(
928 parent_class.value().name() + "##" + cls->getNameAsString());
929 }
930
931 c.set_id(common::to_id(c.full_name(false)));
932
933 if (!cls->getNameAsString().empty()) {
934 // Don't add anonymous structs as contained in the class
935 // as they are already added as aggregations
936 c.add_relationship({relationship_t::kContainment, *id_opt});
937 }
938
939 c.nested(true);
940 }
941}

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

1622{
1623 const auto field_type = field_declaration.getType();
1624 auto type_name =
1625 common::to_string(field_type, field_declaration.getASTContext());
1626 if (type_name.empty())
1627 type_name = "<<anonymous>>";
1628
1629 class_member field{
1630 common::access_specifier_to_access_t(field_declaration.getAccess()),
1631 field_declaration.getNameAsString(),
1632 config().simplify_template_type(type_name)};
1633
1634 field.is_static(true);
1635
1636 process_comment(field_declaration, field);
1637 set_source_location(field_declaration, field);
1638
1639 if (field.skip())
1640 return;
1641
1642 if (!field.skip_relationship()) {
1643 found_relationships_t relationships;
1644
1645 // find relationship for the type
1646 find_relationships(field_declaration.getType(), relationships,
1647 relationship_t::kAssociation);
1648
1649 add_relationships(c, field, relationships);
1650 }
1651
1652 c.add_member(std::move(field));
1653}

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

1294{
1295 // TODO: For now skip implicitly default methods
1296 // in the future, add config option to choose
1297 if (mf.getTemplatedDecl()->isDefaulted() &&
1298 !mf.getTemplatedDecl()->isExplicitlyDefaulted())
1299 return;
1300
1301 class_method method{common::access_specifier_to_access_t(mf.getAccess()),
1302 util::trim(mf.getNameAsString()),
1303 mf.getTemplatedDecl()->getReturnType().getAsString()};
1304
1305 auto method_name = mf.getNameAsString();
1306 if (mf.isTemplated()) {
1307 // Sometimes in template specializations method names contain the
1308 // template parameters for some reason - drop them
1309 // Is there a better way to do this?
1310 method_name = method_name.substr(0, method_name.find('<'));
1311 }
1313 clang::dyn_cast<clang::CXXMethodDecl>(mf.getTemplatedDecl()),
1314 [&](const auto *decl) {
1315 process_method_properties(*decl, c, method_name, method);
1316 });
1317
1319
1320 process_comment(mf, method);
1321
1322 if (method.skip())
1323 return;
1324
1325 for (const auto *param : mf.getTemplatedDecl()->parameters()) {
1326 if (param != nullptr)
1327 process_function_parameter(*param, method, c);
1328 }
1329
1330 method.update(config().using_namespace());
1331
1332 if (diagram().should_include(method)) {
1333 LOG_DBG("Adding method: {}", method.name());
1334
1335 c.add_method(std::move(method));
1336 }
1337}

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

1658{
1659 auto c_ptr = std::make_unique<class_>(config().using_namespace());
1661
1662 auto &template_instantiation = *c_ptr;
1663 template_instantiation.is_template(true);
1664
1665 // TODO: refactor to method get_qualified_name()
1666 auto qualified_name = cls->getQualifiedNameAsString();
1667 util::replace_all(qualified_name, "(anonymous namespace)", "");
1668 util::replace_all(qualified_name, "::::", "::");
1669
1670 namespace_ ns{qualified_name};
1671 ns.pop_back();
1672 template_instantiation.set_name(cls->getNameAsString());
1673 template_instantiation.set_namespace(ns);
1674
1675 template_instantiation.is_struct(cls->isStruct());
1676
1677 process_record_parent(cls, template_instantiation, ns);
1678
1679 if (!template_instantiation.is_nested()) {
1680 template_instantiation.set_name(common::get_tag_name(*cls));
1681 template_instantiation.set_id(
1682 common::to_id(template_instantiation.full_name(false)));
1683 }
1684
1685 process_comment(*cls, template_instantiation);
1686 set_source_location(*cls, template_instantiation);
1687 set_owning_module(*cls, template_instantiation);
1688
1689 if (template_instantiation.skip())
1690 return {};
1691
1692 id_mapper().add(cls->getID(), template_instantiation.id());
1693
1694 return c_ptr;
1695}

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

1917{
1918 // TODO: Refactor to a map with relationships attached to references
1919 // to elements
1920 for (const auto &cls : diagram().classes()) {
1921 for (auto &rel : cls.get().relationships()) {
1922 if (!rel.destination().is_global()) {
1923 const auto maybe_id =
1924 id_mapper().get_global_id(rel.destination());
1925 if (maybe_id) {
1926 LOG_DBG("= Resolved instantiation destination from local "
1927 "id {} to global id {}",
1928 rel.destination(), *maybe_id);
1929 rel.set_destination(*maybe_id);
1930 }
1931 }
1932 }
1933 }
1934 for (const auto &cpt : diagram().concepts()) {
1935 for (auto &rel : cpt.get().relationships()) {
1936 if (!rel.destination().is_global()) {
1937 const auto maybe_id =
1938 id_mapper().get_global_id(rel.destination());
1939 if (maybe_id) {
1940 LOG_DBG("= Resolved instantiation destination from local "
1941 "id {} to global id {}",
1942 rel.destination(), *maybe_id);
1943 rel.set_destination(*maybe_id);
1944 }
1945 }
1946 }
1947 }
1948 for (const auto &enm : diagram().enums()) {
1949 for (auto &rel : enm.get().relationships()) {
1950 if (!rel.destination().is_global()) {
1951 const auto maybe_id =
1952 id_mapper().get_global_id(rel.destination());
1953 if (maybe_id) {
1954 LOG_DBG("= Resolved instantiation destination from local "
1955 "id {} to global id {}",
1956 rel.destination(), *maybe_id);
1957 rel.set_destination(*maybe_id);
1958 }
1959 }
1960 }
1961 }
1962}

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

432{ 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 443 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 437 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 452 of file translation_unit_visitor.h.

◆ template_builder_

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

Definition at line 434 of file translation_unit_visitor.h.


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