0.6.0
C++ to UML diagram generator based on Clang
Loading...
Searching...
No Matches
Public Member Functions | Private Attributes | List of all members
clanguml::common::visitor::template_builder< VisitorT > Class Template Reference

Class responsible for building all kinds of templates from Clang AST. More...

Detailed Description

template<typename VisitorT>
class clanguml::common::visitor::template_builder< VisitorT >

Class responsible for building all kinds of templates from Clang AST.

Definition at line 49 of file template_builder.h.

#include <template_builder.h>

Public Member Functions

 template_builder (clanguml::common::model::diagram &diagram_, const clanguml::config::diagram &config_, VisitorT &visitor)
 Constructor.
 
common::model::diagramdiagram ()
 Get reference to the current diagram model.
 
const config::diagramconfig () const
 Get reference to the current diagram configuration.
 
const namespace_ & using_namespace () const
 Get diagram relative namespace.
 
bool simplify_system_template (template_parameter &ct, const std::string &full_name) const
 Simplify system templates.
 
void build_from_template_declaration (clanguml::common::model::template_trait &template_model, const clang::TemplateDecl &template_declaration, common::optional_ref< common::model::element > templated_element={})
 
void build_from_template_specialization_type (clanguml::common::model::template_element &template_instantiation, const clang::NamedDecl *cls, const clang::TemplateSpecializationType &template_type_decl, std::optional< clanguml::common::model::template_element * > parent={})
 Basic template class build method.
 
void build (clanguml::common::model::template_element &template_instantiation, const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl, clang::ArrayRef< clang::TemplateArgument > template_arguments, std::string full_template_specialization_name, std::optional< clanguml::common::model::template_element * > parent={})
 
void build_from_class_template_specialization (clanguml::common::model::template_element &template_instantiation, const clang::ClassTemplateSpecializationDecl &template_specialization, std::optional< clanguml::common::model::template_element * > parent={})
 Build template class from class template specialization decl.
 
bool add_base_classes (clanguml::common::model::template_element &tinst, std::deque< std::tuple< std::string, int, bool > > &template_base_params, int arg_index, bool variadic_params, const clanguml::common::model::template_parameter &ct)
 Add base classes to the template class, if any.
 
void process_template_arguments (std::optional< clanguml::common::model::template_element * > &parent, const clang::NamedDecl *cls, std::deque< std::tuple< std::string, int, bool > > &template_base_params, const clang::ArrayRef< clang::TemplateArgument > &template_args, clanguml::common::model::template_element &template_instantiation, const clang::TemplateDecl *template_decl)
 Process template class parameters and arguments.
 
void argument_process_dispatch (std::optional< clanguml::common::model::template_element * > &parent, const clang::NamedDecl *cls, clanguml::common::model::template_element &template_instantiation, const clang::TemplateDecl *template_decl, const clang::TemplateArgument &arg, size_t argument_index, std::vector< template_parameter > &argument)
 Process template arguments based on their type.
 
template_parameter process_expression_argument (const clang::TemplateArgument &arg)
 Process clang::TemplateArgument::Expression
 
template_parameter process_integral_argument (const clang::TemplateArgument &arg, const clang::ASTContext &ast_context)
 Process clang::TemplateArgument::Integral
 
template_parameter process_nullptr_argument (const clang::TemplateArgument &arg)
 Process clang::TemplateArgument::NullPtr
 
template_parameter process_null_argument (const clang::TemplateArgument &arg)
 Process clang::TemplateArgument::Null
 
std::vector< template_parameterprocess_pack_argument (std::optional< clanguml::common::model::template_element * > &parent, const clang::NamedDecl *cls, clanguml::common::model::template_element &template_instantiation, const clang::TemplateDecl *base_template_decl, const clang::TemplateArgument &arg, size_t argument_index, std::vector< template_parameter > &argument)
 Process clang::TemplateArgument::Pack
 
template_parameter process_type_argument (std::optional< clanguml::common::model::template_element * > &parent, const clang::NamedDecl *cls, const clang::TemplateDecl *base_template_decl, clang::QualType type, clanguml::common::model::template_element &template_instantiation, size_t argument_index)
 Process clang::TemplateArgument::Type
 
common::model::template_parameter process_template_argument (const clang::TemplateArgument &arg)
 Process clang::TemplateArgument::Template
 
common::model::template_parameter process_template_expansion (const clang::TemplateArgument &arg)
 Process clang::TemplateArgument::TemplateExpansion
 
std::optional< template_parametertry_as_function_prototype (std::optional< clanguml::common::model::template_element * > &parent, const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl, clang::QualType &type, clanguml::common::model::template_element &template_instantiation, size_t argument_index)
 Try to process template type argument as function template.
 
std::optional< template_parametertry_as_array (std::optional< clanguml::common::model::template_element * > &parent, const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl, clang::QualType &type, clanguml::common::model::template_element &template_instantiation, size_t argument_index)
 Try to process template type argument as array.
 
std::optional< template_parametertry_as_template_specialization_type (std::optional< clanguml::common::model::template_element * > &parent, const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl, clang::QualType &type, clanguml::common::model::template_element &template_instantiation, size_t argument_index)
 Try to process template type argument as specialization type.
 
std::optional< template_parametertry_as_template_parm_type (const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl, clang::QualType &type)
 Try to process template type argument as template parameter.
 
std::optional< template_parametertry_as_lambda (const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl, clang::QualType &type)
 Try to process template type argument as lambda.
 
std::optional< template_parametertry_as_record_type (std::optional< clanguml::common::model::template_element * > &parent, const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl, clang::QualType &type, clanguml::common::model::template_element &template_instantiation, size_t argument_index)
 Try to process template type argument as record type.
 
std::optional< template_parametertry_as_enum_type (std::optional< clanguml::common::model::template_element * > &parent, const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl, clang::QualType &type, clanguml::common::model::template_element &template_instantiation)
 Try to process template type argument as enum type.
 
std::optional< template_parametertry_as_builtin_type (std::optional< clanguml::common::model::template_element * > &parent, clang::QualType &type, const clang::TemplateDecl *template_decl)
 Try to process template type argument as builtin type.
 
std::optional< template_parametertry_as_member_pointer (std::optional< clanguml::common::model::template_element * > &parent, const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl, clang::QualType &type, clanguml::common::model::template_element &template_instantiation, size_t argument_index)
 Try to process template type argument as member pointer type.
 
std::optional< template_parametertry_as_decl_type (std::optional< clanguml::common::model::template_element * > &parent, const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl, clang::QualType &type, clanguml::common::model::template_element &template_instantiation, size_t argument_index)
 Try to process template type argument as decltype() type.
 
std::optional< template_parametertry_as_typedef_type (std::optional< clanguml::common::model::template_element * > &parent, const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl, clang::QualType &type, clanguml::common::model::template_element &template_instantiation, size_t argument_index)
 Try to process template type argument as typedef/using type.
 
clang::QualType consume_context (clang::QualType type, template_parameter &tp) const
 Remove types context (e.g. const or reference qualifiers)
 
bool find_relationships_in_unexposed_template_params (const template_parameter &ct, found_relationships_t &relationships)
 Try to find additional relationships in unexposed parameters.
 
void find_instantiation_relationships (common::model::template_element &template_instantiation, eid_t id, const std::string &qualified_name) const
 
common::visitor::ast_id_mapperid_mapper ()
 Get reference to Clang AST to clang-uml id mapper.
 
clang::SourceManager & source_manager () const
 Get reference to the current source manager.
 

Private Attributes

clanguml::common::model::diagramdiagram_
 
const clanguml::config::diagramconfig_
 
common::visitor::ast_id_mapperid_mapper_
 
clang::SourceManager & source_manager_
 
VisitorT & visitor_
 

Constructor & Destructor Documentation

◆ template_builder()

template<typename VisitorT >
clanguml::common::visitor::template_builder< VisitorT >::template_builder ( clanguml::common::model::diagram diagram_,
const clanguml::config::diagram config_,
VisitorT &  visitor 
)

