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,
111 const clang::NamedDecl &location_declaration,
113 const clang::NamedDecl *cls,
114 const clang::TemplateSpecializationType &template_type_decl,
115 std::optional<clanguml::common::model::template_element *> parent = {});
117 void build(
const clang::NamedDecl &location_declaration,
119 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
120 clang::ArrayRef<clang::TemplateArgument> template_arguments,
121 std::string full_template_specialization_name,
122 std::optional<clanguml::common::model::template_element *> parent = {});
133 const clang::ClassTemplateSpecializationDecl &template_specialization,
134 std::optional<clanguml::common::model::template_element *> parent = {});
151 std::deque<std::tuple<std::string, int, bool>> &template_base_params,
152 int arg_index,
bool variadic_params,
166 std::optional<clanguml::common::model::template_element *> &parent,
167 const clang::NamedDecl *cls,
168 std::deque<std::tuple<std::string, int, bool>> &template_base_params,
169 const clang::ArrayRef<clang::TemplateArgument> &template_args,
171 const clang::TemplateDecl *template_decl);
186 std::optional<clanguml::common::model::template_element *> &parent,
187 const clang::NamedDecl *cls,
189 const clang::TemplateDecl *template_decl,
190 const clang::TemplateArgument &arg,
size_t argument_index,
191 std::vector<template_parameter> &argument);
203 const clang::TemplateArgument &arg);
216 const clang::TemplateArgument &arg,
217 const clang::ASTContext &ast_context);
219#if LLVM_VERSION_MAJOR > 17
231 const clang::TemplateArgument &arg,
232 const clang::ASTContext &ast_context);
245 const clang::TemplateArgument &arg);
257 const clang::TemplateArgument &arg);
269 const clang::NamedDecl &location_decl,
270 std::optional<clanguml::common::model::template_element *> &parent,
271 const clang::NamedDecl *cls,
273 const clang::TemplateDecl *base_template_decl,
274 const clang::TemplateArgument &arg,
size_t argument_index,
275 std::vector<template_parameter> &argument);
286 const clang::NamedDecl &location_decl,
287 std::optional<clanguml::common::model::template_element *> &parent,
288 const clang::NamedDecl *cls,
289 const clang::TemplateDecl *base_template_decl, clang::QualType type,
291 size_t argument_index);
303 const clang::TemplateArgument &arg);
315 const clang::TemplateArgument &arg);
329 const clang::NamedDecl &location_decl,
330 std::optional<clanguml::common::model::template_element *> &parent,
331 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
332 clang::QualType &type,
334 size_t argument_index);
348 const clang::NamedDecl &location_decl,
349 std::optional<clanguml::common::model::template_element *> &parent,
350 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
351 clang::QualType &type,
353 size_t argument_index);
368 const clang::NamedDecl &location_decl,
369 std::optional<clanguml::common::model::template_element *> &parent,
370 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
371 clang::QualType &type,
373 size_t argument_index);
384 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
385 clang::QualType &type);
395 std::optional<template_parameter>
try_as_lambda(
const clang::NamedDecl *cls,
396 const clang::TemplateDecl *template_decl, clang::QualType &type);
410 const clang::NamedDecl &location_decl,
411 std::optional<clanguml::common::model::template_element *> &parent,
412 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
413 clang::QualType &type,
415 size_t argument_index);
428 std::optional<clanguml::common::model::template_element *> &parent,
429 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
430 clang::QualType &type,
442 std::optional<clanguml::common::model::template_element *> &parent,
443 clang::QualType &type,
const clang::TemplateDecl *template_decl);
458 const clang::NamedDecl &location_decl,
459 std::optional<clanguml::common::model::template_element *> &parent,
460 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
461 clang::QualType &type,
463 size_t argument_index);
477 std::optional<clanguml::common::model::template_element *> &parent,
478 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
479 clang::QualType &type,
481 size_t argument_index);
495 std::optional<clanguml::common::model::template_element *> &parent,
496 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
497 clang::QualType &type,
499 size_t argument_index);
535 const std::string &qualified_name)
const;
565template <
typename VisitorT>
571 , id_mapper_{visitor.id_mapper()}
572 , source_manager_{visitor.source_manager()}
577template <
typename VisitorT>
583template <
typename VisitorT>
589template <
typename VisitorT>
592 return config_.using_namespace();
595template <
typename VisitorT>
601template <
typename VisitorT>
604 return source_manager_;
607template <
typename VisitorT>
614 auto simplified = config().simplify_template_type(full_name);
616 if (simplified != full_name) {
626template <
typename VisitorT>
629 const clang::TemplateDecl &template_declaration,
632 LOG_DBG(
"Processing {} template parameters...",
635 if (template_declaration.getTemplateParameters() ==
nullptr)
638 for (
const auto *parameter :
639 *template_declaration.getTemplateParameters()) {
640 if (clang::dyn_cast_or_null<clang::TemplateTypeParmDecl>(parameter) !=
642 const auto *template_type_parameter =
643 clang::dyn_cast_or_null<clang::TemplateTypeParmDecl>(parameter);
645 std::optional<std::string> default_arg;
646 if (template_type_parameter->hasDefaultArgument()) {
648#if LLVM_VERSION_MAJOR > 18
650 template_type_parameter->getDefaultArgument(),
651 template_declaration.getASTContext());
653 template_type_parameter->getDefaultArgument().getAsString();
657 auto parameter_name = template_type_parameter->getNameAsString();
658 if (parameter_name.empty())
659 parameter_name =
"typename";
662 default_arg, template_type_parameter->isParameterPack());
664 if constexpr (std::is_same_v<
typename VisitorT::diagram_t,
666 if (template_type_parameter->getTypeConstraint() !=
nullptr) {
668 template_type_parameter->getTypeConstraint()
670 [
this, &ct, &templated_element](
671 const clang::ConceptDecl *named_concept)
mutable {
672 ct.set_concept_constraint(
673 named_concept->getQualifiedNameAsString());
674 if (templated_element &&
675 visitor_.should_include(named_concept)) {
676 templated_element.value().add_relationship(
677 {relationship_t::kConstraint,
680 eid_t{named_concept->getID()})
682 model::access_t::kNone,
689 (void)templated_element;
694 else if (clang::dyn_cast_or_null<clang::NonTypeTemplateParmDecl>(
695 parameter) !=
nullptr) {
696 const auto *template_nontype_parameter =
697 clang::dyn_cast_or_null<clang::NonTypeTemplateParmDecl>(
700 std::optional<std::string> default_arg;
702 if (template_nontype_parameter->hasDefaultArgument()) {
704#if LLVM_VERSION_MAJOR > 18
706 template_nontype_parameter->getDefaultArgument(),
707 template_declaration.getASTContext());
710 template_nontype_parameter->getDefaultArgument());
714 template_nontype_parameter->getType().getAsString(),
715 template_nontype_parameter->getNameAsString(), default_arg,
716 template_nontype_parameter->isParameterPack());
720 else if (clang::dyn_cast_or_null<clang::TemplateTemplateParmDecl>(
721 parameter) !=
nullptr) {
722 const auto *template_template_parameter =
723 clang::dyn_cast_or_null<clang::TemplateTemplateParmDecl>(
725 std::optional<std::string> default_arg;
726 if (template_template_parameter->hasDefaultArgument()) {
728 template_template_parameter->getDefaultArgument()
732 template_template_parameter->getNameAsString(), default_arg,
733 template_template_parameter->isParameterPack());
743template <
typename VisitorT>
745 const clang::NamedDecl &location_declaration,
747 const clang::NamedDecl *cls,
748 const clang::TemplateSpecializationType &template_type_decl,
749 std::optional<clanguml::common::model::template_element *> parent)
751 const auto *template_type_ptr = &template_type_decl;
753 if (template_type_decl.isTypeAlias()) {
754 if (
const auto *tsp =
755 template_type_decl.getAliasedType()
756 ->template getAs<clang::TemplateSpecializationType>();
758 template_type_ptr = tsp;
761 const auto &template_type = *template_type_ptr;
766 template_type.desugar(),
767 template_type.getTemplateName().getAsTemplateDecl()->getASTContext());
769 auto *template_decl{template_type.getTemplateName().getAsTemplateDecl()};
771 build(location_declaration, template_instantiation, cls, template_decl,
772 template_type.template_arguments(), full_template_specialization_name,
776template <
typename VisitorT>
779 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
780 const clang::ArrayRef<clang::TemplateArgument> template_arguments,
781 std::string full_template_specialization_name,
782 std::optional<clanguml::common::model::template_element *> parent)
788 std::deque<std::tuple< std::string, int,
790 template_base_params{};
792 auto template_decl_qualified_name =
793 template_decl->getQualifiedNameAsString();
795 if (
const auto *class_template_decl =
796 clang::dyn_cast<clang::ClassTemplateDecl>(template_decl);
797 (class_template_decl !=
nullptr) &&
798 (class_template_decl->getTemplatedDecl() !=
nullptr) &&
799 (class_template_decl->getTemplatedDecl()->getParent() !=
nullptr) &&
800 class_template_decl->getTemplatedDecl()->getParent()->isRecord()) {
805 ->getOuterLexicalRecordContext())};
808 std::string name = template_decl->getQualifiedNameAsString();
809 if (!ns_str.empty()) {
810 name = name.substr(ns_str.size() + 2);
814 template_instantiation.
set_name(name);
819 namespace_ ns{template_decl_qualified_name};
821 template_instantiation.
set_name(template_decl->getNameAsString());
830 std::pair< std::string,
bool>>
831 template_parameter_names{};
833 for (
const auto *parameter : *template_decl->getTemplateParameters()) {
834 if (parameter->isTemplateParameter() &&
835 (parameter->isTemplateParameterPack() ||
836 parameter->isParameterPack())) {
837 template_parameter_names.emplace_back(
838 parameter->getNameAsString(),
true);
841 template_parameter_names.emplace_back(
842 parameter->getNameAsString(),
false);
848 const auto *templated_class_decl =
849 clang::dyn_cast_or_null<clang::CXXRecordDecl>(
850 template_decl->getTemplatedDecl());
852 if ((templated_class_decl !=
nullptr) &&
853 templated_class_decl->hasDefinition())
854 for (
const auto &base : templated_class_decl->bases()) {
856 base.getType(), templated_class_decl->getASTContext(),
false);
858 LOG_DBG(
"Found template instantiation base: {}, {}",
859 base_class_name, base_index);
863 auto it = std::find_if(template_parameter_names.begin(),
864 template_parameter_names.end(),
866 const auto &p) { return p.first == base_class_name; });
868 if (it != template_parameter_names.end()) {
869 const auto ¶meter_name = it->first;
870 const bool is_variadic = it->second;
872 LOG_DBG(
"Found base class which is a template parameter "
874 parameter_name, is_variadic,
875 std::distance(template_parameter_names.begin(), it));
877 template_base_params.emplace_back(parameter_name,
878 std::distance(template_parameter_names.begin(), it),
888 process_template_arguments(location_decl, parent, cls, template_base_params,
889 template_arguments, template_instantiation, template_decl);
891 if constexpr (std::is_same_v<
typename VisitorT::diagram_t,
893 find_instantiation_relationships(template_instantiation,
894 eid_t{template_decl->getID()}, full_template_specialization_name);
897 template_instantiation.
set_id(
900 visitor_.set_source_location(location_decl, template_instantiation);
903template <
typename VisitorT>
906 const clang::ClassTemplateSpecializationDecl &template_specialization,
907 std::optional<clanguml::common::model::template_element *> parent)
909 LOG_DBG(
"Building class template specialization model: {}",
910 template_specialization.getQualifiedNameAsString());
916 std::deque<std::tuple< std::string, int,
918 template_base_params{};
920 const clang::ClassTemplateDecl *template_decl =
921 template_specialization.getSpecializedTemplate();
923 auto qualified_name = template_decl->getQualifiedNameAsString();
925 namespace_ ns{qualified_name};
927 template_instantiation.
set_name(template_decl->getNameAsString());
930 process_template_arguments(template_specialization, parent,
931 &template_specialization, template_base_params,
932 template_specialization.getTemplateArgs().asArray(),
933 template_instantiation, template_decl);
936 template_instantiation.
set_id(
939 if constexpr (std::is_same_v<
typename VisitorT::diagram_t,
941 find_instantiation_relationships(template_instantiation,
942 eid_t{template_specialization.getID()}, qualified_name);
945 visitor_.set_source_location(
946 template_specialization, template_instantiation);
949template <
typename VisitorT>
952 const std::string &qualified_name)
const
955 template_instantiation, qualified_name,
id);
958template <
typename VisitorT>
960 const clang::NamedDecl &location_decl,
961 std::optional<clanguml::common::model::template_element *> &parent,
962 const clang::NamedDecl *cls,
963 std::deque<std::tuple<std::string, int, bool>> &template_base_params,
964 const clang::ArrayRef<clang::TemplateArgument> &template_args,
966 const clang::TemplateDecl *template_decl)
970 for (
const auto &arg : template_args) {
973 std::vector<template_parameter> arguments;
976 if (arg.getKind() == clang::TemplateArgument::ArgKind::Pack &&
977 arg.getPackAsArray().empty()) {
979 template_parameter::make_empty());
988 if (!diagram().should_include(
989 namespace_{template_decl->getQualifiedNameAsString()})) {
990 const auto *maybe_type_parm_decl =
991 clang::dyn_cast<clang::TemplateTypeParmDecl>(
992 template_decl->getTemplateParameters()->getParam(
993 std::min<unsigned>(arg_index,
994 static_cast<unsigned>(
995 template_decl->getTemplateParameters()
998 if (maybe_type_parm_decl !=
nullptr &&
999 maybe_type_parm_decl->hasDefaultArgument()) {
1007 argument_process_dispatch(location_decl, parent, cls,
1008 template_instantiation, template_decl, arg, arg_index, arguments);
1010 if (arguments.empty()) {
1019 [[maybe_unused]]
auto variadic_params{
false};
1021 if constexpr (std::is_same_v<
typename VisitorT::diagram_t,
1025 if (!template_base_params.empty()) {
1026 variadic_params = add_base_classes(template_instantiation,
1027 template_base_params, arg_index, variadic_params,
1032 for (
auto &argument : arguments) {
1033 simplify_system_template(
1034 argument, argument.to_string(using_namespace(),
false,
true));
1036 LOG_DBG(
"Adding template argument {} to template "
1037 "specialization/instantiation {}",
1038 argument.to_string(using_namespace(),
false),
1039 template_instantiation.
name());
1041 template_instantiation.
add_template(std::move(argument));
1048 template_instantiation.
set_id(
1052template <
typename VisitorT>
1054 const clang::NamedDecl &location_decl,
1055 std::optional<clanguml::common::model::template_element *> &parent,
1056 const clang::NamedDecl *cls,
1058 const clang::TemplateDecl *template_decl,
1059 const clang::TemplateArgument &arg,
size_t argument_index,
1060 std::vector<template_parameter> &argument)
1062 LOG_DBG(
"Processing argument {} in template class: {}", argument_index,
1063 cls->getQualifiedNameAsString());
1065 switch (arg.getKind()) {
1066 case clang::TemplateArgument::Null:
1067 argument.push_back(process_null_argument(arg));
1069 case clang::TemplateArgument::Template:
1070 argument.push_back(process_template_argument(arg));
1072 case clang::TemplateArgument::Type: {
1074 process_type_argument(location_decl, parent, cls, template_decl,
1075 arg.getAsType(), template_instantiation, argument_index));
1078 case clang::TemplateArgument::Declaration:
1080 case clang::TemplateArgument::NullPtr:
1081 argument.push_back(process_nullptr_argument(arg));
1083 case clang::TemplateArgument::Integral:
1085 process_integral_argument(arg, template_decl->getASTContext()));
1087 case clang::TemplateArgument::TemplateExpansion:
1088 argument.push_back(process_template_expansion(arg));
1090 case clang::TemplateArgument::Expression:
1091 argument.push_back(process_expression_argument(arg));
1093 case clang::TemplateArgument::Pack:
1094 for (
auto &a : process_pack_argument(location_decl, parent, cls,
1095 template_instantiation, template_decl, arg, argument_index,
1097 argument.push_back(a);
1100#if LLVM_VERSION_MAJOR > 17
1101 case clang::TemplateArgument::StructuralValue:
1107template <
typename VisitorT>
1109 const clang::TemplateArgument &arg)
1113 LOG_DBG(
"Processing template argument: {}", arg_name);
1115 return template_parameter::make_template_type(arg_name);
1118template <
typename VisitorT>
1120 const clang::TemplateArgument &arg)
1124 LOG_DBG(
"Processing template expansion argument: {}", arg_name);
1127 arg.getAsTemplate().getAsTemplateDecl(), [&arg_name](
const auto *decl) {
1128 arg_name = decl->getQualifiedNameAsString();
1131 auto param = template_parameter::make_template_type(arg_name);
1132 param.is_variadic(
true);
1137template <
typename VisitorT>
1145 return unqualified_type;
1148template <
typename VisitorT>
1150 const clang::NamedDecl &location_decl,
1151 std::optional<clanguml::common::model::template_element *> &parent,
1152 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
1153 clang::QualType type,
1155 size_t argument_index)
1157 std::optional<template_parameter> argument;
1159 if (type->getAs<clang::ElaboratedType>() !=
nullptr) {
1160 type = type->getAs<clang::ElaboratedType>()->getNamedType();
1165 LOG_DBG(
"Processing template {} type argument {}: {}, {}, {}",
1166 template_decl->getQualifiedNameAsString(), argument_index, type_name,
1167 type->getTypeClassName(),
1170 argument = try_as_function_prototype(location_decl, parent, cls,
1171 template_decl, type, template_instantiation, argument_index);
1175 argument = try_as_member_pointer(location_decl, parent, cls, template_decl,
1176 type, template_instantiation, argument_index);
1180 argument = try_as_array(location_decl, parent, cls, template_decl, type,
1181 template_instantiation, argument_index);
1185 argument = try_as_template_parm_type(cls, template_decl, type);
1189 argument = try_as_template_specialization_type(location_decl, parent, cls,
1190 template_decl, type, template_instantiation, argument_index);
1194 argument = try_as_decl_type(parent, cls, template_decl, type,
1195 template_instantiation, argument_index);
1199 argument = try_as_typedef_type(parent, cls, template_decl, type,
1200 template_instantiation, argument_index);
1204 argument = try_as_lambda(cls, template_decl, type);
1208 argument = try_as_record_type(location_decl, parent, cls, template_decl,
1209 type, template_instantiation, argument_index);
1213 argument = try_as_enum_type(
1214 parent, cls, template_decl, type, template_instantiation);
1218 argument = try_as_builtin_type(parent, type, template_decl);
1223 return template_parameter::make_argument(type_name);
1226template <
typename VisitorT>
1231 const auto &type = ct.
type();
1237 LOG_DBG(
"Finding relationships in user defined type: {}",
1238 ct.
to_string(config().using_namespace(),
false));
1240 auto type_with_namespace =
1241 std::make_optional<common::model::namespace_>(type.value());
1243 if (!type_with_namespace.has_value()) {
1248 auto element_opt = diagram().get(type_with_namespace.value().to_string());
1249 if (config_.generate_template_argument_dependencies() && element_opt) {
1250 relationships.emplace_back(
1251 element_opt.value().id(), relationship_t::kDependency);
1256 found = find_relationships_in_unexposed_template_params(
1257 nested_template_params, relationships) ||
1264template <
typename VisitorT>
1266 const clang::TemplateArgument &arg,
const clang::ASTContext &ast_context)
1268 assert(arg.getKind() == clang::TemplateArgument::Integral);
1271 llvm::raw_string_ostream ostream(result);
1272 clang::PrintingPolicy policy(ast_context.getLangOpts());
1274#if LLVM_VERSION_MAJOR > 18
1275 arg.print(policy, ostream,
false);
1280 return template_parameter::make_argument(result);
1283#if LLVM_VERSION_MAJOR > 17
1284template <
typename VisitorT>
1286 const clang::TemplateArgument &arg,
const clang::ASTContext &ast_context)
1288 assert(arg.getKind() == clang::TemplateArgument::StructuralValue);
1291 llvm::raw_string_ostream ostream(result);
1292 clang::PrintingPolicy policy(ast_context.getLangOpts());
1294#if LLVM_VERSION_MAJOR > 18
1295 arg.print(policy, ostream,
false);
1300 return template_parameter::make_argument(result);
1304template <
typename VisitorT>
1306 const clang::TemplateArgument &arg)
1308 assert(arg.getKind() == clang::TemplateArgument::Null);
1310 return template_parameter::make_argument(
"");
1313template <
typename VisitorT>
1315 const clang::TemplateArgument &arg)
1317 assert(arg.getKind() == clang::TemplateArgument::NullPtr);
1321 return template_parameter::make_argument(
"nullptr");
1324template <
typename VisitorT>
1326 const clang::TemplateArgument &arg)
1328 assert(arg.getKind() == clang::TemplateArgument::Expression);
1330 arg.getAsExpr()->getSourceRange(), source_manager()));
1333template <
typename VisitorT>
1334std::vector<template_parameter>
1336 const clang::NamedDecl &location_decl,
1337 std::optional<clanguml::common::model::template_element *> &parent,
1338 const clang::NamedDecl *cls,
1340 const clang::TemplateDecl *base_template_decl,
1341 const clang::TemplateArgument &arg,
size_t argument_index,
1342 std::vector<template_parameter> & )
1344 assert(arg.getKind() == clang::TemplateArgument::Pack);
1346 std::vector<template_parameter> res;
1348 auto pack_argument_index = argument_index;
1350 for (
const auto &a : arg.getPackAsArray()) {
1351 argument_process_dispatch(location_decl, parent, cls,
1352 template_instantiation, base_template_decl, a,
1353 pack_argument_index++, res);
1359template <
typename VisitorT>
1360std::optional<template_parameter>
1362 const clang::NamedDecl &location_decl,
1363 std::optional<clanguml::common::model::template_element *> &parent,
1364 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
1365 clang::QualType &type,
1367 size_t argument_index)
1369 const auto *mp_type =
1371 if (mp_type ==
nullptr)
1374 auto argument = template_parameter::make_template_type(
"");
1375 type = consume_context(type, argument);
1378 if (mp_type->isMemberDataPointer()) {
1379 argument.is_member_pointer(
false);
1380 argument.is_data_pointer(
true);
1382 auto pointee_arg = process_type_argument(location_decl, parent, cls,
1383 template_decl, mp_type->getPointeeType(), template_instantiation,
1386 argument.add_template_param(std::move(pointee_arg));
1388#if LLVM_VERSION_MAJOR < 21
1389 const auto *member_class_type = mp_type->getClass();
1391 const auto *member_class_type = mp_type->getQualifier()->getAsType();
1394 if (member_class_type ==
nullptr)
1397 auto class_type_arg = process_type_argument(location_decl, parent, cls,
1398 template_decl, member_class_type->getCanonicalTypeUnqualified(),
1399 template_instantiation, argument_index);
1401 argument.add_template_param(std::move(class_type_arg));
1405 argument.is_member_pointer(
true);
1406 argument.is_data_pointer(
false);
1408 const auto *function_type =
1409 mp_type->getPointeeType()->getAs<clang::FunctionProtoType>();
1411 assert(function_type !=
nullptr);
1413 auto return_type_arg = process_type_argument(location_decl, parent, cls,
1414 template_decl, function_type->getReturnType(),
1415 template_instantiation, argument_index);
1418 argument.add_template_param(std::move(return_type_arg));
1420#if LLVM_VERSION_MAJOR < 21
1421 const auto *member_class_type = mp_type->getClass();
1423 const auto *member_class_type = mp_type->getQualifier()->getAsType();
1426 if (member_class_type ==
nullptr)
1429 auto class_type_arg = process_type_argument(location_decl, parent, cls,
1430 template_decl, member_class_type->getCanonicalTypeUnqualified(),
1431 template_instantiation, argument_index);
1434 argument.add_template_param(std::move(class_type_arg));
1437 for (
const auto ¶m_type : function_type->param_types()) {
1438 argument.add_template_param(
1439 process_type_argument(location_decl, parent, cls, template_decl,
1440 param_type, template_instantiation, argument_index));
1447template <
typename VisitorT>
1449 const clang::NamedDecl &location_decl,
1450 std::optional<clanguml::common::model::template_element *> &parent,
1451 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
1452 clang::QualType &type,
1454 size_t argument_index)
1457 if (array_type ==
nullptr)
1460 auto argument = template_parameter::make_template_type(
"");
1462 type = consume_context(type, argument);
1464 argument.is_array(
true);
1467 auto element_type = process_type_argument(location_decl, parent, cls,
1468 template_decl, array_type->getElementType(), template_instantiation,
1471 argument.add_template_param(element_type);
1473 if (array_type->isDependentSizedArrayType() &&
1474 array_type->getDependence() ==
1475 clang::TypeDependence::DependentInstantiation) {
1476 argument.add_template_param(
1478 ((clang::DependentSizedArrayType *)array_type)
1481 else if (array_type->isConstantArrayType()) {
1482 argument.add_template_param(template_parameter::make_argument(
1483 std::to_string(((clang::ConstantArrayType *)array_type)
1485 .getLimitedValue())));
1493template <
typename VisitorT>
1494std::optional<template_parameter>
1496 const clang::NamedDecl &location_decl,
1497 std::optional<clanguml::common::model::template_element *> &parent,
1498 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
1499 clang::QualType &type,
1501 size_t argument_index)
1503 const auto *function_type = type->getAs<clang::FunctionProtoType>();
1505 if (function_type ==
nullptr && type->isFunctionPointerType()) {
1507 type->getPointeeType()->getAs<clang::FunctionProtoType>();
1508 if (function_type ==
nullptr)
1512 if (function_type ==
nullptr)
1515 LOG_DBG(
"Template argument is a function prototype");
1517 auto argument = template_parameter::make_template_type(
"");
1519 type = consume_context(type, argument);
1521 argument.is_function_template(
true);
1524 auto return_arg = process_type_argument(location_decl, parent, cls,
1525 template_decl, function_type->getReturnType(), template_instantiation,
1528 argument.add_template_param(return_arg);
1531 if (function_type->isVariadic() && function_type->param_types().empty()) {
1532 auto fallback_arg = template_parameter::make_argument({});
1533 fallback_arg.is_ellipsis(
true);
1534 argument.add_template_param(std::move(fallback_arg));
1537 for (
const auto ¶m_type : function_type->param_types()) {
1538 argument.add_template_param(
1539 process_type_argument(location_decl, parent, cls, template_decl,
1540 param_type, template_instantiation, argument_index));
1547template <
typename VisitorT>
1549 std::optional<clanguml::common::model::template_element *> & ,
1550 const clang::NamedDecl * ,
1551 const clang::TemplateDecl * , clang::QualType &type,
1555 const auto *decl_type =
1557 if (decl_type ==
nullptr) {
1561 LOG_DBG(
"Template argument is a decltype()");
1567template <
typename VisitorT>
1568std::optional<template_parameter>
1570 std::optional<clanguml::common::model::template_element *> &parent,
1571 const clang::NamedDecl * ,
1572 const clang::TemplateDecl * , clang::QualType &type,
1576 const auto *typedef_type =
1578 if (typedef_type ==
nullptr) {
1582 LOG_DBG(
"Template argument is a typedef/using");
1586 if (typedef_type->getAs<clang::DecltypeType>() !=
nullptr) {
1590 if (typedef_type->getDecl()->isCXXClassMember() && parent) {
1591 return template_parameter::make_argument(
1592 fmt::format(
"{}::{}", parent.value()->full_name(
false),
1593 typedef_type->getDecl()->getNameAsString()));
1596 return template_parameter::make_argument(
1597 typedef_type->getDecl()->getQualifiedNameAsString());
1603template <
typename VisitorT>
1604std::optional<template_parameter>
1606 const clang::NamedDecl &location_decl,
1607 std::optional<clanguml::common::model::template_element *> &parent,
1608 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
1609 clang::QualType &type,
1611 size_t argument_index)
1613 const auto *nested_template_type =
1615 if (nested_template_type ==
nullptr) {
1619 LOG_DBG(
"Template argument is a template specialization type");
1621 auto argument = template_parameter::make_argument(
"");
1622 type = consume_context(type, argument);
1624 auto nested_type_name = nested_template_type->getTemplateName()
1625 .getAsTemplateDecl()
1626 ->getQualifiedNameAsString();
1628 if (clang::dyn_cast<clang::TemplateTemplateParmDecl>(
1629 nested_template_type->getTemplateName().getAsTemplateDecl()) !=
1631 if (
const auto *template_specialization_decl =
1632 clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(cls);
1633 template_specialization_decl !=
nullptr) {
1635 template_specialization_decl->getDescribedTemplateParams()
1636 ->getParam(argument_index)
1637 ->getNameAsString();
1641 nested_type_name =
"template";
1644 argument.is_template_template_parameter(
true);
1647 argument.set_type(nested_type_name);
1649 auto nested_template_instantiation =
1650 visitor_.create_element(nested_template_type->getTemplateName()
1651 .getAsTemplateDecl()
1652 ->getTemplatedDecl());
1653 build_from_template_specialization_type(location_decl,
1654 *nested_template_instantiation, cls, *nested_template_type,
1655 diagram().should_include(
1656 namespace_{template_decl->getQualifiedNameAsString()})
1657 ? std::make_optional(&template_instantiation)
1660 argument.set_id(nested_template_instantiation->id());
1662 for (
const auto &t : nested_template_instantiation->template_params())
1663 argument.add_template_param(t);
1668 simplify_system_template(
1669 argument, argument.to_string(using_namespace(),
false));
1672 common::to_id(argument.to_string(using_namespace(),
false)));
1674 const auto nested_template_instantiation_full_name =
1675 nested_template_instantiation->full_name(
false);
1677 if (nested_template_instantiation &&
1678 diagram().should_include(
1679 namespace_{nested_template_instantiation_full_name})) {
1680 if (config_.generate_template_argument_dependencies()) {
1681 if (diagram().should_include(
1682 namespace_{template_decl->getQualifiedNameAsString()})) {
1684 {relationship_t::kDependency,
1685 nested_template_instantiation->id()});
1688 if (parent.has_value())
1689 parent.value()->add_relationship(
1690 {relationship_t::kDependency,
1691 nested_template_instantiation->id()});
1696 if (diagram().should_include(
1697 namespace_{nested_template_instantiation_full_name})) {
1698 visitor_.set_source_location(
1699 location_decl, *nested_template_instantiation);
1700 visitor_.add_diagram_element(std::move(nested_template_instantiation));
1706template <
typename VisitorT>
1707std::optional<template_parameter>
1709 const clang::NamedDecl *cls,
const clang::TemplateDecl * ,
1710 clang::QualType &type)
1712 auto is_variadic{
false};
1714 const auto *type_parameter =
1719 if (type_parameter ==
nullptr) {
1720 if (
const auto *pet =
1725 pet->getPattern()->getAs<clang::TemplateTypeParmType>();
1729 if (type_parameter ==
nullptr)
1732 LOG_DBG(
"Template argument is a template parameter type");
1734 auto argument = template_parameter::make_template_type(
"");
1735 type = consume_context(type, argument);
1738 if (type_parameter_name.empty())
1739 type_parameter_name =
"typename";
1742 cls, type_parameter_name));
1744 argument.is_variadic(is_variadic);
1751template <
typename VisitorT>
1753 const clang::NamedDecl *cls,
const clang::TemplateDecl * ,
1754 clang::QualType &type)
1758 if (type_name.find(
"(lambda at ") != 0)
1761 LOG_DBG(
"Template argument is a lambda");
1763 auto argument = template_parameter::make_argument(
"");
1764 type = consume_context(type, argument);
1767 argument.set_type(type_name);
1772template <
typename VisitorT>
1773std::optional<template_parameter>
1775 const clang::NamedDecl &location_decl,
1776 std::optional<clanguml::common::model::template_element *> &parent,
1777 const clang::NamedDecl * ,
const clang::TemplateDecl *template_decl,
1778 clang::QualType &type,
1782 const auto *record_type =
1784 if (record_type ==
nullptr)
1787 LOG_DBG(
"Template argument is a c++ record");
1789 auto argument = template_parameter::make_argument({});
1790 type = consume_context(type, argument);
1792 const auto type_name = config().simplify_template_type(
1795 argument.set_type(type_name);
1798 argument.set_id(type_id);
1800 const auto *class_template_specialization =
1801 clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(
1802 record_type->getAsRecordDecl());
1804 if (class_template_specialization !=
nullptr) {
1806 visitor_.create_element(class_template_specialization);
1808 build_from_class_template_specialization(
1809 *tag_argument, *class_template_specialization);
1811 tag_argument->is_template(
true);
1814 argument.set_type(tag_argument->name_and_ns());
1815 for (
const auto &p : tag_argument->template_params())
1816 argument.add_template_param(p);
1817 for (
auto &r : tag_argument->relationships()) {
1821 if (config_.generate_template_argument_dependencies() &&
1822 diagram().should_include(tag_argument->get_namespace())) {
1823 if (parent.has_value())
1824 parent.value()->add_relationship(
1825 {relationship_t::kDependency, tag_argument->id()});
1827 visitor_.set_source_location(location_decl, *tag_argument);
1828 visitor_.add_diagram_element(std::move(tag_argument));
1832 else if (
const auto *record_type_decl = record_type->getAsRecordDecl();
1833 record_type_decl !=
nullptr) {
1834 if (config_.generate_template_argument_dependencies() &&
1835 diagram().should_include(namespace_{type_name})) {
1839 {relationship_t::kDependency, type_id});
1846template <
typename VisitorT>
1848 std::optional<clanguml::common::model::template_element *> & ,
1849 const clang::NamedDecl * ,
const clang::TemplateDecl *template_decl,
1850 clang::QualType &type,
1853 const auto *enum_type = type->getAs<clang::EnumType>();
1854 if (enum_type ==
nullptr)
1857 LOG_DBG(
"Template argument is a an enum");
1859 auto argument = template_parameter::make_argument({});
1860 type = consume_context(type, argument);
1863 argument.set_type(type_name);
1865 argument.set_id(type_id);
1867 if (enum_type->getAsTagDecl() !=
nullptr &&
1868 config_.generate_template_argument_dependencies()) {
1870 {relationship_t::kDependency, type_id});
1876template <
typename VisitorT>
1877std::optional<template_parameter>
1879 std::optional<clanguml::common::model::template_element *> & ,
1880 clang::QualType &type,
const clang::TemplateDecl *template_decl)
1882 const auto *builtin_type = type->getAs<clang::BuiltinType>();
1883 if (builtin_type ==
nullptr)
1886 LOG_DBG(
"Template argument is a builtin type");
1889 auto argument = template_parameter::make_argument(type_name);
1891 type = consume_context(type, argument);
1892 argument.set_type(type_name);
1897template <
typename VisitorT>
1900 std::deque<std::tuple<std::string, int, bool>> &template_base_params,
1903 bool add_template_argument_as_base_class =
false;
1905 if (variadic_params) {
1906 add_template_argument_as_base_class =
true;
1909 auto [arg_name, index, is_variadic] = template_base_params.front();
1911 variadic_params = is_variadic;
1912 if ((arg_index == index) || (is_variadic && arg_index >= index)) {
1913 add_template_argument_as_base_class =
true;
1916 template_base_params.pop_front();
1921 const auto maybe_id = ct.
id();
1922 if (add_template_argument_as_base_class && maybe_id) {
1923 LOG_DBG(
"Adding template argument as base class '{}'",
1931 return variadic_params;