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

#include <template_builder.h>

Public Member Functions

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

Private Attributes

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

Constructor & Destructor Documentation

◆ template_builder()

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

Constructor.

Parameters
visitorReference to class diagram translation_unit_visitor

Definition at line 559 of file template_builder.h.

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

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

1831{
1832 bool add_template_argument_as_base_class = false;
1833
1834 if (variadic_params) {
1835 add_template_argument_as_base_class = true;
1836 }
1837 else {
1838 auto [arg_name, index, is_variadic] = template_base_params.front();
1839
1840 variadic_params = is_variadic;
1841 if ((arg_index == index) || (is_variadic && arg_index >= index)) {
1842 add_template_argument_as_base_class = true;
1843 if (!is_variadic) {
1844 // Don't remove the remaining variadic parameter
1845 template_base_params.pop_front();
1846 }
1847 }
1848 }
1849
1850 const auto maybe_id = ct.id();
1851 if (add_template_argument_as_base_class && maybe_id) {
1852 LOG_DBG("Adding template argument as base class '{}'",
1853 ct.to_string({}, false));
1854
1855 class_diagram::model::class_parent cp;
1856 cp.set_access(common::model::access_t::kPublic);
1857 cp.set_name(ct.to_string({}, false));
1858 cp.set_id(maybe_id.value());
1859
1860 dynamic_cast<class_diagram::model::class_ &>(tinst).add_parent(
1861 std::move(cp));
1862 }
1863
1864 return variadic_params;
1865}

◆ argument_process_dispatch()

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

Process template arguments based on their type.

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

Definition at line 1020 of file template_builder.h.

1027{
1028 LOG_DBG("Processing argument {} in template class: {}", argument_index,
1029 cls->getQualifiedNameAsString());
1030
1031 switch (arg.getKind()) {
1032 case clang::TemplateArgument::Null:
1033 argument.push_back(process_null_argument(arg));
1034 break;
1035 case clang::TemplateArgument::Template:
1036 argument.push_back(process_template_argument(arg));
1037 break;
1038 case clang::TemplateArgument::Type: {
1039 argument.push_back(process_type_argument(parent, cls, template_decl,
1040 arg.getAsType(), template_instantiation, argument_index));
1041 break;
1042 }
1043 case clang::TemplateArgument::Declaration:
1044 break;
1045 case clang::TemplateArgument::NullPtr:
1046 argument.push_back(process_nullptr_argument(arg));
1047 break;
1048 case clang::TemplateArgument::Integral:
1049 argument.push_back(process_integral_argument(arg));
1050 break;
1051 case clang::TemplateArgument::TemplateExpansion:
1052 argument.push_back(process_template_expansion(arg));
1053 break;
1054 case clang::TemplateArgument::Expression:
1055 argument.push_back(process_expression_argument(arg));
1056 break;
1057 case clang::TemplateArgument::Pack:
1058 for (auto &a :
1059 process_pack_argument(parent, cls, template_instantiation,
1060 template_decl, arg, argument_index, argument)) {
1061 argument.push_back(a);
1062 }
1063 break;
1064#if LLVM_VERSION_MAJOR > 17
1065 case clang::TemplateArgument::StructuralValue:
1066 break;
1067#endif
1068 }
1069}

◆ build()

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

Definition at line 756 of file template_builder.h.

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

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

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

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

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

◆ build_from_template_specialization_type()

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

Basic template class build method.

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

Definition at line 724 of file template_builder.h.

729{
730 const auto *template_type_ptr = &template_type_decl;
731
732 if (template_type_decl.isTypeAlias()) {
733 if (const auto *tsp =
734 template_type_decl.getAliasedType()
735 ->template getAs<clang::TemplateSpecializationType>();
736 tsp != nullptr)
737 template_type_ptr = tsp;
738 }
739
740 const auto &template_type = *template_type_ptr;
741
742 template_instantiation.is_template(true);
743
744 std::string full_template_specialization_name = common::to_string(
745 template_type.desugar(),
746 template_type.getTemplateName().getAsTemplateDecl()->getASTContext());
747
748 auto *template_decl{template_type.getTemplateName().getAsTemplateDecl()};
749
750 build(template_instantiation, cls, template_decl,
751 template_type.template_arguments(), full_template_specialization_name,
752 parent);
753}

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