Constructor.

Parameters
visitorReference to class diagram translation_unit_visitor

Definition at line 558 of file template_builder.h.

563 , id_mapper_{visitor.id_mapper()}
564 , source_manager_{visitor.source_manager()}
565 , visitor_{visitor}
566{
567}

Member Function Documentation

◆ add_base_classes()

template<typename VisitorT >
bool clanguml::common::visitor::template_builder< VisitorT >::add_base_classes ( clanguml::common::model::template_element tinst,
std::deque< std::tuple< std::string, int, bool > > &  template_base_params,
int  arg_index,
bool  variadic_params,
const clanguml::common::model::template_parameter ct 
)

Add base classes to the template class, if any.

This method adds base classes to a template declaration or specialization, including inferring whether variadic template parameter bases.

Parameters
tinstClass template model
template_base_paramsList of base class template parameters
arg_indexIndex of the template argument used for base class
variadic_paramsWhether the parameter is variadic
ctTemplate parameter model
Returns
True, if any base classes were added

Definition at line 1861 of file template_builder.h.

1865{
1866 bool add_template_argument_as_base_class = false;
1867
1868 if (variadic_params) {
1869 add_template_argument_as_base_class = true;
1870 }
1871 else {
1872 auto [arg_name, index, is_variadic] = template_base_params.front();
1873
1874 variadic_params = is_variadic;
1875 if ((arg_index == index) || (is_variadic && arg_index >= index)) {
1876 add_template_argument_as_base_class = true;
1877 if (!is_variadic) {
1878 // Don't remove the remaining variadic parameter
1879 template_base_params.pop_front();
1880 }
1881 }
1882 }
1883
1884 const auto maybe_id = ct.id();
1885 if (add_template_argument_as_base_class && maybe_id) {
1886 LOG_DBG("Adding template argument as base class '{}'",
1887 ct.to_string({}, false));
1888
1889 dynamic_cast<class_diagram::model::class_ &>(tinst).add_relationship(
1890 common::model::relationship{
1891 maybe_id.value(), common::model::access_t::kPublic, false});
1892 }
1893
1894 return variadic_params;
1895}

◆ argument_process_dispatch()

template<typename VisitorT >
void clanguml::common::visitor::template_builder< VisitorT >::argument_process_dispatch ( std::optional< clanguml::common::model::template_element * > &  parent,
const clang::NamedDecl *  cls,
clanguml::common::model::template_element template_instantiation,
const clang::TemplateDecl *  template_decl,
const clang::TemplateArgument &  arg,
size_t  argument_index,
std::vector< template_parameter > &  argument 
)

Process template arguments based on their type.

Parameters
parentOptional class in which this template is contained
clsTemplate class specialization declaration
template_instantiationTemplate class model to add template args
template_declBase template declaration
argTemplate argument
argument_indexArgument index
argumentOutput list of arguments (can be more than one for variadic parameters)

Definition at line 1039 of file template_builder.h.

1046{
1047 LOG_DBG("Processing argument {} in template class: {}", argument_index,
1048 cls->getQualifiedNameAsString());
1049
1050 switch (arg.getKind()) {
1051 case clang::TemplateArgument::Null:
1052 argument.push_back(process_null_argument(arg));
1053 break;
1054 case clang::TemplateArgument::Template:
1055 argument.push_back(process_template_argument(arg));
1056 break;
1057 case clang::TemplateArgument::Type: {
1058 argument.push_back(process_type_argument(parent, cls, template_decl,
1059 arg.getAsType(), template_instantiation, argument_index));
1060 break;
1061 }
1062 case clang::TemplateArgument::Declaration:
1063 break;
1064 case clang::TemplateArgument::NullPtr:
1065 argument.push_back(process_nullptr_argument(arg));
1066 break;
1067 case clang::TemplateArgument::Integral:
1068 argument.push_back(
1069 process_integral_argument(arg, template_decl->getASTContext()));
1070 break;
1071 case clang::TemplateArgument::TemplateExpansion:
1072 argument.push_back(process_template_expansion(arg));
1073 break;
1074 case clang::TemplateArgument::Expression:
1075 argument.push_back(process_expression_argument(arg));
1076 break;
1077 case clang::TemplateArgument::Pack:
1078 for (auto &a :
1079 process_pack_argument(parent, cls, template_instantiation,
1080 template_decl, arg, argument_index, argument)) {
1081 argument.push_back(a);
1082 }
1083 break;
1084#if LLVM_VERSION_MAJOR > 17
1085 case clang::TemplateArgument::StructuralValue:
1086 break;
1087#endif
1088 }
1089}

◆ build()

template<typename VisitorT >
void clanguml::common::visitor::template_builder< VisitorT >::build ( clanguml::common::model::template_element template_instantiation,
const clang::NamedDecl *  cls,
const clang::TemplateDecl *  template_decl,
clang::ArrayRef< clang::TemplateArgument >  template_arguments,
std::string  full_template_specialization_name,
std::optional< clanguml::common::model::template_element * >  parent = {} 
)

Definition at line 768 of file template_builder.h.

774{
775 //
776 // Here we'll hold the template base class params to replace with the
777 // instantiated values
778 //
779 std::deque<std::tuple</*parameter name*/ std::string, /* position */ int,
780 /*is variadic */ bool>>
781 template_base_params{};
782
783 auto template_decl_qualified_name =
784 template_decl->getQualifiedNameAsString();
785
786 if (const auto *class_template_decl =
787 clang::dyn_cast<clang::ClassTemplateDecl>(template_decl);
788 (class_template_decl != nullptr) &&
789 (class_template_decl->getTemplatedDecl() != nullptr) &&
790 (class_template_decl->getTemplatedDecl()->getParent() != nullptr) &&
791 class_template_decl->getTemplatedDecl()->getParent()->isRecord()) {
792
793 namespace_ ns{
794 common::get_tag_namespace(*class_template_decl->getTemplatedDecl()
795 ->getParent()
796 ->getOuterLexicalRecordContext())};
797
798 std::string ns_str = ns.to_string();
799 std::string name = template_decl->getQualifiedNameAsString();
800 if (!ns_str.empty()) {
801 name = name.substr(ns_str.size() + 2);
802 }
803
804 util::replace_all(name, "::", "##");
805 template_instantiation.set_name(name);
806
807 template_instantiation.set_namespace(ns);
808 }
809 else {
810 namespace_ ns{template_decl_qualified_name};
811 ns.pop_back();
812 template_instantiation.set_name(template_decl->getNameAsString());
813 template_instantiation.set_namespace(ns);
814 }
815
816 // TODO: Refactor handling of base parameters to a separate method
817
818 // We need this to match any possible base classes coming from template
819 // arguments
820 std::vector<
821 std::pair</* parameter name */ std::string, /* is variadic */ bool>>
822 template_parameter_names{};
823
824 for (const auto *parameter : *template_decl->getTemplateParameters()) {
825 if (parameter->isTemplateParameter() &&
826 (parameter->isTemplateParameterPack() ||
827 parameter->isParameterPack())) {
828 template_parameter_names.emplace_back(
829 parameter->getNameAsString(), true);
830 }
831 else
832 template_parameter_names.emplace_back(
833 parameter->getNameAsString(), false);
834 }
835
836 // Check if the primary template has any base classes
837 int base_index = 0;
838
839 const auto *templated_class_decl =
840 clang::dyn_cast_or_null<clang::CXXRecordDecl>(
841 template_decl->getTemplatedDecl());
842
843 if ((templated_class_decl != nullptr) &&
844 templated_class_decl->hasDefinition())
845 for (const auto &base : templated_class_decl->bases()) {
846 const auto base_class_name = common::to_string(
847 base.getType(), templated_class_decl->getASTContext(), false);
848
849 LOG_DBG("Found template instantiation base: {}, {}",
850 base_class_name, base_index);
851
852 // Check if any of the primary template arguments has a
853 // parameter equal to this type
854 auto it = std::find_if(template_parameter_names.begin(),
855 template_parameter_names.end(),
856 [&base_class_name](
857 const auto &p) { return p.first == base_class_name; });
858
859 if (it != template_parameter_names.end()) {
860 const auto &parameter_name = it->first;
861 const bool is_variadic = it->second;
862 // Found base class which is a template parameter
863 LOG_DBG("Found base class which is a template parameter "
864 "{}, {}, {}",
865 parameter_name, is_variadic,
866 std::distance(template_parameter_names.begin(), it));
867
868 template_base_params.emplace_back(parameter_name,
869 std::distance(template_parameter_names.begin(), it),
870 is_variadic);
871 }
872 else {
873 // This is a regular base class - it is handled by
874 // process_template
875 }
876 base_index++;
877 }
878
879 process_template_arguments(parent, cls, template_base_params,
880 template_arguments, template_instantiation, template_decl);
881
882 if constexpr (std::is_same_v<typename VisitorT::diagram_t,
883 class_diagram::model::diagram>) {
884 find_instantiation_relationships(template_instantiation,
885 eid_t{template_decl->getID()}, full_template_specialization_name);
886 }
887
888 template_instantiation.set_id(
889 common::to_id(template_instantiation.full_name(false)));
890
891 visitor_.set_source_location(*cls, template_instantiation);
892}

