Enabled advanced diagram filters in sequence diagrams (#289)
This commit is contained in:
@@ -389,6 +389,12 @@ tvl::value_t namespace_filter::match(const diagram &d, const element &e) const
|
||||
return result;
|
||||
}
|
||||
|
||||
tvl::value_t namespace_filter::match(
|
||||
const diagram &d, const sequence_diagram::model::participant &p) const
|
||||
{
|
||||
return match(d, dynamic_cast<const element &>(p));
|
||||
}
|
||||
|
||||
modules_filter::modules_filter(
|
||||
filter_t type, std::vector<common::string_or_regex> modules)
|
||||
: filter_visitor{type}
|
||||
|
||||
@@ -232,6 +232,9 @@ struct namespace_filter : public filter_visitor {
|
||||
|
||||
tvl::value_t match(const diagram &d, const element &e) const override;
|
||||
|
||||
tvl::value_t match(const diagram &d,
|
||||
const sequence_diagram::model::participant &p) const override;
|
||||
|
||||
private:
|
||||
std::vector<common::namespace_or_regex> namespaces_;
|
||||
};
|
||||
|
||||
@@ -289,7 +289,7 @@ public:
|
||||
return stripped_comment;
|
||||
}
|
||||
|
||||
bool skip_system_header_decl(const clang::NamedDecl *decl)
|
||||
bool skip_system_header_decl(const clang::NamedDecl *decl) const
|
||||
{
|
||||
return !config().include_system_headers() &&
|
||||
source_manager().isInSystemHeader(
|
||||
@@ -302,7 +302,7 @@ public:
|
||||
* @param decl Clang declaration.
|
||||
* @return True, if the entity should be included in the diagram.
|
||||
*/
|
||||
bool should_include(const clang::NamedDecl *decl)
|
||||
bool should_include(const clang::NamedDecl *decl) const
|
||||
{
|
||||
if (decl == nullptr)
|
||||
return false;
|
||||
|
||||
@@ -380,7 +380,7 @@ private:
|
||||
struct method : public function {
|
||||
method(const common::model::namespace_ &using_namespace);
|
||||
|
||||
method(const function &) = delete;
|
||||
method(const method &) = delete;
|
||||
method(method &&) noexcept = delete;
|
||||
method &operator=(const method &) = delete;
|
||||
method &operator=(method &&) = delete;
|
||||
|
||||
@@ -1085,6 +1085,9 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
|
||||
auto generated_message_from_comment = generate_message_from_comment(m);
|
||||
|
||||
if (!generated_message_from_comment && !should_include(expr)) {
|
||||
LOG_DBG("Skipping call expression due to filter at: {}",
|
||||
expr->getBeginLoc().printToString(source_manager()));
|
||||
|
||||
processed_comments().erase(raw_expr_comment);
|
||||
return true;
|
||||
}
|
||||
@@ -1178,7 +1181,7 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
|
||||
auto success = process_function_call_expression(m, expr);
|
||||
|
||||
if (!success) {
|
||||
LOG_DBG("Skipping call to call expression at: {}",
|
||||
LOG_DBG("Skipping call expression at: {}",
|
||||
expr->getBeginLoc().printToString(source_manager()));
|
||||
|
||||
return true;
|
||||
@@ -2098,6 +2101,7 @@ translation_unit_visitor::create_lambda_method_model(
|
||||
ns.pop_back();
|
||||
method_model_ptr->set_name(ns.name());
|
||||
ns.pop_back();
|
||||
method_model_ptr->set_namespace(ns);
|
||||
|
||||
method_model_ptr->is_defaulted(declaration->isDefaulted());
|
||||
method_model_ptr->is_assignment(declaration->isCopyAssignmentOperator() ||
|
||||
@@ -2137,6 +2141,7 @@ translation_unit_visitor::create_method_model(clang::CXXMethodDecl *declaration)
|
||||
ns.pop_back();
|
||||
method_model_ptr->set_name(ns.name());
|
||||
ns.pop_back();
|
||||
method_model_ptr->set_namespace(ns);
|
||||
|
||||
method_model_ptr->is_defaulted(declaration->isDefaulted());
|
||||
method_model_ptr->is_assignment(declaration->isCopyAssignmentOperator() ||
|
||||
@@ -2191,14 +2196,8 @@ translation_unit_visitor::create_method_model(clang::CXXMethodDecl *declaration)
|
||||
|
||||
bool translation_unit_visitor::should_include(const clang::TagDecl *decl) const
|
||||
{
|
||||
if (source_manager().isInSystemHeader(decl->getSourceRange().getBegin()))
|
||||
return false;
|
||||
|
||||
const auto decl_file = decl->getLocation().printToString(source_manager());
|
||||
|
||||
return diagram().should_include(
|
||||
namespace_{decl->getQualifiedNameAsString()}) &&
|
||||
diagram().should_include(common::model::source_file{decl_file});
|
||||
return visitor_specialization_t::should_include(
|
||||
dynamic_cast<const clang::NamedDecl *>(decl));
|
||||
}
|
||||
|
||||
bool translation_unit_visitor::should_include(
|
||||
@@ -2236,8 +2235,11 @@ bool translation_unit_visitor::should_include(const clang::CallExpr *expr) const
|
||||
if (callee_decl != nullptr) {
|
||||
const auto *callee_function = callee_decl->getAsFunction();
|
||||
|
||||
if ((callee_function == nullptr) || !should_include(callee_function))
|
||||
if ((callee_function == nullptr) || !should_include(callee_function)) {
|
||||
LOG_DBG("Skipping call expression at {}",
|
||||
expr->getBeginLoc().printToString(source_manager()));
|
||||
return false;
|
||||
}
|
||||
|
||||
return should_include(callee_function);
|
||||
}
|
||||
@@ -2263,30 +2265,19 @@ bool translation_unit_visitor::should_include(
|
||||
bool translation_unit_visitor::should_include(
|
||||
const clang::FunctionDecl *decl) const
|
||||
{
|
||||
const auto decl_file = decl->getLocation().printToString(source_manager());
|
||||
|
||||
return diagram().should_include(
|
||||
namespace_{decl->getQualifiedNameAsString()}) &&
|
||||
diagram().should_include(common::model::source_file{decl_file});
|
||||
return visitor_specialization_t::should_include(decl);
|
||||
}
|
||||
|
||||
bool translation_unit_visitor::should_include(
|
||||
const clang::FunctionTemplateDecl *decl) const
|
||||
{
|
||||
return should_include(decl->getAsFunction());
|
||||
return visitor_specialization_t::should_include(decl->getAsFunction());
|
||||
}
|
||||
|
||||
bool translation_unit_visitor::should_include(
|
||||
const clang::ClassTemplateDecl *decl) const
|
||||
{
|
||||
if (source_manager().isInSystemHeader(decl->getSourceRange().getBegin()))
|
||||
return false;
|
||||
|
||||
const auto decl_file = decl->getLocation().printToString(source_manager());
|
||||
|
||||
return diagram().should_include(
|
||||
namespace_{decl->getQualifiedNameAsString()}) &&
|
||||
diagram().should_include(common::model::source_file{decl_file});
|
||||
return visitor_specialization_t::should_include(decl);
|
||||
}
|
||||
|
||||
std::optional<std::string> translation_unit_visitor::get_expression_comment(
|
||||
|
||||
15
tests/t20055/.clang-uml
Normal file
15
tests/t20055/.clang-uml
Normal file
@@ -0,0 +1,15 @@
|
||||
diagrams:
|
||||
t20055_sequence:
|
||||
type: sequence
|
||||
filter_mode: advanced
|
||||
glob:
|
||||
- t20055.cc
|
||||
include:
|
||||
anyof:
|
||||
namespaces:
|
||||
- clanguml::t20055::ns2
|
||||
elements:
|
||||
- clanguml::t20055::ns1::B
|
||||
using_namespace: clanguml::t20055
|
||||
from:
|
||||
- function: "clanguml::t20055::ns2::tmain()"
|
||||
34
tests/t20055/t20055.cc
Normal file
34
tests/t20055/t20055.cc
Normal file
@@ -0,0 +1,34 @@
|
||||
namespace clanguml {
|
||||
namespace t20055 {
|
||||
namespace ns1 {
|
||||
|
||||
struct A {
|
||||
void a() { }
|
||||
};
|
||||
|
||||
struct B {
|
||||
A a;
|
||||
void b() { a.a(); }
|
||||
};
|
||||
|
||||
} // namespace ns1
|
||||
namespace ns2 {
|
||||
void f() { }
|
||||
struct C {
|
||||
ns1::B b;
|
||||
void c()
|
||||
{
|
||||
b.b();
|
||||
f();
|
||||
}
|
||||
};
|
||||
|
||||
void tmain()
|
||||
{
|
||||
C c;
|
||||
c.c();
|
||||
}
|
||||
|
||||
} // namespace ns2
|
||||
}
|
||||
}
|
||||
39
tests/t20055/test_case.h
Normal file
39
tests/t20055/test_case.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* tests/t20055/test_case.h
|
||||
*
|
||||
* Copyright (c) 2021-2024 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.
|
||||
*/
|
||||
|
||||
TEST_CASE("t20055")
|
||||
{
|
||||
using namespace clanguml::test;
|
||||
using namespace std::string_literals;
|
||||
|
||||
auto [config, db, diagram, model] =
|
||||
CHECK_SEQUENCE_MODEL("t20055", "t20055_sequence");
|
||||
|
||||
CHECK_SEQUENCE_DIAGRAM(*config, diagram, *model, [](const auto &src) {
|
||||
REQUIRE(MessageOrder(src,
|
||||
{
|
||||
//
|
||||
{{"ns2", "tmain()"}, {"ns2", "C"}, "c()"},
|
||||
{{"ns2", "C"}, {"ns1", "B"}, "b()"},
|
||||
{{"ns2", "C"}, {"ns2", "f()"}, ""}
|
||||
//
|
||||
}));
|
||||
|
||||
REQUIRE(!HasMessage(src, {{"ns1", "B"}, {"ns1", "A"}, "a()"}));
|
||||
});
|
||||
}
|
||||
@@ -9,25 +9,6 @@ module;
|
||||
export module t30015.app;
|
||||
import t30015.lib1;
|
||||
|
||||
// import t30015.app;
|
||||
// import t30015.mod2;
|
||||
// import t30015.mod3;
|
||||
// import t30015.mod4;
|
||||
// import t30015.mod5;
|
||||
// import t30015.mod6;
|
||||
// import t30015.mod7;
|
||||
// import t30015.mod8;
|
||||
// import t30015.mod9;
|
||||
// import t30015.mod10;
|
||||
// import t30015.mod11;
|
||||
// import t30015.mod12;
|
||||
// import t30015.mod13;
|
||||
// import t30015.mod14;
|
||||
// import t30015.mod15;
|
||||
// import t30015.mod16;
|
||||
// import t30015.mod17;
|
||||
// import t30015.mod18;
|
||||
|
||||
export namespace clanguml::t30015 {
|
||||
|
||||
class CBA : public CF {
|
||||
|
||||
@@ -623,6 +623,7 @@ void CHECK_INCLUDE_DIAGRAM(const clanguml::config::config &config,
|
||||
#include "t20052/test_case.h"
|
||||
#include "t20053/test_case.h"
|
||||
#include "t20054/test_case.h"
|
||||
#include "t20055/test_case.h"
|
||||
|
||||
///
|
||||
/// Package diagram tests
|
||||
|
||||
@@ -339,8 +339,16 @@ std::optional<nlohmann::json> get_participant(
|
||||
if (!j.contains("participants"))
|
||||
return {};
|
||||
|
||||
std::string using_namespace{};
|
||||
if (j.contains("using_namespace")) {
|
||||
using_namespace =
|
||||
fmt::format("{}::", j["using_namespace"].get<std::string>());
|
||||
}
|
||||
|
||||
for (const nlohmann::json &e : j.at("participants")) {
|
||||
if (e["display_name"] == name)
|
||||
if (e["display_name"] == name ||
|
||||
e["full_name"].get<std::string>().substr(using_namespace.size()) ==
|
||||
name)
|
||||
return {e};
|
||||
}
|
||||
|
||||
@@ -2482,7 +2490,7 @@ int64_t FindMessage(
|
||||
if (!fail)
|
||||
return -1;
|
||||
|
||||
std::cout << "FindMessage failed with error " << e.what() << "\n";
|
||||
std::cout << "FindMessage failed with error: " << e.what() << "\n";
|
||||
|
||||
throw e;
|
||||
}
|
||||
|
||||
@@ -409,6 +409,9 @@ test_cases:
|
||||
- name: t20054
|
||||
title: Test case for sequence diagram with nested classes
|
||||
description:
|
||||
- name: t20055
|
||||
title: Test case for advanced filter in sequence diagram
|
||||
description:
|
||||
Package diagrams:
|
||||
- name: t30001
|
||||
title: Basic package diagram test case
|
||||
|
||||
Reference in New Issue
Block a user