Skip to content

Commit

Permalink
Extended typed element diagram filter tests (#328)
Browse files Browse the repository at this point in the history
  • Loading branch information
bkryza committed Oct 31, 2024
1 parent 92bad7d commit 6b37602
Show file tree
Hide file tree
Showing 11 changed files with 94 additions and 9 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ endif(CODE_COVERAGE)
#
option(ADDRESS_SANITIZER "" OFF)
if(ADDRESS_SANITIZER)
message(STATUS "Enabling address sanitizer")
set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} \
-fno-omit-frame-pointer \
Expand Down
39 changes: 38 additions & 1 deletion docs/diagram_filters.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ Allows to include or exclude entities from specific C++20 module.
## elements

Allows to directly include or exclude specific entities from the diagrams, for instance to exclude a specific class
from an included namespace:
from an included namespace simply add the following exclude block:

```yaml
include:
Expand All @@ -124,6 +124,43 @@ from an included namespace:
- ns1::ns2::MyClass
```

`elements` filter allows also for more fine-grained control over the diagram
contents. Instead of a literal value in the filter like above, the
filter can also specify to what type of element the filter applies.
For instance the following filter:

```yaml
include:
namespaces:
- ns1::ns2
exclude:
elements:
- ns1::ns2::MyClass
- type: method
name: ns1::ns2::OtherClass::log
```

will, in addition to excluding `ns1::ns2::MyClass`, also exclude `ns1::ns2::OtherClass::log` method.

Another useful example, for instance to ignore all setters and getters in the
code base, the method elements filter can be specified with a regex e.g.:

```yaml
include:
namespaces:
- ns1::ns2
exclude:
elements:
- type: method
name:
r: '.*::(get|set).*'
```

The `type` in this filter can be one of the following:
`any`, `function`, `function_template`, `class`, `enum`, `method`, `member`,
`concept`, `package`, `objc_method`, `objc_member`, `objc_protocol`,
`objc_category`, `objc_interface`.

## element_types

Allows to include or exclude elements of specific type from the diagram, for instance
Expand Down
12 changes: 12 additions & 0 deletions docs/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
* [Schema validation error is thrown, but the configuration file is correct](#schema-validation-error-is-thrown-but-the-configuration-file-is-correct)
* ["fatal error: 'stddef.h' file not found"](#fatal-error-stddefh-file-not-found)
* ["error: unknown pragma ignored"](#error-unknown-pragma-ignored)
* ["bus error" on Apple Silicon macos](#bus-error-on-apple-silicon-macos)
* [Class diagrams](#class-diagrams)
* [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)
Expand Down Expand Up @@ -306,6 +307,17 @@ add_compile_flags:
- -Wno-unknown-pragmas
```

### "bus error" on Apple Silicon macos
On Apple Silicon macos, `clang-uml` must be linked with LLVM libunwind libraries
for proper exception handling, otherwise whenever an exception is thrown
somewhere within `clang-uml` the application is terminated with `bus error`.

In order to mitigate this error when building `clang-uml` from sources, the
following CMake option should be enabled during build:
```bash
-DCMAKE_EXE_LINKER_FLAGS="-L/opt/homebrew/opt/llvm/lib/c++ -Wl,-rpath,/opt/homebrew/opt/llvm/lib/c++"
```

## Class diagrams

### How can I generate class diagram of my entire project
Expand Down
2 changes: 1 addition & 1 deletion src/class_diagram/model/class_element.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
namespace clanguml::class_diagram::model {

class_element::class_element(
common::model::access_t access, std::string name, std::string type)
const common::model::access_t access, std::string name, std::string type)
: access_{access}
, name_{std::move(name)}
, type_{std::move(type)}
Expand Down
11 changes: 10 additions & 1 deletion src/class_diagram/model/class_element.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ 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);
common::model::access_t access, std::string name, std::string type);

~class_element() override = default;

Expand Down Expand Up @@ -79,8 +79,17 @@ class class_element : public common::model::decorated_element,
*/
virtual inja::json context() const;

/**
* @brief Set class elements qualified name.
*
* This method sets the fully qualified path of the class element,
* including namespace and parent class name.
*/
void set_qualified_name(const std::string &qn);

/**
* @brief get fully qualified name of the class element.
*/
std::string qualified_name() const;

private:
Expand Down
14 changes: 14 additions & 0 deletions src/common/model/filters/diagram_filter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,20 @@ tvl::value_t element_filter::match(
(el.name == class_participant.full_name(false));
}

if (p.type_name() == "objc_method") {
const auto &m =
dynamic_cast<const sequence_diagram::model::objc_method &>(
p);
const auto class_id = m.class_id();
const auto &class_participant =
sequence_model.get_participant<participant>(class_id)
.value();

return (el.name == p.name_and_ns()) ||
(el.name == p.full_name(false)) ||
(el.name == class_participant.full_name(false));
}

return el.name == p.full_name(false);
});
}
Expand Down
4 changes: 2 additions & 2 deletions tests/t20001/.clang-uml
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ diagrams:
before:
- "' t20001 test diagram of type {{ diagram.type }}"
after:
- '{% set e=element("clanguml::t20001::tmain()") %} note over {{ e.alias) }}: Main test function'
- '{% set e=element("clanguml::t20001::tmain()") %} note over {{ e.alias }}: Main test function'
mermaid:
before:
- "%% t20001 test diagram of type {{ diagram.type }}"
after:
- '{% set e=element("clanguml::t20001::tmain()") %} Note over {{ e.alias) }}: Main test function'
- '{% set e=element("clanguml::t20001::tmain()") %} Note over {{ e.alias }}: Main test function'
4 changes: 4 additions & 0 deletions tests/t20059/.clang-uml
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,9 @@ diagrams:
include:
paths:
- .
exclude:
elements:
- type: objc_method
name: t20059_A::logA
from:
- function: "t20059_tmain()"
4 changes: 4 additions & 0 deletions tests/t20059/t20059.m
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,12 @@ - (void)printImpl
NSLog(@"t20059_A: Called print_impl method");
}

- (void)logA {
}

- (void)print
{
[self logA];
[self printImpl];
}

Expand Down
4 changes: 4 additions & 0 deletions tests/t20059/test_case.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,9 @@ TEST_CASE("t20059")
{"t20059_tmain()", "t20059_C", "print()"}, //
{"t20059_tmain()", "t20059_D", "print()"}, //
}));

REQUIRE(HasMessage(src, {"t20059_tmain()", "t20059_A", "print()"}));

REQUIRE(!HasMessage(src, {"t20059_A", "t20059_A", "logA()"}));
});
}
8 changes: 4 additions & 4 deletions tests/test_cases.h
Original file line number Diff line number Diff line change
Expand Up @@ -2565,8 +2565,8 @@ int64_t FindMessage(
const json_t &d, const Message &msg, int64_t offset, bool fail)
{
if (msg.is_response) {
// TODO: Currently response are not generated as separate messages in
// JSON format
// TODO: Currently response are not generated as separate messages
// in JSON format
return offset;
}

Expand All @@ -2591,8 +2591,8 @@ int64_t find_message_in_chain(const json_t &d, const Message &msg,
int64_t offset, bool fail, uint32_t chain_index)
{
if (msg.is_response) {
// TODO: Currently response are not generated as separate messages in
// JSON format
// TODO: Currently response are not generated as separate messages
// in JSON format
return offset;
}

Expand Down

0 comments on commit 6b37602

Please sign in to comment.