Added support for constructors and operators in sequence diagrams
This commit is contained in:
@@ -218,10 +218,11 @@ void call_expression_context::leave_loopstmt()
|
|||||||
return loop_stmt_stack_.pop();
|
return loop_stmt_stack_.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
clang::CallExpr *call_expression_context::current_callexpr() const
|
call_expression_context::callexpr_stack_t
|
||||||
|
call_expression_context::current_callexpr() const
|
||||||
{
|
{
|
||||||
if (call_expr_stack_.empty())
|
if (call_expr_stack_.empty())
|
||||||
return nullptr;
|
return {};
|
||||||
|
|
||||||
return call_expr_stack_.top();
|
return call_expr_stack_.top();
|
||||||
}
|
}
|
||||||
@@ -231,6 +232,11 @@ void call_expression_context::enter_callexpr(clang::CallExpr *expr)
|
|||||||
call_expr_stack_.push(expr);
|
call_expr_stack_.push(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void call_expression_context::enter_callexpr(clang::CXXConstructExpr *expr)
|
||||||
|
{
|
||||||
|
call_expr_stack_.push(expr);
|
||||||
|
}
|
||||||
|
|
||||||
void call_expression_context::leave_callexpr()
|
void call_expression_context::leave_callexpr()
|
||||||
{
|
{
|
||||||
if (!call_expr_stack_.empty()) {
|
if (!call_expr_stack_.empty()) {
|
||||||
|
|||||||
@@ -37,6 +37,15 @@ namespace clanguml::sequence_diagram::visitor {
|
|||||||
* e.g. a class method or function.
|
* e.g. a class method or function.
|
||||||
*/
|
*/
|
||||||
struct call_expression_context {
|
struct call_expression_context {
|
||||||
|
/**
|
||||||
|
* In Clang, call to a class constructor is represented by
|
||||||
|
* `clang::CXXConstructExpr`, which does inherit from `clang::CallExpr`.
|
||||||
|
* So to enable to track calls to constructors, we need to be able
|
||||||
|
* to add to the call stack either type.
|
||||||
|
*/
|
||||||
|
using callexpr_stack_t = std::variant<std::monostate, clang::CallExpr *,
|
||||||
|
clang::CXXConstructExpr *>;
|
||||||
|
|
||||||
call_expression_context();
|
call_expression_context();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -252,15 +261,22 @@ struct call_expression_context {
|
|||||||
*
|
*
|
||||||
* @return Call expression
|
* @return Call expression
|
||||||
*/
|
*/
|
||||||
clang::CallExpr *current_callexpr() const;
|
callexpr_stack_t current_callexpr() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Enter a call expression
|
* @brief Enter a call expression
|
||||||
*
|
*
|
||||||
* @param stmt Call expression
|
* @param expr Call expression
|
||||||
*/
|
*/
|
||||||
void enter_callexpr(clang::CallExpr *expr);
|
void enter_callexpr(clang::CallExpr *expr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enter a constructor call expression
|
||||||
|
*
|
||||||
|
* @param expr Constructor call expression
|
||||||
|
*/
|
||||||
|
void enter_callexpr(clang::CXXConstructExpr *expr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Leave call expression
|
* @brief Leave call expression
|
||||||
*/
|
*/
|
||||||
@@ -302,7 +318,7 @@ private:
|
|||||||
std::int64_t current_caller_id_{0};
|
std::int64_t current_caller_id_{0};
|
||||||
std::stack<std::int64_t> current_lambda_caller_id_;
|
std::stack<std::int64_t> current_lambda_caller_id_;
|
||||||
|
|
||||||
std::stack<clang::CallExpr *> call_expr_stack_;
|
std::stack<callexpr_stack_t> call_expr_stack_;
|
||||||
|
|
||||||
std::stack<clang::IfStmt *> if_stmt_stack_;
|
std::stack<clang::IfStmt *> if_stmt_stack_;
|
||||||
std::stack<clang::IfStmt *> elseif_stmt_stack_;
|
std::stack<clang::IfStmt *> elseif_stmt_stack_;
|
||||||
|
|||||||
@@ -488,6 +488,41 @@ bool translation_unit_visitor::TraverseCXXOperatorCallExpr(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool translation_unit_visitor::TraverseCXXTemporaryObjectExpr(
|
||||||
|
clang::CXXTemporaryObjectExpr *expr)
|
||||||
|
{
|
||||||
|
context().enter_callexpr(expr);
|
||||||
|
|
||||||
|
RecursiveASTVisitor<
|
||||||
|
translation_unit_visitor>::TraverseCXXTemporaryObjectExpr(expr);
|
||||||
|
|
||||||
|
translation_unit_visitor::VisitCXXConstructExpr(
|
||||||
|
clang::dyn_cast<clang::CXXConstructExpr>(expr));
|
||||||
|
|
||||||
|
context().leave_callexpr();
|
||||||
|
|
||||||
|
pop_message_to_diagram(expr);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool translation_unit_visitor::TraverseCXXConstructExpr(
|
||||||
|
clang::CXXConstructExpr *expr)
|
||||||
|
{
|
||||||
|
context().enter_callexpr(expr);
|
||||||
|
|
||||||
|
RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXConstructExpr(
|
||||||
|
expr);
|
||||||
|
|
||||||
|
translation_unit_visitor::VisitCXXConstructExpr(expr);
|
||||||
|
|
||||||
|
context().leave_callexpr();
|
||||||
|
|
||||||
|
pop_message_to_diagram(expr);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool translation_unit_visitor::TraverseCompoundStmt(clang::CompoundStmt *stmt)
|
bool translation_unit_visitor::TraverseCompoundStmt(clang::CompoundStmt *stmt)
|
||||||
{
|
{
|
||||||
using clanguml::common::model::message_t;
|
using clanguml::common::model::message_t;
|
||||||
@@ -862,7 +897,8 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
|
|||||||
// message source rather then enclosing context
|
// message source rather then enclosing context
|
||||||
// Unless the lambda is declared in a function or method call
|
// Unless the lambda is declared in a function or method call
|
||||||
if (context().lambda_caller_id() != 0) {
|
if (context().lambda_caller_id() != 0) {
|
||||||
if (context().current_callexpr() == nullptr) {
|
if (!std::holds_alternative<clang::CallExpr *>(
|
||||||
|
context().current_callexpr())) {
|
||||||
m.set_from(context().lambda_caller_id());
|
m.set_from(context().lambda_caller_id());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -885,6 +921,7 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
|
|||||||
if (!process_operator_call_expression(m, operator_call_expr))
|
if (!process_operator_call_expression(m, operator_call_expr))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Call to a class method
|
// Call to a class method
|
||||||
//
|
//
|
||||||
@@ -963,17 +1000,69 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool translation_unit_visitor::VisitCXXConstructExpr(
|
||||||
|
clang::CXXConstructExpr *expr)
|
||||||
|
{
|
||||||
|
using clanguml::common::model::message_scope_t;
|
||||||
|
using clanguml::common::model::message_t;
|
||||||
|
using clanguml::common::model::namespace_;
|
||||||
|
using clanguml::sequence_diagram::model::activity;
|
||||||
|
using clanguml::sequence_diagram::model::message;
|
||||||
|
|
||||||
|
if (!should_include(expr->getConstructor()))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
LOG_TRACE("Visiting cxx construct expression at {} [caller_id = {}]",
|
||||||
|
expr->getBeginLoc().printToString(source_manager()),
|
||||||
|
context().caller_id());
|
||||||
|
|
||||||
|
message m{message_t::kCall, context().caller_id()};
|
||||||
|
|
||||||
|
set_source_location(*expr, m);
|
||||||
|
|
||||||
|
if (context().lambda_caller_id() != 0) {
|
||||||
|
if (!std::holds_alternative<clang::CallExpr *>(
|
||||||
|
context().current_callexpr())) {
|
||||||
|
m.set_from(context().lambda_caller_id());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LOG_DBG("Current lambda declaration is passed to a method or "
|
||||||
|
"function - keep the original caller id");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context().is_expr_in_current_control_statement_condition(expr)) {
|
||||||
|
m.set_message_scope(common::model::message_scope_t::kCondition);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!process_construct_expression(m, expr))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (m.from() > 0 && m.to() > 0) {
|
||||||
|
if (diagram().sequences().find(m.from()) ==
|
||||||
|
diagram().sequences().end()) {
|
||||||
|
activity a{m.from()};
|
||||||
|
diagram().sequences().insert({m.from(), std::move(a)});
|
||||||
|
}
|
||||||
|
|
||||||
|
diagram().add_active_participant(m.from());
|
||||||
|
diagram().add_active_participant(m.to());
|
||||||
|
|
||||||
|
LOG_DBG("Found constructor call {} from {} [{}] to {} [{}] ",
|
||||||
|
m.message_name(), m.from(), m.from(), m.to(), m.to());
|
||||||
|
|
||||||
|
push_message(expr, std::move(m));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool translation_unit_visitor::process_operator_call_expression(
|
bool translation_unit_visitor::process_operator_call_expression(
|
||||||
model::message &m, const clang::CXXOperatorCallExpr *operator_call_expr)
|
model::message &m, const clang::CXXOperatorCallExpr *operator_call_expr)
|
||||||
{
|
{
|
||||||
if (operator_call_expr->getCalleeDecl() == nullptr)
|
if (operator_call_expr->getCalleeDecl() == nullptr)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// For now we only handle call overloaded operators
|
|
||||||
if (operator_call_expr->getOperator() !=
|
|
||||||
clang::OverloadedOperatorKind::OO_Call)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
LOG_DBG("Operator '{}' call expression to {} at {}",
|
LOG_DBG("Operator '{}' call expression to {} at {}",
|
||||||
getOperatorSpelling(operator_call_expr->getOperator()),
|
getOperatorSpelling(operator_call_expr->getOperator()),
|
||||||
operator_call_expr->getCalleeDecl()->getID(),
|
operator_call_expr->getCalleeDecl()->getID(),
|
||||||
@@ -993,6 +1082,39 @@ bool translation_unit_visitor::process_operator_call_expression(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool translation_unit_visitor::process_construct_expression(
|
||||||
|
model::message &m, const clang::CXXConstructExpr *construct_expr)
|
||||||
|
{
|
||||||
|
const auto *constructor = construct_expr->getConstructor();
|
||||||
|
if (constructor == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const auto *constructor_parent = constructor->getParent();
|
||||||
|
if (constructor_parent == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
LOG_DBG("Constructor '{}' call expression to {} at {}",
|
||||||
|
construct_expr->getConstructor()->getNameAsString(),
|
||||||
|
constructor->getID(),
|
||||||
|
construct_expr->getBeginLoc().printToString(source_manager()));
|
||||||
|
|
||||||
|
auto maybe_id = get_unique_id(constructor->getID());
|
||||||
|
if (maybe_id.has_value()) {
|
||||||
|
m.set_to(maybe_id.value());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m.set_to(constructor->getID());
|
||||||
|
}
|
||||||
|
|
||||||
|
m.set_message_name(
|
||||||
|
fmt::format("{}::{}", constructor_parent->getQualifiedNameAsString(),
|
||||||
|
constructor_parent->getNameAsString()));
|
||||||
|
|
||||||
|
diagram().add_active_participant(constructor->getID());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool translation_unit_visitor::process_class_method_call_expression(
|
bool translation_unit_visitor::process_class_method_call_expression(
|
||||||
model::message &m, const clang::CXXMemberCallExpr *method_call_expr)
|
model::message &m, const clang::CXXMemberCallExpr *method_call_expr)
|
||||||
{
|
{
|
||||||
@@ -2102,6 +2224,12 @@ void translation_unit_visitor::push_message(
|
|||||||
call_expr_message_map_.emplace(expr, std::move(m));
|
call_expr_message_map_.emplace(expr, std::move(m));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void translation_unit_visitor::push_message(
|
||||||
|
clang::CXXConstructExpr *expr, model::message &&m)
|
||||||
|
{
|
||||||
|
construct_expr_message_map_.emplace(expr, std::move(m));
|
||||||
|
}
|
||||||
|
|
||||||
void translation_unit_visitor::pop_message_to_diagram(clang::CallExpr *expr)
|
void translation_unit_visitor::pop_message_to_diagram(clang::CallExpr *expr)
|
||||||
{
|
{
|
||||||
assert(expr != nullptr);
|
assert(expr != nullptr);
|
||||||
@@ -2119,6 +2247,25 @@ void translation_unit_visitor::pop_message_to_diagram(clang::CallExpr *expr)
|
|||||||
call_expr_message_map_.erase(expr);
|
call_expr_message_map_.erase(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void translation_unit_visitor::pop_message_to_diagram(
|
||||||
|
clang::CXXConstructExpr *expr)
|
||||||
|
{
|
||||||
|
assert(expr != nullptr);
|
||||||
|
|
||||||
|
// Skip if no message was generated from this expr
|
||||||
|
if (construct_expr_message_map_.find(expr) ==
|
||||||
|
construct_expr_message_map_.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto msg = std::move(construct_expr_message_map_.at(expr));
|
||||||
|
|
||||||
|
auto caller_id = msg.from();
|
||||||
|
diagram().get_activity(caller_id).add_message(std::move(msg));
|
||||||
|
|
||||||
|
construct_expr_message_map_.erase(expr);
|
||||||
|
}
|
||||||
|
|
||||||
void translation_unit_visitor::finalize()
|
void translation_unit_visitor::finalize()
|
||||||
{
|
{
|
||||||
std::set<common::model::diagram_element::id_t> active_participants_unique;
|
std::set<common::model::diagram_element::id_t> active_participants_unique;
|
||||||
|
|||||||
@@ -72,8 +72,11 @@ public:
|
|||||||
|
|
||||||
bool TraverseCXXOperatorCallExpr(clang::CXXOperatorCallExpr *expr);
|
bool TraverseCXXOperatorCallExpr(clang::CXXOperatorCallExpr *expr);
|
||||||
|
|
||||||
// TODO
|
bool VisitCXXConstructExpr(clang::CXXConstructExpr *expr);
|
||||||
// bool TraverseCXXConstructExpr(clang::CXXConstructExpr *expr);
|
|
||||||
|
bool TraverseCXXConstructExpr(clang::CXXConstructExpr *expr);
|
||||||
|
|
||||||
|
bool TraverseCXXTemporaryObjectExpr(clang::CXXTemporaryObjectExpr *expr);
|
||||||
|
|
||||||
bool VisitLambdaExpr(clang::LambdaExpr *expr);
|
bool VisitLambdaExpr(clang::LambdaExpr *expr);
|
||||||
|
|
||||||
@@ -422,7 +425,17 @@ private:
|
|||||||
const clang::CXXDependentScopeMemberExpr *dependent_member_expr) const;
|
const clang::CXXDependentScopeMemberExpr *dependent_member_expr) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Handle a operator call expresion
|
* @brief Handle CXX constructor call
|
||||||
|
*
|
||||||
|
* @param m Message model
|
||||||
|
* @param construct_expr CXX Construct expression
|
||||||
|
* @return True, if `m` contains a valid constructor call
|
||||||
|
*/
|
||||||
|
bool process_construct_expression(
|
||||||
|
model::message &m, const clang::CXXConstructExpr *construct_expr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handle a operator call expression
|
||||||
*
|
*
|
||||||
* @param m Message model
|
* @param m Message model
|
||||||
* @param operator_call_expr Operator call expression
|
* @param operator_call_expr Operator call expression
|
||||||
@@ -485,6 +498,7 @@ private:
|
|||||||
* @param m Message model
|
* @param m Message model
|
||||||
*/
|
*/
|
||||||
void push_message(clang::CallExpr *expr, model::message &&m);
|
void push_message(clang::CallExpr *expr, model::message &&m);
|
||||||
|
void push_message(clang::CXXConstructExpr *expr, model::message &&m);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Move a message model to diagram.
|
* @brief Move a message model to diagram.
|
||||||
@@ -492,6 +506,7 @@ private:
|
|||||||
* @param expr Call expression
|
* @param expr Call expression
|
||||||
*/
|
*/
|
||||||
void pop_message_to_diagram(clang::CallExpr *expr);
|
void pop_message_to_diagram(clang::CallExpr *expr);
|
||||||
|
void pop_message_to_diagram(clang::CXXConstructExpr *expr);
|
||||||
|
|
||||||
// Reference to the output diagram model
|
// Reference to the output diagram model
|
||||||
clanguml::sequence_diagram::model::diagram &diagram_;
|
clanguml::sequence_diagram::model::diagram &diagram_;
|
||||||
@@ -507,6 +522,8 @@ private:
|
|||||||
* sequence after the visitor leaves the call expression AST node
|
* sequence after the visitor leaves the call expression AST node
|
||||||
*/
|
*/
|
||||||
std::map<clang::CallExpr *, model::message> call_expr_message_map_;
|
std::map<clang::CallExpr *, model::message> call_expr_message_map_;
|
||||||
|
std::map<clang::CXXConstructExpr *, model::message>
|
||||||
|
construct_expr_message_map_;
|
||||||
|
|
||||||
std::map<common::model::diagram_element::id_t,
|
std::map<common::model::diagram_element::id_t,
|
||||||
std::unique_ptr<clanguml::sequence_diagram::model::class_>>
|
std::unique_ptr<clanguml::sequence_diagram::model::class_>>
|
||||||
|
|||||||
15
tests/t20030/.clang-uml
Normal file
15
tests/t20030/.clang-uml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
compilation_database_dir: ..
|
||||||
|
output_directory: puml
|
||||||
|
diagrams:
|
||||||
|
t20030_sequence:
|
||||||
|
type: sequence
|
||||||
|
glob:
|
||||||
|
- ../../tests/t20030/t20030.cc
|
||||||
|
include:
|
||||||
|
namespaces:
|
||||||
|
- clanguml::t20030
|
||||||
|
using_namespace:
|
||||||
|
- clanguml::t20030
|
||||||
|
start_from:
|
||||||
|
- function: "clanguml::t20030::tmain(int)"
|
||||||
|
- function: "clanguml::t20030::tmain(bool,int)"
|
||||||
51
tests/t20030/t20030.cc
Normal file
51
tests/t20030/t20030.cc
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
namespace clanguml {
|
||||||
|
namespace t20030 {
|
||||||
|
|
||||||
|
int magic() { return 42; }
|
||||||
|
|
||||||
|
class A {
|
||||||
|
public:
|
||||||
|
A() { create(); }
|
||||||
|
|
||||||
|
A(int v) { a_ = v; }
|
||||||
|
|
||||||
|
A &operator=(const A &a)
|
||||||
|
{
|
||||||
|
set(a.a_);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
A &operator+=(int a)
|
||||||
|
{
|
||||||
|
add(a);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
int value() const { return a_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void create() { a_ = 0; }
|
||||||
|
|
||||||
|
void add(int a) { a_ += a; }
|
||||||
|
void set(int a) { a_ = a; }
|
||||||
|
|
||||||
|
int a_;
|
||||||
|
};
|
||||||
|
|
||||||
|
void tmain(int a)
|
||||||
|
{
|
||||||
|
A an_a{magic()};
|
||||||
|
an_a += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tmain(bool f, int a)
|
||||||
|
{
|
||||||
|
auto an_a = A();
|
||||||
|
auto an_b = A();
|
||||||
|
an_a += 2;
|
||||||
|
an_b = an_a;
|
||||||
|
return an_b.value();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
66
tests/t20030/test_case.h
Normal file
66
tests/t20030/test_case.h
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
/**
|
||||||
|
* tests/t20030/test_case.h
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021-2023 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("t20030", "[test-case][sequence]")
|
||||||
|
{
|
||||||
|
auto [config, db] = load_config("t20030");
|
||||||
|
|
||||||
|
auto diagram = config.diagrams["t20030_sequence"];
|
||||||
|
|
||||||
|
REQUIRE(diagram->name == "t20030_sequence");
|
||||||
|
|
||||||
|
auto model = generate_sequence_diagram(*db, diagram);
|
||||||
|
|
||||||
|
REQUIRE(model->name() == "t20030_sequence");
|
||||||
|
|
||||||
|
{
|
||||||
|
auto puml = generate_sequence_puml(diagram, *model);
|
||||||
|
AliasMatcher _A(puml);
|
||||||
|
|
||||||
|
REQUIRE_THAT(puml, StartsWith("@startuml"));
|
||||||
|
REQUIRE_THAT(puml, EndsWith("@enduml\n"));
|
||||||
|
|
||||||
|
// Check if all calls exist
|
||||||
|
REQUIRE_THAT(puml, HasCall(_A("tmain(int)"), _A("magic()"), ""));
|
||||||
|
|
||||||
|
REQUIRE_THAT(puml, HasCall(_A("A"), _A("A"), "create()"));
|
||||||
|
REQUIRE_THAT(
|
||||||
|
puml, HasCall(_A("tmain(int)"), _A("A"), "operator+=(int)"));
|
||||||
|
REQUIRE_THAT(puml, HasCall(_A("A"), _A("A"), "add(int)"));
|
||||||
|
|
||||||
|
REQUIRE_THAT(puml, HasCall(_A("tmain(bool,int)"), _A("A"), "A()"));
|
||||||
|
REQUIRE_THAT(
|
||||||
|
puml, HasCall(_A("tmain(bool,int)"), _A("A"), "operator+=(int)"));
|
||||||
|
REQUIRE_THAT(puml, HasCall(_A("A"), _A("A"), "add(int)"));
|
||||||
|
REQUIRE_THAT(puml,
|
||||||
|
HasCall(_A("tmain(bool,int)"), _A("A"), "operator=(const A &)"));
|
||||||
|
REQUIRE_THAT(puml, HasCall(_A("A"), _A("A"), "set(int)"));
|
||||||
|
REQUIRE_THAT(puml, HasCall(_A("tmain(bool,int)"), _A("A"), "value()"));
|
||||||
|
|
||||||
|
save_puml(
|
||||||
|
config.output_directory() + "/" + diagram->name + ".puml", puml);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto j = generate_sequence_json(diagram, *model);
|
||||||
|
|
||||||
|
using namespace json;
|
||||||
|
|
||||||
|
save_json(config.output_directory() + "/" + diagram->name + ".json", j);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -343,6 +343,7 @@ using namespace clanguml::test::matchers;
|
|||||||
#include "t20027/test_case.h"
|
#include "t20027/test_case.h"
|
||||||
#include "t20028/test_case.h"
|
#include "t20028/test_case.h"
|
||||||
#include "t20029/test_case.h"
|
#include "t20029/test_case.h"
|
||||||
|
#include "t20030/test_case.h"
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Package diagram tests
|
/// Package diagram tests
|
||||||
|
|||||||
@@ -146,6 +146,7 @@ public:
|
|||||||
util::replace_all(m_message, "*", "\\*");
|
util::replace_all(m_message, "*", "\\*");
|
||||||
util::replace_all(m_message, "[", "\\[");
|
util::replace_all(m_message, "[", "\\[");
|
||||||
util::replace_all(m_message, "]", "\\]");
|
util::replace_all(m_message, "]", "\\]");
|
||||||
|
util::replace_all(m_message, "+", "\\+");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool match(T const &in) const override
|
bool match(T const &in) const override
|
||||||
|
|||||||
@@ -286,6 +286,9 @@ test_cases:
|
|||||||
- name: t20029
|
- name: t20029
|
||||||
title: Combined feature sequence diagram test case
|
title: Combined feature sequence diagram test case
|
||||||
description:
|
description:
|
||||||
|
- name: t20030
|
||||||
|
title: Constructor and operator call test case
|
||||||
|
description:
|
||||||
Package diagrams:
|
Package diagrams:
|
||||||
- name: t30001
|
- name: t30001
|
||||||
title: Basic package diagram test case
|
title: Basic package diagram test case
|
||||||
|
|||||||
Reference in New Issue
Block a user