Fixed sequence diagram test cases

This commit is contained in:
Bartek Kryza
2022-08-06 12:39:42 +02:00
parent cc0119d079
commit 5cdbb364b0
10 changed files with 159 additions and 87 deletions

View File

@@ -154,7 +154,6 @@ add_library(clang-umllib OBJECT ${SOURCES})
#
add_executable(clang-uml ${MAIN_SOURCE_FILE})
target_link_libraries(clang-uml
# ${LIBCLANG_LIBRARIES}
${YAML_CPP_LIBRARIES}
${LIBTOOLING_LIBS}
clang-umllib

View File

@@ -44,6 +44,13 @@ void generator::generate_call(const message &m, std::ostream &ostr) const
ostr << '"' << from << "\" "
<< common::generators::plantuml::to_plantuml(message_t::kCall) << " \""
<< to << "\" : " << m.message << "()" << std::endl;
if (m.message == "add" && to == "A" && from == "A")
LOG_DBG("Generating call '{}' from {} [{}] to {} [{}]", m.message, from,
m.from_usr, to, m.to_usr);
else
LOG_DBG("Generating call '{}' from {} [{}] to {} [{}]", m.message, from,
m.from_usr, to, m.to_usr);
}
void generator::generate_return(const message &m, std::ostream &ostr) const
@@ -81,7 +88,7 @@ void generator::generate(std::ostream &ostr) const
for (const auto &sf : m_config.start_from()) {
if (sf.location_type == source_location::location_t::function) {
std::uint_least64_t start_from;
std::int64_t start_from;
for (const auto &[k, v] : m_model.sequences) {
if (v.from == sf.location) {
start_from = k;

View File

@@ -47,7 +47,7 @@ public:
bool started{false};
std::map<std::uint_least64_t, activity> sequences;
std::map<int64_t, activity> sequences;
};
}

View File

@@ -29,7 +29,7 @@ struct message {
std::string from;
std::uint_least64_t from_usr;
std::string to;
std::uint_least64_t to_usr;
std::int64_t to_usr;
std::string message;
std::string return_type;
unsigned int line;

View File

@@ -29,106 +29,156 @@ translation_unit_visitor::translation_unit_visitor(clang::SourceManager &sm,
: source_manager_{sm}
, diagram_{diagram}
, config_{config}
, current_class_decl_{nullptr}
, current_method_decl_{nullptr}
, current_function_decl_{nullptr}
{
}
/*
void translation_unit_visitor::process_activities(const cppast::cpp_function &e)
clanguml::sequence_diagram::model::diagram &translation_unit_visitor::diagram()
{
return diagram_;
}
for (const auto &function_call_ptr : e.function_calls()) {
const auto &function_call =
static_cast<const cpp_member_function_call &>(*function_call_ptr);
const clanguml::config::sequence_diagram &
translation_unit_visitor::config() const
{
return config_;
}
message m;
m.type = message_t::kCall;
bool translation_unit_visitor::VisitCXXRecordDecl(clang::CXXRecordDecl *cls)
{
current_class_decl_ = cls;
if (!ctx.entity_index()
.lookup_definition(function_call.get_caller_id())
.has_value())
continue;
return true;
}
if (!ctx.entity_index()
.lookup_definition(function_call.get_caller_method_id())
.has_value())
continue;
bool translation_unit_visitor::VisitCXXMethodDecl(clang::CXXMethodDecl *method)
{
current_method_decl_ = method;
if (!ctx.entity_index()
.lookup_definition(function_call.get_callee_id())
.has_value())
continue;
return true;
}
if (!ctx.entity_index()
.lookup_definition(function_call.get_callee_method_id())
.has_value())
continue;
bool translation_unit_visitor::VisitFunctionDecl(
clang::FunctionDecl *function_declaration)
{
if (!function_declaration->isCXXClassMember())
current_class_decl_ = nullptr;
const auto &caller =
ctx.entity_index()
.lookup_definition(function_call.get_caller_id())
.value();
m.from = cx::util::ns(caller) + "::" + caller.name();
current_function_decl_ = function_declaration;
if (!ctx.diagram().should_include(
common::model::namespace_{cx::util::ns(caller)}, caller.name()))
continue;
return true;
}
if (caller.kind() == cpp_entity_kind::function_t)
m.from += "()";
bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
{
using clanguml::common::model::message_t;
using clanguml::common::model::namespace_;
using clanguml::sequence_diagram::model::activity;
using clanguml::sequence_diagram::model::message;
m.from_usr = type_safe::get(function_call.get_caller_method_id());
if (expr->isCallToStdMove())
return true;
const auto &callee =
ctx.entity_index()
.lookup_definition(function_call.get_callee_id())
.value();
m.to = cx::util::ns(callee) + "::" + callee.name();
if (callee.kind() == cpp_entity_kind::function_t)
m.to += "()";
if (expr->isImplicitCXXThis())
return true;
if (!ctx.diagram().should_include(
common::model::namespace_{cx::util::ns(callee)}, callee.name()))
continue;
if (/*clang::dyn_cast_or_null<clang::CXXOperatorCallExpr>(expr) ||*/
clang::dyn_cast_or_null<clang::ImplicitCastExpr>(expr))
return true;
m.to_usr = type_safe::get(function_call.get_callee_method_id());
if (current_class_decl_ &&
!diagram().should_include(
current_class_decl_->getQualifiedNameAsString()))
return true;
const auto &callee_method =
static_cast<const cppast::cpp_member_function &>(
ctx.entity_index()
.lookup_definition(function_call.get_callee_method_id())
.value());
if (current_function_decl_ &&
!diagram().should_include(
current_function_decl_->getQualifiedNameAsString()))
return true;
m.message = callee_method.name();
message m;
m.type = message_t::kCall;
m.return_type = cppast::to_string(callee_method.return_type());
if (ctx.diagram().sequences.find(m.from_usr) ==
ctx.diagram().sequences.end()) {
activity a;
a.usr = m.from_usr;
a.from = m.from;
ctx.diagram().sequences.insert({m.from_usr, std::move(a)});
}
LOG_DBG("Adding sequence {} -{}()-> {}", m.from, m.message, m.to);
ctx.diagram().sequences[m.from_usr].messages.emplace_back(std::move(m));
if (current_class_decl_ != nullptr) {
assert(current_method_decl_ != nullptr);
m.from = current_class_decl_->getQualifiedNameAsString();
m.from_usr = current_method_decl_->getID();
}
else {
m.from = current_function_decl_->getQualifiedNameAsString() + "()";
m.from_usr = current_function_decl_->getID();
}
}
void translation_unit_visitor::operator()(const cppast::cpp_entity &file)
{
const auto &current_ast_context = current_class_decl_
? current_class_decl_->getASTContext()
: current_function_decl_->getASTContext();
cppast::visit(file, [&, this](const cpp_entity &e, visitor_info) {
if (e.kind() == cpp_entity_kind::function_t) {
const auto &function = static_cast<const cpp_function &>(e);
process_activities(function);
}
else if (e.kind() == cpp_entity_kind::member_function_t) {
const auto &member_function = static_cast<const cpp_function &>(e);
process_activities(member_function);
}
});
if (const auto *operator_call_expr =
clang::dyn_cast_or_null<clang::CXXOperatorCallExpr>(expr);
operator_call_expr != nullptr) {
[[maybe_unused]] const auto *callee_method_decl =
operator_call_expr->getCalleeDecl();
}
else if (const auto *method_call_expr =
clang::dyn_cast_or_null<clang::CXXMemberCallExpr>(expr);
method_call_expr != nullptr) {
const auto *callee_decl = method_call_expr->getMethodDecl()
? method_call_expr->getMethodDecl()->getParent()
: nullptr;
if (!callee_decl ||
!diagram().should_include(
/*namespace_{*/ callee_decl->getQualifiedNameAsString()))
return true;
m.to = method_call_expr->getMethodDecl()
->getParent()
->getQualifiedNameAsString();
m.to_usr = method_call_expr->getMethodDecl()->getID();
m.message = method_call_expr->getMethodDecl()->getNameAsString();
m.return_type = method_call_expr->getCallReturnType(current_ast_context)
.getAsString();
}
else if (const auto *function_call_expr =
clang::dyn_cast_or_null<clang::CallExpr>(expr);
function_call_expr != nullptr) {
assert(function_call_expr->getCalleeDecl()->getAsFunction());
m.to = function_call_expr->getCalleeDecl()
->getAsFunction()
->getQualifiedNameAsString() +
"()";
m.message = function_call_expr->getCalleeDecl()
->getAsFunction()
->getNameAsString();
m.to_usr =
function_call_expr->getCalleeDecl()->getAsFunction()->getID();
m.return_type =
function_call_expr->getCallReturnType(current_ast_context)
.getAsString();
}
else {
return true;
}
if (diagram().sequences.find(m.from_usr) == diagram().sequences.end()) {
activity a;
a.usr = m.from_usr;
a.from = m.from;
diagram().sequences.insert({m.from_usr, std::move(a)});
}
LOG_DBG("Found call {} from {} [{}] to {} [{}] ", m.message, m.from,
m.from_usr, m.to, m.to_usr);
diagram().sequences[m.from_usr].messages.emplace_back(std::move(m));
assert(!diagram().sequences.empty());
return true;
}
*/
}

View File

@@ -20,6 +20,7 @@
#include "config/config.h"
#include "sequence_diagram/model/diagram.h"
#include <clang/AST/Expr.h>
#include <clang/AST/RecursiveASTVisitor.h>
#include <clang/Basic/SourceManager.h>
@@ -32,6 +33,18 @@ public:
clanguml::sequence_diagram::model::diagram &diagram,
const clanguml::config::sequence_diagram &config);
virtual bool VisitCallExpr(clang::CallExpr *expr);
virtual bool VisitCXXMethodDecl(clang::CXXMethodDecl *method);
virtual bool VisitCXXRecordDecl(clang::CXXRecordDecl *cls);
virtual bool VisitFunctionDecl(clang::FunctionDecl *function_declaration);
clanguml::sequence_diagram::model::diagram &diagram();
const clanguml::config::sequence_diagram &config() const;
void finalize() { }
private:
@@ -42,6 +55,10 @@ private:
// Reference to class diagram config
const clanguml::config::sequence_diagram &config_;
clang::CXXRecordDecl *current_class_decl_;
clang::CXXMethodDecl *current_method_decl_;
clang::FunctionDecl *current_function_decl_;
};
}

View File

@@ -16,7 +16,6 @@ set(CLANG_UML_TEST_LIBRARIES
clang-umllib
${YAML_CPP_LIBRARIES}
${LIBTOOLING_LIBS}
# ${LIBCLANG_LIBRARIES}
Threads::Threads)

View File

@@ -24,7 +24,7 @@ TEST_CASE("t20001", "[test-case][sequence]")
REQUIRE(diagram->name == "t20001_sequence");
auto model = generate_sequence_diagram(db, diagram);
auto model = generate_sequence_diagram(*db, diagram);
REQUIRE(model->name() == "t20001_sequence");

View File

@@ -24,7 +24,7 @@ TEST_CASE("t20002", "[test-case][sequence]")
REQUIRE(diagram->name == "t20002_sequence");
auto model = generate_sequence_diagram(db, diagram);
auto model = generate_sequence_diagram(*db, diagram);
REQUIRE(model->name() == "t20002_sequence");

View File

@@ -239,8 +239,8 @@ using namespace clanguml::test::matchers;
////
//// Sequence diagram tests
////
//#include "t20001/test_case.h"
//#include "t20002/test_case.h"
#include "t20001/test_case.h"
#include "t20002/test_case.h"
//
////
//// Package diagram tests