◆ build_from_class_template_specialization()

template<typename VisitorT >
void clanguml::common::visitor::template_builder< VisitorT >::build_from_class_template_specialization ( clanguml::common::model::template_element template_instantiation,
const clang::ClassTemplateSpecializationDecl &  template_specialization,
std::optional< clanguml::common::model::template_element * >  parent = {} 
)

Build template class from class template specialization decl.

Parameters
template_specializationClass template specialization declaration
parentOptional class in which this template is contained
Returns
Created template class model

Definition at line 895 of file template_builder.h.

899{
900 //
901 // Here we'll hold the template base params to replace with the
902 // instantiated values
903 //
904 std::deque<std::tuple</*parameter name*/ std::string, /* position */ int,
905 /*is variadic */ bool>>
906 template_base_params{};
907
908 const clang::ClassTemplateDecl *template_decl =
909 template_specialization.getSpecializedTemplate();
910
911 auto qualified_name = template_decl->getQualifiedNameAsString();
912
913 namespace_ ns{qualified_name};
914 ns.pop_back();
915 template_instantiation.set_name(template_decl->getNameAsString());
916 template_instantiation.set_namespace(ns);
917
918 process_template_arguments(parent, &template_specialization,
919 template_base_params,
920 template_specialization.getTemplateArgs().asArray(),
921 template_instantiation, template_decl);
922
923 // Update the id after the template parameters are processed
924 template_instantiation.set_id(
925 common::to_id(template_instantiation.full_name(false)));
926
927 if constexpr (std::is_same_v<typename VisitorT::diagram_t,
928 class_diagram::model::diagram>) {
929 find_instantiation_relationships(template_instantiation,
930 eid_t{template_specialization.getID()}, qualified_name);
931 }
932
933 visitor_.set_source_location(*template_decl, template_instantiation);
934}

◆ build_from_template_declaration()

template<typename VisitorT >
void clanguml::common::visitor::template_builder< VisitorT >::build_from_template_declaration ( clanguml::common::model::template_trait template_model,
const clang::TemplateDecl &  template_declaration,
common::optional_ref< common::model::element templated_element = {} 
)

Definition at line 619 of file template_builder.h.

623{
624 LOG_DBG("Processing {} template parameters...",
625 common::get_qualified_name(template_declaration));
626
627 if (template_declaration.getTemplateParameters() == nullptr)
628 return;
629
630 for (const auto *parameter :
631 *template_declaration.getTemplateParameters()) {
632 if (clang::dyn_cast_or_null<clang::TemplateTypeParmDecl>(parameter) !=
633 nullptr) {
634 const auto *template_type_parameter =
635 clang::dyn_cast_or_null<clang::TemplateTypeParmDecl>(parameter);
636
637 std::optional<std::string> default_arg;
638 if (template_type_parameter->hasDefaultArgument()) {
639 default_arg =
640#if LLVM_VERSION_MAJOR > 18
642 template_type_parameter->getDefaultArgument(),
643 template_declaration.getASTContext());
644#else
645 template_type_parameter->getDefaultArgument().getAsString();
646#endif
647 }
648
649 auto parameter_name = template_type_parameter->getNameAsString();
650 if (parameter_name.empty())
651 parameter_name = "typename";
652
653 auto ct = template_parameter::make_template_type(parameter_name,
654 default_arg, template_type_parameter->isParameterPack());
655
656 if constexpr (std::is_same_v<typename VisitorT::diagram_t,
658 if (template_type_parameter->getTypeConstraint() != nullptr) {
660 template_type_parameter->getTypeConstraint()
661 ->getNamedConcept(),
662 [this, &ct, &templated_element](
663 const clang::ConceptDecl *named_concept) mutable {
664 ct.set_concept_constraint(
665 named_concept->getQualifiedNameAsString());
666 if (templated_element &&
667 visitor_.should_include(named_concept)) {
668 templated_element.value().add_relationship(
669 {relationship_t::kConstraint,
670 id_mapper()
671 .get_global_id(
672 eid_t{named_concept->getID()})
673 .value(),
674 model::access_t::kNone,
675 ct.name().value()});
676 }
677 });
678 }
679 }
680 else {
681 (void)templated_element; // NOLINT
682 }
683
684 template_model.add_template(std::move(ct));
685 }
686 else if (clang::dyn_cast_or_null<clang::NonTypeTemplateParmDecl>(
687 parameter) != nullptr) {
688 const auto *template_nontype_parameter =
689 clang::dyn_cast_or_null<clang::NonTypeTemplateParmDecl>(
690 parameter);
691
692 std::optional<std::string> default_arg;
693
694 if (template_nontype_parameter->hasDefaultArgument()) {
695 default_arg =
696#if LLVM_VERSION_MAJOR > 18
698 template_nontype_parameter->getDefaultArgument(),
699 template_declaration.getASTContext());
700#else
702 template_nontype_parameter->getDefaultArgument());
703#endif
704 }
706 template_nontype_parameter->getType().getAsString(),
707 template_nontype_parameter->getNameAsString(), default_arg,
708 template_nontype_parameter->isParameterPack());
709
710 template_model.add_template(std::move(ct));
711 }
712 else if (clang::dyn_cast_or_null<clang::TemplateTemplateParmDecl>(
713 parameter) != nullptr) {
714 const auto *template_template_parameter =
715 clang::dyn_cast_or_null<clang::TemplateTemplateParmDecl>(
716 parameter);
717 std::optional<std::string> default_arg;
718 if (template_template_parameter->hasDefaultArgument()) {
719 default_arg = common::to_string(
720 template_template_parameter->getDefaultArgument()
721 .getArgument());
722 }
724 template_template_parameter->getNameAsString(), default_arg,
725 template_template_parameter->isParameterPack());
726
727 template_model.add_template(std::move(ct));
728 }
729 else {
730 // pass
731 }
732 }
733}

◆ build_from_template_specialization_type()

template<typename VisitorT >
void clanguml::common::visitor::template_builder< VisitorT >::build_from_template_specialization_type ( clanguml::common::model::template_element template_instantiation,
const clang::NamedDecl *  cls,
const clang::TemplateSpecializationType &  template_type_decl,
std::optional< clanguml::common::model::template_element * >  parent = {} 
)

Basic template class build method.

Parameters
clsClang template declaration
template_type_declTemplate specialization type
parentOptional class in which this template is contained
Returns
Created template class model

Definition at line 736 of file template_builder.h.

