diff --git a/src/config/config.h b/src/config/config.h index 87ca1506..82e0daae 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -39,6 +39,17 @@ struct plantuml { struct filter { std::vector namespaces; + + // Valid values are: + // - inheritance + // - dependency + // - instantiation + std::vector relationships; + + // E.g.: + // - classes + // - enums + std::vector entity_types; }; struct diagram { @@ -53,6 +64,42 @@ struct diagram { plantuml puml; + bool should_include_entities(const std::string &ent) + { + for (const auto &ex : exclude.entity_types) { + if (ent == ex) + return false; + } + + if (include.entity_types.empty()) + return true; + + for (const auto &in : include.entity_types) { + if (ent == in) + return true; + } + + return false; + } + + bool should_include_relationship(const std::string &rel) + { + for (const auto &ex : exclude.relationships) { + if (rel == ex) + return false; + } + + if (include.relationships.empty()) + return true; + + for (const auto &in : include.relationships) { + if (rel == in) + return true; + } + + return false; + } + bool should_include(const std::string &name_) const { auto name = clanguml::util::unqualify(name_); @@ -186,6 +233,15 @@ template <> struct convert { { if (node["namespaces"]) rhs.namespaces = node["namespaces"].as(); + + if (node["relationships"]) + rhs.relationships = + node["relationships"].as(); + + if (node["entity_types"]) + rhs.entity_types = + node["entity_types"].as(); + return true; } }; diff --git a/src/puml/class_diagram_generator.h b/src/puml/class_diagram_generator.h index 79a56f62..94a7fbfb 100644 --- a/src/puml/class_diagram_generator.h +++ b/src/puml/class_diagram_generator.h @@ -101,6 +101,29 @@ public: } } + std::string name(relationship_t r) const + { + switch (r) { + case relationship_t::kOwnership: + case relationship_t::kComposition: + return "composition"; + case relationship_t::kAggregation: + return "aggregation"; + case relationship_t::kContainment: + return "containment"; + case relationship_t::kAssociation: + return "association"; + case relationship_t::kInstantiation: + return "instantiation"; + case relationship_t::kFriendship: + return "friendship"; + case relationship_t::kDependency: + return "dependency"; + default: + return "unknown"; + } + } + void generate_aliases(const class_ &c, std::ostream &ostr) const { std::string class_type{"class"}; @@ -176,16 +199,20 @@ public: ostr << "}" << std::endl; - for (const auto &b : c.bases) { - ostr << m_model.to_alias(m_config.using_namespace, - ns_relative(m_config.using_namespace, b.name)) - << " <|-- " - << m_model.to_alias(m_config.using_namespace, - ns_relative(m_config.using_namespace, c.name)) - << std::endl; - } + if (m_config.should_include_relationship("inheritance")) + for (const auto &b : c.bases) { + ostr << m_model.to_alias(m_config.using_namespace, + ns_relative(m_config.using_namespace, b.name)) + << " <|-- " + << m_model.to_alias(m_config.using_namespace, + ns_relative(m_config.using_namespace, c.name)) + << std::endl; + } for (const auto &r : c.relationships) { + if (!m_config.should_include_relationship(name(r.type))) + continue; + std::string destination; if (r.destination.find("#") != std::string::npos || r.destination.find("@") != std::string::npos) { @@ -226,6 +253,9 @@ public: ostr << "}" << std::endl; for (const auto &r : e.relationships) { + if (!m_config.should_include_relationship(name(r.type))) + continue; + std::string destination; if (r.destination.find("#") != std::string::npos || r.destination.find("@") != std::string::npos) { @@ -260,20 +290,23 @@ public: for (const auto &b : m_config.puml.before) ostr << b << std::endl; - for (const auto &c : m_model.classes) { - generate_aliases(c, ostr); - ostr << std::endl; + if (m_config.should_include_entities("classes")) { + for (const auto &c : m_model.classes) { + generate_aliases(c, ostr); + ostr << std::endl; + } + + for (const auto &c : m_model.classes) { + generate(c, ostr); + ostr << std::endl; + } } - for (const auto &c : m_model.classes) { - generate(c, ostr); - ostr << std::endl; - } - - for (const auto &e : m_model.enums) { - generate(e, ostr); - ostr << std::endl; - } + if (m_config.should_include_entities("enums")) + for (const auto &e : m_model.enums) { + generate(e, ostr); + ostr << std::endl; + } for (const auto &b : m_config.puml.after) ostr << b << std::endl; diff --git a/src/uml/class_diagram_visitor.cc b/src/uml/class_diagram_visitor.cc index 57426648..49774ae0 100644 --- a/src/uml/class_diagram_visitor.cc +++ b/src/uml/class_diagram_visitor.cc @@ -75,13 +75,15 @@ void tu_visitor::operator()(const cppast::cpp_entity &file) cx::util::full_name(e), cppast::to_string(e.kind())); auto &cls = static_cast(e); - auto &clsdef = static_cast( - cppast::get_definition(ctx.entity_index, cls).value()); - if (&cls != &clsdef) { - spdlog::debug( - "Forward declaration of class {} - skipping...", - cls.name()); - return; + if (cppast::get_definition(ctx.entity_index, cls)) { + auto &clsdef = static_cast( + cppast::get_definition(ctx.entity_index, cls).value()); + if (&cls != &clsdef) { + spdlog::debug( + "Forward declaration of class {} - skipping...", + cls.name()); + return; + } } if (ctx.config.should_include(cx::util::fully_prefixed(cls))) process_class_declaration(cls); diff --git a/tests/t00014/t00014.cc b/tests/t00014/t00014.cc index 403cf616..12791b89 100644 --- a/tests/t00014/t00014.cc +++ b/tests/t00014/t00014.cc @@ -18,12 +18,13 @@ template using AString = A; using AIntString = AString; using AStringString = AString; +using BStringString = AStringString; class R { A boolstring; AString floatstring; AIntString intstring; - AStringString stringstring; + BStringString stringstring; }; } }