Added regex support to context filter
This commit is contained in:
@@ -430,7 +430,8 @@ tvl::value_t access_filter::match(
|
|||||||
[&a](const auto &access) { return a == access; });
|
[&a](const auto &access) { return a == access; });
|
||||||
}
|
}
|
||||||
|
|
||||||
context_filter::context_filter(filter_t type, std::vector<std::string> context)
|
context_filter::context_filter(
|
||||||
|
filter_t type, std::vector<common::string_or_regex> context)
|
||||||
: filter_visitor{type}
|
: filter_visitor{type}
|
||||||
, context_{std::move(context)}
|
, context_{std::move(context)}
|
||||||
{
|
{
|
||||||
@@ -447,48 +448,50 @@ tvl::value_t context_filter::match(const diagram &d, const element &e) const
|
|||||||
return {};
|
return {};
|
||||||
|
|
||||||
return tvl::any_of(context_.begin(), context_.end(),
|
return tvl::any_of(context_.begin(), context_.end(),
|
||||||
[&e, &d](const auto &context_root_name) {
|
[&e, &d](const auto &context_root_pattern) {
|
||||||
const auto &context_root =
|
const auto &context_roots =
|
||||||
static_cast<const class_diagram::model::diagram &>(d)
|
static_cast<const class_diagram::model::diagram &>(d)
|
||||||
.find<class_diagram::model::class_>(context_root_name);
|
.find<class_diagram::model::class_>(context_root_pattern);
|
||||||
|
|
||||||
if (context_root.has_value()) {
|
for (auto &context_root : context_roots) {
|
||||||
// This is a direct match to the context root
|
if (context_root.has_value()) {
|
||||||
if (context_root.value().id() == e.id())
|
// This is a direct match to the context root
|
||||||
return true;
|
if (context_root.value().id() == e.id())
|
||||||
|
return true;
|
||||||
|
|
||||||
// Return a positive match if the element e is in a direct
|
// Return a positive match if the element e is in a direct
|
||||||
// relationship with any of the context_root's
|
// relationship with any of the context_root's
|
||||||
for (const relationship &rel :
|
for (const relationship &rel :
|
||||||
context_root.value().relationships()) {
|
context_root.value().relationships()) {
|
||||||
if (d.should_include(rel.type()) &&
|
if (d.should_include(rel.type()) &&
|
||||||
rel.destination() == e.id())
|
rel.destination() == e.id())
|
||||||
return true;
|
|
||||||
}
|
|
||||||
for (const relationship &rel : e.relationships()) {
|
|
||||||
if (d.should_include(rel.type()) &&
|
|
||||||
rel.destination() == context_root.value().id())
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return a positive match if the context_root is a parent
|
|
||||||
// of the element
|
|
||||||
for (const class_diagram::model::class_parent &p :
|
|
||||||
context_root.value().parents()) {
|
|
||||||
if (p.name() == e.full_name(false))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (dynamic_cast<const class_diagram::model::class_ *>(&e) !=
|
|
||||||
nullptr) {
|
|
||||||
for (const class_diagram::model::class_parent &p :
|
|
||||||
static_cast<const class_diagram::model::class_ &>(e)
|
|
||||||
.parents()) {
|
|
||||||
if (p.name() == context_root.value().full_name(false))
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
for (const relationship &rel : e.relationships()) {
|
||||||
|
if (d.should_include(rel.type()) &&
|
||||||
|
rel.destination() == context_root.value().id())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a positive match if the context_root is a parent
|
||||||
|
// of the element
|
||||||
|
for (const class_diagram::model::class_parent &p :
|
||||||
|
context_root.value().parents()) {
|
||||||
|
if (p.name() == e.full_name(false))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (dynamic_cast<const class_diagram::model::class_ *>(
|
||||||
|
&e) != nullptr) {
|
||||||
|
for (const class_diagram::model::class_parent &p :
|
||||||
|
static_cast<const class_diagram::model::class_ &>(e)
|
||||||
|
.parents()) {
|
||||||
|
if (p.name() ==
|
||||||
|
context_root.value().full_name(false))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -363,14 +363,14 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct context_filter : public filter_visitor {
|
struct context_filter : public filter_visitor {
|
||||||
context_filter(filter_t type, std::vector<std::string> context);
|
context_filter(filter_t type, std::vector<common::string_or_regex> context);
|
||||||
|
|
||||||
~context_filter() override = default;
|
~context_filter() override = default;
|
||||||
|
|
||||||
tvl::value_t match(const diagram &d, const element &r) const override;
|
tvl::value_t match(const diagram &d, const element &r) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::string> context_;
|
std::vector<common::string_or_regex> context_;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct paths_filter : public filter_visitor {
|
struct paths_filter : public filter_visitor {
|
||||||
|
|||||||
@@ -127,6 +127,18 @@ public:
|
|||||||
return *value_;
|
return *value_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
T &operator*()
|
||||||
|
{
|
||||||
|
assert(value_ != nullptr);
|
||||||
|
return *value_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const T &operator*() const
|
||||||
|
{
|
||||||
|
assert(value_ != nullptr);
|
||||||
|
return *value_;
|
||||||
|
}
|
||||||
|
|
||||||
void reset() { value_ = nullptr; }
|
void reset() { value_ = nullptr; }
|
||||||
|
|
||||||
T *get() const { return value_; }
|
T *get() const { return value_; }
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ struct filter {
|
|||||||
|
|
||||||
std::vector<std::string> dependencies;
|
std::vector<std::string> dependencies;
|
||||||
|
|
||||||
std::vector<std::string> context;
|
std::vector<common::string_or_regex> context;
|
||||||
|
|
||||||
std::vector<std::filesystem::path> paths;
|
std::vector<std::filesystem::path> paths;
|
||||||
|
|
||||||
|
|||||||
@@ -63,4 +63,9 @@ diagrams:
|
|||||||
type: class
|
type: class
|
||||||
include:
|
include:
|
||||||
specializations:
|
specializations:
|
||||||
- r: 'A<int,.+>'
|
- r: 'A<int,.+>'
|
||||||
|
regex_context_test:
|
||||||
|
type: class
|
||||||
|
include:
|
||||||
|
context:
|
||||||
|
- r: '[A|B]'
|
||||||
@@ -293,23 +293,9 @@ TEST_CASE("Test subclasses regexp filter", "[unit-test]")
|
|||||||
|
|
||||||
diagram_filter filter(diagram, config);
|
diagram_filter filter(diagram, config);
|
||||||
|
|
||||||
c = std::make_unique<class_>(config.using_namespace());
|
CHECK(filter.should_include(*diagram.find<class_>("ns1::ns2::A1")));
|
||||||
c->set_namespace(namespace_{"ns1::ns2"});
|
CHECK(filter.should_include(*diagram.find<class_>("ns1::ns2::B1")));
|
||||||
c->set_name("A1");
|
CHECK(!filter.should_include(*diagram.find<class_>("ns1::ns2::C1")));
|
||||||
c->set_id(to_id("ns1::ns2::A1"s));
|
|
||||||
CHECK(filter.should_include(*c));
|
|
||||||
|
|
||||||
c = std::make_unique<class_>(config.using_namespace());
|
|
||||||
c->set_namespace(namespace_{"ns1::ns2"});
|
|
||||||
c->set_name("B1");
|
|
||||||
c->set_id(to_id("ns1::ns2::B1"s));
|
|
||||||
CHECK(filter.should_include(*c));
|
|
||||||
|
|
||||||
c = std::make_unique<class_>(config.using_namespace());
|
|
||||||
c->set_namespace(namespace_{"ns1::ns2"});
|
|
||||||
c->set_name("C1");
|
|
||||||
c->set_id(to_id("ns1::ns2::C1"s));
|
|
||||||
CHECK(!filter.should_include(*c));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Test parents regexp filter", "[unit-test]")
|
TEST_CASE("Test parents regexp filter", "[unit-test]")
|
||||||
@@ -397,23 +383,9 @@ TEST_CASE("Test parents regexp filter", "[unit-test]")
|
|||||||
|
|
||||||
diagram_filter filter(diagram, config);
|
diagram_filter filter(diagram, config);
|
||||||
|
|
||||||
c = std::make_unique<class_>(config.using_namespace());
|
CHECK(filter.should_include(*diagram.find<class_>("ns1::ns2::BaseA")));
|
||||||
c->set_namespace(namespace_{"ns1::ns2"});
|
CHECK(filter.should_include(*diagram.find<class_>("ns1::ns2::BaseB")));
|
||||||
c->set_name("BaseA");
|
CHECK(!filter.should_include(*diagram.find<class_>("ns1::ns2::Common")));
|
||||||
c->set_id(to_id("ns1::ns2::BaseA"s));
|
|
||||||
CHECK(filter.should_include(*c));
|
|
||||||
|
|
||||||
c = std::make_unique<class_>(config.using_namespace());
|
|
||||||
c->set_namespace(namespace_{"ns1::ns2"});
|
|
||||||
c->set_name("BaseB");
|
|
||||||
c->set_id(to_id("ns1::ns2::BaseB"s));
|
|
||||||
CHECK(filter.should_include(*c));
|
|
||||||
|
|
||||||
c = std::make_unique<class_>(config.using_namespace());
|
|
||||||
c->set_namespace(namespace_{"ns1::ns2"});
|
|
||||||
c->set_name("Common");
|
|
||||||
c->set_id(to_id("ns1::ns2::Common"s));
|
|
||||||
CHECK(!filter.should_include(*c));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Test specializations regexp filter", "[unit-test]")
|
TEST_CASE("Test specializations regexp filter", "[unit-test]")
|
||||||
@@ -476,18 +448,97 @@ TEST_CASE("Test specializations regexp filter", "[unit-test]")
|
|||||||
|
|
||||||
diagram_filter filter(diagram, config);
|
diagram_filter filter(diagram, config);
|
||||||
|
|
||||||
c = std::make_unique<class_>(config.using_namespace());
|
CHECK(filter.should_include(*diagram.find<class_>("A<int,std::string>")));
|
||||||
|
CHECK(!filter.should_include(*diagram.find<class_>("A<double>")));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Test context regexp filter", "[unit-test]")
|
||||||
|
{
|
||||||
|
using clanguml::class_diagram::model::class_;
|
||||||
|
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_context_test"];
|
||||||
|
clanguml::class_diagram::model::diagram diagram;
|
||||||
|
|
||||||
|
auto c = std::make_unique<class_>(config.using_namespace());
|
||||||
c->set_name("A");
|
c->set_name("A");
|
||||||
c->add_template(template_parameter::make_argument("int"));
|
c->set_id(to_id("A"s));
|
||||||
c->add_template(template_parameter::make_argument("std::string"));
|
diagram.add(namespace_{}, std::move(c));
|
||||||
c->set_id(to_id("A<int,std::string>"s));
|
|
||||||
CHECK(filter.should_include(*c));
|
|
||||||
|
|
||||||
c = std::make_unique<class_>(config.using_namespace());
|
c = std::make_unique<class_>(config.using_namespace());
|
||||||
c->set_name("A");
|
c->set_name("A1");
|
||||||
c->add_template(template_parameter::make_argument("double"));
|
c->set_id(to_id("A1"s));
|
||||||
c->set_id(to_id("A<double>"s));
|
c->add_relationship(
|
||||||
CHECK(!filter.should_include(*c));
|
relationship{relationship_t::kAssociation, to_id("A"s)});
|
||||||
|
diagram.add(namespace_{}, std::move(c));
|
||||||
|
|
||||||
|
c = std::make_unique<class_>(config.using_namespace());
|
||||||
|
c->set_name("A2");
|
||||||
|
c->set_id(to_id("A2"s));
|
||||||
|
c->add_relationship(relationship{relationship_t::kDependency, to_id("A"s)});
|
||||||
|
diagram.add(namespace_{}, std::move(c));
|
||||||
|
|
||||||
|
c = std::make_unique<class_>(config.using_namespace());
|
||||||
|
c->set_name("A21");
|
||||||
|
c->set_id(to_id("A21"s));
|
||||||
|
c->add_relationship(
|
||||||
|
relationship{relationship_t::kDependency, to_id("A2"s)});
|
||||||
|
diagram.add(namespace_{}, std::move(c));
|
||||||
|
|
||||||
|
c = std::make_unique<class_>(config.using_namespace());
|
||||||
|
c->set_name("B");
|
||||||
|
c->set_id(to_id("B"s));
|
||||||
|
diagram.add(namespace_{}, std::move(c));
|
||||||
|
|
||||||
|
c = std::make_unique<class_>(config.using_namespace());
|
||||||
|
c->set_name("B1");
|
||||||
|
c->set_id(to_id("B1"s));
|
||||||
|
c->add_relationship(
|
||||||
|
relationship{relationship_t::kAssociation, to_id("B"s)});
|
||||||
|
diagram.add(namespace_{}, std::move(c));
|
||||||
|
|
||||||
|
c = std::make_unique<class_>(config.using_namespace());
|
||||||
|
c->set_name("C");
|
||||||
|
c->set_id(to_id("C"s));
|
||||||
|
diagram.add(namespace_{}, std::move(c));
|
||||||
|
|
||||||
|
c = std::make_unique<class_>(config.using_namespace());
|
||||||
|
c->set_name("C1");
|
||||||
|
c->set_id(to_id("C1"s));
|
||||||
|
c->add_relationship(
|
||||||
|
relationship{relationship_t::kAssociation, to_id("C"s)});
|
||||||
|
diagram.add(namespace_{}, std::move(c));
|
||||||
|
|
||||||
|
diagram.set_complete(true);
|
||||||
|
|
||||||
|
diagram_filter filter(diagram, config);
|
||||||
|
|
||||||
|
CHECK(filter.should_include(*diagram.find<class_>("A")));
|
||||||
|
CHECK(filter.should_include(*diagram.find<class_>("A1")));
|
||||||
|
CHECK(filter.should_include(*diagram.find<class_>("A2")));
|
||||||
|
|
||||||
|
CHECK(!filter.should_include(*diagram.find<class_>("A21")));
|
||||||
|
|
||||||
|
CHECK(filter.should_include(*diagram.find<class_>("B")));
|
||||||
|
CHECK(filter.should_include(*diagram.find<class_>("B1")));
|
||||||
|
|
||||||
|
CHECK(!filter.should_include(*diagram.find<class_>("C")));
|
||||||
|
CHECK(!filter.should_include(*diagram.find<class_>("C1")));
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
|
|||||||
Reference in New Issue
Block a user