Changed 'start_from' to simply 'from' in sequence diagrams

This commit is contained in:
Bartek Kryza
2023-08-31 23:26:53 +02:00
parent 51e0275db3
commit e830195fb7
40 changed files with 136 additions and 78 deletions

View File

@@ -45,71 +45,106 @@ Consider the following diagram:
![extension](test_cases/t20029_sequence.svg)
`clang-uml` generated sequence diagrams are not strictly speaking conforming to the UML specification. In order to
make them more useful for documenting modern C++ code, the following assumptions were made:
* Free functions are included in the sequence diagrams as standalone participants (in fact `clang-uml` can be used
to generate sequence diagrams from plain old C code). Functions can also be aggregated into file participants,
based on their place of declaration
* Call expressions in conditional expressions in block statements (e.g. `if` or `while`) are rendered inside the
PlantUML `alt` or `loop` blocks but wrapped in `[`, `]` brackets
* Lambda expressions are generated as standalone participants, whose name comprises the parent context where they
are defined and the exact source code location
`clang-uml` generated sequence diagrams are not strictly speaking conforming to
the UML specification. In order to make them more useful for documenting modern
C++ code, the following assumptions were made:
* Free functions are included in the sequence diagrams as standalone
participants (in fact `clang-uml` can be used to generate sequence diagrams
from plain old C code). Functions can also be aggregated into file
participants, based on their place of declaration
* Call expressions in conditional expressions in block statements (e.g. `if`
or `while`) are rendered inside the PlantUML `alt` or `loop` blocks but
wrapped in `[`, `]` brackets
* Lambda expressions are generated as standalone participants, whose name
comprises the parent context where they are defined and the exact source code
location
## Specifying diagram location constraints
Sequence diagrams require a specification of location constraints in order to
determine, which call chains should be included in the diagram. Currently,
there are 3 types of constraints:
* `from` - will include all message call chains which start at the
locations specified in this constraint (this was previously named
`start_from`)
* `to` - will include all message call chains which end at the specified
locations
* `from_to` - will include all call chains which start and end at the specified
location constraints
Currently, the constraints can be a method or a free function, both specified
using the full signature of the function, e.g.
## Specifying diagram entry point
Sequence diagrams require an entry point for the diagram in order to determine, at which point in the code the sequence
diagram should start. Currently, the entry point can only be a method or a free function, both specified using `start_from`
configuration property, for instance:
```yaml
start_from:
from:
- function: "main(int,const char**)"
```
or
```yaml
start_from:
- function: "clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitCXXRecordDecl(clang::CXXRecordDecl *)"
to:
- function: "clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitCXXRecordDecl(clang::CXXRecordDecl *)"
```
The entrypoints must be fully qualified and they must match exactly the string
representation of given function or method in the `clang-uml` model.
The locations must be fully qualified, and they must match exactly the string
representation of a given function or method in the `clang-uml` model.
To find the exact function signature run `clang-uml` as follows:
In case of the `from_to` constraint, it is necessary to provide both `from`
and `to` locations as follows:
```yaml
from_to:
- [function: "clanguml::t20034::D::d2()",
function: "clanguml::t20034::A::a2()"]
```
To find the exact function signature which can be used as a `from` location,
run `clang-uml` as follows:
```bash
clang-uml --print-start-from -n main_sequence | grep main
clang-uml --print-from -n main_sequence | grep main
```
Command line flag `--print-start-from` will print on stdout all functions
and methods available in the diagram model, and each line of this output
can be directly used as a value of `start_from` option in the config file.
or to get all possible `to` locations, run:
```bash
clang-uml --print-to -n main_sequence | grep main
```
Command line flags `--print-from` and `--print-to` will print on stdout all
functions and methods available in the diagram model, and each line of this
output can be directly used as a value of `start_from`, `from_to` or `to`
properties in the config file.
Since that list can be quite large, it's best to filter the output to limit
the number of lines to a subset of possible candidates.
## Grouping free functions by file
By default, `clang-uml` will generate a new participant for each call to a free function (not method), which can lead
to a very large number of participants in the diagram. If it's an issue, an option can be provided in the diagram
By default, `clang-uml` will generate a new participant for each call to a free
function (not method), which can lead to a very large number of participants in
the diagram. If it's an issue, an option can be provided in the diagram
definition:
```yaml
combine_free_functions_into_file_participants: true
```
which will aggregate free functions per source file where they were declared thus minimizing the
diagram size. An example of such diagram is presented below:
which will aggregate free functions per source file where they were declared
thus minimizing the diagram size. An example of such diagram is presented below:
![extension](test_cases/t20017_sequence.svg)
## Lambda expressions in sequence diagrams
Lambda expressions in sequence diagrams are... tricky. There is currently tentative support, which follows the
following rules:
* If lambda expression is called within the scope of the diagram, the calls from the lambda will be placed
at the lambda invocation and not declaration
* If lambda expression is passed to some function or method, which is outside the scope of the diagram
(e.g. used in `std::transform` call) the call will not be generated
* If the lambda is passed as template parameter in instantiation it will not be generated
Lambda expressions in sequence diagrams are... tricky. There is currently
tentative support, which follows the following rules:
* If lambda expression is called within the scope of the diagram, the calls
from the lambda will be placed at the lambda invocation and not declaration
* If lambda expression is passed to some function or method, which is outside
the scope of the diagram (e.g. used in `std::transform` call) the call will
not be generated
* If the lambda is passed as template parameter in instantiation it will not
be generated
Another issue is the naming of lambda participants. Currently, each lambda is rendered in the diagram as a separate
class whose name is composed of the lambda location in the code (the only unique way of identifying lambdas I was able
Another issue is the naming of lambda participants. Currently, each lambda is
rendered in the diagram as a separate class whose name is composed of the lambda
location in the code (the only unique way of identifying lambdas I was able
to find). For example the following code:
```cpp
@@ -216,10 +251,11 @@ results in the following diagram:
![extension](test_cases/t20012_sequence.svg)
## Customizing participants order
The default participant order in the sequence diagram can be suboptimal in the sense that consecutive calls
can go right, then left, then right again depending on the specific call chain in the code. It is however
possible to override this order in the diagram definition using `participants_order` property,
for instance like this test case:
The default participant order in the sequence diagram can be suboptimal in the
sense that consecutive calls can go right, then left, then right again
depending on the specific call chain in the code. It is however
possible to override this order in the diagram definition using
`participants_order` property, for instance like this test case:
```yaml
compilation_database_dir: ..

View File

@@ -541,7 +541,8 @@ struct sequence_diagram : public diagram {
common::model::diagram_t type() const override;
option<std::vector<source_location>> start_from{"start_from"};
option<std::vector<source_location>> from{
option_with_alt_names_tag{}, "from", {"start_from"}};
option<std::vector<std::vector<source_location>>> from_to{"from_to"};
option<std::vector<source_location>> to{"to"};
};

View File

@@ -32,6 +32,8 @@ enum class option_inherit_mode {
kAppend /*!< Append to list options */
};
struct option_with_alt_names_tag { };
/**
* @brief Generic configuration option type
*
@@ -62,6 +64,15 @@ template <typename T> struct option {
, inheritance_mode{im}
{
}
option(option_with_alt_names_tag /*unused*/, std::string name_,
std::vector<std::string> alternate_names_,
option_inherit_mode im = option_inherit_mode::kOverride)
: name{std::move(name_)}
, alternate_names{std::move(alternate_names_)}
, value{}
, inheritance_mode{im}
{
}
/**
* @brief Set the option value
@@ -107,6 +118,9 @@ template <typename T> struct option {
/*! Option name, it is also the YAML key in the configuration file */
std::string name;
/*! Alternate option names */
std::vector<std::string> alternate_names;
/*! Option value */
T value;

