Added template function sequence diagram test case
This commit is contained in:
@@ -47,8 +47,10 @@ void generator::generate_call(const message &m, std::ostream &ostr) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto message = m.message;
|
auto message = m.message;
|
||||||
if (!message.empty())
|
if (!message.empty()) {
|
||||||
|
message = m_config.using_namespace().relative(message);
|
||||||
message += "()";
|
message += "()";
|
||||||
|
}
|
||||||
|
|
||||||
ostr << '"' << from << "\" "
|
ostr << '"' << from << "\" "
|
||||||
<< common::generators::plantuml::to_plantuml(message_t::kCall) << " \""
|
<< common::generators::plantuml::to_plantuml(message_t::kCall) << " \""
|
||||||
@@ -103,7 +105,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) {
|
||||||
if (v.from == sf.location) {
|
std::string vfrom = v.from;
|
||||||
|
if (vfrom == sf.location) {
|
||||||
start_from = k;
|
start_from = k;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,9 +27,9 @@ namespace clanguml::sequence_diagram::model {
|
|||||||
struct message {
|
struct message {
|
||||||
common::model::message_t type;
|
common::model::message_t type;
|
||||||
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::int64_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;
|
||||||
|
|||||||
@@ -23,6 +23,31 @@
|
|||||||
|
|
||||||
namespace clanguml::sequence_diagram::visitor {
|
namespace clanguml::sequence_diagram::visitor {
|
||||||
|
|
||||||
|
std::string to_string(const clang::FunctionTemplateDecl *decl)
|
||||||
|
{
|
||||||
|
std::vector<std::string> template_parameters;
|
||||||
|
// Handle template function
|
||||||
|
for (const auto *parameter : *decl->getTemplateParameters()) {
|
||||||
|
if (clang::dyn_cast_or_null<clang::TemplateTypeParmDecl>(parameter)) {
|
||||||
|
const auto *template_type_parameter =
|
||||||
|
clang::dyn_cast_or_null<clang::TemplateTypeParmDecl>(parameter);
|
||||||
|
|
||||||
|
std::string template_parameter{
|
||||||
|
template_type_parameter->getNameAsString()};
|
||||||
|
|
||||||
|
if (template_type_parameter->isParameterPack())
|
||||||
|
template_parameter += "...";
|
||||||
|
|
||||||
|
template_parameters.emplace_back(std::move(template_parameter));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fmt::format("{}<{}>({})", decl->getQualifiedNameAsString(),
|
||||||
|
fmt::join(template_parameters, ","), "");
|
||||||
|
}
|
||||||
|
|
||||||
translation_unit_visitor::translation_unit_visitor(clang::SourceManager &sm,
|
translation_unit_visitor::translation_unit_visitor(clang::SourceManager &sm,
|
||||||
clanguml::sequence_diagram::model::diagram &diagram,
|
clanguml::sequence_diagram::model::diagram &diagram,
|
||||||
const clanguml::config::sequence_diagram &config)
|
const clanguml::config::sequence_diagram &config)
|
||||||
@@ -32,6 +57,8 @@ translation_unit_visitor::translation_unit_visitor(clang::SourceManager &sm,
|
|||||||
, current_class_decl_{nullptr}
|
, current_class_decl_{nullptr}
|
||||||
, current_method_decl_{nullptr}
|
, current_method_decl_{nullptr}
|
||||||
, current_function_decl_{nullptr}
|
, current_function_decl_{nullptr}
|
||||||
|
, current_function_template_decl_{nullptr}
|
||||||
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,6 +95,16 @@ bool translation_unit_visitor::VisitFunctionDecl(
|
|||||||
|
|
||||||
current_function_decl_ = function_declaration;
|
current_function_decl_ = function_declaration;
|
||||||
|
|
||||||
|
// Check if this function is a part of template function declaration,
|
||||||
|
// If no - reset the current_function_template_decl_
|
||||||
|
if (current_function_template_decl_ &&
|
||||||
|
current_function_template_decl_->getQualifiedNameAsString() !=
|
||||||
|
function_declaration->getQualifiedNameAsString())
|
||||||
|
current_function_template_decl_ = nullptr;
|
||||||
|
|
||||||
|
LOG_DBG("Visiting function {}",
|
||||||
|
current_function_decl_->getQualifiedNameAsString());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,6 +116,9 @@ bool translation_unit_visitor::VisitFunctionTemplateDecl(
|
|||||||
|
|
||||||
current_function_template_decl_ = function_declaration;
|
current_function_template_decl_ = function_declaration;
|
||||||
|
|
||||||
|
LOG_DBG("Visiting template function {}",
|
||||||
|
current_function_template_decl_->getQualifiedNameAsString());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,16 +140,21 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Skip if current class was excluded in the config
|
// Skip if current class was excluded in the config
|
||||||
if (current_class_decl_ &&
|
|
||||||
!diagram().should_include(
|
if (current_class_decl_) {
|
||||||
current_class_decl_->getQualifiedNameAsString()))
|
std::string current_class_qualified_name =
|
||||||
return true;
|
current_class_decl_->getQualifiedNameAsString();
|
||||||
|
if (!diagram().should_include(current_class_qualified_name))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Skip if current function was excluded in the config
|
// Skip if current function was excluded in the config
|
||||||
if (current_function_decl_ &&
|
if (current_function_decl_) {
|
||||||
!diagram().should_include(
|
std::string current_function_qualified_name =
|
||||||
current_function_decl_->getQualifiedNameAsString()))
|
current_function_decl_->getQualifiedNameAsString();
|
||||||
return true;
|
if (!diagram().should_include(current_function_qualified_name))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
message m;
|
message m;
|
||||||
m.type = message_t::kCall;
|
m.type = message_t::kCall;
|
||||||
@@ -120,6 +165,12 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
|
|||||||
m.from = current_class_decl_->getQualifiedNameAsString();
|
m.from = current_class_decl_->getQualifiedNameAsString();
|
||||||
m.from_usr = current_method_decl_->getID();
|
m.from_usr = current_method_decl_->getID();
|
||||||
}
|
}
|
||||||
|
else if (current_function_template_decl_ != nullptr &&
|
||||||
|
current_function_decl_ != nullptr) {
|
||||||
|
|
||||||
|
m.from = to_string(current_function_template_decl_);
|
||||||
|
m.from_usr = current_function_template_decl_->getID();
|
||||||
|
}
|
||||||
else if (current_function_decl_ != nullptr) {
|
else if (current_function_decl_ != nullptr) {
|
||||||
// Handle call expression within free function
|
// Handle call expression within free function
|
||||||
m.from = current_function_decl_->getQualifiedNameAsString() + "()";
|
m.from = current_function_decl_->getQualifiedNameAsString() + "()";
|
||||||
@@ -167,23 +218,54 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
|
|||||||
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) {
|
||||||
|
auto *callee_decl = function_call_expr->getCalleeDecl();
|
||||||
|
|
||||||
const auto *callee_decl = function_call_expr->getCalleeDecl();
|
if (callee_decl == nullptr) {
|
||||||
|
LOG_DBG("Cannot get callee declaration - trying direct callee...");
|
||||||
|
callee_decl = function_call_expr->getDirectCallee();
|
||||||
|
}
|
||||||
|
|
||||||
if (!callee_decl)
|
if (!callee_decl) {
|
||||||
return true;
|
if (clang::dyn_cast_or_null<clang::UnresolvedLookupExpr>(
|
||||||
|
function_call_expr->getCallee())) {
|
||||||
|
// This is probably a template
|
||||||
|
auto *unresolved_expr =
|
||||||
|
clang::dyn_cast_or_null<clang::UnresolvedLookupExpr>(
|
||||||
|
function_call_expr->getCallee());
|
||||||
|
|
||||||
if (callee_decl->isTemplateDecl())
|
if (unresolved_expr) {
|
||||||
LOG_DBG("Call to template function!!!!");
|
for (const auto *decl : unresolved_expr->decls()) {
|
||||||
|
if (clang::dyn_cast_or_null<
|
||||||
|
clang::FunctionTemplateDecl>(decl)) {
|
||||||
|
|
||||||
const auto *callee_function = callee_decl->getAsFunction();
|
auto *ftd = clang::dyn_cast_or_null<
|
||||||
|
clang::FunctionTemplateDecl>(decl);
|
||||||
|
|
||||||
if (!callee_function)
|
m.to = to_string(ftd);
|
||||||
return true;
|
m.message = to_string(ftd);
|
||||||
|
m.to_usr = ftd->getID();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!callee_decl)
|
||||||
|
return true;
|
||||||
|
|
||||||
m.to = callee_function->getQualifiedNameAsString() + "()";
|
if (callee_decl->isTemplateDecl())
|
||||||
m.message = callee_function->getNameAsString();
|
LOG_DBG("Call to template function!!!!");
|
||||||
m.to_usr = callee_function->getID();
|
|
||||||
|
const auto *callee_function = callee_decl->getAsFunction();
|
||||||
|
|
||||||
|
if (!callee_function)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
m.to = callee_function->getQualifiedNameAsString() + "()";
|
||||||
|
m.message = callee_function->getNameAsString();
|
||||||
|
m.to_usr = callee_function->getID();
|
||||||
|
}
|
||||||
m.return_type =
|
m.return_type =
|
||||||
function_call_expr->getCallReturnType(current_ast_context)
|
function_call_expr->getCallReturnType(current_ast_context)
|
||||||
.getAsString();
|
.getAsString();
|
||||||
|
|||||||
@@ -63,7 +63,6 @@ private:
|
|||||||
clang::CXXMethodDecl *current_method_decl_;
|
clang::CXXMethodDecl *current_method_decl_;
|
||||||
clang::FunctionDecl *current_function_decl_;
|
clang::FunctionDecl *current_function_decl_;
|
||||||
clang::FunctionTemplateDecl *current_function_template_decl_;
|
clang::FunctionTemplateDecl *current_function_template_decl_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ namespace t20003 {
|
|||||||
|
|
||||||
template <typename T> void m4(T p) { }
|
template <typename T> void m4(T p) { }
|
||||||
|
|
||||||
template <typename T> void m3(T p) { m4<T>(); }
|
template <typename T> void m3(T p) { m4<T>(p); }
|
||||||
|
|
||||||
template <typename T> void m2(T p) { m3<T>(p); }
|
template <typename T> void m2(T p) { m3<T>(p); }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user