diff --git a/src/class_diagram/generators/json/class_diagram_generator.cc b/src/class_diagram/generators/json/class_diagram_generator.cc index cde8df31..df4807ce 100644 --- a/src/class_diagram/generators/json/class_diagram_generator.cc +++ b/src/class_diagram/generators/json/class_diagram_generator.cc @@ -158,26 +158,17 @@ void generator::generate_top_level_elements(nlohmann::json &parent) const { for (const auto &p : model()) { if (auto *pkg = dynamic_cast(p.get()); pkg) { - if (!pkg->is_empty() && - !pkg->all_of([this](const common::model::element &e) { - return !model().should_include(e); - })) + if (!pkg->is_empty()) generate(*pkg, parent); } else if (auto *cls = dynamic_cast(p.get()); cls) { - if (model().should_include(*cls)) { - generate(*cls, parent); - } + generate(*cls, parent); } else if (auto *enm = dynamic_cast(p.get()); enm) { - if (model().should_include(*enm)) { - generate(*enm, parent); - } + generate(*enm, parent); } else if (auto *cpt = dynamic_cast(p.get()); cpt) { - if (model().should_include(*cpt)) { - generate(*cpt, parent); - } + generate(*cpt, parent); } } } @@ -203,10 +194,7 @@ void generator::generate(const package &p, nlohmann::json &parent) const for (const auto &subpackage : p) { if (dynamic_cast(subpackage.get()) != nullptr) { const auto &sp = dynamic_cast(*subpackage); - if (!sp.is_empty() && - !sp.all_of([this](const common::model::element &e) { - return !model().should_include(e); - })) { + if (!sp.is_empty()) { if (config().generate_packages()) generate(sp, package_object); else @@ -214,28 +202,22 @@ void generator::generate(const package &p, nlohmann::json &parent) const } } else if (auto *cls = dynamic_cast(subpackage.get()); cls) { - if (model().should_include(*cls)) { - if (config().generate_packages()) - generate(*cls, package_object); - else - generate(*cls, parent); - } + if (config().generate_packages()) + generate(*cls, package_object); + else + generate(*cls, parent); } else if (auto *enm = dynamic_cast(subpackage.get()); enm) { - if (model().should_include(*enm)) { - if (config().generate_packages()) - generate(*enm, package_object); - else - generate(*enm, parent); - } + if (config().generate_packages()) + generate(*enm, package_object); + else + generate(*enm, parent); } else if (auto *cpt = dynamic_cast(subpackage.get()); cpt) { - if (model().should_include(*cpt)) { - if (config().generate_packages()) - generate(*cpt, package_object); - else - generate(*cpt, parent); - } + if (config().generate_packages()) + generate(*cpt, package_object); + else + generate(*cpt, parent); } } @@ -301,19 +283,13 @@ void generator::generate_relationships(nlohmann::json &parent) const generate_relationships(*pkg, parent); } else if (auto *cls = dynamic_cast(p.get()); cls) { - if (model().should_include(*cls)) { - generate_relationships(*cls, parent); - } + generate_relationships(*cls, parent); } else if (auto *enm = dynamic_cast(p.get()); enm) { - if (model().should_include(*enm)) { - generate_relationships(*enm, parent); - } + generate_relationships(*enm, parent); } else if (auto *cpt = dynamic_cast(p.get()); cpt) { - if (model().should_include(*cpt)) { - generate_relationships(*cpt, parent); - } + generate_relationships(*cpt, parent); } } } @@ -322,9 +298,6 @@ void generator::generate_relationships( const class_ &c, nlohmann::json &parent) const { for (const auto &r : c.relationships()) { - if (!model().should_include(r)) - continue; - auto target_element = model().get(r.destination()); if (!target_element.has_value()) { LOG_DBG("Skipping {} relation from {} to {} due " @@ -353,9 +326,6 @@ void generator::generate_relationships( const enum_ &c, nlohmann::json &parent) const { for (const auto &r : c.relationships()) { - if (!model().should_include(r)) - continue; - auto target_element = model().get(r.destination()); if (!target_element.has_value()) { LOG_DBG("Skipping {} relation from {} to {} due " @@ -374,9 +344,6 @@ void generator::generate_relationships( const concept_ &c, nlohmann::json &parent) const { for (const auto &r : c.relationships()) { - if (!model().should_include(r)) - continue; - auto target_element = model().get(r.destination()); if (!target_element.has_value()) { LOG_DBG("Skipping {} relation from {} to {} due " diff --git a/src/class_diagram/generators/mermaid/class_diagram_generator.cc b/src/class_diagram/generators/mermaid/class_diagram_generator.cc index 6a9a9f40..a7a3cd25 100644 --- a/src/class_diagram/generators/mermaid/class_diagram_generator.cc +++ b/src/class_diagram/generators/mermaid/class_diagram_generator.cc @@ -89,9 +89,6 @@ void generator::generate(const class_ &c, std::ostream &ostr) const std::stringstream all_relations_str; for (const auto &r : c.relationships()) { - if (!model().should_include(r.type())) - continue; - try { generate_relationship(r, rendered_relations); } @@ -111,9 +108,6 @@ void generator::generate(const class_ &c, std::ostream &ostr) const sort_class_elements(members); for (const auto &m : members) { - if (!model().should_include(m)) - continue; - if (!config().include_relations_also_as_members() && rendered_relations.find(m.name()) != rendered_relations.end()) continue; @@ -156,11 +150,7 @@ void generator::generate_methods( sort_class_elements(sorted_methods); for (const auto &m : sorted_methods) { - if (!model().should_include(m)) - continue; - generate_method(m, ostr); - ostr << '\n'; } } @@ -170,17 +160,11 @@ generator::method_groups_t generator::group_methods( { std::map> result; - // First get rid of methods which don't pass the filters - std::vector filtered_methods; - std::copy_if(methods.cbegin(), methods.cend(), - std::back_inserter(filtered_methods), - [this](auto &m) { return model().should_include(m); }); - for (const auto &g : method_groups_) { result[g] = {}; } - for (const auto &m : filtered_methods) { + for (const auto &m : methods) { if (m.is_constructor() || m.is_destructor()) { result["constructors"].push_back(m); } @@ -333,19 +317,13 @@ void generator::generate_relationships(std::ostream &ostr) const generate_relationships(*pkg, ostr); } else if (auto *cls = dynamic_cast(p.get()); cls) { - if (model().should_include(*cls)) { - generate_relationships(*cls, ostr); - } + generate_relationships(*cls, ostr); } else if (auto *enm = dynamic_cast(p.get()); enm) { - if (model().should_include(*enm)) { - generate_relationships(*enm, ostr); - } + generate_relationships(*enm, ostr); } else if (auto *cpt = dynamic_cast(p.get()); cpt) { - if (model().should_include(*cpt)) { - generate_relationships(*cpt, ostr); - } + generate_relationships(*cpt, ostr); } } } @@ -401,9 +379,6 @@ void generator::generate_relationships( std::set unique_relations; for (const auto &r : c.relationships()) { - if (!model().should_include(r.type())) - continue; - LOG_DBG("== Processing relationship {}", to_string(r.type())); std::stringstream relstr; @@ -509,9 +484,6 @@ void generator::generate_relationships( std::set unique_relations; for (const auto &r : c.relationships()) { - if (!model().should_include(r.type())) - continue; - LOG_DBG("== Processing relationship {}", to_string(r.type())); std::stringstream relstr; @@ -583,9 +555,6 @@ void generator::generate_relationships( void generator::generate_relationships(const enum_ &e, std::ostream &ostr) const { for (const auto &r : e.relationships()) { - if (!model().should_include(r.type())) - continue; - eid_t destination{}; std::stringstream relstr; try { @@ -718,10 +687,7 @@ void generator::generate_relationships( // packages which do not contain anything but other // packages are skipped const auto &sp = dynamic_cast(*subpackage); - if (!sp.is_empty() && - !sp.all_of([this](const common::model::element &e) { - return !model().should_include(e); - })) + if (!sp.is_empty()) generate_relationships(sp, ostr); } else if (dynamic_cast(subpackage.get()) != nullptr) { @@ -758,52 +724,43 @@ void generator::generate_top_level_elements(std::ostream &ostr) const { for (const auto &p : model()) { if (auto *pkg = dynamic_cast(p.get()); pkg) { - if (!pkg->is_empty() && - !pkg->all_of([this](const common::model::element &e) { - return !model().should_include(e); - })) + if (!pkg->is_empty()) generate(*pkg, ostr); } else if (auto *cls = dynamic_cast(p.get()); cls) { - if (model().should_include(*cls)) { - auto together_group = - config().get_together_group(cls->full_name(false)); - if (together_group) { - together_group_stack_.group_together( - together_group.value(), cls); - } - else { - generate_alias(*cls, ostr); - generate(*cls, ostr); - } + auto together_group = + config().get_together_group(cls->full_name(false)); + if (together_group) { + together_group_stack_.group_together( + together_group.value(), cls); + } + else { + generate_alias(*cls, ostr); + generate(*cls, ostr); } } else if (auto *enm = dynamic_cast(p.get()); enm) { - if (model().should_include(*enm)) { - auto together_group = - config().get_together_group(enm->full_name(false)); - if (together_group) { - together_group_stack_.group_together( - together_group.value(), enm); - } - else { - generate_alias(*enm, ostr); - generate(*enm, ostr); - } + auto together_group = + config().get_together_group(enm->full_name(false)); + if (together_group) { + together_group_stack_.group_together( + together_group.value(), enm); + } + else { + generate_alias(*enm, ostr); + generate(*enm, ostr); } } else if (auto *cpt = dynamic_cast(p.get()); cpt) { - if (model().should_include(*cpt)) { - auto together_group = - config().get_together_group(cpt->full_name(false)); - if (together_group) { - together_group_stack_.group_together( - together_group.value(), cpt); - } - else { - generate_alias(*cpt, ostr); - generate(*cpt, ostr); - } + auto together_group = + config().get_together_group(cpt->full_name(false)); + if (together_group) { + together_group_stack_.group_together( + together_group.value(), cpt); + } + else { + generate_alias(*cpt, ostr); + generate(*cpt, ostr); } } } diff --git a/src/class_diagram/generators/plantuml/class_diagram_generator.cc b/src/class_diagram/generators/plantuml/class_diagram_generator.cc index 8a11ca2e..05b15466 100644 --- a/src/class_diagram/generators/plantuml/class_diagram_generator.cc +++ b/src/class_diagram/generators/plantuml/class_diagram_generator.cc @@ -157,9 +157,6 @@ void generator::generate(const class_ &c, std::ostream &ostr) const std::stringstream all_relations_str; for (const auto &r : c.relationships()) { - if (!model().should_include(r.type())) - continue; - try { generate_relationship(r, rendered_relations); } @@ -182,9 +179,6 @@ void generator::generate(const class_ &c, std::ostream &ostr) const ostr << "__\n"; for (const auto &m : members) { - if (!model().should_include(m)) - continue; - if (!config().include_relations_also_as_members() && rendered_relations.find(m.name()) != rendered_relations.end()) continue; @@ -228,11 +222,7 @@ void generator::generate_methods( sort_class_elements(sorted_methods); for (const auto &m : sorted_methods) { - if (!model().should_include(m)) - continue; - generate_method(m, ostr); - ostr << '\n'; } } @@ -242,17 +232,11 @@ generator::method_groups_t generator::group_methods( { std::map> result; - // First get rid of methods which don't pass the filters - std::vector filtered_methods; - std::copy_if(methods.cbegin(), methods.cend(), - std::back_inserter(filtered_methods), - [this](auto &m) { return model().should_include(m); }); - for (const auto &g : method_groups_) { result[g] = {}; } - for (const auto &m : filtered_methods) { + for (const auto &m : methods) { if (m.is_constructor() || m.is_destructor()) { result["constructors"].push_back(m); } @@ -417,19 +401,13 @@ void generator::generate_relationships(std::ostream &ostr) const generate_relationships(*pkg, ostr); } else if (auto *cls = dynamic_cast(p.get()); cls) { - if (model().should_include(*cls)) { - generate_relationships(*cls, ostr); - } + generate_relationships(*cls, ostr); } else if (auto *enm = dynamic_cast(p.get()); enm) { - if (model().should_include(*enm)) { - generate_relationships(*enm, ostr); - } + generate_relationships(*enm, ostr); } else if (auto *cpt = dynamic_cast(p.get()); cpt) { - if (model().should_include(*cpt)) { - generate_relationships(*cpt, ostr); - } + generate_relationships(*cpt, ostr); } } } @@ -481,9 +459,6 @@ void generator::generate_relationships( std::set unique_relations; for (const auto &r : c.relationships()) { - if (!model().should_include(r.type())) - continue; - LOG_DBG("== Processing relationship {}", plantuml_common::to_plantuml(r, config())); @@ -661,9 +636,6 @@ void generator::generate(const enum_ &e, std::ostream &ostr) const void generator::generate_relationships(const enum_ &e, std::ostream &ostr) const { for (const auto &r : e.relationships()) { - if (!model().should_include(r.type())) - continue; - eid_t destination{}; std::stringstream relstr; try { @@ -724,10 +696,7 @@ void generator::generate(const package &p, std::ostream &ostr) const if (dynamic_cast(subpackage.get()) != nullptr) { // TODO: add option - generate_empty_packages const auto &sp = dynamic_cast(*subpackage); - if (!sp.is_empty() && - !sp.all_of([this](const common::model::element &e) { - return !model().should_include(e); - })) { + if (!sp.is_empty()) { together_group_stack_.enter(); generate(sp, ostr); @@ -822,10 +791,7 @@ void generator::generate_relationships( // packages which do not contain anything but other // packages are skipped const auto &sp = dynamic_cast(*subpackage); - if (!sp.is_empty() && - !sp.all_of([this](const common::model::element &e) { - return !model().should_include(e); - })) + if (!sp.is_empty()) generate_relationships(sp, ostr); } else if (dynamic_cast(subpackage.get()) != nullptr) { @@ -864,52 +830,43 @@ void generator::generate_top_level_elements(std::ostream &ostr) const { for (const auto &p : model()) { if (auto *pkg = dynamic_cast(p.get()); pkg) { - if (!pkg->is_empty() && - !pkg->all_of([this](const common::model::element &e) { - return !model().should_include(e); - })) + if (!pkg->is_empty()) generate(*pkg, ostr); } else if (auto *cls = dynamic_cast(p.get()); cls) { - if (model().should_include(*cls)) { - auto together_group = - config().get_together_group(cls->full_name(false)); - if (together_group) { - together_group_stack_.group_together( - together_group.value(), cls); - } - else { - generate_alias(*cls, ostr); - generate(*cls, ostr); - } + auto together_group = + config().get_together_group(cls->full_name(false)); + if (together_group) { + together_group_stack_.group_together( + together_group.value(), cls); + } + else { + generate_alias(*cls, ostr); + generate(*cls, ostr); } } else if (auto *enm = dynamic_cast(p.get()); enm) { - if (model().should_include(*enm)) { - auto together_group = - config().get_together_group(enm->full_name(false)); - if (together_group) { - together_group_stack_.group_together( - together_group.value(), enm); - } - else { - generate_alias(*enm, ostr); - generate(*enm, ostr); - } + auto together_group = + config().get_together_group(enm->full_name(false)); + if (together_group) { + together_group_stack_.group_together( + together_group.value(), enm); + } + else { + generate_alias(*enm, ostr); + generate(*enm, ostr); } } else if (auto *cpt = dynamic_cast(p.get()); cpt) { - if (model().should_include(*cpt)) { - auto together_group = - config().get_together_group(cpt->full_name(false)); - if (together_group) { - together_group_stack_.group_together( - together_group.value(), cpt); - } - else { - generate_alias(*cpt, ostr); - generate(*cpt, ostr); - } + auto together_group = + config().get_together_group(cpt->full_name(false)); + if (together_group) { + together_group_stack_.group_together( + together_group.value(), cpt); + } + else { + generate_alias(*cpt, ostr); + generate(*cpt, ostr); } } } diff --git a/src/class_diagram/model/class.cc b/src/class_diagram/model/class.cc index 4dc8c0fc..f2d9f876 100644 --- a/src/class_diagram/model/class.cc +++ b/src/class_diagram/model/class.cc @@ -18,6 +18,7 @@ #include "class.h" +#include "common/model/filters/diagram_filter.h" #include "util/util.h" #include @@ -63,6 +64,7 @@ const std::vector &class_::members() const { return members_; } const std::vector &class_::methods() const { return methods_; } const std::vector &class_::parents() const { return bases_; } +std::vector &class_::parents() { return bases_; } bool operator==(const class_ &l, const class_ &r) { return l.id() == r.id(); } @@ -111,6 +113,21 @@ bool class_::is_abstract() const [](const auto &method) { return method.is_pure_virtual(); }); } +void class_::apply_filter( + const common::model::diagram_filter &filter, const std::set &removed) +{ + diagram_element::apply_filter(filter, removed); + + common::model::apply_filter(members_, filter); + common::model::apply_filter(methods_, filter); + + // Remove class bases which are no longer in the diagram + parents().erase( + std::remove_if(parents().begin(), parents().end(), + [&removed](auto &&p) { return removed.count(p.id()) > 0; }), + parents().end()); +} + std::optional class_::doxygen_link() const { const auto *type = is_struct() ? "struct" : "class"; diff --git a/src/class_diagram/model/class.h b/src/class_diagram/model/class.h index 414ec45e..2e248c95 100644 --- a/src/class_diagram/model/class.h +++ b/src/class_diagram/model/class.h @@ -30,6 +30,10 @@ #include #include +namespace clanguml::common::model { +class diagram_filter; +} + namespace clanguml::class_diagram::model { /** @@ -126,6 +130,7 @@ public: * @return Reference to class parents. */ const std::vector &parents() const; + std::vector &parents(); /** * @brief Get class full name. @@ -166,6 +171,9 @@ public: */ std::optional doxygen_link() const override; + void apply_filter(const common::model::diagram_filter &filter, + const std::set &removed) override; + private: bool is_struct_{false}; bool is_union_{false}; diff --git a/src/class_diagram/model/diagram.cc b/src/class_diagram/model/diagram.cc index ab8aa735..779a0fba 100644 --- a/src/class_diagram/model/diagram.cc +++ b/src/class_diagram/model/diagram.cc @@ -256,6 +256,39 @@ void diagram::remove_redundant_dependencies() } } +void diagram::apply_filter() +{ + // First find all element ids which should be removed + std::set to_remove; + + for (const auto &c : element_view::view()) + if (!filter().should_include(c.get())) + to_remove.emplace(c.get().id()); + + for (const auto &e : element_view::view()) + if (!filter().should_include(e.get())) + to_remove.emplace(e.get().id()); + + for (const auto &c : element_view::view()) + if (!filter().should_include(c.get())) + to_remove.emplace(c.get().id()); + + nested_trait_ns::remove(to_remove); + + element_view::remove(to_remove); + element_view::remove(to_remove); + element_view::remove(to_remove); + + for (auto &c : element_view::view()) + c.get().apply_filter(filter(), to_remove); + + for (auto &e : element_view::view()) + e.get().apply_filter(filter(), to_remove); + + for (auto &c : element_view::view()) + c.get().apply_filter(filter(), to_remove); +} + bool diagram::is_empty() const { return element_view::is_empty() && diff --git a/src/class_diagram/model/diagram.h b/src/class_diagram/model/diagram.h index d5402fdb..cc550f07 100644 --- a/src/class_diagram/model/diagram.h +++ b/src/class_diagram/model/diagram.h @@ -256,6 +256,8 @@ public: */ bool is_empty() const override; + void apply_filter() override; + private: template bool add_with_namespace_path(std::unique_ptr &&e); diff --git a/src/common/clang_utils.cc b/src/common/clang_utils.cc index 85fee0aa..6f87c281 100644 --- a/src/common/clang_utils.cc +++ b/src/common/clang_utils.cc @@ -941,12 +941,27 @@ bool parse_source_location(const std::string &location_str, std::string &file, clang::RawComment *get_expression_raw_comment(const clang::SourceManager &sm, const clang::ASTContext &context, const clang::Stmt *stmt) { - // First get the first line of the expression - auto expr_begin = stmt->getSourceRange().getBegin(); + return get_raw_comment(sm, context, stmt->getSourceRange()); +} + +clang::RawComment *get_declaration_raw_comment(const clang::SourceManager &sm, + const clang::ASTContext &context, const clang::Decl *decl) +{ + return get_raw_comment(sm, context, decl->getSourceRange()); +} + +clang::RawComment *get_raw_comment(const clang::SourceManager &sm, + const clang::ASTContext &context, const clang::SourceRange &source_range) +{ + auto expr_begin = source_range.getBegin(); const auto expr_begin_line = sm.getSpellingLineNumber(expr_begin); + std::string file_Path = sm.getFilename(expr_begin).str(); + + auto file_id = sm.getFileID(expr_begin); + if (!context.Comments.empty() && - context.Comments.getCommentsInFile(sm.getFileID(expr_begin)) != nullptr) + context.Comments.getCommentsInFile(file_id) != nullptr) { for (const auto [offset, raw_comment] : *context.Comments.getCommentsInFile(sm.getFileID(expr_begin))) { const auto comment_end_line = sm.getSpellingLineNumber( @@ -956,6 +971,7 @@ clang::RawComment *get_expression_raw_comment(const clang::SourceManager &sm, expr_begin_line == comment_end_line + 1) return raw_comment; } + } return {}; } diff --git a/src/common/clang_utils.h b/src/common/clang_utils.h index b6df132c..8a4cc0b7 100644 --- a/src/common/clang_utils.h +++ b/src/common/clang_utils.h @@ -299,6 +299,12 @@ consume_type_context(clang::QualType type); clang::RawComment *get_expression_raw_comment(const clang::SourceManager &sm, const clang::ASTContext &context, const clang::Stmt *stmt); +clang::RawComment *get_declaration_raw_comment(const clang::SourceManager &sm, + const clang::ASTContext &context, const clang::Decl *decl); + +clang::RawComment *get_raw_comment(const clang::SourceManager &sm, + const clang::ASTContext &context, const clang::SourceRange &source_range); + /** * Check if function or method declaration is a C++20 coroutine. * diff --git a/src/common/model/diagram.cc b/src/common/model/diagram.cc index ab79be7d..9831ec6e 100644 --- a/src/common/model/diagram.cc +++ b/src/common/model/diagram.cc @@ -59,10 +59,18 @@ void diagram::set_complete(bool complete) { complete_ = complete; } bool diagram::complete() const { return complete_; } -void diagram::finalize() { } +void diagram::finalize() +{ + // Remove elements that do not match the filter + apply_filter(); + filtered_ = true; +} bool diagram::should_include(const element &e) const { + if (filtered_) + return true; + if (filter_.get() == nullptr) return true; @@ -77,6 +85,9 @@ bool diagram::should_include(const element &e) const bool diagram::should_include(const namespace_ &ns) const { + if (filtered_) + return true; + if (filter_.get() == nullptr) return true; diff --git a/src/common/model/diagram.h b/src/common/model/diagram.h index 0cd8568f..b1fe4e03 100644 --- a/src/common/model/diagram.h +++ b/src/common/model/diagram.h @@ -171,10 +171,13 @@ public: */ virtual bool is_empty() const = 0; + virtual void apply_filter() { } + private: std::string name_; std::unique_ptr filter_; bool complete_{false}; + bool filtered_{false}; }; template bool check_diagram_type(diagram_t t); diff --git a/src/common/model/diagram_element.cc b/src/common/model/diagram_element.cc index 98824181..b6bb682e 100644 --- a/src/common/model/diagram_element.cc +++ b/src/common/model/diagram_element.cc @@ -18,6 +18,7 @@ #include "diagram_element.h" +#include "common/model/filters/diagram_filter.h" #include "util/util.h" #include @@ -102,6 +103,19 @@ bool diagram_element::complete() const { return complete_; } void diagram_element::complete(bool completed) { complete_ = completed; } +void diagram_element::apply_filter( + const diagram_filter &filter, const std::set &removed) +{ + common::model::apply_filter(relationships(), filter); + + auto &rels = relationships(); + rels.erase(std::remove_if(std::begin(rels), std::end(rels), + [&removed](auto &&r) { + return removed.count(r.destination()) > 0; + }), + std::end(rels)); +} + bool operator==(const diagram_element &l, const diagram_element &r) { return l.id() == r.id(); diff --git a/src/common/model/diagram_element.h b/src/common/model/diagram_element.h index 50b18297..cef1a546 100644 --- a/src/common/model/diagram_element.h +++ b/src/common/model/diagram_element.h @@ -26,11 +26,14 @@ #include #include +#include #include #include namespace clanguml::common::model { +class diagram_filter; + /** * @brief Base class for standalone diagram elements. * @@ -184,6 +187,9 @@ public: */ void complete(bool completed); + virtual void apply_filter( + const diagram_filter &filter, const std::set &removed); + private: eid_t id_{}; std::optional parent_element_id_{}; diff --git a/src/common/model/element_view.h b/src/common/model/element_view.h index bf7da9ea..dd3d14a0 100644 --- a/src/common/model/element_view.h +++ b/src/common/model/element_view.h @@ -78,6 +78,15 @@ public: */ bool is_empty() const { return elements_.empty(); } + void remove(const std::set &element_ids) + { + elements_.erase(std::remove_if(elements_.begin(), elements_.end(), + [&element_ids](auto &&e) { + return element_ids.count(e.get().id()) > 0; + }), + elements_.end()); + } + private: reference_vector elements_; }; diff --git a/src/common/model/filters/diagram_filter.cc b/src/common/model/filters/diagram_filter.cc index a89abd65..c16033f4 100644 --- a/src/common/model/filters/diagram_filter.cc +++ b/src/common/model/filters/diagram_filter.cc @@ -99,6 +99,12 @@ tvl::value_t filter_visitor::match( return {}; } +tvl::value_t filter_visitor::match( + const diagram &d, const common::model::relationship &r) const +{ + return match(d, r.type()); +} + tvl::value_t filter_visitor::match( const diagram & /*d*/, const common::model::relationship_t & /*r*/) const { @@ -997,7 +1003,7 @@ tvl::value_t paths_filter::match( return {}; } - // Matching source paths doesn't make sens if they are not absolute + // Matching source paths doesn't make sense if they are not absolute if (!p.is_absolute()) { return {}; } @@ -1071,7 +1077,7 @@ tvl::value_t class_member_filter::match( } diagram_filter::diagram_filter(const common::model::diagram &d, - const config::diagram &c, private_constructor_tag_t /*unused*/) + const config::diagram & /*c*/, private_constructor_tag_t /*unused*/) : diagram_{d} { } diff --git a/src/common/model/filters/diagram_filter.h b/src/common/model/filters/diagram_filter.h index 60730349..0b7a7792 100644 --- a/src/common/model/filters/diagram_filter.h +++ b/src/common/model/filters/diagram_filter.h @@ -86,6 +86,9 @@ public: virtual tvl::value_t match( const diagram &d, const common::model::element &e) const; + virtual tvl::value_t match( + const diagram &d, const common::model::relationship &r) const; + virtual tvl::value_t match( const diagram &d, const common::model::relationship_t &r) const; @@ -815,15 +818,6 @@ public: friend class diagram_filter_factory; private: - /** - * @brief Initialize filters. - * - * Some filters require initialization. - * - * @param c Diagram config. - */ - // void init_filters(const config::diagram &c); - /*! List of inclusive filters */ std::vector> inclusive_; @@ -834,6 +828,27 @@ private: const common::model::diagram &diagram_; }; +template +void apply_filter(Collection &col, const diagram_filter &filter) +{ + col.erase(std::remove_if(col.begin(), col.end(), + [&filter](auto &&element) { + return !filter.should_include(element); + }), + col.end()); +} + +template +void apply_filter( + std::vector> &col, const diagram_filter &filter) +{ + col.erase(std::remove_if(col.begin(), col.end(), + [&filter](auto &&element) { + return !filter.should_include(element.get()); + }), + col.end()); +} + template <> bool diagram_filter::should_include(const std::string &name) const; } // namespace clanguml::common::model \ No newline at end of file diff --git a/src/common/model/filters/diagram_filter_factory.cc b/src/common/model/filters/diagram_filter_factory.cc index 3988a8cd..d728852a 100644 --- a/src/common/model/filters/diagram_filter_factory.cc +++ b/src/common/model/filters/diagram_filter_factory.cc @@ -253,8 +253,10 @@ template <> void advanced_diagram_filter_initializer::add_filter< source_file_dependency_filter_t>(const filter_t &filter_type, const std::vector &filter_config, - std::vector> &result, relationship_t &&rt, - bool &&direction) + std::vector> &result, + relationship_t &&rt, // NOLINT + bool &&direction // NOLINT +) { std::vector deps; for (auto &&path : filter_config) { diff --git a/src/common/model/filters/diagram_filter_factory.h b/src/common/model/filters/diagram_filter_factory.h index 0fb0576f..8c80e4aa 100644 --- a/src/common/model/filters/diagram_filter_factory.h +++ b/src/common/model/filters/diagram_filter_factory.h @@ -51,6 +51,8 @@ public: { } + virtual ~diagram_filter_initializer() = default; + virtual void initialize() = 0; protected: @@ -62,6 +64,8 @@ class basic_diagram_filter_initializer : public diagram_filter_initializer { public: using diagram_filter_initializer::diagram_filter_initializer; + ~basic_diagram_filter_initializer() override = default; + void initialize() override; }; @@ -69,6 +73,8 @@ class advanced_diagram_filter_initializer : public diagram_filter_initializer { public: using diagram_filter_initializer::diagram_filter_initializer; + ~advanced_diagram_filter_initializer() override = default; + void initialize() override; private: diff --git a/src/common/model/nested_trait.h b/src/common/model/nested_trait.h index 195cc02d..0d3cb06a 100644 --- a/src/common/model/nested_trait.h +++ b/src/common/model/nested_trait.h @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -245,6 +246,23 @@ public: } } + void remove(const std::set &element_ids) + { + // First remove all matching elements on this level + elements_.erase(std::remove_if(elements_.begin(), elements_.end(), + [&element_ids](auto &&e) { + return element_ids.count(e->id()) > 0; + }), + elements_.end()); + + // Now recurse to any packages on this level + for (auto &p : elements_) { + if (dynamic_cast *>(p.get())) + dynamic_cast *>(p.get())->remove( + element_ids); + } + } + private: std::vector> elements_; }; diff --git a/src/common/visitor/translation_unit_visitor.h b/src/common/visitor/translation_unit_visitor.h index f5f88444..8906b281 100644 --- a/src/common/visitor/translation_unit_visitor.h +++ b/src/common/visitor/translation_unit_visitor.h @@ -253,8 +253,12 @@ public: comment_visitor_->visit(decl, e); - const auto *comment = - decl.getASTContext().getRawCommentForDeclNoCache(&decl); + auto *comment = decl.getASTContext().getRawCommentForDeclNoCache(&decl); + + if (comment == nullptr) { + comment = clanguml::common::get_declaration_raw_comment( + source_manager(), decl.getASTContext(), &decl); + } process_comment(comment, decl.getASTContext().getDiagnostics(), e); } diff --git a/src/include_diagram/generators/json/include_diagram_generator.cc b/src/include_diagram/generators/json/include_diagram_generator.cc index 4a2c934c..7c439500 100644 --- a/src/include_diagram/generators/json/include_diagram_generator.cc +++ b/src/include_diagram/generators/json/include_diagram_generator.cc @@ -39,14 +39,11 @@ void generator::generate_relationships( }); } else { - util::for_each_if( - f.relationships(), - [this](const auto &r) { return model().should_include(r.type()); }, - [&f, &parent](const auto &r) { - nlohmann::json rel = r; - rel["source"] = std::to_string(f.id().value()); - parent["relationships"].push_back(std::move(rel)); - }); + for (const auto &r : f.relationships()) { + nlohmann::json rel = r; + rel["source"] = std::to_string(f.id().value()); + parent["relationships"].push_back(std::move(rel)); + } } } @@ -73,17 +70,15 @@ void generator::generate(const source_file &f, nlohmann::json &parent) const parent["elements"].push_back(std::move(j)); } else { - if (model().should_include(f)) { - LOG_DBG("Generating file {}", f.name()); + LOG_DBG("Generating file {}", f.name()); - j["type"] = "file"; - j["file_kind"] = to_string(f.type()); - if (f.type() == common::model::source_file_t::kHeader) { - j["is_system"] = f.is_system_header(); - } - - parent["elements"].push_back(std::move(j)); + j["type"] = "file"; + j["file_kind"] = to_string(f.type()); + if (f.type() == common::model::source_file_t::kHeader) { + j["is_system"] = f.is_system_header(); } + + parent["elements"].push_back(std::move(j)); } } diff --git a/src/include_diagram/generators/mermaid/include_diagram_generator.cc b/src/include_diagram/generators/mermaid/include_diagram_generator.cc index be7188de..6dfda215 100644 --- a/src/include_diagram/generators/mermaid/include_diagram_generator.cc +++ b/src/include_diagram/generators/mermaid/include_diagram_generator.cc @@ -49,21 +49,13 @@ void generator::generate_relationships( }); } else { - util::for_each_if( - f.relationships(), - [this](const auto &r) { - return model().should_include(r.type()) && - util::contains(m_generated_aliases, - model().get(r.destination()).value().alias()); - }, - [&f, &ostr, this](const auto &r) { - ostr << indent(1) << f.alias() << " " - << (r.type() == common::model::relationship_t::kDependency - ? "-.->" - : "-->") - << " " << model().get(r.destination()).value().alias() - << '\n'; - }); + for (const auto &r : f.relationships()) { + ostr << indent(1) << f.alias() << " " + << (r.type() == common::model::relationship_t::kDependency + ? "-.->" + : "-->") + << " " << model().get(r.destination()).value().alias() << '\n'; + } } } @@ -86,11 +78,9 @@ void generator::generate(const source_file &f, std::ostream &ostr) const else { LOG_DBG("Generating file {}", f.name()); - if (model().should_include(f)) { - ostr << indent(1) << f.alias() << "[" << f.name() << "]\n"; + ostr << indent(1) << f.alias() << "[" << f.name() << "]\n"; - m_generated_aliases.emplace(f.alias()); - } + m_generated_aliases.emplace(f.alias()); } if (config().generate_links) { diff --git a/src/include_diagram/generators/plantuml/include_diagram_generator.cc b/src/include_diagram/generators/plantuml/include_diagram_generator.cc index 373607e8..40420b6f 100644 --- a/src/include_diagram/generators/plantuml/include_diagram_generator.cc +++ b/src/include_diagram/generators/plantuml/include_diagram_generator.cc @@ -44,18 +44,11 @@ void generator::generate_relationships( }); } else { - util::for_each_if( - f.relationships(), - [this](const auto &r) { - return model().should_include(r.type()) && - util::contains(m_generated_aliases, - model().get(r.destination()).value().alias()); - }, - [&f, &ostr, this](const auto &r) { - ostr << f.alias() << " " - << plantuml_common::to_plantuml(r, config()) << " " - << model().get(r.destination()).value().alias() << '\n'; - }); + for (const auto &r : f.relationships()) { + ostr << f.alias() << " " + << plantuml_common::to_plantuml(r, config()) << " " + << model().get(r.destination()).value().alias() << '\n'; + } } } @@ -79,17 +72,15 @@ void generator::generate(const source_file &f, std::ostream &ostr) const else { LOG_DBG("Generating file {}", f.name()); - if (model().should_include(f)) { - ostr << "file \"" << f.name() << "\" as " << f.alias(); + ostr << "file \"" << f.name() << "\" as " << f.alias(); - if (config().generate_links) { - generate_link(ostr, f); - } - - ostr << '\n'; - - m_generated_aliases.emplace(f.alias()); + if (config().generate_links) { + generate_link(ostr, f); } + + ostr << '\n'; + + m_generated_aliases.emplace(f.alias()); } } diff --git a/src/include_diagram/model/diagram.cc b/src/include_diagram/model/diagram.cc index 8bce0ae1..564cbabb 100644 --- a/src/include_diagram/model/diagram.cc +++ b/src/include_diagram/model/diagram.cc @@ -18,6 +18,7 @@ #include "diagram.h" +#include "common/model/filters/diagram_filter.h" #include "util/error.h" #include "util/util.h" @@ -53,8 +54,6 @@ void diagram::add_file(std::unique_ptr &&f) assert(!ff.name().empty()); assert(ff.id().value() != 0); - element_view::add(ff); - auto p = ff.path(); if (!f->path().is_empty()) { @@ -86,7 +85,8 @@ void diagram::add_file(std::unique_ptr &&f) assert(p.type() == common::model::path_type::kFilesystem); - add_element(p, std::move(f)); + if (add_element(p, std::move(f))) + element_view::add(ff); } const common::reference_vector & @@ -133,6 +133,25 @@ inja::json diagram::context() const return ctx; } +void diagram::apply_filter() +{ + // First find all element ids which should be removed + std::set to_remove; + + for (auto &f : element_view::view()) + if (f.get().type() != common::model::source_file_t::kDirectory && + !filter().should_include(f.get())) { + to_remove.emplace(f.get().id()); + } + + for (auto &sf : element_view::view()) + sf.get().apply_filter(filter(), to_remove); + + element_view::remove(to_remove); + + nested_trait_fspath::remove(to_remove); +} + bool diagram::is_empty() const { return element_view::is_empty(); } } // namespace clanguml::include_diagram::model diff --git a/src/include_diagram/model/diagram.h b/src/include_diagram/model/diagram.h index 38fe3a9a..4d2fd3f7 100644 --- a/src/include_diagram/model/diagram.h +++ b/src/include_diagram/model/diagram.h @@ -33,13 +33,15 @@ using clanguml::common::opt_ref; using clanguml::common::model::diagram_element; using clanguml::common::model::source_file; +using nested_trait_fspath = clanguml::common::model::nested_trait; + /** * @brief Class representing an include diagram model. */ class diagram : public clanguml::common::model::diagram, public clanguml::common::model::element_view, - public clanguml::common::model::nested_trait { + public nested_trait_fspath { public: diagram() = default; @@ -128,6 +130,8 @@ public: * @return True, if diagram is empty */ bool is_empty() const override; + + void apply_filter() override; }; template diff --git a/src/package_diagram/generators/json/package_diagram_generator.cc b/src/package_diagram/generators/json/package_diagram_generator.cc index 6cd001e6..ef34efbf 100644 --- a/src/package_diagram/generators/json/package_diagram_generator.cc +++ b/src/package_diagram/generators/json/package_diagram_generator.cc @@ -39,9 +39,7 @@ void generator::generate_relationships( auto destination_package = model().get(r.destination()); - if (!destination_package || - !model().should_include( - dynamic_cast(*destination_package))) + if (!destination_package) continue; rel["source"] = std::to_string(p.id().value()); @@ -88,9 +86,7 @@ void generator::generate(const package &p, nlohmann::json &parent) const for (const auto &subpackage : p) { auto &pkg = dynamic_cast(*subpackage); - if (model().should_include(pkg)) { - generate(pkg, j); - } + generate(pkg, j); } parent["elements"].push_back(std::move(j)); @@ -98,9 +94,7 @@ void generator::generate(const package &p, nlohmann::json &parent) const else { for (const auto &subpackage : p) { auto &pkg = dynamic_cast(*subpackage); - if (model().should_include(pkg)) { - generate(pkg, parent); - } + generate(pkg, parent); } } } @@ -120,15 +114,12 @@ void generator::generate_diagram(nlohmann::json &parent) const for (const auto &p : model()) { auto &pkg = dynamic_cast(*p); - if (model().should_include(pkg)) { - generate(pkg, parent); - } + generate(pkg, parent); } // Process package relationships for (const auto &p : model()) { - if (model().should_include(dynamic_cast(*p))) - generate_relationships(dynamic_cast(*p), parent); + generate_relationships(dynamic_cast(*p), parent); } } diff --git a/src/package_diagram/generators/mermaid/package_diagram_generator.cc b/src/package_diagram/generators/mermaid/package_diagram_generator.cc index e2beff79..a9e0424f 100644 --- a/src/package_diagram/generators/mermaid/package_diagram_generator.cc +++ b/src/package_diagram/generators/mermaid/package_diagram_generator.cc @@ -47,9 +47,7 @@ void generator::generate_relationships( try { auto destination_package = model().get(r.destination()); - if (!destination_package || - !model().should_include( - dynamic_cast(*destination_package))) + if (!destination_package) continue; auto destination_alias = model().to_alias(r.destination()); @@ -94,16 +92,12 @@ void generator::generate(const package &p, std::ostream &ostr) const for (const auto &subpackage : p) { auto &pkg = dynamic_cast(*subpackage); - if (model().should_include(pkg)) { - auto together_group = - config().get_together_group(pkg.full_name(false)); - if (together_group) { - together_group_stack_.group_together( - together_group.value(), &pkg); - } - else { - generate(pkg, ostr); - } + auto together_group = config().get_together_group(pkg.full_name(false)); + if (together_group) { + together_group_stack_.group_together(together_group.value(), &pkg); + } + else { + generate(pkg, ostr); } } @@ -159,16 +153,12 @@ void generator::generate_diagram(std::ostream &ostr) const { for (const auto &p : model()) { auto &pkg = dynamic_cast(*p); - if (model().should_include(pkg)) { - auto together_group = - config().get_together_group(pkg.full_name(false)); - if (together_group) { - together_group_stack_.group_together( - together_group.value(), &pkg); - } - else { - generate(pkg, ostr); - } + auto together_group = config().get_together_group(pkg.full_name(false)); + if (together_group) { + together_group_stack_.group_together(together_group.value(), &pkg); + } + else { + generate(pkg, ostr); } } @@ -176,8 +166,7 @@ void generator::generate_diagram(std::ostream &ostr) const // Process package relationships for (const auto &p : model()) { - if (model().should_include(dynamic_cast(*p))) - generate_relationships(dynamic_cast(*p), ostr); + generate_relationships(dynamic_cast(*p), ostr); } } diff --git a/src/package_diagram/generators/plantuml/package_diagram_generator.cc b/src/package_diagram/generators/plantuml/package_diagram_generator.cc index 935b567b..8a0dd969 100644 --- a/src/package_diagram/generators/plantuml/package_diagram_generator.cc +++ b/src/package_diagram/generators/plantuml/package_diagram_generator.cc @@ -39,10 +39,7 @@ void generator::generate_relationships( std::stringstream relstr; try { auto destination_package = model().get(r.destination()); - - if (!destination_package || - !model().should_include( - dynamic_cast(*destination_package))) + if (!destination_package) continue; auto destination_alias = model().to_alias(r.destination()); @@ -62,9 +59,8 @@ void generator::generate_relationships( // Process it's subpackages relationships for (const auto &subpackage : p) { - if (model().should_include(dynamic_cast(*subpackage))) - generate_relationships( - dynamic_cast(*subpackage), ostr); + generate_relationships( + dynamic_cast(*subpackage), ostr); } } @@ -96,16 +92,12 @@ void generator::generate(const package &p, std::ostream &ostr) const for (const auto &subpackage : p) { auto &pkg = dynamic_cast(*subpackage); - if (model().should_include(pkg)) { - auto together_group = - config().get_together_group(pkg.full_name(false)); - if (together_group) { - together_group_stack_.group_together( - together_group.value(), &pkg); - } - else { - generate(pkg, ostr); - } + auto together_group = config().get_together_group(pkg.full_name(false)); + if (together_group) { + together_group_stack_.group_together(together_group.value(), &pkg); + } + else { + generate(pkg, ostr); } } @@ -138,16 +130,12 @@ void generator::generate_diagram(std::ostream &ostr) const { for (const auto &p : model()) { auto &pkg = dynamic_cast(*p); - if (model().should_include(pkg)) { - auto together_group = - config().get_together_group(pkg.full_name(false)); - if (together_group) { - together_group_stack_.group_together( - together_group.value(), &pkg); - } - else { - generate(pkg, ostr); - } + auto together_group = config().get_together_group(pkg.full_name(false)); + if (together_group) { + together_group_stack_.group_together(together_group.value(), &pkg); + } + else { + generate(pkg, ostr); } } @@ -155,8 +143,7 @@ void generator::generate_diagram(std::ostream &ostr) const // Process package relationships for (const auto &p : model()) { - if (model().should_include(dynamic_cast(*p))) - generate_relationships(dynamic_cast(*p), ostr); + generate_relationships(dynamic_cast(*p), ostr); } generate_config_layout_hints(ostr); diff --git a/src/package_diagram/model/diagram.cc b/src/package_diagram/model/diagram.cc index b1ad3d18..67161539 100644 --- a/src/package_diagram/model/diagram.cc +++ b/src/package_diagram/model/diagram.cc @@ -18,6 +18,7 @@ #include "diagram.h" +#include "common/model/filters/diagram_filter.h" #include "util/error.h" #include "util/util.h" @@ -74,6 +75,23 @@ inja::json diagram::context() const return ctx; } +void diagram::apply_filter() +{ + // First find all element ids which should be removed + std::set to_remove; + + for (const auto &c : packages()) + if (!filter().should_include(c.get())) + to_remove.emplace(c.get().id()); + + nested_trait_ns::remove(to_remove); + + element_view::remove(to_remove); + + for (auto &c : element_view::view()) + c.get().apply_filter(filter(), to_remove); +} + bool diagram::is_empty() const { return element_view::is_empty(); } } // namespace clanguml::package_diagram::model diff --git a/src/package_diagram/model/diagram.h b/src/package_diagram/model/diagram.h index a06bdb28..ada50a25 100644 --- a/src/package_diagram/model/diagram.h +++ b/src/package_diagram/model/diagram.h @@ -32,14 +32,16 @@ using clanguml::common::model::diagram_element; using clanguml::common::model::package; using clanguml::common::model::path; +using nested_trait_ns = + clanguml::common::model::nested_trait; + /** * @brief Package diagram model. */ class diagram : public clanguml::common::model::diagram, public clanguml::common::model::element_view, - public clanguml::common::model::nested_trait< - clanguml::common::model::element, - clanguml::common::model::namespace_> { + public nested_trait_ns { public: diagram() = default; @@ -165,6 +167,8 @@ public: */ bool is_empty() const override; + void apply_filter() override; + private: /** * @brief Add element using module as diagram path