25#include "clang/Basic/Module.h"
27#include <spdlog/spdlog.h>
47 assert(ns !=
nullptr);
52 if (ns->isAnonymousNamespace() || ns->isInline())
60 LOG_DBG(
"Visiting namespace declaration: {}", qualified_name);
62 auto package_path = namespace_{qualified_name};
63 auto package_parent = package_path;
65 (package_path.size() == 1) && !
config().using_namespace().is_empty();
68 if (!package_path.is_empty())
69 name = package_path.name();
71 if (!package_parent.is_empty())
72 package_parent.pop_back();
74 const auto usn =
config().using_namespace();
76 auto p = std::make_unique<common::model::package>(usn);
77 package_path = package_path.relative_to(usn);
80 p->set_namespace(package_parent);
85 assert(p->id().value() > 0);
90 p->set_style(p->style_spec());
92 for (
const auto *attr : ns->attrs()) {
93 if (attr->getKind() == clang::attr::Kind::Deprecated) {
94 p->set_deprecated(
true);
100 LOG_DBG(
"Adding package {}", p->full_name(
false));
102 diagram().add(p->path(), std::move(p));
110 clang::FunctionDecl *function_declaration)
112 assert(function_declaration !=
nullptr);
116 function_declaration->getSourceRange().getBegin()))
122 function_declaration->getReturnType(), relationships);
124 for (
const auto *param : function_declaration->parameters()) {
125 if (param !=
nullptr)
127 function_declaration, param->getType(), relationships);
137 assert(cls !=
nullptr);
140 if (
source_manager().isInSystemHeader(cls->getSourceRange().getBegin()))
144 if (cls->isTemplated() || cls->isTemplateDecl() ||
145 (clang::dyn_cast_or_null<clang::ClassTemplateSpecializationDecl>(cls) !=
151 if (cls->isCompleteDefinition()) {
161 assert(decl !=
nullptr);
164 if (
source_manager().isInSystemHeader(decl->getSourceRange().getBegin()))
169 if (decl->isCompleteDefinition()) {
179 assert(decl !=
nullptr);
182 if (
source_manager().isInSystemHeader(decl->getSourceRange().getBegin()))
187 if (decl->isCompleteDefinition()) {
195 clang::ClassTemplateDecl *decl)
197 assert(decl !=
nullptr);
200 if (
source_manager().isInSystemHeader(decl->getSourceRange().getBegin()))
206 [
this, &relationships, decl](
const auto *template_decl) {
207 if (template_decl->isCompleteDefinition()) {
208 process_class_declaration(*template_decl, relationships);
209 add_relationships(decl, relationships);
216bool translation_unit_visitor::VisitObjCCategoryDecl(
217 clang::ObjCCategoryDecl *decl)
219 assert(decl !=
nullptr);
222 if (source_manager().isInSystemHeader(decl->getSourceRange().getBegin()))
227 const auto target_id = get_package_id(decl->getClassInterface());
228 relationships.emplace_back(target_id, relationship_t::kDependency, decl);
230 process_objc_container_children(*decl, relationships);
231 add_relationships(decl, relationships);
236bool translation_unit_visitor::VisitObjCProtocolDecl(
237 clang::ObjCProtocolDecl *decl)
239 assert(decl !=
nullptr);
242 if (source_manager().isInSystemHeader(decl->getSourceRange().getBegin()))
247 for (
const auto *protocol : decl->protocols()) {
248 process_interface_protocol(*protocol, relationships);
251 process_objc_container_children(*decl, relationships);
252 add_relationships(decl, relationships);
257bool translation_unit_visitor::VisitObjCInterfaceDecl(
258 clang::ObjCInterfaceDecl *decl)
260 assert(decl !=
nullptr);
263 if (source_manager().isInSystemHeader(decl->getSourceRange().getBegin()))
268 for (
const auto *protocol : decl->protocols()) {
269 process_interface_protocol(*protocol, relationships);
273 for (
const auto *field : decl->ivars()) {
274 if (field !=
nullptr)
275 process_field(*field, relationships);
278 process_objc_container_children(*decl, relationships);
280 add_relationships(decl, relationships);
285void translation_unit_visitor::add_relationships(
291 auto file = source_manager().getFilename(cls->getLocation()).str();
296 auto relative_file = config().make_path_relative(file);
297 relative_file.make_preferred();
301 parent_path.pop_back();
302 auto pkg_name = parent_path.name();
303 parent_path.pop_back();
305 auto pkg = std::make_unique<common::model::package>(
308 pkg->set_name(pkg_name);
309 pkg->set_namespace(parent_path);
311 set_source_location(*cls, *pkg);
313 if (diagram().should_include(*pkg))
314 diagram().add(parent_path, std::move(pkg));
317 const auto *module = cls->getOwningModule();
319 if (module ==
nullptr) {
323 std::string module_path_str = module->Name;
324#if LLVM_VERSION_MAJOR < 15
325 if (module->Kind == clang::Module::ModuleKind::PrivateModuleFragment) {
327 if (module->isPrivateModule()) {
329 module_path_str = module->getTopLevelModule()->Name;
334 module_path.pop_back();
336 auto relative_module =
337 config().make_module_relative(std::optional{module_path_str});
341 auto pkg_name = parent_path.name();
342 parent_path.pop_back();
344 auto pkg = std::make_unique<common::model::package>(
347 pkg->set_name(pkg_name);
348 pkg->set_id(get_package_id(cls));
350 pkg->set_module(module_path.to_string());
352 pkg->set_namespace(module_path);
353 set_source_location(*cls, *pkg);
355 if (diagram().should_include(*pkg))
356 diagram().add(parent_path, std::move(pkg));
359 auto current_package_id = get_package_id(cls);
361 if (current_package_id.value() == 0)
366 auto current_package = diagram().get(current_package_id);
368 if (current_package) {
369 std::vector<eid_t> parent_ids =
370 get_parent_package_ids(current_package_id);
372 for (
auto &dependency : relationships) {
373 const auto destination_id = std::get<0>(dependency);
381 get_parent_package_ids(destination_id), current_package_id))
384 relationship r{relationship_t::kDependency, destination_id,
387 if (std::get<2>(dependency) !=
nullptr)
388 set_source_location(*std::get<2>(dependency), r);
390 if (destination_id != current_package_id)
391 current_package.value().add_relationship(std::move(r));
396eid_t translation_unit_visitor::get_package_id(
const clang::Decl *cls)
399 const auto *namespace_context =
400 cls->getDeclContext()->getEnclosingNamespaceContext();
401 if (namespace_context !=
nullptr && namespace_context->isNamespace()) {
403 *llvm::cast<clang::NamespaceDecl>(namespace_context));
410 const auto *module = cls->getOwningModule();
411 if (module !=
nullptr) {
412 std::string module_path = module->Name;
413#if LLVM_VERSION_MAJOR < 15
415 clang::Module::ModuleKind::PrivateModuleFragment) {
417 if (module->isPrivateModule()) {
419 module_path = module->getTopLevelModule()->Name;
428 source_manager().getFilename(cls->getSourceRange().getBegin()).str();
429 auto relative_file = config().make_path_relative(file);
430 relative_file.make_preferred();
433 parent_path.pop_back();
438void translation_unit_visitor::process_class_declaration(
442 process_class_children(cls, relationships);
445 process_class_bases(cls, relationships);
448void translation_unit_visitor::process_class_children(
452 for (
const auto *method : cls.methods()) {
453 if (method !=
nullptr) {
454 process_method(*method, relationships);
458 if (
const auto *decl_context =
459 clang::dyn_cast_or_null<clang::DeclContext>(&cls);
460 decl_context !=
nullptr) {
462 for (
auto const *decl_iterator : decl_context->decls()) {
463 auto const *method_template =
464 llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>(
466 if (method_template ==
nullptr)
469 process_template_method(*method_template, relationships);
474 for (
const auto *field : cls.fields()) {
475 if (field !=
nullptr)
476 process_field(*field, relationships);
481 for (
const auto *decl : cls.decls()) {
482 if (decl->getKind() == clang::Decl::Var) {
483 const clang::VarDecl *variable_declaration{
484 clang::dyn_cast_or_null<clang::VarDecl>(decl)};
485 if ((variable_declaration !=
nullptr) &&
486 variable_declaration->isStaticDataMember()) {
487 process_static_field(*variable_declaration, relationships);
492 if (cls.isCompleteDefinition())
493 for (
const auto *friend_declaration : cls.friends()) {
494 if (friend_declaration !=
nullptr)
495 process_friend(*friend_declaration, relationships);
499void translation_unit_visitor::process_class_bases(
502 for (
const auto &base : cls.bases()) {
503 find_relationships(&cls, base.getType(), relationships);
507void translation_unit_visitor::process_method(
510 find_relationships(&method, method.getReturnType(), relationships);
512 for (
const auto *param : method.parameters()) {
513 if (param !=
nullptr)
514 find_relationships(&method, param->getType(), relationships);
518void translation_unit_visitor::process_objc_method(
521 find_relationships(&mf, mf.getReturnType(), relationships);
523 for (
const auto *param : mf.parameters()) {
524 if (param !=
nullptr)
525 find_relationships(&mf, param->getType(), relationships);
529void translation_unit_visitor::process_record_children(
532 if (
const auto *decl_context =
533 clang::dyn_cast_or_null<clang::DeclContext>(&cls);
534 decl_context !=
nullptr) {
536 for (
auto const *decl_iterator : decl_context->decls()) {
537 auto const *method_template =
538 llvm::dyn_cast_or_null<clang::FunctionTemplateDecl>(
540 if (method_template ==
nullptr)
543 process_template_method(*method_template, relationships);
548 for (
const auto *field : cls.fields()) {
549 if (field !=
nullptr)
550 process_field(*field, relationships);
555 for (
const auto *decl : cls.decls()) {
556 if (decl->getKind() == clang::Decl::Var) {
557 const clang::VarDecl *variable_declaration{
558 clang::dyn_cast_or_null<clang::VarDecl>(decl)};
559 if ((variable_declaration !=
nullptr) &&
560 variable_declaration->isStaticDataMember()) {
561 process_static_field(*variable_declaration, relationships);
567void translation_unit_visitor::process_objc_container_children(
568 const clang::ObjCContainerDecl &cls,
571 for (
const auto *property : cls.properties()) {
572 if (property !=
nullptr)
573 process_objc_property(*property, relationships);
576 for (
const auto *property : cls.class_properties()) {
577 if (property !=
nullptr)
578 process_objc_property(*property, relationships);
581 for (
const auto *method : cls.methods()) {
582 if (method !=
nullptr)
583 process_objc_method(*method, relationships);
586 for (
const auto *method : cls.class_methods()) {
587 if (method !=
nullptr)
588 process_objc_method(*method, relationships);
593 for (
const auto *decl : cls.decls()) {
594 if (decl->getKind() == clang::Decl::Var) {
595 const clang::VarDecl *variable_declaration{
596 clang::dyn_cast_or_null<clang::VarDecl>(decl)};
597 if ((variable_declaration !=
nullptr) &&
598 variable_declaration->isStaticDataMember()) {
599 process_static_field(*variable_declaration, relationships);
605void translation_unit_visitor::process_template_method(
606 const clang::FunctionTemplateDecl &method,
611 if (method.getTemplatedDecl()->isDefaulted() &&
612 !method.getTemplatedDecl()->isExplicitlyDefaulted())
616 &method, method.getTemplatedDecl()->getReturnType(), relationships);
618 for (
const auto *param : method.getTemplatedDecl()->parameters()) {
619 if (param !=
nullptr) {
620 find_relationships(&method, param->getType(), relationships);
625void translation_unit_visitor::process_field(
626 const clang::FieldDecl &field_declaration,
629 find_relationships(&field_declaration, field_declaration.getType(),
630 relationships, relationship_t::kDependency);
633void translation_unit_visitor::process_interface_protocol(
634 const clang::ObjCProtocolDecl &protocol_declaration,
637 const auto target_id = get_package_id(&protocol_declaration);
638 relationships.emplace_back(
639 target_id, relationship_t::kDependency, &protocol_declaration);
642void translation_unit_visitor::process_objc_property(
643 const clang::ObjCPropertyDecl &property_declaration,
646 const auto *property_objc_id_type =
647 property_declaration.getType()->getAsObjCQualifiedIdType();
648 if (property_objc_id_type !=
nullptr) {
649 const auto protocols_count = property_objc_id_type->getNumProtocols();
650 for (
auto i = 0U; i < protocols_count; i++) {
651 const auto target_id =
652 get_package_id(property_objc_id_type->getProtocol(i));
653 relationships.emplace_back(
654 target_id, relationship_t::kDependency, &property_declaration);
658 find_relationships(&property_declaration, property_declaration.getType(),
659 relationships, relationship_t::kDependency);
662void translation_unit_visitor::process_static_field(
663 const clang::VarDecl &field_declaration,
666 find_relationships(&field_declaration, field_declaration.getType(),
667 relationships, relationship_t::kDependency);
670void translation_unit_visitor::process_friend(
671 const clang::FriendDecl &friend_declaration,
674 if (
const auto *friend_type_declaration =
675 friend_declaration.getFriendDecl()) {
676 if (friend_type_declaration->isTemplateDecl()) {
680 else if (
const auto *friend_type = friend_declaration.getFriendType()) {
682 &friend_declaration, friend_type->getType(), relationships);
686bool translation_unit_visitor::find_relationships(
const clang::Decl *decl,
688 relationship_t relationship_hint)
692 if (type->isVoidType() || type->isVoidPointerType()) {
695 else if (type->isObjCObjectPointerType() &&
696 type->getPointeeType()->getAsObjCInterfaceType() !=
nullptr) {
697 const auto *objc_interface =
698 type->getPointeeType()->getAsObjCInterfaceType()->getInterface();
699 const auto target_id = get_package_id(objc_interface);
700 relationships.emplace_back(target_id, relationship_hint, decl);
703 else if (type->isPointerType()) {
704 relationship_hint = relationship_t::kAssociation;
706 decl, type->getPointeeType(), relationships, relationship_hint);
708 else if (type->isRValueReferenceType()) {
709 relationship_hint = relationship_t::kAggregation;
711 decl, type.getNonReferenceType(), relationships, relationship_hint);
713 else if (type->isLValueReferenceType()) {
714 relationship_hint = relationship_t::kAssociation;
716 decl, type.getNonReferenceType(), relationships, relationship_hint);
718 else if (type->isArrayType()) {
719 find_relationships(decl, type->getAsArrayTypeUnsafe()->getElementType(),
720 relationships, relationship_t::kAggregation);
722 else if (type->isEnumeralType()) {
723 if (
const auto *enum_type = type->getAs<clang::EnumType>();
724 enum_type !=
nullptr) {
725 if (
const auto *enum_decl = enum_type->getDecl();
726 enum_decl !=
nullptr)
727 relationships.emplace_back(
728 get_package_id(enum_decl), relationship_hint, decl);
731 else if (
const auto *template_specialization_type =
732 type->getAs<clang::TemplateSpecializationType>()) {
733 if (template_specialization_type !=
nullptr) {
735 relationships.emplace_back(
736 get_package_id(template_specialization_type->getTemplateName()
737 .getAsTemplateDecl()),
738 relationship_hint, decl);
741 for (
const auto &template_argument :
742 template_specialization_type->template_arguments()) {
743 const auto template_argument_kind = template_argument.getKind();
744 if (template_argument_kind ==
745 clang::TemplateArgument::ArgKind::Integral) {
748 else if (template_argument_kind ==
749 clang::TemplateArgument::ArgKind::Null) {
752 else if (template_argument_kind ==
753 clang::TemplateArgument::ArgKind::Expression) {
756 else if (template_argument.getKind() ==
757 clang::TemplateArgument::ArgKind::NullPtr) {
760 else if (template_argument_kind ==
761 clang::TemplateArgument::ArgKind::Template) {
764 else if (template_argument_kind ==
765 clang::TemplateArgument::ArgKind::TemplateExpansion) {
768 else if (
const auto *function_type =
769 template_argument.getAsType()
770 ->getAs<clang::FunctionProtoType>();
771 function_type !=
nullptr) {
772 for (
const auto ¶m_type :
773 function_type->param_types()) {
774 result = find_relationships(decl, param_type,
775 relationships, relationship_t::kDependency);
778 else if (template_argument_kind ==
779 clang::TemplateArgument::ArgKind::Type) {
781 find_relationships(decl, template_argument.getAsType(),
782 relationships, relationship_hint);
787 else if (type->isRecordType()) {
788 if (
const auto *cxxrecord_decl = type->getAsCXXRecordDecl();
789 cxxrecord_decl !=
nullptr) {
791 const auto *namespace_context =
792 cxxrecord_decl->getEnclosingNamespaceContext();
793 if (namespace_context !=
nullptr &&
794 namespace_context->isNamespace()) {
795 const auto *namespace_declaration =
796 clang::cast<clang::NamespaceDecl>(namespace_context);
798 if (namespace_declaration !=
nullptr &&
799 diagram().should_include(
801 *namespace_declaration)})) {
802 const auto target_id = get_package_id(cxxrecord_decl);
803 relationships.emplace_back(
804 target_id, relationship_hint, decl);
809 else if (config().package_type() ==
811 const auto *module = cxxrecord_decl->getOwningModule();
812 if (module !=
nullptr) {
813 const auto target_id = get_package_id(cxxrecord_decl);
814 relationships.emplace_back(
815 target_id, relationship_hint, decl);
820 if (diagram().should_include(
822 *type->getAsCXXRecordDecl())})) {
823 const auto target_id =
824 get_package_id(type->getAsCXXRecordDecl());
825 relationships.emplace_back(
826 target_id, relationship_hint, decl);
831 else if (
const auto *record_decl = type->getAsRecordDecl();
832 record_decl !=
nullptr) {
836 if (diagram().should_include(
838 const auto target_id = get_package_id(record_decl);
839 relationships.emplace_back(
840 target_id, relationship_hint, decl);
850void translation_unit_visitor::finalize() { }
852std::vector<eid_t> translation_unit_visitor::get_parent_package_ids(
eid_t id)
854 std::vector<eid_t> parent_ids;
855 std::optional<eid_t> parent_id = id;
857 while (parent_id.has_value()) {
858 const auto pid = parent_id.
value();
859 parent_ids.push_back(pid);
860 auto parent = this->diagram().get(pid);
862 parent_id = parent.value().parent_element_id();