24#include "clang/Basic/Module.h"
26#include <spdlog/spdlog.h>
46 assert(ns !=
nullptr);
51 if (ns->isAnonymousNamespace() || ns->isInline())
59 LOG_DBG(
"Visiting namespace declaration: {}", qualified_name);
61 auto package_path = namespace_{qualified_name};
62 auto package_parent = package_path;
65 if (!package_path.is_empty())
66 name = package_path.
name();
68 if (!package_parent.is_empty())
69 package_parent.pop_back();
71 const auto usn =
config().using_namespace();
73 auto p = std::make_unique<common::model::package>(usn);
74 package_path = package_path.relative_to(usn);
77 p->set_namespace(package_parent);
81 assert(p->id().value() > 0);
86 p->set_style(p->style_spec());
88 for (
const auto *attr : ns->attrs()) {
89 if (attr->getKind() == clang::attr::Kind::Deprecated) {
90 p->set_deprecated(
true);
96 LOG_DBG(
"Adding package {}", p->full_name(
false));
98 diagram().add(p->path(), std::move(p));
106 clang::FunctionDecl *function_declaration)
108 assert(function_declaration !=
nullptr);
112 function_declaration->getSourceRange().getBegin()))
119 for (
const auto *param : function_declaration->parameters()) {
120 if (param !=
nullptr)
131 assert(cls !=
nullptr);
134 if (
source_manager().isInSystemHeader(cls->getSourceRange().getBegin()))
138 if (cls->isTemplated() || cls->isTemplateDecl() ||
139 (clang::dyn_cast_or_null<clang::ClassTemplateSpecializationDecl>(cls) !=
145 if (cls->isCompleteDefinition()) {
155 assert(decl !=
nullptr);
158 if (
source_manager().isInSystemHeader(decl->getSourceRange().getBegin()))
163 if (decl->isCompleteDefinition()) {
173 assert(decl !=
nullptr);
176 if (
source_manager().isInSystemHeader(decl->getSourceRange().getBegin()))
181 if (decl->isCompleteDefinition()) {
189 clang::ClassTemplateDecl *decl)
191 assert(decl !=
nullptr);
194 if (
source_manager().isInSystemHeader(decl->getSourceRange().getBegin()))
200 [
this, &relationships, decl](
const auto *template_decl) {
201 if (template_decl->isCompleteDefinition()) {
202 process_class_declaration(*template_decl, relationships);
203 add_relationships(decl, relationships);
210void translation_unit_visitor::add_relationships(
216 auto file = source_manager().getFilename(cls->getLocation()).str();
221 auto relative_file = config().make_path_relative(file);
222 relative_file.make_preferred();
226 parent_path.pop_back();
227 auto pkg_name = parent_path.name();
228 parent_path.pop_back();
230 auto pkg = std::make_unique<common::model::package>(
231 config().using_namespace());
233 pkg->set_name(pkg_name);
234 pkg->set_id(get_package_id(cls));
235 set_source_location(*cls, *pkg);
237 if (diagram().should_include(*pkg))
238 diagram().add(parent_path, std::move(pkg));
241 const auto *module = cls->getOwningModule();
243 if (module ==
nullptr) {
247 std::string module_path_str = module->Name;
248#if LLVM_VERSION_MAJOR < 15
249 if (module->Kind == clang::Module::ModuleKind::PrivateModuleFragment) {
251 if (module->isPrivateModule()) {
253 module_path_str = module->getTopLevelModule()->Name;
258 module_path.pop_back();
260 auto relative_module =
261 config().make_module_relative(std::optional{module_path_str});
265 auto pkg_name = parent_path.name();
266 parent_path.pop_back();
268 auto pkg = std::make_unique<common::model::package>(
271 pkg->set_name(pkg_name);
272 pkg->set_id(get_package_id(cls));
274 pkg->set_module(module_path.to_string());
276 pkg->set_namespace(module_path);
277 set_source_location(*cls, *pkg);
279 if (diagram().should_include(*pkg))
280 diagram().add(parent_path, std::move(pkg));
283 auto current_package_id = get_package_id(cls);
285 if (current_package_id.value() == 0)
290 auto current_package = diagram().get(current_package_id);
292 if (current_package) {
293 std::vector<eid_t> parent_ids =
294 get_parent_package_ids(current_package_id);
296 for (
const auto &dependency : relationships) {
297 const auto destination_id = std::get<0>(dependency);
305 get_parent_package_ids(destination_id), current_package_id))
308 relationship r{relationship_t::kDependency, destination_id,
310 if (destination_id != current_package_id)
311 current_package.value().add_relationship(std::move(r));
316eid_t translation_unit_visitor::get_package_id(
const clang::Decl *cls)
319 const auto *namespace_context =
320 cls->getDeclContext()->getEnclosingNamespaceContext();
321 if (namespace_context !=
nullptr && namespace_context->isNamespace()) {
323 *llvm::cast<clang::NamespaceDecl>(namespace_context));
330 const auto *module = cls->getOwningModule();
331 if (module !=
nullptr) {
332 std::string module_path = module->Name;
333#if LLVM_VERSION_MAJOR < 15
335 clang::Module::ModuleKind::PrivateModuleFragment) {
337 if (module->isPrivateModule()) {
339 module_path = module->getTopLevelModule()->Name;
348 source_manager().getFilename(cls->getSourceRange().getBegin()).str();
349 auto relative_file = config().make_path_relative(file);
350 relative_file.make_preferred();
353 parent_path.pop_back();
358void translation_unit_visitor::process_class_declaration(
362 process_class_children(cls, relationships);
365 process_class_bases(cls, relationships);
368void translation_unit_visitor::process_class_children(
372 for (
const auto *method : cls.methods()) {
373 if (method !=
nullptr) {
374 process_method(*method, relationships);
378 if (
const auto *decl_context =
379 clang::dyn_cast_or_null<clang::DeclContext>(&cls);
380 decl_context !=
nullptr) {
382 for (
auto const *decl_iterator : decl_context->decls()) {
383 auto const *method_template =
384 llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>(
386 if (method_template ==
nullptr)
389 process_template_method(*method_template, relationships);
394 for (
const auto *field : cls.fields()) {
395 if (field !=
nullptr)
396 process_field(*field, relationships);
401 for (
const auto *decl : cls.decls()) {
402 if (decl->getKind() == clang::Decl::Var) {
403 const clang::VarDecl *variable_declaration{
404 clang::dyn_cast_or_null<clang::VarDecl>(decl)};
405 if ((variable_declaration !=
nullptr) &&
406 variable_declaration->isStaticDataMember()) {
407 process_static_field(*variable_declaration, relationships);
412 if (cls.isCompleteDefinition())
413 for (
const auto *friend_declaration : cls.friends()) {
414 if (friend_declaration !=
nullptr)
415 process_friend(*friend_declaration, relationships);
419void translation_unit_visitor::process_class_bases(
422 for (
const auto &base : cls.bases()) {
423 find_relationships(base.getType(), relationships);
427void translation_unit_visitor::process_method(
430 find_relationships(method.getReturnType(), relationships);
432 for (
const auto *param : method.parameters()) {
433 if (param !=
nullptr)
434 find_relationships(param->getType(), relationships);
438void translation_unit_visitor::process_record_children(
441 if (
const auto *decl_context =
442 clang::dyn_cast_or_null<clang::DeclContext>(&cls);
443 decl_context !=
nullptr) {
445 for (
auto const *decl_iterator : decl_context->decls()) {
446 auto const *method_template =
447 llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>(
449 if (method_template ==
nullptr)
452 process_template_method(*method_template, relationships);
457 for (
const auto *field : cls.fields()) {
458 if (field !=
nullptr)
459 process_field(*field, relationships);
464 for (
const auto *decl : cls.decls()) {
465 if (decl->getKind() == clang::Decl::Var) {
466 const clang::VarDecl *variable_declaration{
467 clang::dyn_cast_or_null<clang::VarDecl>(decl)};
468 if ((variable_declaration !=
nullptr) &&
469 variable_declaration->isStaticDataMember()) {
470 process_static_field(*variable_declaration, relationships);
476void translation_unit_visitor::process_template_method(
477 const clang::FunctionTemplateDecl &method,
482 if (method.getTemplatedDecl()->isDefaulted() &&
483 !method.getTemplatedDecl()->isExplicitlyDefaulted())
487 method.getTemplatedDecl()->getReturnType(), relationships);
489 for (
const auto *param : method.getTemplatedDecl()->parameters()) {
490 if (param !=
nullptr) {
491 find_relationships(param->getType(), relationships);
496void translation_unit_visitor::process_field(
497 const clang::FieldDecl &field_declaration,
500 find_relationships(field_declaration.getType(), relationships,
501 relationship_t::kDependency);
504void translation_unit_visitor::process_static_field(
505 const clang::VarDecl &field_declaration,
508 find_relationships(field_declaration.getType(), relationships,
509 relationship_t::kDependency);
512void translation_unit_visitor::process_friend(
513 const clang::FriendDecl &friend_declaration,
516 if (
const auto *friend_type_declaration =
517 friend_declaration.getFriendDecl()) {
518 if (friend_type_declaration->isTemplateDecl()) {
522 else if (
const auto *friend_type = friend_declaration.getFriendType()) {
523 find_relationships(friend_type->getType(), relationships);
527bool translation_unit_visitor::find_relationships(
const clang::QualType &type,
532 if (type->isVoidType() || type->isVoidPointerType()) {
535 else if (type->isPointerType()) {
536 relationship_hint = relationship_t::kAssociation;
538 type->getPointeeType(), relationships, relationship_hint);
540 else if (type->isRValueReferenceType()) {
541 relationship_hint = relationship_t::kAggregation;
543 type.getNonReferenceType(), relationships, relationship_hint);
545 else if (type->isLValueReferenceType()) {
546 relationship_hint = relationship_t::kAssociation;
548 type.getNonReferenceType(), relationships, relationship_hint);
550 else if (type->isArrayType()) {
551 find_relationships(type->getAsArrayTypeUnsafe()->getElementType(),
552 relationships, relationship_t::kAggregation);
554 else if (type->isEnumeralType()) {
555 if (
const auto *enum_type = type->getAs<clang::EnumType>();
556 enum_type !=
nullptr) {
557 if (
const auto *enum_decl = enum_type->getDecl();
558 enum_decl !=
nullptr)
559 relationships.emplace_back(
560 get_package_id(enum_decl), relationship_hint);
563 else if (
const auto *template_specialization_type =
564 type->getAs<clang::TemplateSpecializationType>()) {
565 if (template_specialization_type !=
nullptr) {
567 relationships.emplace_back(
568 get_package_id(template_specialization_type->getTemplateName()
569 .getAsTemplateDecl()),
573 for (
const auto &template_argument :
574 template_specialization_type->template_arguments()) {
575 const auto template_argument_kind = template_argument.getKind();
576 if (template_argument_kind ==
577 clang::TemplateArgument::ArgKind::Integral) {
580 else if (template_argument_kind ==
581 clang::TemplateArgument::ArgKind::Null) {
584 else if (template_argument_kind ==
585 clang::TemplateArgument::ArgKind::Expression) {
588 else if (template_argument.getKind() ==
589 clang::TemplateArgument::ArgKind::NullPtr) {
592 else if (template_argument_kind ==
593 clang::TemplateArgument::ArgKind::Template) {
596 else if (template_argument_kind ==
597 clang::TemplateArgument::ArgKind::TemplateExpansion) {
600 else if (
const auto *function_type =
601 template_argument.getAsType()
602 ->getAs<clang::FunctionProtoType>();
603 function_type !=
nullptr) {
604 for (
const auto ¶m_type :
605 function_type->param_types()) {
606 result = find_relationships(param_type, relationships,
607 relationship_t::kDependency);
610 else if (template_argument_kind ==
611 clang::TemplateArgument::ArgKind::Type) {
612 result = find_relationships(template_argument.getAsType(),
613 relationships, relationship_hint);
618 else if (type->isRecordType()) {
619 if (
const auto *cxxrecord_decl = type->getAsCXXRecordDecl();
620 cxxrecord_decl !=
nullptr) {
622 const auto *namespace_context =
623 cxxrecord_decl->getEnclosingNamespaceContext();
624 if (namespace_context !=
nullptr &&
625 namespace_context->isNamespace()) {
626 const auto *namespace_declaration =
627 clang::cast<clang::NamespaceDecl>(namespace_context);
629 if (namespace_declaration !=
nullptr &&
630 diagram().should_include(
632 *namespace_declaration)})) {
633 const auto target_id = get_package_id(cxxrecord_decl);
634 relationships.emplace_back(
635 target_id, relationship_hint);
640 else if (config().package_type() ==
642 const auto *module = cxxrecord_decl->getOwningModule();
643 if (module !=
nullptr) {
644 const auto target_id = get_package_id(cxxrecord_decl);
645 relationships.emplace_back(target_id, relationship_hint);
650 if (diagram().should_include(
652 *type->getAsCXXRecordDecl())})) {
653 const auto target_id =
654 get_package_id(type->getAsCXXRecordDecl());
655 relationships.emplace_back(target_id, relationship_hint);
660 else if (
const auto *record_decl = type->getAsRecordDecl();
661 record_decl !=
nullptr) {
665 if (diagram().should_include(
667 const auto target_id = get_package_id(record_decl);
668 relationships.emplace_back(target_id, relationship_hint);
678void translation_unit_visitor::finalize() { }
680std::vector<eid_t> translation_unit_visitor::get_parent_package_ids(
eid_t id)
682 std::vector<eid_t> parent_ids;
683 std::optional<eid_t> parent_id = id;
685 while (parent_id.has_value()) {
686 const auto pid = parent_id.
value();
687 parent_ids.push_back(pid);
688 auto parent = this->diagram().get(pid);
690 parent_id = parent.value().parent_element_id();