Added highlight of calls within condition statements of if/else blocks
This commit is contained in:
@@ -164,6 +164,22 @@ std::string get_source_text(
|
|||||||
return get_source_text_raw(printable_range, sm);
|
return get_source_text_raw(printable_range, sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_subexpr_of(const clang::Stmt *parent_stmt, const clang::Stmt *sub_stmt)
|
||||||
|
{
|
||||||
|
if (parent_stmt == nullptr || sub_stmt == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (parent_stmt == sub_stmt)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for (const auto *e : parent_stmt->children()) {
|
||||||
|
if (is_subexpr_of(e, sub_stmt))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
template <> id_t to_id(const std::string &full_name)
|
template <> id_t to_id(const std::string &full_name)
|
||||||
{
|
{
|
||||||
return std::hash<std::string>{}(full_name) >> 3;
|
return std::hash<std::string>{}(full_name) >> 3;
|
||||||
|
|||||||
@@ -68,6 +68,8 @@ std::string get_source_text_raw(
|
|||||||
std::string get_source_text(
|
std::string get_source_text(
|
||||||
clang::SourceRange range, const clang::SourceManager &sm);
|
clang::SourceRange range, const clang::SourceManager &sm);
|
||||||
|
|
||||||
|
bool is_subexpr_of(const clang::Stmt *parent_stmt, const clang::Stmt *sub_stmt);
|
||||||
|
|
||||||
template <typename T> id_t to_id(const T &declaration);
|
template <typename T> id_t to_id(const T &declaration);
|
||||||
|
|
||||||
template <> id_t to_id(const std::string &full_name);
|
template <> id_t to_id(const std::string &full_name);
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ enum class relationship_t {
|
|||||||
kDependency
|
kDependency
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Types of sequence diagram activity elements
|
||||||
enum class message_t {
|
enum class message_t {
|
||||||
kCall,
|
kCall,
|
||||||
kReturn,
|
kReturn,
|
||||||
@@ -55,6 +56,13 @@ enum class message_t {
|
|||||||
kNone
|
kNone
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// The scope of the call expression represented in the sequence diagram
|
||||||
|
enum class message_scope_t {
|
||||||
|
kNormal, // This is a regular call expression
|
||||||
|
kCondition // This is a call expression from within a control condition
|
||||||
|
// e.g if(a->is_valid()) { ... }
|
||||||
|
};
|
||||||
|
|
||||||
std::string to_string(relationship_t r);
|
std::string to_string(relationship_t r);
|
||||||
|
|
||||||
std::string to_string(access_t r);
|
std::string to_string(access_t r);
|
||||||
|
|||||||
@@ -79,14 +79,25 @@ void generator::generate_call(const message &m, std::ostream &ostr) const
|
|||||||
const std::string to_alias = generate_alias(to.value());
|
const std::string to_alias = generate_alias(to.value());
|
||||||
|
|
||||||
ostr << from_alias << " "
|
ostr << from_alias << " "
|
||||||
<< common::generators::plantuml::to_plantuml(message_t::kCall) << " "
|
<< common::generators::plantuml::to_plantuml(message_t::kCall) << " ";
|
||||||
<< to_alias;
|
|
||||||
|
ostr << to_alias;
|
||||||
|
|
||||||
if (m_config.generate_links) {
|
if (m_config.generate_links) {
|
||||||
common_generator<diagram_config, diagram_model>::generate_link(ostr, m);
|
common_generator<diagram_config, diagram_model>::generate_link(ostr, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
ostr << " : " << message << std::endl;
|
ostr << " : ";
|
||||||
|
|
||||||
|
if (m.message_scope() == common::model::message_scope_t::kCondition)
|
||||||
|
ostr << "**[**";
|
||||||
|
|
||||||
|
ostr << message;
|
||||||
|
|
||||||
|
if (m.message_scope() == common::model::message_scope_t::kCondition)
|
||||||
|
ostr << "**]**";
|
||||||
|
|
||||||
|
ostr << '\n';
|
||||||
|
|
||||||
LOG_DBG("Generated call '{}' from {} [{}] to {} [{}]", message, from,
|
LOG_DBG("Generated call '{}' from {} [{}] to {} [{}]", message, from,
|
||||||
m.from(), to, m.to());
|
m.from(), to, m.to());
|
||||||
|
|||||||
@@ -50,4 +50,11 @@ void message::set_return_type(std::string t) { return_type_ = std::move(t); }
|
|||||||
|
|
||||||
const std::string &message::return_type() const { return return_type_; }
|
const std::string &message::return_type() const { return return_type_; }
|
||||||
|
|
||||||
|
void message::set_message_scope(common::model::message_scope_t scope)
|
||||||
|
{
|
||||||
|
scope_ = scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
common::model::message_scope_t message::message_scope() const { return scope_; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,9 @@ public:
|
|||||||
void set_return_type(std::string t);
|
void set_return_type(std::string t);
|
||||||
const std::string &return_type() const;
|
const std::string &return_type() const;
|
||||||
|
|
||||||
|
void set_message_scope(common::model::message_scope_t scope);
|
||||||
|
common::model::message_scope_t message_scope() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
common::model::message_t type_{common::model::message_t::kNone};
|
common::model::message_t type_{common::model::message_t::kNone};
|
||||||
|
|
||||||
@@ -54,6 +57,9 @@ private:
|
|||||||
|
|
||||||
common::model::diagram_element::id_t to_{};
|
common::model::diagram_element::id_t to_{};
|
||||||
|
|
||||||
|
common::model::message_scope_t scope_{
|
||||||
|
common::model::message_scope_t::kNormal};
|
||||||
|
|
||||||
// This is only for better verbose messages, we cannot rely on this
|
// This is only for better verbose messages, we cannot rely on this
|
||||||
// always
|
// always
|
||||||
std::string message_name_{};
|
std::string message_name_{};
|
||||||
|
|||||||
@@ -732,6 +732,7 @@ bool translation_unit_visitor::TraverseCXXForRangeStmt(
|
|||||||
|
|
||||||
bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
|
bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
|
||||||
{
|
{
|
||||||
|
using clanguml::common::model::message_scope_t;
|
||||||
using clanguml::common::model::message_t;
|
using clanguml::common::model::message_t;
|
||||||
using clanguml::common::model::namespace_;
|
using clanguml::common::model::namespace_;
|
||||||
using clanguml::sequence_diagram::model::activity;
|
using clanguml::sequence_diagram::model::activity;
|
||||||
@@ -774,6 +775,20 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (context().current_ifstmt()) {
|
||||||
|
if (common::is_subexpr_of(
|
||||||
|
context().current_ifstmt()->getCond(), expr)) {
|
||||||
|
m.set_message_scope(common::model::message_scope_t::kCondition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context().current_elseifstmt()) {
|
||||||
|
if (common::is_subexpr_of(
|
||||||
|
context().current_elseifstmt()->getCond(), expr)) {
|
||||||
|
m.set_message_scope(common::model::message_scope_t::kCondition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (const auto *operator_call_expr =
|
if (const auto *operator_call_expr =
|
||||||
clang::dyn_cast_or_null<clang::CXXOperatorCallExpr>(expr);
|
clang::dyn_cast_or_null<clang::CXXOperatorCallExpr>(expr);
|
||||||
operator_call_expr != nullptr) {
|
operator_call_expr != nullptr) {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ struct A {
|
|||||||
int a1() { return 0; }
|
int a1() { return 0; }
|
||||||
int a2() { return 1; }
|
int a2() { return 1; }
|
||||||
int a3() { return 2; }
|
int a3() { return 2; }
|
||||||
|
int a4() { return 3; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct B {
|
struct B {
|
||||||
@@ -26,6 +27,8 @@ struct C {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool c2() const { return true; }
|
bool c2() const { return true; }
|
||||||
|
|
||||||
|
int c3(int x) { return x * 2; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T> struct D {
|
template <typename T> struct D {
|
||||||
@@ -46,13 +49,15 @@ int tmain()
|
|||||||
result = a.a1();
|
result = a.a1();
|
||||||
}
|
}
|
||||||
else if (reinterpret_cast<uint64_t>(&a) % 64 == 0ULL) {
|
else if (reinterpret_cast<uint64_t>(&a) % 64 == 0ULL) {
|
||||||
if (a.a2() > 2)
|
if (c.c3(a.a2()) > 2)
|
||||||
result = b.b1();
|
result = b.b1();
|
||||||
else
|
else if (a.a3() % 2)
|
||||||
result = b.b2();
|
result = b.b2();
|
||||||
|
else
|
||||||
|
result = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
result = a.a3();
|
result = a.a4();
|
||||||
}
|
}
|
||||||
|
|
||||||
b.log();
|
b.log();
|
||||||
|
|||||||
@@ -36,14 +36,19 @@ TEST_CASE("t20020", "[test-case][sequence]")
|
|||||||
|
|
||||||
// Check if all calls exist
|
// Check if all calls exist
|
||||||
REQUIRE_THAT(puml, HasCall(_A("tmain()"), _A("A"), "a1()"));
|
REQUIRE_THAT(puml, HasCall(_A("tmain()"), _A("A"), "a1()"));
|
||||||
REQUIRE_THAT(puml, HasCall(_A("tmain()"), _A("A"), "a2()"));
|
REQUIRE_THAT(
|
||||||
REQUIRE_THAT(puml, HasCall(_A("tmain()"), _A("A"), "a3()"));
|
puml, HasCallInControlCondition(_A("tmain()"), _A("A"), "a2()"));
|
||||||
|
REQUIRE_THAT(
|
||||||
|
puml, HasCallInControlCondition(_A("tmain()"), _A("A"), "a3()"));
|
||||||
|
|
||||||
REQUIRE_THAT(puml, HasCall(_A("tmain()"), _A("B"), "b1()"));
|
REQUIRE_THAT(puml, HasCall(_A("tmain()"), _A("B"), "b1()"));
|
||||||
REQUIRE_THAT(puml, HasCall(_A("tmain()"), _A("B"), "b2()"));
|
REQUIRE_THAT(puml, HasCall(_A("tmain()"), _A("B"), "b2()"));
|
||||||
REQUIRE_THAT(puml, HasCall(_A("tmain()"), _A("B"), "log()"));
|
REQUIRE_THAT(puml, HasCall(_A("tmain()"), _A("B"), "log()"));
|
||||||
|
|
||||||
REQUIRE_THAT(puml, HasCall(_A("tmain()"), _A("C"), "c1()"));
|
REQUIRE_THAT(puml, HasCall(_A("tmain()"), _A("C"), "c1()"));
|
||||||
|
REQUIRE_THAT(puml, HasCallInControlCondition(_A("C"), _A("C"), "c2()"));
|
||||||
|
REQUIRE_THAT(
|
||||||
|
puml, HasCallInControlCondition(_A("tmain()"), _A("C"), "c3(int)"));
|
||||||
|
|
||||||
save_puml(
|
save_puml(
|
||||||
"./" + config.output_directory() + "/" + diagram->name + ".puml", puml);
|
"./" + config.output_directory() + "/" + diagram->name + ".puml", puml);
|
||||||
|
|||||||
@@ -132,8 +132,10 @@ public:
|
|||||||
, m_message{message}
|
, m_message{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, "*", "\\*");
|
||||||
|
util::replace_all(m_message, "[", "\\[");
|
||||||
|
util::replace_all(m_message, "]", "\\]");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool match(T const &in) const override
|
bool match(T const &in) const override
|
||||||
@@ -169,6 +171,13 @@ auto HasCall(std::string const &from, std::string const &to,
|
|||||||
return HasCallMatcher(from, to, message);
|
return HasCallMatcher(from, to, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto HasCallInControlCondition(std::string const &from, std::string const &to,
|
||||||
|
std::string const &message,
|
||||||
|
CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
|
||||||
|
{
|
||||||
|
return HasCallMatcher(from, to, fmt::format("**[**{}**]**", message));
|
||||||
|
}
|
||||||
|
|
||||||
auto HasCall(std::string const &from, std::string const &message,
|
auto HasCall(std::string const &from, std::string const &message,
|
||||||
CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
|
CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user