Added smart pointer dereference sequence diagram test case

This commit is contained in:
Bartek Kryza
2022-11-29 22:08:46 +01:00
parent f1af5460e3
commit 0e3c69ce38
7 changed files with 161 additions and 18 deletions

View File

@@ -279,32 +279,29 @@ bool translation_unit_visitor::VisitCXXMethodDecl(clang::CXXMethodDecl *m)
LOG_DBG("Getting method's class with local id {}", parent_decl->getID()); LOG_DBG("Getting method's class with local id {}", parent_decl->getID());
set_unique_id(m->getID(), m_ptr->id());
const auto &method_class = const auto &method_class =
diagram() get_participant<model::class_>(parent_decl).value();
.get_participant<model::class_>(
get_unique_id(parent_decl->getID()).value())
.value();
m_ptr->set_class_id(method_class.id()); m_ptr->set_class_id(method_class.id());
m_ptr->set_class_full_name(method_class.full_name(false)); m_ptr->set_class_full_name(method_class.full_name(false));
m_ptr->set_name( m_ptr->set_name(
diagram().participants.at(m_ptr->class_id())->full_name_no_ns() + get_participant(m_ptr->class_id()).value().full_name_no_ns() +
"::" + m->getNameAsString()); "::" + m->getNameAsString());
m_ptr->set_id(common::to_id( m_ptr->set_id(common::to_id(
diagram().participants.at(m_ptr->class_id())->full_name(false) + get_participant(m_ptr->class_id()).value().full_name(false) +
"::" + m->getNameAsString())); "::" + m->getNameAsString()));
LOG_DBG("Set id {} for method name {}", m_ptr->id(), LOG_DBG("Set id {} for method name {}", m_ptr->id(),
diagram().participants.at(m_ptr->class_id())->full_name(false) + get_participant(m_ptr->class_id()).value().full_name(false) +
"::" + m->getNameAsString()); "::" + m->getNameAsString());
context().update(m); context().update(m);
context().set_caller_id(m_ptr->id()); context().set_caller_id(m_ptr->id());
set_unique_id(m->getID(), m_ptr->id());
diagram().add_participant(std::move(m_ptr)); diagram().add_participant(std::move(m_ptr));
return true; return true;
@@ -577,14 +574,36 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
->getTemplateName() ->getTemplateName()
.getAsTemplateDecl(); .getAsTemplateDecl();
auto callee_method_full_name = std::string callee_method_full_name;
diagram()
.participants // First check if the primary template is already in the
.at(get_unique_id(primary_template->getID()) // participants map
.value()) if (get_participant(primary_template).has_value()) {
->full_name(false) + callee_method_full_name =
"::" + get_participant(primary_template)
dependent_member_callee->getMember().getAsString(); .value()
.full_name(false) +
"::" +
dependent_member_callee->getMember().getAsString();
}
else if (is_smart_pointer(primary_template)) {
// Otherwise check if it a smart pointer
primary_template->getTemplateParameters()
->asArray()
.front();
if (get_participant(primary_template).has_value()) {
callee_method_full_name =
get_participant(primary_template)
.value()
.full_name(false) +
"::" +
dependent_member_callee->getMember()
.getAsString();
}
else
return true;
}
auto callee_id = common::to_id(callee_method_full_name); auto callee_id = common::to_id(callee_method_full_name);
m.to = callee_id; m.to = callee_id;
@@ -696,6 +715,16 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
return true; return true;
} }
bool translation_unit_visitor::is_smart_pointer(
const clang::TemplateDecl *primary_template) const
{
return primary_template->getQualifiedNameAsString().find(
"std::unique_ptr") == 0 ||
primary_template->getQualifiedNameAsString().find("std::shared_ptr") ==
0 ||
primary_template->getQualifiedNameAsString().find("std::weak_ptr") == 0;
}
std::unique_ptr<clanguml::sequence_diagram::model::class_> std::unique_ptr<clanguml::sequence_diagram::model::class_>
translation_unit_visitor::create_class_declaration(clang::CXXRecordDecl *cls) translation_unit_visitor::create_class_declaration(clang::CXXRecordDecl *cls)
{ {

View File

@@ -202,6 +202,29 @@ public:
void finalize() { } void finalize() { }
template <typename T = model::participant>
common::optional_ref<T> get_participant(const clang::Decl *decl)
{
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>
common::optional_ref<T> get_participant(
const common::model::diagram_element::id_t id)
{
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(
@@ -277,6 +300,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);
bool is_smart_pointer(const clang::TemplateDecl *primary_template) const;
// Reference to the output diagram model // Reference to the output diagram model
clanguml::sequence_diagram::model::diagram &diagram_; clanguml::sequence_diagram::model::diagram &diagram_;
@@ -296,5 +321,4 @@ private:
common::model::access_t>> common::model::access_t>>
anonymous_struct_relationships_; anonymous_struct_relationships_;
}; };
} }

14
tests/t20009/.clang-uml Normal file
View File

@@ -0,0 +1,14 @@
compilation_database_dir: ..
output_directory: puml
diagrams:
t20009_sequence:
type: sequence
glob:
- ../../tests/t20009/t20009.cc
include:
namespaces:
- clanguml::t20009
using_namespace:
- clanguml::t20009
start_from:
- function: "clanguml::t20009::tmain()"

25
tests/t20009/t20009.cc Normal file
View File

@@ -0,0 +1,25 @@
#include <memory>
#include <string>
namespace clanguml {
namespace t20009 {
template <typename T> struct A {
void a(T arg) { }
};
template <typename T> struct B {
void b(T arg) { a->a(arg); }
std::unique_ptr<A<T>> a;
};
void tmain()
{
std::shared_ptr<B<std::string>> bstring;
auto bint = std::make_unique<B<int>>();
bstring->b("b");
bint.get()->b(42);
}
}
}

47
tests/t20009/test_case.h Normal file
View File

@@ -0,0 +1,47 @@
/**
* tests/t20009/test_case.h
*
* Copyright (c) 2021-2022 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("t20009", "[test-case][sequence]")
{
auto [config, db] = load_config("t20009");
auto diagram = config.diagrams["t20009_sequence"];
REQUIRE(diagram->name == "t20009_sequence");
auto model = generate_sequence_diagram(*db, diagram);
REQUIRE(model->name() == "t20009_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()"), _A("B<std::string>"), "b"));
REQUIRE_THAT(
puml, HasCall(_A("B<std::string>"), _A("A<std::string>"), "a"));
REQUIRE_THAT(puml, HasCall(_A("tmain()"), _A("B<int>"), "b"));
REQUIRE_THAT(puml, HasCall(_A("B<int>"), _A("A<int>"), "a"));
save_puml(
"./" + config.output_directory() + "/" + diagram->name + ".puml", puml);
}

View File

@@ -255,6 +255,7 @@ using namespace clanguml::test::matchers;
#include "t20006/test_case.h" #include "t20006/test_case.h"
#include "t20007/test_case.h" #include "t20007/test_case.h"
#include "t20008/test_case.h" #include "t20008/test_case.h"
#include "t20009/test_case.h"
/// ///
/// Package diagram tests /// Package diagram tests

View File

@@ -172,6 +172,9 @@ test_cases:
- name: t20008 - name: t20008
title: Constexpr if sequence diagram test case title: Constexpr if sequence diagram test case
description: description:
- name: t20009
title: Smart pointer dereference call expression test case
description:
Package diagrams: Package diagrams:
- name: t30001 - name: t30001
title: Basic package diagram test case title: Basic package diagram test case