25#include "glob/glob.hpp"
187 filter_t type, std::vector<std::unique_ptr<filter_visitor>> filters)
189 , filters_{
std::move(filters)}
254 filter_t type, std::vector<std::unique_ptr<filter_visitor>> filters)
256 , filters_{
std::move(filters)}
320 filter_t type, std::vector<common::namespace_or_regex> namespaces)
322 , namespaces_{
std::move(namespaces)}
334 if (std::holds_alternative<namespace_>(nsit.value())) {
335 const auto &ns_pattern = std::get<namespace_>(nsit.value());
337 return ns.starts_with(ns_pattern) ||
338 ns_pattern.starts_with(ns);
340 return ns.starts_with(ns_pattern);
343 const auto &
regex = std::get<common::regex>(nsit.value());
359 dynamic_cast<const package *
>(&e) !=
nullptr) {
362 if (std::holds_alternative<namespace_>(nsit.value())) {
363 const auto &ns_pattern = std::get<namespace_>(nsit.value());
365 auto element_full_name_starts_with_namespace =
366 namespace_{e.name_and_ns()}.starts_with(ns_pattern);
368 auto element_full_name_equals_pattern =
371 auto pattern_starts_with_element_full_name =
374 auto result = element_full_name_starts_with_namespace ||
375 element_full_name_equals_pattern;
379 result || pattern_starts_with_element_full_name;
384 return std::get<common::regex>(nsit.value()) %=
391 "Element {} rejected by namespace_filter", e.
full_name(
false));
398 res =
tvl::any_of(namespaces_.begin(), namespaces_.end(),
399 [&e, is_inclusive = is_inclusive()](
const auto &nsit) {
400 if (std::holds_alternative<namespace_>(nsit.value())) {
401 auto e_ns = namespace_{e.full_name(false)};
402 auto nsit_ns = std::get<namespace_>(nsit.value());
405 return e_ns.starts_with(nsit_ns) ||
406 nsit_ns.starts_with(e_ns) || e_ns == nsit_ns;
408 return e_ns.starts_with(nsit_ns) || e_ns == nsit_ns;
411 return std::get<common::regex>(nsit.value()) %=
418 "Element {} rejected by namespace_filter", e.full_name(
false));
424 namespaces_.begin(), namespaces_.end(), [&e](
const auto &nsit) {
425 if (std::holds_alternative<namespace_>(nsit.value())) {
426 return e.get_namespace().starts_with(
427 std::get<namespace_>(nsit.value()));
430 return std::get<common::regex>(nsit.value()) %= e.full_name(
false);
433 if ((type() == filter_t::kInclusive && tvl::is_false(res)) ||
434 (type() == filter_t::kExclusive && tvl::is_true(res))) {
436 "Element {} rejected by namespace_filter", e.full_name(
false));
444 return match(d,
dynamic_cast<const element &
>(p));
447modules_filter::modules_filter(
448 filter_t type, std::vector<common::string_or_regex> modules)
450 , modules_{
std::move(modules)}
460 if (!e.
module().has_value())
466 if (
dynamic_cast<const package *
>(&e) !=
nullptr &&
468 module_toks.push_back(e.
name());
472 [&e, &module_toks](
const auto &modit) {
473 if (std::holds_alternative<std::string>(modit.value())) {
474 const auto &modit_str = std::get<std::string>(modit.value());
475 const auto modit_toks =
476 path::split(modit_str, path_type::kModule);
478 return e.module() == modit_str ||
479 util::starts_with(module_toks, modit_toks);
482 return std::get<common::regex>(modit.value()) %= e.
module().value();
487 LOG_TRACE(
"Element {} rejected by modules_filter", e.full_name(
false));
494 filter_t type, std::vector<config::element_filter_t> elements)
496 , elements_{
std::move(elements)}
509 if ((el.type != config::element_filter_t::filtered_type::any) &&
510 (config::to_string(el.type) != e.type_name())) {
514 return ((el.name == e.
full_name(
false)) ||
515 (el.name == fmt::format(
"::{}", e.
full_name(
false))));
520 LOG_TRACE(
"Element {} rejected by element_filter", e.full_name(
false));
533 if (ef.type != config::element_filter_t::filtered_type::method)
542 "Class method {} rejected by element_filter", m.display_name());
555 if (ef.type != config::element_filter_t::filtered_type::member)
564 "Class member {} rejected by element_filter", m.qualified_name());
577 if (ef.type != config::element_filter_t::filtered_type::objc_method)
586 "ObjC method {} rejected by element_filter", m.qualified_name());
599 if (ef.type != config::element_filter_t::filtered_type::objc_member)
608 "ObjC member {} rejected by element_filter", m.qualified_name());
623 const auto &sequence_model =
626 [&sequence_model, &p](
const auto &el) {
628 if (el.type != config::element_filter_t::filtered_type::any &&
629 config::to_string(el.type) != p.type_name()) {
634 const auto &m = dynamic_cast<const method &>(p);
635 const auto class_id = m.class_id();
636 const auto &class_participant =
637 sequence_model.get_participant<participant>(class_id)
640 return (el.name == p.name_and_ns()) ||
641 (el.name == p.full_name(false)) ||
642 (el.name == class_participant.full_name(false));
647 dynamic_cast<const sequence_diagram::model::objc_method &>(
649 const auto class_id = m.class_id();
650 const auto &class_participant =
651 sequence_model.get_participant<participant>(class_id)
654 return (el.name == p.name_and_ns()) ||
655 (el.name == p.full_name(false)) ||
656 (el.name == class_participant.full_name(false));
665 "Participant {} rejected by element_filter", p.full_name(
false));
672 filter_t type, std::vector<std::string> element_types)
674 , element_types_{
std::move(element_types)}
683 [&e](
const auto &element_type) {
684 return e.type_name() == element_type;
690 "Element {} rejected by element_type_filter", e.
full_name(
false));
697 filter_t type, std::vector<config::method_type> method_types)
699 , method_types_{
std::move(method_types)}
709 case config::method_type::constructor:
710 return m.is_constructor();
711 case config::method_type::destructor:
712 return m.is_destructor();
713 case config::method_type::assignment:
714 return m.is_copy_assignment() || m.is_move_assignment();
715 case config::method_type::operator_:
716 return m.is_operator();
717 case config::method_type::defaulted:
718 return m.is_defaulted();
719 case config::method_type::deleted:
720 return m.is_deleted();
721 case config::method_type::static_:
722 return m.is_static();
730 LOG_TRACE(
"Class method {} rejected by method_type_filter",
738 filter_t type, std::vector<config::callee_type> callee_types)
740 , callee_types_{
std::move(callee_types)}
752 auto is_lambda = [&d](
const method &m) {
753 auto class_participant =
755 .get_participant<class_>(m.class_id());
756 if (!class_participant)
759 return class_participant.value().is_lambda();
764 auto is_function = [](const participant *p) {
765 return dynamic_cast<const function *>(p) != nullptr;
768 auto is_cuda_kernel = [](
const participant *p) {
769 const auto *f =
dynamic_cast<const function *
>(p);
770 return (f !=
nullptr) && (f->is_cuda_kernel());
773 auto is_cuda_device = [](
const participant *p) {
774 const auto *f =
dynamic_cast<const function *
>(p);
775 return (f !=
nullptr) && (f->is_cuda_device());
783 ((method &)p).is_constructor();
786 ((method &)p).is_assignment();
788 return is_function(&p) && ((function &)p).is_operator();
791 ((method &)p).is_defaulted();
793 return is_function(&p) && ((function &)p).is_static();
797 return p.
type_name() ==
"function_template";
799 return p.
type_name() ==
"method" && is_lambda((method &)p);
801 return is_cuda_kernel(&p);
803 return is_cuda_device(&p);
812 "Participant {} rejected by callee_filter", p.full_name(
false));
819 filter_t type, std::vector<common::string_or_regex> roots)
821 , roots_{
std::move(roots)}
844 if (!class_ref.has_value())
847 parents.emplace(class_ref.value());
849 cd.get_parents(parents);
851 std::vector<std::string> parents_names;
852 for (
const auto p : parents)
853 parents_names.push_back(p.get().full_name(
false));
857 for (
const auto &root :
roots_) {
858 for (
const auto &parent : parents) {
859 auto full_name = parent.get().
full_name(
false);
860 if (root == full_name) {
862 LOG_TRACE(
"Element {} rejected by subclass_filter",
877 filter_t type, std::vector<common::string_or_regex> children)
879 , children_{
std::move(children)}
899 for (
const auto &child_pattern :
children_) {
902 for (
auto &child : child_refs) {
903 if (child.has_value())
904 parents.emplace(child.value());
908 cd.get_parents(parents);
910 for (
const auto &parent : parents) {
911 if (e == parent.get())
921 filter_t type, std::vector<relationship_t> relationships)
923 , relationships_{
std::move(relationships)}
931 [&r](
const auto &rel) { return r == rel; });
936 , access_{
std::move(access)}
944 [&a](
const auto &access) { return a == access; });
948 filter_t type, std::vector<module_access_t> access)
950 , access_{
std::move(access)}
957 if (!e.
module().has_value())
965 if (access == module_access_t::kPublic)
966 return !e.module_private();
968 return e.module_private();
980 const diagram &d,
unsigned idx)
const
982 bool effective_context_extended{
true};
988 const auto &context_cfg =
context_.at(idx);
989 const auto &context_matches =
991 .find<class_diagram::model::class_>(context_cfg.pattern);
993 for (
const auto &maybe_match : context_matches) {
995 effective_context.emplace(maybe_match.value().id());
999 const auto &context_enum_matches =
1001 .find<class_diagram::model::enum_>(context_cfg.pattern);
1003 for (
const auto &maybe_match : context_enum_matches) {
1005 effective_context.emplace(maybe_match.value().id());
1008 const auto &context_concept_matches =
1010 .find<class_diagram::model::concept_>(context_cfg.pattern);
1012 for (
const auto &maybe_match : context_concept_matches) {
1014 effective_context.emplace(maybe_match.value().id());
1019 auto radius_counter = context_cfg.radius;
1020 std::set<eid_t> current_iteration_context;
1022 while (radius_counter > 0 && effective_context_extended) {
1026 effective_context_extended =
false;
1027 current_iteration_context.clear();
1030 find_elements_in_direct_relationship<class_diagram::model::diagram>(
1031 d, context_cfg, effective_context, current_iteration_context);
1033 for (
auto id : current_iteration_context) {
1034 if (effective_context.count(
id) == 0) {
1036 effective_context.emplace(
id);
1037 effective_context_extended =
true;
1044 const diagram &d,
unsigned idx)
const
1048 bool effective_context_extended{
true};
1054 const auto &context_cfg =
context_.at(idx);
1055 const auto &context_matches =
1057 .find<package_diagram::model::package>(context_cfg.pattern);
1059 for (
const auto &maybe_match : context_matches) {
1061 effective_context.emplace(maybe_match.value().id());
1066 auto radius_counter = context_cfg.radius;
1067 std::set<eid_t> current_iteration_context;
1069 while (radius_counter > 0 && effective_context_extended) {
1073 effective_context_extended =
false;
1074 current_iteration_context.clear();
1077 find_elements_in_direct_relationship<package_diagram::model::diagram>(
1078 d, context_cfg, effective_context, current_iteration_context);
1080 for (
auto id : current_iteration_context) {
1081 if (effective_context.count(
id) == 0) {
1083 effective_context.emplace(
id);
1084 effective_context_extended =
true;
1091 const diagram &d,
unsigned idx)
const
1115 for (
auto i = 0U; i <
context_.size(); i++) {
1134 if (
const auto *package_ptr =
1136 package_ptr !=
nullptr) {
1137 if (!package_ptr->is_empty(
true)) {
1146 [](
const auto &ec) { return ec.empty(); }))
1150 if (ec.count(e.
id()) > 0) {
1152 LOG_TRACE(
"Element {} rejected by context_filter",
1174 const std::filesystem::path &root)
1178 for (
const auto &
path : p) {
1179 std::filesystem::path absolute_path;
1182 absolute_path = root;
1183 else if (std::filesystem::path{
path}.is_relative())
1184 absolute_path = root /
path;
1186 absolute_path =
path;
1188 bool match_successful{
false};
1189 for (
auto &resolved_glob_path :
1190 glob::glob(absolute_path.string(),
true)) {
1192 auto resolved_absolute_path = absolute(resolved_glob_path);
1193 resolved_absolute_path =
1194 canonical(resolved_absolute_path.lexically_normal());
1196 resolved_absolute_path.make_preferred();
1198 LOG_DBG(
"Added path {} to paths_filter",
1199 resolved_absolute_path.string());
1201 paths_.emplace_back(std::move(resolved_absolute_path));
1203 match_successful =
true;
1205 catch (std::filesystem::filesystem_error &e) {
1206 LOG_WARN(
"Cannot add non-existent path {} to "
1208 absolute_path.string());
1213 if (!match_successful)
1214 LOG_WARN(
"Paths filter pattern '{}' did not match "
1215 "any files relative to '{}'",
1236 [
this](
const std::filesystem::path &sfp) {
1239 return sfp.root_name().string() ==
1240 path.root_name().string() &&
1241 util::is_relative_to(
1242 sfp.relative_path(), path.relative_path());
1249 LOG_TRACE(
"Source file {} [{}] rejected by paths_filter",
1250 p.
full_name(
false), source_file_path.string());
1255 LOG_TRACE(
"Source file {} [{}] accepted by paths_filter",
1256 p.
full_name(
false), source_file_path.string());
1269 const auto source_location_path = std::filesystem::path{p.
file()};
1273 if (p.
file().empty() || source_location_path.is_relative()) {
1279 [
this](
const std::filesystem::path &p) {
1282 return p.root_name().string() ==
1283 path.root_name().string() &&
1284 util::is_relative_to(
1285 p.relative_path(), path.relative_path());
1288 source_location_path);
1292 LOG_TRACE(
"Source location {} rejected by paths_filter", p.
file());
1305 std::unique_ptr<access_filter> af, std::unique_ptr<method_type_filter> mtf)
1307 , access_filter_{
std::move(af)}
1308 , method_type_filter_{
std::move(mtf)}
1320 LOG_TRACE(
"Class method {} rejected by class_method_filter",
1328 filter_t type, std::unique_ptr<access_filter> af)
1330 , access_filter_{
std::move(af)}
1341 LOG_TRACE(
"Class member {} rejected by class_member_filter",
1355 filter_t filter_type, std::unique_ptr<filter_visitor> fv)
1374 const namespace_ &ns,
const std::string &name)
const
1379 e.set_namespace(ns);
1401bool diagram_filter::should_include<std::string>(
const std::string &name)
const
1408 return should_include(ns, n);