Refactored diagram_filter initialization to a factory (#289)

This commit is contained in:
Bartek Kryza
2024-06-24 19:40:30 +02:00
parent c0f5d5f64a
commit 19bb8ae1ca
12 changed files with 397 additions and 289 deletions

View File

@@ -18,7 +18,7 @@
#include "diagram.h" #include "diagram.h"
#include "common/model/diagram_filter.h" #include "common/model/filters/diagram_filter.h"
#include "util/error.h" #include "util/error.h"
#include "util/util.h" #include "util/util.h"

View File

@@ -22,7 +22,7 @@
#include "class_diagram/generators/plantuml/class_diagram_generator.h" #include "class_diagram/generators/plantuml/class_diagram_generator.h"
#include "cli/cli_handler.h" #include "cli/cli_handler.h"
#include "common/compilation_database.h" #include "common/compilation_database.h"
#include "common/model/diagram_filter.h" #include "common/model/filters/diagram_filter_factory.h"
#include "config/config.h" #include "config/config.h"
#include "include_diagram/generators/json/include_diagram_generator.h" #include "include_diagram/generators/json/include_diagram_generator.h"
#include "include_diagram/generators/mermaid/include_diagram_generator.h" #include "include_diagram/generators/mermaid/include_diagram_generator.h"
@@ -369,7 +369,7 @@ std::unique_ptr<DiagramModel> generate(const common::compilation_database &db,
auto diagram = std::make_unique<DiagramModel>(); auto diagram = std::make_unique<DiagramModel>();
diagram->set_name(name); diagram->set_name(name);
diagram->set_filter( diagram->set_filter(
std::make_unique<model::diagram_filter>(*diagram, config)); model::diagram_filter_factory::create(*diagram, config));
LOG_DBG("Found translation units for diagram {}: {}", name, LOG_DBG("Found translation units for diagram {}: {}", name,
fmt::join(translation_units, ", ")); fmt::join(translation_units, ", "));

View File

@@ -18,7 +18,7 @@
#pragma once #pragma once
#include "common/generators/generator.h" #include "common/generators/generator.h"
#include "common/model/diagram_filter.h" #include "common/model/filters/diagram_filter.h"
#include "config/config.h" #include "config/config.h"
#include "util/error.h" #include "util/error.h"
#include "util/util.h" #include "util/util.h"

View File

@@ -18,7 +18,7 @@
#pragma once #pragma once
#include "common/generators/generator.h" #include "common/generators/generator.h"
#include "common/model/diagram_filter.h" #include "common/model/filters/diagram_filter.h"
#include "config/config.h" #include "config/config.h"
#include "util/error.h" #include "util/error.h"
#include "util/util.h" #include "util/util.h"

View File

@@ -18,7 +18,7 @@
#pragma once #pragma once
#include "common/generators/generator.h" #include "common/generators/generator.h"
#include "common/model/diagram_filter.h" #include "common/model/filters/diagram_filter.h"
#include "common/model/relationship.h" #include "common/model/relationship.h"
#include "config/config.h" #include "config/config.h"
#include "util/error.h" #include "util/error.h"

View File

@@ -18,7 +18,7 @@
#include "diagram.h" #include "diagram.h"
#include "diagram_filter.h" #include "filters/diagram_filter.h"
#include "namespace.h" #include "namespace.h"
namespace clanguml::common::model { namespace clanguml::common::model {

View File

@@ -972,11 +972,10 @@ tvl::value_t class_member_filter::match(
return access_filter_->match(d, m.access()); return access_filter_->match(d, m.access());
} }
diagram_filter::diagram_filter( diagram_filter::diagram_filter(const common::model::diagram &d,
const common::model::diagram &d, const config::diagram &c) const config::diagram &c, private_constructor_tag_t /*unused*/)
: diagram_{d} : diagram_{d}
{ {
init_filters(c);
} }
void diagram_filter::add_inclusive_filter(std::unique_ptr<filter_visitor> fv) void diagram_filter::add_inclusive_filter(std::unique_ptr<filter_visitor> fv)
@@ -1003,254 +1002,6 @@ bool diagram_filter::should_include(
return false; return false;
} }
void diagram_filter::init_filters(const config::diagram &c)
{
using specializations_filter_t =
edge_traversal_filter<class_diagram::model::diagram,
class_diagram::model::class_, common::string_or_regex>;
using class_dependants_filter_t =
edge_traversal_filter<class_diagram::model::diagram,
class_diagram::model::class_, common::string_or_regex>;
using class_dependencies_filter_t =
edge_traversal_filter<class_diagram::model::diagram,
class_diagram::model::class_, common::string_or_regex>;
using package_dependants_filter_t =
edge_traversal_filter<package_diagram::model::diagram,
common::model::package, common::string_or_regex>;
using package_dependencies_filter_t =
edge_traversal_filter<package_diagram::model::diagram,
common::model::package, common::string_or_regex>;
using source_file_dependency_filter_t =
edge_traversal_filter<include_diagram::model::diagram,
common::model::source_file, std::string,
common::model::source_file>;
// Process inclusive filters
if (c.include) {
add_inclusive_filter(std::make_unique<namespace_filter>(
filter_t::kInclusive, c.include().namespaces));
add_inclusive_filter(std::make_unique<modules_filter>(
filter_t::kInclusive, c.include().modules));
add_inclusive_filter(std::make_unique<module_access_filter>(
filter_t::kInclusive, c.include().module_access));
add_inclusive_filter(std::make_unique<relationship_filter>(
filter_t::kInclusive, c.include().relationships));
add_inclusive_filter(std::make_unique<access_filter>(
filter_t::kInclusive, c.include().access));
add_inclusive_filter(std::make_unique<paths_filter>(
filter_t::kInclusive, c.root_directory(), c.include().paths));
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)));
add_inclusive_filter(
std::make_unique<class_member_filter>(filter_t::kInclusive,
std::make_unique<access_filter>(
filter_t::kInclusive, c.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));
element_filters.emplace_back(std::make_unique<element_type_filter>(
filter_t::kInclusive, c.include().element_types));
if (c.type() == diagram_t::kClass) {
element_filters.emplace_back(std::make_unique<subclass_filter>(
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<specializations_filter_t>(filter_t::kInclusive,
relationship_t::kInstantiation,
c.include().specializations));
element_filters.emplace_back(
std::make_unique<class_dependants_filter_t>(
filter_t::kInclusive, relationship_t::kDependency,
c.include().dependants));
element_filters.emplace_back(
std::make_unique<class_dependencies_filter_t>(
filter_t::kInclusive, relationship_t::kDependency,
c.include().dependencies, true));
}
else if (c.type() == diagram_t::kSequence) {
element_filters.emplace_back(std::make_unique<callee_filter>(
filter_t::kInclusive, c.include().callee_types));
}
else if (c.type() == diagram_t::kPackage) {
element_filters.emplace_back(
std::make_unique<package_dependants_filter_t>(
filter_t::kInclusive, relationship_t::kDependency,
c.include().dependants));
element_filters.emplace_back(
std::make_unique<package_dependencies_filter_t>(
filter_t::kInclusive, relationship_t::kDependency,
c.include().dependencies, true));
}
else if (c.type() == diagram_t::kInclude) {
std::vector<std::string> dependants;
std::vector<std::string> dependencies;
for (auto &&path : c.include().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 : c.include().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());
}
}
element_filters.emplace_back(
std::make_unique<source_file_dependency_filter_t>(
filter_t::kInclusive, relationship_t::kAssociation,
dependants, false));
element_filters.emplace_back(
std::make_unique<source_file_dependency_filter_t>(
filter_t::kInclusive, relationship_t::kAssociation,
dependencies, true));
}
element_filters.emplace_back(std::make_unique<context_filter>(
filter_t::kInclusive, c.include().context));
add_inclusive_filter(std::make_unique<anyof_filter>(
filter_t::kInclusive, std::move(element_filters)));
}
// Process exclusive filters
if (c.exclude) {
add_exclusive_filter(std::make_unique<namespace_filter>(
filter_t::kExclusive, c.exclude().namespaces));
add_exclusive_filter(std::make_unique<modules_filter>(
filter_t::kExclusive, c.exclude().modules));
add_exclusive_filter(std::make_unique<module_access_filter>(
filter_t::kExclusive, c.exclude().module_access));
add_exclusive_filter(std::make_unique<paths_filter>(
filter_t::kExclusive, c.root_directory(), c.exclude().paths));
add_exclusive_filter(std::make_unique<element_filter>(
filter_t::kExclusive, c.exclude().elements));
add_exclusive_filter(std::make_unique<element_type_filter>(
filter_t::kExclusive, c.exclude().element_types));
add_exclusive_filter(std::make_unique<relationship_filter>(
filter_t::kExclusive, c.exclude().relationships));
add_exclusive_filter(std::make_unique<access_filter>(
filter_t::kExclusive, c.exclude().access));
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)));
add_exclusive_filter(
std::make_unique<class_member_filter>(filter_t::kExclusive,
std::make_unique<access_filter>(
filter_t::kExclusive, c.exclude().access)));
add_exclusive_filter(std::make_unique<subclass_filter>(
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<specializations_filter_t>(filter_t::kExclusive,
relationship_t::kInstantiation, c.exclude().specializations));
if (c.type() == diagram_t::kClass) {
add_exclusive_filter(std::make_unique<class_dependants_filter_t>(
filter_t::kExclusive, relationship_t::kDependency,
c.exclude().dependants));
add_exclusive_filter(std::make_unique<class_dependencies_filter_t>(
filter_t::kExclusive, relationship_t::kDependency,
c.exclude().dependencies, true));
}
else if (c.type() == diagram_t::kSequence) {
add_exclusive_filter(std::make_unique<callee_filter>(
filter_t::kExclusive, c.exclude().callee_types));
}
else if (c.type() == diagram_t::kPackage) {
add_exclusive_filter(
std::make_unique<package_dependencies_filter_t>(
filter_t::kExclusive, relationship_t::kDependency,
c.exclude().dependencies, true));
add_exclusive_filter(std::make_unique<package_dependants_filter_t>(
filter_t::kExclusive, relationship_t::kDependency,
c.exclude().dependants));
}
else if (c.type() == diagram_t::kInclude) {
std::vector<std::string> dependants;
std::vector<std::string> dependencies;
for (auto &&path : c.exclude().dependants) {
if (auto p = path.get<std::string>(); p.has_value()) {
std::filesystem::path dep_path{*p};
dependants.emplace_back(
dep_path.lexically_normal().string());
}
}
for (auto &&path : c.exclude().dependencies) {
if (auto p = path.get<std::string>(); p.has_value()) {
std::filesystem::path dep_path{*p};
dependencies.emplace_back(
dep_path.lexically_normal().string());
}
}
add_exclusive_filter(
std::make_unique<source_file_dependency_filter_t>(
filter_t::kExclusive, relationship_t::kAssociation,
dependants, false));
add_exclusive_filter(
std::make_unique<source_file_dependency_filter_t>(
filter_t::kExclusive, relationship_t::kAssociation,
dependencies, true));
}
add_exclusive_filter(std::make_unique<context_filter>(
filter_t::kExclusive, c.exclude().context));
}
}
template <> template <>
bool diagram_filter::should_include<std::string>(const std::string &name) const bool diagram_filter::should_include<std::string>(const std::string &name) const
{ {

View File

@@ -1,5 +1,5 @@
/** /**
* @file src/common/model/diagram_filter.h * @file src/common/model/filters/diagram_filter.h
* *
* Copyright (c) 2021-2024 Bartek Kryza <bkryza@gmail.com> * Copyright (c) 2021-2024 Bartek Kryza <bkryza@gmail.com>
* *
@@ -25,18 +25,19 @@
#include "common/model/element.h" #include "common/model/element.h"
#include "common/model/enums.h" #include "common/model/enums.h"
#include "common/model/namespace.h" #include "common/model/namespace.h"
#include "common/model/source_file.h"
#include "common/model/tvl.h"
#include "config/config.h" #include "config/config.h"
#include "diagram.h"
#include "include_diagram/model/diagram.h" #include "include_diagram/model/diagram.h"
#include "sequence_diagram/model/participant.h" #include "sequence_diagram/model/participant.h"
#include "source_file.h"
#include "tvl.h"
#include <filesystem> #include <filesystem>
#include <utility> #include <utility>
namespace clanguml::common::model { namespace clanguml::common::model {
class diagram_filter_factory;
using clanguml::common::eid_t; using clanguml::common::eid_t;
/** /**
@@ -660,6 +661,8 @@ private:
std::unique_ptr<access_filter> access_filter_; std::unique_ptr<access_filter> access_filter_;
}; };
class diagram_filter_factory;
/** /**
* @brief Composite of all diagrams filters. * @brief Composite of all diagrams filters.
* *
@@ -671,8 +674,12 @@ private:
* @see clanguml::common::model::filter_visitor * @see clanguml::common::model::filter_visitor
*/ */
class diagram_filter { class diagram_filter {
private:
struct private_constructor_tag_t { };
public: public:
diagram_filter(const common::model::diagram &d, const config::diagram &c); diagram_filter(const common::model::diagram &d, const config::diagram &c,
private_constructor_tag_t unused);
/** /**
* Add inclusive filter. * Add inclusive filter.
@@ -725,6 +732,8 @@ public:
return static_cast<bool>(tvl::is_undefined(inc) || tvl::is_true(inc)); return static_cast<bool>(tvl::is_undefined(inc) || tvl::is_true(inc));
} }
friend class diagram_filter_factory;
private: private:
/** /**
* @brief Initialize filters. * @brief Initialize filters.
@@ -733,7 +742,7 @@ private:
* *
* @param c Diagram config. * @param c Diagram config.
*/ */
void init_filters(const config::diagram &c); // void init_filters(const config::diagram &c);
/*! List of inclusive filters */ /*! List of inclusive filters */
std::vector<std::unique_ptr<filter_visitor>> inclusive_; std::vector<std::unique_ptr<filter_visitor>> inclusive_;

View File

@@ -0,0 +1,280 @@
/**
* @file src/common/model/filters/diagram_filter_factory.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.
*/
#include "diagram_filter_factory.h"
namespace clanguml::common::model {
namespace {
using specializations_filter_t =
edge_traversal_filter<class_diagram::model::diagram,
class_diagram::model::class_, common::string_or_regex>;
using class_dependants_filter_t =
edge_traversal_filter<class_diagram::model::diagram,
class_diagram::model::class_, common::string_or_regex>;
using class_dependencies_filter_t =
edge_traversal_filter<class_diagram::model::diagram,
class_diagram::model::class_, common::string_or_regex>;
using package_dependants_filter_t =
edge_traversal_filter<package_diagram::model::diagram,
common::model::package, common::string_or_regex>;
using package_dependencies_filter_t =
edge_traversal_filter<package_diagram::model::diagram,
common::model::package, common::string_or_regex>;
using source_file_dependency_filter_t =
edge_traversal_filter<include_diagram::model::diagram,
common::model::source_file, std::string, common::model::source_file>;
}
void basic_diagram_filter_initializer::initialize(
const config::diagram &c, diagram_filter &df)
{
// Process inclusive filters
if (c.include) {
df.add_inclusive_filter(std::make_unique<namespace_filter>(
filter_t::kInclusive, c.include().namespaces));
df.add_inclusive_filter(std::make_unique<modules_filter>(
filter_t::kInclusive, c.include().modules));
df.add_inclusive_filter(std::make_unique<module_access_filter>(
filter_t::kInclusive, c.include().module_access));
df.add_inclusive_filter(std::make_unique<relationship_filter>(
filter_t::kInclusive, c.include().relationships));
df.add_inclusive_filter(std::make_unique<access_filter>(
filter_t::kInclusive, c.include().access));
df.add_inclusive_filter(std::make_unique<paths_filter>(
filter_t::kInclusive, c.root_directory(), c.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)));
df.add_inclusive_filter(
std::make_unique<class_member_filter>(filter_t::kInclusive,
std::make_unique<access_filter>(
filter_t::kInclusive, c.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));
element_filters.emplace_back(std::make_unique<element_type_filter>(
filter_t::kInclusive, c.include().element_types));
if (c.type() == diagram_t::kClass) {
element_filters.emplace_back(std::make_unique<subclass_filter>(
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<specializations_filter_t>(filter_t::kInclusive,
relationship_t::kInstantiation,
c.include().specializations));
element_filters.emplace_back(
std::make_unique<class_dependants_filter_t>(
filter_t::kInclusive, relationship_t::kDependency,
c.include().dependants));
element_filters.emplace_back(
std::make_unique<class_dependencies_filter_t>(
filter_t::kInclusive, relationship_t::kDependency,
c.include().dependencies, true));
}
else if (c.type() == diagram_t::kSequence) {
element_filters.emplace_back(std::make_unique<callee_filter>(
filter_t::kInclusive, c.include().callee_types));
}
else if (c.type() == diagram_t::kPackage) {
element_filters.emplace_back(
std::make_unique<package_dependants_filter_t>(
filter_t::kInclusive, relationship_t::kDependency,
c.include().dependants));
element_filters.emplace_back(
std::make_unique<package_dependencies_filter_t>(
filter_t::kInclusive, relationship_t::kDependency,
c.include().dependencies, true));
}
else if (c.type() == diagram_t::kInclude) {
std::vector<std::string> dependants;
std::vector<std::string> dependencies;
for (auto &&path : c.include().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 : c.include().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());
}
}
element_filters.emplace_back(
std::make_unique<source_file_dependency_filter_t>(
filter_t::kInclusive, relationship_t::kAssociation,
dependants, false));
element_filters.emplace_back(
std::make_unique<source_file_dependency_filter_t>(
filter_t::kInclusive, relationship_t::kAssociation,
dependencies, true));
}
element_filters.emplace_back(std::make_unique<context_filter>(
filter_t::kInclusive, c.include().context));
df.add_inclusive_filter(std::make_unique<anyof_filter>(
filter_t::kInclusive, std::move(element_filters)));
}
// Process exclusive filters
if (c.exclude) {
df.add_exclusive_filter(std::make_unique<namespace_filter>(
filter_t::kExclusive, c.exclude().namespaces));
df.add_exclusive_filter(std::make_unique<modules_filter>(
filter_t::kExclusive, c.exclude().modules));
df.add_exclusive_filter(std::make_unique<module_access_filter>(
filter_t::kExclusive, c.exclude().module_access));
df.add_exclusive_filter(std::make_unique<paths_filter>(
filter_t::kExclusive, c.root_directory(), c.exclude().paths));
df.add_exclusive_filter(std::make_unique<element_filter>(
filter_t::kExclusive, c.exclude().elements));
df.add_exclusive_filter(std::make_unique<element_type_filter>(
filter_t::kExclusive, c.exclude().element_types));
df.add_exclusive_filter(std::make_unique<relationship_filter>(
filter_t::kExclusive, c.exclude().relationships));
df.add_exclusive_filter(std::make_unique<access_filter>(
filter_t::kExclusive, c.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)));
df.add_exclusive_filter(
std::make_unique<class_member_filter>(filter_t::kExclusive,
std::make_unique<access_filter>(
filter_t::kExclusive, c.exclude().access)));
df.add_exclusive_filter(std::make_unique<subclass_filter>(
filter_t::kExclusive, c.exclude().subclasses));
df.add_exclusive_filter(std::make_unique<parents_filter>(
filter_t::kExclusive, c.exclude().parents));
df.add_exclusive_filter(
std::make_unique<specializations_filter_t>(filter_t::kExclusive,
relationship_t::kInstantiation, c.exclude().specializations));
if (c.type() == diagram_t::kClass) {
df.add_exclusive_filter(std::make_unique<class_dependants_filter_t>(
filter_t::kExclusive, relationship_t::kDependency,
c.exclude().dependants));
df.add_exclusive_filter(
std::make_unique<class_dependencies_filter_t>(
filter_t::kExclusive, relationship_t::kDependency,
c.exclude().dependencies, true));
}
else if (c.type() == diagram_t::kSequence) {
df.add_exclusive_filter(std::make_unique<callee_filter>(
filter_t::kExclusive, c.exclude().callee_types));
}
else if (c.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));
df.add_exclusive_filter(
std::make_unique<package_dependants_filter_t>(
filter_t::kExclusive, relationship_t::kDependency,
c.exclude().dependants));
}
else if (c.type() == diagram_t::kInclude) {
std::vector<std::string> dependants;
std::vector<std::string> dependencies;
for (auto &&path : c.exclude().dependants) {
if (auto p = path.get<std::string>(); p.has_value()) {
std::filesystem::path dep_path{*p};
dependants.emplace_back(
dep_path.lexically_normal().string());
}
}
for (auto &&path : c.exclude().dependencies) {
if (auto p = path.get<std::string>(); p.has_value()) {
std::filesystem::path dep_path{*p};
dependencies.emplace_back(
dep_path.lexically_normal().string());
}
}
df.add_exclusive_filter(
std::make_unique<source_file_dependency_filter_t>(
filter_t::kExclusive, relationship_t::kAssociation,
dependants, false));
df.add_exclusive_filter(
std::make_unique<source_file_dependency_filter_t>(
filter_t::kExclusive, relationship_t::kAssociation,
dependencies, true));
}
df.add_exclusive_filter(std::make_unique<context_filter>(
filter_t::kExclusive, c.exclude().context));
}
}
void advanced_diagram_filter_initializer::initialize(
const config::diagram &c, diagram_filter &df)
{
}
} // namespace clanguml::common::model

