Refactored lambda naming in sequence diagrams

This commit is contained in:
Bartek Kryza
2022-12-04 13:19:44 +01:00
parent f07b35802a
commit b87c6acd44
6 changed files with 98 additions and 32 deletions

View File

@@ -164,6 +164,8 @@ std::string get_source_text(
return get_source_text_raw(printable_range, sm); return get_source_text_raw(printable_range, sm);
} }
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;

View File

@@ -36,6 +36,13 @@ generator::generator(
{ {
} }
std::string generator::render_name(std::string name) const
{
util::replace_all(name, "##", "::");
return name;
}
void generator::generate_call(const message &m, std::ostream &ostr) const void generator::generate_call(const message &m, std::ostream &ostr) const
{ {
const auto &from = m_model.get_participant<model::participant>(m.from); const auto &from = m_model.get_participant<model::participant>(m.from);
@@ -142,8 +149,8 @@ void generator::generate_participant(std::ostream &ostr, common::id_t id) const
m_model.get_participant<model::participant>(class_id).value(); m_model.get_participant<model::participant>(class_id).value();
ostr << "participant \"" ostr << "participant \""
<< m_config.using_namespace().relative( << render_name(m_config.using_namespace().relative(
class_participant.full_name(false)) class_participant.full_name(false)))
<< "\" as " << class_participant.alias() << '\n'; << "\" as " << class_participant.alias() << '\n';
generated_participants_.emplace(class_id); generated_participants_.emplace(class_id);

View File

@@ -63,6 +63,8 @@ public:
private: private:
bool is_participant_generated(common::id_t id) const; bool is_participant_generated(common::id_t id) const;
std::string render_name(std::string name) const;
mutable std::set<common::id_t> generated_participants_; mutable std::set<common::id_t> generated_participants_;
}; };

View File

@@ -68,11 +68,22 @@ call_expression_context &translation_unit_visitor::context()
return call_expression_context_; return call_expression_context_;
} }
const call_expression_context &translation_unit_visitor::context() const
{
return call_expression_context_;
}
clanguml::sequence_diagram::model::diagram &translation_unit_visitor::diagram() clanguml::sequence_diagram::model::diagram &translation_unit_visitor::diagram()
{ {
return diagram_; return diagram_;
} }
const clanguml::sequence_diagram::model::diagram &
translation_unit_visitor::diagram() const
{
return diagram_;
}
const clanguml::config::sequence_diagram & const clanguml::config::sequence_diagram &
translation_unit_visitor::config() const translation_unit_visitor::config() const
{ {
@@ -920,15 +931,8 @@ translation_unit_visitor::create_class_declaration(clang::CXXRecordDecl *cls)
else if (cls->isLambda()) { else if (cls->isLambda()) {
c.is_lambda(true); c.is_lambda(true);
if (cls->getParent()) { if (cls->getParent()) {
auto parent_full_name = get_participant(context().caller_id()) const auto type_name = make_lambda_name(cls);
.value()
.full_name_no_ns();
const auto location = cls->getLocation();
const auto type_name =
fmt::format("{}##(lambda {}:{})", parent_full_name,
source_manager().getSpellingLineNumber(location),
source_manager().getSpellingColumnNumber(location));
c.set_name(type_name); c.set_name(type_name);
c.set_namespace(ns); c.set_namespace(ns);
c.set_id(common::to_id(c.full_name(false))); c.set_id(common::to_id(c.full_name(false)));
@@ -1370,17 +1374,8 @@ void translation_unit_visitor::process_template_specialization_argument(
.full_name(false)); .full_name(false));
} }
else { else {
auto parent_full_name = get_participant(context().caller_id())
.value()
.full_name_no_ns();
const auto location =
arg.getAsType()->getAsCXXRecordDecl()->getLocation();
const auto type_name = const auto type_name =
fmt::format("{}##(lambda {}:{})", parent_full_name, make_lambda_name(arg.getAsType()->getAsCXXRecordDecl());
source_manager().getSpellingLineNumber(location),
source_manager().getSpellingColumnNumber(location));
argument.set_name(type_name); argument.set_name(type_name);
} }
} }
@@ -1680,6 +1675,32 @@ bool translation_unit_visitor::simplify_system_template(
return false; return false;
} }
std::string translation_unit_visitor::make_lambda_name(
const clang::CXXRecordDecl *cls) const
{
std::string result;
const auto location = cls->getLocation();
const auto file_line = source_manager().getSpellingLineNumber(location);
const auto file_column = source_manager().getSpellingColumnNumber(location);
const std::string file_name =
util::split(source_manager().getFilename(location).str(), "/").back();
if (context().caller_id() != 0 &&
get_participant(context().caller_id()).has_value()) {
auto parent_full_name =
get_participant(context().caller_id()).value().full_name_no_ns();
result = fmt::format("{}##(lambda {}:{}:{})", parent_full_name,
file_name, file_line, file_column);
}
else {
result =
fmt::format("(lambda {}:{}:{})", file_name, file_line, file_column);
}
return result;
}
void translation_unit_visitor::finalize() void translation_unit_visitor::finalize()
{ {
for (auto &[id, activity] : diagram().sequences) { for (auto &[id, activity] : diagram().sequences) {

View File

@@ -17,10 +17,10 @@
*/ */
#pragma once #pragma once
#include "call_expression_context.h"
#include "common/visitor/translation_unit_visitor.h" #include "common/visitor/translation_unit_visitor.h"
#include "config/config.h" #include "config/config.h"
#include "sequence_diagram/model/diagram.h" #include "sequence_diagram/model/diagram.h"
#include "call_expression_context.h"
#include <clang/AST/Expr.h> #include <clang/AST/Expr.h>
#include <clang/AST/RecursiveASTVisitor.h> #include <clang/AST/RecursiveASTVisitor.h>
@@ -64,10 +64,14 @@ public:
clanguml::sequence_diagram::model::diagram &diagram(); clanguml::sequence_diagram::model::diagram &diagram();
const clanguml::sequence_diagram::model::diagram &diagram() const;
const clanguml::config::sequence_diagram &config() const; const clanguml::config::sequence_diagram &config() const;
call_expression_context &context(); call_expression_context &context();
const call_expression_context &context() const;
void finalize(); void finalize();
template <typename T = model::participant> template <typename T = model::participant>
@@ -82,6 +86,18 @@ public:
return get_participant<T>(unique_participant_id.value()); return get_participant<T>(unique_participant_id.value());
} }
template <typename T = model::participant>
const common::optional_ref<T> get_participant(const clang::Decl *decl) const
{
assert(decl != nullptr);
auto unique_participant_id = get_unique_id(decl->getID());
if (!unique_participant_id.has_value())
return {};
return get_participant<T>(unique_participant_id.value());
}
template <typename T = model::participant> template <typename T = model::participant>
common::optional_ref<T> get_participant( common::optional_ref<T> get_participant(
const common::model::diagram_element::id_t id) const common::model::diagram_element::id_t id)
@@ -93,6 +109,17 @@ public:
*(static_cast<T *>(diagram().participants.at(id).get()))); *(static_cast<T *>(diagram().participants.at(id).get())));
} }
template <typename T = model::participant>
const common::optional_ref<T> get_participant(
const common::model::diagram_element::id_t id) const
{
if (diagram().participants.find(id) == diagram().participants.end())
return {};
return common::optional_ref<T>(
*(static_cast<T *>(diagram().participants.at(id).get())));
}
/// Store the mapping from local clang entity id (obtained using /// Store the mapping from local clang entity id (obtained using
/// getID()) method to clang-uml global id /// getID()) method to clang-uml global id
void set_unique_id( void set_unique_id(
@@ -168,6 +195,8 @@ private:
bool simplify_system_template(class_diagram::model::template_parameter &ct, bool simplify_system_template(class_diagram::model::template_parameter &ct,
const std::string &full_name); const std::string &full_name);
std::string make_lambda_name(const clang::CXXRecordDecl *cls) const;
bool is_smart_pointer(const clang::TemplateDecl *primary_template) const; bool is_smart_pointer(const clang::TemplateDecl *primary_template) const;
bool is_callee_valid_template_specialization( bool is_callee_valid_template_specialization(

View File

@@ -36,30 +36,35 @@ TEST_CASE("t20012", "[test-case][sequence]")
// Check if all calls exist // Check if all calls exist
REQUIRE_THAT(puml, REQUIRE_THAT(puml,
HasCall(_A("tmain()"), _A("tmain()##(lambda 49:20)"), "operator()")); HasCall(_A("tmain()"), _A("tmain()::(lambda t20012.cc:49:20)"),
REQUIRE_THAT(puml, HasCall(_A("tmain()##(lambda 49:20)"), _A("A"), "a")); "operator()"));
REQUIRE_THAT(
puml, HasCall(_A("tmain()::(lambda t20012.cc:49:20)"), _A("A"), "a"));
REQUIRE_THAT(puml, HasCall(_A("A"), _A("A"), "aa")); REQUIRE_THAT(puml, HasCall(_A("A"), _A("A"), "aa"));
REQUIRE_THAT(puml, HasCall(_A("A"), _A("A"), "aaa")); REQUIRE_THAT(puml, HasCall(_A("A"), _A("A"), "aaa"));
REQUIRE_THAT(puml, HasCall(_A("tmain()##(lambda 49:20)"), _A("B"), "b")); REQUIRE_THAT(
puml, HasCall(_A("tmain()::(lambda t20012.cc:49:20)"), _A("B"), "b"));
REQUIRE_THAT(puml, HasCall(_A("B"), _A("B"), "bb")); REQUIRE_THAT(puml, HasCall(_A("B"), _A("B"), "bb"));
REQUIRE_THAT(puml, HasCall(_A("B"), _A("B"), "bbb")); REQUIRE_THAT(puml, HasCall(_A("B"), _A("B"), "bbb"));
REQUIRE_THAT(puml, HasCall(_A("tmain()##(lambda 62:20)"), _A("C"), "c")); REQUIRE_THAT(
puml, HasCall(_A("tmain()::(lambda t20012.cc:62:20)"), _A("C"), "c"));
REQUIRE_THAT(puml, HasCall(_A("C"), _A("C"), "cc")); REQUIRE_THAT(puml, HasCall(_A("C"), _A("C"), "cc"));
REQUIRE_THAT(puml, HasCall(_A("C"), _A("C"), "ccc")); REQUIRE_THAT(puml, HasCall(_A("C"), _A("C"), "ccc"));
REQUIRE_THAT(puml, REQUIRE_THAT(puml,
HasCall(_A("tmain()##(lambda 62:20)"), _A("tmain()##(lambda 49:20)"), HasCall(_A("tmain()::(lambda t20012.cc:62:20)"),
"operator()")); _A("tmain()::(lambda t20012.cc:49:20)"), "operator()"));
REQUIRE_THAT(puml, HasCall(_A("C"), _A("C"), "ccc")); REQUIRE_THAT(puml, HasCall(_A("C"), _A("C"), "ccc"));
REQUIRE_THAT(puml, HasCall(_A("tmain()"), _A("R<R##(lambda 68:9)>"), "r"));
REQUIRE_THAT(puml,
HasCall(_A("R<R##(lambda 68:9)>"), _A("tmain()##(lambda 68:9)"),
"operator()"));
REQUIRE_THAT( REQUIRE_THAT(
puml, HasCall(_A("tmain()##(lambda 68:9)"), _A("C"), "c")); puml, HasCall(_A("tmain()"), _A("R<R::(lambda t20012.cc:68:9)>"), "r"));
REQUIRE_THAT(puml,
HasCall(_A("R<R::(lambda t20012.cc:68:9)>"),
_A("tmain()::(lambda t20012.cc:68:9)"), "operator()"));
REQUIRE_THAT(
puml, HasCall(_A("tmain()::(lambda t20012.cc:68:9)"), _A("C"), "c"));
save_puml( save_puml(
"./" + config.output_directory() + "/" + diagram->name + ".puml", puml); "./" + config.output_directory() + "/" + diagram->name + ".puml", puml);