578{
579 return config_;
580}

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

1104{
1105 auto [unqualified_type, context] = common::consume_type_context(type);
1106
1107 tp.deduced_context(std::move(context));
1108
1109 return unqualified_type;
1110}

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

572{
573 return diagram_;
574}

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

928{
929 visitor_.find_instantiation_relationships(
930 template_instantiation, qualified_name, id);
931}

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

1193{
1194 const auto &type = ct.type();
1195
1196 if (!type)
1197 return false;
1198
1199 bool found{false};
1200 LOG_DBG("Finding relationships in user defined type: {}",
1201 ct.to_string(config().using_namespace(), false));
1202
1203 auto type_with_namespace =
1204 std::make_optional<common::model::namespace_>(type.value());
1205
1206 if (!type_with_namespace.has_value()) {
1207 // Couldn't find declaration of this type
1208 type_with_namespace = common::model::namespace_{type.value()};
1209 }
1210
1211 auto element_opt = diagram().get(type_with_namespace.value().to_string());
1212 if (config_.generate_template_argument_dependencies() && element_opt) {
1213 relationships.emplace_back(
1214 element_opt.value().id(), relationship_t::kDependency);
1215 found = true;
1216 }
1217
1218 for (const auto &nested_template_params : ct.template_params()) {
1220 nested_template_params, relationships) ||
1221 found;
1222 }
1223
1224 return found;
1225}

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

590{
591 return id_mapper_;
592}

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

1278{
1279 assert(arg.getKind() == clang::TemplateArgument::Expression);
1281 arg.getAsExpr()->getSourceRange(), source_manager()));
1282}

◆ process_integral_argument()

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

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

1230{
1231 assert(arg.getKind() == clang::TemplateArgument::Integral);
1232
1233 std::string result;
1234 llvm::raw_string_ostream ostream(result);
1235 arg.dump(ostream);
1236
1237 return template_parameter::make_argument(result);
1238}

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

1258{
1259 assert(arg.getKind() == clang::TemplateArgument::Null);
1260
1262}

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

1267{
1268 assert(arg.getKind() == clang::TemplateArgument::NullPtr);
1269
1270 LOG_DBG("Processing nullptr argument: {}", common::to_string(arg));
1271
1272 return template_parameter::make_argument("nullptr");
1273}

◆ process_pack_argument()

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

Process clang::TemplateArgument::Pack

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

Definition at line 1286 of file template_builder.h.

1293{
1294 assert(arg.getKind() == clang::TemplateArgument::Pack);
1295
1296 std::vector<template_parameter> res;
1297
1298 auto pack_argument_index = argument_index;
1299
1300 for (const auto &a : arg.getPackAsArray()) {
1301 argument_process_dispatch(parent, cls, template_instantiation,
1302 base_template_decl, a, pack_argument_index++, res);
1303 }
1304
1305 return res;
1306}

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

1074{
1075 auto arg_name = common::to_string(arg);
1076
1077 LOG_DBG("Processing template argument: {}", arg_name);
1078
1080}

◆ process_template_arguments()

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

Process template class parameters and arguments.

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

Definition at line 934 of file template_builder.h.

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

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

1085{
1086 auto arg_name = common::to_string(arg);
1087
1088 LOG_DBG("Processing template expansion argument: {}", arg_name);
1089
1091 arg.getAsTemplate().getAsTemplateDecl(), [&arg_name](const auto *decl) {
1092 arg_name = decl->getQualifiedNameAsString();
1093 });
1094
1095 auto param = template_parameter::make_template_type(arg_name);
1096 param.is_variadic(true);
1097
1098 return param;
1099}

◆ process_type_argument()

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

Process clang::TemplateArgument::Type

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

Definition at line 1113 of file template_builder.h.

