Added initial documentation
This commit is contained in:
18
docs/README.md
Normal file
18
docs/README.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# Documentation
|
||||
|
||||
|
||||
* [Quick start](./quick_start.md)
|
||||
* Generating diagrams
|
||||
* [Common options](./common_options.md)
|
||||
* [Class diagrams](./class_diagrams.md)
|
||||
* [Sequence diagrams](./sequence_diagrams.md)
|
||||
* [Package diagrams](./package_diagrams.md)
|
||||
* [Include diagrams](./include_diagrams.md)
|
||||
* [Comment decorators](./comment_decorators.md)
|
||||
* [Diagram filters](./diagram_filters.md)
|
||||
* [Using Jinja templates](./jinja_templates.md)
|
||||
* [Interactive SVG diagrams using links](./interactive_svg_diagrams.md)
|
||||
* [Configuration file reference](./configuration_file.md)
|
||||
* [Doxygen integration](./doxygen_integration.md)
|
||||
* [Test cases documentation](./test_cases.md)
|
||||
* [Troubleshooting](./troubleshooting.md)
|
||||
159
docs/class_diagrams.md
Normal file
159
docs/class_diagrams.md
Normal file
@@ -0,0 +1,159 @@
|
||||
# Generating class diagrams
|
||||
|
||||
The minimal config required to generate a class diagram is presented below:
|
||||
```yaml
|
||||
# Path to the directory where `compile_commands.json` can be found
|
||||
compilation_database_dir: _build
|
||||
# Output directory for the diagrams
|
||||
output_directory: puml
|
||||
# Diagrams definitions
|
||||
diagrams:
|
||||
# Diagram name
|
||||
t00002_class:
|
||||
# Type of diagram (has to be `class`)
|
||||
type: class
|
||||
# Include only translation units matching the following patterns
|
||||
glob:
|
||||
- src/*.cc
|
||||
# Render all names in the diagram relative to specific namespace
|
||||
using_namespace:
|
||||
- ns1
|
||||
# Include only classes from specific namespace
|
||||
include:
|
||||
namespaces:
|
||||
- ns1::ns2
|
||||
```
|
||||
|
||||
## Classes and their properties
|
||||
The basic class diagram generated by `clang-uml` and rendered using PlantUML looks like this:
|
||||
|
||||

|
||||
|
||||
Parameter types and method return types are rendered at the end after `:` sign.
|
||||
|
||||
Static methods and members are underlined.
|
||||
|
||||
In case method argument lists are too long and not required for diagram readability, they can be suppressed completely
|
||||
or abbreviated by setting `generate_method_arguments` option to either `none`, `abbreviated` or `full` (default).
|
||||
|
||||
|
||||
### Excluding private or protected members from the diagram
|
||||
In order to only include public members in the class diagrams, we can add the following inclusion filters:
|
||||
```yaml
|
||||
include:
|
||||
access:
|
||||
- public
|
||||
```
|
||||
|
||||
To render only classes without any properties an exclusion filter can be added:
|
||||
```yaml
|
||||
exclude:
|
||||
access:
|
||||
- public
|
||||
- protected
|
||||
- private
|
||||
```
|
||||
|
||||
## Relationships
|
||||
|
||||
The following table presents the PlantUML arrows representing each relationship in the class diagrams.
|
||||
|
||||
| UML | PlantUML |
|
||||
| ---- | --- |
|
||||
| Inheritance |  |
|
||||
| Association |  |
|
||||
| Dependency |  |
|
||||
| Aggregation |  |
|
||||
| Composition |  |
|
||||
| Template specialization/instantiation |  |
|
||||
| Nesting (inner class/enum) |  |
|
||||
| Include (local) |  |
|
||||
| Include (system) |  |
|
||||
|
||||
|
||||
By default, a member from which a relationship has been added to the diagram between 2 classes will also be rendered
|
||||
inside the class. This behaviour can be however disabled by adding the following option to the
|
||||
diagram definition:
|
||||
```yaml
|
||||
include_relations_also_as_members: false
|
||||
```
|
||||
|
||||
### Relationships to classes in containers or smart pointers
|
||||
`clang-uml` will automatically detect class members as well as method arguments, which reference or own
|
||||
values of types relevant for a given diagram but wrapped in smart pointers or containers ang still generate
|
||||
relationship between these classes, for instance the following code:
|
||||
|
||||
```cpp
|
||||
class A { };
|
||||
|
||||
class B { };
|
||||
|
||||
class C { };
|
||||
|
||||
class R {
|
||||
public:
|
||||
std::unique_ptr<A> a;
|
||||
std::shared_ptr<B> b;
|
||||
std::weak_ptr<C> c;
|
||||
};
|
||||
```
|
||||
|
||||
generates the following diagram:
|
||||
|
||||

|
||||
|
||||
## Inheritance diagrams
|
||||
|
||||
A common type of class diagram is an inheritance diagram, where only subclasses of a specific base class are
|
||||
included and only the inheritance relationships are rendered. This can be easily achieved in `clang-uml` through
|
||||
inclusion filters:
|
||||
```yaml
|
||||
include:
|
||||
subclasses:
|
||||
- clanguml::t00039::A
|
||||
relationships:
|
||||
- inheritance
|
||||
```
|
||||
|
||||
## Namespaces as packages
|
||||
By default, `clang-uml` will render all element names including a namespace (relative to `using_namespace` property),
|
||||
e.g. `ns1::ns2::MyClass`.
|
||||
In order to generate packages in the diagram for each namespace instead, the following option must be set to `true`:
|
||||
|
||||
```yaml
|
||||
generate_packages: true
|
||||
```
|
||||
|
||||
which results in the following diagram:
|
||||
|
||||

|
||||
|
||||
## Class context diagram
|
||||
Sometimes it's helpful to generate a class diagram depicting only direct relationships of a given class, e.g.
|
||||
within the classes documentation page, this can be easily achieved using `context` inclusion filter:
|
||||
|
||||
```yaml
|
||||
include:
|
||||
context:
|
||||
- ns1::MyClass
|
||||
```
|
||||
|
||||
## Disabling dependency relationships
|
||||
In many cases, dependency relationships between classes can clutter the diagram too much, for instance consider this
|
||||
diagram:
|
||||
|
||||

