Skip to content

Commit

Permalink
Added relationship direction flag to context diagram filter (#274)
Browse files Browse the repository at this point in the history
  • Loading branch information
bkryza committed Jun 13, 2024
1 parent 7d859db commit bd92182
Show file tree
Hide file tree
Showing 11 changed files with 240 additions and 35 deletions.
94 changes: 63 additions & 31 deletions src/common/model/diagram_filter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -659,10 +659,10 @@ void context_filter::initialize_effective_context(
auto &effective_context = effective_contexts_[idx];

// First add to effective context all elements matching context_ patterns
const auto &context = context_.at(idx);
const auto &context_cfg = context_.at(idx);
const auto &context_matches =
dynamic_cast<const class_diagram::model::diagram &>(d)
.find<class_diagram::model::class_>(context.pattern);
.find<class_diagram::model::class_>(context_cfg.pattern);

for (const auto &maybe_match : context_matches) {
if (maybe_match)
Expand All @@ -671,7 +671,7 @@ void context_filter::initialize_effective_context(

const auto &context_enum_matches =
dynamic_cast<const class_diagram::model::diagram &>(d)
.find<class_diagram::model::enum_>(context.pattern);
.find<class_diagram::model::enum_>(context_cfg.pattern);

for (const auto &maybe_match : context_enum_matches) {
if (maybe_match)
Expand All @@ -680,7 +680,7 @@ void context_filter::initialize_effective_context(

const auto &context_concept_matches =
dynamic_cast<const class_diagram::model::diagram &>(d)
.find<class_diagram::model::concept_>(context.pattern);
.find<class_diagram::model::concept_>(context_cfg.pattern);

for (const auto &maybe_match : context_concept_matches) {
if (maybe_match)
Expand All @@ -689,7 +689,7 @@ void context_filter::initialize_effective_context(

// Now repeat radius times - extend the effective context with elements
// matching in direct relationship to what is in context
auto radius_counter = context.radius;
auto radius_counter = context_cfg.radius;
std::set<eid_t> current_iteration_context;

while (radius_counter > 0 && effective_context_extended) {
Expand All @@ -701,18 +701,18 @@ void context_filter::initialize_effective_context(

// For each class in the model
find_elements_in_direct_relationship<class_diagram::model::class_>(
d, effective_context, current_iteration_context);
d, context_cfg, effective_context, current_iteration_context);

find_elements_inheritance_relationship(
d, effective_context, current_iteration_context);
d, context_cfg, effective_context, current_iteration_context);

// For each concept in the model
find_elements_in_direct_relationship<class_diagram::model::concept_>(
d, effective_context, current_iteration_context);
d, context_cfg, effective_context, current_iteration_context);

// For each enum in the model
find_elements_in_direct_relationship<class_diagram::model::enum_>(
d, effective_context, current_iteration_context);
d, context_cfg, effective_context, current_iteration_context);

for (auto id : current_iteration_context) {
if (effective_context.count(id) == 0) {
Expand All @@ -725,6 +725,7 @@ void context_filter::initialize_effective_context(
}

void context_filter::find_elements_inheritance_relationship(const diagram &d,
const config::context_config &context_cfg,
std::set<eid_t> &effective_context,
std::set<eid_t> &current_iteration_context) const
{
Expand All @@ -733,36 +734,57 @@ void context_filter::find_elements_inheritance_relationship(const diagram &d,
for (const auto &c : cd.classes()) {
// Check if any of the elements parents are already in the
// effective context...
for (const class_diagram::model::class_parent &p : c.get().parents()) {
for (const auto &ec : effective_context) {
const auto &maybe_parent =
cd.find<class_diagram::model::class_>(ec);
if (!maybe_parent)
continue;

if (d.should_include(relationship_t::kExtension) &&
maybe_parent.value().full_name(false) == p.name())
current_iteration_context.emplace(c.get().id());
}
}
if (context_cfg.direction != config::context_direction_t::outward)
find_elements_base_classes(
d, effective_context, current_iteration_context, cd, c);

// .. or vice-versa
for (const auto &ec : effective_context) {
const auto &maybe_child = cd.find<class_diagram::model::class_>(ec);
if (context_cfg.direction != config::context_direction_t::inward)
find_elements_sub_classes(
effective_context, current_iteration_context, cd, c);
}
}

// The element might not exist because it might have been
// something other than a class
if (!maybe_child)
continue;
void context_filter::find_elements_sub_classes(
std::set<eid_t> &effective_context,
std::set<eid_t> &current_iteration_context,
const class_diagram::model::diagram &cd,
const std::reference_wrapper<class_diagram::model::class_> &c) const
{
for (const auto &ec : effective_context) {
const auto &maybe_child = cd.find<class_diagram::model::class_>(ec);

for (const auto &p : maybe_child.value().parents()) {
if (p.name() == c.get().full_name(false)) {
current_iteration_context.emplace(c.get().id());
}
// The element might not exist because it might have been
// something other than a class
if (!maybe_child)
continue;

for (const auto &p : maybe_child.value().parents()) {
if (p.name() == c.get().full_name(false)) {
current_iteration_context.emplace(c.get().id());
}
}
}
}
void context_filter::find_elements_base_classes(const diagram &d,
std::set<eid_t> &effective_context,
std::set<eid_t> &current_iteration_context,
const class_diagram::model::diagram &cd,
const std::reference_wrapper<class_diagram::model::class_> &c) const
{
for (const class_diagram::model::class_parent &p : c.get().parents()) {
for (const auto &ec : effective_context) {
const auto &maybe_parent =
cd.find<class_diagram::model::class_>(ec);
if (!maybe_parent)
continue;

if (d.should_include(relationship_t::kExtension) &&
maybe_parent.value().full_name(false) == p.name())
current_iteration_context.emplace(c.get().id());
}
}
}

void context_filter::initialize(const diagram &d) const
{
Expand Down Expand Up @@ -802,6 +824,16 @@ tvl::value_t context_filter::match(const diagram &d, const element &e) const
return false;
}

bool context_filter::is_inward(relationship_t r) const
{
return r == relationship_t::kAssociation;
}

bool context_filter::is_outward(relationship_t r) const
{
return r != relationship_t::kAssociation;
}

paths_filter::paths_filter(filter_t type, const std::filesystem::path &root,
const std::vector<std::string> &p)
: filter_visitor{type}
Expand Down
33 changes: 32 additions & 1 deletion src/common/model/diagram_filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -494,8 +494,13 @@ struct context_filter : public filter_visitor {

void initialize_effective_context(const diagram &d, unsigned idx) const;

bool is_inward(relationship_t r) const;

bool is_outward(relationship_t r) const;

template <typename ElementT>
void find_elements_in_direct_relationship(const diagram &d,
const config::context_config &context_cfg,
std::set<eid_t> &effective_context,
std::set<eid_t> &current_iteration_context) const
{
Expand All @@ -511,6 +516,12 @@ struct context_filter : public filter_visitor {
// which have a relationship to any of the effective_context
// elements
for (const relationship &rel : el.get().relationships()) {
if (context_cfg.direction ==
config::context_direction_t::outward/* &&
!is_inward(rel.type())*/) {
continue;
}

for (const auto &element_id : effective_context) {
if (d.should_include(rel.type()) &&
rel.destination() == element_id)
Expand All @@ -519,7 +530,9 @@ struct context_filter : public filter_visitor {
}

// Now search current effective_context elements and add any
// elements of any type in the diagram which to that element
// elements of any type in the diagram which have a relationship
// to that element

for (const auto element_id : effective_context) {
const auto &maybe_element = cd.get(element_id);

Expand All @@ -528,6 +541,12 @@ struct context_filter : public filter_visitor {

for (const relationship &rel :
maybe_element.value().relationships()) {
if ((context_cfg.direction ==
config::context_direction_t::inward) &&
(rel.type() != relationship_t::kAggregation &&
rel.type() != relationship_t::kComposition)) {
continue;
}

if (d.should_include(rel.type()) &&
rel.destination() == el.get().id())
Expand All @@ -538,9 +557,21 @@ struct context_filter : public filter_visitor {
}

void find_elements_inheritance_relationship(const diagram &d,
const config::context_config &context_cfg,
std::set<eid_t> &effective_context,
std::set<eid_t> &current_iteration_context) const;

void find_elements_base_classes(const diagram &d,
std::set<eid_t> &effective_context,
std::set<eid_t> &current_iteration_context,
const class_diagram::model::diagram &cd,
const std::reference_wrapper<class_diagram::model::class_> &c) const;

void find_elements_sub_classes(std::set<eid_t> &effective_context,
std::set<eid_t> &current_iteration_context,
const class_diagram::model::diagram &cd,
const std::reference_wrapper<class_diagram::model::class_> &c) const;

std::vector<config::context_config> context_;

/*!
Expand Down
14 changes: 14 additions & 0 deletions src/config/config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,20 @@ std::string to_string(member_order_t mo)
return "";
}
}
std::string to_string(context_direction_t cd)
{
switch (cd) {
case context_direction_t::inward:
return "inward";
case context_direction_t::outward:
return "outward";
case context_direction_t::any:
return "any";
default:
assert(false);
return "";
}
}

std::optional<std::string> plantuml::get_style(
const common::model::relationship_t relationship_type) const
Expand Down
5 changes: 5 additions & 0 deletions src/config/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,14 @@ struct mermaid {
void append(const mermaid &r);
};

enum class context_direction_t { inward, outward, any };

std::string to_string(context_direction_t cd);

struct context_config {
common::string_or_regex pattern;
unsigned radius{0};
context_direction_t direction{context_direction_t::any};
};

/**
Expand Down
5 changes: 5 additions & 0 deletions src/config/schema.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,15 @@ const std::string schema_str = R"(
- lambda
- cuda_kernel
- cuda_device
direction_t: !variant
- inward
- outward
- any
context_filter_match_t:
match:
radius: int
pattern: regex_or_string_t
direction: !optional direction_t
context_filter_t:
- regex_or_string_t
- context_filter_match_t
Expand Down
27 changes: 25 additions & 2 deletions src/config/yaml_decoders.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ using clanguml::config::callee_type;
using clanguml::config::class_diagram;
using clanguml::config::config;
using clanguml::config::context_config;
using clanguml::config::context_direction_t;
using clanguml::config::diagram_template;
using clanguml::config::filter;
using clanguml::config::generate_links_config;
Expand Down Expand Up @@ -259,6 +260,25 @@ template <> struct convert<module_access_t> {
}
};

//
// config context_direction_t decoder
//
template <> struct convert<context_direction_t> {
static bool decode(const Node &node, context_direction_t &rhs)
{
if (node.as<std::string>() == "inward")
rhs = context_direction_t::inward;
else if (node.as<std::string>() == "outward")
rhs = context_direction_t::outward;
else if (node.as<std::string>() == "any")
rhs = context_direction_t::any;
else
return false;

return true;
}
};

//
// config method_type decoder
//
Expand Down Expand Up @@ -460,8 +480,11 @@ template <> struct convert<context_config> {
{
using namespace std::string_literals;
if (node.IsMap() && has_key(node, "match")) {
rhs.radius = node["match"]["radius"].as<unsigned>();
rhs.pattern = node["match"]["pattern"].as<string_or_regex>();
const auto &match = node["match"];
rhs.radius = match["radius"].as<unsigned>();
rhs.pattern = match["pattern"].as<string_or_regex>();
if (has_key(match, "direction"))
rhs.direction = match["direction"].as<context_direction_t>();
}
else {
rhs.radius = 1;
Expand Down
16 changes: 16 additions & 0 deletions tests/t00076/.clang-uml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
diagrams:
t00076_class:
type: class
glob:
- t00076.cc
include:
namespaces:
- clanguml::t00076
context:
- match:
radius: 1
pattern: clanguml::t00076::B
direction: inward
#relationships:
# - any
using_namespace: clanguml::t00076
36 changes: 36 additions & 0 deletions tests/t00076/t00076.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
namespace clanguml {
namespace t00076 {

enum Color { red, green, blue };

struct F;
struct G { };
struct H { };
struct J { };

struct A { };

struct B : public A {
F *f;
Color c;
G g;
/// @uml{composition[0..1:1..*]}
J j;

void a(H *h) { (void)h; }
};

struct C : public B { };

struct D : public C { };

struct E {
B *b;
};
struct F { };

struct I {
void i(B *b) { (void)b; }
};
}
}
Loading

0 comments on commit bd92182

Please sign in to comment.