Fixed else if statement generation in sequence diagrams (Fixes #81)
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
# CHANGELOG
|
# CHANGELOG
|
||||||
|
|
||||||
|
* Fixed 'else if' statement generation in sequence diagrams (#81)
|
||||||
* Implemented removal of redundant dependency relationhips (#28)
|
* Implemented removal of redundant dependency relationhips (#28)
|
||||||
* Add option to disable generation of dependency relation to template
|
* Add option to disable generation of dependency relation to template
|
||||||
arguments (#141)
|
arguments (#141)
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ void generate_diagrams(const std::vector<std::string> &diagram_names,
|
|||||||
if (indicator)
|
if (indicator)
|
||||||
indicator->complete(name);
|
indicator->complete(name);
|
||||||
}
|
}
|
||||||
catch (std::runtime_error &e) {
|
catch (std::exception &e) {
|
||||||
if (indicator)
|
if (indicator)
|
||||||
indicator->fail(name);
|
indicator->fail(name);
|
||||||
|
|
||||||
|
|||||||
@@ -181,22 +181,27 @@ void call_expression_context::enter_ifstmt(clang::IfStmt *stmt)
|
|||||||
void call_expression_context::leave_ifstmt()
|
void call_expression_context::leave_ifstmt()
|
||||||
{
|
{
|
||||||
if (!if_stmt_stack_.empty()) {
|
if (!if_stmt_stack_.empty()) {
|
||||||
|
elseif_stmt_stacks_.erase(current_ifstmt());
|
||||||
if_stmt_stack_.pop();
|
if_stmt_stack_.pop();
|
||||||
std::stack<clang::IfStmt *>{}.swap(elseif_stmt_stack_);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void call_expression_context::enter_elseifstmt(clang::IfStmt *stmt)
|
void call_expression_context::enter_elseifstmt(clang::IfStmt *stmt)
|
||||||
{
|
{
|
||||||
elseif_stmt_stack_.push(stmt);
|
assert(current_ifstmt() != nullptr);
|
||||||
|
|
||||||
|
elseif_stmt_stacks_[current_ifstmt()].push(stmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
clang::IfStmt *call_expression_context::current_elseifstmt() const
|
clang::IfStmt *call_expression_context::current_elseifstmt() const
|
||||||
{
|
{
|
||||||
if (elseif_stmt_stack_.empty())
|
assert(current_ifstmt() != nullptr);
|
||||||
|
|
||||||
|
if (elseif_stmt_stacks_.count(current_ifstmt()) == 0 ||
|
||||||
|
elseif_stmt_stacks_.at(current_ifstmt()).empty())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
return elseif_stmt_stack_.top();
|
return elseif_stmt_stacks_.at(current_ifstmt()).top();
|
||||||
}
|
}
|
||||||
|
|
||||||
clang::Stmt *call_expression_context::current_loopstmt() const
|
clang::Stmt *call_expression_context::current_loopstmt() const
|
||||||
@@ -315,11 +320,11 @@ bool call_expression_context::is_expr_in_current_control_statement_condition(
|
|||||||
if (common::is_subexpr_of(condition_decl_stmt, stmt))
|
if (common::is_subexpr_of(condition_decl_stmt, stmt))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (current_elseifstmt() != nullptr) {
|
if (current_elseifstmt() != nullptr) {
|
||||||
if (common::is_subexpr_of(current_elseifstmt()->getCond(), stmt))
|
if (common::is_subexpr_of(current_elseifstmt()->getCond(), stmt))
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (current_conditionaloperator() != nullptr) {
|
if (current_conditionaloperator() != nullptr) {
|
||||||
|
|||||||
@@ -321,7 +321,7 @@ private:
|
|||||||
std::stack<callexpr_stack_t> 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::map<clang::IfStmt *, std::stack<clang::IfStmt *>> elseif_stmt_stacks_;
|
||||||
|
|
||||||
std::stack<clang::Stmt *> loop_stmt_stack_;
|
std::stack<clang::Stmt *> loop_stmt_stack_;
|
||||||
std::stack<clang::Stmt *> try_stmt_stack_;
|
std::stack<clang::Stmt *> try_stmt_stack_;
|
||||||
|
|||||||
@@ -539,7 +539,8 @@ bool translation_unit_visitor::TraverseCompoundStmt(clang::CompoundStmt *stmt)
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
const auto *current_ifstmt = context().current_ifstmt();
|
const auto *current_ifstmt = context().current_ifstmt();
|
||||||
const auto *current_elseifstmt = context().current_elseifstmt();
|
const auto *current_elseifstmt =
|
||||||
|
current_ifstmt != nullptr ? context().current_elseifstmt() : nullptr;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Add final else block (not else if)
|
// Add final else block (not else if)
|
||||||
@@ -583,6 +584,8 @@ bool translation_unit_visitor::TraverseIfStmt(clang::IfStmt *stmt)
|
|||||||
|
|
||||||
const auto current_caller_id = context().caller_id();
|
const auto current_caller_id = context().caller_id();
|
||||||
const auto *current_ifstmt = context().current_ifstmt();
|
const auto *current_ifstmt = context().current_ifstmt();
|
||||||
|
const auto *current_elseifstmt =
|
||||||
|
current_ifstmt != nullptr ? context().current_elseifstmt() : nullptr;
|
||||||
|
|
||||||
std::string condition_text;
|
std::string condition_text;
|
||||||
if (config().generate_condition_statements())
|
if (config().generate_condition_statements())
|
||||||
@@ -590,14 +593,18 @@ bool translation_unit_visitor::TraverseIfStmt(clang::IfStmt *stmt)
|
|||||||
|
|
||||||
// Check if this is a beginning of a new if statement, or an
|
// Check if this is a beginning of a new if statement, or an
|
||||||
// else if condition of the current if statement
|
// else if condition of the current if statement
|
||||||
if (current_ifstmt != nullptr) {
|
auto child_stmt_compare = [stmt](auto *child_stmt) {
|
||||||
for (const auto *child_stmt : current_ifstmt->children()) {
|
return child_stmt == stmt;
|
||||||
if (child_stmt == stmt) {
|
};
|
||||||
elseif_block = true;
|
|
||||||
break;
|
if (current_ifstmt != nullptr)
|
||||||
}
|
elseif_block = elseif_block ||
|
||||||
}
|
std::any_of(current_ifstmt->children().begin(),
|
||||||
}
|
current_ifstmt->children().end(), child_stmt_compare);
|
||||||
|
if (current_elseifstmt != nullptr)
|
||||||
|
elseif_block = elseif_block ||
|
||||||
|
std::any_of(current_elseifstmt->children().begin(),
|
||||||
|
current_elseifstmt->children().end(), child_stmt_compare);
|
||||||
|
|
||||||
if ((current_caller_id != 0) && !stmt->isConstexpr()) {
|
if ((current_caller_id != 0) && !stmt->isConstexpr()) {
|
||||||
if (elseif_block) {
|
if (elseif_block) {
|
||||||
@@ -620,10 +627,12 @@ bool translation_unit_visitor::TraverseIfStmt(clang::IfStmt *stmt)
|
|||||||
|
|
||||||
RecursiveASTVisitor<translation_unit_visitor>::TraverseIfStmt(stmt);
|
RecursiveASTVisitor<translation_unit_visitor>::TraverseIfStmt(stmt);
|
||||||
|
|
||||||
if ((current_caller_id != 0) && !stmt->isConstexpr() && !elseif_block) {
|
if ((current_caller_id != 0) && !stmt->isConstexpr()) {
|
||||||
diagram().end_block_message(
|
if (!elseif_block) {
|
||||||
{message_t::kIfEnd, current_caller_id}, message_t::kIf);
|
diagram().end_block_message(
|
||||||
context().leave_ifstmt();
|
{message_t::kIfEnd, current_caller_id}, message_t::kIf);
|
||||||
|
context().leave_ifstmt();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ struct A {
|
|||||||
int a2() { return 1; }
|
int a2() { return 1; }
|
||||||
int a3() { return 2; }
|
int a3() { return 2; }
|
||||||
int a4() { return 3; }
|
int a4() { return 3; }
|
||||||
|
int a5() { return 4; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct B {
|
struct B {
|
||||||
@@ -48,6 +49,9 @@ int tmain()
|
|||||||
if (reinterpret_cast<uint64_t>(&a) % 100 == 0ULL) {
|
if (reinterpret_cast<uint64_t>(&a) % 100 == 0ULL) {
|
||||||
result = a.a1();
|
result = a.a1();
|
||||||
}
|
}
|
||||||
|
else if (reinterpret_cast<uint64_t>(&a) % 100 == 42ULL) {
|
||||||
|
result = a.a5();
|
||||||
|
}
|
||||||
else if (reinterpret_cast<uint64_t>(&a) % 64 == 0ULL) {
|
else if (reinterpret_cast<uint64_t>(&a) % 64 == 0ULL) {
|
||||||
if (c.c3(a.a2()) > 2)
|
if (c.c3(a.a2()) > 2)
|
||||||
result = b.b1();
|
result = b.b1();
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ TEST_CASE("t20020", "[test-case][sequence]")
|
|||||||
using namespace json;
|
using namespace json;
|
||||||
|
|
||||||
std::vector<int> messages = {FindMessage(j, "tmain()", "A", "a1()"),
|
std::vector<int> messages = {FindMessage(j, "tmain()", "A", "a1()"),
|
||||||
|
FindMessage(j, "tmain()", "A", "a5()"),
|
||||||
FindMessage(j, "tmain()", "A", "a2()"),
|
FindMessage(j, "tmain()", "A", "a2()"),
|
||||||
FindMessage(j, "tmain()", "C", "c3(int)"),
|
FindMessage(j, "tmain()", "C", "c3(int)"),
|
||||||
FindMessage(j, "tmain()", "B", "b1()"),
|
FindMessage(j, "tmain()", "B", "b1()"),
|
||||||
|
|||||||
@@ -10,4 +10,4 @@ plantuml:
|
|||||||
before:
|
before:
|
||||||
- 'title clang-uml clanguml::class_diagram::generators::plantuml::generator sequence diagram'
|
- 'title clang-uml clanguml::class_diagram::generators::plantuml::generator sequence diagram'
|
||||||
start_from:
|
start_from:
|
||||||
- function: "clanguml::class_diagram::generators::plantuml::generator::generate(std::ostream &) const"
|
- function: "clanguml::common::generators::plantuml::generator<clanguml::config::class_diagram,clanguml::class_diagram::model::diagram>::generate(std::ostream &) const"
|
||||||
Reference in New Issue
Block a user