1119{
1120 std::optional<template_parameter> argument;
1121
1122 if (type->getAs<clang::ElaboratedType>() != nullptr) {
1123 type = type->getAs<clang::ElaboratedType>()->getNamedType(); // NOLINT
1124 }
1125
1126 auto type_name = common::to_string(type, &cls->getASTContext());
1127
1128 LOG_DBG("Processing template {} type argument {}: {}, {}, {}",
1129 template_decl->getQualifiedNameAsString(), argument_index, type_name,
1130 type->getTypeClassName(),
1131 common::to_string(type, cls->getASTContext()));
1132
1133 argument = try_as_function_prototype(parent, cls, template_decl, type,
1134 template_instantiation, argument_index);
1135 if (argument)
1136 return *argument;
1137
1138 argument = try_as_member_pointer(parent, cls, template_decl, type,
1139 template_instantiation, argument_index);
1140 if (argument)
1141 return *argument;
1142
1143 argument = try_as_array(parent, cls, template_decl, type,
1144 template_instantiation, argument_index);
1145 if (argument)
1146 return *argument;
1147
1148 argument = try_as_template_parm_type(cls, template_decl, type);
1149 if (argument)
1150 return *argument;
1151
1152 argument = try_as_template_specialization_type(parent, cls, template_decl,
1153 type, template_instantiation, argument_index);
1154 if (argument)
1155 return *argument;
1156
1157 argument = try_as_decl_type(parent, cls, template_decl, type,
1158 template_instantiation, argument_index);
1159 if (argument)
1160 return *argument;
1161
1162 argument = try_as_typedef_type(parent, cls, template_decl, type,
1163 template_instantiation, argument_index);
1164 if (argument)
1165 return *argument;
1166
1167 argument = try_as_lambda(cls, template_decl, type);
1168 if (argument)
1169 return *argument;
1170
1171 argument = try_as_record_type(parent, cls, template_decl, type,
1172 template_instantiation, argument_index);
1173 if (argument)
1174 return *argument;
1175
1177 parent, cls, template_decl, type, template_instantiation);
1178 if (argument)
1179 return *argument;
1180
1181 argument = try_as_builtin_type(parent, type, template_decl);
1182 if (argument)
1183 return *argument;
1184
1185 // fallback
1186 return template_parameter::make_argument(type_name);
1187}

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

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

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

596{
597 return source_manager_;
598}

◆ try_as_array()

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

Try to process template type argument as array.

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

Definition at line 1387 of file template_builder.h.

1393{
1394 const auto *array_type = common::dereference(type)->getAsArrayTypeUnsafe();
1395 if (array_type == nullptr)
1396 return {};
1397
1399
1400 type = consume_context(type, argument);
1401
1402 argument.is_array(true);
1403
1404 // Set function template return type
1405 auto element_type = process_type_argument(parent, cls, template_decl,
1406 array_type->getElementType(), template_instantiation, argument_index);
1407
1408 argument.add_template_param(element_type);
1409
1410 if (array_type->isDependentSizedArrayType() &&
1411 array_type->getDependence() ==
1412 clang::TypeDependence::DependentInstantiation) {
1413 argument.add_template_param(
1415 ((clang::DependentSizedArrayType *)array_type) // NOLINT
1416 ->getSizeExpr())));
1417 }
1418 else if (array_type->isConstantArrayType()) {
1420 std::to_string(((clang::ConstantArrayType *)array_type) // NOLINT
1421 ->getSize()
1422 .getLimitedValue())));
1423 }
1424
1425 // TODO: Handle variable sized arrays
1426
1427 return argument;
1428}

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

1810{
1811 const auto *builtin_type = type->getAs<clang::BuiltinType>();
1812 if (builtin_type == nullptr)
1813 return {};
1814
1815 LOG_DBG("Template argument is a builtin type");
1816
1817 auto type_name = common::to_string(type, template_decl->getASTContext());
1819
1820 type = consume_context(type, argument);
1821 argument.set_type(type_name);
1822
1823 return argument;
1824}

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

1489{
1490 const auto *decl_type =
1491 common::dereference(type)->getAs<clang::DecltypeType>();
1492 if (decl_type == nullptr) {
1493 return {};
1494 }
1495
1496 LOG_DBG("Template argument is a decltype()");
1497
1498 // TODO
1499 return {};
1500}

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

