From a2705b10d979f19f309a370b7a58ae61760b8f52 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Tue, 27 Sep 2022 23:12:27 +0200 Subject: [PATCH] Added template function sequence diagram test case --- .../plantuml/sequence_diagram_generator.cc | 7 +- src/sequence_diagram/model/message.h | 4 +- .../visitor/translation_unit_visitor.cc | 120 +++++++++++++++--- .../visitor/translation_unit_visitor.h | 1 - tests/t20003/t20003.cc | 2 +- 5 files changed, 109 insertions(+), 25 deletions(-) diff --git a/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc index fb45c5d2..f04ed517 100644 --- a/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc +++ b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc @@ -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; } diff --git a/src/sequence_diagram/model/message.h b/src/sequence_diagram/model/message.h index bb0b3212..f092dc23 100644 --- a/src/sequence_diagram/model/message.h +++ b/src/sequence_diagram/model/message.h @@ -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; diff --git a/src/sequence_diagram/visitor/translation_unit_visitor.cc b/src/sequence_diagram/visitor/translation_unit_visitor.cc index 4370c998..fde34e68 100644 --- a/src/sequence_diagram/visitor/translation_unit_visitor.cc +++ b/src/sequence_diagram/visitor/translation_unit_visitor.cc @@ -23,6 +23,31 @@ namespace clanguml::sequence_diagram::visitor { +std::string to_string(const clang::FunctionTemplateDecl *decl) +{ + std::vector template_parameters; + // Handle template function + for (const auto *parameter : *decl->getTemplateParameters()) { + if (clang::dyn_cast_or_null(parameter)) { + const auto *template_type_parameter = + clang::dyn_cast_or_null(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(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( + function_call_expr->getCallee())) { + // This is probably a template + auto *unresolved_expr = + clang::dyn_cast_or_null( + 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(); diff --git a/src/sequence_diagram/visitor/translation_unit_visitor.h b/src/sequence_diagram/visitor/translation_unit_visitor.h index f8e72885..811868ed 100644 --- a/src/sequence_diagram/visitor/translation_unit_visitor.h +++ b/src/sequence_diagram/visitor/translation_unit_visitor.h @@ -63,7 +63,6 @@ private: clang::CXXMethodDecl *current_method_decl_; clang::FunctionDecl *current_function_decl_; clang::FunctionTemplateDecl *current_function_template_decl_; - }; } diff --git a/tests/t20003/t20003.cc b/tests/t20003/t20003.cc index 3518b174..af9b75ba 100644 --- a/tests/t20003/t20003.cc +++ b/tests/t20003/t20003.cc @@ -7,7 +7,7 @@ namespace t20003 { template void m4(T p) { } -template void m3(T p) { m4(); } +template void m3(T p) { m4(p); } template void m2(T p) { m3(p); }