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());
|
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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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
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 "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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user