From b0501d4bfbba8fdcc1f2674787ad7a09d7b7c2c3 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Thu, 8 Jun 2023 14:08:31 +0200 Subject: [PATCH] Added regex support to specializations filter --- src/common/model/diagram_filter.cc | 22 +++++---- src/common/model/diagram_filter.h | 29 ++++++++---- src/config/config.h | 2 +- tests/test_config_data/filters.yml | 7 ++- tests/test_filters.cc | 74 ++++++++++++++++++++++++++++++ 5 files changed, 114 insertions(+), 20 deletions(-) diff --git a/src/common/model/diagram_filter.cc b/src/common/model/diagram_filter.cc index d1c4da9d..4357751f 100644 --- a/src/common/model/diagram_filter.cc +++ b/src/common/model/diagram_filter.cc @@ -681,8 +681,9 @@ void diagram_filter::init_filters(const config::diagram &c) element_filters.emplace_back(std::make_unique< edge_traversal_filter>(filter_t::kInclusive, - relationship_t::kInstantiation, c.include().specializations)); + class_diagram::model::class_, common::string_or_regex>>( + filter_t::kInclusive, relationship_t::kInstantiation, + c.include().specializations)); element_filters.emplace_back(std::make_unique< edge_traversal_filter>( + element_filters.emplace_back(std::make_unique>( filter_t::kInclusive, relationship_t::kAssociation, dependants)); - element_filters.emplace_back(std::make_unique< - edge_traversal_filter>( + element_filters.emplace_back(std::make_unique>( filter_t::kInclusive, relationship_t::kAssociation, dependencies, true)); } @@ -777,8 +778,9 @@ void diagram_filter::init_filters(const config::diagram &c) add_exclusive_filter(std::make_unique( filter_t::kExclusive, c.exclude().parents)); - add_exclusive_filter(std::make_unique>( + add_exclusive_filter(std::make_unique< + edge_traversal_filter>( filter_t::kExclusive, relationship_t::kInstantiation, c.exclude().specializations)); diff --git a/src/common/model/diagram_filter.h b/src/common/model/diagram_filter.h index 25e2f998..fef070c1 100644 --- a/src/common/model/diagram_filter.h +++ b/src/common/model/diagram_filter.h @@ -184,10 +184,11 @@ private: }; template struct edge_traversal_filter : public filter_visitor { edge_traversal_filter(filter_t type, relationship_t relationship, - std::vector roots, bool forward = false) + std::vector roots, bool forward = false) : filter_visitor{type} , roots_{std::move(roots)} , relationship_{relationship} @@ -199,8 +200,8 @@ struct edge_traversal_filter : public filter_visitor { tvl::value_t match(const diagram &d, const MatchOverrideT &e) const override { - // This filter should only be run on the completely generated diagram - // model by visitor + // This filter should only be run only on diagram models after the + // entire AST has been visited if (!d.complete()) return {}; @@ -285,10 +286,22 @@ private: // First get all elements specified in the filter configuration // which will serve as starting points for the search // of matching elements - for (const auto &template_root : roots_) { - auto template_ref = detail::get(cd, template_root); - if (template_ref.has_value()) { - matching_elements_.emplace(template_ref.value()); + for (const auto &root_pattern : roots_) { + if constexpr (std::is_same_v) { + auto root_refs = cd.template find( + root_pattern); + + for (auto &root : root_refs) { + if (root.has_value()) + matching_elements_.emplace(root.value()); + } + } + else { + auto root_ref = detail::get(cd, root_pattern); + if (root_ref.has_value()) { + matching_elements_.emplace(root_ref.value()); + } } } @@ -318,7 +331,7 @@ private: initialized_ = true; } - std::vector roots_; + std::vector roots_; relationship_t relationship_; mutable bool initialized_{false}; mutable clanguml::common::reference_set matching_elements_; diff --git a/src/config/config.h b/src/config/config.h index ee1ec919..e3a53149 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -101,7 +101,7 @@ struct filter { std::vector parents; - std::vector specializations; + std::vector specializations; std::vector dependants; diff --git a/tests/test_config_data/filters.yml b/tests/test_config_data/filters.yml index e46aeec1..8fb02e1d 100644 --- a/tests/test_config_data/filters.yml +++ b/tests/test_config_data/filters.yml @@ -58,4 +58,9 @@ diagrams: type: class include: parents: - - r: 'ns1::ns2::.+[1|2]' \ No newline at end of file + - r: 'ns1::ns2::.+[1|2]' + regex_specializations_test: + type: class + include: + specializations: + - r: 'A' \ No newline at end of file diff --git a/tests/test_filters.cc b/tests/test_filters.cc index 9d366bcb..bb47dfe6 100644 --- a/tests/test_filters.cc +++ b/tests/test_filters.cc @@ -416,6 +416,80 @@ TEST_CASE("Test parents regexp filter", "[unit-test]") CHECK(!filter.should_include(*c)); } +TEST_CASE("Test specializations regexp filter", "[unit-test]") +{ + using clanguml::class_diagram::model::class_method; + using clanguml::class_diagram::model::class_parent; + using clanguml::common::to_id; + using clanguml::common::model::access_t; + using clanguml::common::model::diagram_filter; + using clanguml::common::model::namespace_; + using clanguml::common::model::package; + using clanguml::common::model::relationship; + using clanguml::common::model::relationship_t; + using clanguml::common::model::source_file; + using clanguml::common::model::template_parameter; + using namespace std::string_literals; + + using clanguml::class_diagram::model::class_; + + auto cfg = clanguml::config::load("./test_config_data/filters.yml"); + + auto &config = *cfg.diagrams["regex_specializations_test"]; + clanguml::class_diagram::model::diagram diagram; + + const auto template_id = to_id("A"s); + + auto c = std::make_unique(config.using_namespace()); + c->set_name("A"); + c->add_template( + template_parameter::make_template_type("T", std::nullopt, true)); + c->set_id(template_id); + diagram.add(namespace_{}, std::move(c)); + + c = std::make_unique(config.using_namespace()); + c->set_name("A"); + c->add_template(template_parameter::make_argument("double")); + c->set_id(to_id("A"s)); + c->add_relationship( + relationship{relationship_t::kInstantiation, template_id}); + diagram.add(namespace_{}, std::move(c)); + + c = std::make_unique(config.using_namespace()); + c->set_name("A"); + c->add_template(template_parameter::make_argument("int")); + c->set_id(to_id("A"s)); + c->add_relationship( + relationship{relationship_t::kInstantiation, template_id}); + diagram.add(namespace_{}, std::move(c)); + + c = std::make_unique(config.using_namespace()); + c->set_name("A"); + c->add_template(template_parameter::make_argument("int")); + c->add_template(template_parameter::make_argument("std::string")); + c->set_id(to_id("A"s)); + c->add_relationship( + relationship{relationship_t::kInstantiation, template_id}); + diagram.add(namespace_{}, std::move(c)); + + diagram.set_complete(true); + + diagram_filter filter(diagram, config); + + c = std::make_unique(config.using_namespace()); + c->set_name("A"); + c->add_template(template_parameter::make_argument("int")); + c->add_template(template_parameter::make_argument("std::string")); + c->set_id(to_id("A"s)); + CHECK(filter.should_include(*c)); + + c = std::make_unique(config.using_namespace()); + c->set_name("A"); + c->add_template(template_parameter::make_argument("double")); + c->set_id(to_id("A"s)); + CHECK(!filter.should_include(*c)); +} + /// /// Main test function ///