View File

@@ -0,0 +1,49 @@
/**
* @file src/common/model/filters/diagram_filter_factory.h
*
* 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.
*/
#pragma once
#include "diagram_filter.h"
#include "package_diagram/model/diagram.h"
namespace clanguml::common::model {
struct basic_diagram_filter_initializer {
void initialize(const config::diagram &c, diagram_filter &df);
};
struct advanced_diagram_filter_initializer {
void initialize(const config::diagram &c, diagram_filter &df);
};
class diagram_filter_factory {
public:
static std::unique_ptr<diagram_filter> create(
const common::model::diagram &d, const config::diagram &c)
{
auto filter = std::make_unique<diagram_filter>(
d, c, diagram_filter::private_constructor_tag_t{});
basic_diagram_filter_initializer init;
init.initialize(c, *filter);
return filter;
}
};
} // namespace clanguml::common::model

View File

@@ -18,7 +18,7 @@
#include "diagram.h" #include "diagram.h"
#include "common/model/diagram_filter.h" #include "common/model/filters/diagram_filter.h"
#include <functional> #include <functional>
#include <memory> #include <memory>

View File

@@ -21,7 +21,7 @@
#include "class_diagram/model/class.h" #include "class_diagram/model/class.h"
#include "cli/cli_handler.h" #include "cli/cli_handler.h"
#include "common/model/diagram_filter.h" #include "common/model/filters/diagram_filter_factory.h"
#include "common/model/source_file.h" #include "common/model/source_file.h"
#include "config/config.h" #include "config/config.h"
#include "include_diagram/model/diagram.h" #include "include_diagram/model/diagram.h"
@@ -32,6 +32,7 @@
TEST_CASE("Test diagram paths filter") TEST_CASE("Test diagram paths filter")
{ {
using clanguml::common::model::diagram_filter; using clanguml::common::model::diagram_filter;
using clanguml::common::model::diagram_filter_factory;
using clanguml::common::model::source_file; using clanguml::common::model::source_file;
auto cfg = clanguml::config::load("./test_config_data/filters.yml"); auto cfg = clanguml::config::load("./test_config_data/filters.yml");
@@ -39,7 +40,8 @@ TEST_CASE("Test diagram paths filter")
auto &config = *cfg.diagrams["include_test"]; auto &config = *cfg.diagrams["include_test"];
clanguml::include_diagram::model::diagram diagram; clanguml::include_diagram::model::diagram diagram;
diagram_filter filter(diagram, config); auto filter_ptr = diagram_filter_factory::create(diagram, config);
diagram_filter &filter = *filter_ptr;
auto make_path = [&](std::string_view p) { auto make_path = [&](std::string_view p) {
return source_file{config.root_directory() / p}; return source_file{config.root_directory() / p};
@@ -59,6 +61,7 @@ TEST_CASE("Test method_types include filter")
using clanguml::class_diagram::model::class_method; using clanguml::class_diagram::model::class_method;
using clanguml::common::model::access_t; using clanguml::common::model::access_t;
using clanguml::common::model::diagram_filter; using clanguml::common::model::diagram_filter;
using clanguml::common::model::diagram_filter_factory;
using clanguml::common::model::source_file; using clanguml::common::model::source_file;
auto cfg = clanguml::config::load("./test_config_data/filters.yml"); auto cfg = clanguml::config::load("./test_config_data/filters.yml");
@@ -66,7 +69,8 @@ TEST_CASE("Test method_types include filter")
auto &config = *cfg.diagrams["method_type_include_test"]; auto &config = *cfg.diagrams["method_type_include_test"];
clanguml::class_diagram::model::diagram diagram; clanguml::class_diagram::model::diagram diagram;
diagram_filter filter(diagram, config); auto filter_ptr = diagram_filter_factory::create(diagram, config);
diagram_filter &filter = *filter_ptr;
class_method cm{access_t::kPublic, "A", ""}; class_method cm{access_t::kPublic, "A", ""};
cm.is_constructor(true); cm.is_constructor(true);
@@ -84,6 +88,7 @@ TEST_CASE("Test method_types exclude filter")
using clanguml::class_diagram::model::class_method; using clanguml::class_diagram::model::class_method;
using clanguml::common::model::access_t; using clanguml::common::model::access_t;
using clanguml::common::model::diagram_filter; using clanguml::common::model::diagram_filter;
using clanguml::common::model::diagram_filter_factory;
using clanguml::common::model::source_file; using clanguml::common::model::source_file;
auto cfg = clanguml::config::load("./test_config_data/filters.yml"); auto cfg = clanguml::config::load("./test_config_data/filters.yml");
@@ -91,7 +96,8 @@ TEST_CASE("Test method_types exclude filter")
auto &config = *cfg.diagrams["method_type_exclude_test"]; auto &config = *cfg.diagrams["method_type_exclude_test"];
clanguml::class_diagram::model::diagram diagram; clanguml::class_diagram::model::diagram diagram;
diagram_filter filter(diagram, config); auto filter_ptr = diagram_filter_factory::create(diagram, config);
diagram_filter &filter = *filter_ptr;
class_method cm{access_t::kPublic, "A", ""}; class_method cm{access_t::kPublic, "A", ""};
@@ -109,22 +115,23 @@ TEST_CASE("Test method_types exclude filter")
TEST_CASE("Test namespaces filter") TEST_CASE("Test namespaces filter")
{ {
using clanguml::class_diagram::model::class_;
using clanguml::class_diagram::model::class_method; using clanguml::class_diagram::model::class_method;
using clanguml::class_diagram::model::class_parent; using clanguml::class_diagram::model::class_parent;
using clanguml::common::model::access_t; using clanguml::common::model::access_t;
using clanguml::common::model::diagram_filter; using clanguml::common::model::diagram_filter;
using clanguml::common::model::diagram_filter_factory;
using clanguml::common::model::namespace_; using clanguml::common::model::namespace_;
using clanguml::common::model::package; using clanguml::common::model::package;
using clanguml::common::model::source_file; using clanguml::common::model::source_file;
using clanguml::class_diagram::model::class_;
auto cfg = clanguml::config::load("./test_config_data/filters.yml"); auto cfg = clanguml::config::load("./test_config_data/filters.yml");
auto &config = *cfg.diagrams["namespace_test"]; auto &config = *cfg.diagrams["namespace_test"];
clanguml::class_diagram::model::diagram diagram; clanguml::class_diagram::model::diagram diagram;
diagram_filter filter(diagram, config); auto filter_ptr = diagram_filter_factory::create(diagram, config);
diagram_filter &filter = *filter_ptr;
class_ c{{}}; class_ c{{}};
@@ -173,20 +180,21 @@ TEST_CASE("Test namespaces filter")
TEST_CASE("Test elements regexp filter") TEST_CASE("Test elements regexp filter")
{ {
using clanguml::class_diagram::model::class_;
using clanguml::class_diagram::model::class_method; using clanguml::class_diagram::model::class_method;
using clanguml::common::model::access_t; using clanguml::common::model::access_t;
using clanguml::common::model::diagram_filter; using clanguml::common::model::diagram_filter;
using clanguml::common::model::diagram_filter_factory;
using clanguml::common::model::namespace_; using clanguml::common::model::namespace_;
using clanguml::common::model::source_file; using clanguml::common::model::source_file;
using clanguml::class_diagram::model::class_;
auto cfg = clanguml::config::load("./test_config_data/filters.yml"); auto cfg = clanguml::config::load("./test_config_data/filters.yml");
auto &config = *cfg.diagrams["regex_elements_test"]; auto &config = *cfg.diagrams["regex_elements_test"];
clanguml::class_diagram::model::diagram diagram; clanguml::class_diagram::model::diagram diagram;
diagram_filter filter(diagram, config); auto filter_ptr = diagram_filter_factory::create(diagram, config);
diagram_filter &filter = *filter_ptr;
class_ c{{}}; class_ c{{}};
@@ -213,22 +221,23 @@ TEST_CASE("Test elements regexp filter")
TEST_CASE("Test namespaces regexp filter") TEST_CASE("Test namespaces regexp filter")
{ {
using clanguml::class_diagram::model::class_;
using clanguml::class_diagram::model::class_method; using clanguml::class_diagram::model::class_method;
using clanguml::class_diagram::model::class_parent; using clanguml::class_diagram::model::class_parent;
using clanguml::common::model::access_t; using clanguml::common::model::access_t;
using clanguml::common::model::diagram_filter; using clanguml::common::model::diagram_filter;
using clanguml::common::model::diagram_filter_factory;
using clanguml::common::model::namespace_; using clanguml::common::model::namespace_;
using clanguml::common::model::package; using clanguml::common::model::package;
using clanguml::common::model::source_file; using clanguml::common::model::source_file;
using clanguml::class_diagram::model::class_;
auto cfg = clanguml::config::load("./test_config_data/filters.yml"); auto cfg = clanguml::config::load("./test_config_data/filters.yml");
auto &config = *cfg.diagrams["regex_namespace_test"]; auto &config = *cfg.diagrams["regex_namespace_test"];
clanguml::class_diagram::model::diagram diagram; clanguml::class_diagram::model::diagram diagram;
diagram_filter filter(diagram, config); auto filter_ptr = diagram_filter_factory::create(diagram, config);
diagram_filter &filter = *filter_ptr;
class_ c{{}}; class_ c{{}};
@@ -281,8 +290,8 @@ TEST_CASE("Test subclasses regexp filter")
using clanguml::common::model::package; using clanguml::common::model::package;
using clanguml::common::model::source_file; using clanguml::common::model::source_file;
using namespace std::string_literals; using namespace std::string_literals;
using clanguml::class_diagram::model::class_; using clanguml::class_diagram::model::class_;
using clanguml::common::model::diagram_filter_factory;
auto cfg = clanguml::config::load("./test_config_data/filters.yml"); auto cfg = clanguml::config::load("./test_config_data/filters.yml");
@@ -353,7 +362,8 @@ TEST_CASE("Test subclasses regexp filter")
diagram.set_complete(true); diagram.set_complete(true);
diagram_filter filter(diagram, config); auto filter_ptr = diagram_filter_factory::create(diagram, config);
diagram_filter &filter = *filter_ptr;
CHECK(filter.should_include(*diagram.find<class_>("ns1::ns2::A1"))); CHECK(filter.should_include(*diagram.find<class_>("ns1::ns2::A1")));
CHECK(filter.should_include(*diagram.find<class_>("ns1::ns2::B1"))); CHECK(filter.should_include(*diagram.find<class_>("ns1::ns2::B1")));
@@ -371,8 +381,8 @@ TEST_CASE("Test parents regexp filter")
using clanguml::common::model::package; using clanguml::common::model::package;
using clanguml::common::model::source_file; using clanguml::common::model::source_file;
using namespace std::string_literals; using namespace std::string_literals;
using clanguml::class_diagram::model::class_; using clanguml::class_diagram::model::class_;
using clanguml::common::model::diagram_filter_factory;
auto cfg = clanguml::config::load("./test_config_data/filters.yml"); auto cfg = clanguml::config::load("./test_config_data/filters.yml");
@@ -443,7 +453,8 @@ TEST_CASE("Test parents regexp filter")
diagram.set_complete(true); diagram.set_complete(true);
diagram_filter filter(diagram, config); auto filter_ptr = diagram_filter_factory::create(diagram, config);
diagram_filter &filter = *filter_ptr;
CHECK(filter.should_include(*diagram.find<class_>("ns1::ns2::BaseA"))); CHECK(filter.should_include(*diagram.find<class_>("ns1::ns2::BaseA")));
CHECK(filter.should_include(*diagram.find<class_>("ns1::ns2::BaseB"))); CHECK(filter.should_include(*diagram.find<class_>("ns1::ns2::BaseB")));
@@ -464,8 +475,8 @@ TEST_CASE("Test specializations regexp filter")
using clanguml::common::model::source_file; using clanguml::common::model::source_file;
using clanguml::common::model::template_parameter; using clanguml::common::model::template_parameter;
using namespace std::string_literals; using namespace std::string_literals;
using clanguml::class_diagram::model::class_; using clanguml::class_diagram::model::class_;
using clanguml::common::model::diagram_filter_factory;
auto cfg = clanguml::config::load("./test_config_data/filters.yml"); auto cfg = clanguml::config::load("./test_config_data/filters.yml");
@@ -508,7 +519,8 @@ TEST_CASE("Test specializations regexp filter")
diagram.set_complete(true); diagram.set_complete(true);
diagram_filter filter(diagram, config); auto filter_ptr = diagram_filter_factory::create(diagram, config);
diagram_filter &filter = *filter_ptr;
CHECK(filter.should_include(*diagram.find<class_>("A<int,std::string>"))); CHECK(filter.should_include(*diagram.find<class_>("A<int,std::string>")));
CHECK(!filter.should_include(*diagram.find<class_>("A<double>"))); CHECK(!filter.should_include(*diagram.find<class_>("A<double>")));
@@ -529,8 +541,8 @@ TEST_CASE("Test context regexp filter")
using clanguml::common::model::source_file; using clanguml::common::model::source_file;
using clanguml::common::model::template_parameter; using clanguml::common::model::template_parameter;
using namespace std::string_literals; using namespace std::string_literals;
using clanguml::class_diagram::model::class_; using clanguml::class_diagram::model::class_;
using clanguml::common::model::diagram_filter_factory;
auto cfg = clanguml::config::load("./test_config_data/filters.yml"); auto cfg = clanguml::config::load("./test_config_data/filters.yml");
@@ -588,7 +600,8 @@ TEST_CASE("Test context regexp filter")
diagram.set_complete(true); diagram.set_complete(true);
diagram_filter filter(diagram, config); auto filter_ptr = diagram_filter_factory::create(diagram, config);
diagram_filter &filter = *filter_ptr;
CHECK(filter.should_include(*diagram.find<class_>("A"))); CHECK(filter.should_include(*diagram.find<class_>("A")));
CHECK(filter.should_include(*diagram.find<class_>("A1"))); CHECK(filter.should_include(*diagram.find<class_>("A1")));
@@ -619,6 +632,7 @@ TEST_CASE("Test dependencies regexp filter")
using clanguml::common::model::template_parameter; using clanguml::common::model::template_parameter;
using namespace std::string_literals; using namespace std::string_literals;
using clanguml::class_diagram::model::class_; using clanguml::class_diagram::model::class_;
using clanguml::common::model::diagram_filter_factory;
auto cfg = clanguml::config::load("./test_config_data/filters.yml"); auto cfg = clanguml::config::load("./test_config_data/filters.yml");
@@ -673,7 +687,8 @@ TEST_CASE("Test dependencies regexp filter")
diagram.set_complete(true); diagram.set_complete(true);
diagram_filter filter(diagram, config); auto filter_ptr = diagram_filter_factory::create(diagram, config);
diagram_filter &filter = *filter_ptr;
CHECK(filter.should_include(*diagram.find<class_>("A"))); CHECK(filter.should_include(*diagram.find<class_>("A")));
CHECK(!filter.should_include(*diagram.find<class_>("A1"))); CHECK(!filter.should_include(*diagram.find<class_>("A1")));
@@ -703,6 +718,7 @@ TEST_CASE("Test dependants regexp filter")
using clanguml::common::model::template_parameter; using clanguml::common::model::template_parameter;
using namespace std::string_literals; using namespace std::string_literals;
using clanguml::class_diagram::model::class_; using clanguml::class_diagram::model::class_;
using clanguml::common::model::diagram_filter_factory;
auto cfg = clanguml::config::load("./test_config_data/filters.yml"); auto cfg = clanguml::config::load("./test_config_data/filters.yml");
@@ -757,7 +773,8 @@ TEST_CASE("Test dependants regexp filter")
diagram.set_complete(true); diagram.set_complete(true);
diagram_filter filter(diagram, config); auto filter_ptr = diagram_filter_factory::create(diagram, config);
diagram_filter &filter = *filter_ptr;
CHECK(filter.should_include(*diagram.find<class_>("A"))); CHECK(filter.should_include(*diagram.find<class_>("A")));
CHECK(filter.should_include(*diagram.find<class_>("A1"))); CHECK(filter.should_include(*diagram.find<class_>("A1")));
@@ -775,6 +792,7 @@ TEST_CASE("Test callee_types filter")
{ {
using clanguml::common::to_id; using clanguml::common::to_id;
using clanguml::common::model::diagram_filter; using clanguml::common::model::diagram_filter;
using clanguml::common::model::diagram_filter_factory;
using clanguml::sequence_diagram::model::class_; using clanguml::sequence_diagram::model::class_;
using clanguml::sequence_diagram::model::function; using clanguml::sequence_diagram::model::function;
using clanguml::sequence_diagram::model::function_template; using clanguml::sequence_diagram::model::function_template;
@@ -812,7 +830,8 @@ TEST_CASE("Test callee_types filter")
diagram.add_participant(std::move(p)); diagram.add_participant(std::move(p));
diagram.set_complete(true); diagram.set_complete(true);
diagram_filter filter(diagram, config); auto filter_ptr = diagram_filter_factory::create(diagram, config);
diagram_filter &filter = *filter_ptr;
CHECK( CHECK(
filter.should_include(*diagram.get_participant<function>(to_id("A"s)))); filter.should_include(*diagram.get_participant<function>(to_id("A"s))));