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})
|
||||
target_link_libraries(clang-uml
|
||||
# ${LIBCLANG_LIBRARIES}
|
||||
${YAML_CPP_LIBRARIES}
|
||||
${LIBTOOLING_LIBS}
|
||||
clang-umllib
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -47,7 +47,7 @@ public:
|
||||
|
||||
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::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;
|
||||
|
||||
@@ -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 ¤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 (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;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -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_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ set(CLANG_UML_TEST_LIBRARIES
|
||||
clang-umllib
|
||||
${YAML_CPP_LIBRARIES}
|
||||
${LIBTOOLING_LIBS}
|
||||
# ${LIBCLANG_LIBRARIES}
|
||||
Threads::Threads)
|
||||
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user