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

1902{
1903 bool add_template_argument_as_base_class = false;
1904
1905 if (variadic_params) {
1906 add_template_argument_as_base_class = true;
1907 }
1908 else {
1909 auto [arg_name, index, is_variadic] = template_base_params.front();
1910
1911 variadic_params = is_variadic;
1912 if ((arg_index == index) || (is_variadic && arg_index >= index)) {
1913 add_template_argument_as_base_class = true;
1914 if (!is_variadic) {
1915 // Don't remove the remaining variadic parameter
1916 template_base_params.pop_front();
1917 }
1918 }
1919 }
1920
1921 const auto maybe_id = ct.id();
1922 if (add_template_argument_as_base_class && maybe_id) {
1923 LOG_DBG("Adding template argument as base class '{}'",
1924 ct.to_string({}, false));
1925
1926 dynamic_cast<class_diagram::model::class_ &>(tinst).add_relationship(
1927 common::model::relationship{
1928 maybe_id.value(), common::model::access_t::kPublic, false});
1929 }
1930
1931 return variadic_params;
1932}

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

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

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

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

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

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

◆ 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 template_type_parameter->getTypeConstraint()
669 ->getNamedConcept(),
670 [this, &ct, &templated_element](
671 const clang::ConceptDecl *named_concept) mutable {
672 ct.set_concept_constraint(
673 named_concept->getQualifiedNameAsString());
674 if (templated_element &&
675 visitor_.should_include(named_concept)) {
676 templated_element.value().add_relationship(
677 {relationship_t::kConstraint,
678 id_mapper()
679 .get_global_id(
680 eid_t{named_concept->getID()})
681 .value(),
682 model::access_t::kNone,
683 ct.name().value()});
684 }
685 });
686 }
687 }
688 else {
689 (void)templated_element; // NOLINT
690 }
691
692 template_model.add_template(std::move(ct));
693 }
694 else if (clang::dyn_cast_or_null<clang::NonTypeTemplateParmDecl>(
695 parameter) != nullptr) {
696 const auto *template_nontype_parameter =
697 clang::dyn_cast_or_null<clang::NonTypeTemplateParmDecl>(
698 parameter);
699
700 std::optional<std::string> default_arg;
701
702 if (template_nontype_parameter->hasDefaultArgument()) {
703 default_arg =
704#if LLVM_VERSION_MAJOR > 18
706 template_nontype_parameter->getDefaultArgument(),
707 template_declaration.getASTContext());
708#else
710 template_nontype_parameter->getDefaultArgument());
711#endif
712 }
714 template_nontype_parameter->getType().getAsString(),
715 template_nontype_parameter->getNameAsString(), default_arg,
716 template_nontype_parameter->isParameterPack());
717
718 template_model.add_template(std::move(ct));
719 }
720 else if (clang::dyn_cast_or_null<clang::TemplateTemplateParmDecl>(
721 parameter) != nullptr) {
722 const auto *template_template_parameter =
723 clang::dyn_cast_or_null<clang::TemplateTemplateParmDecl>(
724 parameter);
725 std::optional<std::string> default_arg;
726 if (template_template_parameter->hasDefaultArgument()) {
727 default_arg = common::to_string(
728 template_template_parameter->getDefaultArgument()
729 .getArgument());
730 }
732 template_template_parameter->getNameAsString(), default_arg,
733 template_template_parameter->isParameterPack());
734
735 template_model.add_template(std::move(ct));
736 }
737 else {
738 // pass
739 }
740 }
741}

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

750{
751 const auto *template_type_ptr = &template_type_decl;
752
753 if (template_type_decl.isTypeAlias()) {
754 if (const auto *tsp =
755 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 std::string full_template_specialization_name = common::to_string(
766 template_type.desugar(),
767 template_type.getTemplateName().getAsTemplateDecl()->getASTContext());
768
769 auto *template_decl{template_type.getTemplateName().getAsTemplateDecl()};
770
771 build(location_declaration, template_instantiation, cls, template_decl,
772 template_type.template_arguments(), full_template_specialization_name,
773 parent);
774}

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

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

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

953{
954 visitor_.find_instantiation_relationships(
955 template_instantiation, qualified_name, id);
956}

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

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

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

1327{
1328 assert(arg.getKind() == clang::TemplateArgument::Expression);
1330 arg.getAsExpr()->getSourceRange(), source_manager()));
1331}

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

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

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

1307{
1308 assert(arg.getKind() == clang::TemplateArgument::Null);
1309
1311}

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

1316{
1317 assert(arg.getKind() == clang::TemplateArgument::NullPtr);
1318
1319 LOG_DBG("Processing nullptr argument: {}", common::to_string(arg));
1320
1321 return template_parameter::make_argument("nullptr");
1322}

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

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

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

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

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

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

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

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

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

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

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

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

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

