From d8ef12d1c641f0a2e7e0113c8b508b218c268bb3 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Fri, 23 Jun 2023 19:38:28 +0200 Subject: [PATCH] Added Doxygen documentation --- .clang-uml | 8 +- Makefile | 3 + docs/Makefile | 1 + docs/architecture.md | 200 ++++++ docs/common_options.md | 2 +- docs/doxygen/layout-clang-uml.xml | 21 +- docs/doxygen_integration.md | 50 +- docs/generator_types.md | 697 ++++++++++++++++++++- docs/installation.md | 12 +- docs/package_diagrams.md | 4 +- docs/troubleshooting.md | 34 +- uml/class/architecture_visitors_class.yml | 16 + uml/class/common_model_class.yml | 9 +- uml/class/config_class.yml | 18 +- uml/class/diagram_filter_context_class.yml | 6 +- uml/package/architecture_package.yml | 21 + 16 files changed, 1063 insertions(+), 39 deletions(-) create mode 100644 uml/class/architecture_visitors_class.yml create mode 100644 uml/package/architecture_package.yml diff --git a/.clang-uml b/.clang-uml index 4aee04d6..42c5b3ae 100644 --- a/.clang-uml +++ b/.clang-uml @@ -2,10 +2,12 @@ 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: # Class diagrams + architecture_visitors_class: + include!: uml/class/architecture_visitors_class.yml config_class: include!: uml/class/config_class.yml config_context_class: @@ -52,7 +54,7 @@ diagrams: include!: uml/class/sequence_model_class.yml package_model_class: include!: uml/class/package_model_class.yml - # Sequence diargams + # Sequence diagrams main_sequence: include!: uml/sequence/main_sequence.yml load_config_sequence: @@ -70,6 +72,8 @@ diagrams: # 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/include.yml \ No newline at end of file diff --git a/Makefile b/Makefile index 0864a5cd..63a03f8c 100644 --- a/Makefile +++ b/Makefile @@ -142,6 +142,9 @@ docs: doxygen: docs cp CONTRIBUTING.md docs/contributing.md cp CHANGELOG.md docs/changelog.md + cp docs/diagrams/*.svg docs/doxygen/ + mkdir -p docs/doxygen/html/test_cases + cp docs/test_cases/*.svg docs/doxygen/html/test_cases/ ../doxygen/_build/bin/doxygen .PHONY: fedora/% diff --git a/docs/Makefile b/docs/Makefile index ed309583..5c11167b 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -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 diff --git a/docs/architecture.md b/docs/architecture.md index a2dc5cd6..0403ad65 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -1,2 +1,202 @@ # Architecture + + +* [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) + + + +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`](./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). + diff --git a/docs/common_options.md b/docs/common_options.md index fe54e8d3..70a3e9f4 100644 --- a/docs/common_options.md +++ b/docs/common_options.md @@ -21,7 +21,7 @@ from it. The file must be specified in YAML and it's overall structure is as fol # common options for all diagrams ... diagrams: - first_diagram_name>: + first_diagram_name: type: class|sequence|package|include # diagram specific options ... diff --git a/docs/doxygen/layout-clang-uml.xml b/docs/doxygen/layout-clang-uml.xml index f8d7951a..1aa2a958 100644 --- a/docs/doxygen/layout-clang-uml.xml +++ b/docs/doxygen/layout-clang-uml.xml @@ -30,11 +30,11 @@ - - - - - + + + + + @@ -46,6 +46,7 @@ + @@ -83,7 +84,6 @@ - @@ -105,6 +105,7 @@ + @@ -121,7 +122,6 @@ - @@ -137,6 +137,7 @@ + @@ -146,6 +147,7 @@ + @@ -167,7 +169,6 @@ - @@ -184,6 +185,7 @@ + @@ -209,7 +211,6 @@ - @@ -240,6 +241,6 @@ - + diff --git a/docs/doxygen_integration.md b/docs/doxygen_integration.md index 285b3708..90bb5b33 100644 --- a/docs/doxygen_integration.md +++ b/docs/doxygen_integration.md @@ -6,10 +6,12 @@ -`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}="" -``` \ No newline at end of file +``` + +Furthermore, Doxygen adds images to HTML documentation as ``, +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 \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 +`` 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. + diff --git a/docs/generator_types.md b/docs/generator_types.md index fa909016..c434fb03 100644 --- a/docs/generator_types.md +++ b/docs/generator_types.md @@ -16,16 +16,711 @@ For instance to generate both types of diagrams run `clang-uml` as follows: clang-uml -g plantuml -g json ``` -By default only `plantuml` diagram are generated. +By default, only `plantuml` diagram are generated. ## PlantUML Generates UML diagrams in textual PlantUML format, which can then be converted to various image formats. +In case there is a need for adding custom PlantUML directives to generated +diagrams, they can be included directly in the diagram configuration. For +example: + +```yaml + plantuml: + before: + - title clang-uml configuration model + - left to right direction + after: + - 'note left of {{ alias("inheritable_diagram_options") }}: Options common to all diagram types.' + - 'note right of {{ alias("config") }}: General options not used by diagrams.' +``` + +will add before the diagram contents (right after `@startuml`) the title and +direction hint, and after each diagram contents (right before `@enduml`) +2 notes attached to elements. + +An example PlantUML diagram is presented below: + +```plantuml +@startuml +class "A" as C_0001371951663534295727 +class C_0001371951663534295727 [[https://github.com/bkryza/clang-uml/blob/a39af67987036732468c95087191562780a518de/tests/t00003/t00003.cc#L7{A}]] { ++A() = default : void ++A(int i) : void ++A(A &&) = default : void ++A(const A &) = deleted : void ++A(T t) : void ++~A() = default : void +.. ++operator=(A && other) noexcept : A & ++operator=(A & other) noexcept : A & +.. ++operator++() : A & +.. ++auto_method() : int ++basic_method() : void ++const_method() const : void +{static} +create_from_int(int i) : A ++default_int(int i = 12) : int ++default_string(int i, std::string s = "abc") : std::string ++double_int(const int i) : int +-private_method() : void +#protected_method() : void ++size() constexpr const : std::size_t +{static} +static_method() : int ++sum(const double a, const double b) : int +__ +-a_ : int [[[https://github.com/bkryza/clang-uml/blob/a39af67987036732468c95087191562780a518de/tests/t00003/t00003.cc#L70{a_}]]] +{static} +auto_member : const unsigned long [[[https://github.com/bkryza/clang-uml/blob/a39af67987036732468c95087191562780a518de/tests/t00003/t00003.cc#L55{auto_member}]]] +-b_ : int [[[https://github.com/bkryza/clang-uml/blob/a39af67987036732468c95087191562780a518de/tests/t00003/t00003.cc#L70{b_}]]] +-c_ : int [[[https://github.com/bkryza/clang-uml/blob/a39af67987036732468c95087191562780a518de/tests/t00003/t00003.cc#L70{c_}]]] +#compare : std::function [[[https://github.com/bkryza/clang-uml/blob/a39af67987036732468c95087191562780a518de/tests/t00003/t00003.cc#L62{compare}]]] +-private_member : int [[[https://github.com/bkryza/clang-uml/blob/a39af67987036732468c95087191562780a518de/tests/t00003/t00003.cc#L69{private_member}]]] +#protected_member : int [[[https://github.com/bkryza/clang-uml/blob/a39af67987036732468c95087191562780a518de/tests/t00003/t00003.cc#L60{protected_member}]]] ++public_member : int [[[https://github.com/bkryza/clang-uml/blob/a39af67987036732468c95087191562780a518de/tests/t00003/t00003.cc#L52{public_member}]]] +{static} +static_const_int : const int [[[https://github.com/bkryza/clang-uml/blob/a39af67987036732468c95087191562780a518de/tests/t00003/t00003.cc#L54{static_const_int}]]] +{static} +static_int : int [[[https://github.com/bkryza/clang-uml/blob/a39af67987036732468c95087191562780a518de/tests/t00003/t00003.cc#L53{static_int}]]] +} + +'Generated with clang-uml, version 0.3.7-20-ga39af67 +'LLVM version Ubuntu clang version 15.0.6 +@enduml +``` + +The footer at the end is added by default, but can be disabled with +`--no-metadata` command line option. + ## JSON Generates a JSON representation of the intermediate `clang-uml` model, which can be used for scripting, integrations as well as analysing the code base or even generating diagrams in other formats. +An equivalent of the above PlantUML diagram in JSON is presented below: + +```json +{ + "diagram_type": "class", + "elements": [ + { + "bases": [], + "display_name": "clanguml::t00003::A", + "id": "1371951663534295727", + "is_abstract": false, + "is_nested": false, + "is_struct": false, + "is_template": false, + "is_union": false, + "members": [ + { + "access": "public", + "is_static": false, + "name": "public_member", + "source_location": { + "column": 9, + "file": "../../tests/t00003/t00003.cc", + "line": 52, + "translation_unit": "../../tests/t00003/t00003.cc" + }, + "type": "int" + }, + { + "access": "protected", + "is_static": false, + "name": "protected_member", + "source_location": { + "column": 9, + "file": "../../tests/t00003/t00003.cc", + "line": 60, + "translation_unit": "../../tests/t00003/t00003.cc" + }, + "type": "int" + }, + { + "access": "protected", + "is_static": false, + "name": "compare", + "source_location": { + "column": 36, + "file": "../../tests/t00003/t00003.cc", + "line": 62, + "translation_unit": "../../tests/t00003/t00003.cc" + }, + "type": "std::function" + }, + { + "access": "private", + "is_static": false, + "name": "private_member", + "source_location": { + "column": 9, + "file": "../../tests/t00003/t00003.cc", + "line": 69, + "translation_unit": "../../tests/t00003/t00003.cc" + }, + "type": "int" + }, + { + "access": "private", + "is_static": false, + "name": "a_", + "source_location": { + "column": 9, + "file": "../../tests/t00003/t00003.cc", + "line": 70, + "translation_unit": "../../tests/t00003/t00003.cc" + }, + "type": "int" + }, + { + "access": "private", + "is_static": false, + "name": "b_", + "source_location": { + "column": 13, + "file": "../../tests/t00003/t00003.cc", + "line": 70, + "translation_unit": "../../tests/t00003/t00003.cc" + }, + "type": "int" + }, + { + "access": "private", + "is_static": false, + "name": "c_", + "source_location": { + "column": 17, + "file": "../../tests/t00003/t00003.cc", + "line": 70, + "translation_unit": "../../tests/t00003/t00003.cc" + }, + "type": "int" + }, + { + "access": "public", + "is_static": true, + "name": "static_int", + "source_location": { + "column": 16, + "file": "../../tests/t00003/t00003.cc", + "line": 53, + "translation_unit": "../../tests/t00003/t00003.cc" + }, + "type": "int" + }, + { + "access": "public", + "is_static": true, + "name": "static_const_int", + "source_location": { + "column": 22, + "file": "../../tests/t00003/t00003.cc", + "line": 54, + "translation_unit": "../../tests/t00003/t00003.cc" + }, + "type": "const int" + }, + { + "access": "public", + "is_static": true, + "name": "auto_member", + "source_location": { + "column": 23, + "file": "../../tests/t00003/t00003.cc", + "line": 55, + "translation_unit": "../../tests/t00003/t00003.cc" + }, + "type": "const unsigned long" + } + ], + "methods": [ + { + "access": "public", + "is_const": false, + "is_consteval": false, + "is_constexpr": false, + "is_constructor": true, + "is_copy_assignment": false, + "is_defaulted": true, + "is_deleted": false, + "is_move_assignment": false, + "is_noexcept": false, + "is_operator": false, + "is_pure_virtual": false, + "is_static": false, + "is_virtual": false, + "name": "A", + "parameters": [], + "type": "void" + }, + { + "access": "public", + "is_const": false, + "is_consteval": false, + "is_constexpr": false, + "is_constructor": true, + "is_copy_assignment": false, + "is_defaulted": false, + "is_deleted": false, + "is_move_assignment": false, + "is_noexcept": false, + "is_operator": false, + "is_pure_virtual": false, + "is_static": false, + "is_virtual": false, + "name": "A", + "parameters": [ + { + "name": "i", + "type": "int" + } + ], + "type": "void" + }, + { + "access": "public", + "is_const": false, + "is_consteval": false, + "is_constexpr": false, + "is_constructor": true, + "is_copy_assignment": false, + "is_defaulted": true, + "is_deleted": false, + "is_move_assignment": false, + "is_noexcept": false, + "is_operator": false, + "is_pure_virtual": false, + "is_static": false, + "is_virtual": false, + "name": "A", + "parameters": [ + { + "name": "", + "type": "clanguml::t00003::A &&" + } + ], + "type": "void" + }, + { + "access": "public", + "is_const": false, + "is_consteval": false, + "is_constexpr": false, + "is_constructor": true, + "is_copy_assignment": false, + "is_defaulted": false, + "is_deleted": true, + "is_move_assignment": false, + "is_noexcept": false, + "is_operator": false, + "is_pure_virtual": false, + "is_static": false, + "is_virtual": false, + "name": "A", + "parameters": [ + { + "name": "", + "type": "const clanguml::t00003::A &" + } + ], + "type": "void" + }, + { + "access": "public", + "is_const": false, + "is_consteval": false, + "is_constexpr": false, + "is_constructor": false, + "is_copy_assignment": false, + "is_defaulted": true, + "is_deleted": false, + "is_move_assignment": false, + "is_noexcept": false, + "is_operator": false, + "is_pure_virtual": false, + "is_static": false, + "is_virtual": true, + "name": "~A", + "parameters": [], + "type": "void" + }, + { + "access": "public", + "is_const": false, + "is_consteval": false, + "is_constexpr": false, + "is_constructor": false, + "is_copy_assignment": false, + "is_defaulted": false, + "is_deleted": false, + "is_move_assignment": false, + "is_noexcept": false, + "is_operator": false, + "is_pure_virtual": false, + "is_static": false, + "is_virtual": false, + "name": "basic_method", + "parameters": [], + "type": "void" + }, + { + "access": "public", + "is_const": false, + "is_consteval": false, + "is_constexpr": false, + "is_constructor": false, + "is_copy_assignment": false, + "is_defaulted": false, + "is_deleted": false, + "is_move_assignment": false, + "is_noexcept": false, + "is_operator": false, + "is_pure_virtual": false, + "is_static": true, + "is_virtual": false, + "name": "static_method", + "parameters": [], + "type": "int" + }, + { + "access": "public", + "is_const": true, + "is_consteval": false, + "is_constexpr": false, + "is_constructor": false, + "is_copy_assignment": false, + "is_defaulted": false, + "is_deleted": false, + "is_move_assignment": false, + "is_noexcept": false, + "is_operator": false, + "is_pure_virtual": false, + "is_static": false, + "is_virtual": false, + "name": "const_method", + "parameters": [], + "type": "void" + }, + { + "access": "public", + "is_const": false, + "is_consteval": false, + "is_constexpr": false, + "is_constructor": false, + "is_copy_assignment": false, + "is_defaulted": false, + "is_deleted": false, + "is_move_assignment": false, + "is_noexcept": false, + "is_operator": false, + "is_pure_virtual": false, + "is_static": false, + "is_virtual": false, + "name": "auto_method", + "parameters": [], + "type": "int" + }, + { + "access": "public", + "is_const": false, + "is_consteval": false, + "is_constexpr": false, + "is_constructor": false, + "is_copy_assignment": false, + "is_defaulted": false, + "is_deleted": false, + "is_move_assignment": false, + "is_noexcept": false, + "is_operator": true, + "is_pure_virtual": false, + "is_static": false, + "is_virtual": false, + "name": "operator++", + "parameters": [], + "type": "clanguml::t00003::A &" + }, + { + "access": "public", + "is_const": false, + "is_consteval": false, + "is_constexpr": false, + "is_constructor": false, + "is_copy_assignment": false, + "is_defaulted": false, + "is_deleted": false, + "is_move_assignment": true, + "is_noexcept": true, + "is_operator": true, + "is_pure_virtual": false, + "is_static": false, + "is_virtual": false, + "name": "operator=", + "parameters": [ + { + "name": "other", + "type": "clanguml::t00003::A &&" + } + ], + "type": "clanguml::t00003::A &" + }, + { + "access": "public", + "is_const": false, + "is_consteval": false, + "is_constexpr": false, + "is_constructor": false, + "is_copy_assignment": true, + "is_defaulted": false, + "is_deleted": false, + "is_move_assignment": false, + "is_noexcept": true, + "is_operator": true, + "is_pure_virtual": false, + "is_static": false, + "is_virtual": false, + "name": "operator=", + "parameters": [ + { + "name": "other", + "type": "clanguml::t00003::A &" + } + ], + "type": "clanguml::t00003::A &" + }, + { + "access": "public", + "is_const": true, + "is_consteval": false, + "is_constexpr": true, + "is_constructor": false, + "is_copy_assignment": false, + "is_defaulted": false, + "is_deleted": false, + "is_move_assignment": false, + "is_noexcept": false, + "is_operator": false, + "is_pure_virtual": false, + "is_static": false, + "is_virtual": false, + "name": "size", + "parameters": [], + "type": "std::size_t" + }, + { + "access": "public", + "is_const": false, + "is_consteval": false, + "is_constexpr": false, + "is_constructor": false, + "is_copy_assignment": false, + "is_defaulted": false, + "is_deleted": false, + "is_move_assignment": false, + "is_noexcept": false, + "is_operator": false, + "is_pure_virtual": false, + "is_static": false, + "is_virtual": false, + "name": "double_int", + "parameters": [ + { + "name": "i", + "type": "const int" + } + ], + "type": "int" + }, + { + "access": "public", + "is_const": false, + "is_consteval": false, + "is_constexpr": false, + "is_constructor": false, + "is_copy_assignment": false, + "is_defaulted": false, + "is_deleted": false, + "is_move_assignment": false, + "is_noexcept": false, + "is_operator": false, + "is_pure_virtual": false, + "is_static": false, + "is_virtual": false, + "name": "sum", + "parameters": [ + { + "name": "a", + "type": "const double" + }, + { + "name": "b", + "type": "const double" + } + ], + "type": "int" + }, + { + "access": "public", + "is_const": false, + "is_consteval": false, + "is_constexpr": false, + "is_constructor": false, + "is_copy_assignment": false, + "is_defaulted": false, + "is_deleted": false, + "is_move_assignment": false, + "is_noexcept": false, + "is_operator": false, + "is_pure_virtual": false, + "is_static": false, + "is_virtual": false, + "name": "default_int", + "parameters": [ + { + "default_value": "12", + "name": "i", + "type": "int" + } + ], + "type": "int" + }, + { + "access": "public", + "is_const": false, + "is_consteval": false, + "is_constexpr": false, + "is_constructor": false, + "is_copy_assignment": false, + "is_defaulted": false, + "is_deleted": false, + "is_move_assignment": false, + "is_noexcept": false, + "is_operator": false, + "is_pure_virtual": false, + "is_static": false, + "is_virtual": false, + "name": "default_string", + "parameters": [ + { + "name": "i", + "type": "int" + }, + { + "default_value": "\"abc\"", + "name": "s", + "type": "std::string" + } + ], + "type": "std::string" + }, + { + "access": "public", + "is_const": false, + "is_consteval": false, + "is_constexpr": false, + "is_constructor": false, + "is_copy_assignment": false, + "is_defaulted": false, + "is_deleted": false, + "is_move_assignment": false, + "is_noexcept": false, + "is_operator": false, + "is_pure_virtual": false, + "is_static": true, + "is_virtual": false, + "name": "create_from_int", + "parameters": [ + { + "name": "i", + "type": "int" + } + ], + "type": "clanguml::t00003::A" + }, + { + "access": "protected", + "is_const": false, + "is_consteval": false, + "is_constexpr": false, + "is_constructor": false, + "is_copy_assignment": false, + "is_defaulted": false, + "is_deleted": false, + "is_move_assignment": false, + "is_noexcept": false, + "is_operator": false, + "is_pure_virtual": false, + "is_static": false, + "is_virtual": false, + "name": "protected_method", + "parameters": [], + "type": "void" + }, + { + "access": "private", + "is_const": false, + "is_consteval": false, + "is_constexpr": false, + "is_constructor": false, + "is_copy_assignment": false, + "is_defaulted": false, + "is_deleted": false, + "is_move_assignment": false, + "is_noexcept": false, + "is_operator": false, + "is_pure_virtual": false, + "is_static": false, + "is_virtual": false, + "name": "private_method", + "parameters": [], + "type": "void" + }, + { + "access": "public", + "is_const": false, + "is_consteval": false, + "is_constexpr": false, + "is_constructor": true, + "is_copy_assignment": false, + "is_defaulted": false, + "is_deleted": false, + "is_move_assignment": false, + "is_noexcept": false, + "is_operator": false, + "is_pure_virtual": false, + "is_static": false, + "is_virtual": false, + "name": "A", + "parameters": [ + { + "name": "t", + "type": "T" + } + ], + "type": "void" + } + ], + "name": "A", + "namespace": "clanguml::t00003", + "source_location": { + "column": 7, + "file": "../../tests/t00003/t00003.cc", + "line": 7, + "translation_unit": "../../tests/t00003/t00003.cc" + }, + "template_parameters": [], + "type": "class" + } + ], + "metadata": { + "clang_uml_version": "0.3.7-20-ga39af67", + "llvm_version": "Ubuntu clang version 15.0.6", + "schema_version": 1 + }, + "name": "t00003_class", + "relationships": [], + "using_namespace": "clanguml::t00003" +} +``` + diff --git a/docs/installation.md b/docs/installation.md index 0ba4239c..cbb59888 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -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 diff --git a/docs/package_diagrams.md b/docs/package_diagrams.md index 55ff0a6d..364dfbb6 100644 --- a/docs/package_diagrams.md +++ b/docs/package_diagrams.md @@ -31,7 +31,7 @@ diagrams: ``` For instance the following C++ code: -``` +```cpp namespace A::AA { namespace A1 { struct CA { @@ -152,7 +152,7 @@ template std::map> cm() } ``` -generates the following diagram: +results the following diagram: ![package_deps](./test_cases/t30002_package.svg) diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 211e8d46..60c43f83 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -27,6 +27,7 @@ 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 ``` @@ -48,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 @@ -61,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: @@ -175,7 +179,7 @@ output_directory: output .sequence_diagram_anchor: &sequence_diagram_anchor type: sequence - glob: [] + glob: [ ] start_from: - function: 'main(int,const char**)' @@ -183,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)' ``` @@ -197,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. @@ -213,7 +218,7 @@ 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: @@ -253,19 +258,25 @@ clang-uml --add-compile-flag -I/opt/my_toolchain/include \ --remove-compile-flag -I/usr/include ... ``` +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.: +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] + paths: [ include, src ] ``` As the diagram will be huge for even medium-sized projects, it will likely not @@ -277,7 +288,8 @@ 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 + +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. diff --git a/uml/class/architecture_visitors_class.yml b/uml/class/architecture_visitors_class.yml new file mode 100644 index 00000000..7e82625f --- /dev/null +++ b/uml/class/architecture_visitors_class.yml @@ -0,0 +1,16 @@ +type: class +generate_packages: true +glob: + - src/docs/architecture.cc +include: + namespaces: + - clanguml + elements: + - r: "clanguml::.+::translation_unit_visitor.*" + - r: "clanguml::.+::model::diagram" +exclude: + access: [ public, protected, private ] + relationships: [ dependency ] +plantuml: + before: + - title clang-uml top level architecture - AST visitors diff --git a/uml/class/common_model_class.yml b/uml/class/common_model_class.yml index d0b57fb7..46d42760 100644 --- a/uml/class/common_model_class.yml +++ b/uml/class/common_model_class.yml @@ -8,8 +8,15 @@ include: exclude: relationships: - dependency + subclasses: + - clanguml::common::model::filter_visitor + access: [public, protected, private] + element_types: + - enum using_namespace: - clanguml::common::model plantuml: before: - - 'title clang-uml common diagram model' \ No newline at end of file + - 'title clang-uml common diagram model' + after: + - 'note top of {{ alias("diagram") }}: Common class for specific diagram types' \ No newline at end of file diff --git a/uml/class/config_class.yml b/uml/class/config_class.yml index b9ed2406..571e40ae 100644 --- a/uml/class/config_class.yml +++ b/uml/class/config_class.yml @@ -1,12 +1,26 @@ type: class -include_relations_also_as_members: false +include_relations_also_as_members: true glob: - src/config/config.cc include: namespaces: - clanguml::config + context: + - clanguml::config::inheritable_diagram_options + - clanguml::config::config + - clanguml::config::diagram +exclude: + elements: + - r: "clanguml::config::option<.*>" using_namespace: - clanguml::config plantuml: before: - - 'title clang-uml configuration model' \ No newline at end of file + - 'title clang-uml configuration model' + after: + - 'note left of {{ alias("inheritable_diagram_options") }}: Options common to all diagram types.' + - 'note right of {{ alias("config") }}: General options not used by diagrams.' + - 'note bottom of {{ alias("class_diagram") }}: Options for specific class diagrams' + - 'note bottom of {{ alias("sequence_diagram") }}: Options for specific sequence diagrams' + - 'note bottom of {{ alias("package_diagram") }}: Options for specific package diagrams' + - 'note bottom of {{ alias("include_diagram") }}: Options for specific include diagrams' diff --git a/uml/class/diagram_filter_context_class.yml b/uml/class/diagram_filter_context_class.yml index 4337c7a4..30ecf7b3 100644 --- a/uml/class/diagram_filter_context_class.yml +++ b/uml/class/diagram_filter_context_class.yml @@ -1,6 +1,6 @@ type: class include_relations_also_as_members: true -generate_packages: true +generate_packages: false glob: - src/common/model/diagram_filter.cc - src/common/model/diagram.cc @@ -12,5 +12,9 @@ include: exclude: elements: - clanguml::common::model::path + method_types: + - constructor + - destructor + - operator using_namespace: - clanguml \ No newline at end of file diff --git a/uml/package/architecture_package.yml b/uml/package/architecture_package.yml new file mode 100644 index 00000000..216bfc6c --- /dev/null +++ b/uml/package/architecture_package.yml @@ -0,0 +1,21 @@ +type: package +glob: + - src/config/config.cc + - src/common/model/diagram.cc + - src/**/model/diagram.cc + - src/**/visitor/translation_unit_visitor.cc + - src/**/generators/**/*generator.cc +include: + namespaces: + - clanguml + elements: + - clanguml + - clanguml::common + - clanguml::config + - r: "clanguml::.+_diagram" + - r: "clanguml::.+::model" + - r: "clanguml::.+::visitor" + - r: "clanguml::.+::generators" +plantuml: + before: + - 'title clang-uml top level packages' \ No newline at end of file