Added template function sequence diagram test case

This commit is contained in:
Bartek Kryza
2022-09-27 23:12:27 +02:00
parent 511c8d0f65
commit a2705b10d9
5 changed files with 109 additions and 25 deletions

View File

@@ -47,8 +47,10 @@ void generator::generate_call(const message &m, std::ostream &ostr) const
}
auto message = m.message;
if (!message.empty())
if (!message.empty()) {
message = m_config.using_namespace().relative(message);
message += "()";
}
ostr << '"' << from << "\" "
<< 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) {
std::int64_t start_from;
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;
break;
}

View File

@@ -27,9 +27,9 @@ namespace clanguml::sequence_diagram::model {
struct message {
common::model::message_t type;
std::string from;
std::uint_least64_t from_usr;
std::uint_least64_t from_usr{};
std::string to;
std::int64_t to_usr;
std::int64_t to_usr{};
std::string message;
std::string return_type;
unsigned int line;

View File

@@ -23,6 +23,31 @@
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,
clanguml::sequence_diagram::model::diagram &diagram,
const clanguml::config::sequence_diagram &config)
@@ -32,6 +57,8 @@ translation_unit_visitor::translation_unit_visitor(clang::SourceManager &sm,
, current_class_decl_{nullptr}
, current_method_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;
// 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;
}
@@ -79,6 +116,9 @@ bool translation_unit_visitor::VisitFunctionTemplateDecl(
current_function_template_decl_ = function_declaration;
LOG_DBG("Visiting template function {}",
current_function_template_decl_->getQualifiedNameAsString());
return true;
}
@@ -100,16 +140,21 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr)
return true;
// Skip if current class was excluded in the config
if (current_class_decl_ &&
!diagram().should_include(
current_class_decl_->getQualifiedNameAsString()))
return true;
if (current_class_decl_) {
std::string current_class_qualified_name =
current_class_decl_->getQualifiedNameAsString();
if (!diagram().should_include(current_class_qualified_name))
return true;
}
// Skip if current function was excluded in the config
if (current_function_decl_ &&
!diagram().should_include(
current_function_decl_->getQualifiedNameAsString()))
return true;
if (current_function_decl_) {
std::string current_function_qualified_name =
current_function_decl_->getQualifiedNameAsString();
if (!diagram().should_include(current_function_qualified_name))
return true;
}
message m;
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_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) {
// Handle call expression within free function
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 =
clang::dyn_cast_or_null<clang::CallExpr>(expr);
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)
return true;
if (!callee_decl) {
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())
LOG_DBG("Call to template function!!!!");
if (unresolved_expr) {
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)
return true;
m.to = to_string(ftd);
m.message = to_string(ftd);
m.to_usr = ftd->getID();
break;
}
}
}
}
}
else {
if (!callee_decl)
return true;
m.to = callee_function->getQualifiedNameAsString() + "()";
m.message = callee_function->getNameAsString();
m.to_usr = callee_function->getID();
if (callee_decl->isTemplateDecl())
LOG_DBG("Call to template function!!!!");
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 =
function_call_expr->getCallReturnType(current_ast_context)
.getAsString();

View File

@@ -63,7 +63,6 @@ private:
clang::CXXMethodDecl *current_method_decl_;
clang::FunctionDecl *current_function_decl_;
clang::FunctionTemplateDecl *current_function_template_decl_;
};
}

View File

@@ -7,7 +7,7 @@ namespace t20003 {
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); }