741{
742 const auto *template_type_ptr = &template_type_decl;
743
744 if (template_type_decl.isTypeAlias()) {
745 if (const auto *tsp =
746 template_type_decl.getAliasedType()
747 ->template getAs<clang::TemplateSpecializationType>();
748 tsp != nullptr)
749 template_type_ptr = tsp;
750 }
751
752 const auto &template_type = *template_type_ptr;
753
754 template_instantiation.is_template(true);
755
756 std::string full_template_specialization_name = common::to_string(
757 template_type.desugar(),
758 template_type.getTemplateName().getAsTemplateDecl()->getASTContext());
759
760 auto *template_decl{template_type.getTemplateName().getAsTemplateDecl()};
761
762 build(template_instantiation, cls, template_decl,
763 template_type.template_arguments(), full_template_specialization_name,
764 parent);
765}

◆ config()

template<typename VisitorT >
const config::diagram & clanguml::common::visitor::template_builder< VisitorT >::config

Get reference to the current diagram configuration.

Returns
Reference to the current diagram configuration

Definition at line 576 of file template_builder.h.

577{
578 return config_;
579}

◆ consume_context()

template<typename VisitorT >
clang::QualType clanguml::common::visitor::template_builder< VisitorT >::consume_context ( clang::QualType  type,
template_parameter tp 
) const

Remove types context (e.g. const or reference qualifiers)

This method removes all const and reference/pointer qualifiers from type, adds them to the template parameter model tp and returns a type without context.

Parameters
typeType to remove context from
tpTemplate model to add context to
Returns
Type without context

Definition at line 1122 of file template_builder.h.

1124{
1125 auto [unqualified_type, context] = common::consume_type_context(type);
1126
1127 tp.deduced_context(std::move(context));
1128
1129 return unqualified_type;
1130}

◆ diagram()

template<typename VisitorT >
common::model::diagram & clanguml::common::visitor::template_builder< VisitorT >::diagram

Get reference to the current diagram model.

Returns
Reference to the current diagram model

Definition at line 570 of file template_builder.h.

571{
572 return diagram_;
573}

◆ find_instantiation_relationships()

template<typename VisitorT >
void clanguml::common::visitor::template_builder< VisitorT >::find_instantiation_relationships ( common::model::template_element template_instantiation,
eid_t  id,
const std::string &  qualified_name 
) const

Definition at line 937 of file template_builder.h.

940{
941 visitor_.find_instantiation_relationships(
942 template_instantiation, qualified_name, id);
943}

◆ find_relationships_in_unexposed_template_params()

template<typename VisitorT >
bool clanguml::common::visitor::template_builder< VisitorT >::find_relationships_in_unexposed_template_params ( const template_parameter ct,
found_relationships_t relationships 
)

Try to find additional relationships in unexposed parameters.

Sometimes, Clang will report a template parameter as unexposed, which means all we get a is a string representation of the type, sometimes with template parameter names replaced with type-parameter-X-Y string.

This method tries to find any type names, which might be relevant for the diagram relationships.

Parameters
ctTemplate argument model
relationshipsList of discovered relationships
Returns
True, if any relationships were found

Definition at line 1210 of file template_builder.h.

1213{
1214 const auto &type = ct.type();
1215
1216 if (!type)
1217 return false;
1218
1219 bool found{false};
1220 LOG_DBG("Finding relationships in user defined type: {}",
1221 ct.to_string(config().using_namespace(), false));
1222
1223 auto type_with_namespace =
1224 std::make_optional<common::model::namespace_>(type.value());
1225
1226 if (!type_with_namespace.has_value()) {
1227 // Couldn't find declaration of this type
1228 type_with_namespace = common::model::namespace_{type.value()};
1229 }
1230
1231 auto element_opt = diagram().get(type_with_namespace.value().to_string());
1232 if (config_.generate_template_argument_dependencies() && element_opt) {
1233 relationships.emplace_back(
1234 element_opt.value().id(), relationship_t::kDependency);
1235 found = true;
1236 }
1237
1238 for (const auto &nested_template_params : ct.template_params()) {
1240 nested_template_params, relationships) ||
1241 found;
1242 }
1243
1244 return found;
1245}

◆ id_mapper()

template<typename VisitorT >
common::visitor::ast_id_mapper & clanguml::common::visitor::template_builder< VisitorT >::id_mapper

Get reference to Clang AST to clang-uml id mapper.

Returns
Reference to Clang AST to clang-uml id mapper

Definition at line 588 of file template_builder.h.

589{
590 return id_mapper_;
591}

◆ process_expression_argument()

template<typename VisitorT >
template_parameter clanguml::common::visitor::template_builder< VisitorT >::process_expression_argument ( const clang::TemplateArgument &  arg)

Process clang::TemplateArgument::Expression

Note
The template argument is a pack expansion of a template name that was provided for a template template parameter.
Parameters
argTemplate argument
Returns
Return template argument model

Definition at line 1308 of file template_builder.h.

1310{
1311 assert(arg.getKind() == clang::TemplateArgument::Expression);
1313 arg.getAsExpr()->getSourceRange(), source_manager()));
1314}

◆ process_integral_argument()

template<typename VisitorT >
template_parameter clanguml::common::visitor::template_builder< VisitorT >::process_integral_argument ( const clang::TemplateArgument &  arg,
const clang::ASTContext &  ast_context 
)

Process clang::TemplateArgument::Integral

Note
The template argument is an integral value stored in an llvm::APSInt that was provided for an integral non-type template parameter.
Parameters
argTemplate argument
Returns
Return template argument model

Definition at line 1248 of file template_builder.h.

1250{
1251 assert(arg.getKind() == clang::TemplateArgument::Integral);
1252
1253 std::string result;
1254 llvm::raw_string_ostream ostream(result);
1255 clang::PrintingPolicy policy(ast_context.getLangOpts());
1256
1257#if LLVM_VERSION_MAJOR > 18
1258 arg.print(policy, ostream, false);
1259#else
1260 arg.dump(ostream);
1261#endif
1262
1263 return template_parameter::make_argument(result);
1264}

◆ process_null_argument()

template<typename VisitorT >
template_parameter clanguml::common::visitor::template_builder< VisitorT >::process_null_argument ( const clang::TemplateArgument &  arg)

Process clang::TemplateArgument::Null

Note
Represents an empty template argument, e.g., one that has not been deduced.
Parameters
argTemplate argument
Returns
Return template argument model

Definition at line 1288 of file template_builder.h.

1290{
1291 assert(arg.getKind() == clang::TemplateArgument::Null);
1292
1294}

◆ process_nullptr_argument()

template<typename VisitorT >
template_parameter clanguml::common::visitor::template_builder< VisitorT >::process_nullptr_argument ( const clang::TemplateArgument &  arg)

Process clang::TemplateArgument::NullPtr

Note
The template argument is a null pointer or null pointer to member that was provided for a non-type template parameter.
Parameters
argTemplate argument
Returns
Return template argument model

Definition at line 1297 of file template_builder.h.

1299{
1300 assert(arg.getKind() == clang::TemplateArgument::NullPtr);
1301
1302 LOG_DBG("Processing nullptr argument: {}", common::to_string(arg));
1303
1304 return template_parameter::make_argument("nullptr");
1305}

◆ process_pack_argument()

template<typename VisitorT >
std::vector< template_parameter > clanguml::common::visitor::template_builder< VisitorT >::process_pack_argument ( std::optional< clanguml::common::model::template_element * > &  parent,
const clang::NamedDecl *  cls,
clanguml::common::model::template_element template_instantiation,
const clang::TemplateDecl *  base_template_decl,
const clang::TemplateArgument &  arg,
size_t  argument_index,
std::vector< template_parameter > &  argument 
)

Process clang::TemplateArgument::Pack

Note
The template argument is actually a parameter pack. Arguments are stored in the Args struct.
Parameters
argTemplate argument
Returns
Return template argument model

Definition at line 1318 of file template_builder.h.

