25#include "glob/glob.hpp"
185 filter_t type, std::vector<std::unique_ptr<filter_visitor>> filters)
187 , filters_{
std::move(filters)}
246 filter_t type, std::vector<std::unique_ptr<filter_visitor>> filters)
248 , filters_{
std::move(filters)}
307 filter_t type, std::vector<common::namespace_or_regex> namespaces)
309 , namespaces_{
std::move(namespaces)}
321 if (std::holds_alternative<namespace_>(nsit.value())) {
322 const auto &ns_pattern = std::get<namespace_>(nsit.value());
324 return ns.starts_with(ns_pattern) ||
325 ns_pattern.starts_with(ns);
327 return ns.starts_with(ns_pattern);
330 const auto &
regex = std::get<common::regex>(nsit.value());
346 dynamic_cast<const package *
>(&e) !=
nullptr) {
349 if (std::holds_alternative<namespace_>(nsit.value())) {
350 const auto &ns_pattern = std::get<namespace_>(nsit.value());
352 auto element_full_name_starts_with_namespace =
353 namespace_{e.name_and_ns()}.starts_with(ns_pattern);
355 auto element_full_name_equals_pattern =
358 auto pattern_starts_with_element_full_name =
361 auto result = element_full_name_starts_with_namespace ||
362 element_full_name_equals_pattern;
366 result || pattern_starts_with_element_full_name;
371 return std::get<common::regex>(nsit.value()) %=
378 "Element {} rejected by namespace_filter", e.
full_name(
false));
385 res =
tvl::any_of(namespaces_.begin(), namespaces_.end(),
386 [&e, is_inclusive = is_inclusive()](
const auto &nsit) {
387 if (std::holds_alternative<namespace_>(nsit.value())) {
388 auto e_ns = namespace_{e.full_name(false)};
389 auto nsit_ns = std::get<namespace_>(nsit.value());
392 return e_ns.starts_with(nsit_ns) ||
393 nsit_ns.starts_with(e_ns) || e_ns == nsit_ns;
395 return e_ns.starts_with(nsit_ns) || e_ns == nsit_ns;
398 return std::get<common::regex>(nsit.value()) %=
405 "Element {} rejected by namespace_filter", e.full_name(
false));
411 namespaces_.begin(), namespaces_.end(), [&e](
const auto &nsit) {
412 if (std::holds_alternative<namespace_>(nsit.value())) {
413 return e.get_namespace().starts_with(
414 std::get<namespace_>(nsit.value()));
417 return std::get<common::regex>(nsit.value()) %= e.full_name(
false);
420 if ((type() == filter_t::kInclusive && tvl::is_false(res)) ||
421 (type() == filter_t::kExclusive && tvl::is_true(res))) {
423 "Element {} rejected by namespace_filter", e.full_name(
false));
431 return match(d,
dynamic_cast<const element &
>(p));
434modules_filter::modules_filter(
435 filter_t type, std::vector<common::string_or_regex> modules)
437 , modules_{
std::move(modules)}
447 if (!e.
module().has_value())
453 if (
dynamic_cast<const package *
>(&e) !=
nullptr &&
455 module_toks.push_back(e.
name());
459 [&e, &module_toks](
const auto &modit) {
460 if (std::holds_alternative<std::string>(modit.value())) {
461 const auto &modit_str = std::get<std::string>(modit.value());
462 const auto modit_toks =
463 path::split(modit_str, path_type::kModule);
465 return e.module() == modit_str ||
466 util::starts_with(module_toks, modit_toks);
469 return std::get<common::regex>(modit.value()) %= e.
module().value();
474 LOG_TRACE(
"Element {} rejected by modules_filter", e.full_name(
false));
481 filter_t type, std::vector<config::element_filter_t> elements)
483 , elements_{
std::move(elements)}
496 if ((el.type != config::element_filter_t::filtered_type::any) &&
497 (config::to_string(el.type) != e.type_name())) {
501 return ((el.name == e.
full_name(
false)) ||
502 (el.name == fmt::format(
"::{}", e.
full_name(
false))));
507 LOG_TRACE(
"Element {} rejected by element_filter", e.full_name(
false));
520 if (ef.type != config::element_filter_t::filtered_type::method)
529 "Class method {} rejected by element_filter", m.display_name());
542 if (ef.type != config::element_filter_t::filtered_type::member)
551 "Class member {} rejected by element_filter", m.qualified_name());
564 if (ef.type != config::element_filter_t::filtered_type::objc_method)
573 "ObjC method {} rejected by element_filter", m.qualified_name());
586 if (ef.type != config::element_filter_t::filtered_type::objc_member)
595 "ObjC member {} rejected by element_filter", m.qualified_name());
610 const auto &sequence_model =
613 [&sequence_model, &p](
const auto &el) {
615 if (el.type != config::element_filter_t::filtered_type::any &&
616 config::to_string(el.type) != p.type_name()) {
621 const auto &m = dynamic_cast<const method &>(p);
622 const auto class_id = m.class_id();
623 const auto &class_participant =
624 sequence_model.get_participant<participant>(class_id)
627 return (el.name == p.name_and_ns()) ||
628 (el.name == p.full_name(false)) ||
629 (el.name == class_participant.full_name(false));
634 dynamic_cast<const sequence_diagram::model::objc_method &>(
636 const auto class_id = m.class_id();
637 const auto &class_participant =
638 sequence_model.get_participant<participant>(class_id)
641 return (el.name == p.name_and_ns()) ||
642 (el.name == p.full_name(false)) ||
643 (el.name == class_participant.full_name(false));
652 "Participant {} rejected by element_filter", p.full_name(
false));
659 filter_t type, std::vector<std::string> element_types)
661 , element_types_{
std::move(element_types)}
670 [&e](
const auto &element_type) {
671 return e.type_name() == element_type;
677 "Element {} rejected by element_type_filter", e.
full_name(
false));
684 filter_t type, std::vector<config::method_type> method_types)
686 , method_types_{
std::move(method_types)}
696 case config::method_type::constructor:
697 return m.is_constructor();
698 case config::method_type::destructor:
699 return m.is_destructor();
700 case config::method_type::assignment:
701 return m.is_copy_assignment() || m.is_move_assignment();
702 case config::method_type::operator_:
703 return m.is_operator();
704 case config::method_type::defaulted:
705 return m.is_defaulted();
706 case config::method_type::deleted:
707 return m.is_deleted();
708 case config::method_type::static_:
709 return m.is_static();
717 LOG_TRACE(
"Class method {} rejected by method_type_filter",
725 filter_t type, std::vector<config::callee_type> callee_types)
727 , callee_types_{
std::move(callee_types)}
739 auto is_lambda = [&d](
const method &m) {
740 auto class_participant =
742 .get_participant<class_>(m.class_id());
743 if (!class_participant)
746 return class_participant.value().is_lambda();
751 auto is_function = [](const participant *p) {
752 return dynamic_cast<const function *>(p) != nullptr;
755 auto is_cuda_kernel = [](
const participant *p) {
756 const auto *f =
dynamic_cast<const function *
>(p);
757 return (f !=
nullptr) && (f->is_cuda_kernel());
760 auto is_cuda_device = [](
const participant *p) {
761 const auto *f =
dynamic_cast<const function *
>(p);
762 return (f !=
nullptr) && (f->is_cuda_device());
770 ((method &)p).is_constructor();
773 ((method &)p).is_assignment();
775 return is_function(&p) && ((function &)p).is_operator();
778 ((method &)p).is_defaulted();
780 return is_function(&p) && ((function &)p).is_static();
784 return p.
type_name() ==
"function_template";
786 return p.
type_name() ==
"method" && is_lambda((method &)p);
788 return is_cuda_kernel(&p);
790 return is_cuda_device(&p);
799 "Participant {} rejected by callee_filter", p.full_name(
false));
806 filter_t type, std::vector<common::string_or_regex> roots)
808 , roots_{
std::move(roots)}
831 if (!class_ref.has_value())
834 parents.emplace(class_ref.value());
836 cd.get_parents(parents);
838 std::vector<std::string> parents_names;
839 for (
const auto p : parents)
840 parents_names.push_back(p.get().full_name(
false));
844 for (
const auto &root :
roots_) {
845 for (
const auto &parent : parents) {
846 auto full_name = parent.get().
full_name(
false);
847 if (root == full_name) {
849 LOG_TRACE(
"Element {} rejected by subclass_filter",
864 filter_t type, std::vector<common::string_or_regex> children)
866 , children_{
std::move(children)}
886 for (
const auto &child_pattern :
children_) {
889 for (
auto &child : child_refs) {
890 if (child.has_value())
891 parents.emplace(child.value());
895 cd.get_parents(parents);
897 for (
const auto &parent : parents) {
898 if (e == parent.get())
908 filter_t type, std::vector<relationship_t> relationships)
910 , relationships_{
std::move(relationships)}
918 [&r](
const auto &rel) { return r == rel; });
923 , access_{
std::move(access)}
931 [&a](
const auto &access) { return a == access; });
935 filter_t type, std::vector<module_access_t> access)
937 , access_{
std::move(access)}
944 if (!e.
module().has_value())
952 if (access == module_access_t::kPublic)
953 return !e.module_private();
955 return e.module_private();
967 const diagram &d,
unsigned idx)
const
969 bool effective_context_extended{
true};
975 const auto &context_cfg =
context_.at(idx);
976 const auto &context_matches =
978 .find<class_diagram::model::class_>(context_cfg.pattern);
980 for (
const auto &maybe_match : context_matches) {
982 effective_context.emplace(maybe_match.value().id());
985 const auto &context_enum_matches =
987 .find<class_diagram::model::enum_>(context_cfg.pattern);
989 for (
const auto &maybe_match : context_enum_matches) {
991 effective_context.emplace(maybe_match.value().id());
994 const auto &context_concept_matches =
996 .find<class_diagram::model::concept_>(context_cfg.pattern);
998 for (
const auto &maybe_match : context_concept_matches) {
1000 effective_context.emplace(maybe_match.value().id());
1005 auto radius_counter = context_cfg.radius;
1006 std::set<eid_t> current_iteration_context;
1008 while (radius_counter > 0 && effective_context_extended) {
1012 effective_context_extended =
false;
1013 current_iteration_context.clear();
1018 d, context_cfg, effective_context, current_iteration_context);
1023 d, context_cfg, effective_context, current_iteration_context);
1028 d, context_cfg, effective_context, current_iteration_context);
1030 for (
auto id : current_iteration_context) {
1031 if (effective_context.count(
id) == 0) {
1033 effective_context.emplace(
id);
1034 effective_context_extended =
true;
1041 const diagram &d,
unsigned idx)
const
1045 bool effective_context_extended{
true};
1051 const auto &context_cfg =
context_.at(idx);
1052 const auto &context_matches =
1054 .find<package_diagram::model::package>(context_cfg.pattern);
1056 for (
const auto &maybe_match : context_matches) {
1058 effective_context.emplace(maybe_match.value().id());
1063 auto radius_counter = context_cfg.radius;
1064 std::set<eid_t> current_iteration_context;
1066 while (radius_counter > 0 && effective_context_extended) {
1070 effective_context_extended =
false;
1071 current_iteration_context.clear();
1076 d, context_cfg, effective_context, current_iteration_context);
1078 for (
auto id : current_iteration_context) {
1079 if (effective_context.count(
id) == 0) {
1081 effective_context.emplace(
id);
1082 effective_context_extended =
true;
1089 const diagram &d,
unsigned idx)
const
1113 for (
auto i = 0U; i <
context_.size(); i++) {
1132 if (
const auto *package_ptr =
1134 package_ptr !=
nullptr) {
1135 if (!package_ptr->is_empty(
true)) {
1144 [](
const auto &ec) { return ec.empty(); }))
1148 if (ec.count(e.
id()) > 0) {
1150 LOG_TRACE(
"Element {} rejected by context_filter",
1172 const std::filesystem::path &root)
1176 for (
const auto &
path : p) {
1177 std::filesystem::path absolute_path;
1180 absolute_path = root;
1181 else if (std::filesystem::path{
path}.is_relative())
1182 absolute_path = root /
path;
1184 absolute_path =
path;
1186 bool match_successful{
false};
1187 for (
auto &resolved_glob_path :
1188 glob::glob(absolute_path.string(),
true)) {
1190 auto resolved_absolute_path = absolute(resolved_glob_path);
1191 resolved_absolute_path =
1192 canonical(resolved_absolute_path.lexically_normal());
1194 resolved_absolute_path.make_preferred();
1196 LOG_DBG(
"Added path {} to paths_filter",
1197 resolved_absolute_path.string());
1199 paths_.emplace_back(std::move(resolved_absolute_path));
1201 match_successful =
true;
1203 catch (std::filesystem::filesystem_error &e) {
1204 LOG_WARN(
"Cannot add non-existent path {} to "
1206 absolute_path.string());
1211 if (!match_successful)
1212 LOG_WARN(
"Paths filter pattern '{}' did not match "
1213 "any files relative to '{}'",
1234 [
this](
const std::filesystem::path &sfp) {
1237 return sfp.root_name().string() ==
1238 path.root_name().string() &&
1239 util::is_relative_to(
1240 sfp.relative_path(), path.relative_path());
1247 LOG_TRACE(
"Source file {} [{}] rejected by paths_filter",
1248 p.
full_name(
false), source_file_path.string());
1253 LOG_TRACE(
"Source file {} [{}] accepted by paths_filter",
1254 p.
full_name(
false), source_file_path.string());
1267 const auto source_location_path = std::filesystem::path{p.
file()};
1271 if (p.
file().empty() || source_location_path.is_relative()) {
1277 [
this](
const std::filesystem::path &p) {
1280 return p.root_name().string() ==
1281 path.root_name().string() &&
1282 util::is_relative_to(
1283 p.relative_path(), path.relative_path());
1286 source_location_path);
1290 LOG_TRACE(
"Source location {} rejected by paths_filter", p.
file());
1303 std::unique_ptr<access_filter> af, std::unique_ptr<method_type_filter> mtf)
1305 , access_filter_{
std::move(af)}
1306 , method_type_filter_{
std::move(mtf)}
1318 LOG_TRACE(
"Class method {} rejected by class_method_filter",
1326 filter_t type, std::unique_ptr<access_filter> af)
1328 , access_filter_{
std::move(af)}
1339 LOG_TRACE(
"Class member {} rejected by class_member_filter",
1353 filter_t filter_type, std::unique_ptr<filter_visitor> fv)
1372 const namespace_ &ns,
const std::string &name)
const
1377 e.set_namespace(ns);
1390bool diagram_filter::should_include<std::string>(
const std::string &name)
const
1397 return should_include(ns, n);