diff --git a/src/puml/class_diagram_generator.h b/src/puml/class_diagram_generator.h index d853d09e..92dc0f5a 100644 --- a/src/puml/class_diagram_generator.h +++ b/src/puml/class_diagram_generator.h @@ -23,8 +23,8 @@ #include "uml/class_diagram_visitor.h" #include "util/util.h" -#include #include +#include #include #include @@ -87,7 +87,7 @@ public: case relationship_t::kAggregation: return "o--"; case relationship_t::kContainment: - return "+--"; + return "--+"; case relationship_t::kAssociation: return "-->"; case relationship_t::kInstantiation: @@ -224,6 +224,33 @@ public: } ostr << "}" << std::endl; + + for (const auto &r : e.relationships) { + std::string destination; + if (r.destination.find("#") != std::string::npos || + r.destination.find("@") != std::string::npos) { + destination = m_model.usr_to_name( + m_config.using_namespace, r.destination); + if (destination.empty()) { + ostr << "' "; + destination = r.destination; + } + } + else { + destination = r.destination; + } + + ostr << m_model.to_alias(m_config.using_namespace, + ns_relative(m_config.using_namespace, e.name)) + << " " << to_string(r.type) << " " + << m_model.to_alias(m_config.using_namespace, + ns_relative(m_config.using_namespace, destination)); + + if (!r.label.empty()) + ostr << " : " << r.label; + + ostr << std::endl; + } } void generate(std::ostream &ostr) const @@ -287,7 +314,8 @@ clanguml::model::class_diagram::diagram generate( } cppast::cpp_entity_index idx; - cppast::simple_file_parser parser{type_safe::ref(idx)}; + cppast::simple_file_parser parser{ + type_safe::ref(idx)}; // Process all matching translation units clanguml::visitor::class_diagram::tu_visitor ctx(d, diagram); diff --git a/src/uml/class_diagram_model.h b/src/uml/class_diagram_model.h index 52a27e9b..fca6f73d 100644 --- a/src/uml/class_diagram_model.h +++ b/src/uml/class_diagram_model.h @@ -211,6 +211,7 @@ public: struct enum_ : public element { std::vector constants; + std::vector relationships; friend bool operator==(const enum_ &l, const enum_ &r) { diff --git a/src/uml/class_diagram_visitor.cc b/src/uml/class_diagram_visitor.cc index 6d1eb070..499a3330 100644 --- a/src/uml/class_diagram_visitor.cc +++ b/src/uml/class_diagram_visitor.cc @@ -19,11 +19,11 @@ #include #include +#include #include #include #include #include -#include #include namespace clanguml { @@ -71,17 +71,17 @@ void tu_visitor::operator()(const cppast::cpp_entity &file) cppast::visit(file, [&, this](const cppast::cpp_entity &e, cppast::visitor_info info) { if (e.kind() == cppast::cpp_entity_kind::class_t) { - spdlog::debug("{}'{}' - {}", prefix, - cx::util::full_name(e), cppast::to_string(e.kind())); + spdlog::debug("{}'{}' - {}", prefix, cx::util::full_name(e), + cppast::to_string(e.kind())); auto &cls = static_cast(e); if (ctx.config.should_include(cx::util::fully_prefixed(cls))) process_class_declaration(cls); } - else if(e.kind() == cppast::cpp_entity_kind::enum_t) { - spdlog::debug("{}'{}' - {}", prefix, - cx::util::full_name(e), cppast::to_string(e.kind())); + else if (e.kind() == cppast::cpp_entity_kind::enum_t) { + spdlog::debug("{}'{}' - {}", prefix, cx::util::full_name(e), + cppast::to_string(e.kind())); auto &enm = static_cast(e); @@ -91,16 +91,32 @@ void tu_visitor::operator()(const cppast::cpp_entity &file) }); } -void tu_visitor::process_enum_declaration(const cppast::cpp_enum &enm) { +void tu_visitor::process_enum_declaration(const cppast::cpp_enum &enm) +{ enum_ e; e.name = cx::util::full_name(enm); - for(const auto& ev : enm) { - if(ev.kind() == cppast::cpp_entity_kind::enum_value_t) { + for (const auto &ev : enm) { + if (ev.kind() == cppast::cpp_entity_kind::enum_value_t) { e.constants.push_back(ev.name()); } } + // Find if class is contained in another class + for (auto cur = enm.parent(); cur; cur = cur.value().parent()) { + // find nearest parent class, if any + if (cur.value().kind() == cppast::cpp_entity_kind::class_t) { + class_relationship containment; + containment.type = relationship_t::kContainment; + containment.destination = cx::util::full_name(cur.value()); + e.relationships.emplace_back(std::move(containment)); + + spdlog::debug("Added relationship {} +-- {}", e.name, + containment.destination); + break; + } + } + ctx.d.add_enum(std::move(e)); } @@ -199,6 +215,22 @@ void tu_visitor::process_class_declaration(const cppast::cpp_class &cls) } } + // Find if class is contained in another class + for (auto cur = cls.parent(); cur; cur = cur.value().parent()) { + // find nearest parent class, if any + if (cur.value().kind() == cppast::cpp_entity_kind::class_t) { + class_relationship containment; + containment.type = relationship_t::kContainment; + containment.destination = cx::util::full_name(cur.value()); + c.relationships.emplace_back(std::move(containment)); + + spdlog::debug("Added relationship {} +-- {}", + c.full_name(ctx.config.using_namespace), + containment.destination); + break; + } + } + ctx.d.add_class(std::move(c)); } diff --git a/tests/test_cases.h b/tests/test_cases.h index 6931430a..acf87f62 100644 --- a/tests/test_cases.h +++ b/tests/test_cases.h @@ -265,7 +265,7 @@ ContainsMatcher IsInnerClass(std::string const &parent, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes) { return ContainsMatcher( - CasedString(parent + " +-- " + inner, caseSensitivity)); + CasedString(inner + " --+ " + parent, caseSensitivity)); } ContainsMatcher IsAssociation(std::string const &from, std::string const &to,