|
||||
|
||||
where the dependency relationships do not bring much information into the diagram. Thus in such cases it might
|
||||
be useful to disable dependency relationships for this diagram completely using the following exclusion filter:
|
||||
```yaml
|
||||
exclude:
|
||||
relationships:
|
||||
- dependency
|
||||
```
|
||||
|
||||
Dependency relationships are inferred whenever a class uses another class, thus often dependency relationship
|
||||
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.
|
||||
|
||||
|
||||
222
docs/comment_decorators.md
Normal file
222
docs/comment_decorators.md
Normal file
@@ -0,0 +1,222 @@
|
||||
# Comment decorators
|
||||
|
||||
`clang-uml` provides a set of in-comment directives, called decorators, which allow custom control over
|
||||
generation of UML diagrams from C++ and overriding default inference rules for relationships.
|
||||
|
||||
`clang-uml` decorators are specified in the following format:
|
||||
|
||||
```
|
||||
\uml{<decorator>[:<diagram_name>][<options>] <text>}
|
||||
```
|
||||
|
||||
or
|
||||
```
|
||||
@uml{<decorator>[:<diagram_name>][<options>] <text>}
|
||||
```
|
||||
|
||||
The optional `:<diagram_name>` suffix will apply this decorator only to a specific diagram.
|
||||
|
||||
Currently the following decorators are supported.
|
||||
|
||||
## `note`
|
||||
|
||||
This decorator allows to specify directly in the code comments that should be included in the generated diagrams.
|
||||
|
||||
The following code:
|
||||
```cpp
|
||||
/// \uml{note[top] A class note.}
|
||||
class A {
|
||||
};
|
||||
|
||||
/// \uml{note[] B class note.}
|
||||
class B {
|
||||
};
|
||||
|
||||
///
|
||||
/// @uml{note:t00028_class[bottom] C class note.}
|
||||
/// This is class C.
|
||||
class C {
|
||||
};
|
||||
|
||||
/// \uml{note
|
||||
/// D
|
||||
/// class
|
||||
/// note.}
|
||||
class D {
|
||||
};
|
||||
|
||||
/// \uml{note E template class note.}
|
||||
template <typename T> class E {
|
||||
T param;
|
||||
};
|
||||
|
||||
/// \uml{note:other_diagram[left] G class note.}
|
||||
class G {
|
||||
};
|
||||
|
||||
/// @uml{note[ bottom ] F enum note.}
|
||||
enum class F { one, two, three };
|
||||
|
||||
/// \uml{note[right] R class note.}
|
||||
class R {
|
||||
explicit R(C &c)
|
||||
: ccc(c)
|
||||
{
|
||||
}
|
||||
|
||||
A aaa;
|
||||
|
||||
B *bbb;
|
||||
|
||||
C &ccc;
|
||||
|
||||
std::vector<std::shared_ptr<D>> ddd;
|
||||
|
||||
E<int> eee;
|
||||
|
||||
G **ggg;
|
||||
};
|
||||
```
|
||||
|
||||
generates the following class diagram:
|
||||
|
||||

|
||||
|
||||
# `skip` and `skiprelationship`
|
||||
This decorator allows to skip the specific classes or methods from the diagrams, for instance the following code:
|
||||
```cpp
|
||||
|
||||
class A {
|
||||
};
|
||||
|
||||
/// \uml{skip}
|
||||
class B {
|
||||
};
|
||||
|
||||
template <typename T> class C {
|
||||
T param;
|
||||
};
|
||||
|
||||
/// @uml{skip:t00029_class}
|
||||
template <typename T> class D {
|
||||
T param;
|
||||
};
|
||||
|
||||
enum class E { one, two, three };
|
||||
|
||||
/// \uml{skip}
|
||||
enum class F { red, green, blue };
|
||||
|
||||
class G1 {
|
||||
};
|
||||
|
||||
class G2 {
|
||||
};
|
||||
|
||||
class G3 {
|
||||
};
|
||||
|
||||
class G4 {
|
||||
};
|
||||
|
||||
struct R {
|
||||
G1 g1;
|
||||
|
||||
/// \uml{skip}
|
||||
G2 g2;
|
||||
|
||||
/// \uml{skiprelationship}
|
||||
G3 &g3;
|
||||
|
||||
std::shared_ptr<G4> g4;
|
||||
};
|
||||
```
|
||||
|
||||
generates the following diagram:
|
||||
|
||||

|
||||
|
||||
## `composition`, `association` and `aggregation`
|
||||
|
||||
These decorators allow to specify explicitly the type of relationship within a class diagram that should be
|
||||
generated for a given class member. For instance the following code:
|
||||
|
||||
```cpp
|
||||
|
||||
class A {
|
||||
};
|
||||
|
||||
class B {
|
||||
};
|
||||
|
||||
class C {
|
||||
};
|
||||
|
||||
class D {
|
||||
};
|
||||
|
||||
class E {
|
||||
};
|
||||
|
||||
struct R {
|
||||
/// @uml{association[]}
|
||||
A aaa;
|
||||
|
||||
/// @uml{composition[0..1:1..*]}
|
||||
std::vector<B> bbb;
|
||||
|
||||
/// @uml{aggregation[0..1:1..5]}
|
||||
std::vector<C> ccc;
|
||||
|
||||
/// @uml{association[:1]}
|
||||
D ddd;
|
||||
|
||||
/// @uml{aggregation[:1]}
|
||||
E *eee;
|
||||
};
|
||||
```
|
||||
|
||||
generates the following diagram:
|
||||
|
||||

|
||||
|
||||
|
||||
## `style`
|
||||
This decorator allows to specify in the code specific styles for diagram elements, for instance:
|
||||
|
||||
```cpp
|
||||
|
||||
/// @uml{style[#back:lightgreen|yellow;header:blue/red]}
|
||||
class A {
|
||||
};
|
||||
|
||||
/// @uml{style[#line.dotted:blue]}
|
||||
enum B { one, two, three };
|
||||
|
||||
/// @uml{style[#pink;line:red;line.bold;text:red]}
|
||||
template <typename T> class C {
|
||||
T ttt;
|
||||
};
|
||||
|
||||
class D {
|
||||
};
|
||||
|
||||
struct R {
|
||||
/// @uml{style[#red,dashed,thickness=2]}
|
||||
A *aaa;
|
||||
|
||||
/// @uml{composition}
|
||||
/// @uml{style[#green,dashed,thickness=4]}
|
||||
std::vector<B> bbb;
|
||||
|
||||
/// @uml{style[#blue,dotted,thickness=8]}
|
||||
C<int> ccc;
|
||||
|
||||
/// @uml{style[#blue,plain,thickness=16]}
|
||||
D *ddd;
|
||||
};
|
||||
```
|
||||
|
||||
generates the following diagram:
|
||||
|
||||

