Added smart pointer dereference sequence diagram test case
This commit is contained in:
@@ -279,32 +279,29 @@ bool translation_unit_visitor::VisitCXXMethodDecl(clang::CXXMethodDecl *m)
|
||||
|
||||
LOG_DBG("Getting method's class with local id {}", parent_decl->getID());
|
||||
|
||||
set_unique_id(m->getID(), m_ptr->id());
|
||||
|
||||
const auto &method_class =
|
||||
diagram()
|
||||
.get_participant<model::class_>(
|
||||
get_unique_id(parent_decl->getID()).value())
|
||||
.value();
|
||||
get_participant<model::class_>(parent_decl).value();
|
||||
|
||||
m_ptr->set_class_id(method_class.id());
|
||||
m_ptr->set_class_full_name(method_class.full_name(false));
|
||||
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_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()));
|
||||
|
||||
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());
|
||||
|
||||
context().update(m);
|
||||
|
||||
context().set_caller_id(m_ptr->id());
|
||||
|
||||
set_unique_id(m->getID(), m_ptr->id());
|
||||
|
||||
diagram().add_participant(std::move(m_ptr));
|
||||
|
||||
return true;
|
||||
@@ -577,14 +574,36 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
|
||||
->getTemplateName()
|
||||
.getAsTemplateDecl();
|
||||
|
||||
auto callee_method_full_name =
|
||||
diagram()
|
||||
.participants
|
||||
.at(get_unique_id(primary_template->getID())
|
||||
.value())
|
||||
->full_name(false) +
|
||||
"::" +
|
||||
dependent_member_callee->getMember().getAsString();
|
||||
std::string callee_method_full_name;
|
||||
|
||||
// First check if the primary template is already in the
|
||||
// participants map
|
||||
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 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);
|
||||
m.to = callee_id;
|
||||
@@ -696,6 +715,16 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
|
||||
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_>
|
||||
translation_unit_visitor::create_class_declaration(clang::CXXRecordDecl *cls)
|
||||
{
|
||||
|
||||
@@ -202,6 +202,29 @@ public:
|
||||
|
||||
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
|
||||
/// getID()) method to clang-uml global id
|
||||
void set_unique_id(
|
||||
@@ -277,6 +300,8 @@ private:
|
||||
bool simplify_system_template(class_diagram::model::template_parameter &ct,
|
||||
const std::string &full_name);
|
||||
|
||||
bool is_smart_pointer(const clang::TemplateDecl *primary_template) const;
|
||||
|
||||
// Reference to the output diagram model
|
||||
clanguml::sequence_diagram::model::diagram &diagram_;
|
||||
|
||||
@@ -296,5 +321,4 @@ private:
|
||||
common::model::access_t>>
|
||||
anonymous_struct_relationships_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
14
tests/t20009/.clang-uml
Normal file
14
tests/t20009/.clang-uml
Normal 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
25
tests/t20009/t20009.cc
Normal 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
47
tests/t20009/test_case.h
Normal 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);
|
||||
}
|
||||
@@ -255,6 +255,7 @@ using namespace clanguml::test::matchers;
|
||||
#include "t20006/test_case.h"
|
||||
#include "t20007/test_case.h"
|
||||
#include "t20008/test_case.h"
|
||||
#include "t20009/test_case.h"
|
||||
|
||||
///
|
||||
/// Package diagram tests
|
||||
|
||||
@@ -172,6 +172,9 @@ test_cases:
|
||||
- name: t20008
|
||||
title: Constexpr if sequence diagram test case
|
||||
description:
|
||||
- name: t20009
|
||||
title: Smart pointer dereference call expression test case
|
||||
description:
|
||||
Package diagrams:
|
||||
- name: t30001
|
||||
title: Basic package diagram test case
|
||||
|
||||
Reference in New Issue
Block a user