Merge pull request #163 from bkryza/add-doxygen-config

Add doxygen config
This commit is contained in:
Bartek Kryza
2023-06-25 18:45:24 +02:00
committed by GitHub
271 changed files with 16928 additions and 915 deletions

View File

@@ -1,32 +1,79 @@
compilation_database_dir: debug
output_directory: docs/diagrams
comment_parser: clang
generate_links:
link: https://github.com/bkryza/clang-uml/blob/{{ git.commit }}/{{ element.source.path }}#L{{ element.source.line }}
link: "{% if existsIn(element, \"doxygen_link\") %}{{ element.doxygen_link }}{% endif %}"
tooltip: "{% if existsIn(element, \"comment\") and existsIn(element.comment, \"brief\") %}{{ abbrv(trim(replace(element.comment.brief.0, \"\\n+\", \" \")), 256) }}{% else %}{{ element.name }}{% endif %}"
diagrams:
main_package:
include!: uml/main_package_diagram.yml
# Class diagrams
architecture_visitors_class:
include!: uml/class/architecture_visitors_class.yml
config_class:
include!: uml/config_class_diagram.yml
include!: uml/class/config_class.yml
config_context_class:
include!: uml/class/config_context_class.yml
compilation_database_context_class:
include!: uml/class/compilation_database_context_class.yml
inheritable_diagram_options_context_class:
include!: uml/class/inheritable_diagram_options_context_class.yml
diagram_config_hierarchy_class:
include!: uml/class/diagram_config_hierarchy_class.yml
diagram_hierarchy_class:
include!: uml/class/diagram_hierarchy_class.yml
decorated_element_hierarchy_class:
include!: uml/class/decorated_element_hierarchy_class.yml
stylable_element_hierarchy_class:
include!: uml/class/stylable_element_hierarchy_class.yml
source_location_hierarchy_class:
include!: uml/class/source_location_hierarchy_class.yml
filter_visitor_hierarchy_class:
include!: uml/class/filter_visitor_hierarchy_class.yml
diagram_filter_context_class:
include!: uml/class/diagram_filter_context_class.yml
nested_trait_hierarchy_class:
include!: uml/class/nested_trait_hierarchy_class.yml
package_hierarchy_class:
include!: uml/class/package_hierarchy_class.yml
source_file_hierarchy_class:
include!: uml/class/source_file_hierarchy_class.yml
template_trait_hierarchy_class:
include!: uml/class/template_trait_hierarchy_class.yml
comment_visitor_hierarchy_class:
include!: uml/class/comment_visitor_hierarchy_class.yml
decorators_class:
include!: uml/decorators_class_diagram.yml
include!: uml/class/decorators_class.yml
relationship_context_class:
include!: uml/class/relationship_context_class.yml
common_model_class:
include!: uml/common_model_class_diagram.yml
include!: uml/class/common_model_class.yml
class_model_class:
include!: uml/class_model_class_diagram.yml
include!: uml/class/class_model_class.yml
diagram_element_hierarchy_class:
include!: uml/diagram_element_hierarchy_diagram.yml
include!: uml/class/diagram_element_hierarchy_class.yml
sequence_model_class:
include!: uml/sequence_model_class_diagram.yml
main_sequence:
include!: uml/main_sequence_diagram.yml
sequence_diagram_visitor_sequence:
include!: uml/sequence_diagram_visitor_sequence_diagram.yml
class_diagram_generator_sequence:
include!: uml/class_diagram_generator_sequence_diagram.yml
template_builder_sequence:
include!: uml/template_builder_sequence_diagram.yml
include!: uml/class/sequence_model_class.yml
package_model_class:
include!: uml/package_model_class_diagram.yml
include!: uml/class/package_model_class.yml
# Sequence diagrams
main_sequence:
include!: uml/sequence/main_sequence.yml
load_config_sequence:
include!: uml/sequence/load_config_sequence.yml
cli_handle_options_sequence:
include!: uml/sequence/cli_handle_options_sequence.yml
diagram_generate_generic_sequence:
include!: uml/sequence/diagram_generate_generic_sequence.yml
sequence_diagram_visitor_sequence:
include!: uml/sequence/sequence_diagram_visitor_sequence.yml
class_diagram_generator_sequence:
include!: uml/sequence/class_diagram_generator_sequence.yml
template_builder_sequence:
include!: uml/sequence/template_builder_sequence.yml
# Package diagrams
main_package:
include!: uml/package/main_package.yml
architecture_package:
include!: uml/package/architecture_package.yml
# Include diagrams
include_graph:
include!: uml/include_diagram.yml
include!: uml/include/include.yml

5
.gitignore vendored
View File

@@ -22,6 +22,11 @@ bin/
/debug_tidy
/.cache
docs/diagrams
docs/doxygen/html
docs/doxygen/xml
docs/doxygen/latex
docs/contributing.md
docs/changelog.md
coverage*.info

View File

@@ -1,8 +1,10 @@
# Contributing to `clang-uml`
# Contributing to clang-uml
Thanks for taking interest in `clang-uml`!
> Please, make sure you're ok with [Code of conduct](./CODE_OF_CONDUCT.md) and [LICENSE](./LICENSE.md)
> Please, make sure you're ok with
> [Code of conduct](./CODE_OF_CONDUCT.md)
> and [LICENSE](./LICENSE.md)
## If you found a bug
@@ -18,12 +20,12 @@ Thanks for taking interest in `clang-uml`!
the C++ code which triggers the issue, and in `tests/t00050/test_case.h` write the test checks.
The test case must be also added manually to `tests/test_cases.cc`:
```cpp
...
// ...
#include "t00047/test_case.h"
#include "t00048/test_case.h"
#include "t00049/test_case.h"
#include "t00050/test_case.h"
...
#include "t00050/test_case.h" // <<<
// ...
```
Finally, create an issue with a link to your branch with the new test case.
@@ -82,8 +84,8 @@ Thanks for taking interest in `clang-uml`!
the feature to ensure we're on the same page as to its purpose and possible implementation
* Next, implement the feature, please try to adapt to the overall code style:
* 80-character line width
* snakes over camels
* use `make format` before submitting PR to ensure consistent formatting
* snakes not camels
* use `make format` before submitting PR to ensure consistent formatting (requires Docker)
* use `make tidy` to check if your code doesn't introduce any `clang-tidy` warnings
* Add test case (or multiple test cases), which cover the new feature
* Finally, create a pull request!

2676
Doxyfile Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -138,6 +138,15 @@ iwyu_fixes: debug
docs:
make -C docs toc
.PHONY: doxygen
doxygen: docs
cp CONTRIBUTING.md docs/contributing.md
cp CHANGELOG.md docs/changelog.md
cp docs/diagrams/*.svg docs/doxygen/html/
mkdir -p docs/doxygen/html/test_cases
cp docs/test_cases/*.svg docs/doxygen/html/test_cases/
../doxygen/_build/bin/doxygen
.PHONY: fedora/%
fedora/%:
mkdir -p packaging/_BUILD/fedora/$*

View File

@@ -6,6 +6,7 @@
[![Coverage](https://codecov.io/gh/bkryza/clang-uml/branch/master/graph/badge.svg)](https://codecov.io/gh/bkryza/clang-uml)
[![Version](https://img.shields.io/badge/version-0.3.7-blue)](https://github.com/bkryza/clang-uml/releases)
[![Version](https://img.shields.io/badge/LLVM-12,13,14,15,16-orange)](https://github.com/bkryza/clang-uml/releases)
[![Doxygen](https://img.shields.io/badge/Docs-Doxygen-gainsboro)](https://clang-uml.github.io)
`clang-uml` is an automatic C++ to UML class, sequence, package and include diagram generator, driven by
YAML configuration files. The main idea behind the
@@ -16,7 +17,7 @@ The diagrams can be generated in [PlantUML](https://plantuml.com) and JSON forma
`clang-uml` currently supports C++ up to version 17 with partial support for C++ 20.
Full documentation can be found [here](./docs/README.md).
Full documentation can be found at [clang-uml.github.io](https://clang-uml.github.io).
To see what `clang-uml` can do, checkout the diagrams generated for unit
test cases [here](./docs/test_cases.md) or examples in
@@ -55,7 +56,7 @@ Main features supported so far include:
* **Include graph diagram generation**
* Show include graph for selected files - [_example_](docs/test_cases/t40001.md)
More comprehensive documentation can be found [here](./docs/README.md).
More comprehensive documentation can be at [clang-uml.github.io](https://clang-uml.github.io).
## Installation
@@ -441,6 +442,8 @@ This project relies on the following great tools:
* [backward-cpp](https://github.com/bombela/backward-cpp) - stack trace pretty printer for C++
* [yaml-cpp](https://github.com/jbeder/yaml-cpp) - YAML parser library for C++
* [spdlog](https://github.com/gabime/spdlog) - Fast C++ logging library
* [Doxygen](https://www.doxygen.nl/) - C++ documentation generator
* [Doxygen Awesome](https://jothepro.github.io/doxygen-awesome-css) - Doxygen CSS style
## Contributing

View File

@@ -19,6 +19,7 @@ UPDATE_TOC := markdown-toc --bullets "*" -i
.PHONY: toc
toc:
$(UPDATE_TOC) architecture.md
$(UPDATE_TOC) class_diagrams.md
$(UPDATE_TOC) comment_decorators.md
$(UPDATE_TOC) common_options.md

View File

@@ -1,8 +1,28 @@
@mainpage clang-uml
# Documentation
`clang-uml` is an automatic C++ to UML class, sequence, package and include diagram generator, driven by
YAML configuration files. The main idea behind the
project is to easily maintain up-to-date diagrams within a code-base or document
legacy code. The configuration file or files for `clang-uml` define the
types and contents of each generated diagram.
The diagrams can be generated in [PlantUML](https://plantuml.com) and JSON formats.
Example sequence diagram generated using `clang-uml` from [this code](https://github.com/bkryza/clang-uml/blob/master/tests/t20029/t20029.cc):
![Sample sequence diagram](test_cases/t20029_sequence.svg)
`clang-uml` currently supports C++ up to version 17 with partial support for C++ 20.
To see what `clang-uml` can do, checkout the diagrams generated for unit
test cases [here](./test_cases.md) or examples in
[clang-uml-examples](https://github.com/bkryza/clang-uml-examples) repository.
These pages provide both user and developer documentation.
* [Quick start](./quick_start.md)
* [Installation](./installation.md)
* Generating diagrams
* **Generating diagrams**
* [Common options](./common_options.md)
* [Generator types](./generator_types.md)
* [Class diagrams](./class_diagrams.md)
@@ -18,3 +38,8 @@
* [Doxygen integration](./doxygen_integration.md)
* [Test cases documentation](./test_cases.md)
* [Troubleshooting](./troubleshooting.md)
* [Changelog](./changelog.md)
* [License](./license.md)
* **Development**
* [Architecture](./architecture.md)
* [Contributing](./contributing.md)

202
docs/architecture.md Normal file
View File

@@ -0,0 +1,202 @@
# Architecture
<!-- toc -->
* [Overview](#overview)
* [Configuration model](#configuration-model)
* [Diagram model](#diagram-model)
* [Common model](#common-model)
* [Diagram filters](#diagram-filters)
* [Translation unit visitors](#translation-unit-visitors)
* [Diagram generators](#diagram-generators)
* [Command line handler](#command-line-handler)
* [Tests](#tests)
* [Unit tests](#unit-tests)
* [Test cases](#test-cases)
* [Real code tests](#real-code-tests)
<!-- tocstop -->
This section presents general architecture and components of `clang-uml`.
> All diagrams below are generated by `clang-uml` and updated automatically.
## Overview
`clang-uml` is written in C++17 and
uses [Clang LibTooling API](https://releases.llvm.org/16.0.0/tools/clang/docs/LibTooling.html)
to traverse
the AST (Abstract Syntax Tree) of the source code and extract any information
relevant for a specified diagram.
The code is divided into several packages (namespaces), the main of them are:
- [`clanguml::config`](./namespaceclanguml_1_1config.html) - configuration
handling
- [`clanguml::common`](./namespaceclanguml_1_1common.html) - common interfaces
- [`clanguml::class_diagram`](./namespaceclanguml_1_1class__diagram.html) -
specializations for class diagrams
- [`clanguml::sequence_diagram`](./namespaceclanguml_1_1sequence__diagram.html) -
specializations for sequence diagrams
- [`clanguml::include_diagram`](./namespaceclanguml_1_1include__diagram.html) -
specializations for include diagrams
- [`clanguml::package_diagram`](./namespaceclanguml_1_1package__diagram.html) -
specializations for package diagrams
![clang-uml packages](./architecture_package.svg)
## Configuration model
The configuration model consists of classes representing the configuration
specified in the YAML configuration files.
Depending on the option, it can either:
- be specified only at the top level of the configuration file
- only in the specific diagram configuration
- either of the above
The first group of options are stored in
the [`config::config`](structclanguml_1_1config_1_1config.html) class.
The second group is stored in a specific diagram config subclass, e.g.
[`config::sequence_diagram`](structclanguml_1_1config_1_1sequence__diagram.html)
The options in the last group are modeled in the
[`config::inheritable_diagram_options`](./structclanguml_1_1config_1_1inheritable__diagram__options.html).
![configuration model](./config_class.svg)
The YAML configuration file is parsed
using [yaml-cpp](https://github.com/jbeder/yaml-cpp) library:
![configuration load sequence](./load_config_sequence.svg)
For each possible option type, there must an implementation of a
YAML decoder - e.g.
[`YAML::convert<filter>`](./structYAML_1_1convert_3_01filter_01_4.html)
(for converting YAML nodes to configuration model classes)
and a YAML emitter - e.g.
[`operator<<`](./group__yaml__emitters.html#ga4c8bc075684b08daa379aef609bb6297)
(for generating YAML from configuration model classes).
## Diagram model
The diagram model namespace is divided into the [`common`](#common-model) model
namespace and 1 namespace for each supported diagram type.
![clang-uml packages](./architecture_model.svg)
### Common model
The [common diagram model namespace](./namespaceclanguml_1_1common_1_1model.html),
provides a set of classes representing typical UML and C++ concepts such as
diagram elements, packages, templates, and others which are shared by more than
1 diagram type.
![clang-uml packages](./common_model_class.svg)
The diagram elements are composed into a hierarchy spanning all major
namespaces,
depending on whether the element is specific for a single diagram type (
e.g. [`participant`](./structclanguml_1_1sequence__diagram_1_1model_1_1participant.html)),
or whether it's common for several diagram types (
e.g. [`package`](./classclanguml_1_1common_1_1model_1_1package.html)).
### Diagram filters
In order to ease the generation of diagrams, `clang-uml` has a (very) simple
intermediate UML model, which covers only the features necessary for
generation of the supported diagram types. The model can be extended if
necessary to add new features.
![diagram filter context](./diagram_filter_context_class.svg)
## Translation unit visitors
The first stage in the diagram generation involves traversing the AST of
each translation unit from the `compile_commands.json` compilation database,
which matched at least one pattern specified in the `glob` pattern of the
configuration file.
Each visitor is implemented in a subclass of
[`translation_unit_visitor`](./classclanguml_1_1common_1_1visitor_1_1translation__unit__visitor.html),
and must also implement relevant methods from Clang's
[RecursiveASTVisitor](https://clang.llvm.org/doxygen/classclang_1_1RecursiveASTVisitor.html).
![AST visitors](./architecture_visitors_class.svg)
The output of the `translation_unit_visitor` for each diagram type is an
intermediate diagram model, which is then passed to the relevant diagram
generator.
## Diagram generators
Diagram generators convert the `clang-uml`'s internal UML model into actual
diagram in one of the supported formats:
- PlantUML
- JSON
Each diagram generator extends a common interface appropriate for the
selected output format, i.e.:
- [PlantUML](classclanguml_1_1common_1_1generators_1_1plantuml_1_1generator.html)
- [JSON](classclanguml_1_1common_1_1generators_1_1json_1_1generator.html)
and renders the output to a file. For each diagram type there is a separate
generator for each supported output format.
## Command line handler
The [cli_handler](classclanguml_1_1cli_1_1cli__handler.html) is a command line
handler class is a wrapper around [CLI11](https://github.com/CLIUtils/CLI11),
and implements handlers for various actions, validates command line parameters
and reports errors.
## Tests
### Unit tests
Basic set of units tests are stored in
[tests/test_*.cc](https://github.com/bkryza/clang-uml/tree/master/tests)
test files. The unit tests do not aim to cover the entire codebase, only
specific algorithms or methods, which should behave as expected and if their
errors can be difficult to diagnose when running the test cases on C++ code.
### Test cases
These tests are the main tests of `clang-uml`. Each test case tests one or
more feature of a specific diagram type. Each of them has a separated directory
in the `tests` directory and its own `.clang-uml` with diagram configuration
as well as a `test_case.h` file which contains the tests assertions.
Any other sources in that directory are compiled and then used to generate the
diagrams, whose contents should be then verified within `test_case.h`
for correctness. All the sources should be wrapped within a namespace:
`clanguml::`
These test directories are numbered in consecutive numbers using the following
convention:
- Start with a letter `t`
- The first digit of the number is the diagram type:
- `0` - class diagram
- `2` - sequence diagram
- `3` - package diagram
- `4` - include diagram
- `9` - other test cases
- The rest of the name is the consecutive number of the test case
Each test case is also referenced in
[test_cases.yaml](https://github.com/bkryza/clang-uml/blob/master/tests/test_cases.yaml)
where it has assigned a title. That file is used to generate the [test cases
documentation page](./md_docs_2test__cases.html).
### Real code tests
Each release is tested on a set of open-source C++ projects, to be sure that
at least the new version does not crash or introduce some obvious regressions.
The tests are stored in a separate
repository: [clang-uml-examples](https://github.com/bkryza/clang-uml-examples).

View File

@@ -2,10 +2,10 @@
<!-- toc -->
* [`note`](#note)
* [`skip` and `skiprelationship`](#skip-and-skiprelationship)
* [`composition`, `association` and `aggregation`](#composition-association-and-aggregation)
* [`style`](#style)
* ['note'](#note)
* ['skip' and 'skiprelationship'](#skip-and-skiprelationship)
* ['composition', 'association' and 'aggregation'](#composition-association-and-aggregation)
* ['style'](#style)
<!-- tocstop -->
@@ -27,7 +27,7 @@ The optional `:<diagram_name>` suffix will apply this decorator only to a specif
Currently, the following decorators are supported.
## `note`
## 'note'
This decorator allows to specify directly in the code comments that should be included in the generated diagrams.
@@ -91,7 +91,7 @@ generates the following class diagram:
![note](./test_cases/t00028_class.svg)
## `skip` and `skiprelationship`
## 'skip' and 'skiprelationship'
This decorator allows to skip the specific classes or methods from the diagrams, for instance the following code:
```cpp
@@ -145,7 +145,7 @@ generates the following diagram:
![skip](./test_cases/t00029_class.svg)
## `composition`, `association` and `aggregation`
## '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:
@@ -190,7 +190,7 @@ generates the following diagram:
![skip](./test_cases/t00030_class.svg)
## `style`
## 'style'
This decorator allows to specify in the code specific styles for diagram elements, for instance:
```cpp

View File

@@ -7,9 +7,9 @@
* [PlantUML custom directives](#plantuml-custom-directives)
* [Adding debug information in the generated diagrams](#adding-debug-information-in-the-generated-diagrams)
* [Resolving include path and compiler flags issues](#resolving-include-path-and-compiler-flags-issues)
* [Use `--query-driver` command line option](#use---query-driver-command-line-option)
* [Use '--query-driver' command line option](#use---query-driver-command-line-option)
* [Manually add and remove compile flags from the compilation database](#manually-add-and-remove-compile-flags-from-the-compilation-database)
* [Using `CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES`](#using-cmake_cxx_implicit_include_directories)
* [Using 'CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES'](#using-cmake_cxx_implicit_include_directories)
<!-- tocstop -->
@@ -18,14 +18,17 @@ By default, `clang-uml` will look for file `.clang-uml` in the projects director
from it. The file must be specified in YAML and it's overall structure is as follows:
```yaml
<common options for all diagrams>
# 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>
first_diagram_name:
type: class|sequence|package|include
# diagram specific options
...
second_diagram_name:
type: class|sequence|package|include
# diagram specific options
...
...
```
@@ -116,7 +119,7 @@ These errors can be overcome, by ensuring that the Clang parser has the correct
include paths to analyse your code base on the given platform. `clang-uml`
provides several mechanisms to resolve this issue:
### Use `--query-driver` command line option
### Use '--query-driver' command line option
> This option is not available on Windows.
@@ -133,7 +136,7 @@ system, when generating diagrams for an embedded project and providing
`arm-none-eabi-gcc` as driver:
```bash
$ clang-uml --query-driver arm-none-eabi-gcc
clang-uml --query-driver arm-none-eabi-gcc
```
the following options are appended to each command line after `argv[0]` of the
@@ -148,7 +151,7 @@ already as `argv[0]` in your `compile_commands.json`, you can simply invoke
`clang-uml` as:
```bash
$ clang-uml --query-driver .
clang-uml --query-driver .
```
however please make sure that the `compile_commands.json` contain a command,
@@ -173,11 +176,11 @@ remove_compile_flags:
These options can be also passed on the command line, for instance:
```bash
$ clang-uml --add-compile-flag -I/opt/my_toolchain/include \
--remove-compile-flag -I/usr/include ...
clang-uml --add-compile-flag -I/opt/my_toolchain/include \
--remove-compile-flag -I/usr/include ...
```
### Using `CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES`
### Using 'CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES'
Yet another option, for CMake based projects, is to use the following CMake option:
```cmake

View File

@@ -2,18 +2,18 @@
<!-- toc -->
* [`namespaces` _[string or regex]_](#namespaces-_string-or-regex_)
* [`elements` _[string or regex]_](#elements-_string-or-regex_)
* [`element_types`](#element_types)
* [`paths` _[string or glob]_](#paths-_string-or-glob_)
* [`context` _[string or regex]_](#context-_string-or-regex_)
* [`relationships`](#relationships)
* [`subclasses` _[string or regex]_](#subclasses-_string-or-regex_)
* [`parents` _[string or regex]_](#parents-_string-or-regex_)
* [`specializations` _[string or regex]_](#specializations-_string-or-regex_)
* [`access`](#access)
* [`method_types`](#method_types)
* [`dependants` and `dependencies` _[string or regex]_](#dependants-and-dependencies-_string-or-regex_)
* [namespaces](#namespaces)
* [elements](#elements)
* [element_types](#element_types)
* [paths](#paths)
* [context](#context)
* [relationships](#relationships)
* [subclasses](#subclasses)
* [parents](#parents)
* [specializations](#specializations)
* [access](#access)
* [method_types](#method_types)
* [dependants and dependencies](#dependants-and-dependencies)
<!-- tocstop -->
@@ -55,29 +55,29 @@ exclude:
The following table specifies the values allowed in each filter:
| Filter name | Possible values | Example values |
|-------------------|----------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------|
| `namespaces` | Qualified name or regex | - `ns1::ns2::ClassA` <br/>- `r: '.*detail.*'` |
| `elements` | Qualified name or regex | - `ns1::ns2::ClassA` <br/>- `r: '.*detail.*'` |
| `element_types` | Types of diagram elements | - `class`<br/>- `enum`<br/>- `concept` |
| `paths` | File or dir path or glob pattern | - `src/dir1`<br/>- `src/dir2/a.cpp`<br/>- `src/dir3/*.cpp` |
| `context` | Qualified name or regex | - `ns1::ns2::ClassA`<br/>- `r: 'ns1::ns2::ClassA.+'` |
| `relationships` | Type of relationship | - `inheritance`<br/>- `composition`<br/>- `aggregation`<br/>- `ownership`<br/>- `association`<br/>- `instantiation`<br/>- `friendship`<br/>- `dependency` |
| `subclasses` | Qualified name or regex | - `ns1::ns2::ClassA`<br/>- `r: 'ns1::ns2::ClassA.+'` |
| `parents` | Qualified name or regex | - `ns1::ns2::ClassA`<br/>- `r: 'ns1::ns2::ClassA.+'` |
| `specializations` | Qualified name or regex | - `ns1::ns2::ClassA`<br/>- `r: 'ns1::ns2::ClassA.+'` |
| `access` | Method or member access scope | - `public`<br/>- `protected`<br/>- `private` |
| `method_types` | Type of class method | - `constructor`<br/>- `destructor`<br/>- `assignment`<br/>- `operator`<br/>- `defaulted`<br/>- `deleted`<br/>- `static` |
| `dependants` | Qualified name or regex | - `ns1::ns2::ClassA`<br/>- `r: 'ns1::ns2::ClassA.+'` |
| `dependencies` | Qualified name or regex | - `ns1::ns2::ClassA`<br/>- `r: 'ns1::ns2::ClassA.+'` |
| Filter name | Possible values | Example values |
|-------------------|----------------------------------|------------------------------------------------------------------------------------------------------------------------|
| `namespaces` | Qualified name or regex | ```ns1::ns2::ClassA```, ```r: '.*detail.*'``` |
| `elements` | Qualified name or regex | ```ns1::ns2::ClassA```, ```r: '.*detail.*'``` |
| `element_types` | Types of diagram elements | ```class```, ```enum```, ```concept``` |
| `paths` | File or dir path or glob pattern | ```src/dir1```, ```src/dir2/a.cpp```, ```src/dir3/*.cpp``` |
| `context` | Qualified name or regex | ```ns1::ns2::ClassA```, ```r: 'ns1::ns2::ClassA.+'``` |
| `relationships` | Type of relationship | ```inheritance```, ```composition```, ```aggregation```, ```ownership```, ```association```, ```instantiation```, ```friendship```, ```dependency``` |
| `subclasses` | Qualified name or regex | ```ns1::ns2::ClassA```, ```r: 'ns1::ns2::ClassA.+'``` |
| `parents` | Qualified name or regex | ```ns1::ns2::ClassA```, ```r: 'ns1::ns2::ClassA.+'``` |
| `specializations` | Qualified name or regex | ```ns1::ns2::ClassA```, ```r: 'ns1::ns2::ClassA.+'``` |
| `access` | Method or member access scope | ```public```, ```protected```, ```private``` |
| `method_types` | Type of class method | ```constructor```, ```destructor```, ```assignment```, ```operator```, ```defaulted```, ```deleted```, ```static``` |
| `dependants` | Qualified name or regex | ```ns1::ns2::ClassA```, ```r: 'ns1::ns2::ClassA.+'``` |
| `dependencies` | Qualified name or regex | ```ns1::ns2::ClassA```, ```r: 'ns1::ns2::ClassA.+'``` |
The following filters are available.
## `namespaces` _[string or regex]_
## namespaces
Allows to include or exclude entities from specific namespaces.
## `elements` _[string or regex]_
## elements
Allows to directly include or exclude specific entities from the diagrams, for instance to exclude a specific class
from an included namespace:
@@ -91,7 +91,7 @@ from an included namespace:
- ns1::ns2::MyClass
```
## `element_types`
## element_types
Allows to include or exclude elements of specific type from the diagram, for instance
to remove all enums from a diagram add the following:
@@ -102,7 +102,7 @@ to remove all enums from a diagram add the following:
- enum
```
## `paths` _[string or glob]_
## paths
This filter allows to include or exclude from the diagram elements declared
in specific files.
@@ -122,7 +122,7 @@ diagrams:
Currently, this filter does not allow any globbing or wildcards, however
paths to directories can be specified.
## `context` _[string or regex]_
## context
This filter allows to limit the diagram elements only to classes which are in direct relationship (of any kind) with
the specified class:
@@ -134,7 +134,7 @@ the specified class:
```
## `relationships`
## 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:
@@ -156,19 +156,19 @@ The following relationships can be used in this filter:
* friendship
* dependency
## `subclasses` _[string or regex]_
## subclasses
This filter allows to include or exclude all subclasses of a given class in the diagram.
## `parents` _[string or regex]_
## parents
This filter allows to include or exclude all parents (base classes) of a given class in the diagram.
## `specializations` _[string or regex]_
## specializations
This filter allows to include or exclude specializations and instantiations of a specific template from the diagram.
## `access`
## access
This filter allows to include or exclude class methods and members based on their access scope, allowed values ar:
@@ -176,7 +176,7 @@ This filter allows to include or exclude class methods and members based on thei
* `protected`
* `private`
## `method_types`
## method_types
This filter allows to include or exclude various method types from the class diagram, allowed values ar:
* constructor
@@ -190,7 +190,7 @@ This filter allows to include or exclude various method types from the class dia
This filter is independent of the `access` filter, which controls which methods
are included based on access scope (e.g. `public`).
## `dependants` and `dependencies` _[string or regex]_
## 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

View File

@@ -88,7 +88,7 @@ clang-uml --show-template parents_hierarchy_tmpl
users configuration file defines another template with a name which already
exists as built-in template it will override the predefined templates.
Currently the following templates are built-in:
Currently, the following templates are built-in:
* `parents_hierarchy_tmpl` - generate inheritance hierarchy diagram including
parents of a specified class
* `subclass_hierarchy_tmpl` - generate inheritance hierarchy diagram including

28
docs/doxygen/footer.html Normal file
View File

@@ -0,0 +1,28 @@
<!-- HTML footer for doxygen 1.9.1-->
<!-- start footer part -->
<!--BEGIN GENERATE_TREEVIEW-->
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
<ul>
$navpath
<li class="footer">
$generatedby
<a href="https://www.doxygen.org/index.html">
<img class="footer" src="$relpath^doxygen.svg" width="104" height="31" alt="doxygen"/>
</a> $doxygenversion
</li>
</ul>
</div>
<!--END GENERATE_TREEVIEW-->
<!--BEGIN !GENERATE_TREEVIEW-->
<hr class="footer"/><address class="footer">
<small>
<span class="copyright">&#160;&#160;Copyright &copy; 2022-present <a href="https://github.com/bkryza">Bartek Kryza</a>
</span>
$generatedby&#160;
<a href="https://www.doxygen.org/index.html">
<img class="footer" src="$relpath^doxygen.svg" width="104" height="31" alt="doxygen"/>
</a> $doxygenversion
</small></address>
<!--END !GENERATE_TREEVIEW-->
</body>
</html>

7
docs/doxygen/github.min.css vendored Normal file
View File

@@ -0,0 +1,7 @@
/*!
Theme: Github
Author: Defman21
License: ~ MIT (or more permissive) [via base16-schemes-source]
Maintainer: @highlightjs/core-team
Version: 2021.09.0
*/pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#333;background:#fff}.hljs ::selection,.hljs::selection{background-color:#c8c8fa;color:#333}.hljs-comment{color:#969896}.hljs-tag{color:#e8e8e8}.hljs-operator,.hljs-punctuation,.hljs-subst{color:#333}.hljs-operator{opacity:.7}.hljs-bullet,.hljs-deletion,.hljs-name,.hljs-selector-tag,.hljs-template-variable,.hljs-variable{color:#ed6a43}.hljs-attr,.hljs-link,.hljs-literal,.hljs-number,.hljs-symbol,.hljs-variable.constant_{color:#0086b3}.hljs-class .hljs-title,.hljs-title,.hljs-title.class_{color:#795da3}.hljs-strong{font-weight:700;color:#795da3}.hljs-addition,.hljs-built_in,.hljs-code,.hljs-doctag,.hljs-keyword.hljs-atrule,.hljs-quote,.hljs-regexp,.hljs-string,.hljs-title.class_.inherited__{color:#183691}.hljs-attribute,.hljs-function .hljs-title,.hljs-section,.hljs-title.function_,.ruby .hljs-property{color:#795da3}.diff .hljs-meta,.hljs-keyword,.hljs-template-tag,.hljs-type{color:#a71d5d}.hljs-emphasis{color:#a71d5d;font-style:italic}.hljs-meta,.hljs-meta .hljs-keyword,.hljs-meta .hljs-string{color:#333}.hljs-meta .hljs-keyword,.hljs-meta-keyword{font-weight:700}

