31using common::model::template_parameter;
34 std::vector<std::pair<eid_t, common::model::relationship_t>>;
39 const clang::ClassTemplateSpecializationDecl *decl,
const std::string &tp);
42 const clang::TypeAliasTemplateDecl *decl,
const std::string &tp);
47 const clang::Decl *decl,
const std::string &type_parameter);
102 const clang::TemplateDecl &template_declaration,
115 const clang::NamedDecl *cls,
116 const clang::TemplateSpecializationType &template_type_decl,
117 std::optional<clanguml::common::model::template_element *> parent = {});
121 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
122 clang::ArrayRef<clang::TemplateArgument> template_arguments,
123 std::string full_template_specialization_name,
124 std::optional<clanguml::common::model::template_element *> parent = {});
135 const clang::ClassTemplateSpecializationDecl &template_specialization,
136 std::optional<clanguml::common::model::template_element *> parent = {});
153 std::deque<std::tuple<std::string, int, bool>> &template_base_params,
154 int arg_index,
bool variadic_params,
168 std::optional<clanguml::common::model::template_element *> &parent,
169 const clang::NamedDecl *cls,
170 std::deque<std::tuple<std::string, int, bool>> &template_base_params,
171 const clang::ArrayRef<clang::TemplateArgument> &template_args,
173 const clang::TemplateDecl *template_decl);
188 std::optional<clanguml::common::model::template_element *> &parent,
189 const clang::NamedDecl *cls,
191 const clang::TemplateDecl *template_decl,
192 const clang::TemplateArgument &arg,
size_t argument_index,
193 std::vector<template_parameter> &argument);
205 const clang::TemplateArgument &arg);
218 const clang::TemplateArgument &arg);
220#if LLVM_VERSION_MAJOR > 17
232 const clang::TemplateArgument &arg);
245 const clang::TemplateArgument &arg);
257 const clang::TemplateArgument &arg);
269 std::optional<clanguml::common::model::template_element *> &parent,
270 const clang::NamedDecl *cls,
272 const clang::TemplateDecl *base_template_decl,
273 const clang::TemplateArgument &arg,
size_t argument_index,
274 std::vector<template_parameter> &argument);
285 std::optional<clanguml::common::model::template_element *> &parent,
286 const clang::NamedDecl *cls,
287 const clang::TemplateDecl *base_template_decl, clang::QualType type,
289 size_t argument_index);
301 const clang::TemplateArgument &arg);
313 const clang::TemplateArgument &arg);
327 std::optional<clanguml::common::model::template_element *> &parent,
328 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
329 clang::QualType &type,
331 size_t argument_index);
345 std::optional<clanguml::common::model::template_element *> &parent,
346 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
347 clang::QualType &type,
349 size_t argument_index);
364 std::optional<clanguml::common::model::template_element *> &parent,
365 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
366 clang::QualType &type,
368 size_t argument_index);
379 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
380 clang::QualType &type);
390 std::optional<template_parameter>
try_as_lambda(
const clang::NamedDecl *cls,
391 const clang::TemplateDecl *template_decl, clang::QualType &type);
405 std::optional<clanguml::common::model::template_element *> &parent,
406 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
407 clang::QualType &type,
409 size_t argument_index);
422 std::optional<clanguml::common::model::template_element *> &parent,
423 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
424 clang::QualType &type,
436 std::optional<clanguml::common::model::template_element *> &parent,
437 clang::QualType &type,
const clang::TemplateDecl *template_decl);
452 std::optional<clanguml::common::model::template_element *> &parent,
453 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
454 clang::QualType &type,
456 size_t argument_index);
470 std::optional<clanguml::common::model::template_element *> &parent,
471 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
472 clang::QualType &type,
474 size_t argument_index);
488 std::optional<clanguml::common::model::template_element *> &parent,
489 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
490 clang::QualType &type,
492 size_t argument_index);
528 const std::string &qualified_name)
const;
558template <
typename VisitorT>
564 , id_mapper_{visitor.id_mapper()}
565 , source_manager_{visitor.source_manager()}
570template <
typename VisitorT>
576template <
typename VisitorT>
582template <
typename VisitorT>
585 return config_.using_namespace();
588template <
typename VisitorT>
594template <
typename VisitorT>
597 return source_manager_;
600template <
typename VisitorT>
607 auto simplified = config().simplify_template_type(full_name);
609 if (simplified != full_name) {
619template <
typename VisitorT>
622 const clang::TemplateDecl &template_declaration,
625 LOG_DBG(
"Processing {} template parameters...",
628 if (template_declaration.getTemplateParameters() ==
nullptr)
631 for (
const auto *parameter :
632 *template_declaration.getTemplateParameters()) {
633 if (clang::dyn_cast_or_null<clang::TemplateTypeParmDecl>(parameter) !=
635 const auto *template_type_parameter =
636 clang::dyn_cast_or_null<clang::TemplateTypeParmDecl>(parameter);
638 std::optional<std::string> default_arg;
639 if (template_type_parameter->hasDefaultArgument()) {
641 template_type_parameter->getDefaultArgument().getAsString();
644 auto parameter_name = template_type_parameter->getNameAsString();
645 if (parameter_name.empty())
646 parameter_name =
"typename";
649 default_arg, template_type_parameter->isParameterPack());
651 if constexpr (std::is_same_v<
typename VisitorT::diagram_t,
653 if (template_type_parameter->getTypeConstraint() !=
nullptr) {
655 template_type_parameter->getTypeConstraint()
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,
667 eid_t{named_concept->getID()})
669 model::access_t::kNone,
676 (void)templated_element;
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>(
687 std::optional<std::string> default_arg;
689 if (template_nontype_parameter->hasDefaultArgument())
691 template_nontype_parameter->getDefaultArgument());
694 template_nontype_parameter->getType().getAsString(),
695 template_nontype_parameter->getNameAsString(), default_arg,
696 template_nontype_parameter->isParameterPack());
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>(
705 std::optional<std::string> default_arg;
706 if (template_template_parameter->hasDefaultArgument()) {
708 template_template_parameter->getDefaultArgument()
712 template_template_parameter->getNameAsString(), default_arg,
713 template_template_parameter->isParameterPack());
723template <
typename VisitorT>
726 const clang::NamedDecl *cls,
727 const clang::TemplateSpecializationType &template_type_decl,
728 std::optional<clanguml::common::model::template_element *> parent)
730 const auto *template_type_ptr = &template_type_decl;
732 if (template_type_decl.isTypeAlias()) {
733 if (
const auto *tsp =
734 template_type_decl.getAliasedType()
735 ->template getAs<clang::TemplateSpecializationType>();
737 template_type_ptr = tsp;
740 const auto &template_type = *template_type_ptr;
745 template_type.desugar(),
746 template_type.getTemplateName().getAsTemplateDecl()->getASTContext());
748 auto *template_decl{template_type.getTemplateName().getAsTemplateDecl()};
750 build(template_instantiation, cls, template_decl,
751 template_type.template_arguments(), full_template_specialization_name,
755template <
typename VisitorT>
758 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
759 const clang::ArrayRef<clang::TemplateArgument> template_arguments,
760 std::string full_template_specialization_name,
761 std::optional<clanguml::common::model::template_element *> parent)
767 std::deque<std::tuple< std::string, int,
769 template_base_params{};
771 auto template_decl_qualified_name =
772 template_decl->getQualifiedNameAsString();
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()) {
784 ->getOuterLexicalRecordContext())};
787 std::string name = template_decl->getQualifiedNameAsString();
788 if (!ns_str.empty()) {
789 name = name.substr(ns_str.size() + 2);
793 template_instantiation.
set_name(name);
798 namespace_ ns{template_decl_qualified_name};
800 template_instantiation.
set_name(template_decl->getNameAsString());
809 std::pair< std::string,
bool>>
810 template_parameter_names{};
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);
820 template_parameter_names.emplace_back(
821 parameter->getNameAsString(),
false);
827 const auto *templated_class_decl =
828 clang::dyn_cast_or_null<clang::CXXRecordDecl>(
829 template_decl->getTemplatedDecl());
831 if ((templated_class_decl !=
nullptr) &&
832 templated_class_decl->hasDefinition())
833 for (
const auto &base : templated_class_decl->bases()) {
835 base.getType(), templated_class_decl->getASTContext(),
false);
837 LOG_DBG(
"Found template instantiation base: {}, {}",
838 base_class_name, base_index);
842 auto it = std::find_if(template_parameter_names.begin(),
843 template_parameter_names.end(),
845 const auto &p) { return p.first == base_class_name; });
847 if (it != template_parameter_names.end()) {
848 const auto ¶meter_name = it->first;
849 const bool is_variadic = it->second;
851 LOG_DBG(
"Found base class which is a template parameter "
853 parameter_name, is_variadic,
854 std::distance(template_parameter_names.begin(), it));
856 template_base_params.emplace_back(parameter_name,
857 std::distance(template_parameter_names.begin(), it),
867 process_template_arguments(parent, cls, template_base_params,
868 template_arguments, template_instantiation, template_decl);
870 if constexpr (std::is_same_v<
typename VisitorT::diagram_t,
872 find_instantiation_relationships(template_instantiation,
873 eid_t{template_decl->getID()}, full_template_specialization_name);
876 template_instantiation.
set_id(
879 visitor_.set_source_location(*cls, template_instantiation);
882template <
typename VisitorT>
885 const clang::ClassTemplateSpecializationDecl &template_specialization,
886 std::optional<clanguml::common::model::template_element *> parent)
892 std::deque<std::tuple< std::string, int,
894 template_base_params{};
896 const clang::ClassTemplateDecl *template_decl =
897 template_specialization.getSpecializedTemplate();
899 auto qualified_name = template_decl->getQualifiedNameAsString();
901 namespace_ ns{qualified_name};
903 template_instantiation.
set_name(template_decl->getNameAsString());
906 process_template_arguments(parent, &template_specialization,
907 template_base_params,
908 template_specialization.getTemplateArgs().asArray(),
909 template_instantiation, template_decl);
912 template_instantiation.
set_id(
915 if constexpr (std::is_same_v<
typename VisitorT::diagram_t,
917 find_instantiation_relationships(template_instantiation,
918 eid_t{template_specialization.getID()}, qualified_name);
921 visitor_.set_source_location(*template_decl, template_instantiation);
924template <
typename VisitorT>
927 const std::string &qualified_name)
const
930 template_instantiation, qualified_name,
id);
933template <
typename VisitorT>
935 std::optional<clanguml::common::model::template_element *> &parent,
936 const clang::NamedDecl *cls,
937 std::deque<std::tuple<std::string, int, bool>> &template_base_params,
938 const clang::ArrayRef<clang::TemplateArgument> &template_args,
940 const clang::TemplateDecl *template_decl)
944 for (
const auto &arg : template_args) {
947 std::vector<template_parameter> arguments;
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()
965 if (maybe_type_parm_decl !=
nullptr &&
966 maybe_type_parm_decl->hasDefaultArgument()) {
974 argument_process_dispatch(parent, cls, template_instantiation,
975 template_decl, arg, arg_index, arguments);
977 if (arguments.empty()) {
986 [[maybe_unused]]
auto variadic_params{
false};
988 if constexpr (std::is_same_v<
typename VisitorT::diagram_t,
992 if (!template_base_params.empty()) {
993 variadic_params = add_base_classes(template_instantiation,
994 template_base_params, arg_index, variadic_params,
999 for (
auto &argument : arguments) {
1000 simplify_system_template(
1001 argument, argument.to_string(using_namespace(),
false,
true));
1003 LOG_DBG(
"Adding template argument {} to template "
1004 "specialization/instantiation {}",
1005 argument.to_string(using_namespace(),
false),
1006 template_instantiation.
name());
1008 template_instantiation.
add_template(std::move(argument));
1015 template_instantiation.
set_id(
1019template <
typename VisitorT>
1021 std::optional<clanguml::common::model::template_element *> &parent,
1022 const clang::NamedDecl *cls,
1024 const clang::TemplateDecl *template_decl,
1025 const clang::TemplateArgument &arg,
size_t argument_index,
1026 std::vector<template_parameter> &argument)
1028 LOG_DBG(
"Processing argument {} in template class: {}", argument_index,
1029 cls->getQualifiedNameAsString());
1031 switch (arg.getKind()) {
1032 case clang::TemplateArgument::Null:
1033 argument.push_back(process_null_argument(arg));
1035 case clang::TemplateArgument::Template:
1036 argument.push_back(process_template_argument(arg));
1038 case clang::TemplateArgument::Type: {
1039 argument.push_back(process_type_argument(parent, cls, template_decl,
1040 arg.getAsType(), template_instantiation, argument_index));
1043 case clang::TemplateArgument::Declaration:
1045 case clang::TemplateArgument::NullPtr:
1046 argument.push_back(process_nullptr_argument(arg));
1048 case clang::TemplateArgument::Integral:
1049 argument.push_back(process_integral_argument(arg));
1051 case clang::TemplateArgument::TemplateExpansion:
1052 argument.push_back(process_template_expansion(arg));
1054 case clang::TemplateArgument::Expression:
1055 argument.push_back(process_expression_argument(arg));
1057 case clang::TemplateArgument::Pack:
1059 process_pack_argument(parent, cls, template_instantiation,
1060 template_decl, arg, argument_index, argument)) {
1061 argument.push_back(a);
1064#if LLVM_VERSION_MAJOR > 17
1065 case clang::TemplateArgument::StructuralValue:
1071template <
typename VisitorT>
1073 const clang::TemplateArgument &arg)
1077 LOG_DBG(
"Processing template argument: {}", arg_name);
1079 return template_parameter::make_template_type(arg_name);
1082template <
typename VisitorT>
1084 const clang::TemplateArgument &arg)
1088 LOG_DBG(
"Processing template expansion argument: {}", arg_name);
1091 arg.getAsTemplate().getAsTemplateDecl(), [&arg_name](
const auto *decl) {
1092 arg_name = decl->getQualifiedNameAsString();
1095 auto param = template_parameter::make_template_type(arg_name);
1096 param.is_variadic(
true);
1101template <
typename VisitorT>
1109 return unqualified_type;
1112template <
typename VisitorT>
1114 std::optional<clanguml::common::model::template_element *> &parent,
1115 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
1116 clang::QualType type,
1118 size_t argument_index)
1120 std::optional<template_parameter> argument;
1122 if (type->getAs<clang::ElaboratedType>() !=
nullptr) {
1123 type = type->getAs<clang::ElaboratedType>()->getNamedType();
1128 LOG_DBG(
"Processing template {} type argument {}: {}, {}, {}",
1129 template_decl->getQualifiedNameAsString(), argument_index, type_name,
1130 type->getTypeClassName(),
1133 argument = try_as_function_prototype(parent, cls, template_decl, type,
1134 template_instantiation, argument_index);
1138 argument = try_as_member_pointer(parent, cls, template_decl, type,
1139 template_instantiation, argument_index);
1143 argument = try_as_array(parent, cls, template_decl, type,
1144 template_instantiation, argument_index);
1148 argument = try_as_template_parm_type(cls, template_decl, type);
1152 argument = try_as_template_specialization_type(parent, cls, template_decl,
1153 type, template_instantiation, argument_index);
1157 argument = try_as_decl_type(parent, cls, template_decl, type,
1158 template_instantiation, argument_index);
1162 argument = try_as_typedef_type(parent, cls, template_decl, type,
1163 template_instantiation, argument_index);
1167 argument = try_as_lambda(cls, template_decl, type);
1171 argument = try_as_record_type(parent, cls, template_decl, type,
1172 template_instantiation, argument_index);
1176 argument = try_as_enum_type(
1177 parent, cls, template_decl, type, template_instantiation);
1181 argument = try_as_builtin_type(parent, type, template_decl);
1186 return template_parameter::make_argument(type_name);
1189template <
typename VisitorT>
1194 const auto &type = ct.
type();
1200 LOG_DBG(
"Finding relationships in user defined type: {}",
1201 ct.
to_string(config().using_namespace(),
false));
1203 auto type_with_namespace =
1204 std::make_optional<common::model::namespace_>(type.value());
1206 if (!type_with_namespace.has_value()) {
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);
1219 found = find_relationships_in_unexposed_template_params(
1220 nested_template_params, relationships) ||
1227template <
typename VisitorT>
1229 const clang::TemplateArgument &arg)
1231 assert(arg.getKind() == clang::TemplateArgument::Integral);
1234 llvm::raw_string_ostream ostream(result);
1237 return template_parameter::make_argument(result);
1240#if LLVM_VERSION_MAJOR > 17
1241template <
typename VisitorT>
1243 const clang::TemplateArgument &arg)
1245 assert(arg.getKind() == clang::TemplateArgument::StructuralValue);
1248 llvm::raw_string_ostream ostream(result);
1251 return template_parameter::make_argument(result);
1255template <
typename VisitorT>
1257 const clang::TemplateArgument &arg)
1259 assert(arg.getKind() == clang::TemplateArgument::Null);
1261 return template_parameter::make_argument(
"");
1264template <
typename VisitorT>
1266 const clang::TemplateArgument &arg)
1268 assert(arg.getKind() == clang::TemplateArgument::NullPtr);
1272 return template_parameter::make_argument(
"nullptr");
1275template <
typename VisitorT>
1277 const clang::TemplateArgument &arg)
1279 assert(arg.getKind() == clang::TemplateArgument::Expression);
1281 arg.getAsExpr()->getSourceRange(), source_manager()));
1284template <
typename VisitorT>
1285std::vector<template_parameter>
1287 std::optional<clanguml::common::model::template_element *> &parent,
1288 const clang::NamedDecl *cls,
1290 const clang::TemplateDecl *base_template_decl,
1291 const clang::TemplateArgument &arg,
size_t argument_index,
1292 std::vector<template_parameter> & )
1294 assert(arg.getKind() == clang::TemplateArgument::Pack);
1296 std::vector<template_parameter> res;
1298 auto pack_argument_index = argument_index;
1300 for (
const auto &a : arg.getPackAsArray()) {
1301 argument_process_dispatch(parent, cls, template_instantiation,
1302 base_template_decl, a, pack_argument_index++, res);
1308template <
typename VisitorT>
1309std::optional<template_parameter>
1311 std::optional<clanguml::common::model::template_element *> &parent,
1312 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
1313 clang::QualType &type,
1315 size_t argument_index)
1317 const auto *mp_type =
1319 if (mp_type ==
nullptr)
1322 auto argument = template_parameter::make_template_type(
"");
1323 type = consume_context(type, argument);
1326 if (mp_type->isMemberDataPointer()) {
1327 argument.is_member_pointer(
false);
1328 argument.is_data_pointer(
true);
1330 auto pointee_arg = process_type_argument(parent, cls, template_decl,
1331 mp_type->getPointeeType(), template_instantiation, argument_index);
1333 argument.add_template_param(std::move(pointee_arg));
1335 const auto *member_class_type = mp_type->getClass();
1337 if (member_class_type ==
nullptr)
1340 auto class_type_arg = process_type_argument(parent, cls, template_decl,
1341 mp_type->getClass()->getCanonicalTypeUnqualified(),
1342 template_instantiation, argument_index);
1344 argument.add_template_param(std::move(class_type_arg));
1348 argument.is_member_pointer(
true);
1349 argument.is_data_pointer(
false);
1351 const auto *function_type =
1352 mp_type->getPointeeType()->getAs<clang::FunctionProtoType>();
1354 assert(function_type !=
nullptr);
1356 auto return_type_arg = process_type_argument(parent, cls, template_decl,
1357 function_type->getReturnType(), template_instantiation,
1361 argument.add_template_param(std::move(return_type_arg));
1363 const auto *member_class_type = mp_type->getClass();
1365 if (member_class_type ==
nullptr)
1368 auto class_type_arg = process_type_argument(parent, cls, template_decl,
1369 mp_type->getClass()->getCanonicalTypeUnqualified(),
1370 template_instantiation, argument_index);
1373 argument.add_template_param(std::move(class_type_arg));
1376 for (
const auto ¶m_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));
1386template <
typename VisitorT>
1388 std::optional<clanguml::common::model::template_element *> &parent,
1389 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
1390 clang::QualType &type,
1392 size_t argument_index)
1395 if (array_type ==
nullptr)
1398 auto argument = template_parameter::make_template_type(
"");
1400 type = consume_context(type, argument);
1402 argument.is_array(
true);
1405 auto element_type = process_type_argument(parent, cls, template_decl,
1406 array_type->getElementType(), template_instantiation, argument_index);
1408 argument.add_template_param(element_type);
1410 if (array_type->isDependentSizedArrayType() &&
1411 array_type->getDependence() ==
1412 clang::TypeDependence::DependentInstantiation) {
1413 argument.add_template_param(
1415 ((clang::DependentSizedArrayType *)array_type)
1418 else if (array_type->isConstantArrayType()) {
1419 argument.add_template_param(template_parameter::make_argument(
1420 std::to_string(((clang::ConstantArrayType *)array_type)
1422 .getLimitedValue())));
1430template <
typename VisitorT>
1431std::optional<template_parameter>
1433 std::optional<clanguml::common::model::template_element *> &parent,
1434 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
1435 clang::QualType &type,
1437 size_t argument_index)
1439 const auto *function_type = type->getAs<clang::FunctionProtoType>();
1441 if (function_type ==
nullptr && type->isFunctionPointerType()) {
1443 type->getPointeeType()->getAs<clang::FunctionProtoType>();
1444 if (function_type ==
nullptr)
1448 if (function_type ==
nullptr)
1451 LOG_DBG(
"Template argument is a function prototype");
1453 auto argument = template_parameter::make_template_type(
"");
1455 type = consume_context(type, argument);
1457 argument.is_function_template(
true);
1460 auto return_arg = process_type_argument(parent, cls, template_decl,
1461 function_type->getReturnType(), template_instantiation, argument_index);
1463 argument.add_template_param(return_arg);
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));
1472 for (
const auto ¶m_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));
1482template <
typename VisitorT>
1484 std::optional<clanguml::common::model::template_element *> & ,
1485 const clang::NamedDecl * ,
1486 const clang::TemplateDecl * , clang::QualType &type,
1490 const auto *decl_type =
1492 if (decl_type ==
nullptr) {
1496 LOG_DBG(
"Template argument is a decltype()");
1502template <
typename VisitorT>
1503std::optional<template_parameter>
1505 std::optional<clanguml::common::model::template_element *> &parent,
1506 const clang::NamedDecl * ,
1507 const clang::TemplateDecl * , clang::QualType &type,
1511 const auto *typedef_type =
1513 if (typedef_type ==
nullptr) {
1517 LOG_DBG(
"Template argument is a typedef/using");
1521 if (typedef_type->getAs<clang::DecltypeType>() !=
nullptr) {
1525 if (typedef_type->getDecl()->isCXXClassMember() && parent) {
1526 return template_parameter::make_argument(
1527 fmt::format(
"{}::{}", parent.value()->full_name(
false),
1528 typedef_type->getDecl()->getNameAsString()));
1531 return template_parameter::make_argument(
1532 typedef_type->getDecl()->getQualifiedNameAsString());
1538template <
typename VisitorT>
1539std::optional<template_parameter>
1541 std::optional<clanguml::common::model::template_element *> &parent,
1542 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
1543 clang::QualType &type,
1545 size_t argument_index)
1547 const auto *nested_template_type =
1549 if (nested_template_type ==
nullptr) {
1553 LOG_DBG(
"Template argument is a template specialization type");
1555 auto argument = template_parameter::make_argument(
"");
1556 type = consume_context(type, argument);
1558 auto nested_type_name = nested_template_type->getTemplateName()
1559 .getAsTemplateDecl()
1560 ->getQualifiedNameAsString();
1562 if (clang::dyn_cast<clang::TemplateTemplateParmDecl>(
1563 nested_template_type->getTemplateName().getAsTemplateDecl()) !=
1565 if (
const auto *template_specialization_decl =
1566 clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(cls);
1567 template_specialization_decl !=
nullptr) {
1569 template_specialization_decl->getDescribedTemplateParams()
1570 ->getParam(argument_index)
1571 ->getNameAsString();
1575 nested_type_name =
"template";
1578 argument.is_template_template_parameter(
true);
1581 argument.set_type(nested_type_name);
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)
1594 argument.set_id(nested_template_instantiation->id());
1596 for (
const auto &t : nested_template_instantiation->template_params())
1597 argument.add_template_param(t);
1602 simplify_system_template(
1603 argument, argument.to_string(using_namespace(),
false));
1606 common::to_id(argument.to_string(using_namespace(),
false)));
1608 const auto nested_template_instantiation_full_name =
1609 nested_template_instantiation->full_name(
false);
1611 if (nested_template_instantiation &&
1612 diagram().should_include(
1613 namespace_{nested_template_instantiation_full_name})) {
1614 if (config_.generate_template_argument_dependencies()) {
1615 if (diagram().should_include(
1616 namespace_{template_decl->getQualifiedNameAsString()})) {
1618 {relationship_t::kDependency,
1619 nested_template_instantiation->id()});
1622 if (parent.has_value())
1623 parent.value()->add_relationship(
1624 {relationship_t::kDependency,
1625 nested_template_instantiation->id()});
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));
1639template <
typename VisitorT>
1640std::optional<template_parameter>
1642 const clang::NamedDecl *cls,
const clang::TemplateDecl * ,
1643 clang::QualType &type)
1645 auto is_variadic{
false};
1647 const auto *type_parameter =
1652 if (type_parameter ==
nullptr) {
1653 if (
const auto *pet =
1658 pet->getPattern()->getAs<clang::TemplateTypeParmType>();
1662 if (type_parameter ==
nullptr)
1665 LOG_DBG(
"Template argument is a template parameter type");
1667 auto argument = template_parameter::make_template_type(
"");
1668 type = consume_context(type, argument);
1671 if (type_parameter_name.empty())
1672 type_parameter_name =
"typename";
1675 cls, type_parameter_name));
1677 argument.is_variadic(is_variadic);
1684template <
typename VisitorT>
1686 const clang::NamedDecl *cls,
const clang::TemplateDecl * ,
1687 clang::QualType &type)
1691 if (type_name.find(
"(lambda at ") != 0)
1694 LOG_DBG(
"Template argument is a lambda");
1696 auto argument = template_parameter::make_argument(
"");
1697 type = consume_context(type, argument);
1700 argument.set_type(type_name);
1705template <
typename VisitorT>
1706std::optional<template_parameter>
1708 std::optional<clanguml::common::model::template_element *> &parent,
1709 const clang::NamedDecl * ,
const clang::TemplateDecl *template_decl,
1710 clang::QualType &type,
1714 const auto *record_type =
1716 if (record_type ==
nullptr)
1719 LOG_DBG(
"Template argument is a c++ record");
1721 auto argument = template_parameter::make_argument({});
1722 type = consume_context(type, argument);
1724 const auto type_name = config().simplify_template_type(
1727 argument.set_type(type_name);
1730 argument.set_id(type_id);
1732 const auto *class_template_specialization =
1733 clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(
1734 record_type->getAsRecordDecl());
1736 if (class_template_specialization !=
nullptr) {
1738 visitor_.create_element(class_template_specialization);
1740 build_from_class_template_specialization(
1741 *tag_argument, *class_template_specialization);
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()) {
1751 if (config_.generate_template_argument_dependencies() &&
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));
1761 else if (
const auto *record_type_decl = record_type->getAsRecordDecl();
1762 record_type_decl !=
nullptr) {
1763 if (config_.generate_template_argument_dependencies() &&
1764 diagram().should_include(namespace_{type_name})) {
1768 {relationship_t::kDependency, type_id});
1775template <
typename VisitorT>
1777 std::optional<clanguml::common::model::template_element *> & ,
1778 const clang::NamedDecl * ,
const clang::TemplateDecl *template_decl,
1779 clang::QualType &type,
1782 const auto *enum_type = type->getAs<clang::EnumType>();
1783 if (enum_type ==
nullptr)
1786 LOG_DBG(
"Template argument is a an enum");
1788 auto argument = template_parameter::make_argument({});
1789 type = consume_context(type, argument);
1792 argument.set_type(type_name);
1794 argument.set_id(type_id);
1796 if (enum_type->getAsTagDecl() !=
nullptr &&
1797 config_.generate_template_argument_dependencies()) {
1799 {relationship_t::kDependency, type_id});
1805template <
typename VisitorT>
1806std::optional<template_parameter>
1808 std::optional<clanguml::common::model::template_element *> & ,
1809 clang::QualType &type,
const clang::TemplateDecl *template_decl)
1811 const auto *builtin_type = type->getAs<clang::BuiltinType>();
1812 if (builtin_type ==
nullptr)
1815 LOG_DBG(
"Template argument is a builtin type");
1818 auto argument = template_parameter::make_argument(type_name);
1820 type = consume_context(type, argument);
1821 argument.set_type(type_name);
1826template <
typename VisitorT>
1829 std::deque<std::tuple<std::string, int, bool>> &template_base_params,
1832 bool add_template_argument_as_base_class =
false;
1834 if (variadic_params) {
1835 add_template_argument_as_base_class =
true;
1838 auto [arg_name, index, is_variadic] = template_base_params.front();
1840 variadic_params = is_variadic;
1841 if ((arg_index == index) || (is_variadic && arg_index >= index)) {
1842 add_template_argument_as_base_class =
true;
1845 template_base_params.pop_front();
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 '{}'",
1858 cp.
set_id(maybe_id.value());
1864 return variadic_params;