22#include <clang/AST/ExprConcepts.h>
23#include <clang/Basic/FileManager.h>
24#include <clang/Lex/Preprocessor.h>
25#include <spdlog/spdlog.h>
33 , template_builder_{
diagram, config, *this}
38 const clang::NamedDecl *decl)
const
40 auto cls = std::make_unique<class_>(
config().using_namespace());
47 assert(ns !=
nullptr);
52 if (ns->isAnonymousNamespace() || ns->isInline())
55 LOG_DBG(
"= Visiting namespace declaration {} at {}",
56 ns->getQualifiedNameAsString(),
61 auto package_parent = package_path;
63 (package_path.size() == 1) && !
config().using_namespace().is_empty();
64 package_path.is_root(is_root);
67 if (!package_path.is_empty())
68 name = package_path.name();
70 if (!package_parent.is_empty())
71 package_parent.pop_back();
73 const auto usn =
config().using_namespace();
75 auto p = std::make_unique<common::model::package>(usn);
76 package_path = package_path.relative_to(usn);
79 p->set_namespace(package_parent);
89 p->set_style(p->style_spec());
91 for (
const auto *attr : ns->attrs()) {
92 if (attr->getKind() == clang::attr::Kind::Deprecated) {
93 p->set_deprecated(
true);
99 diagram().add(package_path, std::move(p));
114 LOG_DBG(
"= Visiting typedef enum declaration {} at {}",
115 enm->getQualifiedNameAsString(),
123 if (enm->isComplete()) {
136 assert(enm !=
nullptr);
140 if (enm->getNameAsString().empty()) {
147 LOG_DBG(
"= Visiting enum declaration {} at {}",
148 enm->getQualifiedNameAsString(),
158std::unique_ptr<clanguml::class_diagram::model::enum_>
160 const clang::EnumDecl *enm,
const clang::TypedefDecl *typedef_decl)
162 auto e_ptr = std::make_unique<enum_>(
config().using_namespace());
168 std::optional<eid_t> parent_id_opt;
169 [[maybe_unused]] namespace_ parent_ns;
172 std::string enm_name;
173 if (enm->getNameAsString().empty() && typedef_decl !=
nullptr)
174 enm_name = typedef_decl->getNameAsString();
175 else if (parent_id_opt)
176 enm_name = enm->getNameAsString();
180 if (parent_id_opt &&
diagram().find<class_>(*parent_id_opt)) {
184 e.set_name(parent_class.value().name(), enm_name);
186 e.add_relationship({relationship_t::kContainment, *parent_id_opt});
189 else if (parent_id_opt &&
diagram().find<objc_interface>(*parent_id_opt)) {
193 e.set_name(parent_class.value().name(), enm_name);
195 e.add_relationship({relationship_t::kContainment, *parent_id_opt});
199 e.set_name(enm_name);
213 e.set_style(e.style_spec());
221 for (
const auto &ev : enm.enumerators()) {
222 e.
constants().push_back(ev->getNameAsString());
229 clang::ClassTemplateSpecializationDecl *cls)
234 LOG_DBG(
"= Visiting template specialization declaration {} at {} "
235 "(described class id {})",
236 cls->getQualifiedNameAsString(),
238 cls->getSpecializedTemplate()
239 ? cls->getSpecializedTemplate()->getTemplatedDecl()->getID()
243 if (cls->isLocalClass() !=
nullptr)
248 if (!template_specialization_ptr)
251 return add_or_update(cls, std::move(template_specialization_ptr));
255 clang::TypeAliasTemplateDecl *cls)
260 LOG_DBG(
"= Visiting template type alias declaration {} at {}",
261 cls->getQualifiedNameAsString(),
264 const auto *template_type_specialization_ptr =
265 cls->getTemplatedDecl()
266 ->getUnderlyingType()
267 ->getAs<clang::TemplateSpecializationType>();
269 if (template_type_specialization_ptr ==
nullptr)
272 auto template_specialization_ptr =
273 std::make_unique<class_>(
config().using_namespace());
275 *template_specialization_ptr, cls, *template_type_specialization_ptr);
277 template_specialization_ptr->is_template(
true);
280 const auto name = template_specialization_ptr->full_name(
true);
281 const auto id = template_specialization_ptr->id();
283 LOG_DBG(
"Adding class {} with id {}", name,
id);
288 add_class(std::move(template_specialization_ptr));
295 clang::ClassTemplateDecl *cls)
300 LOG_DBG(
"= Visiting class template declaration {} at {}",
301 cls->getQualifiedNameAsString(),
315 const auto cls_full_name = c_ptr->full_name(
false);
319 c_ptr->is_template(
true);
323 constexpr auto kMaxConstraintCount = 24U;
325#if LLVM_VERSION_MAJOR < 21
326 llvm::SmallVector<const clang::Expr *, kMaxConstraintCount> constraints{};
327 if (cls->hasAssociatedConstraints()) {
328 cls->getAssociatedConstraints(constraints);
330 for (
const auto *expr : constraints) {
334 llvm::SmallVector<clang::AssociatedConstraint, kMaxConstraintCount>
336 if (cls->hasAssociatedConstraints()) {
337 cls->getAssociatedConstraints(constraints);
339 for (
const auto &constraint : constraints) {
341 *c_ptr, constraint.ConstraintExpr);
345 return add_or_update(cls->getTemplatedDecl(), std::move(c_ptr));
353 if (clang::dyn_cast_or_null<clang::CXXRecordDecl>(rec) !=
nullptr)
361 LOG_DBG(
"= Visiting record declaration {} at {}",
362 rec->getQualifiedNameAsString(),
374 clang::ObjCCategoryDecl *decl)
379 LOG_DBG(
"= Visiting ObjC category declaration {} at {}",
380 decl->getQualifiedNameAsString(),
388 const auto category_id = category_ptr->id();
392 auto &category_model =
400 LOG_DBG(
"Adding ObjC category {} with id {}",
401 category_model.full_name(
false), category_model.id());
406 LOG_DBG(
"Skipping ObjC category {} with id {}",
407 category_model.full_name(
true), category_model.id());
414 clang::ObjCProtocolDecl *decl)
419 LOG_DBG(
"= Visiting ObjC protocol declaration {} at {}",
420 decl->getQualifiedNameAsString(),
428 const auto protocol_id = protocol_ptr->id();
432 auto &protocol_model =
440 LOG_DBG(
"Adding ObjC protocol {} with id {}",
441 protocol_model.full_name(
false), protocol_model.id());
446 LOG_DBG(
"Skipping ObjC protocol {} with id {}",
447 protocol_model.full_name(
true), protocol_model.id());
454 clang::ObjCInterfaceDecl *decl)
459 LOG_DBG(
"= Visiting ObjC interface declaration {} at {}",
460 decl->getQualifiedNameAsString(),
468 const auto protocol_id = interface_ptr->id();
472 auto &interface_model =
477 if (!interface_model.complete())
481 LOG_DBG(
"Adding ObjC interface {} with id {}",
482 interface_model.full_name(
false), interface_model.id());
487 LOG_DBG(
"Skipping ObjC interface {} with id {}",
488 interface_model.full_name(
true), interface_model.id());
499 LOG_DBG(
"= Visiting concept (isType: {}) declaration {} at {}",
500 cpt->isTypeConcept(), cpt->getQualifiedNameAsString(),
508 const auto concept_id = concept_model->id();
514 constexpr auto kMaxConstraintCount = 24U;
516#if LLVM_VERSION_MAJOR < 21
517 llvm::SmallVector<const clang::Expr *, kMaxConstraintCount> constraints{};
518 if (cpt->hasAssociatedConstraints()) {
519 cpt->getAssociatedConstraints(constraints);
522 for (
const auto *expr : constraints) {
526 llvm::SmallVector<clang::AssociatedConstraint, kMaxConstraintCount>
528 if (cpt->hasAssociatedConstraints()) {
529 cpt->getAssociatedConstraints(constraints);
531 for (
const auto &constraint : constraints) {
533 *concept_model, constraint.ConstraintExpr);
537 if (cpt->getConstraintExpr() !=
nullptr) {
539 cpt, cpt->getConstraintExpr(), *concept_model);
542 *concept_model, cpt->getConstraintExpr());
546 LOG_DBG(
"Adding concept {} with id {}", concept_model->full_name(
false),
547 concept_model->id());
552 LOG_DBG(
"Skipping concept {} with id {}",
553 concept_model->full_name(
true), concept_model->id());
560 const clang::ConceptDecl *cpt,
const clang::Expr *expr,
563 if (
const auto *constraint = llvm::dyn_cast<clang::RequiresExpr>(expr);
568 LOG_DBG(
"== Processing constraint: '{}'", constraint_source);
570 for ([[maybe_unused]]
const auto *requirement :
571 constraint->getRequirements()) {
576 for (
const auto *decl : constraint->getBody()->decls()) {
577 if (
const auto *parm_var_decl =
578 llvm::dyn_cast<clang::ParmVarDecl>(decl);
580 parm_var_decl->getQualifiedNameAsString();
582 auto param_name = parm_var_decl->getNameAsString();
584 parm_var_decl->getType(), cpt->getASTContext());
586 LOG_DBG(
"=== Processing parameter variable declaration: {}, {}",
587 param_type, param_name);
590 {std::move(param_type), std::move(param_name)});
593 LOG_DBG(
"=== Processing some other concept declaration: {}",
599 for (
const auto *req : constraint->getRequirements()) {
600 if (req->getKind() == clang::concepts::Requirement::RK_Simple) {
601 const auto *simple_req =
602 llvm::dyn_cast<clang::concepts::ExprRequirement>(req);
604 if (simple_req !=
nullptr) {
606 simple_req->getExpr(), [&concept_model](
const auto *e) {
607 auto simple_expr = common::to_string(e);
609 LOG_DBG(
"=== Processing expression requirement: {}",
612 concept_model.add_statement(std::move(simple_expr));
616 else if (req->getKind() == clang::concepts::Requirement::RK_Type) {
618 llvm::dyn_cast<clang::concepts::TypeRequirement>(req),
619 [&concept_model, cpt](
const auto *t) {
621 t->getType()->getType(), cpt->getASTContext());
624 "=== Processing type requirement: {}", type_name);
629 else if (req->getKind() ==
630 clang::concepts::Requirement::RK_Nested) {
631 const auto *nested_req =
632 llvm::dyn_cast<clang::concepts::NestedRequirement>(req);
634 if (nested_req !=
nullptr) {
636 nested_req->getConstraintExpr(), [](
const auto *e) {
637 LOG_DBG(
"=== Processing nested requirement: {}",
638 common::to_string(e));
642 else if (req->getKind() ==
643 clang::concepts::Requirement::RK_Compound) {
644 const auto *compound_req =
645 llvm::dyn_cast<clang::concepts::ExprRequirement>(req);
647 if (compound_req !=
nullptr) {
648 const auto *compound_expr_ptr = compound_req->getExpr();
650 if (compound_expr_ptr !=
nullptr) {
654 auto req_return_type =
655 compound_req->getReturnTypeRequirement();
657 if (!req_return_type.isEmpty()) {
659 fmt::format(
"{{{}}} -> {}", compound_expr,
661 req_return_type.getTypeConstraint()));
663 else if (compound_req->hasNoexceptRequirement()) {
665 fmt::format(
"{{{}}} noexcept", compound_expr);
668 LOG_DBG(
"=== Processing compound requirement: {}",
677 else if (
const auto *binop = llvm::dyn_cast<clang::BinaryOperator>(expr);
682 else if (
const auto *unop = llvm::dyn_cast<clang::UnaryOperator>(expr);
693 found_relationships_t relationships;
695 common::if_dyn_cast<clang::UnresolvedLookupExpr>(
696 expr, [&](
const clang::UnresolvedLookupExpr *ul) {
697 for (
const auto ta : ul->template_arguments()) {
698 if (ta.getArgument().getKind() !=
699 clang::TemplateArgument::ArgKind::Type)
702 relationships, relationship_t::kConstraint);
706 common::if_dyn_cast<clang::ConceptSpecializationExpr>(
707 expr, [&](
const auto *cs) {
711 common::if_dyn_cast<clang::RequiresExpr>(expr, [&](
const auto *re) {
715 common::if_dyn_cast<clang::BinaryOperator>(expr, [&](
const auto *op) {
720 common::if_dyn_cast<clang::UnaryOperator>(expr, [&](
const auto *op) {
724 for (
const auto &[type_element_id, relationship_type, source_decl] :
726 if (type_element_id != c.
id() &&
727 (relationship_type != relationship_t::kNone)) {
731 if (source_decl !=
nullptr) {
742 const clang::ConceptSpecializationExpr *concept_specialization)
745 if (
const auto *cpt = concept_specialization->getNamedConcept();
748 const auto cpt_name = cpt->getNameAsString();
749 const eid_t ast_id{cpt->getID()};
754 const auto target_id = maybe_id.value();
756 std::vector<std::string> constrained_template_params;
758 size_t argument_index{};
760 for (
const auto ta : concept_specialization->getTemplateArguments()) {
761 if (ta.getKind() == clang::TemplateArgument::Type) {
765 cpt, constrained_template_params, argument_index,
768 else if (ta.getKind() == clang::TemplateArgument::Pack) {
769 if (!ta.getPackAsArray().empty() &&
770 ta.getPackAsArray().front().isPackExpansion()) {
771 const auto &pack_head =
772 ta.getPackAsArray().front().getAsType();
776 concept_specialization, cpt,
777 constrained_template_params, argument_index, type_name);
781 LOG_DBG(
"Unsupported concept type parameter in concept: {}",
787 if (!constrained_template_params.empty())
789 {relationship_t::kConstraint, target_id, access_t::kNone,
791 "{}", fmt::join(constrained_template_params,
","))});
800 LOG_DBG(
"= Visiting class declaration {} at {}",
801 cls->getQualifiedNameAsString(),
805 "== getQualifiedNameAsString() = {}", cls->getQualifiedNameAsString());
806 if (cls->getOwningModule() !=
nullptr)
808 "== getOwningModule()->Name = {}", cls->getOwningModule()->Name);
809 LOG_DBG(
"== getID() = {}", cls->getID());
810 LOG_DBG(
"== isTemplateDecl() = {}", cls->isTemplateDecl());
811 LOG_DBG(
"== isTemplated() = {}", cls->isTemplated());
812 LOG_DBG(
"== getParent()->isRecord()() = {}", cls->getParent()->isRecord());
813 LOG_DBG(
"== isCompleteDefinition() = {}", cls->isCompleteDefinition());
815 if (
const auto *parent_record =
816 clang::dyn_cast<clang::RecordDecl>(cls->getParent());
817 parent_record !=
nullptr) {
818 LOG_DBG(
"== getParent()->getQualifiedNameAsString() = {}",
819 parent_record->getQualifiedNameAsString());
827 if (cls->isTemplated() && (cls->getDescribedTemplate() !=
nullptr)) {
830 const eid_t ast_id{cls->getDescribedTemplate()->getID()};
836 if (cls->isLocalClass() !=
nullptr)
847std::unique_ptr<clanguml::class_diagram::model::concept_>
850 assert(cpt !=
nullptr);
856 std::make_unique<model::concept_>(
config().using_namespace())};
857 auto &concept_model = *concept_ptr;
861 concept_model.set_name(cpt->getNameAsString());
862 concept_model.set_namespace(ns);
863 concept_model.set_id(
common::to_id(concept_model.full_name(
false)));
869 if (concept_model.skip())
872 concept_model.set_style(concept_model.style_spec());
878 clang::RecordDecl *rec)
880 assert(rec !=
nullptr);
885 auto record_ptr{std::make_unique<class_>(
config().using_namespace())};
886 auto &record = *record_ptr;
890 if (!record.is_nested()) {
891 auto record_name = rec->getQualifiedNameAsString();
893#if LLVM_VERSION_MAJOR < 16
894 if (record_name ==
"(anonymous)") {
896 [&record_name](
const clang::TypedefNameDecl *name) {
897 record_name = name->getNameAsString();
902 record.set_name(record_name);
910 const auto record_full_name = record_ptr->full_name(
false);
912 record.is_struct(rec->isStruct());
913 record.is_union(rec->isUnion());
918 record.set_style(record.style_spec());
924 clang::CXXRecordDecl *cls)
926 assert(cls !=
nullptr);
931 auto c_ptr{std::make_unique<class_>(
config().using_namespace())};
938 if (!c.is_nested()) {
944 c.is_struct(cls->isStruct());
953 c.set_style(c.style_spec());
958std::unique_ptr<clanguml::class_diagram::model::objc_interface>
960 clang::ObjCCategoryDecl *decl)
962 assert(decl !=
nullptr);
967 auto c_ptr{std::make_unique<class_diagram::model::objc_interface>(
968 config().using_namespace())};
971 decl->getClassInterface()->getNameAsString();
972 c.set_name(fmt::format(
"{}({})",
973 decl->getClassInterface()->getNameAsString(), decl->getNameAsString()));
974 c.set_id(
common::to_id(fmt::format(
"__objc__category__{}", c.name())));
983 c.set_style(c.style_spec());
988std::unique_ptr<clanguml::class_diagram::model::objc_interface>
990 clang::ObjCProtocolDecl *decl)
992 assert(decl !=
nullptr);
997 auto c_ptr{std::make_unique<class_diagram::model::objc_interface>(
998 config().using_namespace())};
1001 c.set_name(decl->getNameAsString());
1003 c.is_protocol(
true);
1011 c.set_style(c.style_spec());
1016std::unique_ptr<clanguml::class_diagram::model::objc_interface>
1018 clang::ObjCInterfaceDecl *decl)
1020 assert(decl !=
nullptr);
1025 auto c_ptr{std::make_unique<class_diagram::model::objc_interface>(
1026 config().using_namespace())};
1029 c.set_name(decl->getNameAsString());
1038 c.set_style(c.style_spec());
1044 clang::RecordDecl *cls,
class_ &c,
const namespace_ &ns)
1046 std::optional<eid_t> id_opt;
1047 namespace_ parent_ns = ns;
1051 if (id_opt &&
diagram().find<class_>(*id_opt)) {
1052 process_record_parent_by_type<class_>(*id_opt, c, parent_ns, cls);
1055 if (id_opt &&
diagram().find<objc_interface>(*id_opt)) {
1056 process_record_parent_by_type<objc_interface>(
1057 *id_opt, c, parent_ns, cls);
1079 for (
const auto *method : cls.methods()) {
1080 if (method !=
nullptr) {
1087 if (cls.getClassInterface() !=
nullptr) {
1090 relationship_t::kInstantiation, objc_interface_id, access_t::kNone};
1092 LOG_DBG(
"Found protocol {} [{}] for ObjC interface {}",
1093 cls.getClassInterface()->getNameAsString(),
1108 for (
const auto *method : cls.methods()) {
1109 if (method !=
nullptr) {
1123 for (
const auto *method : cls.methods()) {
1124 if (method !=
nullptr) {
1129 for (
const auto *ivar : cls.ivars()) {
1130 if (ivar !=
nullptr) {
1142 if (
const auto *base = cls.getSuperClass(); base !=
nullptr) {
1146 LOG_DBG(
"Found base class {} [{}] for ObjC interface {}",
1147 base->getNameAsString(), parent_id.
value(), c.
name());
1152 for (
const auto *protocol : cls.protocols()) {
1155 relationship_t::kInstantiation, parent_id, access_t::kNone};
1157 LOG_DBG(
"Found protocol {} [{}] for ObjC interface {}",
1158 protocol->getNameAsString(), parent_id.
value(), c.
name());
1167 LOG_DBG(
"== Visiting ObjC ivar {}", ivar.getNameAsString());
1170 auto relationship_hint = relationship_t::kAggregation;
1172 auto field_type = ivar.getType();
1173 auto field_type_str =
1178 const auto field_name = ivar.getNameAsString();
1182 field_name, field_type_str};
1184 field.set_qualified_name(ivar.getQualifiedNameAsString());
1192 if (field_type->isObjCObjectPointerType()) {
1193 relationship_hint = relationship_t::kAggregation;
1194 field_type = field_type->getPointeeType();
1196 else if (field_type->isPointerType()) {
1197 relationship_hint = relationship_t::kAssociation;
1198 field_type = field_type->getPointeeType();
1200 else if (field_type->isLValueReferenceType()) {
1201 relationship_hint = relationship_t::kAssociation;
1202 field_type = field_type.getNonReferenceType();
1204 else if (field_type->isArrayType()) {
1205 relationship_hint = relationship_t::kAggregation;
1206 while (field_type->isArrayType()) {
1207 auto current_multiplicity = field.destination_multiplicity();
1208 if (!current_multiplicity)
1210 *field_type->getAsArrayTypeUnsafe()));
1212 auto maybe_array_size =
1214 if (maybe_array_size.has_value()) {
1215 field.set_destination_multiplicity(
1216 current_multiplicity.value() *
1217 maybe_array_size.value());
1221 field_type = field_type->getAsArrayTypeUnsafe()->getElementType();
1224 else if (field_type->isRValueReferenceType()) {
1225 field_type = field_type.getNonReferenceType();
1228 found_relationships_t relationships;
1230 if (!field.skip_relationship()) {
1233 if (field_type->getAsObjCInterfaceType() !=
nullptr &&
1234 field_type->getAsObjCInterfaceType()->getInterface() !=
nullptr) {
1235 const auto *objc_iface =
1236 field_type->getAsObjCInterfaceType()->getInterface();
1239 relationship_t::kAggregation, &ivar);
1241 else if ((field_type->getAsRecordDecl() !=
nullptr) &&
1242 field_type->getAsRecordDecl()->getNameAsString().empty()) {
1247 std::make_tuple(field.name(), relationship_hint, field.access(),
1248 field.destination_multiplicity());
1252 &ivar, field_type, relationships, relationship_hint);
1259 if ((field_type->getAsRecordDecl() !=
nullptr) &&
1260 field_type->getAsRecordDecl()->getNameAsString().empty()) {
1262 std::regex anonymous_re(
"anonymous_(\\d*)");
1264 std::regex_replace(field.type(), anonymous_re, field_name));
1272 const clang::CXXRecordDecl *cls,
class_ &c)
1274 for (
const auto &base : cls->bases()) {
1276 if (
const auto *tsp =
1277 base.getType()->getAs<clang::TemplateSpecializationType>();
1279 auto template_specialization_ptr =
1280 std::make_unique<class_>(
config().using_namespace());
1282 *cls, *template_specialization_ptr, cls, *tsp, {});
1284 parent_id = template_specialization_ptr->id();
1287 add_class(std::move(template_specialization_ptr));
1290 else if (
const auto *record_type =
1291 base.getType()->getAs<clang::RecordType>();
1292 record_type !=
nullptr) {
1303 LOG_DBG(
"Found base class {} [{}] for class {}",
1312 const clang::RecordDecl &cls,
class_ &c)
1315 for (
const auto *field : cls.fields()) {
1316 if (field !=
nullptr)
1326 assert(cls !=
nullptr);
1329 for (
const auto *method : cls->methods()) {
1330 if (method !=
nullptr) {
1336 if (
const auto *cls_decl_context =
1337 clang::dyn_cast_or_null<clang::DeclContext>(cls);
1338 cls_decl_context !=
nullptr) {
1339 for (
auto const *decl_iterator : cls_decl_context->decls()) {
1340 auto const *method_template =
1341 llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>(
1343 if (method_template ==
nullptr)
1351 for (
const auto *field : cls->fields()) {
1352 if (field !=
nullptr)
1358 std::set<const clang::EnumDecl *> typedeffed_enums;
1359 for (
const auto *decl : cls->decls()) {
1360 if (decl->getKind() == clang::Decl::Typedef) {
1362 clang::dyn_cast<clang::TypedefDecl>(decl));
1363 if (typedeffed_enum !=
nullptr)
1364 typedeffed_enums.emplace(typedeffed_enum);
1370 for (
const auto *decl : cls->decls()) {
1371 if (decl->getKind() == clang::Decl::Var) {
1372 const clang::VarDecl *variable_declaration{
1373 clang::dyn_cast_or_null<clang::VarDecl>(decl)};
1374 if ((variable_declaration !=
nullptr) &&
1375 variable_declaration->isStaticDataMember()) {
1379 else if (decl->getKind() == clang::Decl::Enum &&
1380 typedeffed_enums.count(
1381 clang::dyn_cast_or_null<clang::EnumDecl>(decl)) == 0) {
1382 const auto *enum_decl =
1383 clang::dyn_cast_or_null<clang::EnumDecl>(decl);
1384 if (enum_decl ==
nullptr)
1387 if (enum_decl->getNameAsString().empty()) {
1388 for (
const auto *enum_const : enum_decl->enumerators()) {
1390 enum_decl->getAccess()),
1391 enum_const->getNameAsString(),
"enum"};
1398 if (cls->isCompleteDefinition())
1399 for (
const auto *friend_declaration : cls->friends()) {
1400 if (friend_declaration !=
nullptr)
1406 const clang::FriendDecl &f,
class_ &c)
1408 if (
const auto *friend_type_info = f.getFriendType()) {
1409 const auto friend_type = friend_type_info->getType();
1410 if (friend_type->getAs<clang::TemplateSpecializationType>() !=
1414 else if (friend_type->getAs<clang::RecordType>() !=
nullptr) {
1428 const clang::CXXMethodDecl &mf,
class_ &c)
1432 if (mf.isDefaulted() && !mf.isExplicitlyDefaulted())
1435 auto method_return_type =
1440 auto method_name = mf.getNameAsString();
1441 if (mf.isTemplated()) {
1445 method_name = method_name.substr(0, method_name.find(
'<'));
1450 config().simplify_template_type(method_return_type)};
1452 method.set_qualified_name(mf.getQualifiedNameAsString());
1464 for (
const auto *param : mf.parameters()) {
1465 if (param !=
nullptr)
1470 found_relationships_t relationships;
1473 if (
const auto *templ = mf.getReturnType()
1474 .getNonReferenceType()
1475 .getUnqualifiedType()
1476 ->getAs<clang::TemplateSpecializationType>();
1478 const auto *unaliased_type = templ;
1479 if (unaliased_type->isTypeAlias())
1480 unaliased_type = unaliased_type->getAliasedType()
1481 ->getAs<clang::TemplateSpecializationType>();
1483 if (unaliased_type !=
nullptr) {
1484 auto template_specialization_ptr =
1485 std::make_unique<class_>(
config().using_namespace());
1487 *template_specialization_ptr,
1488 unaliased_type->getTemplateName().getAsTemplateDecl(),
1489 *unaliased_type, &c);
1491 template_specialization_ptr->is_template();
1494 relationships.emplace_back(template_specialization_ptr->id(),
1495 relationship_t::kDependency, &mf);
1497 add_class(std::move(template_specialization_ptr));
1503 &mf, mf.getReturnType(), relationships, relationship_t::kDependency);
1505 for (
const auto &[type_element_id, relationship_type, source_decl] :
1507 if (type_element_id != c.
id() &&
1508 (relationship_type != relationship_t::kNone)) {
1509 relationship r{relationship_t::kDependency, type_element_id};
1511 if (source_decl !=
nullptr) {
1515 LOG_DBG(
"Adding method return type relationship from {}::{} to "
1517 c, mf.getNameAsString(), r.type(), r.label());
1526 auto underlying_type = mf.getReturnType();
1527 if (underlying_type->isReferenceType())
1528 underlying_type = underlying_type.getNonReferenceType();
1529 if (underlying_type->isPointerType())
1530 underlying_type = underlying_type->getPointeeType();
1532 if (
const auto *atsp = underlying_type->getAs<clang::AutoType>();
1537 method.update(
config().using_namespace());
1540 LOG_DBG(
"Adding method: {}", method.name());
1549 auto method_return_type =
1553 util::trim(mf.getNameAsString()), method_return_type};
1555 method.set_qualified_name(mf.getQualifiedNameAsString());
1565 method.is_static(mf.isClassMethod());
1566 method.is_optional(mf.isOptional());
1568 for (
const auto *param : mf.parameters()) {
1569 if (param !=
nullptr)
1574 found_relationships_t relationships;
1577 &mf, mf.getReturnType(), relationships, relationship_t::kDependency);
1579 for (
const auto &[type_element_id, relationship_type, source_decl] :
1581 if (type_element_id != c.
id() &&
1582 (relationship_type != relationship_t::kNone)) {
1583 relationship r{relationship_t::kDependency, type_element_id};
1585 if (source_decl !=
nullptr) {
1589 LOG_DBG(
"Adding method return type relationship from {}::{} to "
1591 c, mf.getNameAsString(), r.type(), r.label());
1599 LOG_DBG(
"Adding ObjC method: {}", method.name());
1606 const clang::CXXMethodDecl &mf,
const class_ &c,
1607 const std::string &method_name,
class_method &method)
const
1609 const bool is_constructor = c.
name() == method_name;
1610 const bool is_destructor = fmt::format(
"~{}", c.
name()) == method_name;
1612#if LLVM_VERSION_MAJOR > 17
1613 method.is_pure_virtual(mf.isPureVirtual());
1615 method.is_pure_virtual(mf.isPure());
1617 method.is_virtual(mf.isVirtual());
1618 method.is_const(mf.isConst());
1619 method.is_defaulted(mf.isDefaulted());
1620 method.is_deleted(mf.isDeleted());
1621 method.is_static(mf.isStatic());
1622 method.is_operator(mf.isOverloadedOperator());
1623 method.is_constexpr(mf.isConstexprSpecified() && !is_constructor);
1624 method.is_consteval(mf.isConsteval());
1625 method.is_constructor(is_constructor);
1626 method.is_destructor(is_destructor);
1627 method.is_move_assignment(mf.isMoveAssignmentOperator());
1628 method.is_copy_assignment(mf.isCopyAssignmentOperator());
1629 method.is_noexcept(isNoexceptExceptionSpec(mf.getExceptionSpecType()));
1635 class_ &c,
const clang::AutoType *atsp)
1637 auto desugared_atsp = atsp->getDeducedType();
1639 if (atsp->isSugared()) {
1640 const auto *deduced_type =
1641 atsp->desugar()->getAs<clang::DeducedTemplateSpecializationType>();
1643 if (deduced_type !=
nullptr)
1644 desugared_atsp = deduced_type->getDeducedType();
1647 if (desugared_atsp.isNull())
1650 const auto *deduced_record_type = desugared_atsp->isRecordType()
1651 ? desugared_atsp->getAs<clang::RecordType>()
1654 if (deduced_record_type !=
nullptr) {
1655 if (
auto *deduced_auto_decl =
1656 llvm::dyn_cast_or_null<clang::ClassTemplateSpecializationDecl>(
1657 deduced_record_type->getDecl());
1658 deduced_auto_decl !=
nullptr) {
1660 const auto diagram_class_count_before_visit =
1665 const bool visitor_added_new_template_specialization =
1667 diagram_class_count_before_visit) > 0;
1669 if (visitor_added_new_template_specialization) {
1670 const auto &template_specialization_model =
1675 template_specialization_model.get().id()};
1685 const clang::FunctionTemplateDecl &mf,
class_ &c)
1689 if (mf.getTemplatedDecl()->isDefaulted() &&
1690 !mf.getTemplatedDecl()->isExplicitlyDefaulted())
1693 auto method_name = mf.getNameAsString();
1694 if (mf.isTemplated()) {
1698 method_name =
util::trim(method_name.substr(0, method_name.find(
'<')));
1702 method_name, mf.getTemplatedDecl()->getReturnType().getAsString()};
1705 clang::dyn_cast<clang::CXXMethodDecl>(mf.getTemplatedDecl()),
1706 [&](
const auto *decl) {
1707 process_method_properties(*decl, c, method_name, method);
1717 for (
const auto *param : mf.getTemplatedDecl()->parameters()) {
1718 if (param !=
nullptr)
1722 method.update(
config().using_namespace());
1725 LOG_DBG(
"Adding method: {}", method.name());
1732 const clang::QualType &type, found_relationships_t &relationships,
1737 if (type->isPointerType()) {
1738 relationship_hint = relationship_t::kAssociation;
1740 decl, type->getPointeeType(), relationships, relationship_hint);
1742 else if (type->isRValueReferenceType()) {
1743 relationship_hint = relationship_t::kAggregation;
1745 decl, type.getNonReferenceType(), relationships, relationship_hint);
1747 else if (type->isLValueReferenceType()) {
1748 relationship_hint = relationship_t::kAssociation;
1750 decl, type.getNonReferenceType(), relationships, relationship_hint);
1752 else if (type->isArrayType()) {
1754 relationships, relationship_t::kAggregation);
1756 else if (type->isEnumeralType()) {
1757 if (
const auto *enum_type = type->getAs<clang::EnumType>();
1758 enum_type !=
nullptr) {
1762 relationships.emplace_back(
1763 enum_type->getDecl()->getID(), relationship_hint, decl);
1767 else if (type->isRecordType()) {
1768 const auto *type_instantiation_type =
1769 type->getAs<clang::TemplateSpecializationType>();
1771 if (type_instantiation_type !=
nullptr) {
1772 const auto *type_instantiation_template_decl =
1773 type_instantiation_type->getTemplateName().getAsTemplateDecl();
1778 relationships.emplace_back(
1779 type_instantiation_type->getTemplateName()
1780 .getAsTemplateDecl()
1782 relationship_hint, decl);
1786 for (
const auto &template_argument :
1787 type_instantiation_type->template_arguments()) {
1789 auto [overridden_relationship_hint, overridden] =
1791 ->getQualifiedNameAsString(),
1792 idx, relationship_hint);
1794 const auto template_argument_kind = template_argument.getKind();
1795 if (template_argument_kind ==
1796 clang::TemplateArgument::ArgKind::Integral) {
1799 else if (template_argument_kind ==
1800 clang::TemplateArgument::ArgKind::Null) {
1803 else if (template_argument_kind ==
1804 clang::TemplateArgument::ArgKind::Expression) {
1807 else if (template_argument.getKind() ==
1808 clang::TemplateArgument::ArgKind::NullPtr) {
1811 else if (template_argument_kind ==
1812 clang::TemplateArgument::ArgKind::Template) {
1815 else if (template_argument_kind ==
1816 clang::TemplateArgument::ArgKind::TemplateExpansion) {
1819 else if (
const auto *function_type =
1820 template_argument.getAsType()
1821 ->getAs<clang::FunctionProtoType>();
1822 function_type !=
nullptr) {
1823 for (
const auto ¶m_type :
1824 function_type->param_types()) {
1826 relationships, relationship_t::kDependency);
1829 else if (template_argument_kind ==
1830 clang::TemplateArgument::ArgKind::Type) {
1833 relationships, overridden_relationship_hint);
1838 else if (type->getAsCXXRecordDecl() !=
nullptr) {
1839 relationships.emplace_back(
1840 type->getAsCXXRecordDecl()->getID(), relationship_hint, decl);
1844 relationships.emplace_back(
1845 type->getAsRecordDecl()->getID(), relationship_hint, decl);
1849 else if (
const auto *template_specialization_type =
1850 type->getAs<clang::TemplateSpecializationType>();
1851 template_specialization_type !=
nullptr) {
1852 const auto *type_instantiation_template_decl =
1853 template_specialization_type->getTemplateName().getAsTemplateDecl();
1854 if (
should_include(template_specialization_type->getTemplateName()
1855 .getAsTemplateDecl())) {
1856 relationships.emplace_back(
1857 template_specialization_type->getTemplateName()
1858 .getAsTemplateDecl()
1860 relationship_hint, decl);
1863 for (
const auto &template_argument :
1864 template_specialization_type->template_arguments()) {
1866 auto [overridden_relationship_hint, overridden] =
1868 ->getQualifiedNameAsString(),
1869 idx, relationship_hint);
1871 const auto template_argument_kind = template_argument.getKind();
1872 if (template_argument_kind ==
1873 clang::TemplateArgument::ArgKind::Integral) {
1876 else if (template_argument_kind ==
1877 clang::TemplateArgument::ArgKind::Null) {
1880 else if (template_argument_kind ==
1881 clang::TemplateArgument::ArgKind::Expression) {
1884 else if (template_argument.getKind() ==
1885 clang::TemplateArgument::ArgKind::NullPtr) {
1888 else if (template_argument_kind ==
1889 clang::TemplateArgument::ArgKind::Template) {
1892 else if (template_argument_kind ==
1893 clang::TemplateArgument::ArgKind::TemplateExpansion) {
1896 else if (
const auto *function_type =
1897 template_argument.getAsType()
1898 ->getAs<clang::FunctionProtoType>();
1899 function_type !=
nullptr) {
1900 for (
const auto ¶m_type : function_type->param_types()) {
1902 relationship_t::kDependency);
1905 else if (template_argument_kind ==
1906 clang::TemplateArgument::ArgKind::Type) {
1908 relationships, overridden_relationship_hint);
1921 parameter.
set_name(param.getNameAsString());
1925 if (parameter.
skip())
1928 auto parameter_type =
1930 parameter.
set_type(parameter_type);
1934 found_relationships_t relationships;
1936 LOG_DBG(
"Looking for relationships in type: {}",
1940 relationship_t::kDependency);
1942 for (
const auto &[type_element_id, relationship_type, source_decl] :
1944 if (type_element_id != c.
id() &&
1945 (relationship_type != relationship_t::kNone)) {
1946 relationship r{relationship_t::kDependency, type_element_id};
1948 if (source_decl !=
nullptr) {
1952 LOG_DBG(
"Adding ObjC method parameter relationship from {} to "
1954 c, r.type(), r.label());
1961 method.add_parameter(std::move(parameter));
1966 const std::set<std::string> & )
1969 parameter.
set_name(p.getNameAsString());
1973 if (parameter.
skip())
1981 parameter.
set_type(parameter_type);
1983 if (p.hasDefaultArg()) {
1984 const auto *default_arg = p.getDefaultArg();
1985 if (default_arg !=
nullptr) {
1994 found_relationships_t relationships;
1996 LOG_DBG(
"Looking for relationships in type: {}",
1999 if (
const auto *templ =
2001 .getNonReferenceType()
2002 .getUnqualifiedType()
2003 ->getAs<clang::TemplateSpecializationType>();
2005 auto template_specialization_ptr =
2006 std::make_unique<class_>(
config().using_namespace());
2008 *template_specialization_ptr,
2009 templ->getTemplateName().getAsTemplateDecl(), *templ, &c);
2011 template_specialization_ptr->is_template(
true);
2014 relationships.emplace_back(template_specialization_ptr->id(),
2015 relationship_t::kDependency, &p);
2017 add_class(std::move(template_specialization_ptr));
2022 &p, p.getType(), relationships, relationship_t::kDependency);
2024 for (
const auto &[type_element_id, relationship_type, source_decl] :
2026 if (type_element_id != c.
id() &&
2027 (relationship_type != relationship_t::kNone)) {
2028 relationship r{relationship_t::kDependency, type_element_id};
2030 if (source_decl !=
nullptr) {
2034 LOG_DBG(
"Adding function parameter relationship from {} to "
2036 c, r.type(), r.label());
2043 method.add_parameter(std::move(parameter));
2048 const found_relationships_t &relationships,
bool break_on_first_aggregation)
2052 for (
const auto &[target, relationship_type, source_decl] : relationships) {
2053 if (relationship_type != relationship_t::kNone) {
2056 r.set_access(field.
access());
2057 if (source_decl !=
nullptr) {
2060 bool mulitplicity_provided_in_comment{
false};
2061 if (decorator_rtype != relationship_t::kNone) {
2062 r.set_type(decorator_rtype);
2063 auto mult =
util::split(decorator_rmult,
":",
false);
2064 if (mult.size() == 2) {
2065 mulitplicity_provided_in_comment =
true;
2066 r.set_multiplicity_source(mult[0]);
2067 r.set_multiplicity_destination(mult[1]);
2070 if (!mulitplicity_provided_in_comment &&
2072 r.set_multiplicity_destination(
2078 LOG_DBG(
"Adding relationship from {} to {} with label {}", c,
2079 r.destination(), r.type(), r.label());
2083 if (break_on_first_aggregation &&
2084 relationship_type == relationship_t::kAggregation)
2090std::pair<relationship_t, bool>
2092 const std::string &type_name,
int index, relationship_t hint)
2094 bool overridden{
false};
2096 for (
const auto &[pattern, rel_hint] :
config().relationship_hints()) {
2097 if (type_name.find(pattern) == 0) {
2099 hint = rel_hint.default_hint;
2101 hint = rel_hint.get(index, hint);
2108 return {hint, overridden};
2112 const clang::VarDecl &field_declaration,
class_ &c)
2114 const auto field_type = field_declaration.getType();
2117 if (type_name.empty())
2118 type_name =
"<<anonymous>>";
2122 field_declaration.getNameAsString(),
2123 config().simplify_template_type(type_name)};
2125 field.set_qualified_name(field_declaration.getQualifiedNameAsString());
2127 field.is_static(
true);
2135 if (!field.skip_relationship()) {
2136 found_relationships_t relationships;
2140 relationships, relationship_t::kAssociation);
2148std::unique_ptr<class_>
2150 clang::ClassTemplateSpecializationDecl *cls)
2152 LOG_DBG(
"Processing template specialization {} at {}",
2153 cls->getQualifiedNameAsString(),
2156 auto c_ptr = std::make_unique<class_>(
config().using_namespace());
2159 auto &template_instantiation = *c_ptr;
2160 template_instantiation.is_template(
true);
2163 auto qualified_name = cls->getQualifiedNameAsString();
2167 namespace_ ns{qualified_name};
2169 template_instantiation.set_name(cls->getNameAsString());
2170 template_instantiation.set_namespace(ns);
2172 template_instantiation.is_struct(cls->isStruct());
2176 if (!template_instantiation.is_nested()) {
2178 template_instantiation.set_id(
2186 if (template_instantiation.skip())
2189 id_mapper().
add(cls->getID(), template_instantiation.id());
2195 const clang::FieldDecl &field_declaration,
class_ &c)
2198 "== Visiting record member {}", field_declaration.getNameAsString());
2201 auto relationship_hint = relationship_t::kAggregation;
2205 [[maybe_unused]]
bool template_instantiation_added_as_aggregation{
false};
2207 auto field_type = field_declaration.getType();
2213 const auto field_name = field_declaration.getNameAsString();
2215 auto field_type_str =
2222 field_name,
config().simplify_template_type(field_type_str)};
2224 field.set_qualified_name(field_declaration.getQualifiedNameAsString());
2235 if (field_type->isPointerType()) {
2236 relationship_hint = relationship_t::kAssociation;
2237 field_type = field_type->getPointeeType();
2239 else if (field_type->isLValueReferenceType()) {
2240 relationship_hint = relationship_t::kAssociation;
2241 field_type = field_type.getNonReferenceType();
2243 else if (field_type->isArrayType()) {
2244 relationship_hint = relationship_t::kAggregation;
2245 while (field_type->isArrayType()) {
2246 auto current_multiplicity = field.destination_multiplicity();
2247 if (!current_multiplicity)
2249 *field_type->getAsArrayTypeUnsafe()));
2251 auto maybe_array_size =
2253 if (maybe_array_size.has_value()) {
2254 field.set_destination_multiplicity(
2255 current_multiplicity.value() *
2256 maybe_array_size.value());
2260 field_type = field_type->getAsArrayTypeUnsafe()->getElementType();
2263 else if (field_type->isRValueReferenceType()) {
2264 field_type = field_type.getNonReferenceType();
2267 auto [overridden_relationship_hint, overridden] =
2270 relationship_hint = overridden_relationship_hint;
2272 found_relationships_t relationships;
2274 const auto *template_field_type =
2275 field_type->getAs<clang::TemplateSpecializationType>();
2277 if (template_field_type !=
nullptr)
2278 if (template_field_type->isTypeAlias())
2279 template_field_type =
2280 template_field_type->getAliasedType()
2281 ->getAs<clang::TemplateSpecializationType>();
2283 bool field_type_is_template_template_parameter{
false};
2284 if (template_field_type !=
nullptr) {
2288 if (class_template_param.name() ==
2289 template_field_type->getTemplateName()
2290 .getAsTemplateDecl()
2291 ->getNameAsString() +
2293 field_type_is_template_template_parameter =
true;
2299 if (template_field_type !=
nullptr &&
2300 !field_type_is_template_template_parameter) {
2302 auto template_specialization_ptr =
2303 std::make_unique<class_>(
config().using_namespace());
2305 *template_specialization_ptr,
2306 field_type->getAs<clang::TemplateSpecializationType>()
2308 .getAsTemplateDecl(),
2309 *template_field_type, {&c});
2310 template_specialization_ptr->is_template(
true);
2312 if (!field.skip_relationship() && template_specialization_ptr) {
2313 const auto &template_specialization = *template_specialization_ptr;
2319 bool add_template_instantiation_to_diagram{
false};
2322 found_relationships_t::value_type r{
2323 template_specialization.id(), relationship_hint,
2324 &field_declaration};
2326 add_template_instantiation_to_diagram =
true;
2330 template_instantiation_added_as_aggregation =
2331 relationship_hint == relationship_t::kAggregation;
2332 relationships.emplace_back(std::move(r));
2337 found_relationships_t nested_relationships;
2339 if (!template_instantiation_added_as_aggregation) {
2340 for (
const auto &template_argument :
2341 template_specialization.template_params()) {
2343 auto template_argument_str = template_argument.to_string(
2344 config().using_namespace(),
false);
2346 LOG_DBG(
"Looking for nested relationships from {}::{} in "
2347 "template argument {}",
2348 c, field_name, template_argument_str);
2350 auto [overridden_relationship_hint_param,
2353 template_specialization.full_name(
false), idx,
2356 template_instantiation_added_as_aggregation =
2357 template_argument.find_nested_relationships(
2358 &field_declaration, nested_relationships,
2359 overridden_relationship_hint_param,
2361 [&d =
diagram()](
const std::string &full_name) {
2362 if (full_name.empty())
2365 return d.should_include(ns, name);
2379 if (add_template_instantiation_to_diagram)
2380 add_class(std::move(template_specialization_ptr));
2384 if (!field.skip_relationship()) {
2387 if (!template_instantiation_added_as_aggregation) {
2388 if ((field_type->getAsRecordDecl() !=
nullptr) &&
2389 field_type->getAsRecordDecl()->getNameAsString().empty()) {
2394 std::make_tuple(field.name(), relationship_hint,
2395 field.access(), field.destination_multiplicity());
2399 relationships, relationship_hint);
2407 if ((field_type->getAsRecordDecl() !=
nullptr) &&
2408 field_type->getAsRecordDecl()->getNameAsString().empty()) {
2410 std::regex anonymous_re(
"anonymous_(\\d*)");
2412 std::regex_replace(field.type(), anonymous_re, field_name));
2422 std::optional<eid_t> &parent_id_opt, namespace_ &parent_ns)
const
2424 const auto *parent = decl->getParent();
2426 if (parent !=
nullptr) {
2427 if (
const auto *parent_record_decl =
2428 clang::dyn_cast<clang::RecordDecl>(parent);
2429 parent_record_decl !=
nullptr) {
2432 eid_t local_id{parent_record_decl->getID()};
2440 if (!parent_id_opt) {
2441 if (parent_record_decl->getDescribedTemplate() !=
nullptr) {
2443 parent_record_decl->getDescribedTemplate()->getID();
2453 const auto *lexical_parent = decl->getLexicalParent();
2454 if (lexical_parent !=
nullptr) {
2455 if (
const auto *parent_interface_decl =
2456 clang::dyn_cast<clang::ObjCInterfaceDecl>(lexical_parent);
2457 parent_interface_decl !=
nullptr) {
2459 eid_t ast_id{parent_interface_decl->getID()};
2472 diagram().should_include(c->get_namespace())) {
2480 diagram().should_include(e->get_namespace())) {
2489 diagram().for_all_elements([&](
auto &element_view) {
2490 for (
const auto &el : element_view) {
2491 for (
auto &rel : el.get().relationships()) {
2492 if (!rel.destination().is_global()) {
2493 const auto maybe_id =
2496 LOG_TRACE(
"= Resolved instantiation destination "
2498 "id {} to global id {}",
2499 rel.destination(), *maybe_id);
2500 rel.set_destination(*maybe_id);
2504 el.get().remove_duplicate_relationships();
2513 if (
config().skip_redundant_dependencies()) {
2514 diagram().remove_redundant_dependencies();
2519 const clang::ConceptSpecializationExpr *concept_specialization,
2520 const clang::ConceptDecl *cpt,
2521 std::vector<std::string> &constrained_template_params,
2522 size_t argument_index, std::string &type_name)
const
2527 if (!full_declaration_text.empty()) {
2529 if (type_name.find(
"type-parameter-") == 0) {
2530 const auto concept_declaration_text = full_declaration_text.substr(
2531 full_declaration_text.find(cpt->getNameAsString()) +
2532 cpt->getNameAsString().size() + 1);
2535 concept_declaration_text, [](
const auto &t) {
return t; });
2537 if (template_params.size() > argument_index)
2538 type_name = template_params[argument_index].to_string(
2539 config().using_namespace(),
false);
2541 constrained_template_params.push_back(type_name);
2546 std::string qualified_name)
2552 const std::string &qualified_name)
const
2558 std::unique_ptr<common::model::template_element> element)
2560 add_class(util::unique_pointer_cast<class_>(std::move(element)));
2565 if ((
config().generate_packages() &&
2567 assert(!c->file().empty());
2569 const auto file =
config().make_path_relative(c->file());
2575 diagram().add(p, std::move(c));
2577 else if ((
config().generate_packages() &&
2580 const auto module_path =
config().make_module_relative(c->module());
2584 diagram().add(p, std::move(c));
2587 diagram().add(c->path(), std::move(c));
2592 std::unique_ptr<objc_interface> &&c)
2594 if ((
config().generate_packages() &&
2596 assert(!c->file().empty());
2598 const auto file =
config().make_path_relative(c->file());
2604 diagram().add(p, std::move(c));
2607 diagram().add(c->path(), std::move(c));
2613 if ((
config().generate_packages() &&
2615 assert(!e->file().empty());
2617 const auto file =
config().make_path_relative(e->file());
2623 diagram().add(p, std::move(e));
2625 else if ((
config().generate_packages() &&
2628 const auto module_path =
config().make_module_relative(e->module());
2632 diagram().add(p, std::move(e));
2635 diagram().add(e->path(), std::move(e));
2641 if ((
config().generate_packages() &&
2643 assert(!c->file().empty());
2645 const auto file =
config().make_path_relative(c->file());
2651 diagram().add(p, std::move(c));
2653 else if ((
config().generate_packages() &&
2656 const auto module_path =
config().make_module_relative(c->module());
2660 diagram().add(p, std::move(c));
2663 diagram().add(c->path(), std::move(c));
2669 const std::string &full_name,
eid_t templated_decl_id)
2672 template_instantiation_base);
2676 std::string destination{};
2677 std::string best_match_full_name{};
2678 auto full_template_name = template_instantiation.
full_name(
false);
2680 eid_t best_match_id{};
2682 for (
const auto templ :
diagram().classes()) {
2683 if (templ.get() == template_instantiation)
2686 auto c_full_name = templ.get().full_name(
false);
2688 template_instantiation.calculate_template_specialization_match(
2691 if (match > best_match) {
2693 best_match_full_name = c_full_name;
2694 best_match_id = templ.get().id();
2698 auto templated_decl_global_id =
2701 if (best_match_id.value() > 0) {
2702 destination = best_match_full_name;
2703 template_instantiation.add_relationship(
2705 template_instantiation.template_specialization_found(
true);
2709 else if (
diagram().has_element(templated_decl_global_id)) {
2710 template_instantiation.add_relationship(
2712 templated_decl_global_id});
2713 template_instantiation.template_specialization_found(
true);
2715 else if (
id_mapper().get_global_id(templated_decl_id).has_value()) {
2716 template_instantiation.add_relationship(
2718 template_instantiation.template_specialization_found(
true);
2721 LOG_DBG(
"Skipping instantiation relationship from {} to {}",
2722 template_instantiation, templated_decl_global_id);
2725 LOG_DBG(
"== Cannot determine global id for specialization template {} "
2726 "- delaying until the translation unit is complete ",
2727 templated_decl_global_id);
2729 template_instantiation.add_relationship(