0.6.3
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 (const clang::NamedDecl &location_declaration, 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 (const clang::NamedDecl &location_declaration, 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 (const clang::NamedDecl &location_decl, 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 (const clang::NamedDecl &location_decl, 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 (const clang::NamedDecl &location_decl, 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 (const clang::NamedDecl &location_decl, 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 (const clang::NamedDecl &location_decl, 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 (const clang::NamedDecl &location_decl, 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 (const clang::NamedDecl &location_decl, 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 (const clang::NamedDecl &location_decl, 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 (const clang::NamedDecl &location_decl, 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 566 of file template_builder.h.

571 , id_mapper_{visitor.id_mapper()}
572 , source_manager_{visitor.source_manager()}
573 , visitor_{visitor}
574{
575}

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 1939 of file template_builder.h.

1943{
1944 bool add_template_argument_as_base_class = false;
1945
1946 if (variadic_params) {
1947 add_template_argument_as_base_class = true;
1948 }
1949 else {
1950 auto [arg_name, index, is_variadic] = template_base_params.front();
1951
1952 variadic_params = is_variadic;
1953 if ((arg_index == index) || (is_variadic && arg_index >= index)) {
1954 add_template_argument_as_base_class = true;
1955 if (!is_variadic) {
1956 // Don't remove the remaining variadic parameter
1957 template_base_params.pop_front();
1958 }
1959 }
1960 }
1961
1962 const auto maybe_id = ct.id();
1963 if (add_template_argument_as_base_class && maybe_id) {
1964 LOG_DBG("Adding template argument as base class '{}'",
1965 ct.to_string({}, false));
1966
1967 dynamic_cast<class_diagram::model::class_ &>(tinst).add_relationship(
1968 common::model::relationship{
1969 maybe_id.value(), common::model::access_t::kPublic, false});
1970 }
1971
1972 return variadic_params;
1973}

◆ argument_process_dispatch()

template<typename VisitorT >
void clanguml::common::visitor::template_builder< VisitorT >::argument_process_dispatch ( const clang::NamedDecl &  location_decl,
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 1055 of file template_builder.h.

1063{
1064 LOG_DBG("Processing argument {} in template class: {}", argument_index,
1065 cls->getQualifiedNameAsString());
1066
1067 switch (arg.getKind()) {
1068 case clang::TemplateArgument::Null:
1069 argument.push_back(process_null_argument(arg));
1070 break;
1071 case clang::TemplateArgument::Template:
1072 argument.push_back(process_template_argument(arg));
1073 break;
1074 case clang::TemplateArgument::Type: {
1075 argument.push_back(
1076 process_type_argument(location_decl, parent, cls, template_decl,
1077 arg.getAsType(), template_instantiation, argument_index));
1078 break;
1079 }
1080 case clang::TemplateArgument::Declaration:
1081 break;
1082 case clang::TemplateArgument::NullPtr:
1083 argument.push_back(process_nullptr_argument(arg));
1084 break;
1085 case clang::TemplateArgument::Integral:
1086 argument.push_back(
1087 process_integral_argument(arg, template_decl->getASTContext()));
1088 break;
1089 case clang::TemplateArgument::TemplateExpansion:
1090 argument.push_back(process_template_expansion(arg));
1091 break;
1092 case clang::TemplateArgument::Expression:
1093 argument.push_back(process_expression_argument(arg));
1094 break;
1095 case clang::TemplateArgument::Pack:
1096 for (auto &a : process_pack_argument(location_decl, parent, cls,
1097 template_instantiation, template_decl, arg, argument_index,
1098 argument)) {
1099 argument.push_back(a);
1100 }
1101 break;
1102#if LLVM_VERSION_MAJOR > 17
1103 case clang::TemplateArgument::StructuralValue:
1104 break;
1105#endif
1106 }
1107}

◆ build()

template<typename VisitorT >
void clanguml::common::visitor::template_builder< VisitorT >::build ( const clang::NamedDecl &  location_declaration,
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 779 of file template_builder.h.

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

◆ 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 906 of file template_builder.h.

910{
911 LOG_DBG("Building class template specialization model: {}",
912 template_specialization.getQualifiedNameAsString());
913
914 //
915 // Here we'll hold the template base params to replace with the
916 // instantiated values
917 //
918 std::deque<std::tuple</*parameter name*/ std::string, /* position */ int,
919 /*is variadic */ bool>>
920 template_base_params{};
921
922 const clang::ClassTemplateDecl *template_decl =
923 template_specialization.getSpecializedTemplate();
924
925 auto qualified_name = template_decl->getQualifiedNameAsString();
926
927 namespace_ ns{qualified_name};
928 ns.pop_back();
929 template_instantiation.set_name(template_decl->getNameAsString());
930 template_instantiation.set_namespace(ns);
931
932 process_template_arguments(template_specialization, parent,
933 &template_specialization, template_base_params,
934 template_specialization.getTemplateArgs().asArray(),
935 template_instantiation, template_decl);
936
937 // Update the id after the template parameters are processed
938 template_instantiation.set_id(
939 common::to_id(template_instantiation.full_name(false)));
940
941 if constexpr (std::is_same_v<typename VisitorT::diagram_t,
942 class_diagram::model::diagram>) {
943 find_instantiation_relationships(template_instantiation,
944 eid_t{template_specialization.getID()}, qualified_name);
945 }
946
947 visitor_.set_source_location(
948 template_specialization, template_instantiation);
949}

◆ 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 627 of file template_builder.h.

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

◆ build_from_template_specialization_type()

template<typename VisitorT >
void clanguml::common::visitor::template_builder< VisitorT >::build_from_template_specialization_type ( const clang::NamedDecl &  location_declaration,
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 745 of file template_builder.h.

751{
752 const auto *template_type_ptr = &template_type_decl;
753
754 if (template_type_decl.isTypeAlias()) {
755 if (const auto *tsp = template_type_decl.getAliasedType()
756 ->template getAs<clang::TemplateSpecializationType>();
757 tsp != nullptr)
758 template_type_ptr = tsp;
759 }
760
761 const auto &template_type = *template_type_ptr;
762
763 template_instantiation.is_template(true);
764
765 auto *template_decl{template_type.getTemplateName().getAsTemplateDecl()};
766
767 if (template_decl == nullptr)
768 return;
769
770 std::string full_template_specialization_name = common::to_string(
771 template_type.desugar(), template_decl->getASTContext());
772
773 build(location_declaration, template_instantiation, cls, template_decl,
774 template_type.template_arguments(), full_template_specialization_name,
775 parent);
776}

◆ 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 584 of file template_builder.h.

585{
586 return config_;
587}

◆ 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 1140 of file template_builder.h.

1142{
1143 auto [unqualified_type, context] = common::consume_type_context(type);
1144
1145 tp.deduced_context(std::move(context));
1146
1147 return unqualified_type;
1148}

◆ 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 578 of file template_builder.h.

579{
580 return diagram_;
581}

◆ 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 952 of file template_builder.h.

955{
956 visitor_.find_instantiation_relationships(
957 template_instantiation, qualified_name, id);
958}

◆ 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 1231 of file template_builder.h.

1234{
1235 const auto &type = ct.type();
1236
1237 if (!type)
1238 return false;
1239
1240 bool found{false};
1241 LOG_DBG("Finding relationships in user defined type: {}",
1242 ct.to_string(config().using_namespace(), false));
1243
1244 auto type_with_namespace =
1245 std::make_optional<common::model::namespace_>(type.value());
1246
1247 if (!type_with_namespace.has_value()) {
1248 // Couldn't find declaration of this type
1249 type_with_namespace = common::model::namespace_{type.value()};
1250 }
1251
1252 auto element_opt = diagram().get(type_with_namespace.value().to_string());
1253 if (config_.generate_template_argument_dependencies() && element_opt) {
1254 relationships.emplace_back(
1255 element_opt.value().id(), relationship_t::kDependency);
1256 found = true;
1257 }
1258
1259 for (const auto &nested_template_params : ct.template_params()) {
1261 nested_template_params, relationships) ||
1262 found;
1263 }
1264
1265 return found;
1266}

◆ 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 596 of file template_builder.h.

597{
598 return id_mapper_;
599}

◆ 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 1329 of file template_builder.h.

1331{
1332 assert(arg.getKind() == clang::TemplateArgument::Expression);
1334 arg.getAsExpr()->getSourceRange(), source_manager()));
1335}

◆ 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 1269 of file template_builder.h.

1271{
1272 assert(arg.getKind() == clang::TemplateArgument::Integral);
1273
1274 std::string result;
1275 llvm::raw_string_ostream ostream(result);
1276 clang::PrintingPolicy policy(ast_context.getLangOpts());
1277
1278#if LLVM_VERSION_MAJOR > 18
1279 arg.print(policy, ostream, false);
1280#else
1281 arg.dump(ostream);
1282#endif
1283
1284 return template_parameter::make_argument(result);
1285}

◆ 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 1309 of file template_builder.h.

1311{
1312 assert(arg.getKind() == clang::TemplateArgument::Null);
1313
1315}

◆ 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 1318 of file template_builder.h.

1320{
1321 assert(arg.getKind() == clang::TemplateArgument::NullPtr);
1322
1323 LOG_DBG("Processing nullptr argument: {}", common::to_string(arg));
1324
1325 return template_parameter::make_argument("nullptr");
1326}

◆ process_pack_argument()

template<typename VisitorT >
std::vector< template_parameter > clanguml::common::visitor::template_builder< VisitorT >::process_pack_argument ( const clang::NamedDecl &  location_decl,
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 1339 of file template_builder.h.

1347{
1348 assert(arg.getKind() == clang::TemplateArgument::Pack);
1349
1350 std::vector<template_parameter> res;
1351
1352 auto pack_argument_index = argument_index;
1353
1354 for (const auto &a : arg.getPackAsArray()) {
1355 argument_process_dispatch(location_decl, parent, cls,
1356 template_instantiation, base_template_decl, a,
1357 pack_argument_index++, res);
1358 }
1359
1360 return res;
1361}

◆ 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 1110 of file template_builder.h.

1112{
1113 auto arg_name = common::to_string(arg);
1114
1115 LOG_DBG("Processing template argument: {}", arg_name);
1116
1118}

◆ process_template_arguments()

template<typename VisitorT >
void clanguml::common::visitor::template_builder< VisitorT >::process_template_arguments ( const clang::NamedDecl &  location_decl,
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 961 of file template_builder.h.

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

◆ 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 1121 of file template_builder.h.

1123{
1124 auto arg_name = common::to_string(arg);
1125
1126 LOG_DBG("Processing template expansion argument: {}", arg_name);
1127
1129 arg.getAsTemplate().getAsTemplateDecl(), [&arg_name](const auto *decl) {
1130 arg_name = decl->getQualifiedNameAsString();
1131 });
1132
1133 auto param = template_parameter::make_template_type(arg_name);
1134 param.is_variadic(true);
1135
1136 return param;
1137}

◆ process_type_argument()

template<typename VisitorT >
template_parameter clanguml::common::visitor::template_builder< VisitorT >::process_type_argument ( const clang::NamedDecl &  location_decl,
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 1151 of file template_builder.h.

1158{
1159 std::optional<template_parameter> argument;
1160
1161#if LLVM_VERSION_MAJOR < 22
1162 if (type->getAs<clang::ElaboratedType>() != nullptr) {
1163 type = type->getAs<clang::ElaboratedType>()->getNamedType(); // NOLINT
1164 }
1165#endif
1166
1167 auto type_name = common::to_string(type, &cls->getASTContext());
1168
1169 LOG_DBG("Processing template {} type argument {}: {}, {}, {}",
1170 template_decl->getQualifiedNameAsString(), argument_index, type_name,
1171 type->getTypeClassName(),
1172 common::to_string(type, cls->getASTContext()));
1173
1174 argument = try_as_function_prototype(location_decl, parent, cls,
1175 template_decl, type, template_instantiation, argument_index);
1176 if (argument)
1177 return *argument;
1178
1179 argument = try_as_member_pointer(location_decl, parent, cls, template_decl,
1180 type, template_instantiation, argument_index);
1181 if (argument)
1182 return *argument;
1183
1184 argument = try_as_array(location_decl, parent, cls, template_decl, type,
1185 template_instantiation, argument_index);
1186 if (argument)
1187 return *argument;
1188
1189 argument = try_as_template_parm_type(cls, template_decl, type);
1190 if (argument)
1191 return *argument;
1192
1193 argument = try_as_template_specialization_type(location_decl, parent, cls,
1194 template_decl, type, template_instantiation, argument_index);
1195 if (argument)
1196 return *argument;
1197
1198 argument = try_as_decl_type(parent, cls, template_decl, type,
1199 template_instantiation, argument_index);
1200 if (argument)
1201 return *argument;
1202
1203 argument = try_as_typedef_type(parent, cls, template_decl, type,
1204 template_instantiation, argument_index);
1205 if (argument)
1206 return *argument;
1207
1208 argument = try_as_lambda(cls, template_decl, type);
1209 if (argument)
1210 return *argument;
1211
1212 argument = try_as_record_type(location_decl, parent, cls, template_decl,
1213 type, template_instantiation, argument_index);
1214 if (argument)
1215 return *argument;
1216
1218 parent, cls, template_decl, type, template_instantiation);
1219 if (argument)
1220 return *argument;
1221
1222 argument = try_as_builtin_type(parent, type, template_decl);
1223 if (argument)
1224 return *argument;
1225
1226 // fallback
1227 return template_parameter::make_argument(type_name);
1228}

◆ 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 608 of file template_builder.h.

610{
612 return false;
613
614 auto simplified = config().simplify_template_type(full_name);
615
616 if (simplified != full_name) {
617 ct.set_type(simplified);
618 ct.set_id(common::to_id(simplified));
619 ct.clear_params();
620 return true;
621 }
622
623 return false;
624}

◆ 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 602 of file template_builder.h.

603{
604 return source_manager_;
605}

◆ try_as_array()

template<typename VisitorT >
std::optional< template_parameter > clanguml::common::visitor::template_builder< VisitorT >::try_as_array ( const clang::NamedDecl &  location_decl,
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 1456 of file template_builder.h.

1463{
1464 const auto *array_type = common::dereference(type)->getAsArrayTypeUnsafe();
1465 if (array_type == nullptr)
1466 return {};
1467
1469
1470 type = consume_context(type, argument);
1471
1472 argument.is_array(true);
1473
1474 // Set function template return type
1475 auto element_type = process_type_argument(location_decl, parent, cls,
1476 template_decl, array_type->getElementType(), template_instantiation,
1477 argument_index);
1478
1479 argument.add_template_param(element_type);
1480
1481 if (array_type->isDependentSizedArrayType() &&
1482 array_type->getDependence() ==
1483 clang::TypeDependence::DependentInstantiation) {
1484 argument.add_template_param(
1486 ((clang::DependentSizedArrayType *)array_type) // NOLINT
1487 ->getSizeExpr())));
1488 }
1489 else if (array_type->isConstantArrayType()) {
1491 std::to_string(((clang::ConstantArrayType *)array_type) // NOLINT
1492 ->getSize()
1493 .getLimitedValue())));
1494 }
1495
1496 // TODO: Handle variable sized arrays
1497
1498 return argument;
1499}

◆ 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 1919 of file template_builder.h.

1922{
1923 const auto *builtin_type = type->getAs<clang::BuiltinType>();
1924 if (builtin_type == nullptr)
1925 return {};
1926
1927 LOG_DBG("Template argument is a builtin type");
1928
1929 auto type_name = common::to_string(type, template_decl->getASTContext());
1931
1932 type = consume_context(type, argument);
1933 argument.set_type(type_name);
1934
1935 return argument;
1936}

◆ 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 1556 of file template_builder.h.

1562{
1563 const auto *decl_type =
1564 common::dereference(type)->getAs<clang::DecltypeType>();
1565 if (decl_type == nullptr) {
1566 return {};
1567 }
1568
1569 LOG_DBG("Template argument is a decltype()");
1570
1571 // TODO
1572 return {};
1573}

◆ 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 1888 of file template_builder.h.

1893{
1894 const auto *enum_type = type->getAs<clang::EnumType>();
1895 if (enum_type == nullptr)
1896 return {};
1897
1898 LOG_DBG("Template argument is a an enum");
1899
1901 type = consume_context(type, argument);
1902
1903 auto type_name = common::to_string(type, template_decl->getASTContext());
1904 argument.set_type(type_name);
1905 const auto type_id = common::to_id(type_name);
1906 argument.set_id(type_id);
1907
1908 if (enum_type->getAsTagDecl() != nullptr &&
1910 template_instantiation.add_relationship(
1911 {relationship_t::kDependency, type_id});
1912 }
1913
1914 return argument;
1915}

◆ try_as_function_prototype()

template<typename VisitorT >
std::optional< template_parameter > clanguml::common::visitor::template_builder< VisitorT >::try_as_function_prototype ( const clang::NamedDecl &  location_decl,
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 1503 of file template_builder.h.

1510{
1511 const auto *function_type = type->getAs<clang::FunctionProtoType>();
1512
1513 if (function_type == nullptr && type->isFunctionPointerType()) {
1514 function_type =
1515 type->getPointeeType()->getAs<clang::FunctionProtoType>();
1516 if (function_type == nullptr)
1517 return {};
1518 }
1519
1520 if (function_type == nullptr)
1521 return {};
1522
1523 LOG_DBG("Template argument is a function prototype");
1524
1526
1527 type = consume_context(type, argument);
1528
1529 argument.is_function_template(true);
1530
1531 // Set function template return type
1532 auto return_arg = process_type_argument(location_decl, parent, cls,
1533 template_decl, function_type->getReturnType(), template_instantiation,
1534 argument_index);
1535
1536 argument.add_template_param(return_arg);
1537
1538 // Set function template argument types
1539 if (function_type->isVariadic() && function_type->param_types().empty()) {
1540 auto fallback_arg = template_parameter::make_argument({});
1541 fallback_arg.is_ellipsis(true);
1542 argument.add_template_param(std::move(fallback_arg));
1543 }
1544 else {
1545 for (const auto &param_type : function_type->param_types()) {
1546 argument.add_template_param(
1547 process_type_argument(location_decl, parent, cls, template_decl,
1548 param_type, template_instantiation, argument_index));
1549 }
1550 }
1551
1552 return argument;
1553}

◆ 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 1772 of file template_builder.h.

1775{
1776 auto type_name = common::to_string(type, &cls->getASTContext());
1777
1778 if (type_name.find("(lambda at ") != 0)
1779 return {};
1780
1781 LOG_DBG("Template argument is a lambda");
1782
1784 type = consume_context(type, argument);
1785
1787 argument.set_type(type_name);
1788
1789 return argument;
1790}

◆ try_as_member_pointer()

template<typename VisitorT >
std::optional< template_parameter > clanguml::common::visitor::template_builder< VisitorT >::try_as_member_pointer ( const clang::NamedDecl &  location_decl,
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 1365 of file template_builder.h.

1372{
1373 const auto *mp_type =
1374 common::dereference(type)->getAs<clang::MemberPointerType>();
1375 if (mp_type == nullptr)
1376 return {};
1377
1379 type = consume_context(type, argument);
1380
1381 // Handle a pointer to a data member of a class
1382 if (mp_type->isMemberDataPointer()) {
1383 argument.is_member_pointer(false);
1384 argument.is_data_pointer(true);
1385
1386 auto pointee_arg = process_type_argument(location_decl, parent, cls,
1387 template_decl, mp_type->getPointeeType(), template_instantiation,
1388 argument_index);
1389
1390 argument.add_template_param(std::move(pointee_arg));
1391
1392#if LLVM_VERSION_MAJOR < 21
1393 const auto *member_class_type = mp_type->getClass();
1394#elif LLVM_VERSION_MAJOR < 22
1395 const auto *member_class_type = mp_type->getQualifier()->getAsType();
1396#else
1397 const auto *member_class_type = mp_type->getQualifier().getAsType();
1398#endif
1399
1400 if (member_class_type == nullptr)
1401 return {};
1402
1403 auto class_type_arg = process_type_argument(location_decl, parent, cls,
1404 template_decl, member_class_type->getCanonicalTypeUnqualified(),
1405 template_instantiation, argument_index);
1406
1407 argument.add_template_param(std::move(class_type_arg));
1408 }
1409 // Handle pointer to class method member
1410 else {
1411 argument.is_member_pointer(true);
1412 argument.is_data_pointer(false);
1413
1414 const auto *function_type =
1415 mp_type->getPointeeType()->getAs<clang::FunctionProtoType>();
1416
1417 assert(function_type != nullptr);
1418
1419 auto return_type_arg = process_type_argument(location_decl, parent, cls,
1420 template_decl, function_type->getReturnType(),
1421 template_instantiation, argument_index);
1422
1423 // Add return type argument
1424 argument.add_template_param(std::move(return_type_arg));
1425
1426#if LLVM_VERSION_MAJOR < 21
1427 const auto *member_class_type = mp_type->getClass();
1428#elif LLVM_VERSION_MAJOR < 22
1429 const auto *member_class_type = mp_type->getQualifier()->getAsType();
1430#else
1431 const auto *member_class_type = mp_type->getQualifier().getAsType();
1432#endif
1433
1434 if (member_class_type == nullptr)
1435 return {};
1436
1437 auto class_type_arg = process_type_argument(location_decl, parent, cls,
1438 template_decl, member_class_type->getCanonicalTypeUnqualified(),
1439 template_instantiation, argument_index);
1440
1441 // Add class type argument
1442 argument.add_template_param(std::move(class_type_arg));
1443
1444 // Add argument types
1445 for (const auto &param_type : function_type->param_types()) {
1446 argument.add_template_param(
1447 process_type_argument(location_decl, parent, cls, template_decl,
1448 param_type, template_instantiation, argument_index));
1449 }
1450 }
1451
1452 return argument;
1453}

◆ try_as_record_type()

template<typename VisitorT >
std::optional< template_parameter > clanguml::common::visitor::template_builder< VisitorT >::try_as_record_type ( const clang::NamedDecl &  location_decl,
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 1794 of file template_builder.h.

1801{
1802 const auto *record_type =
1803 common::dereference(type)->getAs<clang::RecordType>();
1804 if (record_type == nullptr)
1805 return {};
1806
1807 LOG_DBG("Template argument is a c++ record");
1808
1810 type = consume_context(type, argument);
1811
1812 const auto type_name = config().simplify_template_type(
1813 common::to_string(type, template_decl->getASTContext()));
1814
1815 argument.set_type(type_name);
1816 const auto type_id = common::to_id(type_name);
1817
1818 argument.set_id(type_id);
1819
1820 const auto *class_template_specialization =
1821 clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(
1822 record_type->getAsRecordDecl());
1823
1824 if (class_template_specialization != nullptr) {
1825 auto tag_argument =
1826 visitor_.create_element(class_template_specialization);
1827
1829 *tag_argument, *class_template_specialization);
1830
1831 tag_argument->is_template(true);
1832
1833 if (tag_argument) {
1834 argument.set_type(tag_argument->name_and_ns());
1835 for (const auto &p : tag_argument->template_params())
1836 argument.add_template_param(p);
1837 for (auto &r : tag_argument->relationships()) {
1838 template_instantiation.add_relationship(std::move(r));
1839 }
1840
1842 diagram().should_include(tag_argument->get_namespace())) {
1843 if (parent.has_value())
1844 parent.value()->add_relationship(
1845 {relationship_t::kDependency, tag_argument->id()});
1846
1847 visitor_.set_source_location(location_decl, *tag_argument);
1848 visitor_.add_diagram_element(std::move(tag_argument));
1849 }
1850 }
1851 }
1852 else if (const auto *record_type_decl = record_type->getAsRecordDecl();
1853 record_type_decl != nullptr) {
1854#if LLVM_VERSION_MAJOR >= 22
1855 // In LLVM 22+, non-template record types used as template arguments
1856 // may be printed without full namespace qualification by to_string().
1857 // Use the decl's qualified name to ensure proper namespace resolution.
1858 const auto qualified_name = config().simplify_template_type(
1859 record_type_decl->getQualifiedNameAsString());
1860 if (!qualified_name.empty() && qualified_name != type_name) {
1861 argument.set_type(qualified_name);
1862 argument.set_id(common::to_id(qualified_name));
1863 }
1864 const auto &effective_type_name =
1865 qualified_name.empty() ? type_name : qualified_name;
1866 const auto effective_type_id =
1867 qualified_name.empty() ? type_id : common::to_id(qualified_name);
1869 diagram().should_include(namespace_{effective_type_name})) {
1870 template_instantiation.add_relationship(
1871 {relationship_t::kDependency, effective_type_id});
1872 }
1873#else
1875 diagram().should_include(namespace_{type_name})) {
1876 // Add dependency relationship to the parent
1877 // template
1878 template_instantiation.add_relationship(
1879 {relationship_t::kDependency, type_id});
1880 }
1881#endif
1882 }
1883
1884 return argument;
1885}

◆ 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 1719 of file template_builder.h.

1722{
1723 auto is_variadic{false};
1724
1725 const auto *type_parameter =
1726 common::dereference(type)->getAs<clang::TemplateTypeParmType>();
1727
1728 auto type_name = common::to_string(type, &cls->getASTContext());
1729
1730 if (type_parameter == nullptr) {
1731 if (const auto *pet =
1732 common::dereference(type)->getAs<clang::PackExpansionType>();
1733 pet != nullptr) {
1734 is_variadic = true;
1735 type_parameter =
1736 pet->getPattern()->getAs<clang::TemplateTypeParmType>();
1737 }
1738 }
1739
1740 if (type_parameter == nullptr)
1741 return {};
1742
1743 LOG_DBG("Template argument is a template parameter type");
1744
1746 type = consume_context(type, argument);
1747
1748 auto type_parameter_name = common::to_string(type, cls->getASTContext());
1749 if (type_parameter_name.empty())
1750 type_parameter_name = "typename";
1751
1752 const auto *type_concept_constraint =
1754 type_parameter, template_decl);
1755
1756 if (type_concept_constraint != nullptr) {
1757 argument.set_concept_constraint(
1758 type_concept_constraint->getQualifiedNameAsString());
1759 }
1760
1762 cls, type_parameter_name));
1763
1764 argument.is_variadic(is_variadic);
1765
1766 common::ensure_lambda_type_is_relative(config(), type_parameter_name);
1767
1768 return argument;
1769}

◆ try_as_template_specialization_type()

template<typename VisitorT >
std::optional< template_parameter > clanguml::common::visitor::template_builder< VisitorT >::try_as_template_specialization_type ( const clang::NamedDecl &  location_decl,
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 1613 of file template_builder.h.

1620{
1621 const auto *nested_template_type =
1622 common::dereference(type)->getAs<clang::TemplateSpecializationType>();
1623 if (nested_template_type == nullptr) {
1624 return {};
1625 }
1626
1627 LOG_DBG("Template argument is a template specialization type");
1628
1629 if (nested_template_type->getTemplateName().getAsTemplateDecl() == nullptr)
1630 return {};
1631
1633 type = consume_context(type, argument);
1634
1635 auto nested_type_name = nested_template_type->getTemplateName()
1636 .getAsTemplateDecl()
1637 ->getQualifiedNameAsString();
1638
1639 if (clang::dyn_cast<clang::TemplateTemplateParmDecl>(
1640 nested_template_type->getTemplateName().getAsTemplateDecl()) !=
1641 nullptr) {
1642 if (const auto *template_specialization_decl =
1643 clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(cls);
1644 template_specialization_decl != nullptr) {
1645 nested_type_name =
1646 template_specialization_decl->getDescribedTemplateParams()
1647 ->getParam(argument_index)
1648 ->getNameAsString();
1649 }
1650 else {
1651 // fallback
1652 nested_type_name = "template";
1653 }
1654
1655 argument.is_template_template_parameter(true);
1656 }
1657
1658 argument.set_type(nested_type_name);
1659
1660 auto nested_template_instantiation =
1661 visitor_.create_element(nested_template_type->getTemplateName()
1662 .getAsTemplateDecl()
1663 ->getTemplatedDecl());
1665 *nested_template_instantiation, cls, *nested_template_type,
1666 diagram().should_include(
1667 namespace_{template_decl->getQualifiedNameAsString()})
1668 ? std::make_optional(&template_instantiation)
1669 : parent);
1670
1671 argument.set_id(nested_template_instantiation->id());
1672
1673 for (const auto &t : nested_template_instantiation->template_params())
1674 argument.add_template_param(t);
1675
1676 // Check if this template should be simplified (e.g. system
1677 // template aliases such as 'std:basic_string<char>' should
1678 // be simply 'std::string')
1680 argument, argument.to_string(using_namespace(), false));
1681
1682 argument.set_id(
1683 common::to_id(argument.to_string(using_namespace(), false)));
1684
1685 const auto nested_template_instantiation_full_name =
1686 nested_template_instantiation->full_name(false);
1687
1688 if (nested_template_instantiation &&
1689 diagram().should_include(
1690 namespace_{nested_template_instantiation_full_name})) {
1692 if (diagram().should_include(
1693 namespace_{template_decl->getQualifiedNameAsString()})) {
1694 template_instantiation.add_relationship(
1695 {relationship_t::kDependency,
1696 nested_template_instantiation->id()});
1697 }
1698 else {
1699 if (parent.has_value())
1700 parent.value()->add_relationship(
1701 {relationship_t::kDependency,
1702 nested_template_instantiation->id()});
1703 }
1704 }
1705 }
1706
1707 if (diagram().should_include(
1708 namespace_{nested_template_instantiation_full_name})) {
1709 visitor_.set_source_location(
1710 location_decl, *nested_template_instantiation);
1711 visitor_.add_diagram_element(std::move(nested_template_instantiation));
1712 }
1713
1714 return argument;
1715}

◆ 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 1577 of file template_builder.h.

1583{
1584 const auto *typedef_type =
1585 common::dereference(type)->getAs<clang::TypedefType>();
1586 if (typedef_type == nullptr) {
1587 return {};
1588 }
1589
1590 LOG_DBG("Template argument is a typedef/using");
1591
1592 // If this is a typedef/using alias to a decltype - we're not able
1593 // to figure out anything out of it probably
1594 if (typedef_type->getAs<clang::DecltypeType>() != nullptr) {
1595 // Here we need to figure out the parent context of this alias,
1596 // it can be a:
1597 // - class/struct
1598 if (typedef_type->getDecl()->isCXXClassMember() && parent) {
1600 fmt::format("{}::{}", parent.value()->full_name(false),
1601 typedef_type->getDecl()->getNameAsString()));
1602 }
1603 // - namespace
1605 typedef_type->getDecl()->getQualifiedNameAsString());
1606 }
1607
1608 return {};
1609}

◆ 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 590 of file template_builder.h.

591{
592 return config_.using_namespace();
593}

Member Data Documentation

◆ config_

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

Definition at line 556 of file template_builder.h.

◆ diagram_

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

Definition at line 553 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 558 of file template_builder.h.

◆ source_manager_

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

Definition at line 560 of file template_builder.h.

◆ visitor_

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

Definition at line 562 of file template_builder.h.


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