1325{
1326 assert(arg.getKind() == clang::TemplateArgument::Pack);
1327
1328 std::vector<template_parameter> res;
1329
1330 auto pack_argument_index = argument_index;
1331
1332 for (const auto &a : arg.getPackAsArray()) {
1333 argument_process_dispatch(parent, cls, template_instantiation,
1334 base_template_decl, a, pack_argument_index++, res);
1335 }
1336
1337 return res;
1338}

◆ process_template_argument()

template<typename VisitorT >
template_parameter clanguml::common::visitor::template_builder< VisitorT >::process_template_argument ( const clang::TemplateArgument &  arg)

Process clang::TemplateArgument::Template

Note
The template argument is a template name that was provided for a template template parameter.
Parameters
argTemplate argument
Returns
Return template argument model

Definition at line 1092 of file template_builder.h.

1094{
1095 auto arg_name = common::to_string(arg);
1096
1097 LOG_DBG("Processing template argument: {}", arg_name);
1098
1100}

◆ process_template_arguments()

template<typename VisitorT >
void clanguml::common::visitor::template_builder< VisitorT >::process_template_arguments ( std::optional< clanguml::common::model::template_element * > &  parent,
const clang::NamedDecl *  cls,
std::deque< std::tuple< std::string, int, bool > > &  template_base_params,
const clang::ArrayRef< clang::TemplateArgument > &  template_args,
clanguml::common::model::template_element template_instantiation,
const clang::TemplateDecl *  template_decl 
)

Process template class parameters and arguments.

Parameters
parentOptional class in which this template is contained
clsTemplate class specialization declaration
template_base_paramsList of base class template parameters
template_argsList of template arguments
template_instantiationTemplate class model to add template args
template_declBase template declaration

Definition at line 946 of file template_builder.h.

953{
954 auto arg_index{0};
955
956 for (const auto &arg : template_args) {
957 // Argument can be a parameter pack in which case it gives multiple
958 // arguments
959 std::vector<template_parameter> arguments;
960
961 // Handle empty pack expansion
962 if (arg.getKind() == clang::TemplateArgument::ArgKind::Pack &&
963 arg.getPackAsArray().empty()) {
964 template_instantiation.add_template(
966 }
967
968 // For now ignore the default template arguments of templates which
969 // do not match the inclusion filters, to make the system
970 // templates 'nicer' - i.e. skipping the allocators and comparators
971 // TODO: Change this to ignore only when the arguments are set to
972 // default values, and add them when they are specifically
973 // overridden
974 if (!diagram().should_include(
975 namespace_{template_decl->getQualifiedNameAsString()})) {
976 const auto *maybe_type_parm_decl =
977 clang::dyn_cast<clang::TemplateTypeParmDecl>(
978 template_decl->getTemplateParameters()->getParam(
979 std::min<unsigned>(arg_index,
980 static_cast<unsigned>(
981 template_decl->getTemplateParameters()
982 ->size()) -
983 1)));
984 if (maybe_type_parm_decl != nullptr &&
985 maybe_type_parm_decl->hasDefaultArgument()) {
986 continue;
987 }
988 }
989
990 //
991 // Handle the template parameter/argument based on its kind
992 //
993 argument_process_dispatch(parent, cls, template_instantiation,
994 template_decl, arg, arg_index, arguments);
995
996 if (arguments.empty()) {
997 arg_index++;
998 continue;
999 }
1000
1001 // We can figure this only when we encounter variadic param in
1002 // the list of template params, from then this variable is true
1003 // and we can process following template parameters as belonging
1004 // to the variadic tuple
1005 [[maybe_unused]] auto variadic_params{false};
1006
1007 if constexpr (std::is_same_v<typename VisitorT::diagram_t,
1008 class_diagram::model::diagram>) {
1009 // In case any of the template arguments are base classes, add
1010 // them as parents of the current template instantiation class
1011 if (!template_base_params.empty()) {
1012 variadic_params = add_base_classes(template_instantiation,
1013 template_base_params, arg_index, variadic_params,
1014 arguments.front());
1015 }
1016 }
1017
1018 for (auto &argument : arguments) {
1020 argument, argument.to_string(using_namespace(), false, true));
1021
1022 LOG_DBG("Adding template argument {} to template "
1023 "specialization/instantiation {}",
1024 argument.to_string(using_namespace(), false),
1025 template_instantiation.name());
1026
1027 template_instantiation.add_template(std::move(argument));
1028 }
1029
1030 arg_index++;
1031 }
1032
1033 // Update id
1034 template_instantiation.set_id(
1035 common::to_id(template_instantiation.full_name(false)));
1036}

◆ process_template_expansion()

template<typename VisitorT >
template_parameter clanguml::common::visitor::template_builder< VisitorT >::process_template_expansion ( const clang::TemplateArgument &  arg)

Process clang::TemplateArgument::TemplateExpansion

Note
The template argument is a pack expansion of a template name that was provided for a template template parameter.
Parameters
argTemplate argument
Returns
Return template argument model

Definition at line 1103 of file template_builder.h.

1105{
1106 auto arg_name = common::to_string(arg);
1107
1108 LOG_DBG("Processing template expansion argument: {}", arg_name);
1109
1111 arg.getAsTemplate().getAsTemplateDecl(), [&arg_name](const auto *decl) {
1112 arg_name = decl->getQualifiedNameAsString();
1113 });
1114
1115 auto param = template_parameter::make_template_type(arg_name);
1116 param.is_variadic(true);
1117
1118 return param;
1119}

◆ process_type_argument()

template<typename VisitorT >
template_parameter clanguml::common::visitor::template_builder< VisitorT >::process_type_argument ( std::optional< clanguml::common::model::template_element * > &  parent,
const clang::NamedDecl *  cls,
const clang::TemplateDecl *  base_template_decl,
clang::QualType  type,
clanguml::common::model::template_element template_instantiation,
size_t  argument_index 
)

Process clang::TemplateArgument::Type

Note
The template argument is a type.
Parameters
argTemplate argument
Returns
Return template argument model

Definition at line 1133 of file template_builder.h.

1139{
1140 std::optional<template_parameter> argument;
1141
1142 if (type->getAs<clang::ElaboratedType>() != nullptr) {
1143 type = type->getAs<clang::ElaboratedType>()->getNamedType(); // NOLINT
1144 }
1145
1146 auto type_name = common::to_string(type, &cls->getASTContext());
1147
1148 LOG_DBG("Processing template {} type argument {}: {}, {}, {}",
1149 template_decl->getQualifiedNameAsString(), argument_index, type_name,
1150 type->getTypeClassName(),
1151 common::to_string(type, cls->getASTContext()));
1152
1153 argument = try_as_function_prototype(parent, cls, template_decl, type,
1154 template_instantiation, argument_index);
1155 if (argument)
1156 return *argument;
1157
1158 argument = try_as_member_pointer(parent, cls, template_decl, type,
1159 template_instantiation, argument_index);
1160 if (argument)
1161 return *argument;
1162
1163 argument = try_as_array(parent, cls, template_decl, type,
1164 template_instantiation, argument_index);
1165 if (argument)
1166 return *argument;
1167
1168 argument = try_as_template_parm_type(cls, template_decl, type);
1169 if (argument)
1170 return *argument;
1171
1172 argument = try_as_template_specialization_type(parent, cls, template_decl,
1173 type, template_instantiation, argument_index);
1174 if (argument)
1175 return *argument;
1176
1177 argument = try_as_decl_type(parent, cls, template_decl, type,
1178 template_instantiation, argument_index);
1179 if (argument)
1180 return *argument;
1181
1182 argument = try_as_typedef_type(parent, cls, template_decl, type,
1183 template_instantiation, argument_index);
1184 if (argument)
1185 return *argument;
1186
1187 argument = try_as_lambda(cls, template_decl, type);
1188 if (argument)
1189 return *argument;
1190
1191 argument = try_as_record_type(parent, cls, template_decl, type,
1192 template_instantiation, argument_index);
1193 if (argument)
1194 return *argument;
1195
1197 parent, cls, template_decl, type, template_instantiation);
1198 if (argument)
1199 return *argument;
1200
1201 argument = try_as_builtin_type(parent, type, template_decl);
1202 if (argument)
1203 return *argument;
1204
1205 // fallback
1206 return template_parameter::make_argument(type_name);
1207}

