Fixed handling of relationships to nested enums (#280)

This commit is contained in:
Bartek Kryza
2024-06-03 16:59:26 +02:00
parent cbaf5f65a0
commit 2e861ee3de
3 changed files with 42 additions and 18 deletions

View File

@@ -122,7 +122,8 @@ bool translation_unit_visitor::VisitEnumDecl(clang::EnumDecl *enm)
const auto *parent = enm->getParent(); const auto *parent = enm->getParent();
std::optional<common::id_t> id_opt; // Id of parent class or struct in which this enum is potentially nested
std::optional<common::id_t> parent_id_opt;
if (parent != nullptr) { if (parent != nullptr) {
const auto *parent_record_decl = const auto *parent_record_decl =
@@ -133,26 +134,26 @@ bool translation_unit_visitor::VisitEnumDecl(clang::EnumDecl *enm)
// First check if the parent has been added to the diagram as // First check if the parent has been added to the diagram as
// regular class // regular class
id_opt = id_mapper().get_global_id(local_id); parent_id_opt = id_mapper().get_global_id(local_id);
// If not, check if the parent template declaration is in the model // If not, check if the parent template declaration is in the model
if (!id_opt) { if (!parent_id_opt) {
if (parent_record_decl->getDescribedTemplate() != nullptr) { if (parent_record_decl->getDescribedTemplate() != nullptr) {
local_id = local_id =
parent_record_decl->getDescribedTemplate()->getID(); parent_record_decl->getDescribedTemplate()->getID();
id_opt = id_mapper().get_global_id(local_id); parent_id_opt = id_mapper().get_global_id(local_id);
} }
} }
} }
} }
if (id_opt && diagram().find<class_>(*id_opt)) { if (parent_id_opt && diagram().find<class_>(*parent_id_opt)) {
auto parent_class = diagram().find<class_>(*id_opt); auto parent_class = diagram().find<class_>(*parent_id_opt);
e.set_namespace(ns); e.set_namespace(ns);
e.set_name(parent_class.value().name() + "##" + enm->getNameAsString()); e.set_name(parent_class.value().name() + "##" + enm->getNameAsString());
e.set_id(common::to_id(e.full_name(false))); e.set_id(common::to_id(e.full_name(false)));
e.add_relationship({relationship_t::kContainment, *id_opt}); e.add_relationship({relationship_t::kContainment, *parent_id_opt});
e.nested(true); e.nested(true);
} }
else { else {
@@ -1437,8 +1438,11 @@ bool translation_unit_visitor::find_relationships(const clang::QualType &type,
else if (type->isEnumeralType()) { else if (type->isEnumeralType()) {
if (const auto *enum_type = type->getAs<clang::EnumType>(); if (const auto *enum_type = type->getAs<clang::EnumType>();
enum_type != nullptr) { enum_type != nullptr) {
// Use AST's local ID here for relationship target, as we can't
// calculate here properly the ID for nested enums. It will be
// resolved properly in finalize().
relationships.emplace_back( relationships.emplace_back(
common::to_id(*enum_type->getDecl()), relationship_hint); enum_type->getDecl()->getID(), relationship_hint);
} }
} }
else if (type->isRecordType()) { else if (type->isRecordType()) {
@@ -1989,15 +1993,12 @@ void translation_unit_visitor::resolve_local_to_global_ids()
// to elements // to elements
for (const auto &cls : diagram().classes()) { for (const auto &cls : diagram().classes()) {
for (auto &rel : cls.get().relationships()) { for (auto &rel : cls.get().relationships()) {
if (rel.type() == relationship_t::kInstantiation) { const auto maybe_id = id_mapper().get_global_id(rel.destination());
const auto maybe_id = if (maybe_id) {
id_mapper().get_global_id(rel.destination()); LOG_DBG("= Resolved instantiation destination from local "
if (maybe_id) { "id {} to global id {}",
LOG_DBG("= Resolved instantiation destination from local " rel.destination(), *maybe_id);
"id {} to global id {}", rel.set_destination(*maybe_id);
rel.destination(), *maybe_id);
rel.set_destination(*maybe_id);
}
} }
} }
} }
@@ -2012,6 +2013,17 @@ void translation_unit_visitor::resolve_local_to_global_ids()
} }
} }
} }
for (const auto &enm : diagram().enums()) {
for (auto &rel : enm.get().relationships()) {
const auto maybe_id = id_mapper().get_global_id(rel.destination());
if (maybe_id) {
LOG_DBG("= Resolved instantiation destination from local "
"id {} to global id {}",
rel.destination(), *maybe_id);
rel.set_destination(*maybe_id);
}
}
}
} }
void translation_unit_visitor::finalize() void translation_unit_visitor::finalize()

View File

@@ -1,9 +1,14 @@
namespace clanguml { namespace clanguml {
namespace t00004 { namespace t00004 {
enum Color { Red, Green, Blue };
class B { class B {
public: public:
enum AA { AA_1, AA_2, AA_3 }; enum AA { AA_1, AA_2, AA_3 };
AA aa;
Color *color;
}; };
class A { class A {
@@ -14,7 +19,9 @@ public:
public: public:
enum class Lights { Green, Yellow, Red }; enum class Lights { Green, Yellow, Red };
class AAA { }; class AAA {
Lights lights;
};
}; };
void foo2() const { } void foo2() const { }

View File

@@ -53,5 +53,10 @@ TEST_CASE("t00004")
REQUIRE(IsClass(src, {"detail", "D"})); REQUIRE(IsClass(src, {"detail", "D"}));
REQUIRE(IsClass(src, {"detail", "D::DD"})); REQUIRE(IsClass(src, {"detail", "D::DD"}));
REQUIRE(IsEnum(src, {"detail", "D::AA"})); REQUIRE(IsEnum(src, {"detail", "D::AA"}));
REQUIRE(IsAssociation<Public>(src, "B", "Color", "color"));
REQUIRE(IsAggregation<Public>(src, "B", "B::AA", "aa"));
REQUIRE(IsAggregation<Private>(
src, "A::AA::AAA", "A::AA::Lights", "lights"));
}); });
} }