Changed 'start_from' to simply 'from' in sequence diagrams
This commit is contained in:
@@ -45,71 +45,106 @@ Consider the following diagram:
|
||||
|
||||

|
||||
|
||||
`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:
|
||||
|
||||

|
||||
|
||||
## 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:
|
||||

|
||||
|
||||
## 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: ..
|
||||
|
||||
@@ -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"};
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -13,7 +13,7 @@ diagrams:
|
||||
- clanguml::t20001::detail
|
||||
using_namespace:
|
||||
- clanguml::t20001
|
||||
start_from:
|
||||
from:
|
||||
- function: "clanguml::t20001::tmain()"
|
||||
plantuml:
|
||||
before:
|
||||
|
||||
@@ -10,5 +10,5 @@ diagrams:
|
||||
- clanguml::t20002
|
||||
using_namespace:
|
||||
- clanguml::t20002
|
||||
start_from:
|
||||
from:
|
||||
- function: "clanguml::t20002::m1()"
|
||||
|
||||
@@ -10,5 +10,5 @@ diagrams:
|
||||
- clanguml::t20003
|
||||
using_namespace:
|
||||
- clanguml::t20003
|
||||
start_from:
|
||||
from:
|
||||
- function: "clanguml::t20003::m1<T>(T)"
|
||||
|
||||
@@ -10,5 +10,5 @@ diagrams:
|
||||
- clanguml::t20004
|
||||
using_namespace:
|
||||
- clanguml::t20004
|
||||
start_from:
|
||||
from:
|
||||
- function: "clanguml::t20004::main()"
|
||||
@@ -10,5 +10,5 @@ diagrams:
|
||||
- clanguml::t20005
|
||||
using_namespace:
|
||||
- clanguml::t20005
|
||||
start_from:
|
||||
from:
|
||||
- function: "clanguml::t20005::C<T>::c(T)"
|
||||
@@ -10,5 +10,5 @@ diagrams:
|
||||
- clanguml::t20006
|
||||
using_namespace:
|
||||
- clanguml::t20006
|
||||
start_from:
|
||||
from:
|
||||
- function: "clanguml::t20006::tmain()"
|
||||
@@ -10,5 +10,5 @@ diagrams:
|
||||
- clanguml::t20007
|
||||
using_namespace:
|
||||
- clanguml::t20007
|
||||
start_from:
|
||||
from:
|
||||
- function: "clanguml::t20007::tmain()"
|
||||
@@ -10,5 +10,5 @@ diagrams:
|
||||
- clanguml::t20008
|
||||
using_namespace:
|
||||
- clanguml::t20008
|
||||
start_from:
|
||||
from:
|
||||
- function: "clanguml::t20008::tmain()"
|
||||
@@ -10,5 +10,5 @@ diagrams:
|
||||
- clanguml::t20009
|
||||
using_namespace:
|
||||
- clanguml::t20009
|
||||
start_from:
|
||||
from:
|
||||
- function: "clanguml::t20009::tmain()"
|
||||
@@ -10,5 +10,5 @@ diagrams:
|
||||
- clanguml::t20010
|
||||
using_namespace:
|
||||
- clanguml::t20010
|
||||
start_from:
|
||||
from:
|
||||
- function: "clanguml::t20010::tmain()"
|
||||
@@ -10,5 +10,5 @@ diagrams:
|
||||
- clanguml::t20011
|
||||
using_namespace:
|
||||
- clanguml::t20011
|
||||
start_from:
|
||||
from:
|
||||
- function: "clanguml::t20011::tmain()"
|
||||
@@ -10,5 +10,5 @@ diagrams:
|
||||
- clanguml::t20012
|
||||
using_namespace:
|
||||
- clanguml::t20012
|
||||
start_from:
|
||||
from:
|
||||
- function: "clanguml::t20012::tmain()"
|
||||
@@ -10,5 +10,5 @@ diagrams:
|
||||
- clanguml::t20013
|
||||
using_namespace:
|
||||
- clanguml::t20013
|
||||
start_from:
|
||||
from:
|
||||
- function: "clanguml::t20013::tmain(int,char **)"
|
||||
@@ -13,5 +13,5 @@ diagrams:
|
||||
- clanguml::t20014
|
||||
using_namespace:
|
||||
- clanguml::t20014
|
||||
start_from:
|
||||
from:
|
||||
- function: "clanguml::t20014::tmain()"
|
||||
@@ -13,5 +13,5 @@ diagrams:
|
||||
- clanguml::t20015::detail
|
||||
using_namespace:
|
||||
- clanguml::t20015
|
||||
start_from:
|
||||
from:
|
||||
- function: "clanguml::t20015::tmain()"
|
||||
@@ -10,5 +10,5 @@ diagrams:
|
||||
- clanguml::t20016
|
||||
using_namespace:
|
||||
- clanguml::t20016
|
||||
start_from:
|
||||
from:
|
||||
- function: "clanguml::t20016::tmain()"
|
||||
@@ -14,5 +14,5 @@ diagrams:
|
||||
- .
|
||||
using_namespace:
|
||||
- clanguml::t20017
|
||||
start_from:
|
||||
from:
|
||||
- function: "clanguml::t20017::tmain()"
|
||||
@@ -10,5 +10,5 @@ diagrams:
|
||||
- clanguml::t20018
|
||||
using_namespace:
|
||||
- clanguml::t20018
|
||||
start_from:
|
||||
from:
|
||||
- function: "clanguml::t20018::tmain()"
|
||||
@@ -10,5 +10,5 @@ diagrams:
|
||||
- clanguml::t20019
|
||||
using_namespace:
|
||||
- clanguml::t20019
|
||||
start_from:
|
||||
from:
|
||||
- function: "clanguml::t20019::tmain()"
|
||||
@@ -10,5 +10,5 @@ diagrams:
|
||||
- clanguml::t20020
|
||||
using_namespace:
|
||||
- clanguml::t20020
|
||||
start_from:
|
||||
from:
|
||||
- function: "clanguml::t20020::tmain()"
|
||||
@@ -10,5 +10,5 @@ diagrams:
|
||||
- clanguml::t20021
|
||||
using_namespace:
|
||||
- clanguml::t20021
|
||||
start_from:
|
||||
from:
|
||||
- function: "clanguml::t20021::tmain()"
|
||||
@@ -10,5 +10,5 @@ diagrams:
|
||||
- clanguml::t20022
|
||||
using_namespace:
|
||||
- clanguml::t20022
|
||||
start_from:
|
||||
from:
|
||||
- function: "clanguml::t20022::tmain()"
|
||||
@@ -10,5 +10,5 @@ diagrams:
|
||||
- clanguml::t20024
|
||||
using_namespace:
|
||||
- clanguml::t20024
|
||||
start_from:
|
||||
from:
|
||||
- function: "clanguml::t20024::tmain()"
|
||||
@@ -10,5 +10,5 @@ diagrams:
|
||||
- clanguml::t20025
|
||||
using_namespace:
|
||||
- clanguml::t20025
|
||||
start_from:
|
||||
from:
|
||||
- function: "clanguml::t20025::tmain()"
|
||||
@@ -10,5 +10,5 @@ diagrams:
|
||||
- clanguml::t20026
|
||||
using_namespace:
|
||||
- clanguml::t20026
|
||||
start_from:
|
||||
from:
|
||||
- function: "clanguml::t20026::tmain()"
|
||||
@@ -12,5 +12,5 @@ diagrams:
|
||||
- public
|
||||
using_namespace:
|
||||
- clanguml::t20027
|
||||
start_from:
|
||||
from:
|
||||
- function: "clanguml::t20027::tmain()"
|
||||
@@ -13,5 +13,5 @@ diagrams:
|
||||
- clanguml::t20028::detail
|
||||
using_namespace:
|
||||
- clanguml::t20028
|
||||
start_from:
|
||||
from:
|
||||
- function: "clanguml::t20028::tmain()"
|
||||
@@ -13,7 +13,7 @@ diagrams:
|
||||
- private
|
||||
using_namespace:
|
||||
- clanguml::t20029
|
||||
start_from:
|
||||
from:
|
||||
- function: clanguml::t20029::tmain()
|
||||
participants_order:
|
||||
- clanguml::t20029::tmain()
|
||||
|
||||
@@ -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)"
|
||||
@@ -15,6 +15,6 @@ diagrams:
|
||||
- lambda
|
||||
using_namespace:
|
||||
- clanguml::t20031
|
||||
start_from:
|
||||
from:
|
||||
- function: "clanguml::t20031::tmain(int)"
|
||||
- function: "clanguml::t20031::tmain(bool,int)"
|
||||
@@ -11,5 +11,5 @@ diagrams:
|
||||
using_namespace:
|
||||
- clanguml::t20032
|
||||
generate_return_types: true
|
||||
start_from:
|
||||
from:
|
||||
- function: "clanguml::t20032::tmain(int,char **)"
|
||||
@@ -11,5 +11,5 @@ diagrams:
|
||||
using_namespace:
|
||||
- clanguml::t20033
|
||||
generate_condition_statements: true
|
||||
start_from:
|
||||
from:
|
||||
- function: "clanguml::t20033::tmain()"
|
||||
Reference in New Issue
Block a user