|
|
|
|
@@ -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();
|
|
|
|
|
|