Skip to content

Commit c4ec8be

Browse files
committed
Added generate_concept_requirements config option (#237)
1 parent 52b72f3 commit c4ec8be

13 files changed

+137
-4
lines changed

docs/configuration_file.md

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
* `glob` - list of glob patterns to match source code files for analysis
2626
* `include_relations_also_as_members` - when set to `false`, class members for relationships are rendered in UML are skipped from class definition (default: `true`)
2727
* `generate_method_arguments` - determines whether the class diagrams methods contain full arguments (`full`), are abbreviated (`abbreviated`) or skipped (`none`)
28+
* `generate_concept_requirements` - determines whether concept requirements are rendered in the diagram (default: `true`)
2829
* `using_namespace` - similar to C++ `using namespace`, a `A::B` value here will render a class `A::B::C::MyClass` in the diagram as `C::MyClass`, at most 1 value is supported
2930
* `generate_packages` - whether or not the class diagram should contain packages generated from namespaces or subdirectories
3031
* `package_type` - determines how the packages are inferred: `namespace` - use C++ namespaces, `directory` - use project's directory structure

src/class_diagram/generators/mermaid/class_diagram_generator.cc

+2-2
Original file line numberDiff line numberDiff line change
@@ -293,8 +293,8 @@ void generator::generate(const concept_ &c, std::ostream &ostr) const
293293
ostr << " {" << '\n';
294294
ostr << indent(2) << "<<concept>>\n";
295295

296-
// TODO: add option to enable/disable this
297-
if (c.requires_parameters().size() + c.requires_statements().size() > 0) {
296+
if (config().generate_concept_requirements() &&
297+
(c.requires_parameters().size() + c.requires_statements().size() > 0)) {
298298
std::vector<std::string> parameters;
299299
parameters.reserve(c.requires_parameters().size());
300300
for (const auto &p : c.requires_parameters()) {

src/class_diagram/generators/plantuml/class_diagram_generator.cc

+2-2
Original file line numberDiff line numberDiff line change
@@ -383,8 +383,8 @@ void generator::generate(const concept_ &c, std::ostream &ostr) const
383383

384384
ostr << " {" << '\n';
385385

386-
// TODO: add option to enable/disable this
387-
if (c.requires_parameters().size() + c.requires_statements().size() > 0) {
386+
if (config().generate_concept_requirements() &&
387+
(c.requires_parameters().size() + c.requires_statements().size() > 0)) {
388388
std::vector<std::string> parameters;
389389
parameters.reserve(c.requires_parameters().size());
390390
for (const auto &p : c.requires_parameters()) {

src/config/config.cc

+2
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,8 @@ void inheritable_diagram_options::inherit(
197197
puml.override(parent.puml);
198198
mermaid.override(parent.mermaid);
199199
generate_method_arguments.override(parent.generate_method_arguments);
200+
generate_concept_requirements.override(
201+
parent.generate_concept_requirements);
200202
generate_packages.override(parent.generate_packages);
201203
generate_template_argument_dependencies.override(
202204
parent.generate_template_argument_dependencies);

src/config/config.h

+2
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,8 @@ struct inheritable_diagram_options {
530530
option<struct mermaid> mermaid{"mermaid", option_inherit_mode::kAppend};
531531
option<method_arguments> generate_method_arguments{
532532
"generate_method_arguments", method_arguments::full};
533+
option<bool> generate_concept_requirements{
534+
"generate_concept_requirements", true};
533535
option<bool> group_methods{"group_methods", true};
534536
option<member_order_t> member_order{
535537
"member_order", member_order_t::lexical};

src/config/schema.h

+2
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ const std::string schema_str = R"(
174174
#
175175
generate_method_arguments: !optional generate_method_arguments_t
176176
generate_packages: !optional bool
177+
generate_concept_requirements: !optional bool
177178
package_type: !optional package_type_t
178179
generate_template_argument_dependencies: !optional bool
179180
skip_redundant_dependencies: !optional bool
@@ -335,6 +336,7 @@ const std::string schema_str = R"(
335336
include_relations_also_as_members: !optional bool
336337
generate_method_arguments: !optional generate_method_arguments_t
337338
combine_free_functions_into_file_participants: !optional bool
339+
generate_concept_requirements: !optional bool
338340
generate_return_types: !optional bool
339341
generate_condition_statements: !optional bool
340342
generate_message_comments: !optional bool

src/config/yaml_decoders.cc

+2
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,7 @@ template <> struct convert<class_diagram> {
626626
get_option(node, rhs.layout);
627627
get_option(node, rhs.include_relations_also_as_members);
628628
get_option(node, rhs.generate_method_arguments);
629+
get_option(node, rhs.generate_concept_requirements);
629630
get_option(node, rhs.group_methods);
630631
get_option(node, rhs.member_order);
631632
get_option(node, rhs.generate_packages);
@@ -823,6 +824,7 @@ template <> struct convert<config> {
823824
get_option(node, rhs.puml);
824825
get_option(node, rhs.mermaid);
825826
get_option(node, rhs.generate_method_arguments);
827+
get_option(node, rhs.generate_concept_requirements);
826828
get_option(node, rhs.generate_packages);
827829
get_option(node, rhs.package_type);
828830
get_option(node, rhs.generate_template_argument_dependencies);

src/config/yaml_emitters.cc

+1
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,7 @@ YAML::Emitter &operator<<(
326326
cd != nullptr) {
327327
out << cd->title;
328328
out << c.generate_method_arguments;
329+
out << c.generate_concept_requirements;
329330
out << c.generate_packages;
330331
out << c.include_relations_also_as_members;
331332
if (c.relationship_hints) {

tests/t00074/.clang-uml

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
diagrams:
2+
t00074_class:
3+
type: class
4+
glob:
5+
- t00074.cc
6+
generate_concept_requirements: false
7+
include:
8+
namespaces:
9+
- clanguml::t00074
10+
using_namespace: clanguml::t00074

tests/t00074/t00074.cc

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
namespace clanguml {
2+
namespace t00074 {
3+
template <typename T>
4+
concept fruit_c = requires(T t) {
5+
T{};
6+
t.get_name();
7+
};
8+
9+
template <typename T>
10+
concept apple_c = fruit_c<T> && requires(T t) { t.get_sweetness(); };
11+
12+
template <typename T>
13+
concept orange_c = fruit_c<T> && requires(T t) { t.get_bitterness(); };
14+
15+
}
16+
}

tests/t00074/test_case.h

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/**
2+
* tests/t00074/test_case.h
3+
*
4+
* Copyright (c) 2021-2024 Bartek Kryza <[email protected]>
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
TEST_CASE("t00074", "[test-case][class]")
20+
{
21+
auto [config, db] = load_config("t00074");
22+
23+
auto diagram = config.diagrams["t00074_class"];
24+
25+
REQUIRE(diagram->name == "t00074_class");
26+
27+
auto model = generate_class_diagram(*db, diagram);
28+
29+
REQUIRE(model->name() == "t00074_class");
30+
31+
{
32+
auto src = generate_class_puml(diagram, *model);
33+
AliasMatcher _A(src);
34+
35+
REQUIRE_THAT(src, StartsWith("@startuml"));
36+
REQUIRE_THAT(src, EndsWith("@enduml\n"));
37+
38+
REQUIRE_THAT(src, IsConcept(_A("fruit_c<T>")));
39+
REQUIRE_THAT(src, IsConcept(_A("apple_c<T>")));
40+
REQUIRE_THAT(src, IsConcept(_A("orange_c<T>")));
41+
42+
REQUIRE_THAT(
43+
src, IsConstraint(_A("apple_c<T>"), _A("fruit_c<T>"), "T"));
44+
REQUIRE_THAT(
45+
src, IsConstraint(_A("orange_c<T>"), _A("fruit_c<T>"), "T"));
46+
47+
REQUIRE_THAT(
48+
src, !IsConceptRequirement(_A("apple_c<T>"), "t.get_sweetness()"));
49+
REQUIRE_THAT(src,
50+
!IsConceptRequirement(_A("orange_c<T>"), "t.get_bitterness()"));
51+
52+
save_puml(config.output_directory(), diagram->name + ".puml", src);
53+
}
54+
55+
{
56+
auto j = generate_class_json(diagram, *model);
57+
58+
using namespace json;
59+
60+
REQUIRE(IsConcept(j, "fruit_c<T>"));
61+
REQUIRE(IsConcept(j, "apple_c<T>"));
62+
REQUIRE(IsConcept(j, "orange_c<T>"));
63+
64+
save_json(config.output_directory(), diagram->name + ".json", j);
65+
}
66+
67+
{
68+
auto src = generate_class_mermaid(diagram, *model);
69+
70+
mermaid::AliasMatcher _A(src);
71+
using mermaid::IsConcept;
72+
using mermaid::IsConceptRequirement;
73+
using mermaid::IsConstraint;
74+
75+
REQUIRE_THAT(src, IsConcept(_A("fruit_c<T>")));
76+
REQUIRE_THAT(src, IsConcept(_A("apple_c<T>")));
77+
REQUIRE_THAT(src, IsConcept(_A("orange_c<T>")));
78+
79+
REQUIRE_THAT(
80+
src, IsConstraint(_A("apple_c<T>"), _A("fruit_c<T>"), "T"));
81+
REQUIRE_THAT(
82+
src, IsConstraint(_A("orange_c<T>"), _A("fruit_c<T>"), "T"));
83+
84+
REQUIRE_THAT(
85+
src, !IsConceptRequirement(_A("apple_c<T>"), "t.get_sweetness()"));
86+
REQUIRE_THAT(
87+
src, !IsConceptRequirement(_A("apple_c<T>"), "t.get_bitterness()"));
88+
89+
save_mermaid(config.output_directory(), diagram->name + ".mmd", src);
90+
}
91+
}

tests/test_cases.cc

+3
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,9 @@ using namespace clanguml::test::matchers;
415415
#include "t00072/test_case.h"
416416
#endif
417417
#include "t00073/test_case.h"
418+
#if defined(ENABLE_CXX_STD_20_TEST_CASES)
419+
#include "t00074/test_case.h"
420+
#endif
418421

419422
///
420423
/// Sequence diagram tests

tests/test_cases.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,9 @@ test_cases:
216216
- name: t00073
217217
title: Class diagram for template overload pattern
218218
description:
219+
- name: t00074
220+
title: Test case for rendering concepts without requirements
221+
description:
219222
Sequence diagrams:
220223
- name: t20001
221224
title: Basic sequence diagram test case

0 commit comments

Comments
 (0)