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;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -63,7 +63,6 @@ private:
|
||||
clang::CXXMethodDecl *current_method_decl_;
|
||||
clang::FunctionDecl *current_function_decl_;
|
||||
clang::FunctionTemplateDecl *current_function_template_decl_;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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); }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user