|
||||
73
docs/common_options.md
Normal file
73
docs/common_options.md
Normal file
@@ -0,0 +1,73 @@
|
||||
# Common diagram generation options
|
||||
|
||||
## Overall configuration file structure
|
||||
By default, `clang-uml` will look for file `.clang-uml` in the projects directory and read all diagrams definitions
|
||||
from it. The file must be specified in YAML and it's overall structure is as follows:
|
||||
|
||||
```yaml
|
||||
<common options for all diagrams>
|
||||
diagrams:
|
||||
<first diagram name>:
|
||||
type: [class|sequence|package|include]
|
||||
<diagram specific options>
|
||||
<second diagram name>:
|
||||
type: [class|sequence|package|include]
|
||||
<diagram specific options>
|
||||
...
|
||||
```
|
||||
|
||||
The top level common options are inherited by specific diagrams, if the option is applicable to them and they themselves
|
||||
do not override this option.
|
||||
|
||||
For detailed reference of all configuration options see [here](./configuration_file.md).
|
||||
|
||||
## Translation unit glob patterns
|
||||
One of the key options of the diagram configuration is the list of translation units, which should be parsed to
|
||||
get all necessary information for a diagram.
|
||||
|
||||
The syntax is simple and based on glob patterns, which can be added to the configuration file as follows:
|
||||
|
||||
```yaml
|
||||
glob:
|
||||
- src/dir1/*.cc
|
||||
- src/dir3/*.cc
|
||||
```
|
||||
|
||||
The glob patterns only need to match the translation units, which are also in the `compile_commands.json` file, i.e.
|
||||
any files that match the glob patterns but are not in `compile_commands.json` will be ignored. In case the `glob`
|
||||
pattern set does not much any translation units an error will be printed on the standard output.
|
||||
|
||||
For small projects, the `glob` property can be omitted, which will result in `clang-uml` parsing all translation units
|
||||
from `compile_commands.json` for the diagram. However for large projects, constraining the number of translation units
|
||||
for each diagram to absolute minimum will significantly decrease the diagram generation times.
|
||||
|
||||
## PlantUML custom directives
|
||||
In case it's necessary to add some custom PlantUML declarations before or after the generated diagram content,
|
||||
it can be achieved simply using the `plantuml` configuration properties, for instance:
|
||||
|
||||
```yaml
|
||||
plantuml:
|
||||
before:
|
||||
- left to right direction
|
||||
after:
|
||||
- note left of {{ alias("ns1::ns2::MyClass") }} This is my class.
|
||||
```
|
||||
|
||||
These directive are useful for instance for adding notes to elements in the diagrams or customizing diagram layout
|
||||
or style.
|
||||
|
||||
Please note that when referring to diagram elements in the PlantUML directives, they must be added using Jinja
|
||||
templates `alias` command as in the example above.
|
||||
|
||||
More options can be found in the official PlantUML [documentation](https://plantuml.com/).
|
||||
|
||||
## Adding debug information in the generated diagrams
|
||||
Sometimes it is useful for debugging issues with the diagrams to have information on the exact source location,
|
||||
from which given declaration or call expression was derived. By adding option:
|
||||
|
||||
```yaml
|
||||
debug_mode: true
|
||||
```
|
||||
|
||||
the generated PlantUML diagram will contain comments before each line containing the source location of the
|
||||
specific diagram element.
|
||||
@@ -5,6 +5,7 @@
|
||||
* `output_directory` - path to the directory where PlantUML diagrams will be generated
|
||||
* `diagrams` - the map of diagrams to be generated, each diagram name is provided as
|
||||
the key of the diagram YAML node
|
||||
* `debug_mode` - add inline debug information in the generated diagrams
|
||||
|
||||
### Diagram options
|
||||
* `type` - type of diagram, one of [`class`, `sequence`, `package`, `include`]
|
||||
@@ -22,7 +23,7 @@
|
||||
* `dependants` - include all classes, which depend on the specified class
|
||||
* `dependencies` - include all classes, which are dependencies of the specified class
|
||||
* `context` - include only entities in direct relationship with specified classes
|
||||
* `exclude` - definition of excqlusion patterns:
|
||||
* `exclude` - definition of exclusion patterns:
|
||||
* `namespaces` - list of namespaces to exclude
|
||||
* `relationships` - list of relationships to exclude
|
||||
* `elements` - list of elements, i.e. specific classes, enums, templates to exclude
|
||||
@@ -37,112 +38,6 @@
|
||||
* `before` - list of directives which will be added before the generated diagram
|
||||
* `after` - list of directives which will be added after the generated diagram
|
||||
|
||||
### Template engine
|
||||
`clang-uml` integrates [inja](https://github.com/pantor/inja) template engine, with several
|
||||
additional functions which can be used in textual directives within the configuration files,
|
||||
notes and to generate links and tooltips to diagrams.
|
||||
|
||||
The following, are the `clang-uml` additional template functions:
|
||||
* `ltrim(string)` - left trims a string
|
||||
* `rtrim(string)` - right trims a string
|
||||
* `trim(string)` - trims a string
|
||||
* `substr(string, offset, length)` - returns a substring of a string from offset of length
|
||||
* `split(string)` - splits a string and returns a list of strings
|
||||
* `replace(string, regex, replacement)` - returns a string with replace matches to regex with replacement string
|
||||
* `abbrv(string, length)` - returns a string truncated to length including trailing ellipsis
|
||||
* `element(string)` - returns the entire JSON context a given diagram element, including the following properties:
|
||||
* `name` - name of the element
|
||||
* `type` - type of diagram element (e.g. `class`, `enum`, `package`)
|
||||
* `namespace` - fully qualified element namespace
|
||||
* `full_name` - fully qualified element name
|
||||
* `comment` [optional] - elements comment, if any
|
||||
* `alias` - internal diagram element alias (e.g. PlantUML alias)
|
||||
* `alias(string)` - returns a PlantUML alias of an C++ entity represented by string name
|
||||
* `comment(string)` - returns a comment of an C++ entity represented by string name
|
||||
|
||||
Templates allow complex postprocessing of the diagrams, for instance creation of customized PlantUML
|
||||
notes in the diagrams from comments in the code. Below is an example of using the above commands to
|
||||
generate notes in the PlantUML diagram from code comments (see also test case [t00050](./test_cases/t00050.md)):
|
||||
|
||||
```yaml
|
||||
plantuml:
|
||||
after:
|
||||
# Add a note left of the `A` class with the entire clas comment as content
|
||||
- >
|
||||
note left of {{ alias("A") }}
|
||||
{{ comment("clanguml::t00050::A").formatted }}
|
||||
end note
|
||||
# Same as above
|
||||
- >
|
||||
note right of {{ element("clanguml::t00050::A").alias }}
|
||||
{% set e=element("clanguml::t00050::A") %} {{ e.comment.formatted }}
|
||||
end note
|
||||
# Add a note left of class 'C' using trimmed text content from the class comment
|
||||
- >
|
||||
note left of {{ alias("C") }} #AABBCC
|
||||
{{ trim(comment("clanguml::t00050::C").text) }}
|
||||
end note
|
||||
# For each element in the diagram (class, template, enum):
|
||||
# - Add a note with \brief comment if exists
|
||||
# - Add a note with \todo for each element which has it
|
||||
# - Add a note with template parameter descriptions based on \tparam comment
|
||||
- >
|
||||
{# Render brief comments and todos, if any were written for an element #}
|
||||
{% for e in diagram.elements %}
|
||||
{% if existsIn(e, "comment") and existsIn(e.comment, "brief") %}
|
||||
|
||||
note top of {{ e.alias }} {% if e.type == "class" %} #22AA22 {% else %} #2222AA {% endif %}
|
||||
{% set c=e.comment %} {{ c.brief.0 }}
|
||||
end note
|
||||
|
||||
{% endif %}
|
||||
{% if existsIn(e, "comment") and existsIn(e.comment, "todo") %}
|
||||
{% set c=e.comment %}
|
||||
{% for t in c.todo %}
|
||||
note top of {{ e.alias }} #882222
|
||||
**TODO**
|
||||
{{ t }}
|
||||
end note
|
||||
|
||||
{% endfor %}
|
||||
|
||||
{% endif %}
|
||||
{# Render template paramete if any #}
|
||||
{% if existsIn(e, "comment") and existsIn(e.comment, "tparam") %}
|
||||
{% set c=e.comment %}
|
||||
|
||||
note top of {{ e.alias }} #AAAAFF
|
||||
**Template parameters**
|
||||
{% for tp in c.tparam %}
|
||||
//{{ tp.name }}// {{ trim(tp.description) }}
|
||||
{% endfor %}
|
||||
end note
|
||||
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
```
|
||||
Currently there are 2 available comment parsers:
|
||||
* `plain` - default
|
||||
* `clang`
|
||||
They can be selected using `comment_parser` config option.
|
||||
|
||||
#### `plain` comment parser
|
||||
This parser provides only 2 options to the Jinja context:
|
||||
* `comment.raw` - raw comment text, including comment markers such as `///` or `/**`
|
||||
* `comment.formatted` - formatted entire comment
|
||||
|
||||
#### `clang` comment parser
|
||||
This parser uses Clang comment parsing API to extract commands from the command:
|
||||
* `comment.raw` - raw comment text, including comment markers such as `///` or `/**`
|
||||
* `comment.formatted` - formatted entire comment
|
||||
* `comment.<command>.<N>` - where command is the command used in the command e.g. `brief`, `todo`, etc.
|
||||
and `N` is the index of the command in the array (each comment can have multiple instances of the
|
||||
same command such as `\todo`)
|
||||
* `comment.text` - entire text of the comment that is not attached to any command
|
||||
* `comment.paragraph.<N>` - array of plain text paragraphs, for instance if you don't use `\brief`
|
||||
commands but often provide brief description as first sentence of the comment separated with a new line
|
||||
from the rest of the comment
|
||||
|
||||
## Example complete config
|
||||
|
||||
```yaml
|
||||
|
||||
161
docs/diagram_filters.md
Normal file
161
docs/diagram_filters.md
Normal file
@@ -0,0 +1,161 @@
|
||||
# Diagram filters
|
||||
|
||||
Diagram filters are at the core of generating diagrams with `clang-uml`, as they allow to fine tune the scope
|
||||
of each diagram, and thus provide you with a several small, but readable diagrams instead of a single huge diagram
|
||||
that cannot be effectively browsed, printed or included in an online documentation of your project.
|
||||
|
||||
Filters can be specified separate for each diagram, and they can be added as either `include` or `exclude` filters,
|
||||
depending on which is more appropriate for a given diagram.
|
||||
|
||||
For instance to include only C++ entities from a namespace `ns1::ns2` but not `ns1::ns2::detail` add the following
|
||||
to your diagram configuration:
|
||||
|
||||
```yaml
|
||||
include:
|
||||
namespaces:
|
||||
- ns1::ns2
|
||||
exclude:
|
||||
namespaces:
|
||||
- ns1::ns2::detail
|
||||
```
|
||||
|
||||
The following filters are available.
|
||||
|
||||
## `namespaces`
|
||||
|
||||
Allows to include or exclude entities from specific namespaces.
|
||||
|
||||
## `elements`
|
||||
|
||||
Allows to directly include or exclude specific entities from the diagrams, for instance to exclude a specific class
|
||||
from an included namespace:
|
||||
|
||||
```yaml
|
||||
include:
|
||||
namespaces:
|
||||
- ns1::ns2
|
||||
exclude:
|
||||
elements:
|
||||
- ns1::ns2::MyClass
|
||||
```
|
||||
|
||||
## `context`
|
||||
|
||||
This filter allows to limit the diagram elements only to classes which are in direct relationship (of any kind) with
|
||||
the specified class:
|
||||
|
||||
```yaml
|
||||
include:
|
||||
context:
|
||||
- ns1::ns2::MyClass
|
||||
```
|
||||
|
||||
|
||||
## `relationships`
|
||||
|
||||
This filter allows to include or exclude specific types of relationships from the diagram, for instance to only
|
||||
include inheritance and template specialization/instantiation relationships add the following to the diagram:
|
||||
|
||||
```yaml
|
||||
include:
|
||||
relationships:
|
||||
- inheritance
|
||||
- instantiation
|
||||
```
|
||||
|
||||
The following relationships can be used in this filter:
|
||||
* inheritance
|
||||
* composition
|
||||
* aggregation
|
||||
* ownership
|
||||
* association
|
||||
* instantiation
|
||||
* friendship
|
||||
* dependency
|
||||
|
||||
## `subclasses`
|
||||
|
||||
This filter allows to include or exclude all subclasses of a given class in the diagram.
|
||||
|
||||
## `specializations`
|
||||
|
||||
This filter allows to include or exclude specializations and instantiations of a specific template from the diagram.
|
||||
|
||||
## `dependants` and `dependencies`
|
||||
|
||||
These filters allow to specify that only dependants or dependencies of a given class should be included in the diagram.
|
||||
This can be useful for analyzing what classes in your project depend on some other class, which could have impact for
|
||||
instance on refactoring.
|
||||
|
||||
For instance the following code:
|
||||
```cpp
|
||||
|
||||
namespace dependants {
|
||||
struct A {
|
||||
};
|
||||
|
||||
struct B {
|
||||
void b(A *a) { }
|
||||
};
|
||||
|
||||
struct BB {
|
||||
void bb(A *a) { }
|
||||
};
|
||||
|
||||
struct C {
|
||||
void c(B *b) { }
|
||||
};
|
||||
|
||||
struct D {
|
||||
void d(C *c) { }
|
||||
void dd(BB *bb) { }
|
||||
};
|
||||
|
||||
struct E {
|
||||
void e(D *d) { }
|
||||
};
|
||||
|
||||
struct F {
|
||||
};
|
||||
} // namespace dependants
|
||||
|
||||
namespace dependencies {
|
||||
|
||||
struct G {
|
||||
};
|
||||
|
||||
struct GG {
|
||||
};
|
||||
|
||||
struct H {
|
||||
void h(G *g) { }
|
||||
void hh(GG *gg) { }
|
||||
};
|
||||
|
||||
struct HH {
|
||||
void hh(G *g) { }
|
||||
};
|
||||
|
||||
struct I {
|
||||
void i(H *h) { }
|
||||
};
|
||||
|
||||
struct J {
|
||||
void i(I *i) { }
|
||||
};
|
||||
```
|
||||
|
||||
and the following filter:
|
||||
```yaml
|
||||
include:
|
||||
dependants:
|
||||
- clanguml::t00043::dependants::A
|
||||
dependencies:
|
||||
- clanguml::t00043::dependencies::J
|
||||
relationships:
|
||||
- dependency
|
||||
```
|
||||
|
||||
generates the following diagram:
|
||||
|
||||

|
||||
14
docs/doxygen_integration.md
Normal file
14
docs/doxygen_integration.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# Doxygen integration
|
||||
|
||||
`clang-uml` diagrams can be easily added to the Doxygen documentation using the image tag, however
|
||||
[Doxygen](https://www.doxygen.nl/index.html) does not support the `clang-uml` specific commands.
|
||||
|
||||
`clang-uml` decorators can be omitted completely in Doxygen, by adding the
|
||||
following lines to the Doxygen config file:
|
||||
|
||||
```
|
||||
ALIASES += uml=""
|
||||
ALIASES += uml{1}=""
|
||||
ALIASES += uml{2}=""
|
||||
ALIASES += uml{3}=""
|
||||
```
|
||||
51
docs/include_diagrams.md
Normal file
51
docs/include_diagrams.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# Generating include diagrams
|
||||
|
||||
Include diagrams allow to document the include dependencies among different parts of the project. This can be very useful
|
||||
for instance to detect that a file was included from a module directory, on which specific part of the project
|
||||
should not ever depend.
|
||||
|
||||
The minimal config required to generate an include diagram is presented below:
|
||||
```yaml
|
||||
# Path to the directory where `compile_commands.json` can be found
|
||||
compilation_database_dir: _build
|
||||
# Output directory for the diagrams
|
||||
output_directory: puml
|
||||
# Diagrams definitions
|
||||
diagrams:
|
||||
# Diagram name
|
||||
my_class_diagram:
|
||||
# Type of diagram (has to be `include`)
|
||||
type: include
|
||||
# Include only translation units matching the following patterns
|
||||
glob:
|
||||
- src/*.cc
|
||||
# Render the paths relative to this directory
|
||||
relative_to: src
|
||||
# Include also external system headers
|
||||
generate_system_headers: true
|
||||
# Include only classes and functions from files in `src` directory
|
||||
include:
|
||||
# Include only files belonging to these paths
|
||||
paths:
|
||||
- src
|
||||
```
|
||||
|
||||
One distinctive option in `include` diagrams is `relative_to`, which tells `clang-uml` to render all filename
|
||||
paths relative to this directory.
|
||||
|
||||
## Tracking system headers directly included by projects files
|
||||
|
||||
In case you would like to include the information about what system headers your projects file include simply add
|
||||
the following option to the diagram:
|
||||
|
||||
```yaml
|
||||
generate_system_headers: true
|
||||
```
|
||||
|
||||
This will include only system headers directly included from the projects source files (matched by `glob`) and not
|
||||
their dependencies, for example:
|
||||
|
||||

|
||||
|
||||
Please note that generating include diagram, which contains third party and system library headers will result
|
||||
in a huge diagram that will be unlikely to be useful.
|
||||
15
docs/interactive_svg_diagrams.md
Normal file
15
docs/interactive_svg_diagrams.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# Interactive SVG diagrams
|
||||
|
||||
`clang-uml` in combination with PlantUML's link generation in diagrams allows to generate interactive diagrams,
|
||||
where clicking on any class, method or call expression can direct the user directly to the source code or some other
|
||||
diagram or document available online.
|
||||
|
||||
For instance to generate links to GitHub repository directly for most of diagram elements simple add this to your
|
||||
`.clang-uml` file:
|
||||
```yaml
|
||||
generate_links:
|
||||
link: 'https://github.com/myorg/myrepo/blob/{{ git.commit }}/{{ element.source.path }}#L{{ element.source.line }}'
|
||||
tooltip: '{% if "comment" in element %}{{ abbrv(trim(replace(element.comment, "\n+", " ")), 256) }}{% else %}{{ element.name }}{% endif %}'
|
||||
```
|
||||
|
||||
You can open example diagram [here](https://raw.githubusercontent.com/bkryza/clang-uml/master/docs/test_cases/t00014_class.svg) to see how it works in action.
|
||||
111
docs/jinja_templates.md
Normal file
111
docs/jinja_templates.md
Normal file
@@ -0,0 +1,111 @@
|
||||
# Template engine
|
||||
`clang-uml` integrates [inja](https://github.com/pantor/inja) template engine, with several
|
||||
additional functions which can be used in textual directives within the configuration files,
|
||||
notes and to generate links and tooltips in diagrams.
|
||||
|
||||
The following, are the `clang-uml` additional template functions:
|
||||
* `ltrim(string)` - left trims a string
|
||||
* `rtrim(string)` - right trims a string
|
||||
* `trim(string)` - trims a string
|
||||
* `substr(string, offset, length)` - returns a substring of a string from offset of length
|
||||
* `split(string)` - splits a string and returns a list of strings
|
||||
* `replace(string, regex, replacement)` - returns a string with replace matches to regex with replacement string
|
||||
* `abbrv(string, length)` - returns a string truncated to length including trailing ellipsis
|
||||
* `element(string)` - returns the entire JSON context a given diagram element, including the following properties:
|
||||
* `name` - name of the element
|
||||
* `type` - type of diagram element (e.g. `class`, `enum`, `package`)
|
||||
* `namespace` - fully qualified element namespace
|
||||
* `full_name` - fully qualified element name
|
||||
* `comment` [optional] - elements comment, if any
|
||||
* `alias` - internal diagram element alias (e.g. PlantUML alias)
|
||||
* `alias(string)` - returns a PlantUML alias of an C++ entity represented by string name
|
||||
* `comment(string)` - returns a comment of an C++ entity represented by string name
|
||||
|
||||
Templates allow complex postprocessing of the diagrams, for instance creation of customized PlantUML
|
||||
notes in the diagrams from comments in the code. Below is an example of using the above commands to
|
||||
generate notes in the PlantUML diagram from code comments (see also test case [t00050](./test_cases/t00050.md)):
|
||||
|
||||
```yaml
|
||||
plantuml:
|
||||
after:
|
||||
# Add a note left of the `A` class with the entire clas comment as content
|
||||
- >
|
||||
note left of {{ alias("A") }}
|
||||
{{ comment("clanguml::t00050::A").formatted }}
|
||||
end note
|
||||
# Same as above
|
||||
- >
|
||||
note right of {{ element("clanguml::t00050::A").alias }}
|
||||
{% set e=element("clanguml::t00050::A") %} {{ e.comment.formatted }}
|
||||
end note
|
||||
# Add a note left of class 'C' using trimmed text content from the class comment
|
||||
- >
|
||||
note left of {{ alias("C") }} #AABBCC
|
||||
{{ trim(comment("clanguml::t00050::C").text) }}
|
||||
end note
|
||||
# For each element in the diagram (class, template, enum):
|
||||
# - Add a note with \brief comment if exists
|
||||
# - Add a note with \todo for each element which has it
|
||||
# - Add a note with template parameter descriptions based on \tparam comment
|
||||
- >
|
||||
{# Render brief comments and todos, if any were written for an element #}
|
||||
{% for e in diagram.elements %}
|
||||
{% if existsIn(e, "comment") and existsIn(e.comment, "brief") %}
|
||||
|
||||
note top of {{ e.alias }} {% if e.type == "class" %} #22AA22 {% else %} #2222AA {% endif %}
|
||||
{% set c=e.comment %} {{ c.brief.0 }}
|
||||
end note
|
||||
|
||||
{% endif %}
|
||||
{% if existsIn(e, "comment") and existsIn(e.comment, "todo") %}
|
||||
{% set c=e.comment %}
|
||||
{% for t in c.todo %}
|
||||
note top of {{ e.alias }} #882222
|
||||
**TODO**
|
||||
{{ t }}
|
||||
end note
|
||||
|
||||
{% endfor %}
|
||||
|
||||
{% endif %}
|
||||
{# Render template paramete if any #}
|
||||
{% if existsIn(e, "comment") and existsIn(e.comment, "tparam") %}
|
||||
{% set c=e.comment %}
|
||||
|
||||
note top of {{ e.alias }} #AAAAFF
|
||||
**Template parameters**
|
||||
{% for tp in c.tparam %}
|
||||
//{{ tp.name }}// {{ trim(tp.description) }}
|
||||
{% endfor %}
|
||||
end note
|
||||
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
```
|
||||
|
||||
### Accessing comment content
|
||||
Text available in the code comment blocks can be accessed in the templates depending on the selected comment
|
||||
parser.
|
||||
|
||||
Currently there are 2 available comment parsers:
|
||||
* `plain` - default
|
||||
* `clang` - Clang's comment parser
|
||||
|
||||
They can be selected using `comment_parser` config option.
|
||||
|
||||
#### `plain` comment parser
|
||||
This parser provides only 2 options to the Jinja context:
|
||||
* `comment.raw` - raw comment text, including comment markers such as `///` or `/**`
|
||||
* `comment.formatted` - formatted entire comment
|
||||
|
||||
#### `clang` comment parser
|
||||
This parser uses Clang comment parsing API to extract commands from the command:
|
||||
* `comment.raw` - raw comment text, including comment markers such as `///` or `/**`
|
||||
* `comment.formatted` - formatted entire comment
|
||||
* `comment.<command>.<N>` - where command is the command used in the command e.g. `brief`, `todo`, etc.
|
||||
and `N` is the index of the command in the array (each comment can have multiple instances of the
|
||||
same command such as `\todo`)
|
||||
* `comment.text` - entire text of the comment that is not attached to any command
|
||||
* `comment.paragraph.<N>` - array of plain text paragraphs, for instance if you don't use `\brief`
|
||||
commands but often provide brief description as first sentence of the comment separated with a new line
|
||||
from the rest of the comment
|
||||
151
docs/package_diagrams.md
Normal file
151
docs/package_diagrams.md
Normal file
@@ -0,0 +1,151 @@
|
||||
# Generating package diagrams
|
||||
|
||||
Package diagrams are simple diagrams which can be useful to determine the high level structure of a C++ project,
|
||||
by rendering all projects namespaces as UML packages and their interdependencies.
|
||||
|
||||
The minimal config required to generate a package diagram is presented below:
|
||||
```yaml
|
||||
# Path to the directory where `compile_commands.json` can be found
|
||||
compilation_database_dir: _build
|
||||
# Output directory for the diagrams
|
||||
output_directory: puml
|
||||
# Diagrams definitions
|
||||
diagrams:
|
||||
# Diagram name
|
||||
my_class_diagram:
|
||||
# Type of diagram (has to be `package`)
|
||||
type: package
|
||||
# Include only translation units matching the following patterns
|
||||
glob:
|
||||
- src/*.cc
|
||||
# Include only classes and functions from files in `src` directory
|
||||
include:
|
||||
namespaces:
|
||||
- ns1::ns2
|
||||
```
|
||||
|
||||
For instance the following C++ code:
|
||||
```
|
||||
namespace A::AA {
|
||||
namespace A1 {
|
||||
struct CA {
|
||||
};
|
||||
}
|
||||
namespace A2 {
|
||||
struct CB {
|
||||
};
|
||||
}
|
||||
namespace A3 {
|
||||
struct CC {
|
||||
};
|
||||
}
|
||||
namespace A4 {
|
||||
struct CD {
|
||||
};
|
||||
}
|
||||
namespace A5 {
|
||||
struct CE {
|
||||
};
|
||||
}
|
||||
namespace A6 {
|
||||
struct CF {
|
||||
};
|
||||
}
|
||||
namespace A7 {
|
||||
struct CG {
|
||||
};
|
||||
}
|
||||
namespace A8 {
|
||||
struct CH {
|
||||
};
|
||||
}
|
||||
namespace A9 {
|
||||
struct CI {
|
||||
};
|
||||
}
|
||||
namespace A10 {
|
||||
struct CJ {
|
||||
};
|
||||
}
|
||||
namespace A11 {
|
||||
struct CK {
|
||||
};
|
||||
}
|
||||
namespace A12 {
|
||||
struct CL {
|
||||
};
|
||||
}
|
||||
namespace A13 {
|
||||
struct CM {
|
||||
};
|
||||
}
|
||||
namespace A14 {
|
||||
struct CN {
|
||||
};
|
||||
}
|
||||
namespace A15 {
|
||||
struct CO {
|
||||
};
|
||||
}
|
||||
namespace A16 {
|
||||
struct CP {
|
||||
};
|
||||
}
|
||||
namespace A17 {
|
||||
struct CR {
|
||||
};
|
||||
}
|
||||
}
|
||||
namespace B::BB::BBB {
|
||||
class CBA : public A::AA::A6::CF {
|
||||
public:
|
||||
A::AA::A1::CA *ca_;
|
||||
A::AA::A2::CB cb_;
|
||||
std::shared_ptr<A::AA::A3::CC> cc_;
|
||||
std::map<std::string, std::unique_ptr<A::AA::A4::CD>> *cd_;
|
||||
std::array<A::AA::A15::CO, 5> co_;
|
||||
static A::AA::A16::CP *cp_;
|
||||
|
||||
CBA() = default;
|
||||
|
||||
CBA(A::AA::A14::CN *cn) { }
|
||||
|
||||
friend A::AA::A17::CR;
|
||||
|
||||
template <typename... Item> CBA(std::tuple<Item...> &items) { }
|
||||
|
||||
void ce(const std::vector<A::AA::A5::CE> /*ce_*/) { }
|
||||
|
||||
std::shared_ptr<A::AA::A7::CG> cg() { return {}; }
|
||||
|
||||
template <typename T>
|
||||
void ch(std::map<T, std::shared_ptr<A::AA::A8::CH>> &ch_)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::map<T, std::shared_ptr<A::AA::A9::CI>> ci(T * /*t*/)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
void cj(std::unique_ptr<A::AA::A10::CJ> /*cj_*/) { }
|
||||
|
||||
std::unique_ptr<A::AA::A11::CK> ck() { return {}; }
|
||||
|
||||
template <typename T>
|
||||
void cl(std::map<T, std::shared_ptr<A::AA::A12::CL>> & /*ch_*/)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T> std::map<T, std::shared_ptr<A::AA::A13::CM>> cm()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
generates the following diagram:
|
||||
|
||||

|
||||
56
docs/quick_start.md
Normal file
56
docs/quick_start.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# Quick start
|
||||
|
||||
To add an initial class diagram to your project, follow these steps:
|
||||
|
||||
1. Enter your projects top level directory and run:
|
||||
```bash
|
||||
$ clang-uml --init
|
||||
```
|
||||
2. Edit the generated `.clang-uml` file and set the following:
|
||||
```yaml
|
||||
# Path to `compile_commands.json` directory
|
||||
compilation_database_dir: .
|
||||
# Path to diagram output directory
|
||||
output_directory: puml
|
||||
diagrams:
|
||||
# This is the name of the diagram
|
||||
some_class_diagram:
|
||||
type: class
|
||||
# Parse only translation units in `src` subdirectory
|
||||
glob:
|
||||
- src/*.cc
|
||||
# Render all names relative to `myproject` namespace
|
||||
using_namespace:
|
||||
- myproject
|
||||
include:
|
||||
# Include only elements in `myproject` namespace
|
||||
namespaces:
|
||||
- myproject
|
||||
exclude:
|
||||
# Exclude elements in `myproject::detail` namespace
|
||||
namespaces:
|
||||
- myproject::detail
|
||||
```
|
||||
3. Run `clang-uml` in the projects top directory:
|
||||
```bash
|
||||
$ clang-uml
|
||||
```
|
||||
4. Generate SVG images from the PlantUML diagrams:
|
||||
```bash
|
||||
$ plantuml -tsvg puml/*.puml
|
||||
```
|
||||
5. Add another diagram:
|
||||
```bash
|
||||
$ clang-uml --add-sequence-diagram another_diagram
|
||||
```
|
||||
6. Now list the diagrams defined in the config:
|
||||
```bash
|
||||
$ clang-uml -l
|
||||
The following diagrams are defined in the config file:
|
||||
- another_diagram [sequence]
|
||||
- some_class_diagram [class]
|
||||
```
|
||||
7. Generate only the new diagram:
|
||||
```bash
|
||||
clang-uml -n another_diagram
|
||||
```
|
||||
235
docs/sequence_diagrams.md
Normal file
235
docs/sequence_diagrams.md
Normal file
@@ -0,0 +1,235 @@
|
||||
# Generating sequence diagrams
|
||||
|
||||
The minimal config required to generate a sequence diagram is presented below:
|
||||
```yaml
|
||||
# Path to the directory where `compile_commands.json` can be found
|
||||
compilation_database_dir: _build
|
||||
# Output directory for the diagrams
|
||||
output_directory: puml
|
||||
# Diagrams definitions
|
||||
diagrams:
|
||||
# Diagram name
|
||||
my_class_diagram:
|
||||
# Type of diagram (has to be `sequence`)
|
||||
type: sequence
|
||||
# Include only translation units matching the following patterns
|
||||
glob:
|
||||
- src/*.cc
|
||||
# Include only classes and functions from files in `src` directory
|
||||
include:
|
||||
paths:
|
||||
- src
|
||||
# Exclude calls to/from `std` namespace
|
||||
exclude:
|
||||
namespaces:
|
||||
- std
|
||||
start_from:
|
||||
- function: "main(int,const char**)"
|
||||
```
|
||||
|
||||
## Sequence diagram overview
|
||||
|
||||
Consider the following diagram:
|
||||
|
||||

|
||||
|
||||
`clang-uml` generated sequence diagrams are not stricly 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
|
||||
UML `alt` or `loop` blocks but wrapped in `[`, `]` brackets
|
||||
* Lambda expressions are generated as standalone participants, whose name comprises of the parent context where they
|
||||
are defined and the exact source code location
|
||||
|
||||
## 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:
|
||||
- function: "main(int,char**)"
|
||||
```
|
||||
or
|
||||
```yaml
|
||||
start_from:
|
||||
- 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, which can be tricky. If not sure, the best way is to put anything in the `function`
|
||||
property value at first, run the `clang-uml` on the diagram with verbose set to `-vvv` and look in the logs
|
||||
for the relevant function signature. At the end of the diagram generation at this verbosity level, `clang-uml` will
|
||||
generate a textual representation of all discovered activities relevant for this diagram, for instance if you're looking
|
||||
_for exact signature of method `translation_unit_visitor::VisitCXXRecordDecl`, look for similar_
|
||||
output in the logs:
|
||||
|
||||
```bash
|
||||
[trace] [tid 3842954] [diagram.cc:194] Sequence id=1875210076312968845:
|
||||
[trace] [tid 3842954] [diagram.cc:198] Activity id=1875210076312968845, from=clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitCXXRecordDecl(clang::CXXRecordDecl *):
|
||||
[trace] [tid 3842954] [diagram.cc:208] Message from=clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitCXXRecordDecl(clang::CXXRecordDecl *), from_id=1875210076312968845, to=__UNRESOLVABLE_ID__, to_id=0, name=, type=if
|
||||
[trace] [tid 3842954] [diagram.cc:217] Message from=clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitCXXRecordDecl(clang::CXXRecordDecl *), from_id=1875210076312968845, to=clanguml::sequence_diagram::visitor::translation_unit_visitor::should_include(const clang::TagDecl *), to_id=664596622746486441, name=should_include, type=call
|
||||
```
|
||||
|
||||
Then you just need to copy and paste the signature exactly and rerun `clang-uml`.
|
||||
|
||||
## 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
|
||||
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:
|
||||
|
||||

|
||||
|
||||
## 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 be generated at the point where lambda is passed as parameter
|
||||
* If the lambda is passed as template parameter in instantiation it will not be generated at the moment at all
|
||||
|
||||
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 follwing code:
|
||||
```cpp
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
namespace clanguml {
|
||||
namespace t20012 {
|
||||
struct A {
|
||||
void a() { aa(); }
|
||||
|
||||
void aa() { aaa(); }
|
||||
|
||||
void aaa() { }
|
||||
};
|
||||
|
||||
struct B {
|
||||
void b() { bb(); }
|
||||
|
||||
void bb() { bbb(); }
|
||||
|
||||
void bbb() { }
|
||||
|
||||
void eb() { }
|
||||
};
|
||||
|
||||
struct C {
|
||||
void c() { cc(); }
|
||||
|
||||
void cc() { ccc(); }
|
||||
|
||||
void ccc() { }
|
||||
};
|
||||
|
||||
struct D {
|
||||
int add5(int arg) const { return arg + 5; }
|
||||
};
|
||||
|
||||
class E {
|
||||
std::optional<std::shared_ptr<B>> maybe_b;
|
||||
std::shared_ptr<A> a;
|
||||
|
||||
public:
|
||||
template <typename F> void setup(F &&f) { f(maybe_b); }
|
||||
};
|
||||
|
||||
template <typename F> struct R {
|
||||
R(F &&f)
|
||||
: f_{std::move(f)}
|
||||
{
|
||||
}
|
||||
|
||||
void r() { f_(); }
|
||||
|
||||
F f_;
|
||||
};
|
||||
|
||||
void tmain()
|
||||
{
|
||||
A a;
|
||||
B b;
|
||||
C c;
|
||||
|
||||
// The activity shouldn't be marked at the lambda definition, but
|
||||
// wherever it is actually called...
|
||||
auto alambda = [&a, &b]() {
|
||||
a.a();
|
||||
b.b();
|
||||
};
|
||||
|
||||
// ...like here
|
||||
alambda();
|
||||
|
||||
// There should be no call to B in the sequence diagram as the blambda
|
||||
// is never called
|
||||
[[maybe_unused]] auto blambda = [&b]() { b.b(); };
|
||||
|
||||
// Nested lambdas should also work
|
||||
auto clambda = [alambda, &c]() {
|
||||
c.c();
|
||||
alambda();
|
||||
};
|
||||
clambda();
|
||||
|
||||
R r{[&c]() { c.c(); }};
|
||||
|
||||
r.r();
|
||||
|
||||
D d;
|
||||
|
||||
std::vector<int> ints{0, 1, 2, 3, 4};
|
||||
std::transform(ints.begin(), ints.end(), ints.begin(),
|
||||
[&d](auto i) { return d.add5(i); });
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
generates 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:
|
||||
|
||||
```yaml
|
||||
compilation_database_dir: ..
|
||||
output_directory: puml
|
||||
diagrams:
|
||||
t20029_sequence:
|
||||
type: sequence
|
||||
glob:
|
||||
- ../../tests/t20029/t20029.cc
|
||||
include:
|
||||
namespaces:
|
||||
- clanguml::t20029
|
||||
exclude:
|
||||
access:
|
||||
- private
|
||||
using_namespace:
|
||||
- clanguml::t20029
|
||||
start_from:
|
||||
- function: clanguml::t20029::tmain()
|
||||
participants_order:
|
||||
- clanguml::t20029::tmain()
|
||||
- clanguml::t20029::Encoder<clanguml::t20029::Retrier<clanguml::t20029::ConnectionPool>>
|
||||
- clanguml::t20029::Retrier<clanguml::t20029::ConnectionPool>
|
||||
- clanguml::t20029::ConnectionPool
|
||||
- clanguml::t20029::encode_b64(std::string &&)
|
||||
```
|
||||
|
||||
56
docs/troubleshooting.md
Normal file
56
docs/troubleshooting.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# Troubleshooting
|
||||
|
||||
## General issues
|
||||
### Diagram generated with PlantUML is cropped
|
||||
When generating diagrams with PlantUML without specifying an output file format, the default is PNG.
|
||||
Unfortunately PlantUML will not check if the diagram will fit in the default PNG size, and often the diagram
|
||||
will be be incomplete in the picture. A better option is to specify SVG as output format and then convert
|
||||
to PNG, e.g.:
|
||||
```bash
|
||||
$ plantuml -tsvg mydiagram.puml
|
||||
$ convert +antialias mydiagram.svg mydiagram.png
|
||||
```
|
||||
|
||||
## Class diagrams
|
||||
### "fatal error: 'stddef.h' file not found"
|
||||
This error means that Clang cannot find some standard headers in the include paths
|
||||
specified in the `compile_commands.json`. This typically happens on macos and sometimes on Linux, when
|
||||
the code was compiled with different Clang version than `clang-uml` itself.
|
||||
|
||||
One solution to this issue is to add the following line to your `CMakeLists.txt` file:
|
||||
|
||||
```cmake
|
||||
set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES})
|
||||
```
|
||||
|
||||
Another option is to make sure that the Clang is installed on the system (even if not used for building your
|
||||
project), e.g.:
|
||||
```bash
|
||||
apt install clang
|
||||
```
|
||||
|
||||
## Sequence diagrams
|
||||
### Generated diagram is empty
|
||||
In order to generate sequence diagram the `start_from` configuration option must have a valid starting point
|
||||
for the diagram (e.g. `function`), which must match exactly the function signature in the `clang-uml` model.
|
||||
Look for error in the console output such as:
|
||||
```bash
|
||||
Failed to find participant mynamespace::foo(int) for start_from condition
|
||||
```
|
||||
which means that either you have a typo in the function signature in the configuration file, or that the function
|
||||
was not defined in the translation units you specified in the `glob` patterns for this diagram. Run again the
|
||||
`clang-uml` tool with `-vvv` option and look in the console output for any mentions of the function from
|
||||
which the diagram should start and copy the exact signature into the configuration file.
|
||||
|
||||
### Generated diagram contains several empty control blocks or calls which should not be there
|
||||
Currently the filtering of call expressions and purging empty control blocks (e.g. loops or conditional statements),
|
||||
within which no interesting calls were included in the diagram is not perfect. In case the regular `namespaces` filter
|
||||
is not enough, it is useful to add also a `paths` filter, which will only include participants and call expressions
|
||||
from files in a subdirectory of your project, e.g.:
|
||||
```yaml
|
||||
include:
|
||||
namespaces:
|
||||
- myproject
|
||||
paths:
|
||||
- src
|
||||
```
|
||||
Reference in New Issue
Block a user