Added parents (base classes) diagram filter
This commit is contained in:
@@ -7,6 +7,7 @@
|
|||||||
* [`context`](#context)
|
* [`context`](#context)
|
||||||
* [`relationships`](#relationships)
|
* [`relationships`](#relationships)
|
||||||
* [`subclasses`](#subclasses)
|
* [`subclasses`](#subclasses)
|
||||||
|
* [`parents`](#parents)
|
||||||
* [`specializations`](#specializations)
|
* [`specializations`](#specializations)
|
||||||
* [`dependants` and `dependencies`](#dependants-and-dependencies)
|
* [`dependants` and `dependencies`](#dependants-and-dependencies)
|
||||||
|
|
||||||
@@ -89,6 +90,10 @@ The following relationships can be used in this filter:
|
|||||||
|
|
||||||
This filter allows to include or exclude all subclasses of a given class in the diagram.
|
This filter allows to include or exclude all subclasses of a given class in the diagram.
|
||||||
|
|
||||||
|
## `parents`
|
||||||
|
|
||||||
|
This filter allows to include or exclude all parents (base classes) of a given class in the diagram.
|
||||||
|
|
||||||
## `specializations`
|
## `specializations`
|
||||||
|
|
||||||
This filter allows to include or exclude specializations and instantiations of a specific template from the diagram.
|
This filter allows to include or exclude specializations and instantiations of a specific template from the diagram.
|
||||||
|
|||||||
@@ -263,6 +263,45 @@ tvl::value_t subclass_filter::match(const diagram &d, const element &e) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parents_filter::parents_filter(filter_t type, std::vector<std::string> children)
|
||||||
|
: filter_visitor{type}
|
||||||
|
, children_{std::move(children)}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
tvl::value_t parents_filter::match(const diagram &d, const element &e) const
|
||||||
|
{
|
||||||
|
if (d.type() != diagram_t::kClass)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (children_.empty())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (!d.complete())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
const auto &cd = dynamic_cast<const class_diagram::model::diagram &>(d);
|
||||||
|
|
||||||
|
// First get all parents of element e
|
||||||
|
clanguml::common::reference_set<class_diagram::model::class_> parents;
|
||||||
|
|
||||||
|
for (const auto &child : children_) {
|
||||||
|
auto child_ref = cd.get_class(child);
|
||||||
|
if (!child_ref.has_value())
|
||||||
|
continue;
|
||||||
|
parents.emplace(child_ref.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
cd.get_parents(parents);
|
||||||
|
|
||||||
|
for (const auto &parent : parents) {
|
||||||
|
if (e == parent.get())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
relationship_filter::relationship_filter(
|
relationship_filter::relationship_filter(
|
||||||
filter_t type, std::vector<relationship_t> relationships)
|
filter_t type, std::vector<relationship_t> relationships)
|
||||||
: filter_visitor{type}
|
: filter_visitor{type}
|
||||||
@@ -465,6 +504,9 @@ void diagram_filter::init_filters(const config::diagram &c)
|
|||||||
element_filters.emplace_back(std::make_unique<subclass_filter>(
|
element_filters.emplace_back(std::make_unique<subclass_filter>(
|
||||||
filter_t::kInclusive, c.include().subclasses));
|
filter_t::kInclusive, c.include().subclasses));
|
||||||
|
|
||||||
|
element_filters.emplace_back(std::make_unique<parents_filter>(
|
||||||
|
filter_t::kInclusive, c.include().parents));
|
||||||
|
|
||||||
element_filters.emplace_back(std::make_unique<
|
element_filters.emplace_back(std::make_unique<
|
||||||
edge_traversal_filter<class_diagram::model::diagram,
|
edge_traversal_filter<class_diagram::model::diagram,
|
||||||
class_diagram::model::class_>>(filter_t::kInclusive,
|
class_diagram::model::class_>>(filter_t::kInclusive,
|
||||||
@@ -545,6 +587,9 @@ void diagram_filter::init_filters(const config::diagram &c)
|
|||||||
add_exclusive_filter(std::make_unique<subclass_filter>(
|
add_exclusive_filter(std::make_unique<subclass_filter>(
|
||||||
filter_t::kExclusive, c.exclude().subclasses));
|
filter_t::kExclusive, c.exclude().subclasses));
|
||||||
|
|
||||||
|
add_exclusive_filter(std::make_unique<parents_filter>(
|
||||||
|
filter_t::kExclusive, c.exclude().parents));
|
||||||
|
|
||||||
add_exclusive_filter(std::make_unique<edge_traversal_filter<
|
add_exclusive_filter(std::make_unique<edge_traversal_filter<
|
||||||
class_diagram::model::diagram, class_diagram::model::class_>>(
|
class_diagram::model::diagram, class_diagram::model::class_>>(
|
||||||
filter_t::kExclusive, relationship_t::kInstantiation,
|
filter_t::kExclusive, relationship_t::kInstantiation,
|
||||||
|
|||||||
@@ -135,6 +135,17 @@ private:
|
|||||||
std::vector<std::string> roots_;
|
std::vector<std::string> roots_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct parents_filter : public filter_visitor {
|
||||||
|
parents_filter(filter_t type, std::vector<std::string> roots);
|
||||||
|
|
||||||
|
~parents_filter() override = default;
|
||||||
|
|
||||||
|
tvl::value_t match(const diagram &d, const element &e) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::string> children_;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename DiagramT, typename ElementT,
|
template <typename DiagramT, typename ElementT,
|
||||||
typename MatchOverrideT = common::model::element>
|
typename MatchOverrideT = common::model::element>
|
||||||
struct edge_traversal_filter : public filter_visitor {
|
struct edge_traversal_filter : public filter_visitor {
|
||||||
|
|||||||
@@ -69,6 +69,8 @@ struct filter {
|
|||||||
|
|
||||||
std::vector<std::string> subclasses;
|
std::vector<std::string> subclasses;
|
||||||
|
|
||||||
|
std::vector<std::string> parents;
|
||||||
|
|
||||||
std::vector<std::string> specializations;
|
std::vector<std::string> specializations;
|
||||||
|
|
||||||
std::vector<std::string> dependants;
|
std::vector<std::string> dependants;
|
||||||
|
|||||||
@@ -275,6 +275,9 @@ template <> struct convert<filter> {
|
|||||||
if (node["subclasses"])
|
if (node["subclasses"])
|
||||||
rhs.subclasses = node["subclasses"].as<decltype(rhs.subclasses)>();
|
rhs.subclasses = node["subclasses"].as<decltype(rhs.subclasses)>();
|
||||||
|
|
||||||
|
if (node["parents"])
|
||||||
|
rhs.parents = node["parents"].as<decltype(rhs.parents)>();
|
||||||
|
|
||||||
if (node["specializations"])
|
if (node["specializations"])
|
||||||
rhs.specializations =
|
rhs.specializations =
|
||||||
node["specializations"].as<decltype(rhs.specializations)>();
|
node["specializations"].as<decltype(rhs.specializations)>();
|
||||||
|
|||||||
@@ -69,6 +69,8 @@ YAML::Emitter &operator<<(YAML::Emitter &out, const filter &f)
|
|||||||
<< f.specializations;
|
<< f.specializations;
|
||||||
if (!f.subclasses.empty())
|
if (!f.subclasses.empty())
|
||||||
out << YAML::Key << "subclasses" << YAML::Value << f.subclasses;
|
out << YAML::Key << "subclasses" << YAML::Value << f.subclasses;
|
||||||
|
if (!f.parents.empty())
|
||||||
|
out << YAML::Key << "parents" << YAML::Value << f.parents;
|
||||||
|
|
||||||
out << YAML::EndMap;
|
out << YAML::EndMap;
|
||||||
return out;
|
return out;
|
||||||
|
|||||||
15
tests/t00060/.clang-uml
Normal file
15
tests/t00060/.clang-uml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
compilation_database_dir: ..
|
||||||
|
output_directory: puml
|
||||||
|
diagrams:
|
||||||
|
t00060_class:
|
||||||
|
type: class
|
||||||
|
glob:
|
||||||
|
- ../../tests/t00060/t00060.cc
|
||||||
|
include:
|
||||||
|
namespaces:
|
||||||
|
- clanguml::t00060
|
||||||
|
parents:
|
||||||
|
- clanguml::t00060::D
|
||||||
|
- clanguml::t00060::H<T,P>
|
||||||
|
using_namespace:
|
||||||
|
- clanguml::t00060
|
||||||
20
tests/t00060/t00060.cc
Normal file
20
tests/t00060/t00060.cc
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
namespace clanguml {
|
||||||
|
namespace t00060 {
|
||||||
|
struct A { };
|
||||||
|
struct B : public A { };
|
||||||
|
struct C : public A { };
|
||||||
|
struct D : public B, public C { };
|
||||||
|
struct E : public C { };
|
||||||
|
struct F : public D { };
|
||||||
|
|
||||||
|
template <typename T> struct G {
|
||||||
|
T g;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename P> struct H : public G<T> {
|
||||||
|
G<T> h;
|
||||||
|
P hh;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
50
tests/t00060/test_case.h
Normal file
50
tests/t00060/test_case.h
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/**
|
||||||
|
* tests/t00060/test_case.h
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
|
||||||
|
*
|
||||||
|
* 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("t00060", "[test-case][class]")
|
||||||
|
{
|
||||||
|
auto [config, db] = load_config("t00060");
|
||||||
|
|
||||||
|
auto diagram = config.diagrams["t00060_class"];
|
||||||
|
|
||||||
|
REQUIRE(diagram->name == "t00060_class");
|
||||||
|
|
||||||
|
auto model = generate_class_diagram(*db, diagram);
|
||||||
|
|
||||||
|
REQUIRE(model->name() == "t00060_class");
|
||||||
|
|
||||||
|
auto puml = generate_class_puml(diagram, *model);
|
||||||
|
AliasMatcher _A(puml);
|
||||||
|
|
||||||
|
REQUIRE_THAT(puml, StartsWith("@startuml"));
|
||||||
|
REQUIRE_THAT(puml, EndsWith("@enduml\n"));
|
||||||
|
|
||||||
|
// Check if all classes exist
|
||||||
|
REQUIRE_THAT(puml, IsClass(_A("A")));
|
||||||
|
REQUIRE_THAT(puml, IsClass(_A("B")));
|
||||||
|
REQUIRE_THAT(puml, IsClass(_A("C")));
|
||||||
|
REQUIRE_THAT(puml, IsClass(_A("D")));
|
||||||
|
REQUIRE_THAT(puml, !IsClass(_A("E")));
|
||||||
|
REQUIRE_THAT(puml, !IsClass(_A("F")));
|
||||||
|
|
||||||
|
// Check if class templates exist
|
||||||
|
REQUIRE_THAT(puml, IsClassTemplate("G", "T"));
|
||||||
|
REQUIRE_THAT(puml, IsClassTemplate("H", "T,P"));
|
||||||
|
|
||||||
|
save_puml(config.output_directory() + "/" + diagram->name + ".puml", puml);
|
||||||
|
}
|
||||||
@@ -263,6 +263,8 @@ using namespace clanguml::test::matchers;
|
|||||||
#include "t00058/test_case.h"
|
#include "t00058/test_case.h"
|
||||||
#include "t00059/test_case.h"
|
#include "t00059/test_case.h"
|
||||||
#endif
|
#endif
|
||||||
|
#include "t00060/test_case.h"
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Sequence diagram tests
|
/// Sequence diagram tests
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -174,6 +174,9 @@ test_cases:
|
|||||||
- name: t00059
|
- name: t00059
|
||||||
title: Non-virtual abstract factory pattern using concepts test case
|
title: Non-virtual abstract factory pattern using concepts test case
|
||||||
description:
|
description:
|
||||||
|
- name: t00060
|
||||||
|
title: Parents (base classes) diagram filter test case
|
||||||
|
description:
|
||||||
Sequence diagrams:
|
Sequence diagrams:
|
||||||
- name: t20001
|
- name: t20001
|
||||||
title: Basic sequence diagram test case
|
title: Basic sequence diagram test case
|
||||||
|
|||||||
Reference in New Issue
Block a user