From 6952c3296dea32d79b4aab7fcf185cdbe964b9e6 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Thu, 13 Jun 2024 21:35:11 +0200 Subject: [PATCH] Added context filter relationships option (#274) --- src/common/model/diagram_filter.cc | 11 +++++++++ src/common/model/diagram_filter.h | 18 +++++++++++---- src/config/config.h | 1 + src/config/schema.h | 13 +++++++++++ src/config/yaml_decoders.cc | 3 +++ tests/t00078/.clang-uml | 16 +++++++++++++ tests/t00078/t00078.cc | 22 ++++++++++++++++++ tests/t00078/test_case.h | 36 ++++++++++++++++++++++++++++++ tests/test_cases.cc | 1 + tests/test_cases.yaml | 3 +++ 10 files changed, 120 insertions(+), 4 deletions(-) create mode 100644 tests/t00078/.clang-uml create mode 100644 tests/t00078/t00078.cc create mode 100644 tests/t00078/test_case.h diff --git a/src/common/model/diagram_filter.cc b/src/common/model/diagram_filter.cc index fb4def12..a01125a7 100644 --- a/src/common/model/diagram_filter.cc +++ b/src/common/model/diagram_filter.cc @@ -724,6 +724,13 @@ void context_filter::initialize_effective_context( } } +bool context_filter::should_include( + const config::context_config &context_cfg, relationship_t r) const +{ + return context_cfg.relationships.empty() || + util::contains(context_cfg.relationships, r); +} + void context_filter::find_elements_inheritance_relationship(const diagram &d, const config::context_config &context_cfg, std::set &effective_context, @@ -731,6 +738,10 @@ void context_filter::find_elements_inheritance_relationship(const diagram &d, { const auto &cd = dynamic_cast(d); + if (!should_include(context_cfg, relationship_t::kExtension)) { + return; + } + for (const auto &c : cd.classes()) { // Check if any of the elements parents are already in the // effective context... diff --git a/src/common/model/diagram_filter.h b/src/common/model/diagram_filter.h index c70a59c0..fb2e144c 100644 --- a/src/common/model/diagram_filter.h +++ b/src/common/model/diagram_filter.h @@ -516,6 +516,10 @@ private: // which have a relationship to any of the effective_context // elements for (const relationship &rel : el.get().relationships()) { + if (!should_include(context_cfg, rel.type()) || + !d.should_include(rel.type())) { + continue; + } // At the moment aggregation and composition are added in the // model in reverse direction, so we don't consider them here if (context_cfg.direction == @@ -531,8 +535,7 @@ private: continue; } for (const auto &element_id : effective_context) { - if (d.should_include(rel.type()) && - rel.destination() == element_id) + if (rel.destination() == element_id) current_iteration_context.emplace(el.get().id()); } } @@ -548,6 +551,11 @@ private: for (const relationship &rel : maybe_element.value().relationships()) { + if (!should_include(context_cfg, rel.type()) || + !d.should_include(rel.type())) { + continue; + } + if ((context_cfg.direction == config::context_direction_t::inward) && (rel.type() != relationship_t::kAggregation && @@ -561,14 +569,16 @@ private: continue; } - if (d.should_include(rel.type()) && - rel.destination() == el.get().id()) + if (rel.destination() == el.get().id()) current_iteration_context.emplace(el.get().id()); } } } } + bool should_include( + const config::context_config &context_cfg, relationship_t r) const; + void find_elements_inheritance_relationship(const diagram &d, const config::context_config &context_cfg, std::set &effective_context, diff --git a/src/config/config.h b/src/config/config.h index 36503b77..230d6271 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -167,6 +167,7 @@ struct context_config { common::string_or_regex pattern; unsigned radius{0}; context_direction_t direction{context_direction_t::any}; + std::vector relationships; }; /** diff --git a/src/config/schema.h b/src/config/schema.h index b19a611b..f1e880f6 100644 --- a/src/config/schema.h +++ b/src/config/schema.h @@ -87,6 +87,18 @@ types: - dependency - constraint - none + relationship_context_t: !variant + - extension + - inheritance + - composition + - aggregation + - containment + - ownership + - association + - instantiation + - friendship + - dependency + - constraint access_filter_t: !variant - public - protected @@ -123,6 +135,7 @@ types: radius: int pattern: regex_or_string_t direction: !optional direction_t + relationships: !optional [relationship_context_t] context_filter_t: - regex_or_string_t - context_filter_match_t diff --git a/src/config/yaml_decoders.cc b/src/config/yaml_decoders.cc index 8d4a0148..a21335ba 100644 --- a/src/config/yaml_decoders.cc +++ b/src/config/yaml_decoders.cc @@ -485,6 +485,9 @@ template <> struct convert { rhs.pattern = match["pattern"].as(); if (has_key(match, "direction")) rhs.direction = match["direction"].as(); + if (has_key(match, "relationships")) + rhs.relationships = + match["relationships"].as>(); } else { rhs.radius = 1; diff --git a/tests/t00078/.clang-uml b/tests/t00078/.clang-uml new file mode 100644 index 00000000..d53ec0a7 --- /dev/null +++ b/tests/t00078/.clang-uml @@ -0,0 +1,16 @@ +diagrams: + t00078_class: + type: class + glob: + - t00078.cc + include: + namespaces: + - clanguml::t00078 + context: + - match: + radius: 1 + pattern: clanguml::t00078::A + relationships: + - inheritance + - aggregation + using_namespace: clanguml::t00078 \ No newline at end of file diff --git a/tests/t00078/t00078.cc b/tests/t00078/t00078.cc new file mode 100644 index 00000000..16f3d59c --- /dev/null +++ b/tests/t00078/t00078.cc @@ -0,0 +1,22 @@ +namespace clanguml { +namespace t00078 { + +struct Base { }; + +struct D { }; +struct E { }; +struct A : public Base { + D d; + E *e; +}; + +struct B { + A *a; +}; + +struct C { + A a; +}; + +} +} \ No newline at end of file diff --git a/tests/t00078/test_case.h b/tests/t00078/test_case.h new file mode 100644 index 00000000..e5e67981 --- /dev/null +++ b/tests/t00078/test_case.h @@ -0,0 +1,36 @@ +/** + * tests/t00078/test_case.h + * + * Copyright (c) 2021-2024 Bartek Kryza + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +TEST_CASE("t00078") +{ + using namespace clanguml::test; + using namespace std::string_literals; + + auto [config, db, diagram, model] = + CHECK_CLASS_MODEL("t00078", "t00078_class"); + + CHECK_CLASS_DIAGRAM(*config, diagram, *model, [](const auto &src) { + REQUIRE(IsClass(src, "Base")); + REQUIRE(IsClass(src, "A")); + REQUIRE(IsClass(src, "C")); + REQUIRE(IsClass(src, "D")); + + REQUIRE(!IsClass(src, "B")); + REQUIRE(!IsClass(src, "E")); + }); +} \ No newline at end of file diff --git a/tests/test_cases.cc b/tests/test_cases.cc index 18191124..4a563559 100644 --- a/tests/test_cases.cc +++ b/tests/test_cases.cc @@ -551,6 +551,7 @@ void CHECK_INCLUDE_DIAGRAM(const clanguml::config::config &config, #endif #include "t00076/test_case.h" #include "t00077/test_case.h" +#include "t00078/test_case.h" /// /// Sequence diagram tests diff --git a/tests/test_cases.yaml b/tests/test_cases.yaml index 2da1f626..e0b024b0 100644 --- a/tests/test_cases.yaml +++ b/tests/test_cases.yaml @@ -228,6 +228,9 @@ test_cases: - name: t00077 title: Test case for context diagram with outward direction flag description: + - name: t00078 + title: Test case for context diagram with relationships option + description: Sequence diagrams: - name: t20001 title: Basic sequence diagram test case