Added initial version of advanced diagram filter config (#289)
This commit is contained in:
@@ -169,22 +169,116 @@ anyof_filter::anyof_filter(
|
||||
tvl::value_t anyof_filter::match(
|
||||
const diagram &d, const common::model::element &e) const
|
||||
{
|
||||
return tvl::any_of(filters_.begin(), filters_.end(),
|
||||
[&d, &e](const auto &f) { return f->match(d, e); });
|
||||
return match_anyof(d, e);
|
||||
}
|
||||
|
||||
tvl::value_t anyof_filter::match(
|
||||
const diagram &d, const common::model::relationship_t &r) const
|
||||
{
|
||||
return match_anyof(d, r);
|
||||
}
|
||||
|
||||
tvl::value_t anyof_filter::match(
|
||||
const diagram &d, const common::model::access_t &a) const
|
||||
{
|
||||
return match_anyof(d, a);
|
||||
}
|
||||
|
||||
tvl::value_t anyof_filter::match(
|
||||
const diagram &d, const common::model::namespace_ &ns) const
|
||||
{
|
||||
return match_anyof(d, ns);
|
||||
}
|
||||
|
||||
tvl::value_t anyof_filter::match(
|
||||
const diagram &d, const common::model::source_file &f) const
|
||||
{
|
||||
return match_anyof(d, f);
|
||||
}
|
||||
|
||||
tvl::value_t anyof_filter::match(
|
||||
const diagram &d, const common::model::source_location &f) const
|
||||
{
|
||||
return match_anyof(d, f);
|
||||
}
|
||||
|
||||
tvl::value_t anyof_filter::match(
|
||||
const diagram &d, const class_diagram::model::class_method &m) const
|
||||
{
|
||||
return match_anyof(d, m);
|
||||
}
|
||||
|
||||
tvl::value_t anyof_filter::match(
|
||||
const diagram &d, const class_diagram::model::class_member &m) const
|
||||
{
|
||||
return match_anyof(d, m);
|
||||
}
|
||||
|
||||
tvl::value_t anyof_filter::match(
|
||||
const diagram &d, const sequence_diagram::model::participant &p) const
|
||||
{
|
||||
return tvl::any_of(filters_.begin(), filters_.end(),
|
||||
[&d, &p](const auto &f) { return f->match(d, p); });
|
||||
return match_anyof(d, p);
|
||||
}
|
||||
|
||||
tvl::value_t anyof_filter::match(
|
||||
const diagram &d, const common::model::source_file &e) const
|
||||
allof_filter::allof_filter(
|
||||
filter_t type, std::vector<std::unique_ptr<filter_visitor>> filters)
|
||||
: filter_visitor{type}
|
||||
, filters_{std::move(filters)}
|
||||
{
|
||||
return tvl::any_of(filters_.begin(), filters_.end(),
|
||||
[&d, &e](const auto &f) { return f->match(d, e); });
|
||||
}
|
||||
|
||||
tvl::value_t allof_filter::match(
|
||||
const diagram &d, const common::model::element &e) const
|
||||
{
|
||||
return match_allof(d, e);
|
||||
}
|
||||
|
||||
tvl::value_t allof_filter::match(
|
||||
const diagram &d, const common::model::relationship_t &r) const
|
||||
{
|
||||
return match_allof(d, r);
|
||||
}
|
||||
|
||||
tvl::value_t allof_filter::match(
|
||||
const diagram &d, const common::model::access_t &a) const
|
||||
{
|
||||
return match_allof(d, a);
|
||||
}
|
||||
|
||||
tvl::value_t allof_filter::match(
|
||||
const diagram &d, const common::model::namespace_ &ns) const
|
||||
{
|
||||
return match_allof(d, ns);
|
||||
}
|
||||
|
||||
tvl::value_t allof_filter::match(
|
||||
const diagram &d, const common::model::source_file &f) const
|
||||
{
|
||||
return match_allof(d, f);
|
||||
}
|
||||
|
||||
tvl::value_t allof_filter::match(
|
||||
const diagram &d, const common::model::source_location &f) const
|
||||
{
|
||||
return match_allof(d, f);
|
||||
}
|
||||
|
||||
tvl::value_t allof_filter::match(
|
||||
const diagram &d, const class_diagram::model::class_method &m) const
|
||||
{
|
||||
return match_allof(d, m);
|
||||
}
|
||||
|
||||
tvl::value_t allof_filter::match(
|
||||
const diagram &d, const class_diagram::model::class_member &m) const
|
||||
{
|
||||
return match_allof(d, m);
|
||||
}
|
||||
|
||||
tvl::value_t allof_filter::match(
|
||||
const diagram &d, const sequence_diagram::model::participant &p) const
|
||||
{
|
||||
return match_allof(d, p);
|
||||
}
|
||||
|
||||
namespace_filter::namespace_filter(
|
||||
@@ -978,6 +1072,15 @@ diagram_filter::diagram_filter(const common::model::diagram &d,
|
||||
{
|
||||
}
|
||||
|
||||
void diagram_filter::add_filter(
|
||||
filter_t filter_type, std::unique_ptr<filter_visitor> fv)
|
||||
{
|
||||
if (filter_type == filter_t::kInclusive)
|
||||
add_inclusive_filter(std::move(fv));
|
||||
else
|
||||
add_exclusive_filter(std::move(fv));
|
||||
}
|
||||
|
||||
void diagram_filter::add_inclusive_filter(std::unique_ptr<filter_visitor> fv)
|
||||
{
|
||||
inclusive_.emplace_back(std::move(fv));
|
||||
|
||||
@@ -128,12 +128,81 @@ struct anyof_filter : public filter_visitor {
|
||||
const diagram &d, const common::model::element &e) const override;
|
||||
|
||||
tvl::value_t match(const diagram &d,
|
||||
const sequence_diagram::model::participant &p) const override;
|
||||
const common::model::relationship_t &r) const override;
|
||||
|
||||
tvl::value_t match(
|
||||
const diagram &d, const common::model::source_file &e) const override;
|
||||
const diagram &d, const common::model::access_t &a) const override;
|
||||
|
||||
tvl::value_t match(
|
||||
const diagram &d, const common::model::namespace_ &ns) const override;
|
||||
|
||||
tvl::value_t match(
|
||||
const diagram &d, const common::model::source_file &f) const override;
|
||||
|
||||
tvl::value_t match(const diagram &d,
|
||||
const common::model::source_location &f) const override;
|
||||
|
||||
tvl::value_t match(const diagram &d,
|
||||
const class_diagram::model::class_method &m) const override;
|
||||
|
||||
tvl::value_t match(const diagram &d,
|
||||
const class_diagram::model::class_member &m) const override;
|
||||
|
||||
tvl::value_t match(const diagram &d,
|
||||
const sequence_diagram::model::participant &p) const override;
|
||||
|
||||
private:
|
||||
template <typename E>
|
||||
tvl::value_t match_anyof(const diagram &d, const E &element) const
|
||||
{
|
||||
return tvl::any_of(filters_.begin(), filters_.end(),
|
||||
[&d, &element](const auto &f) { return f->match(d, element); });
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<filter_visitor>> filters_;
|
||||
};
|
||||
|
||||
struct allof_filter : public filter_visitor {
|
||||
allof_filter(
|
||||
filter_t type, std::vector<std::unique_ptr<filter_visitor>> filters);
|
||||
|
||||
~allof_filter() override = default;
|
||||
|
||||
tvl::value_t match(
|
||||
const diagram &d, const common::model::element &e) const override;
|
||||
|
||||
tvl::value_t match(const diagram &d,
|
||||
const common::model::relationship_t &r) const override;
|
||||
|
||||
tvl::value_t match(
|
||||
const diagram &d, const common::model::access_t &a) const override;
|
||||
|
||||
tvl::value_t match(
|
||||
const diagram &d, const common::model::namespace_ &ns) const override;
|
||||
|
||||
tvl::value_t match(
|
||||
const diagram &d, const common::model::source_file &f) const override;
|
||||
|
||||
tvl::value_t match(const diagram &d,
|
||||
const common::model::source_location &f) const override;
|
||||
|
||||
tvl::value_t match(const diagram &d,
|
||||
const class_diagram::model::class_method &m) const override;
|
||||
|
||||
tvl::value_t match(const diagram &d,
|
||||
const class_diagram::model::class_member &m) const override;
|
||||
|
||||
tvl::value_t match(const diagram &d,
|
||||
const sequence_diagram::model::participant &p) const override;
|
||||
|
||||
private:
|
||||
template <typename E>
|
||||
tvl::value_t match_allof(const diagram &d, const E &element) const
|
||||
{
|
||||
return tvl::all_of(filters_.begin(), filters_.end(),
|
||||
[&d, &element](const auto &f) { return f->match(d, element); });
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<filter_visitor>> filters_;
|
||||
};
|
||||
|
||||
@@ -681,6 +750,8 @@ public:
|
||||
diagram_filter(const common::model::diagram &d, const config::diagram &c,
|
||||
private_constructor_tag_t unused);
|
||||
|
||||
void add_filter(filter_t filter_type, std::unique_ptr<filter_visitor> fv);
|
||||
|
||||
/**
|
||||
* Add inclusive filter.
|
||||
*
|
||||
|
||||
@@ -44,92 +44,92 @@ using source_file_dependency_filter_t =
|
||||
common::model::source_file, std::string, common::model::source_file>;
|
||||
}
|
||||
|
||||
void basic_diagram_filter_initializer::initialize(
|
||||
const config::diagram &c, diagram_filter &df)
|
||||
void basic_diagram_filter_initializer::initialize()
|
||||
{
|
||||
// Process inclusive filters
|
||||
if (c.include) {
|
||||
if (diagram_config.include) {
|
||||
df.add_inclusive_filter(std::make_unique<namespace_filter>(
|
||||
filter_t::kInclusive, c.include().namespaces));
|
||||
filter_t::kInclusive, diagram_config.include().namespaces));
|
||||
|
||||
df.add_inclusive_filter(std::make_unique<modules_filter>(
|
||||
filter_t::kInclusive, c.include().modules));
|
||||
filter_t::kInclusive, diagram_config.include().modules));
|
||||
|
||||
df.add_inclusive_filter(std::make_unique<module_access_filter>(
|
||||
filter_t::kInclusive, c.include().module_access));
|
||||
filter_t::kInclusive, diagram_config.include().module_access));
|
||||
|
||||
df.add_inclusive_filter(std::make_unique<relationship_filter>(
|
||||
filter_t::kInclusive, c.include().relationships));
|
||||
filter_t::kInclusive, diagram_config.include().relationships));
|
||||
|
||||
df.add_inclusive_filter(std::make_unique<access_filter>(
|
||||
filter_t::kInclusive, c.include().access));
|
||||
filter_t::kInclusive, diagram_config.include().access));
|
||||
|
||||
df.add_inclusive_filter(std::make_unique<paths_filter>(
|
||||
filter_t::kInclusive, c.root_directory(), c.include().paths));
|
||||
filter_t::kInclusive, diagram_config.root_directory(),
|
||||
diagram_config.include().paths));
|
||||
|
||||
df.add_inclusive_filter(
|
||||
std::make_unique<class_method_filter>(filter_t::kInclusive,
|
||||
std::make_unique<access_filter>(
|
||||
filter_t::kInclusive, c.include().access),
|
||||
std::make_unique<method_type_filter>(
|
||||
filter_t::kInclusive, c.include().method_types)));
|
||||
filter_t::kInclusive, diagram_config.include().access),
|
||||
std::make_unique<method_type_filter>(filter_t::kInclusive,
|
||||
diagram_config.include().method_types)));
|
||||
|
||||
df.add_inclusive_filter(
|
||||
std::make_unique<class_member_filter>(filter_t::kInclusive,
|
||||
std::make_unique<access_filter>(
|
||||
filter_t::kInclusive, c.include().access)));
|
||||
filter_t::kInclusive, diagram_config.include().access)));
|
||||
|
||||
// Include any of these matches even if one them does not match
|
||||
std::vector<std::unique_ptr<filter_visitor>> element_filters;
|
||||
|
||||
element_filters.emplace_back(std::make_unique<element_filter>(
|
||||
filter_t::kInclusive, c.include().elements));
|
||||
filter_t::kInclusive, diagram_config.include().elements));
|
||||
|
||||
element_filters.emplace_back(std::make_unique<element_type_filter>(
|
||||
filter_t::kInclusive, c.include().element_types));
|
||||
filter_t::kInclusive, diagram_config.include().element_types));
|
||||
|
||||
if (c.type() == diagram_t::kClass) {
|
||||
if (diagram_config.type() == diagram_t::kClass) {
|
||||
element_filters.emplace_back(std::make_unique<subclass_filter>(
|
||||
filter_t::kInclusive, c.include().subclasses));
|
||||
filter_t::kInclusive, diagram_config.include().subclasses));
|
||||
|
||||
element_filters.emplace_back(std::make_unique<parents_filter>(
|
||||
filter_t::kInclusive, c.include().parents));
|
||||
filter_t::kInclusive, diagram_config.include().parents));
|
||||
|
||||
element_filters.emplace_back(
|
||||
std::make_unique<specializations_filter_t>(filter_t::kInclusive,
|
||||
relationship_t::kInstantiation,
|
||||
c.include().specializations));
|
||||
diagram_config.include().specializations));
|
||||
|
||||
element_filters.emplace_back(
|
||||
std::make_unique<class_dependants_filter_t>(
|
||||
filter_t::kInclusive, relationship_t::kDependency,
|
||||
c.include().dependants));
|
||||
diagram_config.include().dependants));
|
||||
|
||||
element_filters.emplace_back(
|
||||
std::make_unique<class_dependencies_filter_t>(
|
||||
filter_t::kInclusive, relationship_t::kDependency,
|
||||
c.include().dependencies, true));
|
||||
diagram_config.include().dependencies, true));
|
||||
}
|
||||
else if (c.type() == diagram_t::kSequence) {
|
||||
else if (diagram_config.type() == diagram_t::kSequence) {
|
||||
element_filters.emplace_back(std::make_unique<callee_filter>(
|
||||
filter_t::kInclusive, c.include().callee_types));
|
||||
filter_t::kInclusive, diagram_config.include().callee_types));
|
||||
}
|
||||
else if (c.type() == diagram_t::kPackage) {
|
||||
else if (diagram_config.type() == diagram_t::kPackage) {
|
||||
element_filters.emplace_back(
|
||||
std::make_unique<package_dependants_filter_t>(
|
||||
filter_t::kInclusive, relationship_t::kDependency,
|
||||
c.include().dependants));
|
||||
diagram_config.include().dependants));
|
||||
|
||||
element_filters.emplace_back(
|
||||
std::make_unique<package_dependencies_filter_t>(
|
||||
filter_t::kInclusive, relationship_t::kDependency,
|
||||
c.include().dependencies, true));
|
||||
diagram_config.include().dependencies, true));
|
||||
}
|
||||
else if (c.type() == diagram_t::kInclude) {
|
||||
else if (diagram_config.type() == diagram_t::kInclude) {
|
||||
std::vector<std::string> dependants;
|
||||
std::vector<std::string> dependencies;
|
||||
|
||||
for (auto &&path : c.include().dependants) {
|
||||
for (auto &&path : diagram_config.include().dependants) {
|
||||
if (auto p = path.get<std::string>(); p.has_value()) {
|
||||
const std::filesystem::path dep_path{*p};
|
||||
dependants.emplace_back(
|
||||
@@ -137,7 +137,7 @@ void basic_diagram_filter_initializer::initialize(
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &&path : c.include().dependencies) {
|
||||
for (auto &&path : diagram_config.include().dependencies) {
|
||||
if (auto p = path.get<std::string>(); p.has_value()) {
|
||||
const std::filesystem::path dep_path{*p};
|
||||
dependencies.emplace_back(
|
||||
@@ -157,90 +157,91 @@ void basic_diagram_filter_initializer::initialize(
|
||||
}
|
||||
|
||||
element_filters.emplace_back(std::make_unique<context_filter>(
|
||||
filter_t::kInclusive, c.include().context));
|
||||
filter_t::kInclusive, diagram_config.include().context));
|
||||
|
||||
df.add_inclusive_filter(std::make_unique<anyof_filter>(
|
||||
filter_t::kInclusive, std::move(element_filters)));
|
||||
}
|
||||
|
||||
// Process exclusive filters
|
||||
if (c.exclude) {
|
||||
if (diagram_config.exclude) {
|
||||
df.add_exclusive_filter(std::make_unique<namespace_filter>(
|
||||
filter_t::kExclusive, c.exclude().namespaces));
|
||||
filter_t::kExclusive, diagram_config.exclude().namespaces));
|
||||
|
||||
df.add_exclusive_filter(std::make_unique<modules_filter>(
|
||||
filter_t::kExclusive, c.exclude().modules));
|
||||
filter_t::kExclusive, diagram_config.exclude().modules));
|
||||
|
||||
df.add_exclusive_filter(std::make_unique<module_access_filter>(
|
||||
filter_t::kExclusive, c.exclude().module_access));
|
||||
filter_t::kExclusive, diagram_config.exclude().module_access));
|
||||
|
||||
df.add_exclusive_filter(std::make_unique<paths_filter>(
|
||||
filter_t::kExclusive, c.root_directory(), c.exclude().paths));
|
||||
filter_t::kExclusive, diagram_config.root_directory(),
|
||||
diagram_config.exclude().paths));
|
||||
|
||||
df.add_exclusive_filter(std::make_unique<element_filter>(
|
||||
filter_t::kExclusive, c.exclude().elements));
|
||||
filter_t::kExclusive, diagram_config.exclude().elements));
|
||||
|
||||
df.add_exclusive_filter(std::make_unique<element_type_filter>(
|
||||
filter_t::kExclusive, c.exclude().element_types));
|
||||
filter_t::kExclusive, diagram_config.exclude().element_types));
|
||||
|
||||
df.add_exclusive_filter(std::make_unique<relationship_filter>(
|
||||
filter_t::kExclusive, c.exclude().relationships));
|
||||
filter_t::kExclusive, diagram_config.exclude().relationships));
|
||||
|
||||
df.add_exclusive_filter(std::make_unique<access_filter>(
|
||||
filter_t::kExclusive, c.exclude().access));
|
||||
filter_t::kExclusive, diagram_config.exclude().access));
|
||||
|
||||
df.add_exclusive_filter(
|
||||
std::make_unique<class_method_filter>(filter_t::kExclusive,
|
||||
std::make_unique<access_filter>(
|
||||
filter_t::kExclusive, c.exclude().access),
|
||||
std::make_unique<method_type_filter>(
|
||||
filter_t::kExclusive, c.exclude().method_types)));
|
||||
filter_t::kExclusive, diagram_config.exclude().access),
|
||||
std::make_unique<method_type_filter>(filter_t::kExclusive,
|
||||
diagram_config.exclude().method_types)));
|
||||
|
||||
df.add_exclusive_filter(
|
||||
std::make_unique<class_member_filter>(filter_t::kExclusive,
|
||||
std::make_unique<access_filter>(
|
||||
filter_t::kExclusive, c.exclude().access)));
|
||||
filter_t::kExclusive, diagram_config.exclude().access)));
|
||||
|
||||
df.add_exclusive_filter(std::make_unique<subclass_filter>(
|
||||
filter_t::kExclusive, c.exclude().subclasses));
|
||||
filter_t::kExclusive, diagram_config.exclude().subclasses));
|
||||
|
||||
df.add_exclusive_filter(std::make_unique<parents_filter>(
|
||||
filter_t::kExclusive, c.exclude().parents));
|
||||
filter_t::kExclusive, diagram_config.exclude().parents));
|
||||
|
||||
df.add_exclusive_filter(
|
||||
std::make_unique<specializations_filter_t>(filter_t::kExclusive,
|
||||
relationship_t::kInstantiation, c.exclude().specializations));
|
||||
df.add_exclusive_filter(std::make_unique<specializations_filter_t>(
|
||||
filter_t::kExclusive, relationship_t::kInstantiation,
|
||||
diagram_config.exclude().specializations));
|
||||
|
||||
if (c.type() == diagram_t::kClass) {
|
||||
if (diagram_config.type() == diagram_t::kClass) {
|
||||
df.add_exclusive_filter(std::make_unique<class_dependants_filter_t>(
|
||||
filter_t::kExclusive, relationship_t::kDependency,
|
||||
c.exclude().dependants));
|
||||
diagram_config.exclude().dependants));
|
||||
|
||||
df.add_exclusive_filter(
|
||||
std::make_unique<class_dependencies_filter_t>(
|
||||
filter_t::kExclusive, relationship_t::kDependency,
|
||||
c.exclude().dependencies, true));
|
||||
diagram_config.exclude().dependencies, true));
|
||||
}
|
||||
else if (c.type() == diagram_t::kSequence) {
|
||||
else if (diagram_config.type() == diagram_t::kSequence) {
|
||||
df.add_exclusive_filter(std::make_unique<callee_filter>(
|
||||
filter_t::kExclusive, c.exclude().callee_types));
|
||||
filter_t::kExclusive, diagram_config.exclude().callee_types));
|
||||
}
|
||||
else if (c.type() == diagram_t::kPackage) {
|
||||
else if (diagram_config.type() == diagram_t::kPackage) {
|
||||
df.add_exclusive_filter(
|
||||
std::make_unique<package_dependencies_filter_t>(
|
||||
filter_t::kExclusive, relationship_t::kDependency,
|
||||
c.exclude().dependencies, true));
|
||||
diagram_config.exclude().dependencies, true));
|
||||
|
||||
df.add_exclusive_filter(
|
||||
std::make_unique<package_dependants_filter_t>(
|
||||
filter_t::kExclusive, relationship_t::kDependency,
|
||||
c.exclude().dependants));
|
||||
diagram_config.exclude().dependants));
|
||||
}
|
||||
else if (c.type() == diagram_t::kInclude) {
|
||||
else if (diagram_config.type() == diagram_t::kInclude) {
|
||||
std::vector<std::string> dependants;
|
||||
std::vector<std::string> dependencies;
|
||||
|
||||
for (auto &&path : c.exclude().dependants) {
|
||||
for (auto &&path : diagram_config.exclude().dependants) {
|
||||
if (auto p = path.get<std::string>(); p.has_value()) {
|
||||
std::filesystem::path dep_path{*p};
|
||||
dependants.emplace_back(
|
||||
@@ -248,7 +249,7 @@ void basic_diagram_filter_initializer::initialize(
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &&path : c.exclude().dependencies) {
|
||||
for (auto &&path : diagram_config.exclude().dependencies) {
|
||||
if (auto p = path.get<std::string>(); p.has_value()) {
|
||||
std::filesystem::path dep_path{*p};
|
||||
dependencies.emplace_back(
|
||||
@@ -268,13 +269,129 @@ void basic_diagram_filter_initializer::initialize(
|
||||
}
|
||||
|
||||
df.add_exclusive_filter(std::make_unique<context_filter>(
|
||||
filter_t::kExclusive, c.exclude().context));
|
||||
filter_t::kExclusive, diagram_config.exclude().context));
|
||||
}
|
||||
}
|
||||
|
||||
void advanced_diagram_filter_initializer::initialize(
|
||||
const config::diagram &c, diagram_filter &df)
|
||||
std::vector<std::unique_ptr<filter_visitor>>
|
||||
advanced_diagram_filter_initializer::build(
|
||||
filter_t filter_type, const config::filter &filter_config)
|
||||
{
|
||||
std::vector<std::unique_ptr<filter_visitor>> result;
|
||||
|
||||
// At any level, only allof, anyof, or a set of other non-operator
|
||||
// filters can be present
|
||||
if (filter_config.allof) {
|
||||
std::vector<std::unique_ptr<filter_visitor>> allof_filters =
|
||||
build(filter_type, *filter_config.allof);
|
||||
|
||||
auto allof_filter = std::make_unique<common::model::allof_filter>(
|
||||
filter_type, std::move(allof_filters));
|
||||
|
||||
result.emplace_back(std::move(allof_filter));
|
||||
}
|
||||
|
||||
if (filter_config.anyof) {
|
||||
std::vector<std::unique_ptr<filter_visitor>> anyof_filters =
|
||||
build(filter_type, *filter_config.anyof);
|
||||
|
||||
auto anyof_filter = std::make_unique<common::model::anyof_filter>(
|
||||
filter_type, std::move(anyof_filters));
|
||||
|
||||
result.emplace_back(std::move(anyof_filter));
|
||||
}
|
||||
|
||||
add_filter<namespace_filter>(filter_type, filter_config.namespaces, result);
|
||||
add_filter<modules_filter>(filter_type, filter_config.modules, result);
|
||||
add_filter<module_access_filter>(
|
||||
filter_type, filter_config.module_access, result);
|
||||
add_filter<relationship_filter>(
|
||||
filter_type, filter_config.relationships, result);
|
||||
add_filter<access_filter>(filter_type, filter_config.access, result);
|
||||
|
||||
if (!filter_config.method_types.empty()) {
|
||||
result.emplace_back(std::make_unique<class_method_filter>(filter_type,
|
||||
std::make_unique<access_filter>(
|
||||
filter_t::kInclusive, filter_config.access),
|
||||
std::make_unique<method_type_filter>(
|
||||
filter_t::kInclusive, filter_config.method_types)));
|
||||
}
|
||||
|
||||
if (!filter_config.paths.empty()) {
|
||||
result.emplace_back(std::make_unique<paths_filter>(
|
||||
filter_type, diagram_config.root_directory(), filter_config.paths));
|
||||
}
|
||||
|
||||
if (!filter_config.access.empty())
|
||||
result.emplace_back(std::make_unique<class_member_filter>(filter_type,
|
||||
std::make_unique<access_filter>(
|
||||
filter_type, filter_config.access)));
|
||||
|
||||
add_filter<element_filter>(filter_type, filter_config.elements, result);
|
||||
add_filter<element_type_filter>(
|
||||
filter_type, filter_config.element_types, result);
|
||||
add_filter<subclass_filter>(filter_type, filter_config.subclasses, result);
|
||||
add_filter<parents_filter>(filter_type, filter_config.parents, result);
|
||||
|
||||
add_edge_filter<specializations_filter_t>(filter_type,
|
||||
filter_config.specializations, relationship_t::kInstantiation, false,
|
||||
result);
|
||||
add_edge_filter<class_dependants_filter_t>(filter_type,
|
||||
filter_config.dependants, relationship_t::kDependency, false, result);
|
||||
add_edge_filter<class_dependencies_filter_t>(filter_type,
|
||||
filter_config.dependencies, relationship_t::kDependency, true, result);
|
||||
|
||||
add_filter<callee_filter>(filter_type, filter_config.callee_types, result);
|
||||
|
||||
add_edge_filter<package_dependants_filter_t>(filter_type,
|
||||
filter_config.dependants, relationship_t::kDependency, false, result);
|
||||
add_edge_filter<package_dependencies_filter_t>(filter_type,
|
||||
filter_config.dependencies, relationship_t::kDependency, true, result);
|
||||
|
||||
add_filter<context_filter>(filter_type, filter_config.context, result);
|
||||
|
||||
if (diagram_config.type() == diagram_t::kInclude) {
|
||||
std::vector<std::string> dependants;
|
||||
std::vector<std::string> dependencies;
|
||||
|
||||
for (auto &&path : filter_config.dependants) {
|
||||
if (auto p = path.get<std::string>(); p.has_value()) {
|
||||
const std::filesystem::path dep_path{*p};
|
||||
dependants.emplace_back(dep_path.lexically_normal().string());
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &&path : filter_config.dependencies) {
|
||||
if (auto p = path.get<std::string>(); p.has_value()) {
|
||||
const std::filesystem::path dep_path{*p};
|
||||
dependencies.emplace_back(dep_path.lexically_normal().string());
|
||||
}
|
||||
}
|
||||
|
||||
add_edge_filter<source_file_dependency_filter_t>(filter_type,
|
||||
dependants, relationship_t::kAssociation, false, result);
|
||||
add_edge_filter<source_file_dependency_filter_t>(filter_type,
|
||||
dependencies, relationship_t::kAssociation, true, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void advanced_diagram_filter_initializer::initialize()
|
||||
{
|
||||
if (diagram_config.include) {
|
||||
auto inclusive_filter =
|
||||
build(filter_t::kInclusive, diagram_config.include());
|
||||
for (auto &f : inclusive_filter)
|
||||
df.add_filter(filter_t::kInclusive, std::move(f));
|
||||
}
|
||||
|
||||
if (diagram_config.exclude) {
|
||||
auto exclusive_filter =
|
||||
build(filter_t::kExclusive, diagram_config.exclude());
|
||||
for (auto &f : exclusive_filter)
|
||||
df.add_filter(filter_t::kExclusive, std::move(f));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace clanguml::common::model
|
||||
|
||||
@@ -22,12 +22,57 @@
|
||||
|
||||
namespace clanguml::common::model {
|
||||
|
||||
struct basic_diagram_filter_initializer {
|
||||
void initialize(const config::diagram &c, diagram_filter &df);
|
||||
class diagram_filter_initializer {
|
||||
public:
|
||||
diagram_filter_initializer(const config::diagram &c, diagram_filter &filter)
|
||||
: diagram_config{c}
|
||||
, df{filter}
|
||||
{
|
||||
}
|
||||
|
||||
virtual void initialize() = 0;
|
||||
|
||||
protected:
|
||||
const config::diagram &diagram_config;
|
||||
diagram_filter &df;
|
||||
};
|
||||
|
||||
struct advanced_diagram_filter_initializer {
|
||||
void initialize(const config::diagram &c, diagram_filter &df);
|
||||
class basic_diagram_filter_initializer : public diagram_filter_initializer {
|
||||
public:
|
||||
using diagram_filter_initializer::diagram_filter_initializer;
|
||||
|
||||
void initialize() override;
|
||||
};
|
||||
|
||||
class advanced_diagram_filter_initializer : public diagram_filter_initializer {
|
||||
public:
|
||||
using diagram_filter_initializer::diagram_filter_initializer;
|
||||
|
||||
void initialize() override;
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<filter_visitor>> build(
|
||||
filter_t filter_type, const config::filter &filter_config);
|
||||
|
||||
template <typename FT, typename T>
|
||||
void add_filter(const filter_t &filter_type,
|
||||
const std::vector<T> &filter_config,
|
||||
std::vector<std::unique_ptr<filter_visitor>> &result)
|
||||
{
|
||||
if (!filter_config.empty())
|
||||
result.emplace_back(
|
||||
std::make_unique<FT>(filter_type, filter_config));
|
||||
}
|
||||
|
||||
template <typename FT, typename T>
|
||||
void add_edge_filter(const filter_t &filter_type,
|
||||
const std::vector<T> &filter_config, relationship_t rt, bool direction,
|
||||
std::vector<std::unique_ptr<filter_visitor>> &result)
|
||||
{
|
||||
if (!filter_config.empty())
|
||||
result.emplace_back(std::make_unique<FT>(
|
||||
filter_type, rt, filter_config, direction));
|
||||
}
|
||||
};
|
||||
|
||||
class diagram_filter_factory {
|
||||
@@ -38,9 +83,14 @@ public:
|
||||
auto filter = std::make_unique<diagram_filter>(
|
||||
d, c, diagram_filter::private_constructor_tag_t{});
|
||||
|
||||
basic_diagram_filter_initializer init;
|
||||
|
||||
init.initialize(c, *filter);
|
||||
if (c.filter_mode() == config::filter_mode_t::basic) {
|
||||
basic_diagram_filter_initializer init{c, *filter};
|
||||
init.initialize();
|
||||
}
|
||||
else {
|
||||
advanced_diagram_filter_initializer init{c, *filter};
|
||||
init.initialize();
|
||||
}
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
||||
@@ -186,6 +186,19 @@ std::string to_string(context_direction_t cd)
|
||||
}
|
||||
}
|
||||
|
||||
std::string to_string(filter_mode_t fm)
|
||||
{
|
||||
switch (fm) {
|
||||
case filter_mode_t::basic:
|
||||
return "basic";
|
||||
case filter_mode_t::advanced:
|
||||
return "advanced";
|
||||
default:
|
||||
assert(false);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<std::string> plantuml::get_style(
|
||||
const common::model::relationship_t relationship_type) const
|
||||
{
|
||||
@@ -228,6 +241,7 @@ void inheritable_diagram_options::inherit(
|
||||
using_module.override(parent.using_module);
|
||||
include_relations_also_as_members.override(
|
||||
parent.include_relations_also_as_members);
|
||||
filter_mode.override(parent.filter_mode);
|
||||
include.override(parent.include);
|
||||
exclude.override(parent.exclude);
|
||||
puml.override(parent.puml);
|
||||
|
||||
@@ -116,6 +116,13 @@ struct plantuml_keyword_mapping_t {
|
||||
relationships;
|
||||
};
|
||||
|
||||
enum class filter_mode_t {
|
||||
basic, /*!< Default filter structure without logical operators */
|
||||
advanced /*!< Advanced filter config with logical operators */
|
||||
};
|
||||
|
||||
std::string to_string(filter_mode_t cp);
|
||||
|
||||
/**
|
||||
* @brief PlantUML diagram config section
|
||||
*
|
||||
@@ -187,6 +194,9 @@ struct diagram_template {
|
||||
};
|
||||
|
||||
struct filter {
|
||||
std::shared_ptr<filter> anyof;
|
||||
std::shared_ptr<filter> allof;
|
||||
|
||||
/*! @brief Namespaces filter
|
||||
*
|
||||
* Example:
|
||||
@@ -544,6 +554,7 @@ struct inheritable_diagram_options {
|
||||
option<std::string> using_module{"using_module"};
|
||||
option<bool> include_relations_also_as_members{
|
||||
"include_relations_also_as_members", true};
|
||||
option<filter_mode_t> filter_mode{"filter_mode", filter_mode_t::basic};
|
||||
option<filter> include{"include"};
|
||||
option<filter> exclude{"exclude"};
|
||||
option<plantuml> puml{"plantuml", option_inherit_mode::kAppend};
|
||||
|
||||
@@ -156,6 +156,8 @@ types:
|
||||
paths: !optional [string]
|
||||
method_types: !optional [method_type_filter_t]
|
||||
callee_types: !optional [callee_type_filter_t]
|
||||
anyof: !optional filter_t
|
||||
allof: !optional filter_t
|
||||
function_location_t:
|
||||
function: string
|
||||
marker_location_t:
|
||||
@@ -163,6 +165,9 @@ types:
|
||||
source_location_t:
|
||||
- function_location_t
|
||||
- marker_location_t
|
||||
filter_mode_t: !variant
|
||||
- basic
|
||||
- advanced
|
||||
class_diagram_t:
|
||||
type: !variant [class]
|
||||
#
|
||||
@@ -171,6 +176,7 @@ types:
|
||||
__parent_path: !optional string
|
||||
comment_parser: !optional comment_parser_t
|
||||
debug_mode: !optional bool
|
||||
filter_mode: !optional filter_mode_t
|
||||
exclude: !optional filter_t
|
||||
generate_links: !optional generate_links_t
|
||||
git: !optional git_t
|
||||
|
||||
@@ -158,6 +158,21 @@ void get_option<clanguml::config::comment_parser_t>(const Node &node,
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void get_option<clanguml::config::filter_mode_t>(const Node &node,
|
||||
clanguml::config::option<clanguml::config::filter_mode_t> &option)
|
||||
{
|
||||
if (node[option.name]) {
|
||||
const auto &val = node[option.name].as<std::string>();
|
||||
if (val == "basic")
|
||||
option.set(clanguml::config::filter_mode_t::basic);
|
||||
else if (val == "advanced")
|
||||
option.set(clanguml::config::filter_mode_t::advanced);
|
||||
else
|
||||
throw std::runtime_error("Invalid comment_parser value: " + val);
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void get_option<std::map<std::string, clanguml::config::diagram_template>>(
|
||||
const Node &node,
|
||||
@@ -521,6 +536,14 @@ template <> struct convert<namespace_or_regex> {
|
||||
template <> struct convert<filter> {
|
||||
static bool decode(const Node &node, filter &rhs)
|
||||
{
|
||||
if (node["anyof"]) {
|
||||
rhs.anyof = std::make_unique<filter>(node["anyof"].as<filter>());
|
||||
}
|
||||
|
||||
if (node["allof"]) {
|
||||
rhs.anyof = std::make_unique<filter>(node["anyof"].as<filter>());
|
||||
}
|
||||
|
||||
if (node["namespaces"]) {
|
||||
auto namespace_list =
|
||||
node["namespaces"].as<decltype(rhs.namespaces)>();
|
||||
@@ -631,6 +654,7 @@ template <typename T> bool decode_diagram(const Node &node, T &rhs)
|
||||
get_option(node, rhs.glob);
|
||||
get_option(node, rhs.using_namespace);
|
||||
get_option(node, rhs.using_module);
|
||||
get_option(node, rhs.filter_mode);
|
||||
get_option(node, rhs.include);
|
||||
get_option(node, rhs.exclude);
|
||||
get_option(node, rhs.puml);
|
||||
@@ -849,6 +873,7 @@ template <> struct convert<config> {
|
||||
get_option(node, rhs.glob);
|
||||
get_option(node, rhs.using_namespace);
|
||||
get_option(node, rhs.using_module);
|
||||
get_option(node, rhs.filter_mode);
|
||||
get_option(node, rhs.output_directory);
|
||||
get_option(node, rhs.query_driver);
|
||||
get_option(node, rhs.allow_empty_diagrams);
|
||||
|
||||
@@ -93,6 +93,7 @@ set(TEST_NAMES
|
||||
test_config
|
||||
test_cli_handler
|
||||
test_filters
|
||||
test_filters_advanced
|
||||
test_thread_pool_executor
|
||||
test_query_driver_output_extractor
|
||||
test_progress_indicator)
|
||||
|
||||
20
tests/test_config_data/filters_advanced.yml
Normal file
20
tests/test_config_data/filters_advanced.yml
Normal file
@@ -0,0 +1,20 @@
|
||||
compilation_database_dir: debug
|
||||
output_directory: output
|
||||
diagrams:
|
||||
anyof_test:
|
||||
type: class
|
||||
relative_to: ../../../src
|
||||
glob:
|
||||
- src/**/*.cc
|
||||
- src/**/*.h
|
||||
filter_mode: advanced
|
||||
include:
|
||||
anyof:
|
||||
namespaces:
|
||||
- ns1::ns2
|
||||
elements:
|
||||
- std::thread
|
||||
exclude:
|
||||
anyof:
|
||||
namespaces:
|
||||
- ns1::ns2::detail
|
||||
88
tests/test_filters_advanced.cc
Normal file
88
tests/test_filters_advanced.cc
Normal file
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* @file tests/test_filters_advanced.cc
|
||||
*
|
||||
* Copyright (c) 2021-2024 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.
|
||||
*/
|
||||
#define DOCTEST_CONFIG_IMPLEMENT
|
||||
|
||||
#include "doctest/doctest.h"
|
||||
|
||||
#include "class_diagram/model/class.h"
|
||||
#include "cli/cli_handler.h"
|
||||
#include "common/model/filters/diagram_filter_factory.h"
|
||||
#include "common/model/source_file.h"
|
||||
#include "config/config.h"
|
||||
#include "include_diagram/model/diagram.h"
|
||||
#include "sequence_diagram/model/diagram.h"
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
TEST_CASE("Test advanced diagram filter anyof")
|
||||
{
|
||||
using clanguml::common::model::diagram_filter;
|
||||
using clanguml::common::model::diagram_filter_factory;
|
||||
using clanguml::common::model::namespace_;
|
||||
using clanguml::common::model::source_file;
|
||||
using clanguml::config::filter_mode_t;
|
||||
|
||||
auto cfg =
|
||||
clanguml::config::load("./test_config_data/filters_advanced.yml");
|
||||
|
||||
auto &config = *cfg.diagrams["anyof_test"];
|
||||
clanguml::include_diagram::model::diagram diagram;
|
||||
|
||||
auto filter_ptr = diagram_filter_factory::create(diagram, config);
|
||||
diagram_filter &filter = *filter_ptr;
|
||||
|
||||
CHECK(config.filter_mode() == filter_mode_t::advanced);
|
||||
CHECK(filter.should_include(namespace_{"ns1::ns2"}));
|
||||
CHECK_FALSE(filter.should_include(namespace_{"std::string"}));
|
||||
|
||||
clanguml::common::model::element std_thread{{}};
|
||||
std_thread.set_namespace(namespace_{"std"});
|
||||
std_thread.set_name("thread");
|
||||
CHECK(filter.should_include(std_thread));
|
||||
|
||||
std_thread.set_name("jthread");
|
||||
CHECK_FALSE(filter.should_include(std_thread));
|
||||
|
||||
CHECK_FALSE(filter.should_include(namespace_{"ns1::ns2::detail"}));
|
||||
}
|
||||
|
||||
///
|
||||
/// Main test function
|
||||
///
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
doctest::Context context;
|
||||
|
||||
context.applyCommandLine(argc, argv);
|
||||
|
||||
clanguml::cli::cli_handler clih;
|
||||
|
||||
std::vector<const char *> argvv = {
|
||||
"clang-uml", "--config", "./test_config_data/simple.yml"};
|
||||
|
||||
argvv.push_back("-q");
|
||||
|
||||
clih.handle_options(argvv.size(), argvv.data());
|
||||
|
||||
int res = context.run();
|
||||
|
||||
if (context.shouldExit())
|
||||
return res;
|
||||
|
||||
return res;
|
||||
}
|
||||
Reference in New Issue
Block a user