◆ simplify_system_template()

template<typename VisitorT >
bool clanguml::common::visitor::template_builder< VisitorT >::simplify_system_template ( template_parameter ct,
const std::string &  full_name 
) const

Simplify system templates.

This method tries to simplify all fully qualified template names in the full_name using substitutions from the configuration file ().

Typical example is replace every std::basic_string<char> with std::string.

Parameters
ctTemplate parameter
full_nameFull template name
Returns

Definition at line 600 of file template_builder.h.

602{
604 return false;
605
606 auto simplified = config().simplify_template_type(full_name);
607
608 if (simplified != full_name) {
609 ct.set_type(simplified);
610 ct.set_id(common::to_id(simplified));
611 ct.clear_params();
612 return true;
613 }
614
615 return false;
616}

◆ source_manager()

template<typename VisitorT >
clang::SourceManager & clanguml::common::visitor::template_builder< VisitorT >::source_manager

Get reference to the current source manager.

Returns
Reference to the current source manager

Definition at line 594 of file template_builder.h.

595{
596 return source_manager_;
597}

◆ try_as_array()

template<typename VisitorT >
std::optional< template_parameter > clanguml::common::visitor::template_builder< VisitorT >::try_as_array ( std::optional< clanguml::common::model::template_element * > &  parent,
const clang::NamedDecl *  cls,
const clang::TemplateDecl *  template_decl,
clang::QualType &  type,
clanguml::common::model::template_element template_instantiation,
size_t  argument_index 
)

Try to process template type argument as array.

Parameters
parentOptional class in which this template is contained
clsTemplate class specialization declaration
template_declBase template declaration
typeTemplate type
template_instantiationTemplate class model
argument_indexArgument index
Returns
Array template argument if succeeds, or std::nullopt

Definition at line 1419 of file template_builder.h.

1425{
1426 const auto *array_type = common::dereference(type)->getAsArrayTypeUnsafe();
1427 if (array_type == nullptr)
1428 return {};
1429
1431
1432 type = consume_context(type, argument);
1433
1434 argument.is_array(true);
1435
1436 // Set function template return type
1437 auto element_type = process_type_argument(parent, cls, template_decl,
1438 array_type->getElementType(), template_instantiation, argument_index);
1439
1440 argument.add_template_param(element_type);
1441
1442 if (array_type->isDependentSizedArrayType() &&
1443 array_type->getDependence() ==
1444 clang::TypeDependence::DependentInstantiation) {
1445 argument.add_template_param(
1447 ((clang::DependentSizedArrayType *)array_type) // NOLINT
1448 ->getSizeExpr())));
1449 }
1450 else if (array_type->isConstantArrayType()) {
1452 std::to_string(((clang::ConstantArrayType *)array_type) // NOLINT
1453 ->getSize()
1454 .getLimitedValue())));
1455 }
1456
1457 // TODO: Handle variable sized arrays
1458
1459 return argument;
1460}

◆ try_as_builtin_type()

template<typename VisitorT >
std::optional< template_parameter > clanguml::common::visitor::template_builder< VisitorT >::try_as_builtin_type ( std::optional< clanguml::common::model::template_element * > &  parent,
clang::QualType &  type,
const clang::TemplateDecl *  template_decl 
)

Try to process template type argument as builtin type.

Parameters
parentOptional class in which this template is contained
typeTemplate type
template_declBase template declaration
Returns
Builtin type template argument if succeeds, or std::nullopt

Definition at line 1841 of file template_builder.h.

1844{
1845 const auto *builtin_type = type->getAs<clang::BuiltinType>();
1846 if (builtin_type == nullptr)
1847 return {};
1848
1849 LOG_DBG("Template argument is a builtin type");
1850
1851 auto type_name = common::to_string(type, template_decl->getASTContext());
1853
1854 type = consume_context(type, argument);
1855 argument.set_type(type_name);
1856
1857 return argument;
1858}

◆ try_as_decl_type()

template<typename VisitorT >
std::optional< template_parameter > clanguml::common::visitor::template_builder< VisitorT >::try_as_decl_type ( std::optional< clanguml::common::model::template_element * > &  parent,
const clang::NamedDecl *  cls,
const clang::TemplateDecl *  template_decl,
clang::QualType &  type,
clanguml::common::model::template_element template_instantiation,
size_t  argument_index 
)

Try to process template type argument as decltype() type.

Parameters
parentOptional class in which this template is contained
clsTemplate class specialization declaration
template_declBase template declaration
typeTemplate type
template_instantiationTemplate class model
argument_indexArgument index
Returns
decltype() type template argument if succeeds, or std::nullopt

Definition at line 1515 of file template_builder.h.

1521{
1522 const auto *decl_type =
1523 common::dereference(type)->getAs<clang::DecltypeType>();
1524 if (decl_type == nullptr) {
1525 return {};
1526 }
1527
1528 LOG_DBG("Template argument is a decltype()");
1529
1530 // TODO
1531 return {};
1532}

◆ try_as_enum_type()

template<typename VisitorT >
std::optional< template_parameter > clanguml::common::visitor::template_builder< VisitorT >::try_as_enum_type ( std::optional< clanguml::common::model::template_element * > &  parent,
const clang::NamedDecl *  cls,
const clang::TemplateDecl *  template_decl,
clang::QualType &  type,
clanguml::common::model::template_element template_instantiation 
)

Try to process template type argument as enum type.

Parameters
parentOptional class in which this template is contained
clsTemplate class specialization declaration
template_declBase template declaration
typeTemplate type
template_instantiationTemplate class model
Returns
Enum type template argument if succeeds, or std::nullopt

Definition at line 1810 of file template_builder.h.

1815{
1816 const auto *enum_type = type->getAs<clang::EnumType>();
1817 if (enum_type == nullptr)
1818 return {};
1819
1820 LOG_DBG("Template argument is a an enum");
1821
1823 type = consume_context(type, argument);
1824
1825 auto type_name = common::to_string(type, template_decl->getASTContext());
1826 argument.set_type(type_name);
1827 const auto type_id = common::to_id(type_name);
1828 argument.set_id(type_id);
1829
1830 if (enum_type->getAsTagDecl() != nullptr &&
1832 template_instantiation.add_relationship(
1833 {relationship_t::kDependency, type_id});
1834 }
1835
1836 return argument;
1837}

◆ try_as_function_prototype()

template<typename VisitorT >
std::optional< template_parameter > clanguml::common::visitor::template_builder< VisitorT >::try_as_function_prototype ( std::optional< clanguml::common::model::template_element * > &  parent,
const clang::NamedDecl *  cls,
const clang::TemplateDecl *  template_decl,
clang::QualType &  type,
clanguml::common::model::template_element template_instantiation,
size_t  argument_index 
)

Try to process template type argument as function template.

Parameters
parentOptional class in which this template is contained
clsTemplate class specialization declaration
template_declBase template declaration
typeTemplate type
template_instantiationTemplate class model
argument_indexArgument index
Returns
Function template argument if succeeds, or std::nullopt

Definition at line 1464 of file template_builder.h.

1470{
1471 const auto *function_type = type->getAs<clang::FunctionProtoType>();
1472
1473 if (function_type == nullptr && type->isFunctionPointerType()) {
1474 function_type =
1475 type->getPointeeType()->getAs<clang::FunctionProtoType>();
1476 if (function_type == nullptr)
1477 return {};
1478 }
1479
1480 if (function_type == nullptr)
1481 return {};
1482
1483 LOG_DBG("Template argument is a function prototype");
1484
1486
1487 type = consume_context(type, argument);
1488
1489 argument.is_function_template(true);
1490
1491 // Set function template return type
1492 auto return_arg = process_type_argument(parent, cls, template_decl,
1493 function_type->getReturnType(), template_instantiation, argument_index);
1494
1495 argument.add_template_param(return_arg);
1496
1497 // Set function template argument types
1498 if (function_type->isVariadic() && function_type->param_types().empty()) {
1499 auto fallback_arg = template_parameter::make_argument({});
1500 fallback_arg.is_ellipsis(true);
1501 argument.add_template_param(std::move(fallback_arg));
1502 }
1503 else {
1504 for (const auto &param_type : function_type->param_types()) {
1505 argument.add_template_param(
1506 process_type_argument(parent, cls, template_decl, param_type,
1507 template_instantiation, argument_index));
1508 }
1509 }
1510
1511 return argument;
1512}