1881{
1882 const auto *builtin_type = type->getAs<clang::BuiltinType>();
1883 if (builtin_type == nullptr)
1884 return {};
1885
1886 LOG_DBG("Template argument is a builtin type");
1887
1888 auto type_name = common::to_string(type, template_decl->getASTContext());
1890
1891 type = consume_context(type, argument);
1892 argument.set_type(type_name);
1893
1894 return argument;
1895}

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

1554{
1555 const auto *decl_type =
1556 common::dereference(type)->getAs<clang::DecltypeType>();
1557 if (decl_type == nullptr) {
1558 return {};
1559 }
1560
1561 LOG_DBG("Template argument is a decltype()");
1562
1563 // TODO
1564 return {};
1565}

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

1852{
1853 const auto *enum_type = type->getAs<clang::EnumType>();
1854 if (enum_type == nullptr)
1855 return {};
1856
1857 LOG_DBG("Template argument is a an enum");
1858
1860 type = consume_context(type, argument);
1861
1862 auto type_name = common::to_string(type, template_decl->getASTContext());
1863 argument.set_type(type_name);
1864 const auto type_id = common::to_id(type_name);
1865 argument.set_id(type_id);
1866
1867 if (enum_type->getAsTagDecl() != nullptr &&
1869 template_instantiation.add_relationship(
1870 {relationship_t::kDependency, type_id});
1871 }
1872
1873 return argument;
1874}

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

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

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

1755{
1756 auto type_name = common::to_string(type, &cls->getASTContext());
1757
1758 if (type_name.find("(lambda at ") != 0)
1759 return {};
1760
1761 LOG_DBG("Template argument is a lambda");
1762
1764 type = consume_context(type, argument);
1765
1767 argument.set_type(type_name);
1768
1769 return argument;
1770}

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

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

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

1781{
1782 const auto *record_type =
1783 common::dereference(type)->getAs<clang::RecordType>();
1784 if (record_type == nullptr)
1785 return {};
1786
1787 LOG_DBG("Template argument is a c++ record");
1788
1790 type = consume_context(type, argument);
1791
1792 const auto type_name = config().simplify_template_type(
1793 common::to_string(type, template_decl->getASTContext()));
1794
1795 argument.set_type(type_name);
1796 const auto type_id = common::to_id(type_name);
1797
1798 argument.set_id(type_id);
1799
1800 const auto *class_template_specialization =
1801 clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(
1802 record_type->getAsRecordDecl());
1803
1804 if (class_template_specialization != nullptr) {
1805 auto tag_argument =
1806 visitor_.create_element(class_template_specialization);
1807
1809 *tag_argument, *class_template_specialization);
1810
1811 tag_argument->is_template(true);
1812
1813 if (tag_argument) {
1814 argument.set_type(tag_argument->name_and_ns());
1815 for (const auto &p : tag_argument->template_params())
1816 argument.add_template_param(p);
1817 for (auto &r : tag_argument->relationships()) {
1818 template_instantiation.add_relationship(std::move(r));
1819 }
1820
1822 diagram().should_include(tag_argument->get_namespace())) {
1823 if (parent.has_value())
1824 parent.value()->add_relationship(
1825 {relationship_t::kDependency, tag_argument->id()});
1826
1827 visitor_.set_source_location(location_decl, *tag_argument);
1828 visitor_.add_diagram_element(std::move(tag_argument));
1829 }
1830 }
1831 }
1832 else if (const auto *record_type_decl = record_type->getAsRecordDecl();
1833 record_type_decl != nullptr) {
1835 diagram().should_include(namespace_{type_name})) {
1836 // Add dependency relationship to the parent
1837 // template
1838 template_instantiation.add_relationship(
1839 {relationship_t::kDependency, type_id});
1840 }
1841 }
1842
1843 return argument;
1844}

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

1711{
1712 auto is_variadic{false};
1713
1714 const auto *type_parameter =
1715 common::dereference(type)->getAs<clang::TemplateTypeParmType>();
1716
1717 auto type_name = common::to_string(type, &cls->getASTContext());
1718
1719 if (type_parameter == nullptr) {
1720 if (const auto *pet =
1721 common::dereference(type)->getAs<clang::PackExpansionType>();
1722 pet != nullptr) {
1723 is_variadic = true;
1724 type_parameter =
1725 pet->getPattern()->getAs<clang::TemplateTypeParmType>();
1726 }
1727 }
1728
1729 if (type_parameter == nullptr)
1730 return {};
1731
1732 LOG_DBG("Template argument is a template parameter type");
1733
1735 type = consume_context(type, argument);
1736
1737 auto type_parameter_name = common::to_string(type, cls->getASTContext());
1738 if (type_parameter_name.empty())
1739 type_parameter_name = "typename";
1740
1742 cls, type_parameter_name));
1743
1744 argument.is_variadic(is_variadic);
1745
1746 common::ensure_lambda_type_is_relative(config(), type_parameter_name);
1747
1748 return argument;
1749}

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

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

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

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

◆ 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: