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 clang::dyn_cast_or_null<clang::ConceptDecl>(
669 template_type_parameter->getTypeConstraint()
670 ->getNamedConcept()),
671 [
this, &ct, &templated_element](
672 const clang::ConceptDecl *named_concept)
mutable {
673 ct.set_concept_constraint(
674 named_concept->getQualifiedNameAsString());
675 if (templated_element &&
676 visitor_.should_include(named_concept)) {
677 templated_element.value().add_relationship(
678 {relationship_t::kConstraint,
681 eid_t{named_concept->getID()})
683 model::access_t::kNone,
690 (void)templated_element;
695 else if (clang::dyn_cast_or_null<clang::NonTypeTemplateParmDecl>(
696 parameter) !=
nullptr) {
697 const auto *template_nontype_parameter =
698 clang::dyn_cast_or_null<clang::NonTypeTemplateParmDecl>(
701 std::optional<std::string> default_arg;
703 if (template_nontype_parameter->hasDefaultArgument()) {
705#if LLVM_VERSION_MAJOR > 18
707 template_nontype_parameter->getDefaultArgument(),
708 template_declaration.getASTContext());
711 template_nontype_parameter->getDefaultArgument());
715 template_nontype_parameter->getType().getAsString(),
716 template_nontype_parameter->getNameAsString(), default_arg,
717 template_nontype_parameter->isParameterPack());
721 else if (clang::dyn_cast_or_null<clang::TemplateTemplateParmDecl>(
722 parameter) !=
nullptr) {
723 const auto *template_template_parameter =
724 clang::dyn_cast_or_null<clang::TemplateTemplateParmDecl>(
726 std::optional<std::string> default_arg;
727 if (template_template_parameter->hasDefaultArgument()) {
729 template_template_parameter->getDefaultArgument()
733 template_template_parameter->getNameAsString(), default_arg,
734 template_template_parameter->isParameterPack());
744template <
typename VisitorT>
746 const clang::NamedDecl &location_declaration,
748 const clang::NamedDecl *cls,
749 const clang::TemplateSpecializationType &template_type_decl,
750 std::optional<clanguml::common::model::template_element *> parent)
752 const auto *template_type_ptr = &template_type_decl;
754 if (template_type_decl.isTypeAlias()) {
755 if (
const auto *tsp = template_type_decl.getAliasedType()
756 ->template getAs<clang::TemplateSpecializationType>();
758 template_type_ptr = tsp;
761 const auto &template_type = *template_type_ptr;
765 auto *template_decl{template_type.getTemplateName().getAsTemplateDecl()};
767 if (template_decl ==
nullptr)
771 template_type.desugar(), template_decl->getASTContext());
773 build(location_declaration, template_instantiation, cls, template_decl,
774 template_type.template_arguments(), full_template_specialization_name,
778template <
typename VisitorT>
781 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
782 const clang::ArrayRef<clang::TemplateArgument> template_arguments,
783 std::string full_template_specialization_name,
784 std::optional<clanguml::common::model::template_element *> parent)
790 std::deque<std::tuple< std::string, int,
792 template_base_params{};
794 auto template_decl_qualified_name =
795 template_decl->getQualifiedNameAsString();
797 if (
const auto *class_template_decl =
798 clang::dyn_cast<clang::ClassTemplateDecl>(template_decl);
799 (class_template_decl !=
nullptr) &&
800 (class_template_decl->getTemplatedDecl() !=
nullptr) &&
801 (class_template_decl->getTemplatedDecl()->getParent() !=
nullptr) &&
802 class_template_decl->getTemplatedDecl()->getParent()->isRecord()) {
807 ->getOuterLexicalRecordContext())};
810 std::string name = template_decl->getQualifiedNameAsString();
811 if (!ns_str.empty()) {
812 name = name.substr(ns_str.size() + 2);
816 template_instantiation.
set_name(name);
821 namespace_ ns{template_decl_qualified_name};
823 template_instantiation.
set_name(template_decl->getNameAsString());
832 std::pair< std::string,
bool>>
833 template_parameter_names{};
835 for (
const auto *parameter : *template_decl->getTemplateParameters()) {
836 if (parameter->isTemplateParameter() &&
837 (parameter->isTemplateParameterPack() ||
838 parameter->isParameterPack())) {
839 template_parameter_names.emplace_back(
840 parameter->getNameAsString(),
true);
843 template_parameter_names.emplace_back(
844 parameter->getNameAsString(),
false);
850 const auto *templated_class_decl =
851 clang::dyn_cast_or_null<clang::CXXRecordDecl>(
852 template_decl->getTemplatedDecl());
854 if ((templated_class_decl !=
nullptr) &&
855 templated_class_decl->hasDefinition())
856 for (
const auto &base : templated_class_decl->bases()) {
858 base.getType(), templated_class_decl->getASTContext(),
false);
860 LOG_DBG(
"Found template instantiation base: {}, {}",
861 base_class_name, base_index);
865 auto it = std::find_if(template_parameter_names.begin(),
866 template_parameter_names.end(),
868 const auto &p) { return p.first == base_class_name; });
870 if (it != template_parameter_names.end()) {
871 const auto ¶meter_name = it->first;
872 const bool is_variadic = it->second;
874 LOG_DBG(
"Found base class which is a template parameter "
876 parameter_name, is_variadic,
877 std::distance(template_parameter_names.begin(), it));
879 template_base_params.emplace_back(parameter_name,
880 std::distance(template_parameter_names.begin(), it),
890 process_template_arguments(location_decl, parent, cls, template_base_params,
891 template_arguments, template_instantiation, template_decl);
893 if constexpr (std::is_same_v<
typename VisitorT::diagram_t,
895 find_instantiation_relationships(template_instantiation,
896 eid_t{template_decl->getID()}, full_template_specialization_name);
899 template_instantiation.
set_id(
902 visitor_.set_source_location(location_decl, template_instantiation);
905template <
typename VisitorT>
908 const clang::ClassTemplateSpecializationDecl &template_specialization,
909 std::optional<clanguml::common::model::template_element *> parent)
911 LOG_DBG(
"Building class template specialization model: {}",
912 template_specialization.getQualifiedNameAsString());
918 std::deque<std::tuple< std::string, int,
920 template_base_params{};
922 const clang::ClassTemplateDecl *template_decl =
923 template_specialization.getSpecializedTemplate();
925 auto qualified_name = template_decl->getQualifiedNameAsString();
927 namespace_ ns{qualified_name};
929 template_instantiation.
set_name(template_decl->getNameAsString());
932 process_template_arguments(template_specialization, parent,
933 &template_specialization, template_base_params,
934 template_specialization.getTemplateArgs().asArray(),
935 template_instantiation, template_decl);
938 template_instantiation.
set_id(
941 if constexpr (std::is_same_v<
typename VisitorT::diagram_t,
943 find_instantiation_relationships(template_instantiation,
944 eid_t{template_specialization.getID()}, qualified_name);
947 visitor_.set_source_location(
948 template_specialization, template_instantiation);
951template <
typename VisitorT>
954 const std::string &qualified_name)
const
957 template_instantiation, qualified_name,
id);
960template <
typename VisitorT>
962 const clang::NamedDecl &location_decl,
963 std::optional<clanguml::common::model::template_element *> &parent,
964 const clang::NamedDecl *cls,
965 std::deque<std::tuple<std::string, int, bool>> &template_base_params,
966 const clang::ArrayRef<clang::TemplateArgument> &template_args,
968 const clang::TemplateDecl *template_decl)
972 for (
const auto &arg : template_args) {
975 std::vector<template_parameter> arguments;
978 if (arg.getKind() == clang::TemplateArgument::ArgKind::Pack &&
979 arg.getPackAsArray().empty()) {
981 template_parameter::make_empty());
990 if (!diagram().should_include(
991 namespace_{template_decl->getQualifiedNameAsString()})) {
992 const auto *maybe_type_parm_decl =
993 clang::dyn_cast<clang::TemplateTypeParmDecl>(
994 template_decl->getTemplateParameters()->getParam(
995 std::min<unsigned>(arg_index,
996 static_cast<unsigned>(
997 template_decl->getTemplateParameters()
1000 if (maybe_type_parm_decl !=
nullptr &&
1001 maybe_type_parm_decl->hasDefaultArgument()) {
1009 argument_process_dispatch(location_decl, parent, cls,
1010 template_instantiation, template_decl, arg, arg_index, arguments);
1012 if (arguments.empty()) {
1021 [[maybe_unused]]
auto variadic_params{
false};
1023 if constexpr (std::is_same_v<
typename VisitorT::diagram_t,
1027 if (!template_base_params.empty()) {
1028 variadic_params = add_base_classes(template_instantiation,
1029 template_base_params, arg_index, variadic_params,
1034 for (
auto &argument : arguments) {
1035 simplify_system_template(
1036 argument, argument.to_string(using_namespace(),
false,
true));
1038 LOG_DBG(
"Adding template argument {} to template "
1039 "specialization/instantiation {}",
1040 argument.to_string(using_namespace(),
false),
1041 template_instantiation.
name());
1043 template_instantiation.
add_template(std::move(argument));
1050 template_instantiation.
set_id(
1054template <
typename VisitorT>
1056 const clang::NamedDecl &location_decl,
1057 std::optional<clanguml::common::model::template_element *> &parent,
1058 const clang::NamedDecl *cls,
1060 const clang::TemplateDecl *template_decl,
1061 const clang::TemplateArgument &arg,
size_t argument_index,
1062 std::vector<template_parameter> &argument)
1064 LOG_DBG(
"Processing argument {} in template class: {}", argument_index,
1065 cls->getQualifiedNameAsString());
1067 switch (arg.getKind()) {
1068 case clang::TemplateArgument::Null:
1069 argument.push_back(process_null_argument(arg));
1071 case clang::TemplateArgument::Template:
1072 argument.push_back(process_template_argument(arg));
1074 case clang::TemplateArgument::Type: {
1076 process_type_argument(location_decl, parent, cls, template_decl,
1077 arg.getAsType(), template_instantiation, argument_index));
1080 case clang::TemplateArgument::Declaration:
1082 case clang::TemplateArgument::NullPtr:
1083 argument.push_back(process_nullptr_argument(arg));
1085 case clang::TemplateArgument::Integral:
1087 process_integral_argument(arg, template_decl->getASTContext()));
1089 case clang::TemplateArgument::TemplateExpansion:
1090 argument.push_back(process_template_expansion(arg));
1092 case clang::TemplateArgument::Expression:
1093 argument.push_back(process_expression_argument(arg));
1095 case clang::TemplateArgument::Pack:
1096 for (
auto &a : process_pack_argument(location_decl, parent, cls,
1097 template_instantiation, template_decl, arg, argument_index,
1099 argument.push_back(a);
1102#if LLVM_VERSION_MAJOR > 17
1103 case clang::TemplateArgument::StructuralValue:
1109template <
typename VisitorT>
1111 const clang::TemplateArgument &arg)
1115 LOG_DBG(
"Processing template argument: {}", arg_name);
1117 return template_parameter::make_template_type(arg_name);
1120template <
typename VisitorT>
1122 const clang::TemplateArgument &arg)
1126 LOG_DBG(
"Processing template expansion argument: {}", arg_name);
1129 arg.getAsTemplate().getAsTemplateDecl(), [&arg_name](
const auto *decl) {
1130 arg_name = decl->getQualifiedNameAsString();
1133 auto param = template_parameter::make_template_type(arg_name);
1134 param.is_variadic(
true);
1139template <
typename VisitorT>
1147 return unqualified_type;
1150template <
typename VisitorT>
1152 const clang::NamedDecl &location_decl,
1153 std::optional<clanguml::common::model::template_element *> &parent,
1154 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
1155 clang::QualType type,
1157 size_t argument_index)
1159 std::optional<template_parameter> argument;
1161#if LLVM_VERSION_MAJOR < 22
1162 if (type->getAs<clang::ElaboratedType>() !=
nullptr) {
1163 type = type->getAs<clang::ElaboratedType>()->getNamedType();
1169 LOG_DBG(
"Processing template {} type argument {}: {}, {}, {}",
1170 template_decl->getQualifiedNameAsString(), argument_index, type_name,
1171 type->getTypeClassName(),
1174 argument = try_as_function_prototype(location_decl, parent, cls,
1175 template_decl, type, template_instantiation, argument_index);
1179 argument = try_as_member_pointer(location_decl, parent, cls, template_decl,
1180 type, template_instantiation, argument_index);
1184 argument = try_as_array(location_decl, parent, cls, template_decl, type,
1185 template_instantiation, argument_index);
1189 argument = try_as_template_parm_type(cls, template_decl, type);
1193 argument = try_as_template_specialization_type(location_decl, parent, cls,
1194 template_decl, type, template_instantiation, argument_index);
1198 argument = try_as_decl_type(parent, cls, template_decl, type,
1199 template_instantiation, argument_index);
1203 argument = try_as_typedef_type(parent, cls, template_decl, type,
1204 template_instantiation, argument_index);
1208 argument = try_as_lambda(cls, template_decl, type);
1212 argument = try_as_record_type(location_decl, parent, cls, template_decl,
1213 type, template_instantiation, argument_index);
1217 argument = try_as_enum_type(
1218 parent, cls, template_decl, type, template_instantiation);
1222 argument = try_as_builtin_type(parent, type, template_decl);
1227 return template_parameter::make_argument(type_name);
1230template <
typename VisitorT>
1235 const auto &type = ct.
type();
1241 LOG_DBG(
"Finding relationships in user defined type: {}",
1242 ct.
to_string(config().using_namespace(),
false));
1244 auto type_with_namespace =
1245 std::make_optional<common::model::namespace_>(type.value());
1247 if (!type_with_namespace.has_value()) {
1252 auto element_opt = diagram().get(type_with_namespace.value().to_string());
1253 if (config_.generate_template_argument_dependencies() && element_opt) {
1254 relationships.emplace_back(
1255 element_opt.value().id(), relationship_t::kDependency);
1260 found = find_relationships_in_unexposed_template_params(
1261 nested_template_params, relationships) ||
1268template <
typename VisitorT>
1270 const clang::TemplateArgument &arg,
const clang::ASTContext &ast_context)
1272 assert(arg.getKind() == clang::TemplateArgument::Integral);
1275 llvm::raw_string_ostream ostream(result);
1276 clang::PrintingPolicy policy(ast_context.getLangOpts());
1278#if LLVM_VERSION_MAJOR > 18
1279 arg.print(policy, ostream,
false);
1284 return template_parameter::make_argument(result);
1287#if LLVM_VERSION_MAJOR > 17
1288template <
typename VisitorT>
1290 const clang::TemplateArgument &arg,
const clang::ASTContext &ast_context)
1292 assert(arg.getKind() == clang::TemplateArgument::StructuralValue);
1295 llvm::raw_string_ostream ostream(result);
1296 clang::PrintingPolicy policy(ast_context.getLangOpts());
1298#if LLVM_VERSION_MAJOR > 18
1299 arg.print(policy, ostream,
false);
1304 return template_parameter::make_argument(result);
1308template <
typename VisitorT>
1310 const clang::TemplateArgument &arg)
1312 assert(arg.getKind() == clang::TemplateArgument::Null);
1314 return template_parameter::make_argument(
"");
1317template <
typename VisitorT>
1319 const clang::TemplateArgument &arg)
1321 assert(arg.getKind() == clang::TemplateArgument::NullPtr);
1325 return template_parameter::make_argument(
"nullptr");
1328template <
typename VisitorT>
1330 const clang::TemplateArgument &arg)
1332 assert(arg.getKind() == clang::TemplateArgument::Expression);
1334 arg.getAsExpr()->getSourceRange(), source_manager()));
1337template <
typename VisitorT>
1338std::vector<template_parameter>
1340 const clang::NamedDecl &location_decl,
1341 std::optional<clanguml::common::model::template_element *> &parent,
1342 const clang::NamedDecl *cls,
1344 const clang::TemplateDecl *base_template_decl,
1345 const clang::TemplateArgument &arg,
size_t argument_index,
1346 std::vector<template_parameter> & )
1348 assert(arg.getKind() == clang::TemplateArgument::Pack);
1350 std::vector<template_parameter> res;
1352 auto pack_argument_index = argument_index;
1354 for (
const auto &a : arg.getPackAsArray()) {
1355 argument_process_dispatch(location_decl, parent, cls,
1356 template_instantiation, base_template_decl, a,
1357 pack_argument_index++, res);
1363template <
typename VisitorT>
1364std::optional<template_parameter>
1366 const clang::NamedDecl &location_decl,
1367 std::optional<clanguml::common::model::template_element *> &parent,
1368 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
1369 clang::QualType &type,
1371 size_t argument_index)
1373 const auto *mp_type =
1375 if (mp_type ==
nullptr)
1378 auto argument = template_parameter::make_template_type(
"");
1379 type = consume_context(type, argument);
1382 if (mp_type->isMemberDataPointer()) {
1383 argument.is_member_pointer(
false);
1384 argument.is_data_pointer(
true);
1386 auto pointee_arg = process_type_argument(location_decl, parent, cls,
1387 template_decl, mp_type->getPointeeType(), template_instantiation,
1390 argument.add_template_param(std::move(pointee_arg));
1392#if LLVM_VERSION_MAJOR < 21
1393 const auto *member_class_type = mp_type->getClass();
1394#elif LLVM_VERSION_MAJOR < 22
1395 const auto *member_class_type = mp_type->getQualifier()->getAsType();
1397 const auto *member_class_type = mp_type->getQualifier().getAsType();
1400 if (member_class_type ==
nullptr)
1403 auto class_type_arg = process_type_argument(location_decl, parent, cls,
1404 template_decl, member_class_type->getCanonicalTypeUnqualified(),
1405 template_instantiation, argument_index);
1407 argument.add_template_param(std::move(class_type_arg));
1411 argument.is_member_pointer(
true);
1412 argument.is_data_pointer(
false);
1414 const auto *function_type =
1415 mp_type->getPointeeType()->getAs<clang::FunctionProtoType>();
1417 assert(function_type !=
nullptr);
1419 auto return_type_arg = process_type_argument(location_decl, parent, cls,
1420 template_decl, function_type->getReturnType(),
1421 template_instantiation, argument_index);
1424 argument.add_template_param(std::move(return_type_arg));
1426#if LLVM_VERSION_MAJOR < 21
1427 const auto *member_class_type = mp_type->getClass();
1428#elif LLVM_VERSION_MAJOR < 22
1429 const auto *member_class_type = mp_type->getQualifier()->getAsType();
1431 const auto *member_class_type = mp_type->getQualifier().getAsType();
1434 if (member_class_type ==
nullptr)
1437 auto class_type_arg = process_type_argument(location_decl, parent, cls,
1438 template_decl, member_class_type->getCanonicalTypeUnqualified(),
1439 template_instantiation, argument_index);
1442 argument.add_template_param(std::move(class_type_arg));
1445 for (
const auto ¶m_type : function_type->param_types()) {
1446 argument.add_template_param(
1447 process_type_argument(location_decl, parent, cls, template_decl,
1448 param_type, template_instantiation, argument_index));
1455template <
typename VisitorT>
1457 const clang::NamedDecl &location_decl,
1458 std::optional<clanguml::common::model::template_element *> &parent,
1459 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
1460 clang::QualType &type,
1462 size_t argument_index)
1465 if (array_type ==
nullptr)
1468 auto argument = template_parameter::make_template_type(
"");
1470 type = consume_context(type, argument);
1472 argument.is_array(
true);
1475 auto element_type = process_type_argument(location_decl, parent, cls,
1476 template_decl, array_type->getElementType(), template_instantiation,
1479 argument.add_template_param(element_type);
1481 if (array_type->isDependentSizedArrayType() &&
1482 array_type->getDependence() ==
1483 clang::TypeDependence::DependentInstantiation) {
1484 argument.add_template_param(
1486 ((clang::DependentSizedArrayType *)array_type)
1489 else if (array_type->isConstantArrayType()) {
1490 argument.add_template_param(template_parameter::make_argument(
1491 std::to_string(((clang::ConstantArrayType *)array_type)
1493 .getLimitedValue())));
1501template <
typename VisitorT>
1502std::optional<template_parameter>
1504 const clang::NamedDecl &location_decl,
1505 std::optional<clanguml::common::model::template_element *> &parent,
1506 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
1507 clang::QualType &type,
1509 size_t argument_index)
1511 const auto *function_type = type->getAs<clang::FunctionProtoType>();
1513 if (function_type ==
nullptr && type->isFunctionPointerType()) {
1515 type->getPointeeType()->getAs<clang::FunctionProtoType>();
1516 if (function_type ==
nullptr)
1520 if (function_type ==
nullptr)
1523 LOG_DBG(
"Template argument is a function prototype");
1525 auto argument = template_parameter::make_template_type(
"");
1527 type = consume_context(type, argument);
1529 argument.is_function_template(
true);
1532 auto return_arg = process_type_argument(location_decl, parent, cls,
1533 template_decl, function_type->getReturnType(), template_instantiation,
1536 argument.add_template_param(return_arg);
1539 if (function_type->isVariadic() && function_type->param_types().empty()) {
1540 auto fallback_arg = template_parameter::make_argument({});
1541 fallback_arg.is_ellipsis(
true);
1542 argument.add_template_param(std::move(fallback_arg));
1545 for (
const auto ¶m_type : function_type->param_types()) {
1546 argument.add_template_param(
1547 process_type_argument(location_decl, parent, cls, template_decl,
1548 param_type, template_instantiation, argument_index));
1555template <
typename VisitorT>
1557 std::optional<clanguml::common::model::template_element *> & ,
1558 const clang::NamedDecl * ,
1559 const clang::TemplateDecl * , clang::QualType &type,
1563 const auto *decl_type =
1565 if (decl_type ==
nullptr) {
1569 LOG_DBG(
"Template argument is a decltype()");
1575template <
typename VisitorT>
1576std::optional<template_parameter>
1578 std::optional<clanguml::common::model::template_element *> &parent,
1579 const clang::NamedDecl * ,
1580 const clang::TemplateDecl * , clang::QualType &type,
1584 const auto *typedef_type =
1586 if (typedef_type ==
nullptr) {
1590 LOG_DBG(
"Template argument is a typedef/using");
1594 if (typedef_type->getAs<clang::DecltypeType>() !=
nullptr) {
1598 if (typedef_type->getDecl()->isCXXClassMember() && parent) {
1599 return template_parameter::make_argument(
1600 fmt::format(
"{}::{}", parent.value()->full_name(
false),
1601 typedef_type->getDecl()->getNameAsString()));
1604 return template_parameter::make_argument(
1605 typedef_type->getDecl()->getQualifiedNameAsString());
1611template <
typename VisitorT>
1612std::optional<template_parameter>
1614 const clang::NamedDecl &location_decl,
1615 std::optional<clanguml::common::model::template_element *> &parent,
1616 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
1617 clang::QualType &type,
1619 size_t argument_index)
1621 const auto *nested_template_type =
1623 if (nested_template_type ==
nullptr) {
1627 LOG_DBG(
"Template argument is a template specialization type");
1629 if (nested_template_type->getTemplateName().getAsTemplateDecl() ==
nullptr)
1632 auto argument = template_parameter::make_argument(
"");
1633 type = consume_context(type, argument);
1635 auto nested_type_name = nested_template_type->getTemplateName()
1636 .getAsTemplateDecl()
1637 ->getQualifiedNameAsString();
1639 if (clang::dyn_cast<clang::TemplateTemplateParmDecl>(
1640 nested_template_type->getTemplateName().getAsTemplateDecl()) !=
1642 if (
const auto *template_specialization_decl =
1643 clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(cls);
1644 template_specialization_decl !=
nullptr) {
1646 template_specialization_decl->getDescribedTemplateParams()
1647 ->getParam(argument_index)
1648 ->getNameAsString();
1652 nested_type_name =
"template";
1655 argument.is_template_template_parameter(
true);
1658 argument.set_type(nested_type_name);
1660 auto nested_template_instantiation =
1661 visitor_.create_element(nested_template_type->getTemplateName()
1662 .getAsTemplateDecl()
1663 ->getTemplatedDecl());
1664 build_from_template_specialization_type(location_decl,
1665 *nested_template_instantiation, cls, *nested_template_type,
1666 diagram().should_include(
1667 namespace_{template_decl->getQualifiedNameAsString()})
1668 ? std::make_optional(&template_instantiation)
1671 argument.set_id(nested_template_instantiation->id());
1673 for (
const auto &t : nested_template_instantiation->template_params())
1674 argument.add_template_param(t);
1679 simplify_system_template(
1680 argument, argument.to_string(using_namespace(),
false));
1683 common::to_id(argument.to_string(using_namespace(),
false)));
1685 const auto nested_template_instantiation_full_name =
1686 nested_template_instantiation->full_name(
false);
1688 if (nested_template_instantiation &&
1689 diagram().should_include(
1690 namespace_{nested_template_instantiation_full_name})) {
1691 if (config_.generate_template_argument_dependencies()) {
1692 if (diagram().should_include(
1693 namespace_{template_decl->getQualifiedNameAsString()})) {
1695 {relationship_t::kDependency,
1696 nested_template_instantiation->id()});
1699 if (parent.has_value())
1700 parent.value()->add_relationship(
1701 {relationship_t::kDependency,
1702 nested_template_instantiation->id()});
1707 if (diagram().should_include(
1708 namespace_{nested_template_instantiation_full_name})) {
1709 visitor_.set_source_location(
1710 location_decl, *nested_template_instantiation);
1711 visitor_.add_diagram_element(std::move(nested_template_instantiation));
1717template <
typename VisitorT>
1718std::optional<template_parameter>
1720 const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl,
1721 clang::QualType &type)
1723 auto is_variadic{
false};
1725 const auto *type_parameter =
1730 if (type_parameter ==
nullptr) {
1731 if (
const auto *pet =
1736 pet->getPattern()->getAs<clang::TemplateTypeParmType>();
1740 if (type_parameter ==
nullptr)
1743 LOG_DBG(
"Template argument is a template parameter type");
1745 auto argument = template_parameter::make_template_type(
"");
1746 type = consume_context(type, argument);
1749 if (type_parameter_name.empty())
1750 type_parameter_name =
"typename";
1752 const auto *type_concept_constraint =
1754 type_parameter, template_decl);
1756 if (type_concept_constraint !=
nullptr) {
1757 argument.set_concept_constraint(
1758 type_concept_constraint->getQualifiedNameAsString());
1762 cls, type_parameter_name));
1764 argument.is_variadic(is_variadic);
1771template <
typename VisitorT>
1773 const clang::NamedDecl *cls,
const clang::TemplateDecl * ,
1774 clang::QualType &type)
1778 if (type_name.find(
"(lambda at ") != 0)
1781 LOG_DBG(
"Template argument is a lambda");
1783 auto argument = template_parameter::make_argument(
"");
1784 type = consume_context(type, argument);
1787 argument.set_type(type_name);
1792template <
typename VisitorT>
1793std::optional<template_parameter>
1795 const clang::NamedDecl &location_decl,
1796 std::optional<clanguml::common::model::template_element *> &parent,
1797 const clang::NamedDecl * ,
const clang::TemplateDecl *template_decl,
1798 clang::QualType &type,
1802 const auto *record_type =
1804 if (record_type ==
nullptr)
1807 LOG_DBG(
"Template argument is a c++ record");
1809 auto argument = template_parameter::make_argument({});
1810 type = consume_context(type, argument);
1812 const auto type_name = config().simplify_template_type(
1815 argument.set_type(type_name);
1818 argument.set_id(type_id);
1820 const auto *class_template_specialization =
1821 clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(
1822 record_type->getAsRecordDecl());
1824 if (class_template_specialization !=
nullptr) {
1826 visitor_.create_element(class_template_specialization);
1828 build_from_class_template_specialization(
1829 *tag_argument, *class_template_specialization);
1831 tag_argument->is_template(
true);
1834 argument.set_type(tag_argument->name_and_ns());
1835 for (
const auto &p : tag_argument->template_params())
1836 argument.add_template_param(p);
1837 for (
auto &r : tag_argument->relationships()) {
1841 if (config_.generate_template_argument_dependencies() &&
1842 diagram().should_include(tag_argument->get_namespace())) {
1843 if (parent.has_value())
1844 parent.value()->add_relationship(
1845 {relationship_t::kDependency, tag_argument->id()});
1847 visitor_.set_source_location(location_decl, *tag_argument);
1848 visitor_.add_diagram_element(std::move(tag_argument));
1852 else if (
const auto *record_type_decl = record_type->getAsRecordDecl();
1853 record_type_decl !=
nullptr) {
1854#if LLVM_VERSION_MAJOR >= 22
1858 const auto qualified_name = config().simplify_template_type(
1859 record_type_decl->getQualifiedNameAsString());
1860 if (!qualified_name.empty() && qualified_name != type_name) {
1861 argument.set_type(qualified_name);
1864 const auto &effective_type_name =
1865 qualified_name.empty() ? type_name : qualified_name;
1866 const auto effective_type_id =
1867 qualified_name.empty() ? type_id :
common::to_id(qualified_name);
1868 if (config_.generate_template_argument_dependencies() &&
1869 diagram().should_include(namespace_{effective_type_name})) {
1871 {relationship_t::kDependency, effective_type_id});
1874 if (config_.generate_template_argument_dependencies() &&
1875 diagram().should_include(namespace_{type_name})) {
1879 {relationship_t::kDependency, type_id});
1887template <
typename VisitorT>
1889 std::optional<clanguml::common::model::template_element *> & ,
1890 const clang::NamedDecl * ,
const clang::TemplateDecl *template_decl,
1891 clang::QualType &type,
1894 const auto *enum_type = type->getAs<clang::EnumType>();
1895 if (enum_type ==
nullptr)
1898 LOG_DBG(
"Template argument is a an enum");
1900 auto argument = template_parameter::make_argument({});
1901 type = consume_context(type, argument);
1904 argument.set_type(type_name);
1906 argument.set_id(type_id);
1908 if (enum_type->getAsTagDecl() !=
nullptr &&
1909 config_.generate_template_argument_dependencies()) {
1911 {relationship_t::kDependency, type_id});
1917template <
typename VisitorT>
1918std::optional<template_parameter>
1920 std::optional<clanguml::common::model::template_element *> & ,
1921 clang::QualType &type,
const clang::TemplateDecl *template_decl)
1923 const auto *builtin_type = type->getAs<clang::BuiltinType>();
1924 if (builtin_type ==
nullptr)
1927 LOG_DBG(
"Template argument is a builtin type");
1930 auto argument = template_parameter::make_argument(type_name);
1932 type = consume_context(type, argument);
1933 argument.set_type(type_name);
1938template <
typename VisitorT>
1941 std::deque<std::tuple<std::string, int, bool>> &template_base_params,
1944 bool add_template_argument_as_base_class =
false;
1946 if (variadic_params) {
1947 add_template_argument_as_base_class =
true;
1950 auto [arg_name, index, is_variadic] = template_base_params.front();
1952 variadic_params = is_variadic;
1953 if ((arg_index == index) || (is_variadic && arg_index >= index)) {
1954 add_template_argument_as_base_class =
true;
1957 template_base_params.pop_front();
1962 const auto maybe_id = ct.
id();
1963 if (add_template_argument_as_base_class && maybe_id) {
1964 LOG_DBG(
"Adding template argument as base class '{}'",
1972 return variadic_params;