◆ try_as_lambda()

template<typename VisitorT >
std::optional< template_parameter > clanguml::common::visitor::template_builder< VisitorT >::try_as_lambda ( const clang::NamedDecl *  cls,
const clang::TemplateDecl *  template_decl,
clang::QualType &  type 
)

Try to process template type argument as lambda.

Parameters
clsTemplate class specialization declaration
template_declBase template declaration
typeTemplate type
Returns
Lambda template argument if succeeds, or std::nullopt

Definition at line 1717 of file template_builder.h.

1720{
1721 auto type_name = common::to_string(type, &cls->getASTContext());
1722
1723 if (type_name.find("(lambda at ") != 0)
1724 return {};
1725
1726 LOG_DBG("Template argument is a lambda");
1727
1729 type = consume_context(type, argument);
1730
1732 argument.set_type(type_name);
1733
1734 return argument;
1735}

◆ try_as_member_pointer()

template<typename VisitorT >
std::optional< template_parameter > clanguml::common::visitor::template_builder< VisitorT >::try_as_member_pointer ( std::optional< clanguml::common::model::template_element * > &  parent,
const clang::NamedDecl *  cls,
const clang::TemplateDecl *  template_decl,
clang::QualType &  type,
clanguml::common::model::template_element template_instantiation,
size_t  argument_index 
)

Try to process template type argument as member pointer type.

Parameters
parentOptional class in which this template is contained
clsTemplate class specialization declaration
template_declBase template declaration
typeTemplate type
template_instantiationTemplate class model
argument_indexArgument index
Returns
Member pointer type template argument if succeeds, or std::nullopt

Definition at line 1342 of file template_builder.h.

1348{
1349 const auto *mp_type =
1350 common::dereference(type)->getAs<clang::MemberPointerType>();
1351 if (mp_type == nullptr)
1352 return {};
1353
1355 type = consume_context(type, argument);
1356
1357 // Handle a pointer to a data member of a class
1358 if (mp_type->isMemberDataPointer()) {
1359 argument.is_member_pointer(false);
1360 argument.is_data_pointer(true);
1361
1362 auto pointee_arg = process_type_argument(parent, cls, template_decl,
1363 mp_type->getPointeeType(), template_instantiation, argument_index);
1364
1365 argument.add_template_param(std::move(pointee_arg));
1366
1367 const auto *member_class_type = mp_type->getClass();
1368
1369 if (member_class_type == nullptr)
1370 return {};
1371
1372 auto class_type_arg = process_type_argument(parent, cls, template_decl,
1373 mp_type->getClass()->getCanonicalTypeUnqualified(),
1374 template_instantiation, argument_index);
1375
1376 argument.add_template_param(std::move(class_type_arg));
1377 }
1378 // Handle pointer to class method member
1379 else {
1380 argument.is_member_pointer(true);
1381 argument.is_data_pointer(false);
1382
1383 const auto *function_type =
1384 mp_type->getPointeeType()->getAs<clang::FunctionProtoType>();
1385
1386 assert(function_type != nullptr);
1387
1388 auto return_type_arg = process_type_argument(parent, cls, template_decl,
1389 function_type->getReturnType(), template_instantiation,
1390 argument_index);
1391
1392 // Add return type argument
1393 argument.add_template_param(std::move(return_type_arg));
1394
1395 const auto *member_class_type = mp_type->getClass();
1396
1397 if (member_class_type == nullptr)
1398 return {};
1399
1400 auto class_type_arg = process_type_argument(parent, cls, template_decl,
1401 mp_type->getClass()->getCanonicalTypeUnqualified(),
1402 template_instantiation, argument_index);
1403
1404 // Add class type argument
1405 argument.add_template_param(std::move(class_type_arg));
1406
1407 // Add argument types
1408 for (const auto &param_type : function_type->param_types()) {
1409 argument.add_template_param(
1410 process_type_argument(parent, cls, template_decl, param_type,
1411 template_instantiation, argument_index));
1412 }
1413 }
1414
1415 return argument;
1416}

◆ try_as_record_type()

template<typename VisitorT >
std::optional< template_parameter > clanguml::common::visitor::template_builder< VisitorT >::try_as_record_type ( std::optional< clanguml::common::model::template_element * > &  parent,
const clang::NamedDecl *  cls,
const clang::TemplateDecl *  template_decl,
clang::QualType &  type,
clanguml::common::model::template_element template_instantiation,
size_t  argument_index 
)

Try to process template type argument as record type.

Parameters
parentOptional class in which this template is contained
clsTemplate class specialization declaration
template_declBase template declaration
typeTemplate type
template_instantiationTemplate class model
argument_indexArgument index
Returns
Record type template argument if succeeds, or std::nullopt

Definition at line 1739 of file template_builder.h.

1745{
1746 const auto *record_type =
1747 common::dereference(type)->getAs<clang::RecordType>();
1748 if (record_type == nullptr)
1749 return {};
1750
1751 LOG_DBG("Template argument is a c++ record");
1752
1754 type = consume_context(type, argument);
1755
1756 const auto type_name = config().simplify_template_type(
1757 common::to_string(type, template_decl->getASTContext()));
1758
1759 argument.set_type(type_name);
1760 const auto type_id = common::to_id(type_name);
1761
1762 argument.set_id(type_id);
1763
1764 const auto *class_template_specialization =
1765 clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(
1766 record_type->getAsRecordDecl());
1767
1768 if (class_template_specialization != nullptr) {
1769 auto tag_argument =
1770 visitor_.create_element(class_template_specialization);
1771
1773 *tag_argument, *class_template_specialization);
1774
1775 tag_argument->is_template(true);
1776
1777 if (tag_argument) {
1778 argument.set_type(tag_argument->name_and_ns());
1779 for (const auto &p : tag_argument->template_params())
1780 argument.add_template_param(p);
1781 for (auto &r : tag_argument->relationships()) {
1782 template_instantiation.add_relationship(std::move(r));
1783 }
1784
1786 diagram().should_include(tag_argument->get_namespace())) {
1787 if (parent.has_value())
1788 parent.value()->add_relationship(
1789 {relationship_t::kDependency, tag_argument->id()});
1790 visitor_.set_source_location(*template_decl, *tag_argument);
1791 visitor_.add_diagram_element(std::move(tag_argument));
1792 }
1793 }
1794 }
1795 else if (const auto *record_type_decl = record_type->getAsRecordDecl();
1796 record_type_decl != nullptr) {
1798 diagram().should_include(namespace_{type_name})) {
1799 // Add dependency relationship to the parent
1800 // template
1801 template_instantiation.add_relationship(
1802 {relationship_t::kDependency, type_id});
1803 }
1804 }
1805
1806 return argument;
1807}

◆ try_as_template_parm_type()

template<typename VisitorT >
std::optional< template_parameter > clanguml::common::visitor::template_builder< VisitorT >::try_as_template_parm_type ( const clang::NamedDecl *  cls,
const clang::TemplateDecl *  template_decl,
clang::QualType &  type 
)

Try to process template type argument as template parameter.

Parameters
clsTemplate class specialization declaration
template_declBase template declaration
typeTemplate type
Returns
Template parameter if succeeds, or std::nullopt

Definition at line 1673 of file template_builder.h.

