diff --git a/src/common/model/diagram.cc b/src/common/model/diagram.cc index 9831ec6e4..60b743cd1 100644 --- a/src/common/model/diagram.cc +++ b/src/common/model/diagram.cc @@ -74,13 +74,20 @@ bool diagram::should_include(const element &e) const if (filter_.get() == nullptr) return true; - if (!complete()) { + // In the basic mode, apply the paths filter as soon as possible + // to limit processing unnecessary files + if (filter_->mode() == filter_mode_t::basic) { return filter_->should_include( dynamic_cast(e)); } - return filter_->should_include(e) && - filter_->should_include(dynamic_cast(e)); + // In advanced mode, we have to wait until the diagram model is complete + // before we can filter anything out + if (filter_->mode() == filter_mode_t::advanced && !complete()) { + return true; + } + + return filter_->should_include(e); } bool diagram::should_include(const namespace_ &ns) const diff --git a/src/common/model/filters/diagram_filter.cc b/src/common/model/filters/diagram_filter.cc index 8eec9a8bb..825dbaea8 100644 --- a/src/common/model/filters/diagram_filter.cc +++ b/src/common/model/filters/diagram_filter.cc @@ -983,6 +983,12 @@ tvl::value_t paths_filter::match( return false; } +tvl::value_t paths_filter::match( + const diagram &d, const common::model::element &e) const +{ + return match(d, dynamic_cast(e)); +} + class_method_filter::class_method_filter(filter_t type, std::unique_ptr af, std::unique_ptr mtf) : filter_visitor{type} @@ -1052,6 +1058,10 @@ bool diagram_filter::should_include( return false; } +filter_mode_t diagram_filter::mode() const { return mode_; } + +void diagram_filter::set_mode(filter_mode_t mode) { mode_ = mode; } + template <> bool diagram_filter::should_include(const std::string &name) const { diff --git a/src/common/model/filters/diagram_filter.h b/src/common/model/filters/diagram_filter.h index 34db8a393..d74504c20 100644 --- a/src/common/model/filters/diagram_filter.h +++ b/src/common/model/filters/diagram_filter.h @@ -692,6 +692,9 @@ struct paths_filter : public filter_visitor { tvl::value_t match(const diagram &d, const common::model::source_location &sl) const override; + tvl::value_t match( + const diagram &d, const common::model::element &e) const override; + private: std::vector paths_; std::filesystem::path root_; @@ -802,6 +805,10 @@ class diagram_filter { return static_cast(tvl::is_undefined(inc) || tvl::is_true(inc)); } + filter_mode_t mode() const; + + void set_mode(filter_mode_t mode); + friend class diagram_filter_factory; private: @@ -813,6 +820,8 @@ class diagram_filter { /*! Reference to the diagram model */ const common::model::diagram &diagram_; + + filter_mode_t mode_{filter_mode_t::basic}; }; template diff --git a/src/common/model/filters/diagram_filter_factory.h b/src/common/model/filters/diagram_filter_factory.h index 8c80e4aa4..8c6b9cb0b 100644 --- a/src/common/model/filters/diagram_filter_factory.h +++ b/src/common/model/filters/diagram_filter_factory.h @@ -110,7 +110,9 @@ class diagram_filter_factory { auto filter = std::make_unique( d, c, diagram_filter::private_constructor_tag_t{}); - if (c.filter_mode() == config::filter_mode_t::basic) { + filter->set_mode(c.filter_mode()); + + if (filter->mode() == config::filter_mode_t::basic) { basic_diagram_filter_initializer init{c, *filter}; init.initialize(); } diff --git a/tests/test_config_data/filters_advanced.yml b/tests/test_config_data/filters_advanced.yml index 31057c44a..5a3418912 100644 --- a/tests/test_config_data/filters_advanced.yml +++ b/tests/test_config_data/filters_advanced.yml @@ -37,6 +37,18 @@ diagrams: anyof: namespaces: - ns1::ns2::detail + anyof_paths_test: + type: class + relative_to: ../../../src + glob: + - src/**/*.cc + - src/**/*.h + include: + anyof: + paths: + - . + elements: + - std::thread modules_test: type: class include: diff --git a/tests/test_filters_advanced.cc b/tests/test_filters_advanced.cc index f6cfd5acb..9a27445b8 100644 --- a/tests/test_filters_advanced.cc +++ b/tests/test_filters_advanced.cc @@ -91,6 +91,40 @@ TEST_CASE("Test advanced diagram filter anyof") CHECK_FALSE(filter.should_include(namespace_{"ns1::ns2::detail"})); } +TEST_CASE("Test advanced diagram filter anyof with paths") +{ + auto cfg = + clanguml::config::load("./test_config_data/filters_advanced.yml"); + + auto &config = *cfg.diagrams["anyof_paths_test"]; + clanguml::include_diagram::model::diagram diagram; + + diagram.set_complete(true); + + auto filter_ptr = diagram_filter_factory::create(diagram, config); + diagram_filter &filter = *filter_ptr; + + CHECK(config.filter_mode() == filter_mode_t::advanced); + + clanguml::common::model::element std_thread{{}}; + std_thread.set_namespace(namespace_{"std"}); + std_thread.set_name("thread"); + std_thread.set_file("/usr/include/thread"); + CHECK(filter.should_include(std_thread)); + + std_thread.set_name("jthread"); + CHECK_FALSE(filter.should_include(std_thread)); + + clanguml::common::model::element myclass{{}}; + myclass.set_namespace(namespace_{"myns"}); + myclass.set_name("myclass"); + + auto myclass_path = config.root_directory() / "include/myclass.h"; + + myclass.set_file(weakly_canonical(myclass_path).string()); + CHECK(filter.should_include(myclass)); +} + TEST_CASE("Test advanced diagram filter modules") { auto cfg =