1781{
1782 const auto *enum_type = type->getAs<clang::EnumType>();
1783 if (enum_type == nullptr)
1784 return {};
1785
1786 LOG_DBG("Template argument is a an enum");
1787
1789 type = consume_context(type, argument);
1790
1791 auto type_name = common::to_string(type, template_decl->getASTContext());
1792 argument.set_type(type_name);
1793 const auto type_id = common::to_id(type_name);
1794 argument.set_id(type_id);
1795
1796 if (enum_type->getAsTagDecl() != nullptr &&
1798 template_instantiation.add_relationship(
1799 {relationship_t::kDependency, type_id});
1800 }
1801
1802 return argument;
1803}

◆ try_as_function_prototype()

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

Try to process template type argument as function template.

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

Definition at line 1432 of file template_builder.h.

1438{
1439 const auto *function_type = type->getAs<clang::FunctionProtoType>();
1440
1441 if (function_type == nullptr && type->isFunctionPointerType()) {
1442 function_type =
1443 type->getPointeeType()->getAs<clang::FunctionProtoType>();
1444 if (function_type == nullptr)
1445 return {};
1446 }
1447
1448 if (function_type == nullptr)
1449 return {};
1450
1451 LOG_DBG("Template argument is a function prototype");
1452
1454
1455 type = consume_context(type, argument);
1456
1457 argument.is_function_template(true);
1458
1459 // Set function template return type
1460 auto return_arg = process_type_argument(parent, cls, template_decl,
1461 function_type->getReturnType(), template_instantiation, argument_index);
1462
1463 argument.add_template_param(return_arg);
1464
1465 // Set function template argument types
1466 if (function_type->isVariadic() && function_type->param_types().empty()) {
1467 auto fallback_arg = template_parameter::make_argument({});
1468 fallback_arg.is_ellipsis(true);
1469 argument.add_template_param(std::move(fallback_arg));
1470 }
1471 else {
1472 for (const auto &param_type : function_type->param_types()) {
1473 argument.add_template_param(
1474 process_type_argument(parent, cls, template_decl, param_type,
1475 template_instantiation, argument_index));
1476 }
1477 }
1478
1479 return argument;
1480}

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

1688{
1689 auto type_name = common::to_string(type, &cls->getASTContext());
1690
1691 if (type_name.find("(lambda at ") != 0)
1692 return {};
1693
1694 LOG_DBG("Template argument is a lambda");
1695
1697 type = consume_context(type, argument);
1698
1700 argument.set_type(type_name);
1701
1702 return argument;
1703}

◆ try_as_member_pointer()

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

Try to process template type argument as member pointer type.

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

Definition at line 1310 of file template_builder.h.

1316{
1317 const auto *mp_type =
1318 common::dereference(type)->getAs<clang::MemberPointerType>();
1319 if (mp_type == nullptr)
1320 return {};
1321
1323 type = consume_context(type, argument);
1324
1325 // Handle a pointer to a data member of a class
1326 if (mp_type->isMemberDataPointer()) {
1327 argument.is_member_pointer(false);
1328 argument.is_data_pointer(true);
1329
1330 auto pointee_arg = process_type_argument(parent, cls, template_decl,
1331 mp_type->getPointeeType(), template_instantiation, argument_index);
1332
1333 argument.add_template_param(std::move(pointee_arg));
1334
1335 const auto *member_class_type = mp_type->getClass();
1336
1337 if (member_class_type == nullptr)
1338 return {};
1339
1340 auto class_type_arg = process_type_argument(parent, cls, template_decl,
1341 mp_type->getClass()->getCanonicalTypeUnqualified(),
1342 template_instantiation, argument_index);
1343
1344 argument.add_template_param(std::move(class_type_arg));
1345 }
1346 // Handle pointer to class method member
1347 else {
1348 argument.is_member_pointer(true);
1349 argument.is_data_pointer(false);
1350
1351 const auto *function_type =
1352 mp_type->getPointeeType()->getAs<clang::FunctionProtoType>();
1353
1354 assert(function_type != nullptr);
1355
1356 auto return_type_arg = process_type_argument(parent, cls, template_decl,
1357 function_type->getReturnType(), template_instantiation,
1358 argument_index);
1359
1360 // Add return type argument
1361 argument.add_template_param(std::move(return_type_arg));
1362
1363 const auto *member_class_type = mp_type->getClass();
1364
1365 if (member_class_type == nullptr)
1366 return {};
1367
1368 auto class_type_arg = process_type_argument(parent, cls, template_decl,
1369 mp_type->getClass()->getCanonicalTypeUnqualified(),
1370 template_instantiation, argument_index);
1371
1372 // Add class type argument
1373 argument.add_template_param(std::move(class_type_arg));
1374
1375 // Add argument types
1376 for (const auto &param_type : function_type->param_types()) {
1377 argument.add_template_param(
1378 process_type_argument(parent, cls, template_decl, param_type,
1379 template_instantiation, argument_index));
1380 }
1381 }
1382
1383 return argument;
1384}

