WIP
This commit is contained in:
@@ -60,7 +60,7 @@ void generator::generate_call(const message &m, std::ostream &ostr) const
|
|||||||
<< to.value().alias() << " : " << message << std::endl;
|
<< to.value().alias() << " : " << message << std::endl;
|
||||||
|
|
||||||
LOG_DBG("Generated call '{}' from {} [{}] to {} [{}]", message, from,
|
LOG_DBG("Generated call '{}' from {} [{}] to {} [{}]", message, from,
|
||||||
m.from_name, to, m.to_name);
|
m.from, to, m.to);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generator::generate_return(const message &m, std::ostream &ostr) const
|
void generator::generate_return(const message &m, std::ostream &ostr) const
|
||||||
@@ -84,19 +84,19 @@ void generator::generate_activity(const activity &a, std::ostream &ostr) const
|
|||||||
if (!to)
|
if (!to)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
LOG_DBG("Generating message {} --> {}", m.from_name, m.to_name);
|
LOG_DBG("Generating message {} --> {}", m.from, m.to);
|
||||||
generate_call(m, ostr);
|
generate_call(m, ostr);
|
||||||
|
|
||||||
ostr << "activate " << to.value().alias() << std::endl;
|
ostr << "activate " << to.value().alias() << std::endl;
|
||||||
|
|
||||||
if (m_model.sequences.find(m.to) != m_model.sequences.end()) {
|
if (m_model.sequences.find(m.to) != m_model.sequences.end()) {
|
||||||
LOG_DBG("Creating activity {} --> {} - missing sequence {}",
|
LOG_DBG("Creating activity {} --> {} - missing sequence {}",
|
||||||
m.from_name, m.to_name, m.to);
|
m.from, m.to, m.to);
|
||||||
generate_activity(m_model.sequences[m.to], ostr);
|
generate_activity(m_model.sequences[m.to], ostr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LOG_DBG("Skipping activity {} --> {} - missing sequence {}",
|
LOG_DBG("Skipping activity {} --> {} - missing sequence {}",
|
||||||
m.from_name, m.to_name, m.to);
|
m.from, m.to, m.to);
|
||||||
|
|
||||||
generate_return(m, ostr);
|
generate_return(m, ostr);
|
||||||
|
|
||||||
@@ -159,6 +159,8 @@ void generator::generate(std::ostream &ostr) const
|
|||||||
{
|
{
|
||||||
m_model.print();
|
m_model.print();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ostr << "@startuml" << std::endl;
|
ostr << "@startuml" << std::endl;
|
||||||
|
|
||||||
generate_plantuml_directives(ostr, m_config.puml().before);
|
generate_plantuml_directives(ostr, m_config.puml().before);
|
||||||
@@ -167,7 +169,8 @@ void generator::generate(std::ostream &ostr) const
|
|||||||
if (sf.location_type == source_location::location_t::function) {
|
if (sf.location_type == source_location::location_t::function) {
|
||||||
std::int64_t start_from;
|
std::int64_t start_from;
|
||||||
for (const auto &[k, v] : m_model.sequences) {
|
for (const auto &[k, v] : m_model.sequences) {
|
||||||
std::string vfrom = v.from;
|
const auto& caller = *m_model.participants.at(v.from);
|
||||||
|
std::string vfrom = caller.full_name(false);
|
||||||
if (vfrom == sf.location) {
|
if (vfrom == sf.location) {
|
||||||
LOG_DBG("Found sequence diagram start point: {}", k);
|
LOG_DBG("Found sequence diagram start point: {}", k);
|
||||||
start_from = k;
|
start_from = k;
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "message.h"
|
#include "message.h"
|
||||||
|
#include "participant.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -25,8 +26,10 @@
|
|||||||
namespace clanguml::sequence_diagram::model {
|
namespace clanguml::sequence_diagram::model {
|
||||||
|
|
||||||
struct activity {
|
struct activity {
|
||||||
std::uint_least64_t usr;
|
// std::uint_least64_t from_id;
|
||||||
std::string from;
|
// std::string from_name;
|
||||||
|
// std::string from_method_name;
|
||||||
|
common::model::diagram_element::id_t from;
|
||||||
std::vector<message> messages;
|
std::vector<message> messages;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -73,13 +73,25 @@ inja::json diagram::context() const
|
|||||||
|
|
||||||
void diagram::print() const
|
void diagram::print() const
|
||||||
{
|
{
|
||||||
|
LOG_DBG(" --- Participants ---");
|
||||||
|
for (const auto &[id, participant] : participants) {
|
||||||
|
LOG_DBG("{} - {}", id, participant->to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DBG(" --- Activities ---");
|
||||||
for (const auto &[from_id, act] : sequences) {
|
for (const auto &[from_id, act] : sequences) {
|
||||||
LOG_DBG("Sequence id={}:", from_id);
|
LOG_DBG("Sequence id={}:", from_id);
|
||||||
LOG_DBG(" Activity id={}, from={}:", act.usr, act.from);
|
const auto &from_activity = *(participants.at(from_id));
|
||||||
|
LOG_DBG(" Activity id={}, from={}:", act.from,
|
||||||
|
from_activity.full_name(false));
|
||||||
for (const auto &message : act.messages) {
|
for (const auto &message : act.messages) {
|
||||||
LOG_DBG(
|
const auto &from_participant = *participants.at(message.from);
|
||||||
" Message from={}, from_id={}, to={}, to_id={}, name={}",
|
const auto &to_participant = *participants.at(message.to);
|
||||||
message.from_name, message.from, message.to_name, message.to,
|
|
||||||
|
LOG_DBG(" Message from={}, from_id={}, "
|
||||||
|
"to={}, to_id={}, name={}",
|
||||||
|
from_participant.full_name(false), from_participant.id(),
|
||||||
|
to_participant.full_name(false), to_participant.id(),
|
||||||
message.message_name);
|
message.message_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,16 +66,16 @@ public:
|
|||||||
|
|
||||||
void add_participant(std::unique_ptr<participant> p)
|
void add_participant(std::unique_ptr<participant> p)
|
||||||
{
|
{
|
||||||
LOG_DBG("Adding {} participant: {}, {} [{}]", p->type_name(),
|
const auto participant_id = p->id();
|
||||||
p->full_name(false), p->id(),
|
|
||||||
p->type_name() == "method"
|
|
||||||
? dynamic_cast<method *>(p.get())->method_name()
|
|
||||||
: "");
|
|
||||||
|
|
||||||
const auto pid = p->id();
|
if (participants.find(participant_id) == participants.end()) {
|
||||||
|
LOG_DBG("Adding '{}' participant: {}, {} [{}]", p->type_name(),
|
||||||
|
p->full_name(false), p->id(),
|
||||||
|
p->type_name() == "method"
|
||||||
|
? dynamic_cast<method *>(p.get())->method_name()
|
||||||
|
: "");
|
||||||
|
|
||||||
if (participants.find(pid) == participants.end()) {
|
participants.emplace(participant_id, std::move(p));
|
||||||
participants.emplace(pid, std::move(p));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/model/enums.h"
|
#include "common/model/enums.h"
|
||||||
|
#include "participant.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -27,9 +28,10 @@ namespace clanguml::sequence_diagram::model {
|
|||||||
struct message {
|
struct message {
|
||||||
message()
|
message()
|
||||||
: from{}
|
: from{}
|
||||||
, from_name{}
|
// , from_method_name{}
|
||||||
|
// , from_name{}
|
||||||
, to{}
|
, to{}
|
||||||
, to_name{}
|
// , to_name{}
|
||||||
, message_name{}
|
, message_name{}
|
||||||
, return_type{}
|
, return_type{}
|
||||||
, line{}
|
, line{}
|
||||||
@@ -37,17 +39,21 @@ struct message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
common::model::message_t type;
|
common::model::message_t type;
|
||||||
|
common::model::diagram_element::id_t from;
|
||||||
/// Source participant id
|
common::model::diagram_element::id_t to;
|
||||||
std::uint_least64_t from;
|
//
|
||||||
std::string from_name;
|
// /// Source participant id
|
||||||
// std::uint_least64_t from_usr{};
|
// std::uint_least64_t from;
|
||||||
|
// std::string from_method_name;
|
||||||
/// Target participant id
|
//
|
||||||
std::uint_least64_t to;
|
// std::string from_name;
|
||||||
std::string to_name;
|
// // std::uint_least64_t from_usr{};
|
||||||
|
//
|
||||||
// std::int64_t to_usr{};
|
// /// Target participant id
|
||||||
|
// std::uint_least64_t to;
|
||||||
|
// std::string to_name;
|
||||||
|
//
|
||||||
|
// // std::int64_t to_usr{};
|
||||||
|
|
||||||
std::string message_name;
|
std::string message_name;
|
||||||
|
|
||||||
|
|||||||
@@ -66,6 +66,12 @@ struct participant : public common::model::element,
|
|||||||
|
|
||||||
std::string type_name() const override { return "participant"; }
|
std::string type_name() const override { return "participant"; }
|
||||||
|
|
||||||
|
virtual std::string to_string() const
|
||||||
|
{
|
||||||
|
return fmt::format("Participant '{}': id={} name={}", type_name(), id(),
|
||||||
|
full_name(false));
|
||||||
|
}
|
||||||
|
|
||||||
stereotype_t stereotype_{stereotype_t::participant};
|
stereotype_t stereotype_{stereotype_t::participant};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -148,6 +154,12 @@ struct method : public participant {
|
|||||||
|
|
||||||
diagram_element::id_t class_id() const { return class_id_; }
|
diagram_element::id_t class_id() const { return class_id_; }
|
||||||
|
|
||||||
|
std::string to_string() const override
|
||||||
|
{
|
||||||
|
return fmt::format("Participant '{}': id={}, name={}, class_id={}",
|
||||||
|
type_name(), id(), full_name(false), class_id());
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
diagram_element::id_t class_id_;
|
diagram_element::id_t class_id_;
|
||||||
std::string method_name_;
|
std::string method_name_;
|
||||||
|
|||||||
@@ -78,8 +78,6 @@ bool translation_unit_visitor::VisitCXXRecordDecl(clang::CXXRecordDecl *cls)
|
|||||||
if (!diagram().should_include(cls->getQualifiedNameAsString()))
|
if (!diagram().should_include(cls->getQualifiedNameAsString()))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
call_expression_context_.reset();
|
|
||||||
|
|
||||||
if (!diagram().should_include(cls->getQualifiedNameAsString())) {
|
if (!diagram().should_include(cls->getQualifiedNameAsString())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -102,6 +100,8 @@ bool translation_unit_visitor::VisitCXXRecordDecl(clang::CXXRecordDecl *cls)
|
|||||||
if (!c_ptr)
|
if (!c_ptr)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
call_expression_context_.reset();
|
||||||
|
|
||||||
const auto cls_id = c_ptr->id();
|
const auto cls_id = c_ptr->id();
|
||||||
|
|
||||||
set_ast_local_id(cls->getID(), cls_id);
|
set_ast_local_id(cls->getID(), cls_id);
|
||||||
@@ -152,9 +152,9 @@ bool translation_unit_visitor::VisitClassTemplateDecl(
|
|||||||
if (!diagram().should_include(cls->getQualifiedNameAsString()))
|
if (!diagram().should_include(cls->getQualifiedNameAsString()))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
LOG_DBG("= Visiting class template declaration {} at {}",
|
LOG_DBG("= Visiting class template declaration {} at {} [{}]",
|
||||||
cls->getQualifiedNameAsString(),
|
cls->getQualifiedNameAsString(),
|
||||||
cls->getLocation().printToString(source_manager()));
|
cls->getLocation().printToString(source_manager()), (void *)cls);
|
||||||
|
|
||||||
auto c_ptr = create_class_declaration(cls->getTemplatedDecl());
|
auto c_ptr = create_class_declaration(cls->getTemplatedDecl());
|
||||||
|
|
||||||
@@ -181,8 +181,7 @@ bool translation_unit_visitor::VisitClassTemplateDecl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (diagram_.should_include(*c_ptr)) {
|
if (diagram_.should_include(*c_ptr)) {
|
||||||
const auto name = c_ptr->full_name();
|
LOG_DBG("Adding class template {} with id {}", cls_full_name, id);
|
||||||
LOG_DBG("Adding class template {} with id {}", name, id);
|
|
||||||
|
|
||||||
call_expression_context_.set_caller_id(id);
|
call_expression_context_.set_caller_id(id);
|
||||||
call_expression_context_.update(cls);
|
call_expression_context_.update(cls);
|
||||||
@@ -195,7 +194,7 @@ bool translation_unit_visitor::VisitClassTemplateDecl(
|
|||||||
|
|
||||||
bool translation_unit_visitor::VisitCXXMethodDecl(clang::CXXMethodDecl *m)
|
bool translation_unit_visitor::VisitCXXMethodDecl(clang::CXXMethodDecl *m)
|
||||||
{
|
{
|
||||||
if (call_expression_context_.current_class_decl_ == nullptr ||
|
if (call_expression_context_.current_class_decl_ == nullptr &&
|
||||||
call_expression_context_.current_class_template_decl_ == nullptr)
|
call_expression_context_.current_class_template_decl_ == nullptr)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@@ -210,11 +209,22 @@ bool translation_unit_visitor::VisitCXXMethodDecl(clang::CXXMethodDecl *m)
|
|||||||
m_ptr->set_name(ns.name());
|
m_ptr->set_name(ns.name());
|
||||||
ns.pop_back();
|
ns.pop_back();
|
||||||
m_ptr->set_namespace(ns);
|
m_ptr->set_namespace(ns);
|
||||||
m_ptr->set_id(common::to_id(m->getQualifiedNameAsString()));
|
|
||||||
|
|
||||||
m_ptr->set_class_id(
|
if (call_expression_context_.current_class_decl_)
|
||||||
get_ast_local_id(call_expression_context_.current_class_decl_->getID())
|
m_ptr->set_class_id(get_ast_local_id(
|
||||||
.value());
|
call_expression_context_.current_class_decl_->getID())
|
||||||
|
.value());
|
||||||
|
else
|
||||||
|
m_ptr->set_class_id(get_ast_local_id(
|
||||||
|
call_expression_context_.current_class_template_decl_->getID())
|
||||||
|
.value());
|
||||||
|
|
||||||
|
m_ptr->set_name(
|
||||||
|
diagram().participants.at(m_ptr->class_id())->full_name_no_ns() +
|
||||||
|
"::" + m->getNameAsString());
|
||||||
|
|
||||||
|
m_ptr->set_id(
|
||||||
|
common::to_id(m_ptr->full_name(false) + "::" + m->getNameAsString()));
|
||||||
|
|
||||||
call_expression_context_.update(m);
|
call_expression_context_.update(m);
|
||||||
|
|
||||||
@@ -327,6 +337,8 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
|
|||||||
using clanguml::sequence_diagram::model::activity;
|
using clanguml::sequence_diagram::model::activity;
|
||||||
using clanguml::sequence_diagram::model::message;
|
using clanguml::sequence_diagram::model::message;
|
||||||
|
|
||||||
|
// expr->dump();
|
||||||
|
|
||||||
// Skip casts, moves and such
|
// Skip casts, moves and such
|
||||||
if (expr->isCallToStdMove())
|
if (expr->isCallToStdMove())
|
||||||
return true;
|
return true;
|
||||||
@@ -337,24 +349,28 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
|
|||||||
if (clang::dyn_cast_or_null<clang::ImplicitCastExpr>(expr))
|
if (clang::dyn_cast_or_null<clang::ImplicitCastExpr>(expr))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
call_expression_context_.dump();
|
||||||
|
|
||||||
if (!call_expression_context_.valid())
|
if (!call_expression_context_.valid())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
message m;
|
message m;
|
||||||
m.type = message_t::kCall;
|
m.type = message_t::kCall;
|
||||||
m.from = call_expression_context_.caller_id();
|
m.from = call_expression_context_.caller_id();
|
||||||
m.from_name = diagram().participants.at(m.from)->full_name(false);
|
|
||||||
|
|
||||||
const auto ¤t_ast_context =
|
const auto ¤t_ast_context =
|
||||||
*call_expression_context_.get_ast_context();
|
*call_expression_context_.get_ast_context();
|
||||||
|
|
||||||
|
LOG_DBG("Visiting call expression at {}",
|
||||||
|
expr->getBeginLoc().printToString(source_manager()));
|
||||||
|
|
||||||
if (const auto *operator_call_expr =
|
if (const auto *operator_call_expr =
|
||||||
clang::dyn_cast_or_null<clang::CXXOperatorCallExpr>(expr);
|
clang::dyn_cast_or_null<clang::CXXOperatorCallExpr>(expr);
|
||||||
operator_call_expr != nullptr) {
|
operator_call_expr != nullptr) {
|
||||||
// TODO: Handle C++ operator calls
|
// TODO: Handle C++ operator calls
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
// class method
|
// Call to a class method
|
||||||
//
|
//
|
||||||
else if (const auto *method_call_expr =
|
else if (const auto *method_call_expr =
|
||||||
clang::dyn_cast_or_null<clang::CXXMemberCallExpr>(expr);
|
clang::dyn_cast_or_null<clang::CXXMemberCallExpr>(expr);
|
||||||
@@ -376,7 +392,6 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
|
|||||||
// encountered by the visitor - for now it's not a problem
|
// encountered by the visitor - for now it's not a problem
|
||||||
// as overloaded methods are not supported
|
// as overloaded methods are not supported
|
||||||
m.to = common::to_id(method_decl->getQualifiedNameAsString());
|
m.to = common::to_id(method_decl->getQualifiedNameAsString());
|
||||||
m.to_name = callee_decl->getQualifiedNameAsString();
|
|
||||||
m.message_name = method_decl->getNameAsString();
|
m.message_name = method_decl->getNameAsString();
|
||||||
m.return_type = method_call_expr->getCallReturnType(current_ast_context)
|
m.return_type = method_call_expr->getCallReturnType(current_ast_context)
|
||||||
.getAsString();
|
.getAsString();
|
||||||
@@ -385,6 +400,9 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
|
|||||||
diagram().add_active_participant(
|
diagram().add_active_participant(
|
||||||
get_ast_local_id(callee_decl->getID()).value());
|
get_ast_local_id(callee_decl->getID()).value());
|
||||||
}
|
}
|
||||||
|
//
|
||||||
|
// Call to a function
|
||||||
|
//
|
||||||
else if (const auto *function_call_expr =
|
else if (const auto *function_call_expr =
|
||||||
clang::dyn_cast_or_null<clang::CallExpr>(expr);
|
clang::dyn_cast_or_null<clang::CallExpr>(expr);
|
||||||
function_call_expr != nullptr) {
|
function_call_expr != nullptr) {
|
||||||
@@ -396,8 +414,49 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!callee_decl) {
|
if (!callee_decl) {
|
||||||
if (clang::dyn_cast_or_null<clang::UnresolvedLookupExpr>(
|
//
|
||||||
|
// Call to a method of a class template
|
||||||
|
//
|
||||||
|
if (clang::dyn_cast_or_null<clang::CXXDependentScopeMemberExpr>(
|
||||||
function_call_expr->getCallee())) {
|
function_call_expr->getCallee())) {
|
||||||
|
auto *dependent_member_callee =
|
||||||
|
clang::dyn_cast_or_null<clang::CXXDependentScopeMemberExpr>(
|
||||||
|
function_call_expr->getCallee());
|
||||||
|
|
||||||
|
if (!dependent_member_callee->getBaseType().isNull()) {
|
||||||
|
const auto *primary_template =
|
||||||
|
dependent_member_callee->getBaseType()
|
||||||
|
->getAs<clang::TemplateSpecializationType>()
|
||||||
|
->getTemplateName()
|
||||||
|
.getAsTemplateDecl();
|
||||||
|
|
||||||
|
auto callee_method_full_name =
|
||||||
|
diagram()
|
||||||
|
.participants
|
||||||
|
.at(get_ast_local_id(primary_template->getID())
|
||||||
|
.value())
|
||||||
|
->full_name(false) +
|
||||||
|
"::" +
|
||||||
|
dependent_member_callee->getMember().getAsString();
|
||||||
|
|
||||||
|
auto callee_id = common::to_id(callee_method_full_name);
|
||||||
|
m.to = callee_id;
|
||||||
|
|
||||||
|
m.message_name =
|
||||||
|
dependent_member_callee->getMember().getAsString();
|
||||||
|
m.return_type = "";
|
||||||
|
|
||||||
|
if (get_ast_local_id(primary_template->getID()))
|
||||||
|
diagram().add_active_participant(
|
||||||
|
get_ast_local_id(primary_template->getID())
|
||||||
|
.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Call to a template function
|
||||||
|
//
|
||||||
|
else if (clang::dyn_cast_or_null<clang::UnresolvedLookupExpr>(
|
||||||
|
function_call_expr->getCallee())) {
|
||||||
// This is probably a template
|
// This is probably a template
|
||||||
auto *unresolved_expr =
|
auto *unresolved_expr =
|
||||||
clang::dyn_cast_or_null<clang::UnresolvedLookupExpr>(
|
clang::dyn_cast_or_null<clang::UnresolvedLookupExpr>(
|
||||||
@@ -411,7 +470,8 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
|
|||||||
auto *ftd = clang::dyn_cast_or_null<
|
auto *ftd = clang::dyn_cast_or_null<
|
||||||
clang::FunctionTemplateDecl>(decl);
|
clang::FunctionTemplateDecl>(decl);
|
||||||
|
|
||||||
m.to_name = to_string(ftd);
|
// m.to_name =
|
||||||
|
// to_string(ftd);
|
||||||
m.to = get_ast_local_id(ftd->getID()).value();
|
m.to = get_ast_local_id(ftd->getID()).value();
|
||||||
auto message_name =
|
auto message_name =
|
||||||
diagram()
|
diagram()
|
||||||
@@ -430,11 +490,8 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!callee_decl)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (callee_decl->isTemplateDecl())
|
if (callee_decl->isTemplateDecl())
|
||||||
LOG_DBG("Call to template function!!!!");
|
LOG_DBG("Call to template function");
|
||||||
|
|
||||||
const auto *callee_function = callee_decl->getAsFunction();
|
const auto *callee_function = callee_decl->getAsFunction();
|
||||||
|
|
||||||
@@ -473,7 +530,8 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
|
|||||||
LOG_DBG("Processing implicit template specialization {}",
|
LOG_DBG("Processing implicit template specialization {}",
|
||||||
f_ptr->full_name(false));
|
f_ptr->full_name(false));
|
||||||
|
|
||||||
m.to_name = callee_function->getQualifiedNameAsString();
|
// m.to_name =
|
||||||
|
// callee_function->getQualifiedNameAsString();
|
||||||
if (is_implicit) {
|
if (is_implicit) {
|
||||||
// If this is an implicit template specialization/instantiation
|
// If this is an implicit template specialization/instantiation
|
||||||
// for now we just redirect the call to it's primary template
|
// for now we just redirect the call to it's primary template
|
||||||
@@ -512,8 +570,8 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
|
|||||||
if (m.from > 0 && m.to > 0) {
|
if (m.from > 0 && m.to > 0) {
|
||||||
if (diagram().sequences.find(m.from) == diagram().sequences.end()) {
|
if (diagram().sequences.find(m.from) == diagram().sequences.end()) {
|
||||||
activity a;
|
activity a;
|
||||||
a.usr = m.from;
|
// a.usr = m.from;
|
||||||
a.from = m.from_name;
|
a.from = m.from;
|
||||||
diagram().sequences.insert({m.from, std::move(a)});
|
diagram().sequences.insert({m.from, std::move(a)});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -521,7 +579,7 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
|
|||||||
diagram().add_active_participant(m.to);
|
diagram().add_active_participant(m.to);
|
||||||
|
|
||||||
LOG_DBG("Found call {} from {} [{}] to {} [{}] ", m.message_name,
|
LOG_DBG("Found call {} from {} [{}] to {} [{}] ", m.message_name,
|
||||||
m.from_name, m.from, m.to_name, m.to);
|
m.from, m.from, m.to, m.to);
|
||||||
|
|
||||||
diagram().sequences[m.from].messages.emplace_back(std::move(m));
|
diagram().sequences[m.from].messages.emplace_back(std::move(m));
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ std::string to_string(const clang::FunctionTemplateDecl *decl);
|
|||||||
struct call_expression_context {
|
struct call_expression_context {
|
||||||
call_expression_context()
|
call_expression_context()
|
||||||
: current_class_decl_{nullptr}
|
: current_class_decl_{nullptr}
|
||||||
|
, current_class_template_decl_{nullptr}
|
||||||
, current_method_decl_{nullptr}
|
, current_method_decl_{nullptr}
|
||||||
, current_function_decl_{nullptr}
|
, current_function_decl_{nullptr}
|
||||||
, current_function_template_decl_{nullptr}
|
, current_function_template_decl_{nullptr}
|
||||||
@@ -40,29 +41,40 @@ struct call_expression_context {
|
|||||||
|
|
||||||
void reset()
|
void reset()
|
||||||
{
|
{
|
||||||
|
current_caller_id_ = 0;
|
||||||
current_class_decl_ = nullptr;
|
current_class_decl_ = nullptr;
|
||||||
|
current_class_template_decl_ = nullptr;
|
||||||
current_method_decl_ = nullptr;
|
current_method_decl_ = nullptr;
|
||||||
current_function_decl_ = nullptr;
|
current_function_decl_ = nullptr;
|
||||||
current_function_template_decl_ = nullptr;
|
current_function_template_decl_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dump()
|
||||||
|
{
|
||||||
|
LOG_DBG("current_caller_id_ = {}", current_caller_id_);
|
||||||
|
LOG_DBG("current_class_decl_ = {}", (void *)current_class_decl_);
|
||||||
|
LOG_DBG("current_class_template_decl_ = {}",
|
||||||
|
(void *)current_class_template_decl_);
|
||||||
|
LOG_DBG("current_method_decl_ = {}", (void *)current_method_decl_);
|
||||||
|
LOG_DBG("current_function_decl_ = {}", (void *)current_function_decl_);
|
||||||
|
LOG_DBG("current_function_template_decl_ = {}",
|
||||||
|
(void *)current_function_template_decl_);
|
||||||
|
}
|
||||||
|
|
||||||
bool valid() const
|
bool valid() const
|
||||||
{
|
{
|
||||||
return (current_class_decl_ != nullptr) ||
|
return (current_class_decl_ != nullptr) ||
|
||||||
|
(current_class_template_decl_ != nullptr) ||
|
||||||
(current_method_decl_ != nullptr) ||
|
(current_method_decl_ != nullptr) ||
|
||||||
(current_function_decl_ != nullptr) ||
|
(current_function_decl_ != nullptr) ||
|
||||||
(current_function_template_decl_ != nullptr);
|
(current_function_template_decl_ != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void update(clang::CXXRecordDecl *cls) { current_class_decl_ = cls; }
|
|
||||||
|
|
||||||
void update(clang::ClassTemplateDecl *clst)
|
|
||||||
{
|
|
||||||
current_class_template_decl_ = clst;
|
|
||||||
}
|
|
||||||
|
|
||||||
clang::ASTContext *get_ast_context()
|
clang::ASTContext *get_ast_context()
|
||||||
{
|
{
|
||||||
|
if (current_class_template_decl_)
|
||||||
|
return ¤t_class_template_decl_->getASTContext();
|
||||||
|
|
||||||
if (current_class_decl_)
|
if (current_class_decl_)
|
||||||
return ¤t_class_decl_->getASTContext();
|
return ¤t_class_decl_->getASTContext();
|
||||||
|
|
||||||
@@ -72,6 +84,13 @@ struct call_expression_context {
|
|||||||
return ¤t_function_decl_->getASTContext();
|
return ¤t_function_decl_->getASTContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void update(clang::CXXRecordDecl *cls) { current_class_decl_ = cls; }
|
||||||
|
|
||||||
|
void update(clang::ClassTemplateDecl *clst)
|
||||||
|
{
|
||||||
|
current_class_template_decl_ = clst;
|
||||||
|
}
|
||||||
|
|
||||||
void update(clang::CXXMethodDecl *method) { current_method_decl_ = method; }
|
void update(clang::CXXMethodDecl *method) { current_method_decl_ = method; }
|
||||||
|
|
||||||
void update(clang::FunctionDecl *function)
|
void update(clang::FunctionDecl *function)
|
||||||
@@ -118,73 +137,6 @@ struct call_expression_context {
|
|||||||
current_function_template_decl_ != nullptr;
|
current_function_template_decl_ != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// std::string caller_name() const
|
|
||||||
// {
|
|
||||||
// if (in_class_method())
|
|
||||||
// return current_class_decl_->getQualifiedNameAsString();
|
|
||||||
// else if (in_function_template()) {
|
|
||||||
// return to_string(current_function_template_decl_);
|
|
||||||
// }
|
|
||||||
// else if (in_function()) {
|
|
||||||
// const auto function_name =
|
|
||||||
// current_function_decl_->getQualifiedNameAsString();
|
|
||||||
// LOG_DBG("Processing function {}", function_name);
|
|
||||||
// // Handle call expression within free function
|
|
||||||
// if
|
|
||||||
// (current_function_decl_->isFunctionTemplateSpecialization()) {
|
|
||||||
// /*
|
|
||||||
// /// This template specialization was formed from a
|
|
||||||
// template-id but
|
|
||||||
// /// has not yet been declared, defined, or
|
|
||||||
// instantiated. TSK_Undeclared = 0,
|
|
||||||
// /// This template specialization was implicitly
|
|
||||||
// instantiated
|
|
||||||
// from a
|
|
||||||
// /// template. (C++ [temp.inst]).
|
|
||||||
// TSK_ImplicitInstantiation,
|
|
||||||
// /// This template specialization was declared or
|
|
||||||
// defined by
|
|
||||||
// an
|
|
||||||
// /// explicit specialization (C++ [temp.expl.spec]) or
|
|
||||||
// partial
|
|
||||||
// /// specialization (C++ [temp.class.spec]).
|
|
||||||
// TSK_ExplicitSpecialization,
|
|
||||||
// /// This template specialization was instantiated from
|
|
||||||
// a
|
|
||||||
// template
|
|
||||||
// /// due to an explicit instantiation declaration
|
|
||||||
// request
|
|
||||||
// /// (C++11 [temp.explicit]).
|
|
||||||
// TSK_ExplicitInstantiationDeclaration,
|
|
||||||
// /// This template specialization was instantiated from
|
|
||||||
// a
|
|
||||||
// template
|
|
||||||
// /// due to an explicit instantiation definition
|
|
||||||
// request
|
|
||||||
// /// (C++ [temp.explicit]).
|
|
||||||
// TSK_ExplicitInstantiationDefinition
|
|
||||||
// */
|
|
||||||
// [[maybe_unused]] const auto specialization_kind =
|
|
||||||
// current_function_decl_->getTemplateSpecializationKind();
|
|
||||||
// [[maybe_unused]] const auto *primary_template =
|
|
||||||
// current_function_decl_->getPrimaryTemplate();
|
|
||||||
//
|
|
||||||
// for (const auto &arg :
|
|
||||||
// current_function_decl_->getTemplateSpecializationArgs()
|
|
||||||
// ->asArray()) {
|
|
||||||
// LOG_DBG("TEMPLATE SPECIALIZATION ARG:");
|
|
||||||
// arg.dump();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// LOG_DBG("--------------");
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return function_name + "()";
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// return "";
|
|
||||||
// }
|
|
||||||
|
|
||||||
std::int64_t caller_id() const { return current_caller_id_; }
|
std::int64_t caller_id() const { return current_caller_id_; }
|
||||||
|
|
||||||
void set_caller_id(std::int64_t id)
|
void set_caller_id(std::int64_t id)
|
||||||
|
|||||||
14
tests/t20005/.clang-uml
Normal file
14
tests/t20005/.clang-uml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
compilation_database_dir: ..
|
||||||
|
output_directory: puml
|
||||||
|
diagrams:
|
||||||
|
t20005_sequence:
|
||||||
|
type: sequence
|
||||||
|
glob:
|
||||||
|
- ../../tests/t20005/t20005.cc
|
||||||
|
include:
|
||||||
|
namespaces:
|
||||||
|
- clanguml::t20005
|
||||||
|
using_namespace:
|
||||||
|
- clanguml::t20005
|
||||||
|
start_from:
|
||||||
|
- function: "clanguml::t20005::C<T>::c"
|
||||||
21
tests/t20005/t20005.cc
Normal file
21
tests/t20005/t20005.cc
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
namespace clanguml {
|
||||||
|
namespace t20005 {
|
||||||
|
|
||||||
|
template <typename T> struct A {
|
||||||
|
T a(T arg) { return arg; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T> struct B {
|
||||||
|
T b(T arg) { return a_.a(arg); }
|
||||||
|
|
||||||
|
A<T> a_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T> struct C {
|
||||||
|
T c(T arg) { return b_.b(arg); }
|
||||||
|
|
||||||
|
B<T> b_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
45
tests/t20005/test_case.h
Normal file
45
tests/t20005/test_case.h
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* tests/t20005/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("t20005", "[test-case][sequence]")
|
||||||
|
{
|
||||||
|
auto [config, db] = load_config("t20005");
|
||||||
|
|
||||||
|
auto diagram = config.diagrams["t20005_sequence"];
|
||||||
|
|
||||||
|
REQUIRE(diagram->name == "t20005_sequence");
|
||||||
|
|
||||||
|
auto model = generate_sequence_diagram(*db, diagram);
|
||||||
|
|
||||||
|
REQUIRE(model->name() == "t20005_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("C<T>"), _A("B<T>"), "b"));
|
||||||
|
REQUIRE_THAT(puml, HasCall(_A("B<T>"), _A("A<T>"), "a"));
|
||||||
|
|
||||||
|
|
||||||
|
save_puml(
|
||||||
|
"./" + config.output_directory() + "/" + diagram->name + ".puml", puml);
|
||||||
|
}
|
||||||
@@ -251,6 +251,7 @@ using namespace clanguml::test::matchers;
|
|||||||
#include "t20002/test_case.h"
|
#include "t20002/test_case.h"
|
||||||
#include "t20003/test_case.h"
|
#include "t20003/test_case.h"
|
||||||
#include "t20004/test_case.h"
|
#include "t20004/test_case.h"
|
||||||
|
#include "t20005/test_case.h"
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Package diagram tests
|
/// Package diagram tests
|
||||||
|
|||||||
@@ -160,6 +160,9 @@ test_cases:
|
|||||||
- name: t20004
|
- name: t20004
|
||||||
title: Function template instantiation sequence diagram test case
|
title: Function template instantiation sequence diagram test case
|
||||||
description:
|
description:
|
||||||
|
- name: t20005
|
||||||
|
title: Class template basic sequence diagram
|
||||||
|
description:
|
||||||
Package diagrams:
|
Package diagrams:
|
||||||
- name: t30001
|
- name: t30001
|
||||||
title: Basic package diagram test case
|
title: Basic package diagram test case
|
||||||
|
|||||||
@@ -7,4 +7,6 @@ diagrams:
|
|||||||
- ../../tests/{{ name }}/{{ name }}.cc
|
- ../../tests/{{ name }}/{{ name }}.cc
|
||||||
include:
|
include:
|
||||||
namespaces:
|
namespaces:
|
||||||
- clanguml::{{ name }}
|
- clanguml::{{ name }}
|
||||||
|
using_namespace:
|
||||||
|
- clanguml::{{ name }}
|
||||||
Reference in New Issue
Block a user