diff --git a/CHANGELOG.md b/CHANGELOG.md index 6480310c..706ca2d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # CHANGELOG + * Add option to disable generation of dependency relation to template + arguments (#141) + * Added configuration file validation (#57) + ### 0.3.8 * Added option to display block conditional statements in sequence diagrams (#162) * Added Doxygen documentation (#161) diff --git a/docs/class_diagrams.md b/docs/class_diagrams.md index f23faf46..68a2fc71 100644 --- a/docs/class_diagrams.md +++ b/docs/class_diagrams.md @@ -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 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; +}; +``` + +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 +``` diff --git a/src/class_diagram/visitor/template_builder.cc b/src/class_diagram/visitor/template_builder.cc index e9c9fe71..65f1d903 100644 --- a/src/class_diagram/visitor/template_builder.cc +++ b/src/class_diagram/visitor/template_builder.cc @@ -616,7 +616,7 @@ bool template_builder::find_relationships_in_unexposed_template_params( } 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( element_opt.value().id(), relationship_t::kDependency); found = true; @@ -1035,16 +1035,19 @@ template_builder::try_as_template_specialization_type( if (nested_template_instantiation && diagram().should_include( namespace_{nested_template_instantiation_full_name})) { - if (diagram().should_include( - namespace_{template_decl->getQualifiedNameAsString()})) { - template_instantiation.add_relationship( - {relationship_t::kDependency, - nested_template_instantiation->id()}); - } - else { - if (parent.has_value()) - parent.value()->add_relationship({relationship_t::kDependency, - nested_template_instantiation->id()}); + if (config_.generate_template_argument_dependencies()) { + if (diagram().should_include( + namespace_{template_decl->getQualifiedNameAsString()})) { + template_instantiation.add_relationship( + {relationship_t::kDependency, + nested_template_instantiation->id()}); + } + else { + if (parent.has_value()) + parent.value()->add_relationship( + {relationship_t::kDependency, + nested_template_instantiation->id()}); + } } } @@ -1159,7 +1162,8 @@ std::optional template_builder::try_as_record_type( 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()) parent.value()->add_relationship( {relationship_t::kDependency, tag_argument->id()}); @@ -1170,7 +1174,8 @@ std::optional template_builder::try_as_record_type( } else if (const auto *record_type_decl = record_type->getAsRecordDecl(); 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 // template template_instantiation.add_relationship( @@ -1200,7 +1205,8 @@ std::optional template_builder::try_as_enum_type( const auto type_id = common::to_id(type_name); argument.set_id(type_id); - if (enum_type->getAsTagDecl() != nullptr) { + if (enum_type->getAsTagDecl() != nullptr && + config_.generate_template_argument_dependencies()) { template_instantiation.add_relationship( {relationship_t::kDependency, type_id}); } diff --git a/src/config/config.cc b/src/config/config.cc index 242b07e0..ee964f08 100644 --- a/src/config/config.cc +++ b/src/config/config.cc @@ -184,7 +184,11 @@ void inheritable_diagram_options::inherit( puml.override(parent.puml); generate_method_arguments.override(parent.generate_method_arguments); generate_packages.override(parent.generate_packages); + generate_template_argument_dependencies.override( + parent.generate_template_argument_dependencies); package_type.override(parent.package_type); + generate_template_argument_dependencies.override( + parent.generate_template_argument_dependencies); generate_links.override(parent.generate_links); generate_system_headers.override(parent.generate_system_headers); git.override(parent.git); diff --git a/src/config/config.h b/src/config/config.h index 2cb6a2ba..26872c6d 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -438,6 +438,8 @@ struct inheritable_diagram_options { option generate_packages{"generate_packages", false}; option package_type{ "package_type", package_type_t::kNamespace}; + option generate_template_argument_dependencies{ + "generate_template_argument_dependencies", true}; option generate_links{"generate_links"}; option git{"git"}; option layout{"layout"}; diff --git a/src/config/schema.h b/src/config/schema.h index a424e02b..118b6700 100644 --- a/src/config/schema.h +++ b/src/config/schema.h @@ -159,6 +159,7 @@ types: generate_method_arguments: !optional generate_method_arguments_t generate_packages: !optional bool package_type: !optional package_type_t + generate_template_argument_dependencies: !optional bool member_order: !optional member_order_t group_methods: !optional bool type_aliases: !optional map_t @@ -290,6 +291,7 @@ root: generate_packages: !optional bool group_methods: !optional bool package_type: !optional package_type_t + generate_template_argument_dependencies: !optional bool )"; } // namespace clanguml::config \ No newline at end of file diff --git a/src/config/yaml_decoders.cc b/src/config/yaml_decoders.cc index 22fbf1b4..8614ed4e 100644 --- a/src/config/yaml_decoders.cc +++ b/src/config/yaml_decoders.cc @@ -551,6 +551,7 @@ template <> struct convert { get_option(node, rhs.member_order); get_option(node, rhs.generate_packages); get_option(node, rhs.package_type); + get_option(node, rhs.generate_template_argument_dependencies); get_option(node, rhs.relationship_hints); get_option(node, rhs.type_aliases); get_option(node, rhs.relative_to); @@ -755,6 +756,7 @@ template <> struct convert { get_option(node, rhs.generate_method_arguments); get_option(node, rhs.generate_packages); 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_system_headers); get_option(node, rhs.git); diff --git a/src/config/yaml_emitters.cc b/src/config/yaml_emitters.cc index ec3eba8e..89d01c69 100644 --- a/src/config/yaml_emitters.cc +++ b/src/config/yaml_emitters.cc @@ -312,6 +312,7 @@ YAML::Emitter &operator<<( } out << c.member_order; out << c.package_type; + out << c.generate_template_argument_dependencies; } else if (dynamic_cast(&c) != nullptr) { out << c.combine_free_functions_into_file_participants; diff --git a/tests/t00019/.clang-uml b/tests/t00019/.clang-uml index 6c1daa20..6a6df084 100644 --- a/tests/t00019/.clang-uml +++ b/tests/t00019/.clang-uml @@ -5,6 +5,7 @@ diagrams: type: class glob: - ../../tests/t00019/**.cc + generate_template_argument_dependencies: false using_namespace: - clanguml::t00019 include: diff --git a/tests/t00019/test_case.h b/tests/t00019/test_case.h index db7bdcca..8b0a4332 100644 --- a/tests/t00019/test_case.h +++ b/tests/t00019/test_case.h @@ -38,16 +38,28 @@ TEST_CASE("t00019", "[test-case][class]") REQUIRE_THAT(puml, IsClassTemplate("Layer1", "LowerLayer")); REQUIRE_THAT(puml, IsClassTemplate("Layer2", "LowerLayer")); REQUIRE_THAT(puml, IsClassTemplate("Layer3", "LowerLayer")); + REQUIRE_THAT(puml, IsBaseClass(_A("Base"), _A("Layer3"))); + REQUIRE_THAT(puml, !IsDependency(_A("Base"), _A("Layer3"))); + REQUIRE_THAT( puml, IsBaseClass(_A("Layer3"), _A("Layer2>"))); + REQUIRE_THAT(puml, + !IsDependency(_A("Layer3"), _A("Layer2>"))); + REQUIRE_THAT(puml, IsBaseClass(_A("Layer2>"), _A("Layer1>>"))); + REQUIRE_THAT(puml, + !IsDependency(_A("Layer2>"), + _A("Layer1>>"))); + REQUIRE_THAT(puml, IsAggregation( _A("A"), _A("Layer1>>"), "+layers")); + REQUIRE_THAT( + puml, !IsDependency(_A("A"), _A("Layer1>>"))); REQUIRE_THAT(puml, !IsAggregation(_A("A"), _A("Layer2>"), "+layers")); diff --git a/tests/test_config.cc b/tests/test_config.cc index d04cb81c..0befda08 100644 --- a/tests/test_config.cc +++ b/tests/test_config.cc @@ -40,6 +40,7 @@ TEST_CASE("Test config simple", "[unit-test]") CHECK(diagram.generate_method_arguments() == clanguml::config::method_arguments::full); CHECK(diagram.generate_packages() == true); + CHECK(diagram.generate_template_argument_dependencies() == false); CHECK(diagram.generate_links == true); CHECK(diagram.generate_links().link == "https://github.com/bkryza/clang-uml/blob/{{ git.branch }}/{{ " diff --git a/tests/test_config_data/simple.yml b/tests/test_config_data/simple.yml index 63d16f10..a0ac5fa0 100644 --- a/tests/test_config_data/simple.yml +++ b/tests/test_config_data/simple.yml @@ -1,6 +1,7 @@ compilation_database_dir: debug comment_parser: clang output_directory: output +generate_template_argument_dependencies: false diagrams: class_main: type: class