◆ try_as_record_type()

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

Try to process template type argument as record type.

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

Definition at line 1707 of file template_builder.h.

1713{
1714 const auto *record_type =
1715 common::dereference(type)->getAs<clang::RecordType>();
1716 if (record_type == nullptr)
1717 return {};
1718
1719 LOG_DBG("Template argument is a c++ record");
1720
1722 type = consume_context(type, argument);
1723
1724 const auto type_name = config().simplify_template_type(
1725 common::to_string(type, template_decl->getASTContext()));
1726
1727 argument.set_type(type_name);
1728 const auto type_id = common::to_id(type_name);
1729
1730 argument.set_id(type_id);
1731
1732 const auto *class_template_specialization =
1733 clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(
1734 record_type->getAsRecordDecl());
1735
1736 if (class_template_specialization != nullptr) {
1737 auto tag_argument =
1738 visitor_.create_element(class_template_specialization);
1739
1741 *tag_argument, *class_template_specialization);
1742
1743 if (tag_argument) {
1744 argument.set_type(tag_argument->name_and_ns());
1745 for (const auto &p : tag_argument->template_params())
1746 argument.add_template_param(p);
1747 for (auto &r : tag_argument->relationships()) {
1748 template_instantiation.add_relationship(std::move(r));
1749 }
1750
1752 diagram().should_include(tag_argument->get_namespace())) {
1753 if (parent.has_value())
1754 parent.value()->add_relationship(
1755 {relationship_t::kDependency, tag_argument->id()});
1756 visitor_.set_source_location(*template_decl, *tag_argument);
1757 visitor_.add_diagram_element(std::move(tag_argument));
1758 }
1759 }
1760 }
1761 else if (const auto *record_type_decl = record_type->getAsRecordDecl();
1762 record_type_decl != nullptr) {
1764 diagram().should_include(namespace_{type_name})) {
1765 // Add dependency relationship to the parent
1766 // template
1767 template_instantiation.add_relationship(
1768 {relationship_t::kDependency, type_id});
1769 }
1770 }
1771
1772 return argument;
1773}

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

1644{
1645 auto is_variadic{false};
1646
1647 const auto *type_parameter =
1648 common::dereference(type)->getAs<clang::TemplateTypeParmType>();
1649
1650 auto type_name = common::to_string(type, &cls->getASTContext());
1651
1652 if (type_parameter == nullptr) {
1653 if (const auto *pet =
1654 common::dereference(type)->getAs<clang::PackExpansionType>();
1655 pet != nullptr) {
1656 is_variadic = true;
1657 type_parameter =
1658 pet->getPattern()->getAs<clang::TemplateTypeParmType>();
1659 }
1660 }
1661
1662 if (type_parameter == nullptr)
1663 return {};
1664
1665 LOG_DBG("Template argument is a template parameter type");
1666
1668 type = consume_context(type, argument);
1669
1670 auto type_parameter_name = common::to_string(type, cls->getASTContext());
1671 if (type_parameter_name.empty())
1672 type_parameter_name = "typename";
1673
1675 cls, type_parameter_name));
1676
1677 argument.is_variadic(is_variadic);
1678
1679 common::ensure_lambda_type_is_relative(config(), type_parameter_name);
1680
1681 return argument;
1682}

◆ try_as_template_specialization_type()

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

Try to process template type argument as specialization type.

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

Definition at line 1540 of file template_builder.h.

