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(),
129 assert(enm !=
nullptr);
133 if (enm->getNameAsString().empty()) {
140 LOG_DBG(
"= Visiting enum declaration {} at {}",
141 enm->getQualifiedNameAsString(),
152std::unique_ptr<clanguml::class_diagram::model::enum_>
154 const clang::EnumDecl *enm,
const clang::TypedefDecl *typedef_decl)
156 auto e_ptr = std::make_unique<enum_>(
config().using_namespace());
162 std::optional<eid_t> parent_id_opt;
163 [[maybe_unused]] namespace_ parent_ns;
166 std::string enm_name;
167 if (enm->getNameAsString().empty() && typedef_decl !=
nullptr)
168 enm_name = typedef_decl->getNameAsString();
169 else if (parent_id_opt)
170 enm_name = enm->getNameAsString();
174 if (parent_id_opt &&
diagram().find<class_>(*parent_id_opt)) {
178 e.set_name(parent_class.value().name(), enm_name);
180 e.add_relationship({relationship_t::kContainment, *parent_id_opt});
183 else if (parent_id_opt &&
diagram().find<objc_interface>(*parent_id_opt)) {
187 e.set_name(parent_class.value().name(), enm_name);
189 e.add_relationship({relationship_t::kContainment, *parent_id_opt});
193 e.set_name(enm_name);
207 e.set_style(e.style_spec());
209 for (
const auto &ev : enm->enumerators()) {
210 e.constants().push_back(ev->getNameAsString());
217 clang::ClassTemplateSpecializationDecl *cls)
222 LOG_DBG(
"= Visiting template specialization declaration {} at {} "
223 "(described class id {})",
224 cls->getQualifiedNameAsString(),
226 cls->getSpecializedTemplate()
227 ? cls->getSpecializedTemplate()->getTemplatedDecl()->getID()
231 if (cls->isLocalClass() !=
nullptr)
236 if (!template_specialization_ptr)
239 auto &template_specialization = *template_specialization_ptr;
241 if (cls->hasDefinition()) {
249 if (!template_specialization.template_specialization_found()) {
252 const eid_t ast_id{cls->getSpecializedTemplate()->getID()};
254 if (maybe_id.has_value())
255 template_specialization.add_relationship(
256 {relationship_t::kInstantiation, maybe_id.value()});
260 const auto full_name = template_specialization.full_name(
false);
261 const auto id = template_specialization.id();
263 LOG_DBG(
"Adding class template specialization {} with id {}", full_name,
265 add_class(std::move(template_specialization_ptr));
272 clang::TypeAliasTemplateDecl *cls)
277 LOG_DBG(
"= Visiting template type alias declaration {} at {}",
278 cls->getQualifiedNameAsString(),
281 const auto *template_type_specialization_ptr =
282 cls->getTemplatedDecl()
283 ->getUnderlyingType()
284 ->getAs<clang::TemplateSpecializationType>();
286 if (template_type_specialization_ptr ==
nullptr)
289 auto template_specialization_ptr =
290 std::make_unique<class_>(
config().using_namespace());
292 *template_specialization_ptr, cls, *template_type_specialization_ptr);
294 template_specialization_ptr->is_template(
true);
297 const auto name = template_specialization_ptr->full_name(
true);
298 const auto id = template_specialization_ptr->id();
300 LOG_DBG(
"Adding class {} with id {}", name,
id);
305 add_class(std::move(template_specialization_ptr));
312 clang::ClassTemplateDecl *cls)
317 LOG_DBG(
"= Visiting class template declaration {} at {}",
318 cls->getQualifiedNameAsString(),
332 const auto cls_full_name = c_ptr->full_name(
false);
336 c_ptr->is_template(
true);
340 constexpr auto kMaxConstraintCount = 24U;
341 llvm::SmallVector<const clang::Expr *, kMaxConstraintCount> constraints{};
342 if (cls->hasAssociatedConstraints()) {
343 cls->getAssociatedConstraints(constraints);
346 for (
const auto *expr : constraints) {
350 if (!cls->getTemplatedDecl()->isCompleteDefinition()) {
358 const auto name = c_ptr->full_name(
true);
359 LOG_DBG(
"Adding class template {} with id {}", name,
id);
369 if (clang::dyn_cast_or_null<clang::CXXRecordDecl>(rec) !=
nullptr)
377 LOG_DBG(
"= Visiting record declaration {} at {}",
378 rec->getQualifiedNameAsString(),
386 const auto rec_id = record_ptr->id();
390 auto &record_model =
diagram().find<
class_>(rec_id).has_value()
394 if (rec->isCompleteDefinition() && !record_model.complete()) {
396 record_model.complete(
true);
399 auto id = record_model.id();
400 if (!rec->isCompleteDefinition()) {
407 LOG_DBG(
"Adding struct/union {} with id {}",
408 record_model.full_name(
false), record_model.id());
413 LOG_DBG(
"Skipping struct/union {} with id {}",
414 record_model.full_name(
true), record_model.id());
421 clang::ObjCCategoryDecl *decl)
426 LOG_DBG(
"= Visiting ObjC category declaration {} at {}",
427 decl->getQualifiedNameAsString(),
435 const auto category_id = category_ptr->id();
439 auto &category_model =
447 LOG_DBG(
"Adding ObjC category {} with id {}",
448 category_model.full_name(
false), category_model.id());
453 LOG_DBG(
"Skipping ObjC category {} with id {}",
454 category_model.full_name(
true), category_model.id());
461 clang::ObjCProtocolDecl *decl)
466 LOG_DBG(
"= Visiting ObjC protocol declaration {} at {}",
467 decl->getQualifiedNameAsString(),
475 const auto protocol_id = protocol_ptr->id();
479 auto &protocol_model =
487 LOG_DBG(
"Adding ObjC protocol {} with id {}",
488 protocol_model.full_name(
false), protocol_model.id());
493 LOG_DBG(
"Skipping ObjC protocol {} with id {}",
494 protocol_model.full_name(
true), protocol_model.id());
501 clang::ObjCInterfaceDecl *decl)
506 LOG_DBG(
"= Visiting ObjC interface declaration {} at {}",
507 decl->getQualifiedNameAsString(),
515 const auto protocol_id = interface_ptr->id();
519 auto &interface_model =
524 if (!interface_model.complete())
528 LOG_DBG(
"Adding ObjC interface {} with id {}",
529 interface_model.full_name(
false), interface_model.id());
534 LOG_DBG(
"Skipping ObjC interface {} with id {}",
535 interface_model.full_name(
true), interface_model.id());
546 LOG_DBG(
"= Visiting concept (isType: {}) declaration {} at {}",
547 cpt->isTypeConcept(), cpt->getQualifiedNameAsString(),
555 const auto concept_id = concept_model->id();
561 constexpr auto kMaxConstraintCount = 24U;
562 llvm::SmallVector<const clang::Expr *, kMaxConstraintCount> constraints{};
563 if (cpt->hasAssociatedConstraints()) {
564 cpt->getAssociatedConstraints(constraints);
567 for (
const auto *expr : constraints) {
571 if (cpt->getConstraintExpr() !=
nullptr) {
573 cpt, cpt->getConstraintExpr(), *concept_model);
576 *concept_model, cpt->getConstraintExpr());
580 LOG_DBG(
"Adding concept {} with id {}", concept_model->full_name(
false),
581 concept_model->id());
586 LOG_DBG(
"Skipping concept {} with id {}",
587 concept_model->full_name(
true), concept_model->id());
594 const clang::ConceptDecl *cpt,
const clang::Expr *expr,
597 if (
const auto *constraint = llvm::dyn_cast<clang::RequiresExpr>(expr);
602 LOG_DBG(
"== Processing constraint: '{}'", constraint_source);
604 for ([[maybe_unused]]
const auto *requirement :
605 constraint->getRequirements()) {
610 for (
const auto *decl : constraint->getBody()->decls()) {
611 if (
const auto *parm_var_decl =
612 llvm::dyn_cast<clang::ParmVarDecl>(decl);
614 parm_var_decl->getQualifiedNameAsString();
616 auto param_name = parm_var_decl->getNameAsString();
618 parm_var_decl->getType(), cpt->getASTContext());
620 LOG_DBG(
"=== Processing parameter variable declaration: {}, {}",
621 param_type, param_name);
624 {std::move(param_type), std::move(param_name)});
627 LOG_DBG(
"=== Processing some other concept declaration: {}",
633 for (
const auto *req : constraint->getRequirements()) {
634 if (req->getKind() == clang::concepts::Requirement::RK_Simple) {
635 const auto *simple_req =
636 llvm::dyn_cast<clang::concepts::ExprRequirement>(req);
638 if (simple_req !=
nullptr) {
640 simple_req->getExpr(), [&concept_model](
const auto *e) {
641 auto simple_expr = common::to_string(e);
643 LOG_DBG(
"=== Processing expression requirement: {}",
646 concept_model.add_statement(std::move(simple_expr));
650 else if (req->getKind() == clang::concepts::Requirement::RK_Type) {
652 llvm::dyn_cast<clang::concepts::TypeRequirement>(req),
653 [&concept_model, cpt](
const auto *t) {
655 t->getType()->getType(), cpt->getASTContext());
658 "=== Processing type requirement: {}", type_name);
663 else if (req->getKind() ==
664 clang::concepts::Requirement::RK_Nested) {
665 const auto *nested_req =
666 llvm::dyn_cast<clang::concepts::NestedRequirement>(req);
668 if (nested_req !=
nullptr) {
670 nested_req->getConstraintExpr(), [](
const auto *e) {
671 LOG_DBG(
"=== Processing nested requirement: {}",
672 common::to_string(e));
676 else if (req->getKind() ==
677 clang::concepts::Requirement::RK_Compound) {
678 const auto *compound_req =
679 llvm::dyn_cast<clang::concepts::ExprRequirement>(req);
681 if (compound_req !=
nullptr) {
682 const auto *compound_expr_ptr = compound_req->getExpr();
684 if (compound_expr_ptr !=
nullptr) {
688 auto req_return_type =
689 compound_req->getReturnTypeRequirement();
691 if (!req_return_type.isEmpty()) {
693 fmt::format(
"{{{}}} -> {}", compound_expr,
695 req_return_type.getTypeConstraint()));
697 else if (compound_req->hasNoexceptRequirement()) {
699 fmt::format(
"{{{}}} noexcept", compound_expr);
702 LOG_DBG(
"=== Processing compound requirement: {}",
711 else if (
const auto *binop = llvm::dyn_cast<clang::BinaryOperator>(expr);
716 else if (
const auto *unop = llvm::dyn_cast<clang::UnaryOperator>(expr);
727 found_relationships_t relationships;
729 common::if_dyn_cast<clang::UnresolvedLookupExpr>(
730 expr, [&](
const clang::UnresolvedLookupExpr *ul) {
731 for (
const auto ta : ul->template_arguments()) {
732 if (ta.getArgument().getKind() !=
733 clang::TemplateArgument::ArgKind::Type)
736 relationships, relationship_t::kConstraint);
740 common::if_dyn_cast<clang::ConceptSpecializationExpr>(
741 expr, [&](
const auto *cs) {
745 common::if_dyn_cast<clang::RequiresExpr>(expr, [&](
const auto *re) {
749 common::if_dyn_cast<clang::BinaryOperator>(expr, [&](
const auto *op) {
754 common::if_dyn_cast<clang::UnaryOperator>(expr, [&](
const auto *op) {
758 for (
const auto &[type_element_id, relationship_type, source_decl] :
760 if (type_element_id != c.
id() &&
761 (relationship_type != relationship_t::kNone)) {
765 if (source_decl !=
nullptr) {
776 const clang::ConceptSpecializationExpr *concept_specialization)
779 if (
const auto *cpt = concept_specialization->getNamedConcept();
782 const auto cpt_name = cpt->getNameAsString();
783 const eid_t ast_id{cpt->getID()};
788 const auto target_id = maybe_id.value();
790 std::vector<std::string> constrained_template_params;
792 size_t argument_index{};
794 for (
const auto ta : concept_specialization->getTemplateArguments()) {
795 if (ta.getKind() == clang::TemplateArgument::Type) {
799 cpt, constrained_template_params, argument_index,
802 else if (ta.getKind() == clang::TemplateArgument::Pack) {
803 if (!ta.getPackAsArray().empty() &&
804 ta.getPackAsArray().front().isPackExpansion()) {
805 const auto &pack_head =
806 ta.getPackAsArray().front().getAsType();
810 concept_specialization, cpt,
811 constrained_template_params, argument_index, type_name);
815 LOG_DBG(
"Unsupported concept type parameter in concept: {}",
821 if (!constrained_template_params.empty())
823 {relationship_t::kConstraint, target_id, access_t::kNone,
825 "{}", fmt::join(constrained_template_params,
","))});
834 LOG_DBG(
"= Visiting class declaration {} at {}",
835 cls->getQualifiedNameAsString(),
839 "== getQualifiedNameAsString() = {}", cls->getQualifiedNameAsString());
840 if (cls->getOwningModule() !=
nullptr)
842 "== getOwningModule()->Name = {}", cls->getOwningModule()->Name);
843 LOG_DBG(
"== getID() = {}", cls->getID());
844 LOG_DBG(
"== isTemplateDecl() = {}", cls->isTemplateDecl());
845 LOG_DBG(
"== isTemplated() = {}", cls->isTemplated());
846 LOG_DBG(
"== getParent()->isRecord()() = {}", cls->getParent()->isRecord());
848 if (
const auto *parent_record =
849 clang::dyn_cast<clang::RecordDecl>(cls->getParent());
850 parent_record !=
nullptr) {
851 LOG_DBG(
"== getParent()->getQualifiedNameAsString() = {}",
852 parent_record->getQualifiedNameAsString());
860 if (cls->isTemplated() && (cls->getDescribedTemplate() !=
nullptr)) {
863 const eid_t ast_id{cls->getDescribedTemplate()->getID()};
869 if (cls->isLocalClass() !=
nullptr)
877 const auto cls_id = c_ptr->id();
881 auto &class_model =
diagram().find<
class_>(cls_id).has_value()
885 if (cls->isCompleteDefinition() && !class_model.complete())
888 auto id = class_model.id();
889 if (!cls->isCompleteDefinition()) {
896 LOG_DBG(
"Adding class {} with id {}", class_model, class_model.id());
901 LOG_DBG(
"Skipping class {} with id {}", class_model, class_model.id());
907std::unique_ptr<clanguml::class_diagram::model::concept_>
910 assert(cpt !=
nullptr);
916 std::make_unique<model::concept_>(
config().using_namespace())};
917 auto &concept_model = *concept_ptr;
921 concept_model.set_name(cpt->getNameAsString());
922 concept_model.set_namespace(ns);
923 concept_model.set_id(
common::to_id(concept_model.full_name(
false)));
929 if (concept_model.skip())
932 concept_model.set_style(concept_model.style_spec());
938 clang::RecordDecl *rec)
940 assert(rec !=
nullptr);
945 auto record_ptr{std::make_unique<class_>(
config().using_namespace())};
946 auto &record = *record_ptr;
950 if (!record.is_nested()) {
951 auto record_name = rec->getQualifiedNameAsString();
953#if LLVM_VERSION_MAJOR < 16
954 if (record_name ==
"(anonymous)") {
956 [&record_name](
const clang::TypedefNameDecl *name) {
957 record_name = name->getNameAsString();
962 record.set_name(record_name);
970 const auto record_full_name = record_ptr->full_name(
false);
972 record.is_struct(rec->isStruct());
973 record.is_union(rec->isUnion());
978 record.set_style(record.style_spec());
984 clang::CXXRecordDecl *cls)
986 assert(cls !=
nullptr);
991 auto c_ptr{std::make_unique<class_>(
config().using_namespace())};
998 if (!c.is_nested()) {
1000 c.set_namespace(ns);
1004 c.is_struct(cls->isStruct());
1013 c.set_style(c.style_spec());
1018std::unique_ptr<clanguml::class_diagram::model::objc_interface>
1020 clang::ObjCCategoryDecl *decl)
1022 assert(decl !=
nullptr);
1027 auto c_ptr{std::make_unique<class_diagram::model::objc_interface>(
1028 config().using_namespace())};
1031 decl->getClassInterface()->getNameAsString();
1032 c.set_name(fmt::format(
"{}({})",
1033 decl->getClassInterface()->getNameAsString(), decl->getNameAsString()));
1034 c.set_id(
common::to_id(fmt::format(
"__objc__category__{}", c.name())));
1035 c.is_category(
true);
1043 c.set_style(c.style_spec());
1048std::unique_ptr<clanguml::class_diagram::model::objc_interface>
1050 clang::ObjCProtocolDecl *decl)
1052 assert(decl !=
nullptr);
1057 auto c_ptr{std::make_unique<class_diagram::model::objc_interface>(
1058 config().using_namespace())};
1061 c.set_name(decl->getNameAsString());
1063 c.is_protocol(
true);
1071 c.set_style(c.style_spec());
1076std::unique_ptr<clanguml::class_diagram::model::objc_interface>
1078 clang::ObjCInterfaceDecl *decl)
1080 assert(decl !=
nullptr);
1085 auto c_ptr{std::make_unique<class_diagram::model::objc_interface>(
1086 config().using_namespace())};
1089 c.set_name(decl->getNameAsString());
1098 c.set_style(c.style_spec());
1104 clang::RecordDecl *cls,
class_ &c,
const namespace_ &ns)
1106 std::optional<eid_t> id_opt;
1107 namespace_ parent_ns = ns;
1111 if (id_opt &&
diagram().find<class_>(*id_opt)) {
1112 process_record_parent_by_type<class_>(*id_opt, c, parent_ns, cls);
1115 if (id_opt &&
diagram().find<objc_interface>(*id_opt)) {
1116 process_record_parent_by_type<objc_interface>(
1117 *id_opt, c, parent_ns, cls);
1122 const clang::CXXRecordDecl &cls,
class_ &c)
1139 for (
const auto *method : cls.methods()) {
1140 if (method !=
nullptr) {
1147 if (cls.getClassInterface() !=
nullptr) {
1150 relationship_t::kInstantiation, objc_interface_id, access_t::kNone};
1152 LOG_DBG(
"Found protocol {} [{}] for ObjC interface {}",
1153 cls.getClassInterface()->getNameAsString(),
1168 for (
const auto *method : cls.methods()) {
1169 if (method !=
nullptr) {
1183 for (
const auto *method : cls.methods()) {
1184 if (method !=
nullptr) {
1189 for (
const auto *ivar : cls.ivars()) {
1190 if (ivar !=
nullptr) {
1202 if (
const auto *base = cls.getSuperClass(); base !=
nullptr) {
1206 LOG_DBG(
"Found base class {} [{}] for ObjC interface {}",
1207 base->getNameAsString(), parent_id.
value(), c.
name());
1212 for (
const auto *protocol : cls.protocols()) {
1215 relationship_t::kInstantiation, parent_id, access_t::kNone};
1217 LOG_DBG(
"Found protocol {} [{}] for ObjC interface {}",
1218 protocol->getNameAsString(), parent_id.
value(), c.
name());
1227 LOG_DBG(
"== Visiting ObjC ivar {}", ivar.getNameAsString());
1230 auto relationship_hint = relationship_t::kAggregation;
1232 auto field_type = ivar.getType();
1233 auto field_type_str =
1238 const auto field_name = ivar.getNameAsString();
1242 field_name, field_type_str};
1244 field.set_qualified_name(ivar.getQualifiedNameAsString());
1252 if (field_type->isObjCObjectPointerType()) {
1253 relationship_hint = relationship_t::kAggregation;
1254 field_type = field_type->getPointeeType();
1256 else if (field_type->isPointerType()) {
1257 relationship_hint = relationship_t::kAssociation;
1258 field_type = field_type->getPointeeType();
1260 else if (field_type->isLValueReferenceType()) {
1261 relationship_hint = relationship_t::kAssociation;
1262 field_type = field_type.getNonReferenceType();
1264 else if (field_type->isArrayType()) {
1265 relationship_hint = relationship_t::kAggregation;
1266 while (field_type->isArrayType()) {
1267 auto current_multiplicity = field.destination_multiplicity();
1268 if (!current_multiplicity)
1270 *field_type->getAsArrayTypeUnsafe()));
1272 auto maybe_array_size =
1274 if (maybe_array_size.has_value()) {
1275 field.set_destination_multiplicity(
1276 current_multiplicity.value() *
1277 maybe_array_size.value());
1281 field_type = field_type->getAsArrayTypeUnsafe()->getElementType();
1284 else if (field_type->isRValueReferenceType()) {
1285 field_type = field_type.getNonReferenceType();
1288 found_relationships_t relationships;
1290 if (!field.skip_relationship()) {
1293 if (field_type->getAsObjCInterfaceType() !=
nullptr &&
1294 field_type->getAsObjCInterfaceType()->getInterface() !=
nullptr) {
1295 const auto *objc_iface =
1296 field_type->getAsObjCInterfaceType()->getInterface();
1299 relationship_t::kAggregation, &ivar);
1301 else if ((field_type->getAsRecordDecl() !=
nullptr) &&
1302 field_type->getAsRecordDecl()->getNameAsString().empty()) {
1307 std::make_tuple(field.name(), relationship_hint, field.access(),
1308 field.destination_multiplicity());
1312 &ivar, field_type, relationships, relationship_hint);
1319 if ((field_type->getAsRecordDecl() !=
nullptr) &&
1320 field_type->getAsRecordDecl()->getNameAsString().empty()) {
1322 std::regex anonymous_re(
"anonymous_(\\d*)");
1324 std::regex_replace(field.type(), anonymous_re, field_name));
1332 const clang::CXXRecordDecl *cls,
class_ &c)
1334 for (
const auto &base : cls->bases()) {
1336 if (
const auto *tsp =
1337 base.getType()->getAs<clang::TemplateSpecializationType>();
1339 auto template_specialization_ptr =
1340 std::make_unique<class_>(
config().using_namespace());
1342 *template_specialization_ptr, cls, *tsp, {});
1344 parent_id = template_specialization_ptr->id();
1347 add_class(std::move(template_specialization_ptr));
1350 else if (
const auto *record_type =
1351 base.getType()->getAs<clang::RecordType>();
1352 record_type !=
nullptr) {
1363 LOG_DBG(
"Found base class {} [{}] for class {}",
1372 const clang::RecordDecl *cls,
class_ &c)
1375 for (
const auto *field : cls->fields()) {
1376 if (field !=
nullptr)
1382 const clang::CXXRecordDecl *cls,
class_ &c)
1384 assert(cls !=
nullptr);
1387 for (
const auto *method : cls->methods()) {
1388 if (method !=
nullptr) {
1394 if (
const auto *cls_decl_context =
1395 clang::dyn_cast_or_null<clang::DeclContext>(cls);
1396 cls_decl_context !=
nullptr) {
1397 for (
auto const *decl_iterator : cls_decl_context->decls()) {
1398 auto const *method_template =
1399 llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>(
1401 if (method_template ==
nullptr)
1409 for (
const auto *field : cls->fields()) {
1410 if (field !=
nullptr)
1416 std::set<const clang::EnumDecl *> typedeffed_enums;
1417 for (
const auto *decl : cls->decls()) {
1418 if (decl->getKind() == clang::Decl::Typedef) {
1420 clang::dyn_cast<clang::TypedefDecl>(decl));
1421 if (typedeffed_enum !=
nullptr)
1422 typedeffed_enums.emplace(typedeffed_enum);
1428 for (
const auto *decl : cls->decls()) {
1429 if (decl->getKind() == clang::Decl::Var) {
1430 const clang::VarDecl *variable_declaration{
1431 clang::dyn_cast_or_null<clang::VarDecl>(decl)};
1432 if ((variable_declaration !=
nullptr) &&
1433 variable_declaration->isStaticDataMember()) {
1437 else if (decl->getKind() == clang::Decl::Enum &&
1438 typedeffed_enums.count(
1439 clang::dyn_cast_or_null<clang::EnumDecl>(decl)) == 0) {
1440 const auto *enum_decl =
1441 clang::dyn_cast_or_null<clang::EnumDecl>(decl);
1442 if (enum_decl ==
nullptr)
1445 if (enum_decl->getNameAsString().empty()) {
1446 for (
const auto *enum_const : enum_decl->enumerators()) {
1448 enum_decl->getAccess()),
1449 enum_const->getNameAsString(),
"enum"};
1456 if (cls->isCompleteDefinition())
1457 for (
const auto *friend_declaration : cls->friends()) {
1458 if (friend_declaration !=
nullptr)
1464 const clang::FriendDecl &f,
class_ &c)
1466 if (
const auto *friend_type_info = f.getFriendType()) {
1467 const auto friend_type = friend_type_info->getType();
1468 if (friend_type->getAs<clang::TemplateSpecializationType>() !=
1472 else if (friend_type->getAs<clang::RecordType>() !=
nullptr) {
1486 const clang::CXXMethodDecl &mf,
class_ &c)
1490 if (mf.isDefaulted() && !mf.isExplicitlyDefaulted())
1493 auto method_return_type =
1498 auto method_name = mf.getNameAsString();
1499 if (mf.isTemplated()) {
1503 method_name = method_name.substr(0, method_name.find(
'<'));
1508 config().simplify_template_type(method_return_type)};
1510 method.set_qualified_name(mf.getQualifiedNameAsString());
1522 for (
const auto *param : mf.parameters()) {
1523 if (param !=
nullptr)
1528 found_relationships_t relationships;
1531 if (
const auto *templ = mf.getReturnType()
1532 .getNonReferenceType()
1533 .getUnqualifiedType()
1534 ->getAs<clang::TemplateSpecializationType>();
1536 const auto *unaliased_type = templ;
1537 if (unaliased_type->isTypeAlias())
1538 unaliased_type = unaliased_type->getAliasedType()
1539 ->getAs<clang::TemplateSpecializationType>();
1541 if (unaliased_type !=
nullptr) {
1542 auto template_specialization_ptr =
1543 std::make_unique<class_>(
config().using_namespace());
1545 *template_specialization_ptr,
1546 unaliased_type->getTemplateName().getAsTemplateDecl(),
1547 *unaliased_type, &c);
1549 template_specialization_ptr->is_template();
1552 relationships.emplace_back(template_specialization_ptr->id(),
1553 relationship_t::kDependency, &mf);
1555 add_class(std::move(template_specialization_ptr));
1561 &mf, mf.getReturnType(), relationships, relationship_t::kDependency);
1563 for (
const auto &[type_element_id, relationship_type, source_decl] :
1565 if (type_element_id != c.
id() &&
1566 (relationship_type != relationship_t::kNone)) {
1567 relationship r{relationship_t::kDependency, type_element_id};
1569 if (source_decl !=
nullptr) {
1573 LOG_DBG(
"Adding method return type relationship from {}::{} to "
1575 c, mf.getNameAsString(), r.type(), r.label());
1584 auto underlying_type = mf.getReturnType();
1585 if (underlying_type->isReferenceType())
1586 underlying_type = underlying_type.getNonReferenceType();
1587 if (underlying_type->isPointerType())
1588 underlying_type = underlying_type->getPointeeType();
1590 if (
const auto *atsp = underlying_type->getAs<clang::AutoType>();
1595 method.update(
config().using_namespace());
1598 LOG_DBG(
"Adding method: {}", method.name());
1607 auto method_return_type =
1611 util::trim(mf.getNameAsString()), method_return_type};
1613 method.set_qualified_name(mf.getQualifiedNameAsString());
1623 method.is_static(mf.isClassMethod());
1624 method.is_optional(mf.isOptional());
1626 for (
const auto *param : mf.parameters()) {
1627 if (param !=
nullptr)
1632 found_relationships_t relationships;
1635 &mf, mf.getReturnType(), relationships, relationship_t::kDependency);
1637 for (
const auto &[type_element_id, relationship_type, source_decl] :
1639 if (type_element_id != c.
id() &&
1640 (relationship_type != relationship_t::kNone)) {
1641 relationship r{relationship_t::kDependency, type_element_id};
1643 if (source_decl !=
nullptr) {
1647 LOG_DBG(
"Adding method return type relationship from {}::{} to "
1649 c, mf.getNameAsString(), r.type(), r.label());
1657 LOG_DBG(
"Adding ObjC method: {}", method.name());
1664 const clang::CXXMethodDecl &mf,
const class_ &c,
1665 const std::string &method_name,
class_method &method)
const
1667 const bool is_constructor = c.
name() == method_name;
1668 const bool is_destructor = fmt::format(
"~{}", c.
name()) == method_name;
1670#if LLVM_VERSION_MAJOR > 17
1671 method.is_pure_virtual(mf.isPureVirtual());
1673 method.is_pure_virtual(mf.isPure());
1675 method.is_virtual(mf.isVirtual());
1676 method.is_const(mf.isConst());
1677 method.is_defaulted(mf.isDefaulted());
1678 method.is_deleted(mf.isDeleted());
1679 method.is_static(mf.isStatic());
1680 method.is_operator(mf.isOverloadedOperator());
1681 method.is_constexpr(mf.isConstexprSpecified() && !is_constructor);
1682 method.is_consteval(mf.isConsteval());
1683 method.is_constructor(is_constructor);
1684 method.is_destructor(is_destructor);
1685 method.is_move_assignment(mf.isMoveAssignmentOperator());
1686 method.is_copy_assignment(mf.isCopyAssignmentOperator());
1687 method.is_noexcept(isNoexceptExceptionSpec(mf.getExceptionSpecType()));
1693 class_ &c,
const clang::AutoType *atsp)
1695 auto desugared_atsp = atsp->getDeducedType();
1697 if (atsp->isSugared()) {
1698 const auto *deduced_type =
1699 atsp->desugar()->getAs<clang::DeducedTemplateSpecializationType>();
1701 if (deduced_type !=
nullptr)
1702 desugared_atsp = deduced_type->getDeducedType();
1705 if (desugared_atsp.isNull())
1708 const auto *deduced_record_type = desugared_atsp->isRecordType()
1709 ? desugared_atsp->getAs<clang::RecordType>()
1712 if (deduced_record_type !=
nullptr) {
1713 if (
auto *deduced_auto_decl =
1714 llvm::dyn_cast_or_null<clang::ClassTemplateSpecializationDecl>(
1715 deduced_record_type->getDecl());
1716 deduced_auto_decl !=
nullptr) {
1718 const auto diagram_class_count_before_visit =
1723 const bool visitor_added_new_template_specialization =
1725 diagram_class_count_before_visit) > 0;
1727 if (visitor_added_new_template_specialization) {
1728 const auto &template_specialization_model =
1733 template_specialization_model.get().id()};
1743 const clang::FunctionTemplateDecl &mf,
class_ &c)
1747 if (mf.getTemplatedDecl()->isDefaulted() &&
1748 !mf.getTemplatedDecl()->isExplicitlyDefaulted())
1751 auto method_name = mf.getNameAsString();
1752 if (mf.isTemplated()) {
1756 method_name =
util::trim(method_name.substr(0, method_name.find(
'<')));
1760 method_name, mf.getTemplatedDecl()->getReturnType().getAsString()};
1763 clang::dyn_cast<clang::CXXMethodDecl>(mf.getTemplatedDecl()),
1764 [&](
const auto *decl) {
1765 process_method_properties(*decl, c, method_name, method);
1775 for (
const auto *param : mf.getTemplatedDecl()->parameters()) {
1776 if (param !=
nullptr)
1780 method.update(
config().using_namespace());
1783 LOG_DBG(
"Adding method: {}", method.name());
1790 const clang::QualType &type, found_relationships_t &relationships,
1795 if (type->isPointerType()) {
1796 relationship_hint = relationship_t::kAssociation;
1798 decl, type->getPointeeType(), relationships, relationship_hint);
1800 else if (type->isRValueReferenceType()) {
1801 relationship_hint = relationship_t::kAggregation;
1803 decl, type.getNonReferenceType(), relationships, relationship_hint);
1805 else if (type->isLValueReferenceType()) {
1806 relationship_hint = relationship_t::kAssociation;
1808 decl, type.getNonReferenceType(), relationships, relationship_hint);
1810 else if (type->isArrayType()) {
1812 relationships, relationship_t::kAggregation);
1814 else if (type->isEnumeralType()) {
1815 if (
const auto *enum_type = type->getAs<clang::EnumType>();
1816 enum_type !=
nullptr) {
1820 relationships.emplace_back(
1821 enum_type->getDecl()->getID(), relationship_hint, decl);
1825 else if (type->isRecordType()) {
1826 const auto *type_instantiation_decl =
1827 type->getAs<clang::TemplateSpecializationType>();
1829 if (type_instantiation_decl !=
nullptr) {
1833 .getAsTemplateDecl())) {
1834 relationships.emplace_back(
1835 type_instantiation_decl->getTemplateName()
1836 .getAsTemplateDecl()
1838 relationship_hint, decl);
1840 for (
const auto &template_argument :
1841 type_instantiation_decl->template_arguments()) {
1842 const auto template_argument_kind = template_argument.getKind();
1843 if (template_argument_kind ==
1844 clang::TemplateArgument::ArgKind::Integral) {
1847 else if (template_argument_kind ==
1848 clang::TemplateArgument::ArgKind::Null) {
1851 else if (template_argument_kind ==
1852 clang::TemplateArgument::ArgKind::Expression) {
1855 else if (template_argument.getKind() ==
1856 clang::TemplateArgument::ArgKind::NullPtr) {
1859 else if (template_argument_kind ==
1860 clang::TemplateArgument::ArgKind::Template) {
1863 else if (template_argument_kind ==
1864 clang::TemplateArgument::ArgKind::TemplateExpansion) {
1867 else if (
const auto *function_type =
1868 template_argument.getAsType()
1869 ->getAs<clang::FunctionProtoType>();
1870 function_type !=
nullptr) {
1871 for (
const auto ¶m_type :
1872 function_type->param_types()) {
1874 relationships, relationship_t::kDependency);
1877 else if (template_argument_kind ==
1878 clang::TemplateArgument::ArgKind::Type) {
1881 relationships, relationship_hint);
1885 else if (type->getAsCXXRecordDecl() !=
nullptr) {
1886 relationships.emplace_back(
1887 type->getAsCXXRecordDecl()->getID(), relationship_hint, decl);
1891 relationships.emplace_back(
1892 type->getAsRecordDecl()->getID(), relationship_hint, decl);
1896 else if (
const auto *template_specialization_type =
1897 type->getAs<clang::TemplateSpecializationType>();
1898 template_specialization_type !=
nullptr) {
1899 if (
should_include(template_specialization_type->getTemplateName()
1900 .getAsTemplateDecl())) {
1901 relationships.emplace_back(
1902 template_specialization_type->getTemplateName()
1903 .getAsTemplateDecl()
1905 relationship_hint, decl);
1907 for (
const auto &template_argument :
1908 template_specialization_type->template_arguments()) {
1909 const auto template_argument_kind = template_argument.getKind();
1910 if (template_argument_kind ==
1911 clang::TemplateArgument::ArgKind::Integral) {
1914 else if (template_argument_kind ==
1915 clang::TemplateArgument::ArgKind::Null) {
1918 else if (template_argument_kind ==
1919 clang::TemplateArgument::ArgKind::Expression) {
1922 else if (template_argument.getKind() ==
1923 clang::TemplateArgument::ArgKind::NullPtr) {
1926 else if (template_argument_kind ==
1927 clang::TemplateArgument::ArgKind::Template) {
1930 else if (template_argument_kind ==
1931 clang::TemplateArgument::ArgKind::TemplateExpansion) {
1934 else if (
const auto *function_type =
1935 template_argument.getAsType()
1936 ->getAs<clang::FunctionProtoType>();
1937 function_type !=
nullptr) {
1938 for (
const auto ¶m_type : function_type->param_types()) {
1940 relationship_t::kDependency);
1943 else if (template_argument_kind ==
1944 clang::TemplateArgument::ArgKind::Type) {
1946 relationships, relationship_hint);
1958 parameter.
set_name(param.getNameAsString());
1962 if (parameter.
skip())
1965 auto parameter_type =
1967 parameter.
set_type(parameter_type);
1971 found_relationships_t relationships;
1973 LOG_DBG(
"Looking for relationships in type: {}",
1977 relationship_t::kDependency);
1979 for (
const auto &[type_element_id, relationship_type, source_decl] :
1981 if (type_element_id != c.
id() &&
1982 (relationship_type != relationship_t::kNone)) {
1983 relationship r{relationship_t::kDependency, type_element_id};
1985 if (source_decl !=
nullptr) {
1989 LOG_DBG(
"Adding ObjC method parameter relationship from {} to "
1991 c, r.type(), r.label());
1998 method.add_parameter(std::move(parameter));
2003 const std::set<std::string> & )
2006 parameter.
set_name(p.getNameAsString());
2010 if (parameter.
skip())
2018 parameter.
set_type(parameter_type);
2020 if (p.hasDefaultArg()) {
2021 const auto *default_arg = p.getDefaultArg();
2022 if (default_arg !=
nullptr) {
2031 found_relationships_t relationships;
2033 LOG_DBG(
"Looking for relationships in type: {}",
2036 if (
const auto *templ =
2038 .getNonReferenceType()
2039 .getUnqualifiedType()
2040 ->getAs<clang::TemplateSpecializationType>();
2042 auto template_specialization_ptr =
2043 std::make_unique<class_>(
config().using_namespace());
2045 *template_specialization_ptr,
2046 templ->getTemplateName().getAsTemplateDecl(), *templ, &c);
2048 template_specialization_ptr->is_template(
true);
2051 relationships.emplace_back(template_specialization_ptr->id(),
2052 relationship_t::kDependency, &p);
2054 add_class(std::move(template_specialization_ptr));
2059 &p, p.getType(), relationships, relationship_t::kDependency);
2061 for (
const auto &[type_element_id, relationship_type, source_decl] :
2063 if (type_element_id != c.
id() &&
2064 (relationship_type != relationship_t::kNone)) {
2065 relationship r{relationship_t::kDependency, type_element_id};
2067 if (source_decl !=
nullptr) {
2071 LOG_DBG(
"Adding function parameter relationship from {} to "
2073 c, r.type(), r.label());
2080 method.add_parameter(std::move(parameter));
2085 const found_relationships_t &relationships,
bool break_on_first_aggregation)
2089 for (
const auto &[target, relationship_type, source_decl] : relationships) {
2090 if (relationship_type != relationship_t::kNone) {
2093 r.set_access(field.
access());
2094 if (source_decl !=
nullptr) {
2097 bool mulitplicity_provided_in_comment{
false};
2098 if (decorator_rtype != relationship_t::kNone) {
2099 r.set_type(decorator_rtype);
2100 auto mult =
util::split(decorator_rmult,
":",
false);
2101 if (mult.size() == 2) {
2102 mulitplicity_provided_in_comment =
true;
2103 r.set_multiplicity_source(mult[0]);
2104 r.set_multiplicity_destination(mult[1]);
2107 if (!mulitplicity_provided_in_comment &&
2109 r.set_multiplicity_destination(
2115 LOG_DBG(
"Adding relationship from {} to {} with label {}", c,
2116 r.destination(), r.type(), r.label());
2120 if (break_on_first_aggregation &&
2121 relationship_type == relationship_t::kAggregation)
2128 const clang::VarDecl &field_declaration,
class_ &c)
2130 const auto field_type = field_declaration.getType();
2133 if (type_name.empty())
2134 type_name =
"<<anonymous>>";
2138 field_declaration.getNameAsString(),
2139 config().simplify_template_type(type_name)};
2141 field.set_qualified_name(field_declaration.getQualifiedNameAsString());
2143 field.is_static(
true);
2151 if (!field.skip_relationship()) {
2152 found_relationships_t relationships;
2156 relationships, relationship_t::kAssociation);
2164std::unique_ptr<class_>
2166 clang::ClassTemplateSpecializationDecl *cls)
2168 auto c_ptr = std::make_unique<class_>(
config().using_namespace());
2171 auto &template_instantiation = *c_ptr;
2172 template_instantiation.is_template(
true);
2175 auto qualified_name = cls->getQualifiedNameAsString();
2179 namespace_ ns{qualified_name};
2181 template_instantiation.set_name(cls->getNameAsString());
2182 template_instantiation.set_namespace(ns);
2184 template_instantiation.is_struct(cls->isStruct());
2188 if (!template_instantiation.is_nested()) {
2190 template_instantiation.set_id(
2198 if (template_instantiation.skip())
2201 id_mapper().
add(cls->getID(), template_instantiation.id());
2207 const clang::FieldDecl &field_declaration,
class_ &c)
2210 "== Visiting record member {}", field_declaration.getNameAsString());
2213 auto relationship_hint = relationship_t::kAggregation;
2217 [[maybe_unused]]
bool template_instantiation_added_as_aggregation{
false};
2219 auto field_type = field_declaration.getType();
2225 const auto field_name = field_declaration.getNameAsString();
2227 auto field_type_str =
2234 field_name,
config().simplify_template_type(field_type_str)};
2236 field.set_qualified_name(field_declaration.getQualifiedNameAsString());
2247 if (field_type->isPointerType()) {
2248 relationship_hint = relationship_t::kAssociation;
2249 field_type = field_type->getPointeeType();
2251 else if (field_type->isLValueReferenceType()) {
2252 relationship_hint = relationship_t::kAssociation;
2253 field_type = field_type.getNonReferenceType();
2255 else if (field_type->isArrayType()) {
2256 relationship_hint = relationship_t::kAggregation;
2257 while (field_type->isArrayType()) {
2258 auto current_multiplicity = field.destination_multiplicity();
2259 if (!current_multiplicity)
2261 *field_type->getAsArrayTypeUnsafe()));
2263 auto maybe_array_size =
2265 if (maybe_array_size.has_value()) {
2266 field.set_destination_multiplicity(
2267 current_multiplicity.value() *
2268 maybe_array_size.value());
2272 field_type = field_type->getAsArrayTypeUnsafe()->getElementType();
2275 else if (field_type->isRValueReferenceType()) {
2276 field_type = field_type.getNonReferenceType();
2279 if (type_name.find(
"std::shared_ptr") == 0)
2280 relationship_hint = relationship_t::kAssociation;
2281 if (type_name.find(
"std::weak_ptr") == 0)
2282 relationship_hint = relationship_t::kAssociation;
2284 found_relationships_t relationships;
2286 const auto *template_field_type =
2287 field_type->getAs<clang::TemplateSpecializationType>();
2289 if (template_field_type !=
nullptr)
2290 if (template_field_type->isTypeAlias())
2291 template_field_type =
2292 template_field_type->getAliasedType()
2293 ->getAs<clang::TemplateSpecializationType>();
2295 bool field_type_is_template_template_parameter{
false};
2296 if (template_field_type !=
nullptr) {
2300 if (class_template_param.name() ==
2301 template_field_type->getTemplateName()
2302 .getAsTemplateDecl()
2303 ->getNameAsString() +
2305 field_type_is_template_template_parameter =
true;
2311 if (template_field_type !=
nullptr &&
2312 !field_type_is_template_template_parameter) {
2314 auto template_specialization_ptr =
2315 std::make_unique<class_>(
config().using_namespace());
2317 *template_specialization_ptr,
2318 field_type->getAs<clang::TemplateSpecializationType>()
2320 .getAsTemplateDecl(),
2321 *template_field_type, {&c});
2322 template_specialization_ptr->is_template(
true);
2324 if (!field.skip_relationship() && template_specialization_ptr) {
2325 const auto &template_specialization = *template_specialization_ptr;
2331 bool add_template_instantiation_to_diagram{
false};
2334 found_relationships_t::value_type r{
2335 template_specialization.id(), relationship_hint,
2336 &field_declaration};
2338 add_template_instantiation_to_diagram =
true;
2342 template_instantiation_added_as_aggregation =
2343 relationship_hint == relationship_t::kAggregation;
2344 relationships.emplace_back(std::move(r));
2349 found_relationships_t nested_relationships;
2350 if (!template_instantiation_added_as_aggregation) {
2351 for (
const auto &template_argument :
2352 template_specialization.template_params()) {
2354 LOG_DBG(
"Looking for nested relationships from {}::{} in "
2355 "template argument {}",
2357 template_argument.to_string(
2358 config().using_namespace(),
false));
2360 template_instantiation_added_as_aggregation =
2361 template_argument.find_nested_relationships(
2362 &field_declaration, nested_relationships,
2364 [&d =
diagram()](
const std::string &full_name) {
2365 if (full_name.empty())
2368 return d.should_include(ns, name);
2380 if (add_template_instantiation_to_diagram)
2381 add_class(std::move(template_specialization_ptr));
2385 if (!field.skip_relationship()) {
2388 if (!template_instantiation_added_as_aggregation) {
2389 if ((field_type->getAsRecordDecl() !=
nullptr) &&
2390 field_type->getAsRecordDecl()->getNameAsString().empty()) {
2395 std::make_tuple(field.name(), relationship_hint,
2396 field.access(), field.destination_multiplicity());
2400 relationships, relationship_hint);
2408 if ((field_type->getAsRecordDecl() !=
nullptr) &&
2409 field_type->getAsRecordDecl()->getNameAsString().empty()) {
2411 std::regex anonymous_re(
"anonymous_(\\d*)");
2413 std::regex_replace(field.type(), anonymous_re, field_name));
2423 std::optional<eid_t> &parent_id_opt, namespace_ &parent_ns)
const
2425 const auto *parent = decl->getParent();
2427 if (parent !=
nullptr) {
2428 if (
const auto *parent_record_decl =
2429 clang::dyn_cast<clang::RecordDecl>(parent);
2430 parent_record_decl !=
nullptr) {
2433 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()};
2471 if (
diagram().should_include(c->get_namespace())) {
2480 diagram().for_all_elements([&](
auto &element_view) {
2481 for (
const auto &el : element_view) {
2482 for (
auto &rel : el.get().relationships()) {
2483 if (!rel.destination().is_global()) {
2484 const auto maybe_id =
2488 "= Resolved instantiation destination from local "
2489 "id {} to global id {}",
2490 rel.destination(), *maybe_id);
2491 rel.set_destination(*maybe_id);
2495 el.get().remove_duplicate_relationships();
2504 if (
config().skip_redundant_dependencies()) {
2505 diagram().remove_redundant_dependencies();
2510 const clang::ConceptSpecializationExpr *concept_specialization,
2511 const clang::ConceptDecl *cpt,
2512 std::vector<std::string> &constrained_template_params,
2513 size_t argument_index, std::string &type_name)
const
2518 if (!full_declaration_text.empty()) {
2520 if (type_name.find(
"type-parameter-") == 0) {
2521 const auto concept_declaration_text = full_declaration_text.substr(
2522 full_declaration_text.find(cpt->getNameAsString()) +
2523 cpt->getNameAsString().size() + 1);
2526 concept_declaration_text, [](
const auto &t) {
return t; });
2528 if (template_params.size() > argument_index)
2529 type_name = template_params[argument_index].to_string(
2530 config().using_namespace(),
false);
2532 constrained_template_params.push_back(type_name);
2537 std::string qualified_name)
2543 const std::string &qualified_name)
const
2549 std::unique_ptr<common::model::template_element> element)
2551 add_class(util::unique_pointer_cast<class_>(std::move(element)));
2558 if ((
config().generate_packages() &&
2560 assert(!c->file().empty());
2562 const auto file =
config().make_path_relative(c->file());
2568 diagram().add(p, std::move(c));
2570 else if ((
config().generate_packages() &&
2573 const auto module_path =
config().make_module_relative(c->module());
2577 diagram().add(p, std::move(c));
2580 diagram().add(c->path(), std::move(c));
2585 std::unique_ptr<objc_interface> &&c)
2589 if ((
config().generate_packages() &&
2591 assert(!c->file().empty());
2593 const auto file =
config().make_path_relative(c->file());
2599 diagram().add(p, std::move(c));
2602 diagram().add(c->path(), std::move(c));
2610 if ((
config().generate_packages() &&
2612 assert(!e->file().empty());
2614 const auto file =
config().make_path_relative(e->file());
2620 diagram().add(p, std::move(e));
2622 else if ((
config().generate_packages() &&
2625 const auto module_path =
config().make_module_relative(e->module());
2629 diagram().add(p, std::move(e));
2632 diagram().add(e->path(), std::move(e));
2640 if ((
config().generate_packages() &&
2642 assert(!c->file().empty());
2644 const auto file =
config().make_path_relative(c->file());
2650 diagram().add(p, std::move(c));
2652 else if ((
config().generate_packages() &&
2655 const auto module_path =
config().make_module_relative(c->module());
2659 diagram().add(p, std::move(c));
2662 diagram().add(c->path(), std::move(c));
2668 const std::string &full_name,
eid_t templated_decl_id)
2671 template_instantiation_base);
2675 std::string destination{};
2676 std::string best_match_full_name{};
2677 auto full_template_name = template_instantiation.
full_name(
false);
2679 eid_t best_match_id{};
2681 for (
const auto templ :
diagram().classes()) {
2682 if (templ.get() == template_instantiation)
2685 auto c_full_name = templ.get().full_name(
false);
2687 template_instantiation.calculate_template_specialization_match(
2690 if (match > best_match) {
2692 best_match_full_name = c_full_name;
2693 best_match_id = templ.get().id();
2697 auto templated_decl_global_id =
2700 if (best_match_id.value() > 0) {
2701 destination = best_match_full_name;
2702 template_instantiation.add_relationship(
2704 template_instantiation.template_specialization_found(
true);
2708 else if (
diagram().has_element(templated_decl_global_id)) {
2709 template_instantiation.add_relationship(
2711 templated_decl_global_id});
2712 template_instantiation.template_specialization_found(
true);
2715 LOG_DBG(
"Skipping instantiation relationship from {} to {}",
2716 template_instantiation, templated_decl_global_id);
2719 LOG_DBG(
"== Cannot determine global id for specialization template {} "
2720 "- delaying until the translation unit is complete ",
2721 templated_decl_global_id);
2723 template_instantiation.add_relationship(