diff --git a/src/class_diagram/visitor/translation_unit_visitor.cc b/src/class_diagram/visitor/translation_unit_visitor.cc index 0b6e329f..198f4b97 100644 --- a/src/class_diagram/visitor/translation_unit_visitor.cc +++ b/src/class_diagram/visitor/translation_unit_visitor.cc @@ -137,11 +137,9 @@ bool translation_unit_visitor::VisitEnumDecl(clang::EnumDecl *enm) } } - if (id_opt) { + if (id_opt && diagram_.get_class(*id_opt)) { auto parent_class = diagram_.get_class(*id_opt); - assert(parent_class); - e.set_namespace(ns); e.set_name(parent_class.value().name() + "##" + enm->getNameAsString()); e.set_id(common::to_id(e.full_name(false))); @@ -696,6 +694,7 @@ bool translation_unit_visitor::VisitCXXRecordDecl(clang::CXXRecordDecl *cls) LOG_DBG("== isTemplateDecl() = {}", cls->isTemplateDecl()); LOG_DBG("== isTemplated() = {}", cls->isTemplated()); LOG_DBG("== getParent()->isRecord()() = {}", cls->getParent()->isRecord()); + if (const auto *parent_record = clang::dyn_cast(cls->getParent()); parent_record != nullptr) { @@ -799,7 +798,18 @@ std::unique_ptr translation_unit_visitor::create_record_declaration( process_record_parent(rec, record, namespace_{}); if (!record.is_nested()) { - record.set_name(common::get_tag_name(*rec)); + auto record_name = rec->getQualifiedNameAsString(); + +#if LLVM_VERSION_MAJOR < 16 + if (record_name == "(anonymous)") { + util::apply_if_not_null(rec->getTypedefNameForAnonDecl(), + [&record_name](const clang::TypedefNameDecl *name) { + record_name = name->getNameAsString(); + }); + } +#endif + + record.set_name(record_name); record.set_id(common::to_id(record.full_name(false))); } @@ -886,14 +896,12 @@ void translation_unit_visitor::process_record_parent( } } - if (id_opt) { + if (id_opt && diagram_.get_class(*id_opt)) { // Here we have 2 options, either: // - the parent is a regular C++ class/struct // - the parent is a class template declaration/specialization auto parent_class = diagram_.get_class(*id_opt); - assert(parent_class); - c.set_namespace(parent_ns); const auto cls_name = cls->getNameAsString(); if (cls_name.empty()) { diff --git a/src/common/clang_utils.cc b/src/common/clang_utils.cc index fc9f2855..8c6ab799 100644 --- a/src/common/clang_utils.cc +++ b/src/common/clang_utils.cc @@ -84,6 +84,7 @@ model::namespace_ get_template_namespace(const clang::TemplateDecl &declaration) std::string get_tag_name(const clang::TagDecl &declaration) { auto base_name = declaration.getNameAsString(); + if (base_name.empty()) { base_name = fmt::format("(anonymous_{})", std::to_string(declaration.getID())); diff --git a/tests/t00057/t00057.c b/tests/t00057/t00057.c index 2c025cd4..c63c0eec 100644 --- a/tests/t00057/t00057.c +++ b/tests/t00057/t00057.c @@ -29,6 +29,10 @@ struct t00057_E { } height; }; +typedef struct { + int g1; +} t00057_G; + struct t00057_R { struct t00057_A a; t00057_B b; @@ -36,4 +40,5 @@ struct t00057_R { union t00057_D d; struct t00057_E *e; struct t00057_F *f; + struct t00057_G *g; }; diff --git a/tests/t00057/test_case.h b/tests/t00057/test_case.h index 9f01a0f7..26eb1d5d 100644 --- a/tests/t00057/test_case.h +++ b/tests/t00057/test_case.h @@ -41,6 +41,8 @@ TEST_CASE("t00057", "[test-case][class]") REQUIRE_THAT(puml, IsUnion(_A("t00057_D"))); REQUIRE_THAT(puml, IsClass(_A("t00057_E"))); REQUIRE_THAT(puml, IsClass(_A("t00057_F"))); + REQUIRE_THAT(puml, IsClass(_A("t00057_G"))); + REQUIRE_THAT(puml, !IsClass(_A("(anonymous)"))); REQUIRE_THAT(puml, IsClass(_A("t00057_R"))); // Check if all relationships exist @@ -70,6 +72,8 @@ TEST_CASE("t00057", "[test-case][class]") REQUIRE(get_element(j, "t00057_C").value()["type"] == "class"); REQUIRE(get_element(j, "t00057_D").value()["type"] == "class"); REQUIRE(get_element(j, "t00057_E").value()["type"] == "class"); + REQUIRE(get_element(j, "t00057_F").value()["type"] == "class"); + REQUIRE(get_element(j, "t00057_G").value()["type"] == "class"); REQUIRE(get_element(j, "t00057_R").value()["type"] == "class"); save_json(config.output_directory() + "/" + diagram->name + ".json", j);