1546{
1547 const auto *nested_template_type =
1548 common::dereference(type)->getAs<clang::TemplateSpecializationType>();
1549 if (nested_template_type == nullptr) {
1550 return {};
1551 }
1552
1553 LOG_DBG("Template argument is a template specialization type");
1554
1556 type = consume_context(type, argument);
1557
1558 auto nested_type_name = nested_template_type->getTemplateName()
1559 .getAsTemplateDecl()
1560 ->getQualifiedNameAsString();
1561
1562 if (clang::dyn_cast<clang::TemplateTemplateParmDecl>(
1563 nested_template_type->getTemplateName().getAsTemplateDecl()) !=
1564 nullptr) {
1565 if (const auto *template_specialization_decl =
1566 clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(cls);
1567 template_specialization_decl != nullptr) {
1568 nested_type_name =
1569 template_specialization_decl->getDescribedTemplateParams()
1570 ->getParam(argument_index)
1571 ->getNameAsString();
1572 }
1573 else {
1574 // fallback
1575 nested_type_name = "template";
1576 }
1577
1578 argument.is_template_template_parameter(true);
1579 }
1580
1581 argument.set_type(nested_type_name);
1582
1583 auto nested_template_instantiation =
1584 visitor_.create_element(nested_template_type->getTemplateName()
1585 .getAsTemplateDecl()
1586 ->getTemplatedDecl());
1587 build_from_template_specialization_type(*nested_template_instantiation, cls,
1588 *nested_template_type,
1589 diagram().should_include(
1590 namespace_{template_decl->getQualifiedNameAsString()})
1591 ? std::make_optional(&template_instantiation)
1592 : parent);
1593
1594 argument.set_id(nested_template_instantiation->id());
1595
1596 for (const auto &t : nested_template_instantiation->template_params())
1597 argument.add_template_param(t);
1598
1599 // Check if this template should be simplified (e.g. system
1600 // template aliases such as 'std:basic_string<char>' should
1601 // be simply 'std::string')
1603 argument, argument.to_string(using_namespace(), false));
1604
1605 argument.set_id(
1606 common::to_id(argument.to_string(using_namespace(), false)));
1607
1608 const auto nested_template_instantiation_full_name =
1609 nested_template_instantiation->full_name(false);
1610
1611 if (nested_template_instantiation &&
1612 diagram().should_include(
1613 namespace_{nested_template_instantiation_full_name})) {
1615 if (diagram().should_include(
1616 namespace_{template_decl->getQualifiedNameAsString()})) {
1617 template_instantiation.add_relationship(
1618 {relationship_t::kDependency,
1619 nested_template_instantiation->id()});
1620 }
1621 else {
1622 if (parent.has_value())
1623 parent.value()->add_relationship(
1624 {relationship_t::kDependency,
1625 nested_template_instantiation->id()});
1626 }
1627 }
1628 }
1629
1630 if (diagram().should_include(
1631 namespace_{nested_template_instantiation_full_name})) {
1632 visitor_.set_source_location(*cls, *nested_template_instantiation);
1633 visitor_.add_diagram_element(std::move(nested_template_instantiation));
1634 }
1635
1636 return argument;
1637}

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

1510{
1511 const auto *typedef_type =
1512 common::dereference(type)->getAs<clang::TypedefType>();
1513 if (typedef_type == nullptr) {
1514 return {};
1515 }
1516
1517 LOG_DBG("Template argument is a typedef/using");
1518
1519 // If this is a typedef/using alias to a decltype - we're not able
1520 // to figure out anything out of it probably
1521 if (typedef_type->getAs<clang::DecltypeType>() != nullptr) {
1522 // Here we need to figure out the parent context of this alias,
1523 // it can be a:
1524 // - class/struct
1525 if (typedef_type->getDecl()->isCXXClassMember() && parent) {
1527 fmt::format("{}::{}", parent.value()->full_name(false),
1528 typedef_type->getDecl()->getNameAsString()));
1529 }
1530 // - namespace
1532 typedef_type->getDecl()->getQualifiedNameAsString());
1533 }
1534
1535 return {};
1536}

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

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

Member Data Documentation

◆ config_

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

Definition at line 549 of file template_builder.h.

◆ diagram_

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

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

◆ source_manager_

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

Definition at line 553 of file template_builder.h.

◆ visitor_

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

Definition at line 555 of file template_builder.h.


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