31using common::model::template_parameter;
36 const clang::ClassTemplateSpecializationDecl *decl,
const std::string &tp);
39 const clang::TypeAliasTemplateDecl *decl,
const std::string &tp);
44 const clang::Decl *decl,
const std::string &type_parameter);
99 const clang::TemplateDecl &template_declaration,
112 const clang::NamedDecl *cls,
113 const clang::TemplateSpecializationType &template_type_decl,
114 std::optional<clanguml::common::model::template_element *> parent = {});
118 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
119 clang::ArrayRef<clang::TemplateArgument> template_arguments,
120 std::string full_template_specialization_name,
121 std::optional<clanguml::common::model::template_element *> parent = {});
132 const clang::ClassTemplateSpecializationDecl &template_specialization,
133 std::optional<clanguml::common::model::template_element *> parent = {});
150 std::deque<std::tuple<std::string, int, bool>> &template_base_params,
151 int arg_index,
bool variadic_params,
165 std::optional<clanguml::common::model::template_element *> &parent,
166 const clang::NamedDecl *cls,
167 std::deque<std::tuple<std::string, int, bool>> &template_base_params,
168 const clang::ArrayRef<clang::TemplateArgument> &template_args,
170 const clang::TemplateDecl *template_decl);
185 std::optional<clanguml::common::model::template_element *> &parent,
186 const clang::NamedDecl *cls,
188 const clang::TemplateDecl *template_decl,
189 const clang::TemplateArgument &arg,
size_t argument_index,
190 std::vector<template_parameter> &argument);
202 const clang::TemplateArgument &arg);
215 const clang::TemplateArgument &arg,
216 const clang::ASTContext &ast_context);
218#if LLVM_VERSION_MAJOR > 17
230 const clang::TemplateArgument &arg,
231 const clang::ASTContext &ast_context);
244 const clang::TemplateArgument &arg);
256 const clang::TemplateArgument &arg);
268 std::optional<clanguml::common::model::template_element *> &parent,
269 const clang::NamedDecl *cls,
271 const clang::TemplateDecl *base_template_decl,
272 const clang::TemplateArgument &arg,
size_t argument_index,
273 std::vector<template_parameter> &argument);
284 std::optional<clanguml::common::model::template_element *> &parent,
285 const clang::NamedDecl *cls,
286 const clang::TemplateDecl *base_template_decl, clang::QualType type,
288 size_t argument_index);
300 const clang::TemplateArgument &arg);
312 const clang::TemplateArgument &arg);
326 std::optional<clanguml::common::model::template_element *> &parent,
327 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
328 clang::QualType &type,
330 size_t argument_index);
344 std::optional<clanguml::common::model::template_element *> &parent,
345 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
346 clang::QualType &type,
348 size_t argument_index);
363 std::optional<clanguml::common::model::template_element *> &parent,
364 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
365 clang::QualType &type,
367 size_t argument_index);
378 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
379 clang::QualType &type);
389 std::optional<template_parameter>
try_as_lambda(
const clang::NamedDecl *cls,
390 const clang::TemplateDecl *template_decl, clang::QualType &type);
404 std::optional<clanguml::common::model::template_element *> &parent,
405 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
406 clang::QualType &type,
408 size_t argument_index);
421 std::optional<clanguml::common::model::template_element *> &parent,
422 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
423 clang::QualType &type,
435 std::optional<clanguml::common::model::template_element *> &parent,
436 clang::QualType &type,
const clang::TemplateDecl *template_decl);
451 std::optional<clanguml::common::model::template_element *> &parent,
452 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
453 clang::QualType &type,
455 size_t argument_index);
469 std::optional<clanguml::common::model::template_element *> &parent,
470 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
471 clang::QualType &type,
473 size_t argument_index);
487 std::optional<clanguml::common::model::template_element *> &parent,
488 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
489 clang::QualType &type,
491 size_t argument_index);
527 const std::string &qualified_name)
const;
557template <
typename VisitorT>
563 , id_mapper_{visitor.id_mapper()}
564 , source_manager_{visitor.source_manager()}
569template <
typename VisitorT>
575template <
typename VisitorT>
581template <
typename VisitorT>
584 return config_.using_namespace();
587template <
typename VisitorT>
593template <
typename VisitorT>
596 return source_manager_;
599template <
typename VisitorT>
606 auto simplified = config().simplify_template_type(full_name);
608 if (simplified != full_name) {
618template <
typename VisitorT>
621 const clang::TemplateDecl &template_declaration,
624 LOG_DBG(
"Processing {} template parameters...",
627 if (template_declaration.getTemplateParameters() ==
nullptr)
630 for (
const auto *parameter :
631 *template_declaration.getTemplateParameters()) {
632 if (clang::dyn_cast_or_null<clang::TemplateTypeParmDecl>(parameter) !=
634 const auto *template_type_parameter =
635 clang::dyn_cast_or_null<clang::TemplateTypeParmDecl>(parameter);
637 std::optional<std::string> default_arg;
638 if (template_type_parameter->hasDefaultArgument()) {
640#if LLVM_VERSION_MAJOR > 18
642 template_type_parameter->getDefaultArgument(),
643 template_declaration.getASTContext());
645 template_type_parameter->getDefaultArgument().getAsString();
649 auto parameter_name = template_type_parameter->getNameAsString();
650 if (parameter_name.empty())
651 parameter_name =
"typename";
654 default_arg, template_type_parameter->isParameterPack());
656 if constexpr (std::is_same_v<
typename VisitorT::diagram_t,
658 if (template_type_parameter->getTypeConstraint() !=
nullptr) {
660 template_type_parameter->getTypeConstraint()
662 [
this, &ct, &templated_element](
663 const clang::ConceptDecl *named_concept)
mutable {
664 ct.set_concept_constraint(
665 named_concept->getQualifiedNameAsString());
666 if (templated_element &&
667 visitor_.should_include(named_concept)) {
668 templated_element.value().add_relationship(
669 {relationship_t::kConstraint,
672 eid_t{named_concept->getID()})
674 model::access_t::kNone,
681 (void)templated_element;
686 else if (clang::dyn_cast_or_null<clang::NonTypeTemplateParmDecl>(
687 parameter) !=
nullptr) {
688 const auto *template_nontype_parameter =
689 clang::dyn_cast_or_null<clang::NonTypeTemplateParmDecl>(
692 std::optional<std::string> default_arg;
694 if (template_nontype_parameter->hasDefaultArgument()) {
696#if LLVM_VERSION_MAJOR > 18
698 template_nontype_parameter->getDefaultArgument(),
699 template_declaration.getASTContext());
702 template_nontype_parameter->getDefaultArgument());
706 template_nontype_parameter->getType().getAsString(),
707 template_nontype_parameter->getNameAsString(), default_arg,
708 template_nontype_parameter->isParameterPack());
712 else if (clang::dyn_cast_or_null<clang::TemplateTemplateParmDecl>(
713 parameter) !=
nullptr) {
714 const auto *template_template_parameter =
715 clang::dyn_cast_or_null<clang::TemplateTemplateParmDecl>(
717 std::optional<std::string> default_arg;
718 if (template_template_parameter->hasDefaultArgument()) {
720 template_template_parameter->getDefaultArgument()
724 template_template_parameter->getNameAsString(), default_arg,
725 template_template_parameter->isParameterPack());
735template <
typename VisitorT>
738 const clang::NamedDecl *cls,
739 const clang::TemplateSpecializationType &template_type_decl,
740 std::optional<clanguml::common::model::template_element *> parent)
742 const auto *template_type_ptr = &template_type_decl;
744 if (template_type_decl.isTypeAlias()) {
745 if (
const auto *tsp =
746 template_type_decl.getAliasedType()
747 ->template getAs<clang::TemplateSpecializationType>();
749 template_type_ptr = tsp;
752 const auto &template_type = *template_type_ptr;
757 template_type.desugar(),
758 template_type.getTemplateName().getAsTemplateDecl()->getASTContext());
760 auto *template_decl{template_type.getTemplateName().getAsTemplateDecl()};
762 build(template_instantiation, cls, template_decl,
763 template_type.template_arguments(), full_template_specialization_name,
767template <
typename VisitorT>
770 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
771 const clang::ArrayRef<clang::TemplateArgument> template_arguments,
772 std::string full_template_specialization_name,
773 std::optional<clanguml::common::model::template_element *> parent)
779 std::deque<std::tuple< std::string, int,
781 template_base_params{};
783 auto template_decl_qualified_name =
784 template_decl->getQualifiedNameAsString();
786 if (
const auto *class_template_decl =
787 clang::dyn_cast<clang::ClassTemplateDecl>(template_decl);
788 (class_template_decl !=
nullptr) &&
789 (class_template_decl->getTemplatedDecl() !=
nullptr) &&
790 (class_template_decl->getTemplatedDecl()->getParent() !=
nullptr) &&
791 class_template_decl->getTemplatedDecl()->getParent()->isRecord()) {
796 ->getOuterLexicalRecordContext())};
799 std::string name = template_decl->getQualifiedNameAsString();
800 if (!ns_str.empty()) {
801 name = name.substr(ns_str.size() + 2);
805 template_instantiation.
set_name(name);
810 namespace_ ns{template_decl_qualified_name};
812 template_instantiation.
set_name(template_decl->getNameAsString());
821 std::pair< std::string,
bool>>
822 template_parameter_names{};
824 for (
const auto *parameter : *template_decl->getTemplateParameters()) {
825 if (parameter->isTemplateParameter() &&
826 (parameter->isTemplateParameterPack() ||
827 parameter->isParameterPack())) {
828 template_parameter_names.emplace_back(
829 parameter->getNameAsString(),
true);
832 template_parameter_names.emplace_back(
833 parameter->getNameAsString(),
false);
839 const auto *templated_class_decl =
840 clang::dyn_cast_or_null<clang::CXXRecordDecl>(
841 template_decl->getTemplatedDecl());
843 if ((templated_class_decl !=
nullptr) &&
844 templated_class_decl->hasDefinition())
845 for (
const auto &base : templated_class_decl->bases()) {
847 base.getType(), templated_class_decl->getASTContext(),
false);
849 LOG_DBG(
"Found template instantiation base: {}, {}",
850 base_class_name, base_index);
854 auto it = std::find_if(template_parameter_names.begin(),
855 template_parameter_names.end(),
857 const auto &p) { return p.first == base_class_name; });
859 if (it != template_parameter_names.end()) {
860 const auto ¶meter_name = it->first;
861 const bool is_variadic = it->second;
863 LOG_DBG(
"Found base class which is a template parameter "
865 parameter_name, is_variadic,
866 std::distance(template_parameter_names.begin(), it));
868 template_base_params.emplace_back(parameter_name,
869 std::distance(template_parameter_names.begin(), it),
879 process_template_arguments(parent, cls, template_base_params,
880 template_arguments, template_instantiation, template_decl);
882 if constexpr (std::is_same_v<
typename VisitorT::diagram_t,
884 find_instantiation_relationships(template_instantiation,
885 eid_t{template_decl->getID()}, full_template_specialization_name);
888 template_instantiation.
set_id(
891 visitor_.set_source_location(*cls, template_instantiation);
894template <
typename VisitorT>
897 const clang::ClassTemplateSpecializationDecl &template_specialization,
898 std::optional<clanguml::common::model::template_element *> parent)
904 std::deque<std::tuple< std::string, int,
906 template_base_params{};
908 const clang::ClassTemplateDecl *template_decl =
909 template_specialization.getSpecializedTemplate();
911 auto qualified_name = template_decl->getQualifiedNameAsString();
913 namespace_ ns{qualified_name};
915 template_instantiation.
set_name(template_decl->getNameAsString());
918 process_template_arguments(parent, &template_specialization,
919 template_base_params,
920 template_specialization.getTemplateArgs().asArray(),
921 template_instantiation, template_decl);
924 template_instantiation.
set_id(
927 if constexpr (std::is_same_v<
typename VisitorT::diagram_t,
929 find_instantiation_relationships(template_instantiation,
930 eid_t{template_specialization.getID()}, qualified_name);
933 visitor_.set_source_location(*template_decl, template_instantiation);
936template <
typename VisitorT>
939 const std::string &qualified_name)
const
942 template_instantiation, qualified_name,
id);
945template <
typename VisitorT>
947 std::optional<clanguml::common::model::template_element *> &parent,
948 const clang::NamedDecl *cls,
949 std::deque<std::tuple<std::string, int, bool>> &template_base_params,
950 const clang::ArrayRef<clang::TemplateArgument> &template_args,
952 const clang::TemplateDecl *template_decl)
956 for (
const auto &arg : template_args) {
959 std::vector<template_parameter> arguments;
962 if (arg.getKind() == clang::TemplateArgument::ArgKind::Pack &&
963 arg.getPackAsArray().empty()) {
965 template_parameter::make_empty());
974 if (!diagram().should_include(
975 namespace_{template_decl->getQualifiedNameAsString()})) {
976 const auto *maybe_type_parm_decl =
977 clang::dyn_cast<clang::TemplateTypeParmDecl>(
978 template_decl->getTemplateParameters()->getParam(
979 std::min<unsigned>(arg_index,
980 static_cast<unsigned>(
981 template_decl->getTemplateParameters()
984 if (maybe_type_parm_decl !=
nullptr &&
985 maybe_type_parm_decl->hasDefaultArgument()) {
993 argument_process_dispatch(parent, cls, template_instantiation,
994 template_decl, arg, arg_index, arguments);
996 if (arguments.empty()) {
1005 [[maybe_unused]]
auto variadic_params{
false};
1007 if constexpr (std::is_same_v<
typename VisitorT::diagram_t,
1011 if (!template_base_params.empty()) {
1012 variadic_params = add_base_classes(template_instantiation,
1013 template_base_params, arg_index, variadic_params,
1018 for (
auto &argument : arguments) {
1019 simplify_system_template(
1020 argument, argument.to_string(using_namespace(),
false,
true));
1022 LOG_DBG(
"Adding template argument {} to template "
1023 "specialization/instantiation {}",
1024 argument.to_string(using_namespace(),
false),
1025 template_instantiation.
name());
1027 template_instantiation.
add_template(std::move(argument));
1034 template_instantiation.
set_id(
1038template <
typename VisitorT>
1040 std::optional<clanguml::common::model::template_element *> &parent,
1041 const clang::NamedDecl *cls,
1043 const clang::TemplateDecl *template_decl,
1044 const clang::TemplateArgument &arg,
size_t argument_index,
1045 std::vector<template_parameter> &argument)
1047 LOG_DBG(
"Processing argument {} in template class: {}", argument_index,
1048 cls->getQualifiedNameAsString());
1050 switch (arg.getKind()) {
1051 case clang::TemplateArgument::Null:
1052 argument.push_back(process_null_argument(arg));
1054 case clang::TemplateArgument::Template:
1055 argument.push_back(process_template_argument(arg));
1057 case clang::TemplateArgument::Type: {
1058 argument.push_back(process_type_argument(parent, cls, template_decl,
1059 arg.getAsType(), template_instantiation, argument_index));
1062 case clang::TemplateArgument::Declaration:
1064 case clang::TemplateArgument::NullPtr:
1065 argument.push_back(process_nullptr_argument(arg));
1067 case clang::TemplateArgument::Integral:
1069 process_integral_argument(arg, template_decl->getASTContext()));
1071 case clang::TemplateArgument::TemplateExpansion:
1072 argument.push_back(process_template_expansion(arg));
1074 case clang::TemplateArgument::Expression:
1075 argument.push_back(process_expression_argument(arg));
1077 case clang::TemplateArgument::Pack:
1079 process_pack_argument(parent, cls, template_instantiation,
1080 template_decl, arg, argument_index, argument)) {
1081 argument.push_back(a);
1084#if LLVM_VERSION_MAJOR > 17
1085 case clang::TemplateArgument::StructuralValue:
1091template <
typename VisitorT>
1093 const clang::TemplateArgument &arg)
1097 LOG_DBG(
"Processing template argument: {}", arg_name);
1099 return template_parameter::make_template_type(arg_name);
1102template <
typename VisitorT>
1104 const clang::TemplateArgument &arg)
1108 LOG_DBG(
"Processing template expansion argument: {}", arg_name);
1111 arg.getAsTemplate().getAsTemplateDecl(), [&arg_name](
const auto *decl) {
1112 arg_name = decl->getQualifiedNameAsString();
1115 auto param = template_parameter::make_template_type(arg_name);
1116 param.is_variadic(
true);
1121template <
typename VisitorT>
1129 return unqualified_type;
1132template <
typename VisitorT>
1134 std::optional<clanguml::common::model::template_element *> &parent,
1135 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
1136 clang::QualType type,
1138 size_t argument_index)
1140 std::optional<template_parameter> argument;
1142 if (type->getAs<clang::ElaboratedType>() !=
nullptr) {
1143 type = type->getAs<clang::ElaboratedType>()->getNamedType();
1148 LOG_DBG(
"Processing template {} type argument {}: {}, {}, {}",
1149 template_decl->getQualifiedNameAsString(), argument_index, type_name,
1150 type->getTypeClassName(),
1153 argument = try_as_function_prototype(parent, cls, template_decl, type,
1154 template_instantiation, argument_index);
1158 argument = try_as_member_pointer(parent, cls, template_decl, type,
1159 template_instantiation, argument_index);
1163 argument = try_as_array(parent, cls, template_decl, type,
1164 template_instantiation, argument_index);
1168 argument = try_as_template_parm_type(cls, template_decl, type);
1172 argument = try_as_template_specialization_type(parent, cls, template_decl,
1173 type, template_instantiation, argument_index);
1177 argument = try_as_decl_type(parent, cls, template_decl, type,
1178 template_instantiation, argument_index);
1182 argument = try_as_typedef_type(parent, cls, template_decl, type,
1183 template_instantiation, argument_index);
1187 argument = try_as_lambda(cls, template_decl, type);
1191 argument = try_as_record_type(parent, cls, template_decl, type,
1192 template_instantiation, argument_index);
1196 argument = try_as_enum_type(
1197 parent, cls, template_decl, type, template_instantiation);
1201 argument = try_as_builtin_type(parent, type, template_decl);
1206 return template_parameter::make_argument(type_name);
1209template <
typename VisitorT>
1214 const auto &type = ct.
type();
1220 LOG_DBG(
"Finding relationships in user defined type: {}",
1221 ct.
to_string(config().using_namespace(),
false));
1223 auto type_with_namespace =
1224 std::make_optional<common::model::namespace_>(type.value());
1226 if (!type_with_namespace.has_value()) {
1231 auto element_opt = diagram().get(type_with_namespace.value().to_string());
1232 if (config_.generate_template_argument_dependencies() && element_opt) {
1233 relationships.emplace_back(
1234 element_opt.value().id(), relationship_t::kDependency);
1239 found = find_relationships_in_unexposed_template_params(
1240 nested_template_params, relationships) ||
1247template <
typename VisitorT>
1249 const clang::TemplateArgument &arg,
const clang::ASTContext &ast_context)
1251 assert(arg.getKind() == clang::TemplateArgument::Integral);
1254 llvm::raw_string_ostream ostream(result);
1255 clang::PrintingPolicy policy(ast_context.getLangOpts());
1257#if LLVM_VERSION_MAJOR > 18
1258 arg.print(policy, ostream,
false);
1263 return template_parameter::make_argument(result);
1266#if LLVM_VERSION_MAJOR > 17
1267template <
typename VisitorT>
1269 const clang::TemplateArgument &arg,
const clang::ASTContext &ast_context)
1271 assert(arg.getKind() == clang::TemplateArgument::StructuralValue);
1274 llvm::raw_string_ostream ostream(result);
1275 clang::PrintingPolicy policy(ast_context.getLangOpts());
1277#if LLVM_VERSION_MAJOR > 18
1278 arg.print(policy, ostream,
false);
1283 return template_parameter::make_argument(result);
1287template <
typename VisitorT>
1289 const clang::TemplateArgument &arg)
1291 assert(arg.getKind() == clang::TemplateArgument::Null);
1293 return template_parameter::make_argument(
"");
1296template <
typename VisitorT>
1298 const clang::TemplateArgument &arg)
1300 assert(arg.getKind() == clang::TemplateArgument::NullPtr);
1304 return template_parameter::make_argument(
"nullptr");
1307template <
typename VisitorT>
1309 const clang::TemplateArgument &arg)
1311 assert(arg.getKind() == clang::TemplateArgument::Expression);
1313 arg.getAsExpr()->getSourceRange(), source_manager()));
1316template <
typename VisitorT>
1317std::vector<template_parameter>
1319 std::optional<clanguml::common::model::template_element *> &parent,
1320 const clang::NamedDecl *cls,
1322 const clang::TemplateDecl *base_template_decl,
1323 const clang::TemplateArgument &arg,
size_t argument_index,
1324 std::vector<template_parameter> & )
1326 assert(arg.getKind() == clang::TemplateArgument::Pack);
1328 std::vector<template_parameter> res;
1330 auto pack_argument_index = argument_index;
1332 for (
const auto &a : arg.getPackAsArray()) {
1333 argument_process_dispatch(parent, cls, template_instantiation,
1334 base_template_decl, a, pack_argument_index++, res);
1340template <
typename VisitorT>
1341std::optional<template_parameter>
1343 std::optional<clanguml::common::model::template_element *> &parent,
1344 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
1345 clang::QualType &type,
1347 size_t argument_index)
1349 const auto *mp_type =
1351 if (mp_type ==
nullptr)
1354 auto argument = template_parameter::make_template_type(
"");
1355 type = consume_context(type, argument);
1358 if (mp_type->isMemberDataPointer()) {
1359 argument.is_member_pointer(
false);
1360 argument.is_data_pointer(
true);
1362 auto pointee_arg = process_type_argument(parent, cls, template_decl,
1363 mp_type->getPointeeType(), template_instantiation, argument_index);
1365 argument.add_template_param(std::move(pointee_arg));
1367 const auto *member_class_type = mp_type->getClass();
1369 if (member_class_type ==
nullptr)
1372 auto class_type_arg = process_type_argument(parent, cls, template_decl,
1373 mp_type->getClass()->getCanonicalTypeUnqualified(),
1374 template_instantiation, argument_index);
1376 argument.add_template_param(std::move(class_type_arg));
1380 argument.is_member_pointer(
true);
1381 argument.is_data_pointer(
false);
1383 const auto *function_type =
1384 mp_type->getPointeeType()->getAs<clang::FunctionProtoType>();
1386 assert(function_type !=
nullptr);
1388 auto return_type_arg = process_type_argument(parent, cls, template_decl,
1389 function_type->getReturnType(), template_instantiation,
1393 argument.add_template_param(std::move(return_type_arg));
1395 const auto *member_class_type = mp_type->getClass();
1397 if (member_class_type ==
nullptr)
1400 auto class_type_arg = process_type_argument(parent, cls, template_decl,
1401 mp_type->getClass()->getCanonicalTypeUnqualified(),
1402 template_instantiation, argument_index);
1405 argument.add_template_param(std::move(class_type_arg));
1408 for (
const auto ¶m_type : function_type->param_types()) {
1409 argument.add_template_param(
1410 process_type_argument(parent, cls, template_decl, param_type,
1411 template_instantiation, argument_index));
1418template <
typename VisitorT>
1420 std::optional<clanguml::common::model::template_element *> &parent,
1421 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
1422 clang::QualType &type,
1424 size_t argument_index)
1427 if (array_type ==
nullptr)
1430 auto argument = template_parameter::make_template_type(
"");
1432 type = consume_context(type, argument);
1434 argument.is_array(
true);
1437 auto element_type = process_type_argument(parent, cls, template_decl,
1438 array_type->getElementType(), template_instantiation, argument_index);
1440 argument.add_template_param(element_type);
1442 if (array_type->isDependentSizedArrayType() &&
1443 array_type->getDependence() ==
1444 clang::TypeDependence::DependentInstantiation) {
1445 argument.add_template_param(
1447 ((clang::DependentSizedArrayType *)array_type)
1450 else if (array_type->isConstantArrayType()) {
1451 argument.add_template_param(template_parameter::make_argument(
1452 std::to_string(((clang::ConstantArrayType *)array_type)
1454 .getLimitedValue())));
1462template <
typename VisitorT>
1463std::optional<template_parameter>
1465 std::optional<clanguml::common::model::template_element *> &parent,
1466 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
1467 clang::QualType &type,
1469 size_t argument_index)
1471 const auto *function_type = type->getAs<clang::FunctionProtoType>();
1473 if (function_type ==
nullptr && type->isFunctionPointerType()) {
1475 type->getPointeeType()->getAs<clang::FunctionProtoType>();
1476 if (function_type ==
nullptr)
1480 if (function_type ==
nullptr)
1483 LOG_DBG(
"Template argument is a function prototype");
1485 auto argument = template_parameter::make_template_type(
"");
1487 type = consume_context(type, argument);
1489 argument.is_function_template(
true);
1492 auto return_arg = process_type_argument(parent, cls, template_decl,
1493 function_type->getReturnType(), template_instantiation, argument_index);
1495 argument.add_template_param(return_arg);
1498 if (function_type->isVariadic() && function_type->param_types().empty()) {
1499 auto fallback_arg = template_parameter::make_argument({});
1500 fallback_arg.is_ellipsis(
true);
1501 argument.add_template_param(std::move(fallback_arg));
1504 for (
const auto ¶m_type : function_type->param_types()) {
1505 argument.add_template_param(
1506 process_type_argument(parent, cls, template_decl, param_type,
1507 template_instantiation, argument_index));
1514template <
typename VisitorT>
1516 std::optional<clanguml::common::model::template_element *> & ,
1517 const clang::NamedDecl * ,
1518 const clang::TemplateDecl * , clang::QualType &type,
1522 const auto *decl_type =
1524 if (decl_type ==
nullptr) {
1528 LOG_DBG(
"Template argument is a decltype()");
1534template <
typename VisitorT>
1535std::optional<template_parameter>
1537 std::optional<clanguml::common::model::template_element *> &parent,
1538 const clang::NamedDecl * ,
1539 const clang::TemplateDecl * , clang::QualType &type,
1543 const auto *typedef_type =
1545 if (typedef_type ==
nullptr) {
1549 LOG_DBG(
"Template argument is a typedef/using");
1553 if (typedef_type->getAs<clang::DecltypeType>() !=
nullptr) {
1557 if (typedef_type->getDecl()->isCXXClassMember() && parent) {
1558 return template_parameter::make_argument(
1559 fmt::format(
"{}::{}", parent.value()->full_name(
false),
1560 typedef_type->getDecl()->getNameAsString()));
1563 return template_parameter::make_argument(
1564 typedef_type->getDecl()->getQualifiedNameAsString());
1570template <
typename VisitorT>
1571std::optional<template_parameter>
1573 std::optional<clanguml::common::model::template_element *> &parent,
1574 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
1575 clang::QualType &type,
1577 size_t argument_index)
1579 const auto *nested_template_type =
1581 if (nested_template_type ==
nullptr) {
1585 LOG_DBG(
"Template argument is a template specialization type");
1587 auto argument = template_parameter::make_argument(
"");
1588 type = consume_context(type, argument);
1590 auto nested_type_name = nested_template_type->getTemplateName()
1591 .getAsTemplateDecl()
1592 ->getQualifiedNameAsString();
1594 if (clang::dyn_cast<clang::TemplateTemplateParmDecl>(
1595 nested_template_type->getTemplateName().getAsTemplateDecl()) !=
1597 if (
const auto *template_specialization_decl =
1598 clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(cls);
1599 template_specialization_decl !=
nullptr) {
1601 template_specialization_decl->getDescribedTemplateParams()
1602 ->getParam(argument_index)
1603 ->getNameAsString();
1607 nested_type_name =
"template";
1610 argument.is_template_template_parameter(
true);
1613 argument.set_type(nested_type_name);
1615 auto nested_template_instantiation =
1616 visitor_.create_element(nested_template_type->getTemplateName()
1617 .getAsTemplateDecl()
1618 ->getTemplatedDecl());
1619 build_from_template_specialization_type(*nested_template_instantiation, cls,
1620 *nested_template_type,
1621 diagram().should_include(
1622 namespace_{template_decl->getQualifiedNameAsString()})
1623 ? std::make_optional(&template_instantiation)
1626 argument.set_id(nested_template_instantiation->id());
1628 for (
const auto &t : nested_template_instantiation->template_params())
1629 argument.add_template_param(t);
1634 simplify_system_template(
1635 argument, argument.to_string(using_namespace(),
false));
1638 common::to_id(argument.to_string(using_namespace(),
false)));
1640 const auto nested_template_instantiation_full_name =
1641 nested_template_instantiation->full_name(
false);
1643 if (nested_template_instantiation &&
1644 diagram().should_include(
1645 namespace_{nested_template_instantiation_full_name})) {
1646 if (config_.generate_template_argument_dependencies()) {
1647 if (diagram().should_include(
1648 namespace_{template_decl->getQualifiedNameAsString()})) {
1650 {relationship_t::kDependency,
1651 nested_template_instantiation->id()});
1654 if (parent.has_value())
1655 parent.value()->add_relationship(
1656 {relationship_t::kDependency,
1657 nested_template_instantiation->id()});
1662 if (diagram().should_include(
1663 namespace_{nested_template_instantiation_full_name})) {
1664 visitor_.set_source_location(*cls, *nested_template_instantiation);
1665 visitor_.add_diagram_element(std::move(nested_template_instantiation));
1671template <
typename VisitorT>
1672std::optional<template_parameter>
1674 const clang::NamedDecl *cls,
const clang::TemplateDecl * ,
1675 clang::QualType &type)
1677 auto is_variadic{
false};
1679 const auto *type_parameter =
1684 if (type_parameter ==
nullptr) {
1685 if (
const auto *pet =
1690 pet->getPattern()->getAs<clang::TemplateTypeParmType>();
1694 if (type_parameter ==
nullptr)
1697 LOG_DBG(
"Template argument is a template parameter type");
1699 auto argument = template_parameter::make_template_type(
"");
1700 type = consume_context(type, argument);
1703 if (type_parameter_name.empty())
1704 type_parameter_name =
"typename";
1707 cls, type_parameter_name));
1709 argument.is_variadic(is_variadic);
1716template <
typename VisitorT>
1718 const clang::NamedDecl *cls,
const clang::TemplateDecl * ,
1719 clang::QualType &type)
1723 if (type_name.find(
"(lambda at ") != 0)
1726 LOG_DBG(
"Template argument is a lambda");
1728 auto argument = template_parameter::make_argument(
"");
1729 type = consume_context(type, argument);
1732 argument.set_type(type_name);
1737template <
typename VisitorT>
1738std::optional<template_parameter>
1740 std::optional<clanguml::common::model::template_element *> &parent,
1741 const clang::NamedDecl * ,
const clang::TemplateDecl *template_decl,
1742 clang::QualType &type,
1746 const auto *record_type =
1748 if (record_type ==
nullptr)
1751 LOG_DBG(
"Template argument is a c++ record");
1753 auto argument = template_parameter::make_argument({});
1754 type = consume_context(type, argument);
1756 const auto type_name = config().simplify_template_type(
1759 argument.set_type(type_name);
1762 argument.set_id(type_id);
1764 const auto *class_template_specialization =
1765 clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(
1766 record_type->getAsRecordDecl());
1768 if (class_template_specialization !=
nullptr) {
1770 visitor_.create_element(class_template_specialization);
1772 build_from_class_template_specialization(
1773 *tag_argument, *class_template_specialization);
1775 tag_argument->is_template(
true);
1778 argument.set_type(tag_argument->name_and_ns());
1779 for (
const auto &p : tag_argument->template_params())
1780 argument.add_template_param(p);
1781 for (
auto &r : tag_argument->relationships()) {
1785 if (config_.generate_template_argument_dependencies() &&
1786 diagram().should_include(tag_argument->get_namespace())) {
1787 if (parent.has_value())
1788 parent.value()->add_relationship(
1789 {relationship_t::kDependency, tag_argument->id()});
1790 visitor_.set_source_location(*template_decl, *tag_argument);
1791 visitor_.add_diagram_element(std::move(tag_argument));
1795 else if (
const auto *record_type_decl = record_type->getAsRecordDecl();
1796 record_type_decl !=
nullptr) {
1797 if (config_.generate_template_argument_dependencies() &&
1798 diagram().should_include(namespace_{type_name})) {
1802 {relationship_t::kDependency, type_id});
1809template <
typename VisitorT>
1811 std::optional<clanguml::common::model::template_element *> & ,
1812 const clang::NamedDecl * ,
const clang::TemplateDecl *template_decl,
1813 clang::QualType &type,
1816 const auto *enum_type = type->getAs<clang::EnumType>();
1817 if (enum_type ==
nullptr)
1820 LOG_DBG(
"Template argument is a an enum");
1822 auto argument = template_parameter::make_argument({});
1823 type = consume_context(type, argument);
1826 argument.set_type(type_name);
1828 argument.set_id(type_id);
1830 if (enum_type->getAsTagDecl() !=
nullptr &&
1831 config_.generate_template_argument_dependencies()) {
1833 {relationship_t::kDependency, type_id});
1839template <
typename VisitorT>
1840std::optional<template_parameter>
1842 std::optional<clanguml::common::model::template_element *> & ,
1843 clang::QualType &type,
const clang::TemplateDecl *template_decl)
1845 const auto *builtin_type = type->getAs<clang::BuiltinType>();
1846 if (builtin_type ==
nullptr)
1849 LOG_DBG(
"Template argument is a builtin type");
1852 auto argument = template_parameter::make_argument(type_name);
1854 type = consume_context(type, argument);
1855 argument.set_type(type_name);
1860template <
typename VisitorT>
1863 std::deque<std::tuple<std::string, int, bool>> &template_base_params,
1866 bool add_template_argument_as_base_class =
false;
1868 if (variadic_params) {
1869 add_template_argument_as_base_class =
true;
1872 auto [arg_name, index, is_variadic] = template_base_params.front();
1874 variadic_params = is_variadic;
1875 if ((arg_index == index) || (is_variadic && arg_index >= index)) {
1876 add_template_argument_as_base_class =
true;
1879 template_base_params.pop_front();
1884 const auto maybe_id = ct.
id();
1885 if (add_template_argument_as_base_class && maybe_id) {
1886 LOG_DBG(
"Adding template argument as base class '{}'",
1894 return variadic_params;