111
docs/doxygen/header.html Normal file
View File

@@ -0,0 +1,111 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen $doxygenversion"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<!-- BEGIN opengraph metadata -->
<meta property="og:title" content="clang-uml" />
<meta property="og:image" content="$relpath^clang-uml-logo.svg" />
<meta property="og:description" content="C++ to UML diagram generator based on Clang." />
<meta property="og:url" content="https://clang-uml.github.io/" />
<!-- END opengraph metadata -->
<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
<link rel="icon" type="image/svg+xml" href="logo.drawio.svg"/>
<script type="text/javascript" src="$relpath^jquery.js"></script>
<script type="text/javascript" src="$relpath^dynsections.js"></script>
<!--<script type="text/javascript" src="$relpath^doxygen-awesome-darkmode-toggle.js"></script>-->
<script type="text/javascript" src="$relpath^doxygen-awesome-fragment-copy-button.js"></script>
<script type="text/javascript" src="$relpath^doxygen-awesome-paragraph-link.js"></script>
<!--<script type="text/javascript" src="$relpath^doxygen-awesome-interactive-toc.js"></script>-->
<!--<script type="text/javascript" src="$relpath^doxygen-awesome-tabs.js"></script>-->
<!--<script type="text/javascript" src="$relpath^toggle-alternative-theme.js"></script>-->
<script type="text/javascript">
DoxygenAwesomeFragmentCopyButton.init()
// DoxygenAwesomeDarkModeToggle.init()
DoxygenAwesomeParagraphLink.init()
// DoxygenAwesomeInteractiveToc.init()
// DoxygenAwesomeTabs.init()
</script>
$treeview
$search
$mathjax
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
<link rel="stylesheet" href="$relpath^github.min.css">
<script src="$relpath^highlight.min.js"></script>
<script>
$(function() {
hljs.configure({useBR: false});
$(".fragment").each(function(i,node) {
var $node = $(node);
// Only apply highlight.js to non-cpp code blocks
if (!$node.hasClass("language-cpp")) {
$node.html("<pre><code class='" +
$node.attr("class") + "'>" +
$node.text() + "</code></pre>");
hljs.highlightElement(node);
}
});
});
</script>
$extrastylesheet
</head>
<body>
<!-- https://tholman.com/github-corners/ -->
<!--<a href="https://github.com/bkryza/clang-uml" class="github-corner" title="View source on GitHub" target="_blank">-->
<!-- <svg viewBox="0 0 250 250" width="70" height="70" style="position: absolute; top: 0; border: 0; right: 0; z-index: 99;" aria-hidden="true">-->
<!-- <path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style>-->
<div id="top" style="background-color: gainsboro"><!-- do not remove this div, it is closed by doxygen! -->
<!--BEGIN TITLEAREA-->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<!--BEGIN PROJECT_LOGO-->
<td id="projectlogo">
<a href="$relpath^index.html">
<img alt="Main page" src="$relpath^$projectlogo"/>
</a>
</td>
<!--END PROJECT_LOGO-->
<!--BEGIN PROJECT_NAME-->
<td id="projectalign" style="padding-left: 0.5em;">
<div id="projectname">
<span id="projectnumber">$projectnumber</span>
</div>
<div id="projectbrief">$projectbrief</div><!--END PROJECT_BRIEF-->
</td>
<!--END PROJECT_NAME-->
<!--BEGIN !PROJECT_NAME-->
<!--BEGIN PROJECT_BRIEF-->
<!-- <td style="padding-left: 0.5em;">-->
<!-- <div id="projectbrief">$projectbrief</div>-->
<!-- </td>-->
<td>
<div>
<a href="https://github.com/bkryza/clang-uml">
<img alt="GitHub" src="$relpath^github-mark.svg"/>
</a>
</div>
</td>
<!--END PROJECT_BRIEF-->
<!--END !PROJECT_NAME-->
<!--BEGIN DISABLE_INDEX-->
<!--BEGIN SEARCHENGINE-->
<td>$searchbox</td>
<!--END SEARCHENGINE-->
<!--END DISABLE_INDEX-->
</tr>
</tbody>
</table>
</div>
<!--END TITLEAREA-->
<!-- end header part -->

2575
docs/doxygen/highlight.js Normal file

File diff suppressed because it is too large Load Diff

611
docs/doxygen/highlight.min.js vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,234 @@
<doxygenlayout version="1.0">
<!-- Generated by doxygen 1.9.7 -->
<!-- Navigation index tabs for HTML output -->
<navindex>
<!-- <tab type="mainpage" visible="yes" title=""/>-->
<!-- <tab type="pages" visible="yes" title="" intro=""/>-->
<!-- <tab type="modules" visible="yes" title="" intro=""/>-->
<tab type="user" url="./md_docs_2installation.html" title="Installation"/>
<tab type="user" url="./md_docs_2test__cases.html" title="Test cases"/>
<tab type="user" visible="yes" url="./index.html" title="Doxygen">
<tab type="namespaces" visible="yes" title="">
<tab type="namespacelist" visible="yes" title="" intro=""/>
<tab type="namespacemembers" visible="yes" title="" intro=""/>
</tab>
<tab type="classes" visible="yes" title="">
<tab type="classlist" visible="yes" title="" intro=""/>
<tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/>
<tab type="hierarchy" visible="yes" title="" intro=""/>
<tab type="classmembers" visible="yes" title="" intro=""/>
</tab>
<tab type="structs" visible="yes" title="">
<tab type="structlist" visible="yes" title="" intro=""/>
<tab type="structindex" visible="$ALPHABETICAL_INDEX" title=""/>
</tab>
<tab type="files" visible="yes" title="">
<tab type="filelist" visible="yes" title="" intro=""/>
<tab type="globals" visible="yes" title="" intro=""/>
</tab>
</tab>
<tab type="user" url="https://github.com/bkryza/clang-uml-examples" title="Examples"/>
<tab type="user" url="https://github.com/bkryza/clang-uml" title="GitHub"/>
</navindex>
<!-- Layout definition for a class page -->
<class>
<briefdescription visible="yes"/>
<detaileddescription title=""/>
<includes visible="$SHOW_HEADERFILE"/>
<inheritancegraph visible="$CLASS_GRAPH"/>
<collaborationgraph visible="$COLLABORATION_GRAPH"/>
<memberdecl>
<nestedclasses visible="yes" title=""/>
<publictypes title=""/>
<services title=""/>
<interfaces title=""/>
<publicslots title=""/>
<signals title=""/>
<publicmethods title=""/>
<publicstaticmethods title=""/>
<publicattributes title=""/>
<publicstaticattributes title=""/>
<protectedtypes title=""/>
<protectedslots title=""/>
<protectedmethods title=""/>
<protectedstaticmethods title=""/>
<protectedattributes title=""/>
<protectedstaticattributes title=""/>
<packagetypes title=""/>
<packagemethods title=""/>
<packagestaticmethods title=""/>
<packageattributes title=""/>
<packagestaticattributes title=""/>
<properties title=""/>
<events title=""/>
<privatetypes title=""/>
<privateslots title=""/>
<privatemethods title=""/>
<privatestaticmethods title=""/>
<privateattributes title=""/>
<privatestaticattributes title=""/>
<friends title=""/>
<related title="" subtitle=""/>
<membergroups visible="yes"/>
</memberdecl>
<memberdef>
<inlineclasses title=""/>
<typedefs title=""/>
<enums title=""/>
<services title=""/>
<interfaces title=""/>
<constructors title=""/>
<functions title=""/>
<related title=""/>
<variables title=""/>
<properties title=""/>
<events title=""/>
</memberdef>
<allmemberslink visible="yes"/>
<usedfiles visible="$SHOW_USED_FILES"/>
<authorsection visible="yes"/>
</class>
<!-- Layout definition for a namespace page -->
<namespace>
<briefdescription visible="yes"/>
<detaileddescription title=""/>
<memberdecl>
<nestednamespaces visible="yes" title=""/>
<constantgroups visible="yes" title=""/>
<interfaces visible="yes" title=""/>
<classes visible="yes" title=""/>
<concepts visible="yes" title=""/>
<structs visible="yes" title=""/>
<exceptions visible="yes" title=""/>
<typedefs title=""/>
<sequences title=""/>
<dictionaries title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
<membergroups visible="yes"/>
</memberdecl>
<memberdef>
<inlineclasses title=""/>
<typedefs title=""/>
<sequences title=""/>
<dictionaries title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
</memberdef>
<authorsection visible="yes"/>
</namespace>
<!-- Layout definition for a concept page -->
<concept>
<briefdescription visible="yes"/>
<detaileddescription title=""/>
<includes visible="$SHOW_HEADERFILE"/>
<definition visible="yes" title=""/>
<detaileddescription title=""/>
<authorsection visible="yes"/>
</concept>
<!-- Layout definition for a file page -->
<file>
<briefdescription visible="yes"/>
<!-- <detaileddescription title=""/>-->
<includes visible="$SHOW_INCLUDE_FILES"/>
<includegraph visible="$INCLUDE_GRAPH"/>
<includedbygraph visible="$INCLUDED_BY_GRAPH"/>
<sourcelink visible="yes"/>
<memberdecl>
<interfaces visible="yes" title=""/>
<classes visible="yes" title=""/>
<structs visible="yes" title=""/>
<exceptions visible="yes" title=""/>
<namespaces visible="yes" title=""/>
<concepts visible="yes" title=""/>
<constantgroups visible="yes" title=""/>
<defines title=""/>
<typedefs title=""/>
<sequences title=""/>
<dictionaries title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
<membergroups visible="yes"/>
</memberdecl>
<memberdef>
<inlineclasses title=""/>
<defines title=""/>
<typedefs title=""/>
<sequences title=""/>
<dictionaries title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
</memberdef>
<authorsection/>
</file>
<!-- Layout definition for a group page -->
<group>
<briefdescription visible="yes"/>
<detaileddescription title=""/>
<groupgraph visible="$GROUP_GRAPHS"/>
<memberdecl>
<nestedgroups visible="yes" title=""/>
<dirs visible="yes" title=""/>
<files visible="yes" title=""/>
<namespaces visible="yes" title=""/>
<concepts visible="yes" title=""/>
<classes visible="yes" title=""/>
<defines title=""/>
<typedefs title=""/>
<sequences title=""/>
<dictionaries title=""/>
<enums title=""/>
<enumvalues title=""/>
<functions title=""/>
<variables title=""/>
<signals title=""/>
<publicslots title=""/>
<protectedslots title=""/>
<privateslots title=""/>
<events title=""/>
<properties title=""/>
<friends title=""/>
<membergroups visible="yes"/>
</memberdecl>
<memberdef>
<pagedocs/>
<inlineclasses title=""/>
<defines title=""/>
<typedefs title=""/>
<sequences title=""/>
<dictionaries title=""/>
<enums title=""/>
<enumvalues title=""/>
<functions title=""/>
<variables title=""/>
<signals title=""/>
<publicslots title=""/>
<protectedslots title=""/>
<privateslots title=""/>
<events title=""/>
<properties title=""/>
<friends title=""/>
</memberdef>
<authorsection visible="yes"/>
</group>
<!-- Layout definition for a directory page -->
<directory>
<briefdescription visible="yes"/>
<directorygraph visible="yes"/>
<memberdecl>
<dirs visible="yes"/>
<files visible="yes"/>
</memberdecl>
<!-- <detaileddescription title=""/>-->
</directory>
</doxygenlayout>

7
docs/doxygen/solarized-light.min.css vendored Normal file
View File

@@ -0,0 +1,7 @@
/*!
Theme: Solarized Light
Author: Ethan Schoonover (modified by aramisgithub)
License: ~ MIT (or more permissive) [via base16-schemes-source]
Maintainer: @highlightjs/core-team
Version: 2021.09.0
*/pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#586e75;background:#fdf6e3}.hljs ::selection,.hljs::selection{background-color:#93a1a1;color:#586e75}.hljs-comment{color:#839496}.hljs-tag{color:#657b83}.hljs-operator,.hljs-punctuation,.hljs-subst{color:#586e75}.hljs-operator{opacity:.7}.hljs-bullet,.hljs-deletion,.hljs-name,.hljs-selector-tag,.hljs-template-variable,.hljs-variable{color:#dc322f}.hljs-attr,.hljs-link,.hljs-literal,.hljs-number,.hljs-symbol,.hljs-variable.constant_{color:#cb4b16}.hljs-class .hljs-title,.hljs-title,.hljs-title.class_{color:#b58900}.hljs-strong{font-weight:700;color:#b58900}.hljs-addition,.hljs-code,.hljs-string,.hljs-title.class_.inherited__{color:#859900}.hljs-built_in,.hljs-doctag,.hljs-keyword.hljs-atrule,.hljs-quote,.hljs-regexp{color:#2aa198}.hljs-attribute,.hljs-function .hljs-title,.hljs-section,.hljs-title.function_,.ruby .hljs-property{color:#268bd2}.diff .hljs-meta,.hljs-keyword,.hljs-template-tag,.hljs-type{color:#6c71c4}.hljs-emphasis{color:#6c71c4;font-style:italic}.hljs-meta,.hljs-meta .hljs-keyword,.hljs-meta .hljs-string{color:#d33682}.hljs-meta .hljs-keyword,.hljs-meta-keyword{font-weight:700}

View File