1676{
1677 auto is_variadic{false};
1678
1679 const auto *type_parameter =
1680 common::dereference(type)->getAs<clang::TemplateTypeParmType>();
1681
1682 auto type_name = common::to_string(type, &cls->getASTContext());
1683
1684 if (type_parameter == nullptr) {
1685 if (const auto *pet =
1686 common::dereference(type)->getAs<clang::PackExpansionType>();
1687 pet != nullptr) {
1688 is_variadic = true;
1689 type_parameter =
1690 pet->getPattern()->getAs<clang::TemplateTypeParmType>();
1691 }
1692 }
1693
1694 if (type_parameter == nullptr)
1695 return {};
1696
1697 LOG_DBG("Template argument is a template parameter type");
1698
1700 type = consume_context(type, argument);
1701
1702 auto type_parameter_name = common::to_string(type, cls->getASTContext());
1703 if (type_parameter_name.empty())
1704 type_parameter_name = "typename";
1705
1707 cls, type_parameter_name));
1708
1709 argument.is_variadic(is_variadic);
1710
1711 common::ensure_lambda_type_is_relative(config(), type_parameter_name);
1712
1713 return argument;
1714}

◆ try_as_template_specialization_type()

template<typename VisitorT >
std::optional< template_parameter > clanguml::common::visitor::template_builder< VisitorT >::try_as_template_specialization_type ( std::optional< clanguml::common::model::template_element * > &  parent,
const clang::NamedDecl *  cls,
const clang::TemplateDecl *  template_decl,
clang::QualType &  type,
clanguml::common::model::template_element template_instantiation,
size_t  argument_index 
)

Try to process template type argument as specialization type.

Parameters
parentOptional class in which this template is contained
clsTemplate class specialization declaration
template_declBase template declaration
typeTemplate type
template_instantiationTemplate class model
argument_indexArgument index
Returns
Template specialization template argument if succeeds, or std::nullopt

Definition at line 1572 of file template_builder.h.

1578{
1579 const auto *nested_template_type =
1580 common::dereference(type)->getAs<clang::TemplateSpecializationType>();
1581 if (nested_template_type == nullptr) {
1582 return {};
1583 }
1584
1585 LOG_DBG("Template argument is a template specialization type");
1586
1588 type = consume_context(type, argument);
1589
1590 auto nested_type_name = nested_template_type->getTemplateName()
1591 .getAsTemplateDecl()
1592 ->getQualifiedNameAsString();
1593
1594 if (clang::dyn_cast<clang::TemplateTemplateParmDecl>(
1595 nested_template_type->getTemplateName().getAsTemplateDecl()) !=
1596 nullptr) {
1597 if (const auto *template_specialization_decl =
1598 clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(cls);
1599 template_specialization_decl != nullptr) {
1600 nested_type_name =
1601 template_specialization_decl->getDescribedTemplateParams()
1602 ->getParam(argument_index)
1603 ->getNameAsString();
1604 }
1605 else {
1606 // fallback
1607 nested_type_name = "template";
1608 }
1609
1610 argument.is_template_template_parameter(true);
1611 }
1612
1613 argument.set_type(nested_type_name);
1614
1615 auto nested_template_instantiation =
1616 visitor_.create_element(nested_template_type->getTemplateName()
1617 .getAsTemplateDecl()
1618 ->getTemplatedDecl());
1619 build_from_template_specialization_type(*nested_template_instantiation, cls,
1620 *nested_template_type,
1621 diagram().should_include(
1622 namespace_{template_decl->getQualifiedNameAsString()})
1623 ? std::make_optional(&template_instantiation)
1624 : parent);
1625
1626 argument.set_id(nested_template_instantiation->id());
1627
1628 for (const auto &t : nested_template_instantiation->template_params())
1629 argument.add_template_param(t);
1630
1631 // Check if this template should be simplified (e.g. system
1632 // template aliases such as 'std:basic_string<char>' should
1633 // be simply 'std::string')
1635 argument, argument.to_string(using_namespace(), false));
1636
1637 argument.set_id(
1638 common::to_id(argument.to_string(using_namespace(), false)));
1639
1640 const auto nested_template_instantiation_full_name =
1641 nested_template_instantiation->full_name(false);
1642
1643 if (nested_template_instantiation &&
1644 diagram().should_include(
1645 namespace_{nested_template_instantiation_full_name})) {
1647 if (diagram().should_include(
1648 namespace_{template_decl->getQualifiedNameAsString()})) {
1649 template_instantiation.add_relationship(
1650 {relationship_t::kDependency,
1651 nested_template_instantiation->id()});
1652 }
1653 else {
1654 if (parent.has_value())
1655 parent.value()->add_relationship(
1656 {relationship_t::kDependency,
1657 nested_template_instantiation->id()});
1658 }
1659 }
1660 }
1661
1662 if (diagram().should_include(
1663 namespace_{nested_template_instantiation_full_name})) {
1664 visitor_.set_source_location(*cls, *nested_template_instantiation);
1665 visitor_.add_diagram_element(std::move(nested_template_instantiation));
1666 }
1667
1668 return argument;
1669}

◆ try_as_typedef_type()

template<typename VisitorT >
std::optional< template_parameter > clanguml::common::visitor::template_builder< VisitorT >::try_as_typedef_type ( std::optional< clanguml::common::model::template_element * > &  parent,
const clang::NamedDecl *  cls,
const clang::TemplateDecl *  template_decl,
clang::QualType &  type,
clanguml::common::model::template_element template_instantiation,
size_t  argument_index 
)

Try to process template type argument as typedef/using type.

Parameters
parentOptional class in which this template is contained
clsTemplate class specialization declaration
template_declBase template declaration
typeTemplate type
template_instantiationTemplate class model
argument_indexArgument index
Returns
Typedef type template argument if succeeds, or std::nullopt

Definition at line 1536 of file template_builder.h.

1542{
1543 const auto *typedef_type =
1544 common::dereference(type)->getAs<clang::TypedefType>();
1545 if (typedef_type == nullptr) {
1546 return {};
1547 }
1548
1549 LOG_DBG("Template argument is a typedef/using");
1550
1551 // If this is a typedef/using alias to a decltype - we're not able
1552 // to figure out anything out of it probably
1553 if (typedef_type->getAs<clang::DecltypeType>() != nullptr) {
1554 // Here we need to figure out the parent context of this alias,
1555 // it can be a:
1556 // - class/struct
1557 if (typedef_type->getDecl()->isCXXClassMember() && parent) {
1559 fmt::format("{}::{}", parent.value()->full_name(false),
1560 typedef_type->getDecl()->getNameAsString()));
1561 }
1562 // - namespace
1564 typedef_type->getDecl()->getQualifiedNameAsString());
1565 }
1566
1567 return {};
1568}

◆ using_namespace()

template<typename VisitorT >
const namespace_ & clanguml::common::visitor::template_builder< VisitorT >::using_namespace

Get diagram relative namespace.

Returns
Diagram relative namespace

Definition at line 582 of file template_builder.h.

583{
584 return config_.using_namespace();
585}

Member Data Documentation

◆ config_

template<typename VisitorT >
const clanguml::config::diagram& clanguml::common::visitor::template_builder< VisitorT >::config_
private

Definition at line 548 of file template_builder.h.

◆ diagram_

template<typename VisitorT >
clanguml::common::model::diagram& clanguml::common::visitor::template_builder< VisitorT >::diagram_
private

Definition at line 545 of file template_builder.h.

◆ id_mapper_

template<typename VisitorT >
common::visitor::ast_id_mapper& clanguml::common::visitor::template_builder< VisitorT >::id_mapper_
private

Definition at line 550 of file template_builder.h.

◆ source_manager_

template<typename VisitorT >
clang::SourceManager& clanguml::common::visitor::template_builder< VisitorT >::source_manager_
private

Definition at line 552 of file template_builder.h.

◆ visitor_

template<typename VisitorT >
VisitorT& clanguml::common::visitor::template_builder< VisitorT >::visitor_
private

Definition at line 554 of file template_builder.h.


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