From b87c6acd4487d2db4ef0d898e9987946b9273560 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Sun, 4 Dec 2022 13:19:44 +0100 Subject: [PATCH] Refactored lambda naming in sequence diagrams --- src/common/clang_utils.cc | 2 + .../plantuml/sequence_diagram_generator.cc | 11 +++- .../plantuml/sequence_diagram_generator.h | 2 + .../visitor/translation_unit_visitor.cc | 57 +++++++++++++------ .../visitor/translation_unit_visitor.h | 31 +++++++++- tests/t20012/test_case.h | 27 +++++---- 6 files changed, 98 insertions(+), 32 deletions(-) diff --git a/src/common/clang_utils.cc b/src/common/clang_utils.cc index c5fec542..e02210e9 100644 --- a/src/common/clang_utils.cc +++ b/src/common/clang_utils.cc @@ -164,6 +164,8 @@ std::string get_source_text( return get_source_text_raw(printable_range, sm); } + + template <> id_t to_id(const std::string &full_name) { return std::hash{}(full_name) >> 3; diff --git a/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc index a425c010..d775e103 100644 --- a/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc +++ b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc @@ -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 { const auto &from = m_model.get_participant(m.from); @@ -142,8 +149,8 @@ void generator::generate_participant(std::ostream &ostr, common::id_t id) const m_model.get_participant(class_id).value(); ostr << "participant \"" - << m_config.using_namespace().relative( - class_participant.full_name(false)) + << render_name(m_config.using_namespace().relative( + class_participant.full_name(false))) << "\" as " << class_participant.alias() << '\n'; generated_participants_.emplace(class_id); diff --git a/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.h b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.h index e2148bee..98273676 100644 --- a/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.h +++ b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.h @@ -63,6 +63,8 @@ public: private: bool is_participant_generated(common::id_t id) const; + std::string render_name(std::string name) const; + mutable std::set generated_participants_; }; diff --git a/src/sequence_diagram/visitor/translation_unit_visitor.cc b/src/sequence_diagram/visitor/translation_unit_visitor.cc index a813b64e..a9163e04 100644 --- a/src/sequence_diagram/visitor/translation_unit_visitor.cc +++ b/src/sequence_diagram/visitor/translation_unit_visitor.cc @@ -68,11 +68,22 @@ call_expression_context &translation_unit_visitor::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() { return diagram_; } +const clanguml::sequence_diagram::model::diagram & +translation_unit_visitor::diagram() const +{ + return diagram_; +} + const clanguml::config::sequence_diagram & translation_unit_visitor::config() const { @@ -920,15 +931,8 @@ translation_unit_visitor::create_class_declaration(clang::CXXRecordDecl *cls) else if (cls->isLambda()) { c.is_lambda(true); if (cls->getParent()) { - auto parent_full_name = get_participant(context().caller_id()) - .value() - .full_name_no_ns(); + const auto type_name = make_lambda_name(cls); - 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_namespace(ns); 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)); } 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 = - fmt::format("{}##(lambda {}:{})", parent_full_name, - source_manager().getSpellingLineNumber(location), - source_manager().getSpellingColumnNumber(location)); - + make_lambda_name(arg.getAsType()->getAsCXXRecordDecl()); argument.set_name(type_name); } } @@ -1680,6 +1675,32 @@ bool translation_unit_visitor::simplify_system_template( 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() { for (auto &[id, activity] : diagram().sequences) { diff --git a/src/sequence_diagram/visitor/translation_unit_visitor.h b/src/sequence_diagram/visitor/translation_unit_visitor.h index 060d49cd..90fafbe7 100644 --- a/src/sequence_diagram/visitor/translation_unit_visitor.h +++ b/src/sequence_diagram/visitor/translation_unit_visitor.h @@ -17,10 +17,10 @@ */ #pragma once +#include "call_expression_context.h" #include "common/visitor/translation_unit_visitor.h" #include "config/config.h" #include "sequence_diagram/model/diagram.h" -#include "call_expression_context.h" #include #include @@ -64,10 +64,14 @@ public: clanguml::sequence_diagram::model::diagram &diagram(); + const clanguml::sequence_diagram::model::diagram &diagram() const; + const clanguml::config::sequence_diagram &config() const; call_expression_context &context(); + const call_expression_context &context() const; + void finalize(); template @@ -82,6 +86,18 @@ public: return get_participant(unique_participant_id.value()); } + template + const common::optional_ref 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(unique_participant_id.value()); + } + template common::optional_ref get_participant( const common::model::diagram_element::id_t id) @@ -93,6 +109,17 @@ public: *(static_cast(diagram().participants.at(id).get()))); } + template + const common::optional_ref get_participant( + const common::model::diagram_element::id_t id) const + { + if (diagram().participants.find(id) == diagram().participants.end()) + return {}; + + return common::optional_ref( + *(static_cast(diagram().participants.at(id).get()))); + } + /// Store the mapping from local clang entity id (obtained using /// getID()) method to clang-uml global id void set_unique_id( @@ -168,6 +195,8 @@ private: bool simplify_system_template(class_diagram::model::template_parameter &ct, 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_callee_valid_template_specialization( diff --git a/tests/t20012/test_case.h b/tests/t20012/test_case.h index 16681581..bc789226 100644 --- a/tests/t20012/test_case.h +++ b/tests/t20012/test_case.h @@ -36,30 +36,35 @@ TEST_CASE("t20012", "[test-case][sequence]") // Check if all calls exist REQUIRE_THAT(puml, - HasCall(_A("tmain()"), _A("tmain()##(lambda 49:20)"), "operator()")); - REQUIRE_THAT(puml, HasCall(_A("tmain()##(lambda 49:20)"), _A("A"), "a")); + HasCall(_A("tmain()"), _A("tmain()::(lambda t20012.cc:49:20)"), + "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"), "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"), "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"), "ccc")); REQUIRE_THAT(puml, - HasCall(_A("tmain()##(lambda 62:20)"), _A("tmain()##(lambda 49:20)"), - "operator()")); + HasCall(_A("tmain()::(lambda t20012.cc:62:20)"), + _A("tmain()::(lambda t20012.cc:49:20)"), "operator()")); REQUIRE_THAT(puml, HasCall(_A("C"), _A("C"), "ccc")); - REQUIRE_THAT(puml, HasCall(_A("tmain()"), _A("R"), "r")); - REQUIRE_THAT(puml, - HasCall(_A("R"), _A("tmain()##(lambda 68:9)"), - "operator()")); REQUIRE_THAT( - puml, HasCall(_A("tmain()##(lambda 68:9)"), _A("C"), "c")); + puml, HasCall(_A("tmain()"), _A("R"), "r")); + REQUIRE_THAT(puml, + HasCall(_A("R"), + _A("tmain()::(lambda t20012.cc:68:9)"), "operator()")); + REQUIRE_THAT( + puml, HasCall(_A("tmain()::(lambda t20012.cc:68:9)"), _A("C"), "c")); save_puml( "./" + config.output_directory() + "/" + diagram->name + ".puml", puml);