Fixed sequence diagram test cases
This commit is contained in:
@@ -154,7 +154,6 @@ add_library(clang-umllib OBJECT ${SOURCES})
|
|||||||
#
|
#
|
||||||
add_executable(clang-uml ${MAIN_SOURCE_FILE})
|
add_executable(clang-uml ${MAIN_SOURCE_FILE})
|
||||||
target_link_libraries(clang-uml
|
target_link_libraries(clang-uml
|
||||||
# ${LIBCLANG_LIBRARIES}
|
|
||||||
${YAML_CPP_LIBRARIES}
|
${YAML_CPP_LIBRARIES}
|
||||||
${LIBTOOLING_LIBS}
|
${LIBTOOLING_LIBS}
|
||||||
clang-umllib
|
clang-umllib
|
||||||
|
|||||||
@@ -44,6 +44,13 @@ void generator::generate_call(const message &m, std::ostream &ostr) const
|
|||||||
ostr << '"' << from << "\" "
|
ostr << '"' << from << "\" "
|
||||||
<< common::generators::plantuml::to_plantuml(message_t::kCall) << " \""
|
<< common::generators::plantuml::to_plantuml(message_t::kCall) << " \""
|
||||||
<< to << "\" : " << m.message << "()" << std::endl;
|
<< 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
|
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()) {
|
for (const auto &sf : m_config.start_from()) {
|
||||||
if (sf.location_type == source_location::location_t::function) {
|
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) {
|
for (const auto &[k, v] : m_model.sequences) {
|
||||||
if (v.from == sf.location) {
|
if (v.from == sf.location) {
|
||||||
start_from = k;
|
start_from = k;
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ public:
|
|||||||
|
|
||||||
bool started{false};
|
bool started{false};
|
||||||
|
|
||||||
std::map<std::uint_least64_t, activity> sequences;
|
std::map<int64_t, activity> sequences;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ struct message {
|
|||||||
std::string from;
|
std::string from;
|
||||||
std::uint_least64_t from_usr;
|
std::uint_least64_t from_usr;
|
||||||
std::string to;
|
std::string to;
|
||||||
std::uint_least64_t to_usr;
|
std::int64_t to_usr;
|
||||||
std::string message;
|
std::string message;
|
||||||
std::string return_type;
|
std::string return_type;
|
||||||
unsigned int line;
|
unsigned int line;
|
||||||
|
|||||||
@@ -29,106 +29,156 @@ translation_unit_visitor::translation_unit_visitor(clang::SourceManager &sm,
|
|||||||
: source_manager_{sm}
|
: source_manager_{sm}
|
||||||
, diagram_{diagram}
|
, diagram_{diagram}
|
||||||
, config_{config}
|
, config_{config}
|
||||||
|
, current_class_decl_{nullptr}
|
||||||
|
, current_method_decl_{nullptr}
|
||||||
|
, current_function_decl_{nullptr}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
clanguml::sequence_diagram::model::diagram &translation_unit_visitor::diagram()
|
||||||
void translation_unit_visitor::process_activities(const cppast::cpp_function &e)
|
|
||||||
{
|
{
|
||||||
|
return diagram_;
|
||||||
|
}
|
||||||
|
|
||||||
for (const auto &function_call_ptr : e.function_calls()) {
|
const clanguml::config::sequence_diagram &
|
||||||
const auto &function_call =
|
translation_unit_visitor::config() const
|
||||||
static_cast<const cpp_member_function_call &>(*function_call_ptr);
|
{
|
||||||
|
return config_;
|
||||||
|
}
|
||||||
|
|
||||||
message m;
|
bool translation_unit_visitor::VisitCXXRecordDecl(clang::CXXRecordDecl *cls)
|
||||||
m.type = message_t::kCall;
|
{
|
||||||
|
current_class_decl_ = cls;
|
||||||
|
|
||||||
if (!ctx.entity_index()
|
return true;
|
||||||
.lookup_definition(function_call.get_caller_id())
|
}
|
||||||
.has_value())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!ctx.entity_index()
|
bool translation_unit_visitor::VisitCXXMethodDecl(clang::CXXMethodDecl *method)
|
||||||
.lookup_definition(function_call.get_caller_method_id())
|
{
|
||||||
.has_value())
|
current_method_decl_ = method;
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!ctx.entity_index()
|
return true;
|
||||||
.lookup_definition(function_call.get_callee_id())
|
}
|
||||||
.has_value())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!ctx.entity_index()
|
bool translation_unit_visitor::VisitFunctionDecl(
|
||||||
.lookup_definition(function_call.get_callee_method_id())
|
clang::FunctionDecl *function_declaration)
|
||||||
.has_value())
|
{
|
||||||
continue;
|
if (!function_declaration->isCXXClassMember())
|
||||||
|
current_class_decl_ = nullptr;
|
||||||
|
|
||||||
const auto &caller =
|
current_function_decl_ = function_declaration;
|
||||||
ctx.entity_index()
|
|
||||||
.lookup_definition(function_call.get_caller_id())
|
|
||||||
.value();
|
|
||||||
m.from = cx::util::ns(caller) + "::" + caller.name();
|
|
||||||
|
|
||||||
if (!ctx.diagram().should_include(
|
return true;
|
||||||
common::model::namespace_{cx::util::ns(caller)}, caller.name()))
|
}
|
||||||
continue;
|
|
||||||
|
|
||||||
if (caller.kind() == cpp_entity_kind::function_t)
|
bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
|
||||||
m.from += "()";
|
{
|
||||||
|
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 =
|
if (expr->isImplicitCXXThis())
|
||||||
ctx.entity_index()
|
return true;
|
||||||
.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 (!ctx.diagram().should_include(
|
if (/*clang::dyn_cast_or_null<clang::CXXOperatorCallExpr>(expr) ||*/
|
||||||
common::model::namespace_{cx::util::ns(callee)}, callee.name()))
|
clang::dyn_cast_or_null<clang::ImplicitCastExpr>(expr))
|
||||||
continue;
|
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 =
|
if (current_function_decl_ &&
|
||||||
static_cast<const cppast::cpp_member_function &>(
|
!diagram().should_include(
|
||||||
ctx.entity_index()
|
current_function_decl_->getQualifiedNameAsString()))
|
||||||
.lookup_definition(function_call.get_callee_method_id())
|
return true;
|
||||||
.value());
|
|
||||||
|
|
||||||
m.message = callee_method.name();
|
message m;
|
||||||
|
m.type = message_t::kCall;
|
||||||
|
|
||||||
m.return_type = cppast::to_string(callee_method.return_type());
|
if (current_class_decl_ != nullptr) {
|
||||||
|
assert(current_method_decl_ != nullptr);
|
||||||
if (ctx.diagram().sequences.find(m.from_usr) ==
|
m.from = current_class_decl_->getQualifiedNameAsString();
|
||||||
ctx.diagram().sequences.end()) {
|
m.from_usr = current_method_decl_->getID();
|
||||||
activity a;
|
}
|
||||||
a.usr = m.from_usr;
|
else {
|
||||||
a.from = m.from;
|
m.from = current_function_decl_->getQualifiedNameAsString() + "()";
|
||||||
ctx.diagram().sequences.insert({m.from_usr, std::move(a)});
|
m.from_usr = current_function_decl_->getID();
|
||||||
}
|
|
||||||
|
|
||||||
LOG_DBG("Adding sequence {} -{}()-> {}", m.from, m.message, m.to);
|
|
||||||
|
|
||||||
ctx.diagram().sequences[m.from_usr].messages.emplace_back(std::move(m));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void translation_unit_visitor::operator()(const cppast::cpp_entity &file)
|
const auto ¤t_ast_context = current_class_decl_
|
||||||
{
|
? current_class_decl_->getASTContext()
|
||||||
|
: current_function_decl_->getASTContext();
|
||||||
|
|
||||||
cppast::visit(file, [&, this](const cpp_entity &e, visitor_info) {
|
if (const auto *operator_call_expr =
|
||||||
if (e.kind() == cpp_entity_kind::function_t) {
|
clang::dyn_cast_or_null<clang::CXXOperatorCallExpr>(expr);
|
||||||
const auto &function = static_cast<const cpp_function &>(e);
|
operator_call_expr != nullptr) {
|
||||||
process_activities(function);
|
[[maybe_unused]] const auto *callee_method_decl =
|
||||||
}
|
operator_call_expr->getCalleeDecl();
|
||||||
else if (e.kind() == cpp_entity_kind::member_function_t) {
|
}
|
||||||
const auto &member_function = static_cast<const cpp_function &>(e);
|
else if (const auto *method_call_expr =
|
||||||
process_activities(member_function);
|
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;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "config/config.h"
|
#include "config/config.h"
|
||||||
#include "sequence_diagram/model/diagram.h"
|
#include "sequence_diagram/model/diagram.h"
|
||||||
|
|
||||||
|
#include <clang/AST/Expr.h>
|
||||||
#include <clang/AST/RecursiveASTVisitor.h>
|
#include <clang/AST/RecursiveASTVisitor.h>
|
||||||
#include <clang/Basic/SourceManager.h>
|
#include <clang/Basic/SourceManager.h>
|
||||||
|
|
||||||
@@ -32,6 +33,18 @@ public:
|
|||||||
clanguml::sequence_diagram::model::diagram &diagram,
|
clanguml::sequence_diagram::model::diagram &diagram,
|
||||||
const clanguml::config::sequence_diagram &config);
|
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() { }
|
void finalize() { }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -42,6 +55,10 @@ private:
|
|||||||
|
|
||||||
// Reference to class diagram config
|
// Reference to class diagram config
|
||||||
const clanguml::config::sequence_diagram &config_;
|
const clanguml::config::sequence_diagram &config_;
|
||||||
|
|
||||||
|
clang::CXXRecordDecl *current_class_decl_;
|
||||||
|
clang::CXXMethodDecl *current_method_decl_;
|
||||||
|
clang::FunctionDecl *current_function_decl_;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ set(CLANG_UML_TEST_LIBRARIES
|
|||||||
clang-umllib
|
clang-umllib
|
||||||
${YAML_CPP_LIBRARIES}
|
${YAML_CPP_LIBRARIES}
|
||||||
${LIBTOOLING_LIBS}
|
${LIBTOOLING_LIBS}
|
||||||
# ${LIBCLANG_LIBRARIES}
|
|
||||||
Threads::Threads)
|
Threads::Threads)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ TEST_CASE("t20001", "[test-case][sequence]")
|
|||||||
|
|
||||||
REQUIRE(diagram->name == "t20001_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");
|
REQUIRE(model->name() == "t20001_sequence");
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ TEST_CASE("t20002", "[test-case][sequence]")
|
|||||||
|
|
||||||
REQUIRE(diagram->name == "t20002_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");
|
REQUIRE(model->name() == "t20002_sequence");
|
||||||
|
|
||||||
|
|||||||
@@ -239,8 +239,8 @@ using namespace clanguml::test::matchers;
|
|||||||
////
|
////
|
||||||
//// Sequence diagram tests
|
//// Sequence diagram tests
|
||||||
////
|
////
|
||||||
//#include "t20001/test_case.h"
|
#include "t20001/test_case.h"
|
||||||
//#include "t20002/test_case.h"
|
#include "t20002/test_case.h"
|
||||||
//
|
//
|
||||||
////
|
////
|
||||||
//// Package diagram tests
|
//// Package diagram tests
|
||||||
|
|||||||
Reference in New Issue
Block a user