View File

@@ -194,7 +194,8 @@ types:
generate_return_types: !optional bool
generate_condition_statements: !optional bool
participants_order: !optional [string]
start_from: !optional [source_location_t]
start_from: !optional [source_location_t] # deprecated -> 'from'
from: !optional [source_location_t]
from_to: !optional [[source_location_t]]
to: !optional [source_location_t]
package_diagram_t:

View File

@@ -65,6 +65,12 @@ void get_option(const Node &node, clanguml::config::option<T> &option)
{
if (node[option.name])
option.set(node[option.name].template as<T>());
for (const auto &alt_name : option.alternate_names)
if (node[alt_name]) {
option.set(node[alt_name].template as<T>());
break;
}
}
template <>
@@ -573,7 +579,7 @@ template <> struct convert<sequence_diagram> {
if (!decode_diagram(node, rhs))
return false;
get_option(node, rhs.start_from);
get_option(node, rhs.from);
get_option(node, rhs.from_to);
get_option(node, rhs.to);
get_option(node, rhs.combine_free_functions_into_file_participants);

View File

@@ -347,7 +347,7 @@ YAML::Emitter &operator<<(YAML::Emitter &out, const sequence_diagram &c)
{
out << YAML::BeginMap;
out << YAML::Key << "type" << YAML::Value << c.type();
out << c.start_from;
out << c.from;
out << c.from_to;
out << c.to;
out << dynamic_cast<const inheritable_diagram_options &>(c);

View File

@@ -691,7 +691,7 @@ void generator::generate_diagram(nlohmann::json &parent) const
json_["sequences"].push_back(std::move(sequence));
}
for (const auto &sf : config().start_from()) {
for (const auto &sf : config().from()) {
if (sf.location_type == location_t::function) {
common::model::diagram_element::id_t start_from{0};
std::string start_from_str;

View File

@@ -488,7 +488,7 @@ void generator::generate_diagram(std::ostream &ostr) const
}
}
for (const auto &sf : config().start_from()) {
for (const auto &sf : config().from()) {
if (sf.location_type == location_t::function) {
common::model::diagram_element::id_t start_from{0};
for (const auto &[k, v] : model().sequences()) {

View File

@@ -13,7 +13,7 @@ diagrams:
- clanguml::t20001::detail
using_namespace:
- clanguml::t20001
start_from:
from:
- function: "clanguml::t20001::tmain()"
plantuml:
before:

View File

@@ -10,5 +10,5 @@ diagrams:
- clanguml::t20002
using_namespace:
- clanguml::t20002
start_from:
from:
- function: "clanguml::t20002::m1()"

View File

@@ -10,5 +10,5 @@ diagrams:
- clanguml::t20003
using_namespace:
- clanguml::t20003
start_from:
from:
- function: "clanguml::t20003::m1<T>(T)"

View File

@@ -10,5 +10,5 @@ diagrams:
- clanguml::t20004
using_namespace:
- clanguml::t20004
start_from:
from:
- function: "clanguml::t20004::main()"

View File

@@ -10,5 +10,5 @@ diagrams:
- clanguml::t20005
using_namespace:
- clanguml::t20005
start_from:
from:
- function: "clanguml::t20005::C<T>::c(T)"

View File

@@ -10,5 +10,5 @@ diagrams:
- clanguml::t20006
using_namespace:
- clanguml::t20006
start_from:
from:
- function: "clanguml::t20006::tmain()"

View File

@@ -10,5 +10,5 @@ diagrams:
- clanguml::t20007
using_namespace:
- clanguml::t20007
start_from:
from:
- function: "clanguml::t20007::tmain()"

View File

@@ -10,5 +10,5 @@ diagrams:
- clanguml::t20008
using_namespace:
- clanguml::t20008
start_from:
from:
- function: "clanguml::t20008::tmain()"

View File

@@ -10,5 +10,5 @@ diagrams:
- clanguml::t20009
using_namespace:
- clanguml::t20009
start_from:
from:
- function: "clanguml::t20009::tmain()"

View File

@@ -10,5 +10,5 @@ diagrams:
- clanguml::t20010
using_namespace:
- clanguml::t20010
start_from:
from:
- function: "clanguml::t20010::tmain()"

View File

@@ -10,5 +10,5 @@ diagrams:
- clanguml::t20011
using_namespace:
- clanguml::t20011
start_from:
from:
- function: "clanguml::t20011::tmain()"

View File

@@ -10,5 +10,5 @@ diagrams:
- clanguml::t20012
using_namespace:
- clanguml::t20012
start_from:
from:
- function: "clanguml::t20012::tmain()"

View File

@@ -10,5 +10,5 @@ diagrams:
- clanguml::t20013
using_namespace:
- clanguml::t20013
start_from:
from:
- function: "clanguml::t20013::tmain(int,char **)"

View File

@@ -13,5 +13,5 @@ diagrams:
- clanguml::t20014
using_namespace:
- clanguml::t20014
start_from:
from:
- function: "clanguml::t20014::tmain()"

View File

@@ -13,5 +13,5 @@ diagrams:
- clanguml::t20015::detail
using_namespace:
- clanguml::t20015
start_from:
from:
- function: "clanguml::t20015::tmain()"

View File

@@ -10,5 +10,5 @@ diagrams:
- clanguml::t20016
using_namespace:
- clanguml::t20016
start_from:
from:
- function: "clanguml::t20016::tmain()"

View File

@@ -14,5 +14,5 @@ diagrams:
- .
using_namespace:
- clanguml::t20017
start_from:
from:
- function: "clanguml::t20017::tmain()"

View File

@@ -10,5 +10,5 @@ diagrams:
- clanguml::t20018
using_namespace:
- clanguml::t20018
start_from:
from:
- function: "clanguml::t20018::tmain()"

View File

@@ -10,5 +10,5 @@ diagrams:
- clanguml::t20019
using_namespace:
- clanguml::t20019
start_from:
from:
- function: "clanguml::t20019::tmain()"

View File

@@ -10,5 +10,5 @@ diagrams:
- clanguml::t20020
using_namespace:
- clanguml::t20020
start_from:
from:
- function: "clanguml::t20020::tmain()"

View File

@@ -10,5 +10,5 @@ diagrams:
- clanguml::t20021
using_namespace:
- clanguml::t20021
start_from:
from:
- function: "clanguml::t20021::tmain()"

View File

@@ -10,5 +10,5 @@ diagrams:
- clanguml::t20022
using_namespace:
- clanguml::t20022
start_from:
from:
- function: "clanguml::t20022::tmain()"

View File

@@ -10,5 +10,5 @@ diagrams:
- clanguml::t20024
using_namespace:
- clanguml::t20024
start_from:
from:
- function: "clanguml::t20024::tmain()"

View File

@@ -10,5 +10,5 @@ diagrams:
- clanguml::t20025
using_namespace:
- clanguml::t20025
start_from:
from:
- function: "clanguml::t20025::tmain()"

View File

@@ -10,5 +10,5 @@ diagrams:
- clanguml::t20026
using_namespace:
- clanguml::t20026
start_from:
from:
- function: "clanguml::t20026::tmain()"

View File

@@ -12,5 +12,5 @@ diagrams:
- public
using_namespace:
- clanguml::t20027
start_from:
from:
- function: "clanguml::t20027::tmain()"

View File

@@ -13,5 +13,5 @@ diagrams:
- clanguml::t20028::detail
using_namespace:
- clanguml::t20028
start_from:
from:
- function: "clanguml::t20028::tmain()"

View File

@@ -13,7 +13,7 @@ diagrams:
- private
using_namespace:
- clanguml::t20029
start_from:
from:
- function: clanguml::t20029::tmain()
participants_order:
- clanguml::t20029::tmain()

View File

@@ -10,6 +10,6 @@ diagrams:
- clanguml::t20030
using_namespace:
- clanguml::t20030
start_from:
from:
- function: "clanguml::t20030::tmain(int)"
- function: "clanguml::t20030::tmain(bool,int)"

View File

@@ -15,6 +15,6 @@ diagrams:
- lambda
using_namespace:
- clanguml::t20031
start_from:
from:
- function: "clanguml::t20031::tmain(int)"
- function: "clanguml::t20031::tmain(bool,int)"

View File

@@ -11,5 +11,5 @@ diagrams:
using_namespace:
- clanguml::t20032
generate_return_types: true
start_from:
from:
- function: "clanguml::t20032::tmain(int,char **)"

View File

@@ -11,5 +11,5 @@ diagrams:
using_namespace:
- clanguml::t20033
generate_condition_statements: true
start_from:
from:
- function: "clanguml::t20033::tmain()"