diff --git a/src/sequence_diagram/visitor/translation_unit_visitor.cc b/src/sequence_diagram/visitor/translation_unit_visitor.cc index a6db6454..4370c998 100644 --- a/src/sequence_diagram/visitor/translation_unit_visitor.cc +++ b/src/sequence_diagram/visitor/translation_unit_visitor.cc @@ -71,6 +71,17 @@ bool translation_unit_visitor::VisitFunctionDecl( return true; } +bool translation_unit_visitor::VisitFunctionTemplateDecl( + clang::FunctionTemplateDecl *function_declaration) +{ + if (!function_declaration->isCXXClassMember()) + current_class_decl_ = nullptr; + + current_function_template_decl_ = function_declaration; + + return true; +} + bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr) { using clanguml::common::model::message_t; @@ -109,11 +120,20 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr) m.from = current_class_decl_->getQualifiedNameAsString(); m.from_usr = current_method_decl_->getID(); } - else { + else if (current_function_decl_ != nullptr) { // Handle call expression within free function m.from = current_function_decl_->getQualifiedNameAsString() + "()"; m.from_usr = current_function_decl_->getID(); } + else { + m.from = current_function_template_decl_->getQualifiedNameAsString(); + std::vector params; + for (const auto &template_parameter : + *current_function_template_decl_->getTemplateParameters()) { + params.push_back(template_parameter->getNameAsString()); + } + m.from += fmt::format("<{}>", fmt::join(params, ",")); + } const auto ¤t_ast_context = current_class_decl_ ? current_class_decl_->getASTContext() @@ -153,6 +173,9 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr) if (!callee_decl) return true; + if (callee_decl->isTemplateDecl()) + LOG_DBG("Call to template function!!!!"); + const auto *callee_function = callee_decl->getAsFunction(); if (!callee_function) diff --git a/src/sequence_diagram/visitor/translation_unit_visitor.h b/src/sequence_diagram/visitor/translation_unit_visitor.h index a5e3fbf5..f8e72885 100644 --- a/src/sequence_diagram/visitor/translation_unit_visitor.h +++ b/src/sequence_diagram/visitor/translation_unit_visitor.h @@ -41,6 +41,9 @@ public: virtual bool VisitFunctionDecl(clang::FunctionDecl *function_declaration); + bool VisitFunctionTemplateDecl( + clang::FunctionTemplateDecl *function_declaration); + clanguml::sequence_diagram::model::diagram &diagram(); const clanguml::config::sequence_diagram &config() const; @@ -59,6 +62,8 @@ private: clang::CXXRecordDecl *current_class_decl_; clang::CXXMethodDecl *current_method_decl_; clang::FunctionDecl *current_function_decl_; + clang::FunctionTemplateDecl *current_function_template_decl_; + }; } diff --git a/tests/t20003/.clang-uml b/tests/t20003/.clang-uml new file mode 100644 index 00000000..d592e566 --- /dev/null +++ b/tests/t20003/.clang-uml @@ -0,0 +1,14 @@ +compilation_database_dir: .. +output_directory: puml +diagrams: + t20003_sequence: + type: sequence + glob: + - ../../tests/t20003/t20003.cc + include: + namespaces: + - clanguml::t20003 + using_namespace: + - clanguml::t20003 + start_from: + - function: "clanguml::t20003::m1()" diff --git a/tests/t20003/t20003.cc b/tests/t20003/t20003.cc new file mode 100644 index 00000000..3518b174 --- /dev/null +++ b/tests/t20003/t20003.cc @@ -0,0 +1,16 @@ +#include +#include +#include + +namespace clanguml { +namespace t20003 { + +template void m4(T p) { } + +template void m3(T p) { m4(); } + +template void m2(T p) { m3(p); } + +template void m1(T p) { m2(p); } +} +} diff --git a/tests/t20003/test_case.h b/tests/t20003/test_case.h new file mode 100644 index 00000000..eb8aecf5 --- /dev/null +++ b/tests/t20003/test_case.h @@ -0,0 +1,42 @@ +/** + * tests/t20003/test_case.cc + * + * Copyright (c) 2021-2022 Bartek Kryza + * + * 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("t20003", "[test-case][sequence]") +{ + auto [config, db] = load_config("t20003"); + + auto diagram = config.diagrams["t20003_sequence"]; + + REQUIRE(diagram->name == "t20003_sequence"); + + auto model = generate_sequence_diagram(*db, diagram); + + REQUIRE(model->name() == "t20003_sequence"); + + auto puml = generate_sequence_puml(diagram, *model); + + REQUIRE_THAT(puml, StartsWith("@startuml")); + REQUIRE_THAT(puml, EndsWith("@enduml\n")); + + REQUIRE_THAT(puml, HasFunctionCall("m1", "m2")); + REQUIRE_THAT(puml, HasFunctionCall("m2", "m3")); + REQUIRE_THAT(puml, HasFunctionCall("m3", "m4")); + + save_puml( + "./" + config.output_directory() + "/" + diagram->name + ".puml", puml); +} diff --git a/tests/test_cases.cc b/tests/test_cases.cc index 5f5381b1..a95557f9 100644 --- a/tests/test_cases.cc +++ b/tests/test_cases.cc @@ -249,6 +249,7 @@ using namespace clanguml::test::matchers; /// #include "t20001/test_case.h" #include "t20002/test_case.h" +#include "t20003/test_case.h" /// /// Package diagram tests