Added option to exclude dependencies from template arguments (Fixes #141)

This commit is contained in:
Bartek Kryza
2023-08-02 00:04:11 +02:00
parent c119a622fa
commit f6efb7941f
12 changed files with 67 additions and 14 deletions

View File

@@ -1,5 +1,9 @@
# CHANGELOG # CHANGELOG
* Add option to disable generation of dependency relation to template
arguments (#141)
* Added configuration file validation (#57)
### 0.3.8 ### 0.3.8
* Added option to display block conditional statements in sequence diagrams (#162) * Added option to display block conditional statements in sequence diagrams (#162)
* Added Doxygen documentation (#161) * Added Doxygen documentation (#161)

View File

@@ -181,4 +181,21 @@ Dependency relationships are inferred whenever a class uses another class, thus
will be rendered in addition to other relationships such as association or inheritance. In the future there might will be rendered in addition to other relationships such as association or inheritance. In the future there might
be an option to remove the redundant dependency relationships from the diagram automatically. be an option to remove the redundant dependency relationships from the diagram automatically.
It is also possible to only disable dependency relationships generated from
template arguments to other templates. By default, the following code:
```cpp
class A {};
class B {
std::vector<A> a;
};
```
will generate a dependency from `B` to `A` in addition to aggregation
relationship. This can be disabled by specifying the following option:
```yaml
generate_template_argument_dependencies: false
```

View File

@@ -616,7 +616,7 @@ bool template_builder::find_relationships_in_unexposed_template_params(
} }
auto element_opt = diagram().get(type_with_namespace.value().to_string()); auto element_opt = diagram().get(type_with_namespace.value().to_string());
if (element_opt) { if (config_.generate_template_argument_dependencies() && element_opt) {
relationships.emplace_back( relationships.emplace_back(
element_opt.value().id(), relationship_t::kDependency); element_opt.value().id(), relationship_t::kDependency);
found = true; found = true;
@@ -1035,6 +1035,7 @@ template_builder::try_as_template_specialization_type(
if (nested_template_instantiation && if (nested_template_instantiation &&
diagram().should_include( diagram().should_include(
namespace_{nested_template_instantiation_full_name})) { namespace_{nested_template_instantiation_full_name})) {
if (config_.generate_template_argument_dependencies()) {
if (diagram().should_include( if (diagram().should_include(
namespace_{template_decl->getQualifiedNameAsString()})) { namespace_{template_decl->getQualifiedNameAsString()})) {
template_instantiation.add_relationship( template_instantiation.add_relationship(
@@ -1043,10 +1044,12 @@ template_builder::try_as_template_specialization_type(
} }
else { else {
if (parent.has_value()) if (parent.has_value())
parent.value()->add_relationship({relationship_t::kDependency, parent.value()->add_relationship(
{relationship_t::kDependency,
nested_template_instantiation->id()}); nested_template_instantiation->id()});
} }
} }
}
if (diagram().should_include( if (diagram().should_include(
namespace_{nested_template_instantiation_full_name})) { namespace_{nested_template_instantiation_full_name})) {
@@ -1159,7 +1162,8 @@ std::optional<template_parameter> template_builder::try_as_record_type(
template_instantiation.add_relationship(std::move(r)); template_instantiation.add_relationship(std::move(r));
} }
if (diagram().should_include(tag_argument->get_namespace())) { if (config_.generate_template_argument_dependencies() &&
diagram().should_include(tag_argument->get_namespace())) {
if (parent.has_value()) if (parent.has_value())
parent.value()->add_relationship( parent.value()->add_relationship(
{relationship_t::kDependency, tag_argument->id()}); {relationship_t::kDependency, tag_argument->id()});
@@ -1170,7 +1174,8 @@ std::optional<template_parameter> template_builder::try_as_record_type(
} }
else if (const auto *record_type_decl = record_type->getAsRecordDecl(); else if (const auto *record_type_decl = record_type->getAsRecordDecl();
record_type_decl != nullptr) { record_type_decl != nullptr) {
if (diagram().should_include(namespace_{type_name})) { if (config_.generate_template_argument_dependencies() &&
diagram().should_include(namespace_{type_name})) {
// Add dependency relationship to the parent // Add dependency relationship to the parent
// template // template
template_instantiation.add_relationship( template_instantiation.add_relationship(
@@ -1200,7 +1205,8 @@ std::optional<template_parameter> template_builder::try_as_enum_type(
const auto type_id = common::to_id(type_name); const auto type_id = common::to_id(type_name);
argument.set_id(type_id); argument.set_id(type_id);
if (enum_type->getAsTagDecl() != nullptr) { if (enum_type->getAsTagDecl() != nullptr &&
config_.generate_template_argument_dependencies()) {
template_instantiation.add_relationship( template_instantiation.add_relationship(
{relationship_t::kDependency, type_id}); {relationship_t::kDependency, type_id});
} }

View File

@@ -184,7 +184,11 @@ void inheritable_diagram_options::inherit(
puml.override(parent.puml); puml.override(parent.puml);
generate_method_arguments.override(parent.generate_method_arguments); generate_method_arguments.override(parent.generate_method_arguments);
generate_packages.override(parent.generate_packages); generate_packages.override(parent.generate_packages);
generate_template_argument_dependencies.override(
parent.generate_template_argument_dependencies);
package_type.override(parent.package_type); package_type.override(parent.package_type);
generate_template_argument_dependencies.override(
parent.generate_template_argument_dependencies);
generate_links.override(parent.generate_links); generate_links.override(parent.generate_links);
generate_system_headers.override(parent.generate_system_headers); generate_system_headers.override(parent.generate_system_headers);
git.override(parent.git); git.override(parent.git);

View File

@@ -438,6 +438,8 @@ struct inheritable_diagram_options {
option<bool> generate_packages{"generate_packages", false}; option<bool> generate_packages{"generate_packages", false};
option<package_type_t> package_type{ option<package_type_t> package_type{
"package_type", package_type_t::kNamespace}; "package_type", package_type_t::kNamespace};
option<bool> generate_template_argument_dependencies{
"generate_template_argument_dependencies", true};
option<generate_links_config> generate_links{"generate_links"}; option<generate_links_config> generate_links{"generate_links"};
option<git_config> git{"git"}; option<git_config> git{"git"};
option<layout_hints> layout{"layout"}; option<layout_hints> layout{"layout"};

View File

@@ -159,6 +159,7 @@ types:
generate_method_arguments: !optional generate_method_arguments_t generate_method_arguments: !optional generate_method_arguments_t
generate_packages: !optional bool generate_packages: !optional bool
package_type: !optional package_type_t package_type: !optional package_type_t
generate_template_argument_dependencies: !optional bool
member_order: !optional member_order_t member_order: !optional member_order_t
group_methods: !optional bool group_methods: !optional bool
type_aliases: !optional map_t<string;string> type_aliases: !optional map_t<string;string>
@@ -290,6 +291,7 @@ root:
generate_packages: !optional bool generate_packages: !optional bool
group_methods: !optional bool group_methods: !optional bool
package_type: !optional package_type_t package_type: !optional package_type_t
generate_template_argument_dependencies: !optional bool
)"; )";
} // namespace clanguml::config } // namespace clanguml::config

View File

@@ -551,6 +551,7 @@ template <> struct convert<class_diagram> {
get_option(node, rhs.member_order); get_option(node, rhs.member_order);
get_option(node, rhs.generate_packages); get_option(node, rhs.generate_packages);
get_option(node, rhs.package_type); get_option(node, rhs.package_type);
get_option(node, rhs.generate_template_argument_dependencies);
get_option(node, rhs.relationship_hints); get_option(node, rhs.relationship_hints);
get_option(node, rhs.type_aliases); get_option(node, rhs.type_aliases);
get_option(node, rhs.relative_to); get_option(node, rhs.relative_to);
@@ -755,6 +756,7 @@ template <> struct convert<config> {
get_option(node, rhs.generate_method_arguments); get_option(node, rhs.generate_method_arguments);
get_option(node, rhs.generate_packages); get_option(node, rhs.generate_packages);
get_option(node, rhs.package_type); get_option(node, rhs.package_type);
get_option(node, rhs.generate_template_argument_dependencies);
get_option(node, rhs.generate_links); get_option(node, rhs.generate_links);
get_option(node, rhs.generate_system_headers); get_option(node, rhs.generate_system_headers);
get_option(node, rhs.git); get_option(node, rhs.git);

View File

@@ -312,6 +312,7 @@ YAML::Emitter &operator<<(
} }
out << c.member_order; out << c.member_order;
out << c.package_type; out << c.package_type;
out << c.generate_template_argument_dependencies;
} }
else if (dynamic_cast<const sequence_diagram *>(&c) != nullptr) { else if (dynamic_cast<const sequence_diagram *>(&c) != nullptr) {
out << c.combine_free_functions_into_file_participants; out << c.combine_free_functions_into_file_participants;

View File

@@ -5,6 +5,7 @@ diagrams:
type: class type: class
glob: glob:
- ../../tests/t00019/**.cc - ../../tests/t00019/**.cc
generate_template_argument_dependencies: false
using_namespace: using_namespace:
- clanguml::t00019 - clanguml::t00019
include: include:

View File

@@ -38,16 +38,28 @@ TEST_CASE("t00019", "[test-case][class]")
REQUIRE_THAT(puml, IsClassTemplate("Layer1", "LowerLayer")); REQUIRE_THAT(puml, IsClassTemplate("Layer1", "LowerLayer"));
REQUIRE_THAT(puml, IsClassTemplate("Layer2", "LowerLayer")); REQUIRE_THAT(puml, IsClassTemplate("Layer2", "LowerLayer"));
REQUIRE_THAT(puml, IsClassTemplate("Layer3", "LowerLayer")); REQUIRE_THAT(puml, IsClassTemplate("Layer3", "LowerLayer"));
REQUIRE_THAT(puml, IsBaseClass(_A("Base"), _A("Layer3<Base>"))); REQUIRE_THAT(puml, IsBaseClass(_A("Base"), _A("Layer3<Base>")));
REQUIRE_THAT(puml, !IsDependency(_A("Base"), _A("Layer3<Base>")));
REQUIRE_THAT( REQUIRE_THAT(
puml, IsBaseClass(_A("Layer3<Base>"), _A("Layer2<Layer3<Base>>"))); puml, IsBaseClass(_A("Layer3<Base>"), _A("Layer2<Layer3<Base>>")));
REQUIRE_THAT(puml,
!IsDependency(_A("Layer3<Base>"), _A("Layer2<Layer3<Base>>")));
REQUIRE_THAT(puml, REQUIRE_THAT(puml,
IsBaseClass(_A("Layer2<Layer3<Base>>"), IsBaseClass(_A("Layer2<Layer3<Base>>"),
_A("Layer1<Layer2<Layer3<Base>>>"))); _A("Layer1<Layer2<Layer3<Base>>>")));
REQUIRE_THAT(puml,
!IsDependency(_A("Layer2<Layer3<Base>>"),
_A("Layer1<Layer2<Layer3<Base>>>")));
REQUIRE_THAT(puml, REQUIRE_THAT(puml,
IsAggregation( IsAggregation(
_A("A"), _A("Layer1<Layer2<Layer3<Base>>>"), "+layers")); _A("A"), _A("Layer1<Layer2<Layer3<Base>>>"), "+layers"));
REQUIRE_THAT(
puml, !IsDependency(_A("A"), _A("Layer1<Layer2<Layer3<Base>>>")));
REQUIRE_THAT(puml, REQUIRE_THAT(puml,
!IsAggregation(_A("A"), _A("Layer2<Layer3<Base>>"), "+layers")); !IsAggregation(_A("A"), _A("Layer2<Layer3<Base>>"), "+layers"));

View File

@@ -40,6 +40,7 @@ TEST_CASE("Test config simple", "[unit-test]")
CHECK(diagram.generate_method_arguments() == CHECK(diagram.generate_method_arguments() ==
clanguml::config::method_arguments::full); clanguml::config::method_arguments::full);
CHECK(diagram.generate_packages() == true); CHECK(diagram.generate_packages() == true);
CHECK(diagram.generate_template_argument_dependencies() == false);
CHECK(diagram.generate_links == true); CHECK(diagram.generate_links == true);
CHECK(diagram.generate_links().link == CHECK(diagram.generate_links().link ==
"https://github.com/bkryza/clang-uml/blob/{{ git.branch }}/{{ " "https://github.com/bkryza/clang-uml/blob/{{ git.branch }}/{{ "

View File

@@ -1,6 +1,7 @@
compilation_database_dir: debug compilation_database_dir: debug
comment_parser: clang comment_parser: clang
output_directory: output output_directory: output
generate_template_argument_dependencies: false
diagrams: diagrams:
class_main: class_main:
type: class type: class