@@ -6,10 +6,12 @@
<!-- tocstop -->
`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` 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](./comment_decorators.md), which
will appear in the documentation unprocessed.
`clang-uml` decorators can be omitted completely in Doxygen, by adding the
The best solution to this is to tell Doxygen to ignore them, by adding the
following lines to the Doxygen config file:
```
@@ -17,4 +19,44 @@ ALIASES += uml=""
ALIASES += uml{1}=""
ALIASES += uml{2}=""
ALIASES += uml{3}=""
```
```
Furthermore, Doxygen adds images to HTML documentation as `<img src=""/>`,
which disables interactive links in SVG diagrams. One way to go around it
is to use a special command for these images, for instance:
```
ALIASES += embed{1}="\htmlonly <embed src=\"\1\"/> \endhtmlonly"
```
and then use the following in the source code comments:
```cpp
/**
* @brief Base class for all diagram models
*
* @embed{diagram_hierarchy_class.svg}
*/
class diagram {
public:
// ...
```
This directive in the configuration file will add the SVG diagrams using
`<embed>` HTML tag, and enable the links in the diagram on most browsers.
Finally, to have `clang-uml` generate links from diagram elements such as classes
or packages to Doxygen pages, it is only necessary to add the following
configuration file option:
```yaml
generate_links:
link: "{% if existsIn(element, \"doxygen_link\") %}{{ element.doxygen_link }}{% endif %}"
tooltip: "{% if existsIn(element, \"comment\") and existsIn(element.comment, \"brief\") %}{{ abbrv(trim(replace(element.comment.brief.0, \"\\n+\", \" \")), 256) }}{% else %}{{ element.name }}{% endif %}"
```
This option will tell `clang-uml` to generate a link to a local Doxygen
documentation page, provided that it is possible to generate it. Currently,
this only works for diagram elements, it will not work for instance
for individual methods.

File diff suppressed because it is too large Load Diff

1
docs/img/github-mark.svg Normal file
View File

@@ -0,0 +1 @@
<svg width="98" height="96" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z" fill="#24292f"/></svg>

After

Width:  |  Height:  |  Size: 963 B

View File

@@ -2,7 +2,7 @@
<!-- toc -->
* [Tracking system headers directly included by projects files](#tracking-system-headers-directly-included-by-projects-files)
* [Tracking system headers directly included by project sources](#tracking-system-headers-directly-included-by-project-sources)
<!-- tocstop -->
@@ -46,7 +46,7 @@ The following table presents the PlantUML arrows representing relationships in t
| Include (local) | ![association](img/puml_association.png) |
| Include (system) | ![dependency](img/puml_dependency.png) |
## Tracking system headers directly included by projects files
## Tracking system headers directly included by project sources
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:

View File

@@ -30,12 +30,16 @@ sudo apt install clang-uml
```bash
# Fedora 36
wget https://github.com/bkryza/clang-uml/releases/download/0.3.1/clang-uml-0.3.1-1.fc36.x86_64.rpm
sudo dnf install ./clang-uml-0.3.1-1.fc36.x86_64.rpm
wget https://github.com/bkryza/clang-uml/releases/download/0.3.7/clang-uml-0.3.7-1.fc36.x86_64.rpm
sudo dnf install ./clang-uml-0.3.7-1.fc36.x86_64.rpm
# Fedora 37
wget https://github.com/bkryza/clang-uml/releases/download/0.3.1/clang-uml-0.3.1-1.fc37.x86_64.rpm
sudo dnf install ./clang-uml-0.3.1-1.fc37.x86_64.rpm
wget https://github.com/bkryza/clang-uml/releases/download/0.3.7/clang-uml-0.3.7-1.fc37.x86_64.rpm
sudo dnf install ./clang-uml-0.3.7-1.fc37.x86_64.rpm
# Fedora 38
wget https://github.com/bkryza/clang-uml/releases/download/0.3.7/clang-uml-0.3.7-1.fc38.x86_64.rpm
sudo dnf install ./clang-uml-0.3.7-1.fc38.x86_64.rpm
```
#### Conda

View File

@@ -3,8 +3,8 @@
<!-- toc -->
* [Accessing comment content](#accessing-comment-content)
* [`plain` comment parser](#plain-comment-parser)
* [`clang` comment parser](#clang-comment-parser)
* ['plain' comment parser](#plain-comment-parser)
* ['clang' comment parser](#clang-comment-parser)
<!-- tocstop -->
@@ -102,12 +102,12 @@ Currently there are 2 available comment parsers:
They can be selected using `comment_parser` config option.
#### `plain` comment parser
#### '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
#### '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

15
docs/license.md Normal file
View File

@@ -0,0 +1,15 @@
## LICENSE
Copyright 2021-present Bartek Kryza <bkryza@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -31,7 +31,7 @@ diagrams:
```
For instance the following C++ code:
```
```cpp
namespace A::AA {
namespace A1 {
struct CA {
@@ -152,7 +152,7 @@ template <typename T> std::map<T, std::shared_ptr<A::AA::A13::CM>> cm()
}
```
generates the following diagram:
results the following diagram:
![package_deps](./test_cases/t30002_package.svg)

View File

@@ -10,7 +10,7 @@ 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
clang-uml --init
```
2. Edit the generated `.clang-uml` file and set the following:
```yaml
@@ -39,21 +39,21 @@ To add an initial class diagram to your project, follow these steps:
```
3. Run `clang-uml` in the projects top directory:
```bash
$ clang-uml
clang-uml
# or to see generation progress for each diagram run
$ clang-uml --progress
clang-uml --progress
```
4. Generate SVG images from the PlantUML diagrams:
```bash
$ plantuml -tsvg puml/*.puml
plantuml -tsvg puml/*.puml
```
5. Add another diagram:
```bash
$ clang-uml --add-sequence-diagram another_diagram
clang-uml --add-sequence-diagram another_diagram
```
6. Now list the diagrams defined in the config:
```bash
$ clang-uml -l
clang-uml -l
The following diagrams are defined in the config file:
- another_diagram [sequence]
- some_class_diagram [class]

View File

@@ -89,9 +89,11 @@ Then you just need to copy and paste the signature exactly and rerun `clang-uml`
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:
@@ -109,6 +111,7 @@ following rules:
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
#include <algorithm>
#include <functional>

View File

@@ -1,4 +1,15 @@
# Test cases index
<!-- toc -->
* [Class diagrams](#class-diagrams)
* [Sequence diagrams](#sequence-diagrams)
* [Package diagrams](#package-diagrams)
* [Include diagrams](#include-diagrams)
* [Other diagrams](#other-diagrams)
<!-- tocstop -->
## Class diagrams
* [t00002](./test_cases/t00002.md) - Basic class inheritance
* [t00003](./test_cases/t00003.md) - Class fields and methods
@@ -112,5 +123,5 @@
* [t40001](./test_cases/t40001.md) - Basic include graph diagram test case
* [t40002](./test_cases/t40002.md) - Cyclic include graph diagram test case
* [t40003](./test_cases/t40003.md) - Dependants and dependencies include diagram filter test
## Configuration diagrams
## Other diagrams
* [t90000](./test_cases/t90000.md) - Basic config test

View File

@@ -3,15 +3,16 @@
<!-- toc -->
* [General issues](#general-issues)
* [`clang-uml` crashed when generating diagram](#clang-uml-crashed-when-generating-diagram)
* [clang-uml crashes when generating diagram](#clang-uml-crashes-when-generating-diagram)
* [Diagram generation is very slow](#diagram-generation-is-very-slow)
* [Diagram generated with PlantUML is cropped](#diagram-generated-with-plantuml-is-cropped)
* [`clang` produces several warnings during diagram generation](#clang-produces-several-warnings-during-diagram-generation)
* [Clang produces several warnings during diagram generation](#clang-produces-several-warnings-during-diagram-generation)
* [Cannot generate diagrams from header-only projects](#cannot-generate-diagrams-from-header-only-projects)
* [YAML anchors and aliases are not fully supported](#yaml-anchors-and-aliases-are-not-fully-supported)
* [Class diagrams](#class-diagrams)
* ["fatal error: 'stddef.h' file not found"](#fatal-error-stddefh-file-not-found)
* [Cannot generate classes for `std` namespace](#cannot-generate-classes-for-std-namespace)
* [How can I generate class diagram of my entire project](#how-can-i-generate-class-diagram-of-my-entire-project)
* [Cannot generate classes for 'std' namespace](#cannot-generate-classes-for-std-namespace)
* [Sequence diagrams](#sequence-diagrams)
* [Generated diagram is empty](#generated-diagram-is-empty)
* [Generated diagram contains several empty control blocks or calls which should not be there](#generated-diagram-contains-several-empty-control-blocks-or-calls-which-should-not-be-there)
@@ -20,14 +21,15 @@
## General issues
### `clang-uml` crashed when generating diagram
### clang-uml crashes when generating diagram
If `clang-uml` crashes with a segmentation fault, it is possible to trace the
exact stack trace of the fault using the following steps:
First, build `clang-uml` from source in debug mode, e.g.:
```bash
$ make debug
make debug
```
Then run `clang-uml`, preferably with `-vvv` for verbose log output. If your
@@ -35,7 +37,7 @@ Then run `clang-uml`, preferably with `-vvv` for verbose log output. If your
a single diagram to make it easier to trace the root cause of the crash, e.g.:
```bash
$ debug/src/clang-uml -vvv -n my_diagram
debug/src/clang-uml -vvv -n my_diagram
```
After `clang-uml` crashes again, detailed backtrace (generated using
@@ -47,11 +49,13 @@ paste the stack trace and few last logs from the console.
### Diagram generation is very slow
`clang-uml` uses Clang's [RecursiveASTVisitor](https://clang.llvm.org/doxygen/classclang_1_1RecursiveASTVisitor.html), to
`clang-uml` uses
Clang's [RecursiveASTVisitor](https://clang.llvm.org/doxygen/classclang_1_1RecursiveASTVisitor.html),
to
traverse the source code. By default, this visitor is invoked on every
translation unit (i.e. each entry in your `compile_commands.json`), including
all of their header dependencies recursively. This means, that for large code
bases with hundreds or thousands of translation units, traversing all of them
bases with hundreds or thousands of translation units, traversing all of them
will be slow (think `clang-tidy` slow...).
Fortunately, in most practical cases it is not necessary to traverse the entire
@@ -60,7 +64,8 @@ a single diagram usually can be found in just a few translation units, or even
a single one.
This is where the `glob` configuration parameter comes in. It can be used to
limit the number of translation units to visit for a given diagram, for instance:
limit the number of translation units to visit for a given diagram, for
instance:
```yaml
diagrams:
@@ -95,11 +100,11 @@ format and then convert
to PNG, e.g.:
```bash
$ plantuml -tsvg mydiagram.puml
$ convert +antialias mydiagram.svg mydiagram.png
plantuml -tsvg mydiagram.puml
convert +antialias mydiagram.svg mydiagram.png
```
### `clang` produces several warnings during diagram generation
### Clang produces several warnings during diagram generation
During the generation of the diagram `clang` may report a lot of warnings, which
do not occur during the compilation with other compiler (e.g. GCC). This can be
@@ -122,8 +127,8 @@ add_compile_flags:
Alternatively, the same can be passed through the `clang-uml` command line, e.g.
```bash
$ clang-uml --add-compile-flag -Wno-implicit-const-int-float-conversion \
--add-compile-flag -Wno-shadow ...
clang-uml --add-compile-flag -Wno-implicit-const-int-float-conversion \
--add-compile-flag -Wno-shadow ...
```
Please note that if your `compile_commands.json` already contains - for instance
@@ -174,7 +179,7 @@ output_directory: output
.sequence_diagram_anchor: &sequence_diagram_anchor
type: sequence
glob: []
glob: [ ]
start_from:
- function: 'main(int,const char**)'
@@ -182,7 +187,7 @@ diagrams:
main_sequence_diagram: *sequence_diagram_anchor # This will work
foo_sequence_diagram:
<<: *sequence_diagram_anchor # This will not work
glob: [src/foo.cc]
glob: [ src/foo.cc ]
start_from:
- function: 'foo(int,float)'
```
@@ -196,10 +201,11 @@ yq 'explode(.)' .clang-uml | clang-uml --config -
```
## Class diagrams
### "fatal error: 'stddef.h' file not found"
This error means that Clang cannot find some standard headers in include
paths specified in the `compile_commands.json`. This typically happens on macOS
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.
@@ -212,13 +218,13 @@ set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTOR
Another option is to provide an option (on command line or in configuration
file) called `query_driver` (inspired by the [clangd](https://clangd.llvm.org/)
language server - although much less flexible), which will invoke the
language server - although much less flexible), which will invoke the
provider compiler command and query it for its default system paths, which then
will be added to each compile command in the database. This is especially useful
on macOS as well as for embedded toolchains, example usage:
```bash
$ clang-uml --query-driver arm-none-eabi-g++
clang-uml --query-driver arm-none-eabi-g++
```
Another option is to make sure that the Clang is installed on the system (even
@@ -248,12 +254,42 @@ remove_compile_flags:
These options can be also passed on the command line, for instance:
```bash
$ clang-uml --add-compile-flag -I/opt/my_toolchain/include \
--remove-compile-flag -I/usr/include ...
clang-uml --add-compile-flag -I/opt/my_toolchain/include \
--remove-compile-flag -I/usr/include ...
```
### Cannot generate classes for `std` namespace
Currently, system headers are skipped automatically by `clang-uml`, due to
Also see
[here](./md_docs_2common__options.html#resolving-include-path-and-compiler-flags-issues).
### How can I generate class diagram of my entire project
I want to generate a diagram containing all classes and relationships in my
project - I don't care how big it is going to be.
Of course this is possible, the best way to do this is to specify
that `clang-uml`
should only include elements defined in files contained in project sources,
e.g.:
```yaml
diagrams:
all_classes:
type: class
include:
paths: [ include, src ]
```
As the diagram will be huge for even medium-sized projects, it will likely not
be readable. However, this option can be useful for cases when we want to get
a complete JSON model of the codebase using the JSON generator:
```bash
clang-uml -g json -n all_classes --progress
```
### Cannot generate classes for 'std' namespace
Currently, system headers are skipped automatically by `clang-uml`, due to
too many errors they produce when generating diagrams, especially when trying
to process `GCC`'s or `MSVC`'s system headers by `Clang` - not yet sure why
that is the case.
@@ -278,6 +314,7 @@ exclude:
Hopefully this will be eventually resolved.
## Sequence diagrams
### Generated diagram is empty
In order to generate sequence diagram the `start_from` configuration option must

View File

@@ -1,5 +1,5 @@
/**
* src/class_diagram/generators/json/class_diagram_generator.cc
* @file rc/class_diagram/generators/json/class_diagram_generator.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*

View File

@@ -1,5 +1,5 @@
/**
* src/class_diagram/generators/json/class_diagram_generator.h
* @file src/class_diagram/generators/json/class_diagram_generator.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -56,36 +56,110 @@ using clanguml::common::model::relationship_t;
using namespace clanguml::util;
/**
* @brief Class diagram JSON generator
*/
class generator : public common_generator<diagram_config, diagram_model> {
public:
generator(diagram_config &config, diagram_model &model);
/**
* @brief Main generator method.
*
* This method is called first and coordinates the entire diagram
* generation.
*
* @param ostr Output stream.
*/
void generate(std::ostream &ostr) const override;
/**
* Render class element into a JSON node.
*
* @param c class diagram element
* @param parent JSON node
*/
void generate(const class_ &c, nlohmann::json &parent) const;
/**
* Render enum element into a JSON node.
*
* @param c enum diagram element
* @param parent JSON node
*/
void generate(const enum_ &c, nlohmann::json &parent) const;
/**
* Render concept element into a JSON node.
*
* @param c concept diagram element
* @param parent JSON node
*/
void generate(const concept_ &c, nlohmann::json &parent) const;
/**
* Render package element into a JSON node.
*
* @param p package diagram element
* @param parent JSON node
*/
void generate(const package &p, nlohmann::json &parent) const;
/**
* @brief In a nested diagram, generate the top level elements.
*
* This method iterates over the top level elements. In case the diagram
* is nested (i.e. includes packages), for each package it recursively
* call generation of elements contained in each package.
*
* @param parent JSON node
*/
void generate_top_level_elements(nlohmann::json &parent) const;
/**
* @brief Generate all relationships in the diagram.
*
* @param parent JSON node
*/
void generate_relationships(nlohmann::json &parent) const;
/**
* @brief Generate all relationships originating at a class element.
*
* @param c Class diagram element
* @param parent JSON node
*/
void generate_relationships(const class_ &c, nlohmann::json &parent) const;
/**
* @brief Generate all relationships originating at an enum element.
*
* @param c Enum diagram element
* @param parent JSON node
*/
void generate_relationships(const enum_ &c, nlohmann::json &parent) const;
/**
* @brief Generate all relationships originating at a concept element.
*
* @param c Concept diagram element
* @param parent JSON node
*/
void generate_relationships(
const concept_ &c, nlohmann::json &parent) const;
/**
* @brief Generate all relationships in a package.
*
* If the diagram is nested, it recursively calls relationship generation
* for all subelements.
*
* @param p Package diagram element
* @param parent JSON node
*/
void generate_relationships(const package &p, nlohmann::json &parent) const;
private:
std::string render_name(std::string name) const;
mutable nlohmann::json json_;
};

View File

@@ -1,5 +1,5 @@
/**
* src/class_diagram/generators/plantuml/class_diagram_generator.cc
* @file src/class_diagram/generators/plantuml/class_diagram_generator.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -813,10 +813,9 @@ void generator::generate(const package &p, std::ostream &ostr) const
// using_namespace
if (!uns.starts_with({p.full_name(false)})) {
ostr << "}" << '\n';
generate_notes(ostr, p);
}
}
generate_notes(ostr, p);
}
void generator::generate_relationships(

View File

@@ -1,5 +1,5 @@
/**
* src/class_diagram/generators/plantuml/class_diagram_generator.h
* @file src/class_diagram/generators/plantuml/class_diagram_generator.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -59,60 +59,208 @@ using clanguml::common::model::relationship_t;
using namespace clanguml::util;
/**
* @brief Class diagram PlantUML generator
*/
class generator : public common_generator<diagram_config, diagram_model> {
using method_groups_t = std::map<std::string, std::vector<class_method>>;
public:
generator(diagram_config &config, diagram_model &model);
/**
* @brief Main generator method.
*
* This method is called first and coordinates the entire diagram
* generation.
*
* @param ostr Output stream.
*/
void generate(std::ostream &ostr) const override;
/**
* @brief In a nested diagram, generate the top level elements.
*
* This method iterates over the top level elements. In case the diagram
* is nested (i.e. includes packages), for each package it recursively
* call generation of elements contained in each package.
*
* @param parent JSON node
*/
void generate_top_level_elements(std::ostream &ostr) const;
/**
* @brief Generate a hyperlink for a class element.
*
* @param ostr Output stream
* @param e Class element (e.g. a method)
*/
void generate_link(std::ostream &ostr, const class_element &e) const;
/**
* @brief Generate PlantUML alias for a class element.
*
* @param c Class element
* @param ostr Output stream
*/
void generate_alias(const class_ &c, std::ostream &ostr) const;
/**
* @brief Generate PlantUML alias for a enum element.
*
* @param e Enum element
* @param ostr Output stream
*/
void generate_alias(const enum_ &e, std::ostream &ostr) const;
/**
* @brief Generate PlantUML alias for a concept element.
*
* @param c Concept element
* @param ostr Output stream
*/
void generate_alias(const concept_ &c, std::ostream &ostr) const;
/**
* @brief Render class element to PlantUML
*
* @param c Class element
* @param ostr Output stream
*/
void generate(const class_ &c, std::ostream &ostr) const;
/**
* @brief Render class methods to PlantUML
*
* @param methods List of class methods
* @param ostr Output stream
*/
void generate_methods(
const std::vector<class_method> &methods, std::ostream &ostr) const;
/**
* @brief Render class methods to PlantUML in groups
*
* @param methods Methods grouped by method type
* @param ostr Output stream
*/
void generate_methods(
const method_groups_t &methods, std::ostream &ostr) const;
/**
* @brief Render class method to PlantUML
*
* @param m Class method
* @param ostr Output stream
*/
void generate_method(const class_method &m, std::ostream &ostr) const;
/**
* @brief Render class member to PlantUML
*
* @param m Class member
* @param ostr Output stream
*/
void generate_member(const class_member &m, std::ostream &ostr) const;
void generate_top_level_elements(std::ostream &ostr) const;
/**
* @brief Render all relationships in the diagram to PlantUML
*
* @param ostr Output stream
*/
void generate_relationships(std::ostream &ostr) const;
/**
* @brief Render all relationships originating from class element.
*
* @param c Class element
* @param ostr Output stream
*/
void generate_relationships(const class_ &c, std::ostream &ostr) const;
/**
* @brief Render a specific relationship to PlantUML.
*
* @param r Relationship model
* @param rendered_relations Set of already rendered relationships, to
* ensure that there are no duplicate
* relationships
*/
void generate_relationship(
const relationship &r, std::set<std::string> &rendered_relations) const;
/**
* @brief Render enum element to PlantUML
*
* @param e Enum element
* @param ostr Output stream
*/
void generate(const enum_ &e, std::ostream &ostr) const;
/**
* @brief Render all relationships originating from enum element.
*
* @param c Enum element
* @param ostr Output stream
*/
void generate_relationships(const enum_ &c, std::ostream &ostr) const;
/**
* @brief Render concept element to PlantUML
*
* @param c Concept element
* @param ostr Output stream
*/
void generate(const concept_ &c, std::ostream &ostr) const;
/**
* @brief Render all relationships originating from concept element.
*
* @param c Concept element
* @param ostr Output stream
*/
void generate_relationships(const concept_ &c, std::ostream &ostr) const;
/**
* @brief Render package element to PlantUML
*
* @param p Package element
* @param ostr Output stream
*/
void generate(const package &p, std::ostream &ostr) const;
/**
* @brief Render all relationships originating from package element.
*
* @param p Package element
* @param ostr Output stream
*/
void generate_relationships(const package &p, std::ostream &ostr) const;
/**
* @brief Generate any notes attached specifically to some class element.
*
* @param ostream Output stream
* @param member Class element (member or method)
* @param alias PlantUML class alias
*/
void generate_member_notes(std::ostream &ostream,
const class_element &member, const std::string &basicString) const;
const class_element &member, const std::string &alias) const;
/**
* @brief Generate elements grouped together in `together` groups.
*
* @param ostr Output stream
*/
void generate_groups(std::ostream &ostr) const;
void generate(std::ostream &ostr) const override;
/**
* @brief Group class methods based on method type.
*
* @param methods List of class methods.
*
* @return Map of method groups.
*/
method_groups_t group_methods(
const std::vector<class_method> &methods) const;

View File

@@ -1,5 +1,5 @@
/**
* src/class_diagram/model/class.cc
* @file src/class_diagram/model/class.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -37,6 +37,10 @@ bool class_::is_template() const { return is_template_; }
void class_::is_template(bool is_template) { is_template_ = is_template; }
bool class_::is_union() const { return is_union_; }
void class_::is_union(bool is_union) { is_union_ = is_union; }
void class_::add_member(class_member &&member)
{
members_.emplace_back(std::move(member));
@@ -121,4 +125,25 @@ int class_::calculate_template_specialization_match(const class_ &other) const
return template_trait::calculate_template_specialization_match(other);
}
void class_::template_specialization_found(bool found)
{
template_specialization_found_ = found;
}
bool class_::template_specialization_found() const
{
return template_specialization_found_;
}
std::optional<std::string> class_::doxygen_link() const
{
const auto *type = is_struct() ? "struct" : "class";
auto name = name_and_ns();
util::replace_all(name, "_", "__");
util::replace_all(name, "::", "_1_1");
util::replace_all(name, "##", "_1_1"); // nested classes
return fmt::format("{}{}.html", type, name);
}
} // namespace clanguml::class_diagram::model

View File

@@ -1,5 +1,5 @@
/**
* src/class_diagram/model/class.h
* @file src/class_diagram/model/class.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -32,6 +32,9 @@
namespace clanguml::class_diagram::model {
/**
* @brief Diagram element representing a class or class template.
*/
class class_ : public common::model::element,
public common::model::stylable_element,
public template_trait {
@@ -43,44 +46,165 @@ public:
class_ &operator=(const class_ &) = delete;
class_ &operator=(class_ &&) = delete;
std::string type_name() const override { return "class"; }
bool is_struct() const;
void is_struct(bool is_struct);
bool is_template() const;
void is_template(bool is_template);
bool is_union() const { return is_union_; }
void is_union(bool u) { is_union_ = u; }
void add_member(class_member &&member);
void add_method(class_method &&method);
void add_parent(class_parent &&parent);
const std::vector<class_member> &members() const;
const std::vector<class_method> &methods() const;
const std::vector<class_parent> &parents() const;
friend bool operator==(const class_ &l, const class_ &r);
/**
* Get the type name of the diagram element.
*
* @return Type name of the diagram element.
*/
std::string type_name() const override { return "class"; }
/**
* Whether or not the class was declared in the code as 'struct'.
*
* @return True, if the class was declared as 'struct'
*/
bool is_struct() const;
/**
* Set, whether the class was declared as 'struct'.
*
* @param is_struct True, if the class was declared as 'struct'
*/
void is_struct(bool is_struct);
/**
* Whether or not the class is a template.
*
* @return True, if the class is a template.
*/
bool is_template() const;
/**
* Set, whether the class is a template.
*
* @param is_struct True, if the class is a template.
*/
void is_template(bool is_template);
/**
* Whether or not the class is a union.
*
* @return True, if the class is a union.
*/
bool is_union() const;
/**
* Set, whether the class is a union.
*
* @param u True, if the class is a union.
*/
void is_union(bool is_union);
/**
* Add a data member to the class.
*
* @param member Class data member.
*/
void add_member(class_member &&member);
/**
* Add a method to the class.
*
* @param method Class method.
*/
void add_method(class_method &&method);
/**
* Add class parent (inheritance relationship).
*
* @todo Maybe it would be good to refactor this into a regular
* relationship. We could drop the 'class_parent' class completely...
*
* @param parent Class parent.
*/
void add_parent(class_parent &&parent);
/**
* Get reference to class member list.
*
* @return Reference to class members.
*/
const std::vector<class_member> &members() const;
/**
* Get reference to class method list.
*
* @return Reference to class methods.
*/
const std::vector<class_method> &methods() const;
/**
* Get reference to class parent list.
*
* @return Reference to class parents.
*/
const std::vector<class_parent> &parents() const;
/**
* @brief Get class full name.
*
* This method renders the entire class name including all template
* parameters and/or arguments.
*
* @param relative Whether the class name should be relative to
* using_namespace
* @return Full class name.
*/
std::string full_name(bool relative = true) const override;
/**
* @brief Get unqualified class ful name.
*
* This method returns the class full name but without any namespace
* qualifier.
*
* @return Full class name without namespace.
*/
std::string full_name_no_ns() const override;
/**
* Whether the class is abstract.
*
* @return True, if at least one method is abstract (=0).
*/
bool is_abstract() const;
/**
* @brief Calculate template specialization match with other class.
*
* This method is a wrapper over
* @ref template_trait::calculate_template_specialization_match()
*
* @param other
* @return
*/
int calculate_template_specialization_match(const class_ &other) const;
void template_specialization_found(bool found)
{
template_specialization_found_ = found;
}
/**
* Whether, a template specialization has already been found for this class.
* @return True, if a template specialization has already been found.
*/
bool template_specialization_found() const;
bool template_specialization_found() const
{
return template_specialization_found_;
}
/**
* Set, whether a template specialization has already been found for this
* class.
*
* @param found True, if a template specialization has already been found.
*/
void template_specialization_found(bool found);
/**
* @brief Generate Doxygen style HTML link for the class.
*
* This method generates a link, which can be used in SVG diagrams to
* create links from classes to Doxygen documentation pages.
*
* @return Doxygen-style HTML link for the class.
*/
std::optional<std::string> doxygen_link() const override;
private:
bool is_struct_{false};
@@ -90,7 +214,6 @@ private:
std::vector<class_method> methods_;
std::vector<class_parent> bases_;
std::string base_template_full_name_;
std::string full_name_;
bool template_specialization_found_{false};

View File

@@ -1,5 +1,5 @@
/**
* src/class_diagram/model/class_element.cc
* @file src/class_diagram/model/class_element.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*

View File

@@ -1,5 +1,5 @@
/**
* src/class_diagram/model/class_element.h
* @file src/class_diagram/model/class_element.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -26,21 +26,57 @@
namespace clanguml::class_diagram::model {
/**
* @brief Base class for class elements (e.g. member or method).
*/
class class_element : public common::model::decorated_element,
public common::model::source_location {
public:
class_element(
common::model::access_t scope, std::string name, std::string type);
virtual ~class_element() = default;
~class_element() override = default;
/**
* @brief Get elements access scope.
*
* @return Elements access scope.
*/
common::model::access_t access() const;
/**
* @brief Get elements name.
*
* @return Elements name.
*/
std::string name() const;
/**
* @brief Set elements name.
*
* @param name Elements name.
*/
void set_name(const std::string &name);
/**
* @brief Get elements type as string.
*
* @return Elements type as string.
*/
std::string type() const;
/**
* @brief Set elements type as string.
*
* @param type Elements type as string.
*/
void set_type(const std::string &type);
/**
* @brief Get elements inja context in JSON.
*
* @return Context in JSON
*/
virtual inja::json context() const;
private:

View File

@@ -1,5 +1,5 @@
/**
* src/class_diagram/model/class_member.cc
* @file src/class_diagram/model/class_member.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*

View File

@@ -1,5 +1,5 @@
/**
* src/class_diagram/model/class_member.h
* @file src/class_diagram/model/class_member.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -23,18 +23,38 @@
namespace clanguml::class_diagram::model {
/**
* @brief Class member model.
*/
class class_member : public class_element {
public:
/**
* @brief Constructor.
*
* @param access Members access scope (e.g. public)
* @param name Members name.
* @param type Members type as string.
*/
class_member(common::model::access_t access, const std::string &name,
const std::string &type);
~class_member() override = default;
/**
* @brief Whether the member is static.
*
* @return True, if the member is static.
*/
bool is_static() const;
/**
* @brief Set members static status.
*
* @param is_static True, if the member is static.
*/
void is_static(bool is_static);
private:
bool is_relationship_{false};
bool is_static_{false};
};

View File

@@ -1,5 +1,5 @@
/**
* src/class_diagram/model/class_method.cc
* @file src/class_diagram/model/class_method.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*

View File

@@ -1,5 +1,5 @@
/**
* src/class_diagram/model/class_method.h
* @file src/class_diagram/model/class_method.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -29,56 +29,225 @@ namespace clanguml::class_diagram::model {
using clanguml::common::model::template_trait;
/**
* @brief Class method model.
*/
class class_method : public class_element, public template_trait {
public:
/**
* @brief Constructor.
*
* @param access Methods access scope (e.g. public)
* @param name Methods name.
* @param type Methods return type as string.
*/
class_method(common::model::access_t access, const std::string &name,
const std::string &type);
~class_method() override = default;
/**
* @brief Whether the method is pure virtual.
*
* @return True, if the method is pure virtual
*/
bool is_pure_virtual() const;
void is_pure_virtual(bool is_pure_virtual);
/**
* @brief Whether the method is virtual.
*
* @return True, if the method is virtual
*/
bool is_virtual() const;
/**
* @brief Set whether the method is virtual.
*
* @param is_virtual True, if the method is virtual
*/
void is_virtual(bool is_virtual);
/**
* @brief Whether the method is const.
*
* @return True, if the method is const
*/
bool is_const() const;
/**
* @brief Set whether the method is const.
*
* @param is_const True, if the method is const
*/
void is_const(bool is_const);
/**
* @brief Whether the method is defaulted.
*
* @return True, if the method is defaulted
*/
bool is_defaulted() const;
/**
* @brief Set whether the method is defaulted.
*
* @param is_defaulted True, if the method is defaulted
*/
void is_defaulted(bool is_defaulted);
/**
* @brief Whether the method is deleted.
*
* @return True, if the method is deleted
*/
bool is_deleted() const;
/**
* @brief Set whether the method is deleted.
*
* @param is_deleted True, if the method is deleted
*/
void is_deleted(bool is_deleted);
/**
* @brief Whether the method is static.
*
* @return True, if the method is static
*/
bool is_static() const;
/**
* @brief Set whether the method is static.
*
* @param is_static True, if the method is static
*/
void is_static(bool is_static);
/**
* @brief Whether the method is constexpr.
*
* @return True, if the method is constexpr
*/
bool is_constexpr() const;
/**
* @brief Set whether the method is constexpr.
*
* @param is_constexpr True, if the method is constexpr
*/
void is_constexpr(bool is_constexpr);
/**
* @brief Whether the method is consteval.
*
* @return True, if the method is consteval
*/
bool is_consteval() const;
/**
* @brief Set whether the method is consteval.
*
* @param is_consteval True, if the method is consteval
*/
void is_consteval(bool is_consteval);
/**
* @brief Whether the method is noexcept.
*
* @return True, if the method is noexcept
*/
bool is_noexcept() const;
/**
* @brief Set whether the method is noexcept.
*
* @param is_noexcept True, if the method is noexcept
*/
void is_noexcept(bool is_noexcept);
/**
* @brief Whether the method is a constructor.
*
* @return True, if the method is a constructor
*/
bool is_constructor() const;
/**
* @brief Set whether the method is a constructor.
*
* @param is_constructor True, if the method is a constructor
*/
void is_constructor(bool is_constructor);
/**
* @brief Whether the method is a destructor.
*
* @return True, if the method is a destructor
*/
bool is_destructor() const;
/**
* @brief Set whether the method is a destructor.
*
* @param is_destructor True, if the method is a destructor
*/
void is_destructor(bool is_destructor);
/**
* @brief Whether the method is move assignment.
*
* @return True, if the method is move assignment
*/
bool is_move_assignment() const;
/**
* @brief Set whether the method is a move assignment.
*
* @param is_move_assignment True, if the method is a move assignment
*/
void is_move_assignment(bool is_move_assignment);
/**
* @brief Whether the method is copy assignment.
*
* @return True, if the method is copy assignment
*/
bool is_copy_assignment() const;
/**
* @brief Set whether the method is a copy assignment.
*
* @param is_copy_assignment True, if the method is a copy assignment
*/
void is_copy_assignment(bool is_copy_assignment);
/**
* @brief Whether the method is an operator.
*
* @return True, if the method is an operator
*/
bool is_operator() const;
/**
* @brief Set whether the method is an operator.
*
* @param is_copy_assignment True, if the method is an operator
*/
void is_operator(bool is_operator);
/**
* @brief Get the method parameters.
*
* @return List of methods parameters
*/
const std::vector<method_parameter> &parameters() const;
/**
* @brief Add methods parameter.
*
* @param parameter Method parameter.
*/
void add_parameter(method_parameter &&parameter);
private:

View File

@@ -1,5 +1,5 @@
/**
* src/class_diagram/model/class_parent.cc
* @file src/class_diagram/model/class_parent.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -24,6 +24,10 @@ void class_parent::set_name(const std::string &name) { name_ = name; }
std::string class_parent::name() const { return name_; }
void class_parent::set_id(clanguml::common::id_t id) { id_ = id; }
clanguml::common::id_t class_parent::id() const noexcept { return id_; }
void class_parent::is_virtual(bool is_virtual) { is_virtual_ = is_virtual; }
bool class_parent::is_virtual() const { return is_virtual_; }

View File

@@ -1,5 +1,5 @@
/**
* src/class_diagram/model/class_parent.h
* @file src/class_diagram/model/class_parent.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -25,25 +25,75 @@
namespace clanguml::class_diagram::model {
/**
* @brief Class parent relationship model.
*
* @todo Consider refactoring this class to a regular relationship.
*/
class class_parent {
public:
class_parent() = default;
class_parent(const std::string &name)
{
set_name(name);
set_id(common::to_id(name));
}
/**
* @brief Set the fully qualified name of class parent.
*
* @param name Fully qualified name of the parent class.
*/
void set_name(const std::string &name);
/**
* @brief Get the fully qualified name of class parent.
*
* @return Fully qualified name of the parent class.
*/
std::string name() const;
clanguml::common::id_t id() const noexcept { return id_; }
void set_id(clanguml::common::id_t id) { id_ = id; }
/**
* @brief Set the id of class parent.
*
* @param id Id of the parent class.
*/
void set_id(clanguml::common::id_t id);
/**
* @brief Get the id of class parent.
*
* @return Id of the parent class.
*/
clanguml::common::id_t id() const noexcept;
/**
* @brief Set whether the parent is virtual.
*
* @param is_virtual True if the parent is virtual
*/
void is_virtual(bool is_virtual);
/**
* @brief Get whether the parent is virtual.
*
* @return True, if the parent is virtual
*/
bool is_virtual() const;
/**
* @brief Set the parents access scope
*
* @param access Parents access scope
*/
void set_access(common::model::access_t access);
/**
* @brief Get parents access scope.
*
* @return Parents access scope.
*/
common::model::access_t access() const;
private:

View File

@@ -1,5 +1,5 @@
/**
* src/class_diagram/model/concept.cc
* @file src/class_diagram/model/concept.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -70,9 +70,9 @@ std::string concept_::full_name(bool relative) const
return res;
}
void concept_::add_parameter(method_parameter mp)
void concept_::add_parameter(const method_parameter &mp)
{
requires_parameters_.emplace_back(std::move(mp));
requires_parameters_.emplace_back(mp);
}
const std::vector<method_parameter> &concept_::requires_parameters() const

View File

@@ -1,5 +1,5 @@
/**
* src/class_diagram/model/concept.h
* @file src/class_diagram/model/concept.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -29,11 +29,9 @@
namespace clanguml::class_diagram::model {
struct requires_expression {
common::model::template_parameter parameter;
std::vector<std::string> requirements;
};
/**
* @brief Model of C++ concept.
*/
class concept_ : public common::model::element,
public common::model::stylable_element,
public common::model::template_trait {
@@ -45,6 +43,11 @@ public:
concept_ &operator=(const concept_ &) = delete;
concept_ &operator=(concept_ &&) = delete;
/**
* @brief Get the elements type name.
*
* @return 'concept'
*/
std::string type_name() const override { return "concept"; }
friend bool operator==(const concept_ &l, const concept_ &r);
@@ -53,12 +56,35 @@ public:
std::string full_name_no_ns() const override;
void add_parameter(method_parameter mp);
/**
* @brief Add concept parameter
*
* Concept class for convenience uses the same method parameter model
* as regular methods and functions.
*
* @param mp Concept parameter
*/
void add_parameter(const method_parameter &mp);
/**
* @brief Get concepts requires expression parameters
*
* @return List of concept requires expression parameters
*/
const std::vector<method_parameter> &requires_parameters() const;
/**
* @brief Add a concept statement
*
* @param stmt Concept statement
*/
void add_statement(std::string stmt);
/**
* @brief Get the concepts requires statements
*
* @return List of concepts requires statements
*/
const std::vector<std::string> &requires_statements() const;
private:

View File

@@ -1,5 +1,5 @@
/**
* src/class_diagram/model/diagram.cc
* @file src/class_diagram/model/diagram.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -198,6 +198,11 @@ inja::json diagram::context() const
elements.emplace_back(e.get().context());
}
// Add enums
for (const auto &c : concepts()) {
elements.emplace_back(c.get().context());
}
ctx["elements"] = elements;
return ctx;

View File

@@ -1,5 +1,5 @@
/**
* src/class_diagram/model/diagram.h
* @file src/class_diagram/model/diagram.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -45,6 +45,9 @@ using nested_trait_ns =
clanguml::common::model::nested_trait<clanguml::common::model::element,
clanguml::common::model::namespace_>;
/**
* @brief Class representing a class diagram.
*/
class diagram : public common::model::diagram,
public element_view<class_>,
public element_view<enum_>,
@@ -58,36 +61,132 @@ public:
diagram &operator=(const diagram &) = delete;
diagram &operator=(diagram &&) = default;
/**
* @brief Get the diagram model type - in this case class.
*
* @return Type of class diagram.
*/
diagram_t type() const override;
/**
* Inherit the should_include methods from the common diagram model.
*/
using common::model::diagram::should_include;
/**
* @brief Whether a class_member should be included in the diagram.
*
* @param m Class member
* @return True, if class member should be included in the diagram.
*/
bool should_include(const class_member &m) const;
/**
* @brief Whether a class_method should be included in the diagram.
*
* @param m Class method
* @return True, if class method should be included in the diagram.
*/
bool should_include(const class_method &m) const;
/**
* @brief Search for element in the diagram by fully qualified name.
*
* @param full_name Fully qualified element name.
* @return Optional reference to a diagram element.
*/
opt_ref<diagram_element> get(const std::string &full_name) const override;
/**
* @brief Search for element in the diagram by id.
*
* @param id Element id.
* @return Optional reference to a diagram element.
*/
opt_ref<diagram_element> get(diagram_element::id_t id) const override;
/**
* @brief Get list of references to classes in the diagram model.
*
* @return List of references to classes in the diagram model.
*/
const common::reference_vector<class_> &classes() const;
/**
* @brief Get list of references to enums in the diagram model.
*
* @return List of references to enums in the diagram model.
*/
const common::reference_vector<enum_> &enums() const;
/**
* @brief Get list of references to concepts in the diagram model.
*
* @return List of references to concepts in the diagram model.
*/
const common::reference_vector<concept_> &concepts() const;
/**
* @brief Check, if diagram contains a specific element.
*
* @tparam ElementT Type of diagram element (e.g. class_)
* @param e Element to check
* @return True, if element already exists in the diagram
*/
template <typename ElementT> bool contains(const ElementT &e);
/**
* @brief Find an element in the diagram by name.
*
* This method allows for typed search, where the type of searched for
* element is determined from template specialization.
*
* @tparam ElementT Type of element (e.g. class_)
* @param name Fully qualified name of the element
* @return Optional reference to a diagram element
*/
template <typename ElementT>
opt_ref<ElementT> find(const std::string &name) const;
/**
* @brief Find elements in the diagram by regex pattern.
*
* This method allows for typed search, where the type of searched for
* element is determined from template specialization.
*
* @tparam ElementT Type of element (e.g. class_)
* @param name String or regex pattern
* @return List of optional references to matched elements.
*/
template <typename ElementT>
std::vector<opt_ref<ElementT>> find(
const clanguml::common::string_or_regex &pattern) const;
/**
* @brief Find an element in the diagram by id.
*
* This method allows for typed search, where the type of searched for
* element is determined from template specialization.
*
* @tparam ElementT Type of element (e.g. class_)
* @param id Id of the element
* @return Optional reference to a diagram element
*/
template <typename ElementT>
opt_ref<ElementT> find(diagram_element::id_t id) const;
/**
* @brief Add element to the diagram at a specified nested path.
*
* Adds an element to a diagram, at a specific package (if any exist).
* The package is specified by the `parent_path`, which can be either
* a namespace or a directory path.
*
* @tparam ElementT Type of diagram element.
* @param parent_path Path to the parent package of the new diagram element.
* @param e Diagram element to be added.
* @return True, if the element was added to the diagram.
*/
template <typename ElementT>
bool add(const path &parent_path, std::unique_ptr<ElementT> &&e)
{
@@ -98,14 +197,41 @@ public:
return add_with_filesystem_path(parent_path, std::move(e));
}
/**
* @brief Convert element id to PlantUML alias.
*
* @todo This method does not belong here - refactor to PlantUML specific
* code.
*
* @param id Id of the diagram element.
* @return PlantUML alias.
*/
std::string to_alias(diagram_element::id_t id) const;
/**
* @brief Given an initial set of classes, add all their parents to the
* argument.
* @param parents In and out parameter with the parent classes.
*/
void get_parents(clanguml::common::reference_set<class_> &parents) const;
friend void print_diagram_tree(const diagram &d, int level);
/**
* @brief Check if diagram contains element by id.
*
* @todo Remove in favour of 'contains'
*
* @param id Id of the element.
* @return True, if diagram contains an element with a specific id.
*/
bool has_element(diagram_element::id_t id) const override;
/**
* @brief Return the elements JSON context for inja templates.
*
* @return JSON node with elements context.
*/
inja::json context() const override;
private:

View File

@@ -1,5 +1,5 @@
/**
* src/class_diagram/model/enum.cc
* @file src/class_diagram/model/enum.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -54,4 +54,11 @@ std::vector<std::string> &enum_::constants() { return constants_; }
const std::vector<std::string> &enum_::constants() const { return constants_; }
std::optional<std::string> enum_::doxygen_link() const
{
auto name = name_and_ns();
util::replace_all(name, "_", "__");
util::replace_all(name, "::", "_1_1");
return fmt::format("enum{}.html", name);
}
} // namespace clanguml::class_diagram::model

View File

@@ -1,5 +1,5 @@
/**
* src/class_diagram/model/enum.h
* @file src/class_diagram/model/enum.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -24,6 +24,9 @@
namespace clanguml::class_diagram::model {
/*
* @brief Diagram element representing an enum.
*/
class enum_ : public common::model::element,
public common::model::stylable_element {
public:
@@ -36,15 +39,31 @@ public:
std::string type_name() const override { return "enum"; }
// TODO: Do we need this?
friend bool operator==(const enum_ &l, const enum_ &r);
std::string full_name(bool relative = true) const override;
/**
* @brief Get the enums constants.
*
* @return Enums constants names list.
*/
std::vector<std::string> &constants();
/**
* @brief Get the enums constants.
*
* @return Enums constants names list.
*/
const std::vector<std::string> &constants() const;
/**
* @brief Get Doxygen link to documentation page for this element.
*
* @return Doxygen link for this element.
*/
std::optional<std::string> doxygen_link() const override;
private:
std::vector<std::string> constants_;
};

View File

@@ -1,5 +1,5 @@
/**
* src/class_diagram/model/method_parameter.cc
* @file src/class_diagram/model/method_parameter.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*

View File

@@ -1,5 +1,5 @@
/**
* src/class_diagram/model/method_parameter.h
* @file src/class_diagram/model/method_parameter.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -25,21 +25,73 @@
namespace clanguml::class_diagram::model {
/**
* @brief Model of a method parameter.
*/
class method_parameter : public common::model::decorated_element {
public:
method_parameter() = default;
/**
* @brief Constructor.
*
* @param type Type of the method parameter as string.
* @param name Name of the method parameter.
* @param default_value Default value of the parameter or empty.
*/
method_parameter(
std::string type, std::string name, std::string default_value = {});
~method_parameter() override = default;
/**
* @brief Set parameters type.
*
* @param type Parameters type as string.
*/
void set_type(const std::string &type);
/**
* @brief Get parameters type.
*
* @return Parameters type as string.
*/
std::string type() const;
/**
* @brief Set parameters name.
*
* @param type Parameters name.
*/
void set_name(const std::string &name);
/**
* @brief Get parameters name.
*
* @return Parameters name.
*/
std::string name() const;
/**
* @brief Set parameters default value.
*
* @param type Parameters default value as string.
*/
void set_default_value(const std::string &value);
/**
* @brief Get parameters name.
*
* @return Parameters name.
*/
std::string default_value() const;
/**
* @brief Render the method parameter to a string.
*
* @param using_namespaces If provided, make all namespaces relative to it.
* @return String representation of the parameter.
*/
std::string to_string(
const common::model::namespace_ &using_namespaces) const;

View File

@@ -1,5 +1,5 @@
/**
* src/class_diagram/visitor/template_builder.cc
* @file src/class_diagram/visitor/template_builder.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -235,7 +235,7 @@ std::unique_ptr<class_> template_builder::build(const clang::NamedDecl *cls,
auto templated_decl_id =
template_type.getTemplateName().getAsTemplateDecl()->getID();
auto templated_decl_local_id =
auto templated_decl_global_id =
id_mapper().get_global_id(templated_decl_id).value_or(0);
if (best_match_id > 0) {
@@ -246,12 +246,13 @@ std::unique_ptr<class_> template_builder::build(const clang::NamedDecl *cls,
}
// If we can't find optimal match for parent template specialization,
// just use whatever clang suggests
else if (diagram().has_element(templated_decl_local_id)) {
else if (diagram().has_element(templated_decl_global_id)) {
template_instantiation.add_relationship(
{relationship_t::kInstantiation, templated_decl_local_id});
{relationship_t::kInstantiation, templated_decl_global_id});
template_instantiation.template_specialization_found(true);
}
else if (diagram().should_include(full_template_specialization_name)) {
else if (diagram().should_include(
namespace_{full_template_specialization_name})) {
LOG_DBG("Skipping instantiation relationship from {} to {}",
template_instantiation_ptr->full_name(false), templated_decl_id);
}
@@ -351,7 +352,7 @@ template_builder::build_from_class_template_specialization(
{relationship_t::kInstantiation, templated_decl_local_id});
template_instantiation.template_specialization_found(true);
}
else if (diagram().should_include(qualified_name)) {
else if (diagram().should_include(namespace_{qualified_name})) {
LOG_DBG("Skipping instantiation relationship from {} to {}",
template_instantiation_ptr->full_name(false), templated_decl_id);
}
@@ -380,7 +381,7 @@ void template_builder::process_template_arguments(
// default values, and add them when they are specifically
// overridden
if (!diagram().should_include(
template_decl->getQualifiedNameAsString())) {
namespace_{template_decl->getQualifiedNameAsString()})) {
const auto *maybe_type_parm_decl =
clang::dyn_cast<clang::TemplateTypeParmDecl>(
template_decl->getTemplateParameters()->getParam(
@@ -1012,7 +1013,8 @@ template_builder::try_as_template_specialization_type(
argument.set_type(nested_type_name);
auto nested_template_instantiation = build(cls, *nested_template_type,
diagram().should_include(template_decl->getQualifiedNameAsString())
diagram().should_include(
namespace_{template_decl->getQualifiedNameAsString()})
? std::make_optional(&template_instantiation)
: parent);
@@ -1031,9 +1033,10 @@ template_builder::try_as_template_specialization_type(
nested_template_instantiation->full_name(false);
if (nested_template_instantiation &&
diagram().should_include(nested_template_instantiation_full_name)) {
diagram().should_include(
namespace_{nested_template_instantiation_full_name})) {
if (diagram().should_include(
template_decl->getQualifiedNameAsString())) {
namespace_{template_decl->getQualifiedNameAsString()})) {
template_instantiation.add_relationship(
{relationship_t::kDependency,
nested_template_instantiation->id()});
@@ -1045,7 +1048,8 @@ template_builder::try_as_template_specialization_type(
}
}
if (diagram().should_include(nested_template_instantiation_full_name)) {
if (diagram().should_include(
namespace_{nested_template_instantiation_full_name})) {
visitor_.set_source_location(
*template_decl, *nested_template_instantiation);
visitor_.add_class(std::move(nested_template_instantiation));
@@ -1155,7 +1159,7 @@ std::optional<template_parameter> template_builder::try_as_record_type(
template_instantiation.add_relationship(std::move(r));
}
if (diagram().should_include(tag_argument->full_name(false))) {
if (diagram().should_include(tag_argument->get_namespace())) {
if (parent.has_value())
parent.value()->add_relationship(
{relationship_t::kDependency, tag_argument->id()});
@@ -1166,7 +1170,7 @@ std::optional<template_parameter> template_builder::try_as_record_type(
}
else if (const auto *record_type_decl = record_type->getAsRecordDecl();
record_type_decl != nullptr) {
if (diagram().should_include(type_name)) {
if (diagram().should_include(namespace_{type_name})) {
// Add dependency relationship to the parent
// template
template_instantiation.add_relationship(

View File

@@ -1,5 +1,5 @@
/**
* src/class_diagram/visitor/template_builder.h
* @file src/class_diagram/visitor/template_builder.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -36,35 +36,111 @@ using found_relationships_t =
class translation_unit_visitor;
/**
* @brief Class responsible for building all kinds of templates from Clang AST.
*/
class template_builder {
public:
/**
* @brief Constructor.
*
* @param visitor Reference to class diagram translation_unit_visitor
*/
template_builder(
clanguml::class_diagram::visitor::translation_unit_visitor &visitor);
/**
* @brief Get reference to the current diagram model
*
* @return Reference to the current diagram model
*/
class_diagram::model::diagram &diagram();
/**
* @brief Get reference to the current diagram configuration
*
* @return Reference to the current diagram configuration
*/
const config::class_diagram &config() const;
/**
* @brief Get diagram relative namespace
*
* @return Diagram relative namespace
*/
const namespace_ &using_namespace() const;
/**
* @brief Simplify system templates
*
* This method tries to simplify all fully qualified template names
* in the `full_name` using substitutions from the configuration file
* ().
*
* Typical example is replace every `std::basic_string<char>` with
* `std::string`.
*
* @param ct Template parameter
* @param full_name Full template name
* @return
*/
bool simplify_system_template(
template_parameter &ct, const std::string &full_name) const;
/**
* @brief Basic template class build method
*
* @param cls Clang template declaration
* @param template_type_decl Template specialization type
* @param parent Optional class in which this template is contained
* @return Created template class model
*/
std::unique_ptr<clanguml::class_diagram::model::class_> build(
const clang::NamedDecl *cls,
const clang::TemplateSpecializationType &template_type_decl,
std::optional<clanguml::class_diagram::model::class_ *> parent = {});
/**
* @brief Build template class from class template specialization decl
*
* @param template_specialization Class template specialization declaration
* @param parent Optional class in which this template is contained
* @return Created template class model
*/
std::unique_ptr<clanguml::class_diagram::model::class_>
build_from_class_template_specialization(
const clang::ClassTemplateSpecializationDecl &template_specialization,
std::optional<clanguml::class_diagram::model::class_ *> parent = {});
/**
* @brief Add base classes to the template class, if any.
*
* This method adds base classes to a template declaration or
* specialization, including inferring whether variadic template
* parameter bases.
*
* @param tinst Class template model
* @param template_base_params List of base class template parameters
* @param arg_index Index of the template argument used for base class
* @param variadic_params Whether the parameter is variadic
* @param ct Template parameter model
* @return True, if any base classes were added
*/
bool add_base_classes(clanguml::class_diagram::model::class_ &tinst,
std::deque<std::tuple<std::string, int, bool>> &template_base_params,
int arg_index, bool variadic_params,
const clanguml::common::model::template_parameter &ct);
/**
* @brief Process template class parameters and arguments
*
* @param parent Optional class in which this template is contained
* @param cls Template class specialization declaration
* @param template_base_params List of base class template parameters
* @param template_args List of template arguments
* @param template_instantiation Template class model to add template args
* @param template_decl Base template declaration
*/
void process_template_arguments(
std::optional<clanguml::class_diagram::model::class_ *> &parent,
const clang::NamedDecl *cls,
@@ -73,6 +149,18 @@ public:
model::class_ &template_instantiation,
const clang::TemplateDecl *template_decl);
/**
* @brief Process template arguments based on their type
*
* @param parent Optional class in which this template is contained
* @param cls Template class specialization declaration
* @param template_instantiation Template class model to add template args
* @param template_decl Base template declaration
* @param arg Template argument
* @param argument_index Argument index
* @param argument Output list of arguments (can be more than one for
* variadic parameters)
*/
void argument_process_dispatch(
std::optional<clanguml::class_diagram::model::class_ *> &parent,
const clang::NamedDecl *cls, class_ &template_instantiation,
@@ -80,18 +168,64 @@ public:
const clang::TemplateArgument &arg, size_t argument_index,
std::vector<template_parameter> &argument);
/**
* @brief Process `clang::TemplateArgument::Expression`
*
* @note The template argument is a pack expansion of a template name that
* was provided for a template template parameter.
*
* @param arg Template argument
* @return Return template argument model
*/
template_parameter process_expression_argument(
const clang::TemplateArgument &arg);
/**
* @brief Process `clang::TemplateArgument::Integral`
*
* @note The template argument is an integral value stored in an
* llvm::APSInt that was provided for an integral non-type template
* parameter.
*
* @param arg Template argument
* @return Return template argument model
*/
template_parameter process_integral_argument(
const clang::TemplateArgument &arg);
/**
* @brief Process `clang::TemplateArgument::NullPtr`
*
* @note The template argument is a null pointer or null pointer to member
* that was provided for a non-type template parameter.
*
* @param arg Template argument
* @return Return template argument model
*/
template_parameter process_nullptr_argument(
const clang::TemplateArgument &arg);
/**
* @brief Process `clang::TemplateArgument::Null`
*
* @note Represents an empty template argument, e.g., one that has not
* been deduced.
*
* @param arg Template argument
* @return Return template argument model
*/
template_parameter process_null_argument(
const clang::TemplateArgument &arg);
/**
* @brief Process `clang::TemplateArgument::Pack`
*
* @note The template argument is actually a parameter pack. Arguments are
* stored in the Args struct.
*
* @param arg Template argument
* @return Return template argument model
*/
std::vector<template_parameter> process_pack_argument(
std::optional<clanguml::class_diagram::model::class_ *> &parent,
const clang::NamedDecl *cls, class_ &template_instantiation,
@@ -99,85 +233,260 @@ public:
const clang::TemplateArgument &arg, size_t argument_index,
std::vector<template_parameter> &argument);
/**
* @brief Process `clang::TemplateArgument::Type`
*
* @note The template argument is a type.
*
* @param arg Template argument
* @return Return template argument model
*/
template_parameter process_type_argument(
std::optional<clanguml::class_diagram::model::class_ *> &parent,
const clang::NamedDecl *cls,
const clang::TemplateDecl *base_template_decl, clang::QualType type,
model::class_ &template_instantiation, size_t argument_index);
/**
* @brief Process `clang::TemplateArgument::Template`
*
* @note The template argument is a template name that was provided for a
* template template parameter.
*
* @param arg Template argument
* @return Return template argument model
*/
common::model::template_parameter process_template_argument(
const clang::TemplateArgument &arg);
/**
* @brief Process `clang::TemplateArgument::TemplateExpansion`
*
* @note The template argument is a pack expansion of a template name that
* was provided for a template template parameter.
*
* @param arg Template argument
* @return Return template argument model
*/
common::model::template_parameter process_template_expansion(
const clang::TemplateArgument &arg);
/**
* @brief Try to process template type argument as function template
*
* @param parent Optional class in which this template is contained
* @param cls Template class specialization declaration
* @param template_decl Base template declaration
* @param type Template type
* @param template_instantiation Template class model
* @param argument_index Argument index
* @return Function template argument if succeeds, or std::nullopt
*/
std::optional<template_parameter> try_as_function_prototype(
std::optional<clanguml::class_diagram::model::class_ *> &parent,
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
clang::QualType &type, class_ &template_instantiation,
size_t argument_index);
/**
* @brief Try to process template type argument as array
*
* @param parent Optional class in which this template is contained
* @param cls Template class specialization declaration
* @param template_decl Base template declaration
* @param type Template type
* @param template_instantiation Template class model
* @param argument_index Argument index
* @return Array template argument if succeeds, or std::nullopt
*/
std::optional<template_parameter> try_as_array(
std::optional<clanguml::class_diagram::model::class_ *> &parent,
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
clang::QualType &type, class_ &template_instantiation,
size_t argument_index);
/**
* @brief Try to process template type argument as specialization type
*
* @param parent Optional class in which this template is contained
* @param cls Template class specialization declaration
* @param template_decl Base template declaration
* @param type Template type
* @param template_instantiation Template class model
* @param argument_index Argument index
* @return Template specialization template argument if succeeds,
* or std::nullopt
*/
std::optional<template_parameter> try_as_template_specialization_type(
std::optional<clanguml::class_diagram::model::class_ *> &parent,
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
clang::QualType &type, class_ &template_instantiation,
size_t argument_index);
/**
* @brief Try to process template type argument as template parameter
*
* @param cls Template class specialization declaration
* @param template_decl Base template declaration
* @param type Template type
* @return Template parameter if succeeds, or std::nullopt
*/
std::optional<template_parameter> try_as_template_parm_type(
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
clang::QualType &type);
/**
* @brief Try to process template type argument as lambda
*
* @param cls Template class specialization declaration
* @param template_decl Base template declaration
* @param type Template type
* @return Lambda template argument if succeeds, or std::nullopt
*/
std::optional<template_parameter> try_as_lambda(const clang::NamedDecl *cls,
const clang::TemplateDecl *template_decl, clang::QualType &type);
/**
* @brief Try to process template type argument as record type
*
* @param parent Optional class in which this template is contained
* @param cls Template class specialization declaration
* @param template_decl Base template declaration
* @param type Template type
* @param template_instantiation Template class model
* @param argument_index Argument index
* @return Record type template argument if succeeds, or std::nullopt
*/
std::optional<template_parameter> try_as_record_type(
std::optional<clanguml::class_diagram::model::class_ *> &parent,
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
clang::QualType &type, class_ &template_instantiation,
size_t argument_index);
/**
* @brief Try to process template type argument as enum type
*
* @param parent Optional class in which this template is contained
* @param cls Template class specialization declaration
* @param template_decl Base template declaration
* @param type Template type
* @param template_instantiation Template class model
* @return Enum type template argument if succeeds, or std::nullopt
*/
std::optional<template_parameter> try_as_enum_type(
std::optional<clanguml::class_diagram::model::class_ *> &parent,
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
clang::QualType &type, class_ &template_instantiation);
/**
* @brief Try to process template type argument as builtin type
*
* @param parent Optional class in which this template is contained
* @param type Template type
* @param template_decl Base template declaration
* @return Builtin type template argument if succeeds, or std::nullopt
*/
std::optional<template_parameter> try_as_builtin_type(
std::optional<clanguml::class_diagram::model::class_ *> &parent,
clang::QualType &type, const clang::TemplateDecl *template_decl);
/**
* @brief Try to process template type argument as member pointer type
*
* @param parent Optional class in which this template is contained
* @param cls Template class specialization declaration
* @param template_decl Base template declaration
* @param type Template type
* @param template_instantiation Template class model
* @param argument_index Argument index
* @return Member pointer type template argument if succeeds,
* or std::nullopt
*/
std::optional<template_parameter> try_as_member_pointer(
std::optional<clanguml::class_diagram::model::class_ *> &parent,
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
clang::QualType &type, class_ &template_instantiation,
size_t argument_index);
/**
* @brief Try to process template type argument as `decltype()` type
*
* @param parent Optional class in which this template is contained
* @param cls Template class specialization declaration
* @param template_decl Base template declaration
* @param type Template type
* @param template_instantiation Template class model
* @param argument_index Argument index
* @return `decltype()` type template argument if succeeds, or std::nullopt
*/
std::optional<template_parameter> try_as_decl_type(
std::optional<clanguml::class_diagram::model::class_ *> &parent,
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
clang::QualType &type, class_ &template_instantiation,
size_t argument_index);
/**
* @brief Try to process template type argument as typedef/using type
*
* @param parent Optional class in which this template is contained
* @param cls Template class specialization declaration
* @param template_decl Base template declaration
* @param type Template type
* @param template_instantiation Template class model
* @param argument_index Argument index
* @return Typedef type template argument if succeeds, or std::nullopt
*/
std::optional<template_parameter> try_as_typedef_type(
std::optional<clanguml::class_diagram::model::class_ *> &parent,
const clang::NamedDecl *cls, const clang::TemplateDecl *template_decl,
clang::QualType &type, class_ &template_instantiation,
size_t argument_index);
/**
* @brief Remove types context (e.g. const or reference qualifiers)
*
* This method removes all const and reference/pointer qualifiers from
* `type`, adds them to the template parameter model `tp` and returns
* a type without context.
*
* @param type Type to remove context from
* @param tp Template model to add context to
* @return Type without context
*/
clang::QualType consume_context(
clang::QualType type, template_parameter &tp) const;
/**
* @brief Try to find additional relationships in unexposed parameters
*
* Sometimes, Clang will report a template parameter as unexposed, which
* means all we get a is a string representation of the type, sometimes
* with template parameter names replaced with `type-parameter-X-Y`
* string.
*
* This method tries to find any type names, which might be relevant for
* the diagram relationships.
*
* @param ct Template argument model
* @param relationships List of discovered relationships
* @return True, if any relationships were found
*/
bool find_relationships_in_unexposed_template_params(
const template_parameter &ct,
class_diagram::visitor::found_relationships_t &relationships);
/**
* @brief Get reference to Clang AST to clang-uml id mapper
*
* @return Reference to Clang AST to clang-uml id mapper
*/
common::visitor::ast_id_mapper &id_mapper();
/**
* @brief Get reference to the current source manager
*
* @return Reference to the current source manager
*/
clang::SourceManager &source_manager() const;
private:

View File

@@ -1,5 +1,5 @@
/**
* src/class_diagram/visitor/translation_unit_visitor.cc
* @file src/class_diagram/visitor/translation_unit_visitor.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -100,7 +100,7 @@ bool translation_unit_visitor::VisitEnumDecl(clang::EnumDecl *enm)
if (enm->getNameAsString().empty())
return true;
if (!diagram().should_include(enm->getQualifiedNameAsString()))
if (!should_include(enm))
return true;
LOG_DBG("= Visiting enum declaration {} at {}",
@@ -169,8 +169,7 @@ bool translation_unit_visitor::VisitEnumDecl(clang::EnumDecl *enm)
e.constants().push_back(ev->getNameAsString());
}
if (diagram().should_include(qualified_name))
add_enum(std::move(e_ptr));
add_enum(std::move(e_ptr));
return true;
}
@@ -178,10 +177,7 @@ bool translation_unit_visitor::VisitEnumDecl(clang::EnumDecl *enm)
bool translation_unit_visitor::VisitClassTemplateSpecializationDecl(
clang::ClassTemplateSpecializationDecl *cls)
{
if (source_manager().isInSystemHeader(cls->getSourceRange().getBegin()))
return true;
if (!diagram().should_include(cls->getQualifiedNameAsString()))
if (!should_include(cls))
return true;
LOG_DBG("= Visiting template specialization declaration {} at {} "
@@ -241,10 +237,7 @@ bool translation_unit_visitor::VisitClassTemplateSpecializationDecl(
bool translation_unit_visitor::VisitTypeAliasTemplateDecl(
clang::TypeAliasTemplateDecl *cls)
{
if (source_manager().isInSystemHeader(cls->getSourceRange().getBegin()))
return true;
if (!diagram().should_include(cls->getQualifiedNameAsString()))
if (!should_include(cls))
return true;
LOG_DBG("= Visiting template type alias declaration {} at {}",
@@ -280,10 +273,7 @@ bool translation_unit_visitor::VisitTypeAliasTemplateDecl(
bool translation_unit_visitor::VisitClassTemplateDecl(
clang::ClassTemplateDecl *cls)
{
if (source_manager().isInSystemHeader(cls->getSourceRange().getBegin()))
return true;
if (!diagram().should_include(cls->getQualifiedNameAsString()))
if (!should_include(cls))
return true;
LOG_DBG("= Visiting class template declaration {} at {}",
@@ -339,16 +329,12 @@ bool translation_unit_visitor::VisitClassTemplateDecl(
bool translation_unit_visitor::VisitRecordDecl(clang::RecordDecl *rec)
{
// Skip system headers
if (source_manager().isInSystemHeader(rec->getSourceRange().getBegin()))
return true;
if (clang::dyn_cast_or_null<clang::CXXRecordDecl>(rec) != nullptr)
// This is handled by VisitCXXRecordDecl()
return true;
// It seems we are in a C (not C++) translation unit
if (!diagram().should_include(rec->getQualifiedNameAsString()))
if (!should_include(rec))
return true;
LOG_DBG("= Visiting record declaration {} at {}",
@@ -396,11 +382,7 @@ bool translation_unit_visitor::VisitRecordDecl(clang::RecordDecl *rec)
bool translation_unit_visitor::TraverseConceptDecl(clang::ConceptDecl *cpt)
{
// Skip system headers
if (source_manager().isInSystemHeader(cpt->getSourceRange().getBegin()))
return true;
if (!diagram().should_include(cpt->getQualifiedNameAsString()))
if (!should_include(cpt))
return true;
LOG_DBG("= Visiting concept (isType: {}) declaration {} at {}",
@@ -1314,7 +1296,7 @@ void translation_unit_visitor::process_method(
*unaliased_type, &c);
if (diagram().should_include(
template_specialization_ptr->full_name(false))) {
template_specialization_ptr->get_namespace())) {
relationships.emplace_back(template_specialization_ptr->id(),
relationship_t::kDependency);
@@ -1686,7 +1668,7 @@ void translation_unit_visitor::process_function_parameter(
templ->getTemplateName().getAsTemplateDecl(), *templ, &c);
if (diagram().should_include(
template_specialization_ptr->full_name(false))) {
template_specialization_ptr->get_namespace())) {
relationships.emplace_back(template_specialization_ptr->id(),
relationship_t::kDependency);
@@ -1956,7 +1938,7 @@ void translation_unit_visitor::process_field(
// it's a std::vector<>, it's nested types might be added
bool add_template_instantiation_to_diagram{false};
if (diagram().should_include(
template_specialization.full_name(false))) {
template_specialization.get_namespace())) {
found_relationships_t::value_type r{
template_specialization.id(), relationship_hint};
@@ -2034,7 +2016,7 @@ void translation_unit_visitor::process_field(
void translation_unit_visitor::add_incomplete_forward_declarations()
{
for (auto &[id, c] : forward_declarations_) {
if (diagram().should_include(c->full_name(false))) {
if (diagram().should_include(c->get_namespace())) {
add_class(std::move(c));
}
}
@@ -2107,8 +2089,21 @@ void translation_unit_visitor::extract_constrained_template_param_name(
bool translation_unit_visitor::should_include(const clang::NamedDecl *decl)
{
return decl != nullptr &&
diagram().should_include(decl->getQualifiedNameAsString());
if (decl == nullptr)
return false;
if (source_manager().isInSystemHeader(decl->getSourceRange().getBegin()))
return false;
auto should_include_namespace =
diagram().should_include(namespace_{decl->getQualifiedNameAsString()});
const auto decl_file = decl->getLocation().printToString(source_manager());
const auto should_include_decl_file =
diagram().should_include(common::model::source_file{decl_file});
return should_include_namespace && should_include_decl_file;
}
void translation_unit_visitor::add_processed_template_class(

View File

@@ -1,5 +1,5 @@
/**
* src/class_diagram/visitor/translation_unit_visitor.h
* @file src/class_diagram/visitor/translation_unit_visitor.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -57,17 +57,28 @@ using clanguml::common::model::template_trait;
/**
* @brief Class diagram translation unit visitor
*
* This class implements the @link clang::RecursiveASTVisitor interface
* This class implements the `clang::RecursiveASTVisitor` interface
* for selected visitors relevant to generating class diagrams.
*/
class translation_unit_visitor
: public clang::RecursiveASTVisitor<translation_unit_visitor>,
public common::visitor::translation_unit_visitor {
public:
/**
* @brief Constructor.
*
* @param sm Current source manager reference
* @param diagram Diagram model
* @param config Diagram configuration
*/
explicit translation_unit_visitor(clang::SourceManager &sm,
clanguml::class_diagram::model::diagram &diagram,
const clanguml::config::class_diagram &config);
/**
* \defgroup Implementation of ResursiveASTVisitor methods
* @{
*/
bool shouldVisitTemplateInstantiations() const { return false; }
bool shouldVisitImplicitCode() const { return false; }
@@ -89,6 +100,7 @@ public:
virtual bool VisitTypeAliasTemplateDecl(clang::TypeAliasTemplateDecl *cls);
virtual bool TraverseConceptDecl(clang::ConceptDecl *cpt);
/** @} */
/**
* @brief Get diagram model reference
@@ -97,6 +109,11 @@ public:
*/
clanguml::class_diagram::model::diagram &diagram() { return diagram_; }
/**
* @brief Get diagram model reference
*
* @return Reference to diagram model created by the visitor
*/
const clanguml::class_diagram::model::diagram &diagram() const
{
return diagram_;
@@ -119,112 +136,335 @@ public:
*/
void finalize();
/**
* @brief Get reference to Clang AST to clang-uml id mapper
*
* @return Reference to Clang AST to clang-uml id mapper
*/
common::visitor::ast_id_mapper &id_mapper() const { return id_mapper_; }
/**
* @brief Add class (or template class) to the diagram.
*
* @param c Class model
*/
void add_class(std::unique_ptr<class_> &&c);
/**
* @brief Add enum to the diagram.
*
* @param e Enum model
*/
void add_enum(std::unique_ptr<enum_> &&e);
/**
* @brief Add concept to the diagram.
*
* @param c Concept model
*/
void add_concept(std::unique_ptr<concept_> &&c);
void ensure_lambda_type_is_relative(std::string &parameter_type) const;
private:
/**
* @brief Check if the diagram should include a declaration.
*
* @param decl Clang declaration.
* @return True, if the entity should be included in the diagram.
*/
bool should_include(const clang::NamedDecl *decl);
/**
* @brief Create class element model from class declaration
*
* @param cls Class declaration
* @return Class diagram element model
*/
std::unique_ptr<clanguml::class_diagram::model::class_>
create_class_declaration(clang::CXXRecordDecl *cls);
/**
* @brief Create class element model from record (e.g. struct) declaration
*
* @param rec Record declaration
* @return Class diagram element model
*/
std::unique_ptr<clanguml::class_diagram::model::class_>
create_record_declaration(clang::RecordDecl *rec);
/**
* @brief Create concept element model from concept declaration
* @param cpt Concept declaration
* @return Concept diagram element model
*/
std::unique_ptr<clanguml::class_diagram::model::concept_>
create_concept_declaration(clang::ConceptDecl *cpt);
/**
* @brief Process class declaration
*
* @param cls Class declaration
* @param c Class diagram element return from `create_class_declaration`
*/
void process_class_declaration(const clang::CXXRecordDecl &cls,
clanguml::class_diagram::model::class_ &c);
/**
* @brief Process class declaration bases (parents), if any
*
* @param cls Class declaration
* @param c Class diagram element model
*/
void process_class_bases(const clang::CXXRecordDecl *cls,
clanguml::class_diagram::model::class_ &c);
/**
* @brief Process class children elements (members and methods)
*
* @param cls Class declaration
* @param c Class diagram element model
*/
void process_class_children(const clang::CXXRecordDecl *cls,
clanguml::class_diagram::model::class_ &c);
/**
* @brief Process class or record data members
* @param cls Class declaration
* @param c Class diagram element model
*/
void process_record_members(const clang::RecordDecl *cls, class_ &c);
/**
* @brief Process class template specialization/instantiation
*
* @param cls Class template specialization declaration
* @return Class diagram element model
*/
std::unique_ptr<clanguml::class_diagram::model::class_>
process_template_specialization(
clang::ClassTemplateSpecializationDecl *cls);
/**
* @brief Process template specialiaztion children (members and methods)
* @param cls Class template specialization declaration
* @param c Class diagram element model
*/
void process_template_specialization_children(
const clang::ClassTemplateSpecializationDecl *cls, class_ &c);
/**
* @brief Process template parameters
*
* @param template_declaration Template declaration
* @param t `template_trait` instance to which the parameters should be
* added
* @param templated_element Optional templated diagram element (e.g. class_)
* @return Ignored
*/
bool process_template_parameters(
const clang::TemplateDecl &template_declaration,
clanguml::common::model::template_trait &t,
common::optional_ref<common::model::element> templated_element = {});
/**
* @brief Process class method
*
* @param mf Method declaration
* @param c Class diagram element model
*/
void process_method(const clang::CXXMethodDecl &mf,
clanguml::class_diagram::model::class_ &c);
/**
* @brief Process class method properties
* @param mf Method declaration
* @param c Class diagram element model
* @param method_name Method name
* @param method Method model
*/
void process_method_properties(const clang::CXXMethodDecl &mf,
const class_ &c, const std::string &method_name,
class_method &method) const;
/**
* @brief Process class template method
*
* @param mf Method declaration
* @param c Class diagram element model
*/
void process_template_method(const clang::FunctionTemplateDecl &mf,
clanguml::class_diagram::model::class_ &c);
/**
* @brief Process class static data member
*
* @param field_declaration Static data member declaration
* @param c Class diagram element model
*/
void process_static_field(const clang::VarDecl &field_declaration,
clanguml::class_diagram::model::class_ &c);
/**
* @brief Process class data member
*
* @param field_declaration Data member declaration
* @param c Class diagram element model
*/
void process_field(const clang::FieldDecl &field_declaration,
clanguml::class_diagram::model::class_ &c);
/**
* @brief Process function/method parameter
*
* @param param Parameter declaration
* @param method Class method model
* @param c Class diagram element model
* @param template_parameter_names Ignored
*/
void process_function_parameter(const clang::ParmVarDecl &param,
clanguml::class_diagram::model::class_method &method,
clanguml::class_diagram::model::class_ &c,
const std::set<std::string> &template_parameter_names = {});
/**
* @brief Process class friend
*
* @param f Friend declaration
* @param c Class diagram element model
*/
void process_friend(
const clang::FriendDecl &f, clanguml::class_diagram::model::class_ &c);
/**
* @brief Find relationships in a specific type
*
* @param type Type to search for relationships
* @param relationship_hint Default relationship type to infer from this
* type
* @return True, if any relationships were found
*/
bool find_relationships(const clang::QualType &type,
found_relationships_t & /*relationships*/,
clanguml::common::model::relationship_t relationship_hint);
/**
* @brief Add relationships from relationship list to a class model
*
* This method takes a list of relationships whose originating element
* is class `c` and adds them to it, ignoring any duplicates and skipping
* relationships that should be excluded from the diagram.
*
* @param c Class diagram element model
* @param field Class member model
* @param relationships List of found relationships
* @param break_on_first_aggregation Stop adding relatinoships, after first
* aggregation is found
*/
void add_relationships(clanguml::class_diagram::model::class_ &c,
const clanguml::class_diagram::model::class_member &field,
const found_relationships_t &relationships,
bool break_on_first_aggregation = false);
/**
* @brief Process record parent element (e.g. for nested classes)
*
* This method handles nested classes or structs.
*
* @param cls Record declaration
* @param c Class diagram element model
* @param ns Package in the diagram to which the class `c` should belong
*/
void process_record_parent(
clang::RecordDecl *cls, class_ &c, const namespace_ &ns);
/**
* @brief Find relationships in function parameter
*
* @param c Class diagram element model
* @param atsp `auto` type
*/
void process_function_parameter_find_relationships_in_autotype(
model::class_ &c, const clang::AutoType *atsp);
/**
* @brief Find relationships in concept constraint expression
*
* @param c Diagram element model (concept)
* @param expr Concept constraint expression
*/
void find_relationships_in_constraint_expression(
clanguml::common::model::element &c, const clang::Expr *expr);
/**
* @brief Register incomplete forward declaration to be updated later
*/
void add_incomplete_forward_declarations();
/**
* @brief Replace any AST local ids in diagram elements with global ones
*
* Not all elements global ids can be set in relationships during
* traversal of the AST. In such cases, a local id (obtained from `getID()`)
* and at after the traversal is complete, the id is replaced with the
* global diagram id.
*/
void resolve_local_to_global_ids();
/**
* @brief Process concept constraint requirements
*
* @param cpt Concept declaration
* @param expr Requires expression
* @param concept_model Concept diagram element model
*/
void process_constraint_requirements(const clang::ConceptDecl *cpt,
const clang::Expr *expr, model::concept_ &concept_model) const;
/**
* @brief Find concept specializations relationships
*
* @param c Concept element model
* @param concept_specialization Concept specialization expression
*/
void process_concept_specialization_relationships(common::model::element &c,
const clang::ConceptSpecializationExpr *concept_specialization);
/**
* @brief Extract template contraint parameter name from raw source code
*
* @param concept_specialization Concept specialization expression
* @param cpt Concept declaration
* @param constrained_template_params Found constraint template param names
* @param argument_index Argument index
* @param type_name Type parameter name - used if extraction fails
*/
void extract_constrained_template_param_name(
const clang::ConceptSpecializationExpr *concept_specialization,
const clang::ConceptDecl *cpt,
std::vector<std::string> &constrained_template_params,
size_t argument_index, std::string &type_name) const;
/// Store the mapping from local clang entity id (obtained using
/// getID()) method to clang-uml global id
void set_ast_local_id(
int64_t local_id, common::model::diagram_element::id_t global_id);
/**
* @brief Register already processed template class name
*
* @param qualified_name Fully qualified template class name
*/
void add_processed_template_class(std::string qualified_name);
/**
* @brief Check if template class has already been processed
*
* @param qualified_name Fully qualified template class name
* @return True, if template class has already been processed
*/
bool has_processed_template_class(const std::string &qualified_name) const;
/**
* @brief Get template builder reference
*
* @return Reference to 'template_builder' instance
*/
template_builder &tbuilder() { return template_builder_; }
// Reference to the output diagram model
@@ -246,13 +486,13 @@ private:
common::model::access_t>>
anonymous_struct_relationships_;
// When visiting CXX records we need to know if they have already been
// process in VisitClassTemplateDecl or VisitClassTemplateSpecializationDecl
// If yes, then we need to skip it
// TODO: There must be a better way to do this...
/**
* When visiting CXX records we need to know if they have already been
* process in VisitClassTemplateDecl or
* VisitClassTemplateSpecializationDecl. If yes, then we need to skip it
*
* @todo There must be a better way to do this...
*/
std::set<std::string> processed_template_qualified_names_;
void process_method_properties(const clang::CXXMethodDecl &mf,
const class_ &c, const std::string &method_name,
class_method &method) const;
};
} // namespace clanguml::class_diagram::visitor

View File

@@ -1,5 +1,5 @@
/**
* src/options/cli_handler.cc
* @file src/options/cli_handler.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*

View File

@@ -1,5 +1,5 @@
/**
* src/options/cli_handler.h
* @file src/options/cli_handler.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -25,9 +25,21 @@
#include <optional>
namespace clanguml::cli {
/**
* This enum represents possible exit states of the command line parser.
*/
enum class cli_flow_t {
kExit, /*!< The application should exit (e.g. `-h`) */
kError, /*!< The options or configuration file were invalid */
kContinue /*!< Continue with processing diagrams */
};
enum class cli_flow_t { kExit, kError, kContinue };
/**
* @brief Command line options handler
*
* This class is responsible for handling the command line options
* and executing required actions.
*/
class cli_handler {
public:
cli_handler(std::ostream &ostr = std::cout,
@@ -37,45 +49,55 @@ public:
/**
* Main CLI handling method.
*
* @embed{cli_handle_options_sequence.svg}
*
* @param argc
* @param argv
* @return
* @return Command line handler state
*/
cli_flow_t handle_options(int argc, const char **argv);
/**
* Print the program version and basic information
*
* @return Command line handler state
*/
cli_flow_t print_version();
/**
* Print list of diagrams available in the configuration file
*
* @return Command line handler state
*/
cli_flow_t print_diagrams_list();
/**
* Print list of available diagram templates, including their names
* and types.
*
* @return Command line handler state
*/
cli_flow_t print_diagram_templates();
/**
* Print definition of a specific diagram template.
*
* @param template_name
* @return
* @param template_name Name of the diagram template
* @return Command line handler state
*/
cli_flow_t print_diagram_template(const std::string &template_name);
/**
* Print effective config after loading and setting default values.
*
* @return Command line handler state
*/
cli_flow_t print_config();
/**
* Generate sample configuration file and exit.
*
* @return 0 on success or error code
* @return Command line handler state
*/
cli_flow_t create_config_file();
@@ -85,7 +107,7 @@ public:
* @param type Type of the sample diagram to add
* @param config_file_path Path to the config file
* @param name Name of the new diagram
* @return 0 on success or error code
* @return Command line handler state
*/
cli_flow_t add_config_diagram(clanguml::common::model::diagram_t type,
const std::string &config_file_path, const std::string &name);
@@ -96,7 +118,7 @@ public:
* @param config_file_path
* @param template_name
* @param template_variables
* @return
* @return Command line handler state
*/
cli_flow_t add_config_diagram_from_template(
const std::string &config_file_path, const std::string &template_name,
@@ -144,14 +166,39 @@ public:
clanguml::config::config config;
private:
/**
* This method parses the command line options using CLI11 library.
*
* @param argc
* @param argv
* @return Command line handler state
*/
cli_flow_t parse(int argc, const char **argv);
/**
* Handle command line options before parsing the configuration file
*
* @return Command line handler state
*/
cli_flow_t handle_pre_config_options();
/**
* Load configuration file from file or stdin
*
* @return Command line handler state
*/
cli_flow_t load_config();
/**
* Handle command line options before parsing the configuration file
*
* @return Command line handler state
*/
cli_flow_t handle_post_config_options();
/**
* Setup spdlog library depending on provided command line options
*/
void setup_logging();
std::ostream &ostr_;

View File

@@ -1,5 +1,5 @@
/**
* src/common/visitor/clang_utils.cc
* @file src/common/clang_utils.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*

View File

@@ -1,5 +1,5 @@
/**
* src/common/clang_utils.h
* @file src/common/clang_utils.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -35,23 +35,35 @@ class NamespaceDecl;
namespace clanguml::common {
/**
* @brief Convert @link clang::AccessSpecifier to @link model::access_t
* @brief Convert `clang::AccessSpecifier` to @see clanguml::model::access_t
*
* @param access_specifier Clang member access specifier
* @return Enum value of @link model::access_t
* @return Enum value of @see clanguml::model::access_t
*/
model::access_t access_specifier_to_access_t(
clang::AccessSpecifier access_specifier);
/**
* @brief Generate full qualified name for @link clang::TagDecl instance
* @brief Generate full qualified name for
* [clang::TagDecl](https://clang.llvm.org/doxygen/classclang_1_1TagDecl.html)
* instance
*
* @param declaration Input declaration
* @return String representation including any templates, parameters and
* attribtues
* attribtues
*/
std::string get_tag_name(const clang::TagDecl &declaration);
/**
* @brief Get qualified name of some Clang declaration
*
* This template is convenient for getting qualified name of various types of
* clang declarations.
*
* @tparam T Type of Clang's declaration, e.g. `clang::TagDecl`
* @param declaration Reference to a clang declaration
* @return Fully qualified name
*/
template <typename T> std::string get_qualified_name(const T &declaration)
{
auto qualified_name = declaration.getQualifiedNameAsString();
@@ -70,8 +82,20 @@ template <typename T> std::string get_qualified_name(const T &declaration)
return qualified_name;
}
/**
* Get namespace of a specific `clang::TagDecl`
*
* @param declaration Reference to clang::TagDecl
* @return Namespace instance
*/
model::namespace_ get_tag_namespace(const clang::TagDecl &declaration);
/**
* Get namespace of a specific `clang::TemplateDecl`
*
* @param declaration Reference to clang::TemplateDecl
* @return Namespace instance
*/
model::namespace_ get_template_namespace(
const clang::TemplateDecl &declaration);
@@ -94,12 +118,35 @@ std::string to_string(const clang::TypeConstraint *tc);
std::string to_string(const clang::TemplateName &templ);
/**
* @brief Get raw text of specific source range
*
* @param range Source range
* @param sm Source manager reference
* @return Raw source text
*/
std::string get_source_text_raw(
clang::SourceRange range, const clang::SourceManager &sm);
/**
* @brief Get printable range of text of specific source range
*
* @param range Source range
* @param sm Source manager reference
* @return Printable source text
*/
std::string get_source_text(
clang::SourceRange range, const clang::SourceManager &sm);
/**
* @brief Extract template depth and index
*
* This function extracts template depth and index values from Clang's
* `type-parameter-` names.
*
* @param type_parameter Clang's type parameter string
* @return (depth, index, qualifier)
*/
std::tuple<unsigned int, unsigned int, std::string>
extract_template_parameter_index(const std::string &type_parameter);
@@ -115,17 +162,14 @@ extract_template_parameter_index(const std::string &type_parameter);
*/
bool is_subexpr_of(const clang::Stmt *parent_stmt, const clang::Stmt *sub_stmt);
/**
* @brief Forward template for convertions to ID from various entities
/** @defgroup to_id Forward template for convertions to ID from various entities
*
* These methods provide the main mechanism for generating globally unique
* identifiers for all elements in the diagrams. The identifiers must be unique
* between different translation units in order for element relationships to
* be properly rendered in diagrams.
*
* @tparam T Type of entity for which ID should be computed
* @param declaration Element (e.g. declaration) for which the ID is needed
* @return Unique ID
* @{
*/
template <typename T> id_t to_id(const T &declaration);
@@ -148,10 +192,25 @@ template <> id_t to_id(const clang::EnumType &type);
template <> id_t to_id(const clang::TemplateSpecializationType &type);
template <> id_t to_id(const std::filesystem::path &type);
/** @} */ // end of to_id
/**
* @brief Split qualified name to namespace and name
*
* @param full_name Fully qualified element name
* @return (namespace, name)
*/
std::pair<common::model::namespace_, std::string> split_ns(
const std::string &full_name);
/**
* @brief Parse unexposed (available as string) template params
*
* @param params String parameters as provided by Clang
* @param ns_resolve Namespace resolver function
* @param depth Current depth in the template specification
* @return Parsed template parameter
*/
std::vector<common::model::template_parameter> parse_unexposed_template_params(
const std::string &params,
const std::function<std::string(const std::string &)> &ns_resolve,
@@ -191,6 +250,17 @@ bool is_type_token(const std::string &t);
clang::QualType dereference(clang::QualType type);
/**
* @brief Extract type context and return raw type
*
* This function removes the context for a type, for example for:
* `std::string const&`
* it will return
* `(std::string, [const&])`
*
* @param type Type to process
* @return (type, [qualifiers])
*/
std::pair<clang::QualType, std::deque<common::model::context>>
consume_type_context(clang::QualType type);

View File

@@ -1,5 +1,5 @@
/**
* src/common/compilation_database.cc
* @file src/common/compilation_database.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -17,7 +17,7 @@
*/
#include "compilation_database.h"
#include "util/error.h"
#include "util/query_driver_output_extractor.h"
namespace clanguml::common {
@@ -31,7 +31,7 @@ compilation_database::auto_detect_from_directory(
cfg.compilation_database_dir(), error_message);
if (!error_message.empty())
throw compilation_database_error(error_message);
throw error::compilation_database_error(error_message);
return std::make_unique<compilation_database>(std::move(res), cfg);
}

View File

@@ -1,5 +1,5 @@
/**
* src/common/compilation_database.h
* @file src/common/compilation_database.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -22,6 +22,7 @@
#include "common/model/template_parameter.h"
#include "config/config.h"
#include "types.h"
#include "util/error.h"
#include "util/util.h"
#include <clang/Frontend/CompilerInstance.h>
@@ -34,10 +35,16 @@
namespace clanguml::common {
class compilation_database_error : public std::runtime_error {
using std::runtime_error::runtime_error;
};
/**
* @brief Custom compilation database class
*
* This class provides custom specialization of Clang's
* [CompilationDatabase](https://clang.llvm.org/doxygen/classclang_1_1tooling_1_1CompilationDatabase.html),
* which provides the possibility of adjusting the compilation flags after
* they have been loaded from the `compile_commands.json` file.
*
* @embed{compilation_database_context_class.svg}
*/
class compilation_database : public clang::tooling::CompilationDatabase {
public:
compilation_database(
@@ -46,19 +53,52 @@ public:
~compilation_database() override = default;
/**
* Loads the compilation database from directory specified on command
* line or in the configuration file.
*
* @param cfg Reference to config instance
* @return Instance of compilation_database.
*/
static std::unique_ptr<compilation_database> auto_detect_from_directory(
const clanguml::config::config &cfg);
/**
* Retrieves and adjusts compilation commands from the database, for
* a given translation unit.
*
* @return List of adjusted compile commands.
*/
std::vector<clang::tooling::CompileCommand> getCompileCommands(
clang::StringRef FilePath) const override;
/**
* Returns all files in the database.
*
* @return List of all files in compilation database.
*/
std::vector<std::string> getAllFiles() const override;
/**
* Retrieves and adjusts all compilation commands from the database.
*
* @return List of adjusted compile commands.
*/
std::vector<clang::tooling::CompileCommand>
getAllCompileCommands() const override;
/**
* Returns reference to clanguml's config instance.
*
* @return Reference to config instance.
*/
const clanguml::config::config &config() const;
/**
* Returns reference to CompilationDatabase as was loaded from file.
*
* @return Reference to CompilationDatabase.
*/
const clang::tooling::CompilationDatabase &base() const;
std::string guess_language_from_filename(const std::string &filename) const;
@@ -67,11 +107,17 @@ private:
void adjust_compilation_database(
std::vector<clang::tooling::CompileCommand> &commands) const;
// Actual instance of the compilation database is stored in here
// The inheritance is just to keep the interface
/*!
* Pointer to the Clang's original compilation database.
*
* Actual instance of the compilation database is stored in here.
* The inheritance is just to keep the interface.
*/
std::unique_ptr<clang::tooling::CompilationDatabase> base_;
// Reference to the clang-uml config
/*!
* Reference to the instance of clanguml config.
*/
const clanguml::config::config &config_;
};

View File

@@ -1,5 +1,5 @@
/**
* src/common/generators/generators.cc
* @file src/common/generators/generators.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -184,32 +184,33 @@ void generate_diagrams(const std::vector<std::string> &diagram_names,
continue;
}
futs.emplace_back(generator_executor.add(
[&od, &generators, &name = name, &diagram = diagram, &indicator,
db = std::ref(*db), translation_units = valid_translation_units,
verbose]() mutable {
try {
if (indicator)
indicator->add_progress_bar(name,
translation_units.size(),
diagram_type_to_color(diagram->type()));
auto generator = [&od, &generators, &name = name, &diagram = diagram,
&indicator, db = std::ref(*db),
translation_units = valid_translation_units,
verbose]() mutable {
try {
if (indicator)
indicator->add_progress_bar(name, translation_units.size(),
diagram_type_to_color(diagram->type()));
generate_diagram(od, name, diagram, db, translation_units,
generators, verbose != 0, [&indicator, &name]() {
if (indicator)
indicator->increment(name);
});
generate_diagram(od, name, diagram, db, translation_units,
generators, verbose != 0, [&indicator, &name]() {
if (indicator)
indicator->increment(name);
});
if (indicator)
indicator->complete(name);
}
catch (std::runtime_error &e) {
if (indicator)
indicator->fail(name);
if (indicator)
indicator->complete(name);
}
catch (std::runtime_error &e) {
if (indicator)
indicator->fail(name);
LOG_ERROR(e.what());
}
}));
LOG_ERROR(e.what());
}
};
futs.emplace_back(generator_executor.add(std::move(generator)));
}
for (auto &fut : futs) {

View File

@@ -1,5 +1,5 @@
/**
* src/common/generators/generators.h
* @file src/common/generators/generators.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -49,8 +49,13 @@
namespace clanguml::common::generators {
// template trait for selecting diagram model type based on diagram config
// type
/** @defgroup diagram_model_t Diagram model selector
*
* Template traits for selecting diagram model type based on diagram config
* type
*
* @{
*/
template <typename DiagramConfig> struct diagram_model_t;
template <> struct diagram_model_t<clanguml::config::class_diagram> {
using type = clanguml::class_diagram::model::diagram;
@@ -64,9 +69,15 @@ template <> struct diagram_model_t<clanguml::config::package_diagram> {
template <> struct diagram_model_t<clanguml::config::include_diagram> {
using type = clanguml::include_diagram::model::diagram;
};
/** @} */
// template trait for selecting diagram visitor type based on diagram config
// type
/** @defgroup diagram_visitor_t Diagram model selector
*
* Template traits for selecting diagram visitor type based on diagram config
* type
*
* @{
*/
template <typename DiagramConfig> struct diagram_visitor_t;
template <> struct diagram_visitor_t<clanguml::config::class_diagram> {
using type = clanguml::class_diagram::visitor::translation_unit_visitor;
@@ -80,16 +91,29 @@ template <> struct diagram_visitor_t<clanguml::config::package_diagram> {
template <> struct diagram_visitor_t<clanguml::config::include_diagram> {
using type = clanguml::include_diagram::visitor::translation_unit_visitor;
};
/** @} */
// template trait for selecting diagram generator type based on diagram config
// type
/** @defgroup diagram_generator_tag Diagram model tags
*
* Tags to determine the generator output file extension
*
* @{
*/
struct plantuml_generator_tag {
inline static const std::string extension = "puml";
};
struct json_generator_tag {
inline static const std::string extension = "json";
};
/** @} */
/** @defgroup diagram_generator_t Diagram generator selector
*
* Tags to determine the generator type based on diagram config type
* and output format
*
* @{
*/
template <typename DiagramConfig, typename GeneratorType>
struct diagram_generator_t;
template <>
@@ -132,14 +156,40 @@ struct diagram_generator_t<clanguml::config::include_diagram,
json_generator_tag> {
using type = clanguml::include_diagram::generators::json::generator;
};
/** @} */
template <typename DiagramConfig> struct diagram_visitor_t;
/**
* @brief Assign translation units to diagrams
*
* This function assigns for each diagram to be generated the list of
* translation units based on it's `glob` pattern if any.
*
* If `diagram_names` is empty, this function processes all diagrams in
* `config`.
*
* @param diagram_names List of diagram names, applies to all if empty
* @param config Reference to config instance
* @param compilation_database_files List of files found in compilation database
* @param translation_units_map Resulting translation units map is stored here
*/
void find_translation_units_for_diagrams(
const std::vector<std::string> &diagram_names,
clanguml::config::config &config,
const std::vector<std::string> &compilation_database_files,
std::map<std::string, std::vector<std::string>> &translation_units_map);
/**
* @brief Specialization of
* [clang::ASTConsumer](https://clang.llvm.org/doxygen/classclang_1_1ASTConsumer.html)
*
* This class provides overriden HandleTranslationUnit() method, which
* calls a translation_unit_visitor for a specific diagram type on
* each translation unit assigned to the diagram.
*
* @tparam DiagramModel Type of diagram_model
* @tparam DiagramConfig Type of diagram_config
* @tparam TranslationUnitVisitor Type of translation_unit_visitor
*/
template <typename DiagramModel, typename DiagramConfig,
typename TranslationUnitVisitor>
class diagram_ast_consumer : public clang::ASTConsumer {
@@ -161,6 +211,17 @@ public:
}
};
/**
* @brief Specialization of
* [clang::ASTFrontendAction](https://clang.llvm.org/doxygen/classclang_1_1ASTFrontendAction.html)
*
* This class overrides the BeginSourceFileAction() and CreateASTConsumer()
* methods to create and setup an appropriate diagram_ast_consumer instance.
*
* @tparam DiagramModel Type of diagram_model
* @tparam DiagramConfig Type of diagram_config
* @tparam TranslationUnitVisitor Type of translation_unit_visitor
*/
template <typename DiagramModel, typename DiagramConfig,
typename DiagramVisitor>
class diagram_fronted_action : public clang::ASTFrontendAction {
@@ -193,6 +254,8 @@ protected:
{
LOG_DBG("Visiting source file: {}", getCurrentFile().str());
// Update progress indicators, if enabled, on each translation
// unit
if (progress_)
progress_();
@@ -216,6 +279,17 @@ private:
std::function<void()> progress_;
};
/**
* @brief Specialization of
* [clang::ASTFrontendAction](https://clang.llvm.org/doxygen/classclang_1_1tooling_1_1FrontendActionFactory.html)
*
* This class overrides the create() method in order to create an instance
* of diagram_frontend_action of appropriate type.
*
* @tparam DiagramModel Type of diagram_model
* @tparam DiagramConfig Type of diagram_config
* @tparam TranslationUnitVisitor Type of translation_unit_visitor
*/
template <typename DiagramModel, typename DiagramConfig,
typename DiagramVisitor>
class diagram_action_visitor_factory
@@ -241,6 +315,19 @@ private:
std::function<void()> progress_;
};
/**
* @brief Specialization of
* [clang::ASTFrontendAction](https://clang.llvm.org/doxygen/classclang_1_1tooling_1_1FrontendActionFactory.html)
*
* This is the entry point function to initiate AST frontend action for a
* specific diagram.
*
* @embed{diagram_generate_generic_sequence.svg}
*
* @tparam DiagramModel Type of diagram_model
* @tparam DiagramConfig Type of diagram_config
* @tparam TranslationUnitVisitor Type of translation_unit_visitor
*/
template <typename DiagramModel, typename DiagramConfig,
typename DiagramVisitor>
std::unique_ptr<DiagramModel> generate(const common::compilation_database &db,
@@ -275,6 +362,17 @@ std::unique_ptr<DiagramModel> generate(const common::compilation_database &db,
return diagram;
}
/**
* @brief Generate a single diagram
*
* @param od Output directory path
* @param name Name of the diagram
* @param diagram Effective diagram configuration
* @param db Reference to compilation database
* @param translation_units List of translation units for the diagram
* @param generators List of generator types to be used for the diagram
* @param verbose Log level
*/
void generate_diagram(const std::string &od, const std::string &name,
std::shared_ptr<clanguml::config::diagram> diagram,
const common::compilation_database &db,
@@ -282,6 +380,19 @@ void generate_diagram(const std::string &od, const std::string &name,
const std::vector<clanguml::common::generator_type_t> &generators,
bool verbose);
/**
* @brief Generate diagrams
*
* @param diagram_names List of diagram names to generate
* @param config Reference to config instance
* @param od Path to output directory
* @param db Reference to compilation database
* @param verbose Log level
* @param thread_count Number of diagrams to be generated in parallel
* @param progress Whether progress indicators should be displayed
* @param generators List of generator types to use for each diagram
* @param translation_units_map Map of translation units for each file
*/
void generate_diagrams(const std::vector<std::string> &diagram_names,
clanguml::config::config &config, const std::string &od,
const common::compilation_database_ptr &db, int verbose,
@@ -290,6 +401,12 @@ void generate_diagrams(const std::vector<std::string> &diagram_names,
const std::map<std::string, std::vector<std::string>>
&translation_units_map);
/**
* @brief Return indicators progress bar color for diagram type
*
* @param diagram_type Diagram type
* @return Progress bar color
*/
indicators::Color diagram_type_to_color(model::diagram_t diagram_type);
} // namespace clanguml::common::generators

View File

@@ -1,5 +1,5 @@
/**
* src/common/generators/json/generator.cc
* @file src/common/generators/json/generator.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*

View File

@@ -1,5 +1,5 @@
/**
* src/common/generators/json/generator.h
* @file src/common/generators/json/generator.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*

View File

@@ -1,5 +1,5 @@
/**
* src/common/generators/nested_element_stack.h
* @file src/common/generators/nested_element_stack.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -38,6 +38,9 @@ public:
current_level_groups_.push_back({});
}
/**
* Switch to next level in the element stack
*/
void enter()
{
if (!is_flat_)
@@ -46,6 +49,9 @@ public:
current_level_groups_.push_back({});
}
/**
* Switch to previous level in the element stack
*/
void leave()
{
if (!is_flat_)
@@ -54,16 +60,30 @@ public:
current_level_groups_.pop_back();
}
/**
* Add element pointer to a specified group at the current level
*/
void group_together(const std::string &group_name, T *e)
{
current_level_groups_[current_level_][group_name].push_back(e);
}
/**
* Get map of element groups at the current level.
*
* @return Reference to element groups.
*/
const std::map<std::string, std::vector<T *>> &get_current_groups()
{
return current_level_groups_.at(current_level_);
}
/**
* Get element group by name - the group must exist at the current level.
*
* @param group_name Element group name
* @return
*/
const std::vector<T *> &get_group(const std::string &group_name)
{
return get_current_groups().at(group_name);

View File

@@ -1,5 +1,5 @@
/**
* src/common/generators/plantuml/generator.h
* @file src/common/generators/plantuml/generator.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*

View File

@@ -1,5 +1,5 @@
/**
* src/common/generators/plantuml/generator.h
* @file src/common/generators/plantuml/generator.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -334,7 +334,7 @@ void generator<C, D>::generate_plantuml_directives(
// Render the directive with template engine first
std::string directive{env().render(std::string_view{d}, context())};
// Now search for alias @A() directives in the text
// Now search for alias `@A()` directives in the text
// (this is deprecated)
std::tuple<std::string, size_t, size_t> alias_match;
while (util::find_element_alias(directive, alias_match)) {

View File

@@ -1,5 +1,5 @@
/**
* src/common/generators/progress_indicator.cc
* @file src/common/generators/progress_indicator.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*

View File

@@ -1,5 +1,5 @@
/**
* src/common/generators/progress_indicator.h
* @file src/common/generators/progress_indicator.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -25,6 +25,9 @@
namespace clanguml::common::generators {
/**
* @brief Container for diagram generation progress indicators
*/
class progress_indicator {
public:
struct progress_state {
@@ -42,15 +45,40 @@ public:
progress_indicator();
/**
* Add a new progress bar to the indicator set
*
* @param name Name (prefix) of the progress bar
* @param max Total number of steps in the progress bar
* @param color Color of the progress bar
*/
void add_progress_bar(
const std::string &name, size_t max, indicators::Color color);
/**
* Increment specified progress bar.
*
* @param name Name of the progress bar
*/
void increment(const std::string &name);
/**
* Stop all the progress bars.
*/
void stop();
/**
* Set specified progress bar as complete.
*
* @param name Name of the progress bar
*/
void complete(const std::string &name);
/**
* Set progress bar as failed.
*
* @param name Name of the progress bar
*/
void fail(const std::string &name);
private:

View File

@@ -1,5 +1,5 @@
/**
* src/class_diagram/model/decorated_element.cc
* @file src/common/model/decorated_element.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -90,4 +90,10 @@ void decorated_element::append(const decorated_element &de)
std::optional<comment_t> decorated_element::comment() const { return comment_; }
void decorated_element::set_comment(const comment_t &c) { comment_ = c; }
std::optional<std::string> decorated_element::doxygen_link() const
{
return std::nullopt;
}
} // namespace clanguml::common::model

View File

@@ -1,5 +1,5 @@
/**
* src/class_diagram/model/decorated_element.h
* @file src/common/model/decorated_element.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -34,28 +34,106 @@ namespace clanguml::common::model {
using comment_t = inja::json;
/**
* @brief Base class for decorated diagram elements
*
* Decorators in `clang-uml` mean that custom `@uml{}` directives can be
* applied to them in the code comments.
*
* @embed{decorated_element_hierarchy_class.svg}
*
* @see clanguml::decorators::decorator
*
*/
class decorated_element {
public:
virtual ~decorated_element() = default;
/**
* Whether this element should be skipped from the diagram.
*
* @return
*/
bool skip() const;
/**
* Whether this relationship should be skipped from the diagram.
*
* @return
*/
bool skip_relationship() const;
/**
* If this element is a member or a method, get relationship decorator
* if any.
*
* @code
* /// @uml{aggregation[0..1:1..5]}
* std::vector<C> ccc;
* @endcode
*
* @return Relationship specified as a decorator on class member.
*/
std::pair<relationship_t, std::string> get_relationship() const;
/**
* Get stype specification for this element, if any.
*
* @code
* /// @uml{style[#back:lightgreen|yellow;header:blue/red]}
* class A { };
* @endcode
*
* @return
*/
std::string style_spec() const;
/**
* Get all decorators for this element.
*
* @return List of decorator pointers.
*/
const std::vector<std::shared_ptr<decorators::decorator>> &
decorators() const;
/**
* Add decorators to the element.
*
* @param decorators List of decorator pointers.
*/
void add_decorators(
const std::vector<std::shared_ptr<decorators::decorator>> &decorators);
/**
* Append decorators from another element.
*
* @param de Source element to copy decorators from.
*/
void append(const decorated_element &de);
/**
* Get entire comment model for this element.
*
* @return Comment model.
*/
std::optional<comment_t> comment() const;
/**
* Set comment model for this element.
*
* Comment model is currently a JSON object.
*
* @param c Comment model.
*/
void set_comment(const comment_t &c);
/**
* Return Doxygen HTML documentation link for the element.
*
* @return Element context.
*/
virtual std::optional<std::string> doxygen_link() const;
private:
std::vector<std::shared_ptr<decorators::decorator>> decorators_;
std::optional<comment_t> comment_;

View File

@@ -1,5 +1,5 @@
/**
* src/common/model/diagram.cc
* @file src/common/model/diagram.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -68,12 +68,12 @@ bool diagram::should_include(const element &e) const
filter_->should_include(dynamic_cast<const source_location &>(e));
}
bool diagram::should_include(const std::string &name) const
bool diagram::should_include(const namespace_ &ns) const
{
if (filter_.get() == nullptr)
return true;
return filter_->should_include(name);
return filter_->should_include(ns);
}
bool diagram::should_include(const relationship_t r) const

View File

@@ -1,5 +1,5 @@
/**
* src/common/model/diagram.h
* @file src/common/model/diagram.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -31,22 +31,49 @@ class diagram_filter;
class element;
class relationship;
/**
* @brief Base class for all diagram models
*
* @embed{diagram_hierarchy_class.svg}
*/
class diagram {
public:
diagram();
virtual ~diagram();
/**
* @brief Return type of the diagram.
*
* @return Type of diagram
*/
virtual diagram_t type() const = 0;
/**
* Return optional reference to a diagram_element by name.
*
* @param full_name Fully qualified name of a diagram element.
* @return Optional reference to a diagram element.
*/
virtual opt_ref<clanguml::common::model::diagram_element> get(
const std::string &full_name) const = 0;
/**
* Return optional reference to a diagram_element by id.
*
* @param id Id of a diagram element.
* @return Optional reference to a diagram element.
*/
virtual common::optional_ref<clanguml::common::model::diagram_element> get(
diagram_element::id_t id) const = 0;
/// \brief Find element in diagram which can have full name or be
/// relative to ns
/**
* Return optional reference to a diagram_element by name and namespace.
*
* @param name Name of the diagram element (e.g. a class name)
* @param ns Namespace of the element.
* @return Optional reference to a diagram element.
*/
virtual common::optional_ref<clanguml::common::model::diagram_element>
get_with_namespace(const std::string &name, const namespace_ &ns) const;
@@ -55,22 +82,63 @@ public:
diagram &operator=(const diagram &) = delete;
diagram &operator=(diagram && /*unused*/) noexcept;
/**
* Set diagram name.
*
* @param name Name of the diagram.
*/
void set_name(const std::string &name);
/**
* Return the name of the diagram.
*
* @return Name of the diagram.
*/
std::string name() const;
/**
* Set diagram filter for this diagram.
*
* @param filter diagram_filter instance
*
* @see clanguml::common::model::diagram_filter
*/
void set_filter(std::unique_ptr<diagram_filter> filter);
/**
* Get diagram filter
*
* @return Reference to the diagrams element filter
*/
const diagram_filter &filter() const { return *filter_; }
/**
* @brief Set diagram in a complete state.
*
* This must be called after the diagram's 'translation_unit_visitor' has
* completed for all translation units, in order to apply filters which can
* only work after the diagram is complete.
*
* @param complete Status of diagram visitor completion.
*/
void set_complete(bool complete);
/**
* Whether the diagram is complete.
*
* @return Diagram completion status.
*/
bool complete() const;
// TODO: refactor to a template method
bool should_include(const element &e) const;
bool should_include(const std::string &e) const;
bool should_include(const namespace_ &ns) const;
bool should_include(const source_file &path) const;
bool should_include(relationship r) const;
bool should_include(relationship_t r) const;
bool should_include(access_t s) const;
// Disallow std::string overload
bool should_include(const std::string &s) const = delete;
virtual bool has_element(const diagram_element::id_t /*id*/) const
{
@@ -80,6 +148,11 @@ public:
virtual bool should_include(
const namespace_ &ns, const std::string &name) const;
/**
* Return diagrams JSON context for inja templates.
*
* @return JSON context.
*/
virtual inja::json context() const = 0;
private:

View File

@@ -1,5 +1,5 @@
/**
* src/common/model/diagram_element.cc
* @file src/common/model/diagram_element.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -73,8 +73,12 @@ inja::json diagram_element::context() const
{
inja::json ctx;
ctx["name"] = name();
ctx["type"] = type_name();
ctx["alias"] = alias();
ctx["full_name"] = full_name(false);
auto maybe_doxygen_link = doxygen_link();
if (maybe_doxygen_link)
ctx["doxygen_link"] = maybe_doxygen_link.value();
return ctx;
}

View File

@@ -31,34 +31,105 @@
namespace clanguml::common::model {
/**
* @brief Base class for standalone diagram elements.
*
* This is a base cass of any standalone elements such as classes, structs,
* concepts, packages and so on participants and so on.
*/
class diagram_element : public decorated_element, public source_location {
public:
using id_t = int64_t;
diagram_element();
virtual ~diagram_element() = default;
~diagram_element() override = default;
/**
* @brief Returns diagram element id.
*
* Each element in the diagram is uniquely identified by id. The id
* is currently calculated from the full string representation of the
* element, in order to be uniquely identifiable among multiple translation
* units.
*
* @return Elements id.
*/
id_t id() const;
/**
* Set elements id.
*
* @param id Elements id.
*/
void set_id(id_t id);
/**
* @brief Return elements' diagram alias.
*
* @todo This is a PlantUML specific method - it shouldn't be here.
*
* @return PlantUML's diagram element alias.
*/
virtual std::string alias() const;
/**
* Set diagram elements name.
*
* @param name Elements name.
*/
void set_name(const std::string &name) { name_ = name; }
/**
* Return diagram's name.
*
* @return Diagram's name.
*/
std::string name() const { return name_; }
/**
* Return the type name of the diagram.
*
* @return Diagrams type name.
*/
virtual std::string type_name() const { return "__undefined__"; };
/**
* @brief Return the elements fully qualified name.
*
* This method should be implemented in each subclass, and ensure that
* for instance it includes fully qualified namespace, template params, etc.
*
* @return Full elements name.
*/
virtual std::string full_name(bool /*relative*/) const { return name(); }
/**
* Return all relationships outgoing from this element.
*
* @return List of relationships.
*/
std::vector<relationship> &relationships();
/**
* Return all relationships outgoing from this element.
*
* @return List of relationships.
*/
const std::vector<relationship> &relationships() const;
/**
* Add relationships, whose source is this element.
*
* @param cr Relationship to another diagram element.
*/
void add_relationship(relationship &&cr);
/**
* Add element to the diagram.
*
* @param e Diagram element.
*/
void append(const decorated_element &e);
friend bool operator==(const diagram_element &l, const diagram_element &r);
@@ -66,14 +137,39 @@ public:
friend std::ostream &operator<<(
std::ostream &out, const diagram_element &rhs);
/**
* Return elements inja JSON context.
*
* @return Element context.
*/
virtual inja::json context() const;
/**
* Whether this element is nested in another element.
*
* @return
*/
bool is_nested() const;
/**
* Set element's nested status.
*
* @param nested
*/
void nested(bool nested);
/**
* Returns the diagrams completion status.
*
* @return Whether the diagram is complete.
*/
bool complete() const;
/**
* Set the diagrams completion status.
*
* @param completed
*/
void complete(bool completed);
private:

View File

@@ -1,5 +1,5 @@
/**
* src/common/model/diagram_filter.cc
* @file src/common/model/diagram_filter.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -186,60 +186,100 @@ tvl::value_t namespace_filter::match(
if (ns.is_empty())
return {};
return tvl::any_of(
namespaces_.begin(), namespaces_.end(), [&ns](const auto &nsit) {
return tvl::any_of(namespaces_.begin(), namespaces_.end(),
[&ns, is_inclusive = is_inclusive()](const auto &nsit) {
if (std::holds_alternative<namespace_>(nsit.value())) {
const auto &ns_pattern = std::get<namespace_>(nsit.value());
return ns.starts_with(ns_pattern) || ns == ns_pattern;
if (is_inclusive)
return ns.starts_with(ns_pattern) ||
ns_pattern.starts_with(ns);
return ns.starts_with(ns_pattern);
}
const auto &regex = std::get<common::regex>(nsit.value());
return regex == ns.to_string();
return regex %= ns.to_string();
});
}
tvl::value_t namespace_filter::match(
const diagram & /*d*/, const element &e) const
tvl::value_t namespace_filter::match(const diagram &d, const element &e) const
{
if (dynamic_cast<const package *>(&e) != nullptr) {
return tvl::any_of(namespaces_.begin(), namespaces_.end(),
if (d.type() != diagram_t::kPackage &&
dynamic_cast<const package *>(&e) != nullptr) {
auto result = tvl::any_of(namespaces_.begin(), namespaces_.end(),
[&e, is_inclusive = is_inclusive()](const auto &nsit) {
if (std::holds_alternative<namespace_>(nsit.value())) {
const auto &ns_pattern = std::get<namespace_>(nsit.value());
auto element_full_name_starts_with_namespace =
(e.get_namespace() | e.name()).starts_with(ns_pattern);
namespace_{e.name_and_ns()}.starts_with(ns_pattern);
auto element_full_name_equals_pattern =
(e.get_namespace() | e.name()) == ns_pattern;
namespace_{e.name_and_ns()} == ns_pattern;
auto namespace_starts_with_element_qualified_name =
ns_pattern.starts_with(e.get_namespace());
auto pattern_starts_with_element_full_name =
ns_pattern.starts_with(namespace_{e.name_and_ns()});
auto result = element_full_name_starts_with_namespace ||
element_full_name_equals_pattern;
if (is_inclusive)
result = result ||
namespace_starts_with_element_qualified_name;
result =
result || pattern_starts_with_element_full_name;
return result;
}
return std::get<common::regex>(nsit.value()) ==
return std::get<common::regex>(nsit.value()) %=
e.full_name(false);
});
if (tvl::is_false(result))
LOG_DBG("Element {} rejected by namespace_filter 1",
e.full_name(false));
return result;
}
return tvl::any_of(
if (d.type() == diagram_t::kPackage) {
auto result = tvl::any_of(namespaces_.begin(), namespaces_.end(),
[&e, is_inclusive = is_inclusive()](const auto &nsit) {
if (std::holds_alternative<namespace_>(nsit.value())) {
auto e_ns = namespace_{e.full_name(false)};
auto nsit_ns = std::get<namespace_>(nsit.value());
if (is_inclusive)
return e_ns.starts_with(nsit_ns) ||
nsit_ns.starts_with(e_ns) || e_ns == nsit_ns;
return e_ns.starts_with(nsit_ns) || e_ns == nsit_ns;
}
return std::get<common::regex>(nsit.value()) %=
e.full_name(false);
});
if (tvl::is_false(result))
LOG_DBG("Element {} rejected by namespace_filter (package diagram)",
e.full_name(false));
return result;
}
auto result = tvl::any_of(
namespaces_.begin(), namespaces_.end(), [&e](const auto &nsit) {
if (std::holds_alternative<namespace_>(nsit.value())) {
return e.get_namespace().starts_with(
std::get<namespace_>(nsit.value()));
}
return std::get<common::regex>(nsit.value()) == e.full_name(false);
return std::get<common::regex>(nsit.value()) %= e.full_name(false);
});
if (tvl::is_false(result))
LOG_DBG("Element {} rejected by namespace_filter", e.full_name(false));
return result;
}
element_filter::element_filter(
@@ -249,9 +289,12 @@ element_filter::element_filter(
{
}
tvl::value_t element_filter::match(
const diagram & /*d*/, const element &e) const
tvl::value_t element_filter::match(const diagram &d, const element &e) const
{
// Do not apply element filter to packages in class diagrams
if (d.type() == diagram_t::kClass && e.type_name() == "package")
return std::nullopt;
return tvl::any_of(
elements_.begin(), elements_.end(), [&e](const auto &el) {
return ((el == e.full_name(false)) ||

View File

@@ -1,5 +1,5 @@
/**
* src/common/model/diagram_filter.h
* @file src/common/model/diagram_filter.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -36,7 +36,15 @@
namespace clanguml::common::model {
enum filter_t { kInclusive, kExclusive };
/**
* Diagram filters can be add in 2 modes:
* - inclusive - the elements that match are included in the diagram
* - exclusive - the elements that match are excluded from the diagram
*/
enum class filter_t {
kInclusive, /*!< Filter is inclusive */
kExclusive /*!< Filter is exclusve */
};
namespace detail {
template <typename ElementT, typename DiagramT>
@@ -56,6 +64,16 @@ clanguml::common::id_t destination_comparator(
const common::model::source_file &f);
} // namespace detail
/**
* @brief Base class for any diagram filter.
*
* This class acts as a visitor for diagram elements. It provides a set of
* common methods which can be overriden by specific filters. If a filter
* does not implement a specific method, it is ignored through the 3 value
* logic implemented in @see clanguml::common::model::tvl
*
* @embed{filter_visitor_hierarchy_class.svg}
*/
class filter_visitor {
public:
filter_visitor(filter_t type);
@@ -111,6 +129,10 @@ private:
std::vector<std::unique_ptr<filter_visitor>> filters_;
};
/**
* Match namespace or diagram element to a set of specified namespaces or
* regex patterns.
*/
struct namespace_filter : public filter_visitor {
namespace_filter(
filter_t type, std::vector<common::namespace_or_regex> namespaces);
@@ -125,6 +147,9 @@ private:
std::vector<common::namespace_or_regex> namespaces_;
};
/**
* Match element's name to a set of names or regex patterns.
*/
struct element_filter : public filter_visitor {
element_filter(
filter_t type, std::vector<common::string_or_regex> elements);
@@ -137,6 +162,9 @@ private:
std::vector<common::string_or_regex> elements_;
};
/**
* Match diagram elements based on elements type (e.g. class).
*/
struct element_type_filter : public filter_visitor {
element_type_filter(filter_t type, std::vector<std::string> element_types);
@@ -148,6 +176,9 @@ private:
std::vector<std::string> element_types_;
};
/**
* Match class methods based on their category (e.g. operator).
*/
struct method_type_filter : public filter_visitor {
method_type_filter(
filter_t type, std::vector<config::method_type> method_types);
@@ -161,6 +192,10 @@ private:
std::vector<config::method_type> method_types_;
};
/**
* Match element based on whether it is a subclass of a set of base classes,
* or one of them.
*/
struct subclass_filter : public filter_visitor {
subclass_filter(filter_t type, std::vector<common::string_or_regex> roots);
@@ -172,6 +207,10 @@ private:
std::vector<common::string_or_regex> roots_;
};
/**
* Match element based on whether it is a parent of a set of children, or one
* of them.
*/
struct parents_filter : public filter_visitor {
parents_filter(filter_t type, std::vector<common::string_or_regex> roots);
@@ -183,6 +222,20 @@ private:
std::vector<common::string_or_regex> children_;
};
/**
* @brief Common template for filters involving traversing relationship graph.
*
* This class template provides a common implementation of a diagram
* relationship graph traversal. It is used for filters, which need to check
* for instance, whether an element is in some kind of relationship with other
* element.
*
* @tparam DiagramT Diagram type
* @tparam ElementT Element type
* @tparam ConfigEntryT Type of configuration option used to specify initial
* elements for traversal
* @tparam MatchOverrideT Type of the matched element
*/
template <typename DiagramT, typename ElementT,
typename ConfigEntryT = std::string,
typename MatchOverrideT = common::model::element>
@@ -337,6 +390,9 @@ private:
bool forward_;
};
/**
* Match relationship types.
*/
struct relationship_filter : public filter_visitor {
relationship_filter(
filter_t type, std::vector<relationship_t> relationships);
@@ -350,6 +406,9 @@ private:
std::vector<relationship_t> relationships_;
};
/**
* Match class members and methods based on access (public, protected, private).
*/
struct access_filter : public filter_visitor {
access_filter(filter_t type, std::vector<access_t> access);
@@ -361,6 +420,10 @@ private:
std::vector<access_t> access_;
};
/**
* Match diagram elements which are in direct relationship to any of the
* elements specified in context.
*/
struct context_filter : public filter_visitor {
context_filter(filter_t type, std::vector<common::string_or_regex> context);
@@ -372,6 +435,10 @@ private:
std::vector<common::string_or_regex> context_;
};
/**
* Match elements based on their source location, whether it matches to
* a specified file paths.
*/
struct paths_filter : public filter_visitor {
paths_filter(filter_t type, const std::filesystem::path &root,
const std::vector<std::string> &p);
@@ -389,6 +456,9 @@ private:
std::filesystem::path root_;
};
/**
* Match class method based on specified method categories.
*/
struct class_method_filter : public filter_visitor {
class_method_filter(filter_t type, std::unique_ptr<access_filter> af,
std::unique_ptr<method_type_filter> mtf);
@@ -403,6 +473,9 @@ private:
std::unique_ptr<method_type_filter> method_type_filter_;
};
/**
* Match class members.
*/
struct class_member_filter : public filter_visitor {
class_member_filter(filter_t type, std::unique_ptr<access_filter> af);
@@ -415,16 +488,49 @@ private:
std::unique_ptr<access_filter> access_filter_;
};
/**
* @brief Composite of all diagrams filters.
*
* Instances of this class contain all filters specified in configuration file
* for a given diagram.
*
* @embed{diagram_filter_context_class.svg}
*
* @see clanguml::common::model::filter_visitor
*/
class diagram_filter {
public:
diagram_filter(const common::model::diagram &d, const config::diagram &c);
/**
* Add inclusive filter.
*
* @param fv Filter visitor.
*/
void add_inclusive_filter(std::unique_ptr<filter_visitor> fv);
/** Add exclusive filter.
*
* @param fv Filter visitor.
*/
void add_exclusive_filter(std::unique_ptr<filter_visitor> fv);
/**
* `should_include` overload for namespace and name.
*
* @param ns Namespace
* @param name Name
* @return Match result.
*/
bool should_include(const namespace_ &ns, const std::string &name) const;
/**
* Generic `should_include` overload for various diagram elements.
*
* @tparam T Type to to match - must match one of filter_visitor's match(T)
* @param e Value of type T to match
* @return Match result.
*/
template <typename T> bool should_include(const T &e) const
{
auto exc = tvl::any_of(exclusive_.begin(), exclusive_.end(),
@@ -440,11 +546,22 @@ public:
}
private:
/**
* @brief Initialize filters.
*
* Some filters require initialization.
*
* @param c Diagram config.
*/
void init_filters(const config::diagram &c);
/*! List of inclusive filters */
std::vector<std::unique_ptr<filter_visitor>> inclusive_;
/*! List of exclusive filters */
std::vector<std::unique_ptr<filter_visitor>> exclusive_;
/*! Reference to the diagram model */
const common::model::diagram &diagram_;
};

View File

@@ -1,5 +1,5 @@
/**
* src/common/model/element.cc
* @file src/common/model/element.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -34,11 +34,7 @@ const namespace_ &element::using_namespace() const { return using_namespace_; }
inja::json element::context() const
{
inja::json ctx;
ctx["name"] = name();
ctx["type"] = type_name();
ctx["alias"] = alias();
ctx["full_name"] = full_name(false);
inja::json ctx = diagram_element::context();
ctx["namespace"] = get_namespace().to_string();
if (const auto maybe_comment = comment(); maybe_comment.has_value()) {
ctx["comment"] = maybe_comment.value();

View File

@@ -1,5 +1,5 @@
/**
* src/common/model/element.h
* @file src/common/model/element.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -32,36 +32,83 @@
namespace clanguml::common::model {
/**
* @brief Base class for any element qualified by namespace.
*/
class element : public diagram_element {
public:
element(namespace_ using_namespace);
~element() override = default;
/**
* Return the elements fully qualified name, but without template
* arguments or function params.
*
* @return Fully qualified element name.
*/
std::string name_and_ns() const
{
auto ns = ns_ | name();
return ns.to_string();
}
/**
* Set elements namespace.
*
* @param ns Namespace.
*/
void set_namespace(const namespace_ &ns) { ns_ = ns; }
/**
* Return elements namespace.
*
* @return Namespace.
*/
namespace_ get_namespace() const { return ns_; }
/**
* Return elements relative namespace.
*
* @return Namespace.
*/
namespace_ get_relative_namespace() const
{
return ns_.relative_to(using_namespace_);
}
/**
* Return elements namespace as path.
*
* Namespace is a nested path in diagrams where packages are generated
* from namespaces.
*
* @return Namespace.
*/
const namespace_ &path() const { return ns_; }
/**
* Return elements full name.
*
* @return Fully qualified elements name.
*/
std::string full_name(bool /*relative*/) const override
{
return name_and_ns();
}
/**
* Return elements full name but without namespace.
*
* @return Elements full name without namespace.
*/
virtual std::string full_name_no_ns() const { return name(); }
/**
* Return the relative namespace from config.
*
* @return Namespace.
*/
const namespace_ &using_namespace() const;
friend bool operator==(const element &l, const element &r);

View File

@@ -1,5 +1,5 @@
/**
* src/common/model/element_view.h
* @file src/common/model/element_view.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*

View File

@@ -1,5 +1,5 @@
/**
* src/common/model/enums.cc
* @file src/common/model/enums.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*

View File

@@ -1,5 +1,5 @@
/**
* src/common/model/enums.h
* @file src/common/model/enums.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*

View File

@@ -1,5 +1,5 @@
/**
* src/common/model/namespace.cc
* @file src/common/model/namespace.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*

View File

@@ -1,5 +1,5 @@
/**
* src/common/model/namespace.h
* @file src/common/model/namespace.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*

View File

@@ -1,5 +1,5 @@
/**
* src/common/model/nested_trait.h
* @file src/common/model/nested_trait.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -25,6 +25,18 @@
#include <vector>
namespace clanguml::common::model {
/**
* @brief Base class for elements nested in the diagram.
*
* This class provides a common trait for diagram elements which can contain
* other nested elements, e.g. packages.
*
* @embed{nested_trait_hierarchy_class.svg}
*
* @tparam T Type of element
* @tparam Path Type of nested path (e.g. namespace or directory path)
*/
template <typename T, typename Path> class nested_trait {
public:
nested_trait() = default;
@@ -37,6 +49,13 @@ public:
virtual ~nested_trait() = default;
/**
* Add element at the current nested level.
*
* @tparam V Type of element
* @param p Element
* @return True, if element was added.
*/
template <typename V = T>
[[nodiscard]] bool add_element(std::unique_ptr<V> p)
{
@@ -53,6 +72,14 @@ public:
return true;
}
/**
* Add element at a nested path.
*
* @tparam V Type of element
* @param path Nested path (e.g. list of namespaces)
* @param p Element
* @return True, if element was added.
*/
template <typename V = T>
bool add_element(const Path &path, std::unique_ptr<V> p)
{
@@ -77,6 +104,13 @@ public:
"No parent element found for " + path.to_string());
}
/**
* Get element at path, if exists.
*
* @tparam V Element type.
* @param path Path to the element.
* @return Optional reference to the element.
*/
template <typename V = T> auto get_element(const Path &path) const
{
if (path.is_empty() || !has_element(path[0])) {
@@ -100,18 +134,13 @@ public:
return optional_ref<V>{};
}
template <typename V = T> auto get_element_parent(const T &element) const
{
auto path = element.path();
auto parent = get_element(path);
if (parent.has_value())
return optional_ref<V>{
std::ref<V>(dynamic_cast<V &>(parent.value()))};
return optional_ref<V>{};
}
/**
* Get element by name at the current nested level.
*
* @tparam V Type of element.
* @param name Name of the element (cannot contain namespace or path)
* @return Optional reference to the element.
*/
template <typename V = T> auto get_element(const std::string &name) const
{
assert(!util::contains(name, "::"));
@@ -130,6 +159,13 @@ public:
return optional_ref<V>{};
}
/**
* Returns true of this nested level contains an element with specified
* name.
*
* @param name Name of the element.
* @return True if element exists.
*/
bool has_element(const std::string &name) const
{
return std::find_if(elements_.cbegin(), elements_.cend(),
@@ -137,6 +173,12 @@ public:
elements_.end();
}
/**
* Return result of functor f applied to all_of elements.
* @tparam F Functor type
* @param f Functor value
* @return True, if functor return true for elements, including nested ones.
*/
template <typename F> bool all_of(F &&f) const
{
return std::all_of(
@@ -151,6 +193,11 @@ public:
});
}
/**
* Check if nested element is empty.
*
* @return True if this nested element is empty.
*/
bool is_empty() const
{
return elements_.empty() ||
@@ -170,6 +217,13 @@ public:
auto begin() const { return elements_.begin(); }
auto end() const { return elements_.end(); }
/**
* Print the nested trait in the form of a tree.
*
* This method is used for debugging only.
*
* @param level Tree level
*/
void print_tree(const int level)
{
const auto &d = *this;

View File

@@ -1,5 +1,5 @@
/**
* src/common/model/package.cc
* @file src/common/model/package.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -40,4 +40,11 @@ bool package::is_deprecated() const { return is_deprecated_; }
void package::set_deprecated(bool deprecated) { is_deprecated_ = deprecated; }
std::optional<std::string> package::doxygen_link() const
{
auto name = full_name(false);
util::replace_all(name, "_", "__");
util::replace_all(name, "::", "_1_1");
return fmt::format("namespace{}.html", name);
}
} // namespace clanguml::common::model

View File

@@ -1,5 +1,5 @@
/**
* src/common/model/package.h
* @file src/common/model/package.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -32,6 +32,11 @@
namespace clanguml::common::model {
/**
* @brief Diagram element representing namespace or directory package
*
* @embed{package_hierarchy_class.svg}
*/
class package : public element,
public stylable_element,
public nested_trait<element, path> {
@@ -47,11 +52,29 @@ public:
std::string full_name(bool relative) const override;
/**
* Returns whether the namespace is deprecated.
*
* @return True, if namespace is deprecated.
*/
bool is_deprecated() const;
/**
* Set namespace deprecation status.
*
* @param deprecated True, if namespace is deprecated
*/
void set_deprecated(bool deprecated);
void add_package(std::unique_ptr<common::model::package> &&p);
/**
* @brief Generate Doxygen style HTML link for the class.
*
* This method generates a link, which can be used in SVG diagrams to
* create links from classes to Doxygen documentation pages.
*
* @return Doxygen-style HTML link for the class.
*/
std::optional<std::string> doxygen_link() const override;
private:
bool is_deprecated_{false};

View File

@@ -1,5 +1,5 @@
/**
* src/common/model/path.h
* @file src/common/model/path.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -25,10 +25,30 @@
namespace clanguml::common::model {
enum class path_type { kNamespace, kFilesystem };
/**
* @brief Type of diagram path
*
* Paths in diagrams represent the nest structure within a diagram, e.g.
* a nested set of namespaces or nested set of directories.
*/
enum class path_type {
kNamespace, /*!< Namespace path */
kFilesystem /*!< Filesystem path */
};
/**
* @brief Diagram path
*
* This class stores a diagram path, such as a namespace or directory
* structure.
*/
class path {
/**
* Returns the path separator based on the path type.
*
* @return Path separator
*/
const char *separator() const
{
switch (path_type_) {
@@ -133,15 +153,36 @@ public:
return left.to_string() < right.to_string();
}
/**
* Render the path as string.
*
* @return String representation of the path.
*/
std::string to_string() const
{
return fmt::format("{}", fmt::join(path_, std::string{separator()}));
}
/**
* Whether the path is empty.
*
* @return
*/
bool is_empty() const { return path_.empty(); }
/**
* Return the number of elements in the path.
*
* @return Size of path.
*/
size_t size() const { return path_.size(); }
/**
* Append path to path.
*
* @param right Path to append at the end.
* @return New merged path.
*/
path operator|(const path &right) const
{
path res{*this};
@@ -149,8 +190,18 @@ public:
return res;
}
/**
* Append path to the current path.
*
* @param right
*/
void operator|=(const path &right) { append(right); }
/**
* Append path element to path.
*
* @return New path.
*/
path operator|(const std::string &right) const
{
path res{*this};
@@ -158,6 +209,11 @@ public:
return res;
}
/**
* Append path element to the current path.
*
* @param right Path element to append.
*/
void operator|=(const std::string &right) { append(right); }
std::string &operator[](const unsigned int index) { return path_[index]; }
@@ -167,8 +223,18 @@ public:
return path_[index];
}
void append(const std::string &ns) { path_.push_back(ns); }
/**
* Append path element to path.
*
* @return New path.
*/
void append(const std::string &name) { path_.push_back(name); }
/**
* Append path to current path.
*
* @param ns Path to append.
*/
void append(const path &ns)
{
for (const auto &n : ns) {
@@ -176,6 +242,9 @@ public:
}
}
/**
* Drop the last element of the path.
*/
void pop_back()
{
if (!path_.empty()) {
@@ -183,6 +252,11 @@ public:
}
}
/**
* Get the parent of the last element in the path.
*
* @return Path to the parent of the last element, or nullopt.
*/
std::optional<path> parent() const
{
if (size() <= 1) {
@@ -194,16 +268,34 @@ public:
return {std::move(res)};
}
bool starts_with(const path &right) const
/**
* Returns true if path starts with specified prefix.
* @param prefix Path prefix to check.
* @return
*/
bool starts_with(const path &prefix) const
{
return util::starts_with(path_, right.path_);
return util::starts_with(path_, prefix.path_);
}
bool ends_with(const path &right) const
/**
* Returns true if path ends with suffix
* @param suffix Path suffix to check
* @return
*/
bool ends_with(const path &suffix) const
{
return util::ends_with(path_, right.path_);
return util::ends_with(path_, suffix.path_);
}
/**
* @brief Returns the common prefix of 2 paths.
*
* If no common prefix exists between 2 paths, the result is an empty path.
*
* @param right Path to compare
* @return Common path prefix
*/
path common_path(const path &right) const
{
path res{};
@@ -216,6 +308,14 @@ public:
return res;
}
/**
* Make the current path relative to the other path, if possible.
*
* If not, return the original path.
*
* @param right Parent path
* @return Path relative to `right`
*/
path relative_to(const path &right) const
{
path res{*this};
@@ -226,15 +326,21 @@ public:
return res;
}
std::string relative(const std::string &name) const
/**
* Make path represented as a string relative to the current path.
*
* @param ns Path to make relative against *this.
* @return Relative path.
*/
std::string relative(const std::string &ns) const
{
if (is_empty())
return name;
return ns;
if (name == to_string())
return name;
if (ns == to_string())
return ns;
auto res = name;
auto res = ns;
auto ns_prefix = to_string() + std::string{separator()};
auto it = res.find(ns_prefix);
@@ -246,6 +352,11 @@ public:
return res;
}
/**
* Return the name of the last element in the path.
*
* @return Name of the last element in the path.
*/
std::string name() const
{
assert(size() > 0);
@@ -265,6 +376,11 @@ public:
path::container_type::const_iterator begin() const { return path_.begin(); }
path::container_type::const_iterator end() const { return path_.end(); }
/**
* Get path type.
*
* @return Path type.
*/
path_type type() const { return path_type_; }
private:

View File

@@ -1,5 +1,5 @@
/**
* src/common/model/relationship.cc
* @file src/common/model/relationship.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*

View File

@@ -1,5 +1,5 @@
/**
* src/common/model/relationship.h
* @file src/common/model/relationship.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -25,33 +25,119 @@
namespace clanguml::common::model {
/**
* @brief Class representing any relationship other than inheritance
*
* This class represents all kinds of relationships between diagram elements,
* except for inheritance which are handled in a special way
* (See @ref clanguml::class_diagram::model::class_parent).
*
* @embed{relationship_context_class.svg}
*/
class relationship : public common::model::decorated_element,
public common::model::stylable_element {
public:
/**
* Constructor.
*
* @param type Type of relationship
* @param destination Id of the relationship target
* @param access Access scope of the relationship
* @param label Relationship label
* @param multiplicity_source Multiplicity at the source
* @param multiplicity_destination Multiplicity at the destination
*/
relationship(relationship_t type, int64_t destination,
access_t access = access_t::kPublic, std::string label = "",
std::string multiplicity_source = "",
std::string multiplicity_destination = "");
virtual ~relationship() = default;
~relationship() override = default;
/**
* Set the type of relatinoship.
*
* @param type Type of relationship.
*/
void set_type(relationship_t type) noexcept;
/**
* Get the type of relatinoship.
*
* @return Type of relationship.
*/
relationship_t type() const noexcept;
/**
* Set id of the diagram element which is the target of this
* relationship.
*
* @param destination Target element id.
*/
void set_destination(int64_t destination);
/**
* Get the id of the target element of this relationship.
*
* @return Target element id.
*/
clanguml::common::id_t destination() const;
/**
* Set the relationship multiplicity at the source.
*
* @param multiplicity_source Source multiplicity.
*/
void set_multiplicity_source(const std::string &multiplicity_source);
/**
* Set the relationship multiplicity at the source.
*
* @return Source multiplicity.
*/
std::string multiplicity_source() const;
/**
* Set the relationship multiplicity at the destination.
*
* @param multiplicity_destination Destination multiplicity.
*/
void set_multiplicity_destination(
const std::string &multiplicity_destination);
/**
* Set the relationship multiplicity at the destination.
*
* @return Destination multiplicity.
*/
std::string multiplicity_destination() const;
/**
* Set relationship label.
*
* @param label Relationship label.
*/
void set_label(const std::string &label);
/**
* Get the relationship label.
*
* @return Relationoship label.
*/
std::string label() const;
/**
* Set the access scope for this relationship (e.g `public`)
*
* @param scope Access scope
*/
void set_access(access_t scope) noexcept;
/**
* Get the relationship access scope (e.g. `public`).
*
* @return Access scope
*/
access_t access() const noexcept;
friend bool operator==(const relationship &l, const relationship &r);

View File

@@ -1,5 +1,5 @@
/**
* src/common/model/source_file.cc
* @file src/common/model/source_file.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*

View File

@@ -1,5 +1,5 @@
/**
* src/common/model/source_file.h
* @file src/common/model/source_file.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -34,7 +34,14 @@
namespace clanguml::common::model {
enum class source_file_t { kDirectory, kHeader, kImplementation };
/**
* This enum represents different kinds of files in the diagram.
*/
enum class source_file_t {
kDirectory, /*!< Diagram element is a directory */
kHeader, /*!< Diagram element is a header */
kImplementation /*!< Diagram element is a source file (e.g. cpp) */
};
std::string to_string(source_file_t sf);
@@ -48,6 +55,11 @@ struct fs_path_sep {
using filesystem_path = common::model::path;
/**
* @brief Diagram element representing some file or directory.
*
* @embed{source_file_hierarchy_class.svg}
*/
class source_file
: public common::model::diagram_element,
public common::model::stylable_element,
@@ -66,16 +78,6 @@ public:
set_id(common::to_id(preferred));
}
void set_path(const filesystem_path &p) { path_ = p; }
void set_absolute() { is_absolute_ = true; }
bool is_absolute() const { return is_absolute_; }
void set_type(source_file_t type) { type_ = type; }
source_file_t type() const { return type_; }
source_file(const source_file &) = delete;
source_file(source_file &&) = default;
source_file &operator=(const source_file &) = delete;
@@ -87,15 +89,64 @@ public:
(type_ == right.type_);
}
/**
* Set the path to the element in the diagram.
*
* @param p Diagram path.
*/
void set_path(const filesystem_path &p) { path_ = p; }
/**
* Is the elements path absolute?
*
* @return True if the elements path is absolute.
*/
bool is_absolute() const { return is_absolute_; }
/**
* Set the type of the source file.
*
* @param type Type of the source file.
*/
void set_type(source_file_t type) { type_ = type; }
/**
* Get the source file elements type.
*
* @return Type of the source file.
*/
source_file_t type() const { return type_; }
/**
* Get the source file's parent path.
*
* @return Source file parent path.
*/
const filesystem_path &path() const { return path_; }
/**
* Return the full path string, i.e. parent path and elements name.
*
* @return Full source file path as string.
*/
std::string full_name(bool /*relative*/) const override
{
return (path_ | name()).to_string();
}
/**
* Return full path, i.e. parent path and elements name.
*
* @return Full source file path.
*/
auto full_path() const { return path() | name(); }
/**
* Convert the source file path to std::filesystem::path, relative to `base`
*
* @param base Base path
* @return Filesystem path to the source file.
*/
std::filesystem::path fs_path(const std::filesystem::path &base = {}) const
{
std::filesystem::path res;
@@ -114,6 +165,11 @@ public:
return res.lexically_normal();
}
/**
* Return inja context for this element.
*
* @return Inja context.
*/
inja::json context() const override
{
inja::json ctx = diagram_element::context();

View File

@@ -1,5 +1,5 @@
/**
* src/common/model/source_location.cc
* @file src/common/model/source_location.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*

View File

@@ -1,5 +1,5 @@
/**
* src/common/model/source_location.h
* @file src/common/model/source_location.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -22,6 +22,11 @@
namespace clanguml::common::model {
/**
* @brief Base class of all diagram elements that have source location.
*
* @embed{source_location_hierarchy_class.svg}
*/
class source_location {
public:
source_location() = default;
@@ -32,31 +37,96 @@ public:
{
}
/**
* Return absolute source file path.
*
* @return Absolute file path.
*/
const std::string &file() const { return file_; }
/**
* Set absolute file path.
*
* @param file Absolute file path.
*/
void set_file(const std::string &file) { file_ = file; }
/**
* Return source file path relative to `relative_to` config option.
*
* @return Relative file path.
*/
const std::string &file_relative() const { return file_relative_; }
/**
* Set relative file path.
*
* @param file Relative file path.
*/
void set_file_relative(const std::string &file) { file_relative_ = file; }
/**
* Get the translation unit, from which this source location was visited.
*
* @return Path to the translation unit.
*/
const std::string &translation_unit() const { return translation_unit_; }
/**
* Set the path to translation unit, from which this source location was
* visited.
*
* @param translation_unit Path to the translation unit.
*/
void set_translation_unit(const std::string &translation_unit)
{
translation_unit_ = translation_unit;
}
/**
* Get the source location line number.
*
* @return Line number.
*/
unsigned int line() const { return line_; }
/**
* Set the source location line number.
*
* @param line Line number.
*/
void set_line(const unsigned line) { line_ = line; }
/**
* Get the source location column number.
*
* @return Column number.
*/
unsigned int column() const { return column_; }
/**
* Set the source location column number.
*
* @param line Column number.
*/
void set_column(const unsigned column) { column_ = column; }
/**
* Get the source location id.
*
* The location id is equivalent to Clang's SourceLocation::getHashValue()
*
* @return Location id.
*/
unsigned int location_id() const { return hash_; }
/**
* Set the source location id.
*
* The location id is equivalent to Clang's SourceLocation::getHashValue()
*
* @param h Location id.
*/
void set_location_id(unsigned int h) { hash_ = h; }
private:

View File

@@ -1,5 +1,5 @@
/**
* src/common/model/stylable_element.cc
* @file src/common/model/stylable_element.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*

View File

@@ -1,5 +1,5 @@
/**
* src/common/model/stylable_element.h
* @file src/common/model/stylable_element.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
@@ -21,9 +21,25 @@
namespace clanguml::common::model {
/**
* @brief Diagram elements to which style can be applied.
*
* @embed{stylable_element_hierarchy_class.svg}
*/
class stylable_element {
public:
/**
* Set style.
*
* @param style Style specification
*/
void set_style(const std::string &style);
/**
* Get style
*
* @return Style specification
*/
std::string style() const;
private:

Some files were not shown because too many files have changed in this diff Show More