31 , template_builder_{diagram, config, *this}
35std::unique_ptr<sequence_diagram::model::class_>
37 const clang::NamedDecl * )
const
39 return std::make_unique<sequence_diagram::model::class_>(
40 config().using_namespace());
59 clang::CXXRecordDecl *declaration)
65 if (declaration->isTemplated() &&
66 declaration->getDescribedTemplate() !=
nullptr) {
72 if (declaration->isLocalClass() !=
nullptr)
75 LOG_TRACE(
"Visiting class declaration at {}",
87 const auto class_id = class_model_ptr->id();
100 if (!declaration->isCompleteDefinition()) {
108 LOG_DBG(
"Adding class participant {} with id {}",
109 class_model.full_name(
false), class_model.id());
111 assert(class_model.id() == class_id);
116 diagram().add_participant(std::move(class_model_ptr));
120 "Skipping class {} with id {}", class_model.full_name(), class_id);
127 clang::ClassTemplateDecl *declaration)
132 LOG_TRACE(
"Visiting class template declaration {} at {} [{}]",
133 declaration->getQualifiedNameAsString(),
135 (
void *)declaration);
139 if (!class_model_ptr)
144 const auto class_full_name = class_model_ptr->full_name(
false);
149 class_model_ptr->set_id(
id);
153 if (!declaration->getTemplatedDecl()->isCompleteDefinition()) {
160 LOG_DBG(
"Adding class template participant {} with id {}",
161 class_full_name,
id);
166 diagram().add_participant(std::move(class_model_ptr));
173 clang::ClassTemplateSpecializationDecl *declaration)
178 LOG_TRACE(
"Visiting template specialization declaration {} at {}",
179 declaration->getQualifiedNameAsString(),
183 if (declaration->isLocalClass() !=
nullptr)
186 auto template_specialization_ptr =
189 if (!template_specialization_ptr)
192 const auto class_full_name = template_specialization_ptr->full_name(
false);
195 template_specialization_ptr->set_id(
id);
199 if (!declaration->isCompleteDefinition()) {
201 id, std::move(template_specialization_ptr));
208 "Adding class template specialization participant {} with id {}",
209 class_full_name,
id);
214 diagram().add_participant(std::move(template_specialization_ptr));
221 clang::CXXMethodDecl *declaration)
226 auto context_backup =
context();
228 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXMethodDecl(
237 clang::CXXMethodDecl *declaration)
242 if (!declaration->isThisDeclarationADefinition()) {
243 if (
auto *declaration_definition = declaration->getDefinition();
244 declaration_definition !=
nullptr) {
245 if (
auto *method_definition = clang::dyn_cast<clang::CXXMethodDecl>(
246 declaration_definition);
247 method_definition !=
nullptr) {
248 LOG_DBG(
"Calling VisitCXXMethodDecl recursively for forward "
256 LOG_TRACE(
"Visiting method {} in class {} [{}]",
257 declaration->getQualifiedNameAsString(),
258 declaration->getParent()->getQualifiedNameAsString(),
259 (
void *)declaration->getParent());
265 if (!method_model_ptr)
272 const auto method_full_name = method_model_ptr->full_name(
false);
278 if (declaration->isThisDeclarationADefinition()) {
280 declaration->getFirstDecl()->getID(), method_model_ptr->id());
285 LOG_TRACE(
"Set id {} --> {} for method name {} [{}]", declaration->getID(),
286 method_model_ptr->id(), method_full_name,
287 declaration->isThisDeclarationADefinition());
293 diagram().add_participant(std::move(method_model_ptr));
299 clang::FunctionDecl *declaration)
304 auto context_backup =
context();
306 RecursiveASTVisitor<translation_unit_visitor>::TraverseFunctionDecl(
315 clang::FunctionDecl *declaration)
317 if (declaration->isCXXClassMember())
323 if (!declaration->isThisDeclarationADefinition()) {
324 if (
auto *declaration_definition = declaration->getDefinition();
325 declaration_definition !=
nullptr)
327 static_cast<clang::FunctionDecl *
>(declaration_definition));
330 LOG_TRACE(
"Visiting function declaration {} at {}",
331 declaration->getQualifiedNameAsString(),
334 if (declaration->isTemplated()) {
335 if (declaration->getDescribedTemplate() !=
nullptr) {
339 eid_t{declaration->getDescribedTemplate()->getID()}))
344 std::unique_ptr<model::function> function_model_ptr{};
346 if (declaration->isFunctionTemplateSpecialization()) {
354 if (!function_model_ptr)
357 function_model_ptr->set_id(
360 function_model_ptr->is_void(declaration->getReturnType()->isVoidType());
362 function_model_ptr->is_operator(declaration->isOverloadedOperator());
364 function_model_ptr->is_cuda_kernel(
367 function_model_ptr->is_cuda_device(
374 if (declaration->isThisDeclarationADefinition()) {
376 declaration->getFirstDecl()->getID(), function_model_ptr->id());
379 set_unique_id(declaration->getID(), function_model_ptr->id());
385 diagram().add_participant(std::move(function_model_ptr));
391 clang::FunctionTemplateDecl *declaration)
396 const auto function_name = declaration->getQualifiedNameAsString();
398 LOG_TRACE(
"Visiting function template declaration {} at {}", function_name,
408 function_template_model->is_void(
409 declaration->getAsFunction()->getReturnType()->isVoidType());
411 function_template_model->set_id(
414 function_template_model->is_operator(
415 declaration->getAsFunction()->isOverloadedOperator());
421 set_unique_id(declaration->getID(), function_template_model->id());
423 diagram().add_participant(std::move(function_template_model));
433 const auto lambda_full_name =
434 expr->getLambdaClass()->getCanonicalDecl()->getNameAsString();
436 LOG_TRACE(
"Visiting lambda expression {} at {} [caller_id = {}]",
437 lambda_full_name, expr->getBeginLoc().printToString(
source_manager()),
440 LOG_TRACE(
"Lambda call operator ID {} - lambda class ID {}, class call "
442 expr->getCallOperator()->getID(), expr->getLambdaClass()->getID(),
443 expr->getLambdaClass()->getLambdaCallOperator()->getID());
446 auto *cls = expr->getLambdaClass();
449 if (!lambda_class_model_ptr)
452 const auto cls_id = lambda_class_model_ptr->id();
456 auto lambda_method_model_ptr =
459 lambda_method_model_ptr->set_class_id(cls_id);
462 auto lambda_class_full_name = lambda_class_model_ptr->full_name(
false);
463 lambda_method_model_ptr->set_class_full_name(lambda_class_full_name);
465 diagram().add_participant(std::move(lambda_class_model_ptr));
467 lambda_method_model_ptr->set_id(
469 "::" + lambda_method_model_ptr->full_name_no_ns()));
471 get_participant<model::class_>(cls_id).value().set_lambda_operator_id(
472 lambda_method_model_ptr->id());
476 if (std::holds_alternative<clang::CallExpr *>(
477 context().current_callexpr()) &&
478 (!
context().lambda_caller_id().has_value())) {
484 m.set_from(
context().caller_id());
485 m.set_to(lambda_method_model_ptr->id());
487 diagram().add_active_participant(m.from());
488 diagram().add_active_participant(m.to());
490 LOG_DBG(
"Found call {} from {} [{}] to {} [{}]", m.message_name(),
491 m.from(), m.from(), m.to(), m.to());
500 expr->getCallOperator()->getID(), lambda_method_model_ptr->id());
502 diagram().add_participant(std::move(lambda_method_model_ptr));
504 [[maybe_unused]]
const auto is_generic_lambda = expr->isGenericLambda();
511 RecursiveASTVisitor<translation_unit_visitor>::TraverseLambdaExpr(expr);
521 if (!
config().include_system_headers() &&
522 source_manager().isInSystemHeader(expr->getSourceRange().getBegin()))
525 LOG_TRACE(
"Entering call expression at {}",
530 RecursiveASTVisitor<translation_unit_visitor>::TraverseCallExpr(expr);
532 LOG_TRACE(
"Leaving call expression at {}",
543 clang::CUDAKernelCallExpr *expr)
545 if (!
config().include_system_headers() &&
546 source_manager().isInSystemHeader(expr->getSourceRange().getBegin()))
549 LOG_TRACE(
"Entering CUDA kernel call expression at {}",
554 RecursiveASTVisitor<translation_unit_visitor>::TraverseCallExpr(expr);
556 LOG_TRACE(
"Leaving CUDA kernel call expression at {}",
567 clang::CXXMemberCallExpr *expr)
569 if (!
config().include_system_headers() &&
570 source_manager().isInSystemHeader(expr->getSourceRange().getBegin()))
573 LOG_TRACE(
"Entering member call expression at {}",
578 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXMemberCallExpr(
581 LOG_TRACE(
"Leaving member call expression at {}",
592 clang::CXXOperatorCallExpr *expr)
596 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXOperatorCallExpr(
607 clang::CXXTemporaryObjectExpr *expr)
615 clang::dyn_cast<clang::CXXConstructExpr>(expr));
625 clang::CXXConstructExpr *expr)
627 LOG_TRACE(
"Entering cxx construct call expression at {}",
632 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXConstructExpr(
637 LOG_TRACE(
"Leaving cxx construct call expression at {}",
658 const auto *current_elseifstmt =
664 if (current_elseifstmt !=
nullptr) {
665 if (current_elseifstmt->getElse() == stmt) {
668 if (current_caller_id.value() != 0) {
671 diagram().add_message(std::move(m));
675 else if (current_ifstmt !=
nullptr) {
676 if (current_ifstmt->getElse() == stmt) {
679 if (current_caller_id.value() != 0) {
682 diagram().add_message(std::move(m));
687 RecursiveASTVisitor<translation_unit_visitor>::TraverseCompoundStmt(stmt);
699 bool elseif_block{
false};
703 const auto *current_elseifstmt =
706 std::string condition_text;
707 if (
config().generate_condition_statements())
712 auto child_stmt_compare = [stmt](
auto *child_stmt) {
713 return child_stmt == stmt;
716 if (current_ifstmt !=
nullptr)
717 elseif_block = elseif_block ||
718 std::any_of(current_ifstmt->children().begin(),
719 current_ifstmt->children().end(), child_stmt_compare);
720 if (current_elseifstmt !=
nullptr)
721 elseif_block = elseif_block ||
722 std::any_of(current_elseifstmt->children().begin(),
723 current_elseifstmt->children().end(), child_stmt_compare);
725 if ((current_caller_id.value() != 0) && !stmt->isConstexpr()) {
729 message m{message_t::kElseIf, current_caller_id};
731 m.condition_text(condition_text);
733 *
context().get_ast_context(), current_caller_id, stmt));
734 diagram().add_block_message(std::move(m));
739 message m{message_t::kIf, current_caller_id};
741 m.condition_text(condition_text);
743 *
context().get_ast_context(), current_caller_id, stmt));
744 diagram().add_block_message(std::move(m));
748 RecursiveASTVisitor<translation_unit_visitor>::TraverseIfStmt(stmt);
750 if ((current_caller_id.value() != 0) && !stmt->isConstexpr()) {
753 {message_t::kIfEnd, current_caller_id}, message_t::kIf);
769 std::string condition_text;
770 if (
config().generate_condition_statements())
773 if (current_caller_id.value() != 0) {
774 LOG_TRACE(
"Entering while statement at {}",
778 message m{message_t::kWhile, current_caller_id};
780 m.condition_text(condition_text);
782 *
context().get_ast_context(), current_caller_id, stmt));
783 diagram().add_block_message(std::move(m));
786 RecursiveASTVisitor<translation_unit_visitor>::TraverseWhileStmt(stmt);
788 if (current_caller_id.value() != 0) {
790 {message_t::kWhileEnd, current_caller_id}, message_t::kWhile);
805 std::string condition_text;
806 if (
config().generate_condition_statements())
809 if (current_caller_id.value() != 0) {
811 message m{message_t::kDo, current_caller_id};
813 m.condition_text(condition_text);
815 *
context().get_ast_context(), current_caller_id, stmt));
816 diagram().add_block_message(std::move(m));
819 RecursiveASTVisitor<translation_unit_visitor>::TraverseDoStmt(stmt);
821 if (current_caller_id.value() != 0) {
823 {message_t::kDoEnd, current_caller_id}, message_t::kDo);
838 std::string condition_text;
839 if (
config().generate_condition_statements())
842 if (current_caller_id.value() != 0) {
844 message m{message_t::kFor, current_caller_id};
846 m.condition_text(condition_text);
849 *
context().get_ast_context(), current_caller_id, stmt));
851 diagram().add_block_message(std::move(m));
854 RecursiveASTVisitor<translation_unit_visitor>::TraverseForStmt(stmt);
856 if (current_caller_id.value() != 0) {
858 {message_t::kForEnd, current_caller_id}, message_t::kFor);
873 if (current_caller_id.value() != 0) {
875 message m{message_t::kTry, current_caller_id};
878 *
context().get_ast_context(), current_caller_id, stmt));
879 diagram().add_block_message(std::move(m));
882 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXTryStmt(stmt);
884 if (current_caller_id.value() != 0) {
886 {message_t::kTryEnd, current_caller_id}, message_t::kTry);
901 if ((current_caller_id.value() != 0) &&
902 (
context().current_trystmt() !=
nullptr)) {
903 std::string caught_type;
904 if (stmt->getCaughtType().isNull())
908 stmt->getCaughtType(), *
context().get_ast_context());
912 diagram().add_message(std::move(m));
915 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXCatchStmt(stmt);
921 clang::CXXForRangeStmt *stmt)
929 std::string condition_text;
930 if (
config().generate_condition_statements())
933 if (current_caller_id.value() != 0) {
935 message m{message_t::kFor, current_caller_id};
937 m.condition_text(condition_text);
939 *
context().get_ast_context(), current_caller_id, stmt));
940 diagram().add_block_message(std::move(m));
943 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXForRangeStmt(
946 if (current_caller_id.value() != 0) {
948 {message_t::kForEnd, current_caller_id}, message_t::kFor);
961 if (current_caller_id.value() != 0) {
966 *
context().get_ast_context(), current_caller_id, stmt));
967 diagram().add_block_message(std::move(m));
970 RecursiveASTVisitor<translation_unit_visitor>::TraverseSwitchStmt(stmt);
972 if (current_caller_id.value() != 0) {
975 {message_t::kSwitchEnd, current_caller_id}, message_t::kSwitch);
987 if ((current_caller_id.value() != 0) &&
988 (
context().current_switchstmt() !=
nullptr)) {
991 diagram().add_case_stmt_message(std::move(m));
994 RecursiveASTVisitor<translation_unit_visitor>::TraverseCaseStmt(stmt);
1005 if ((current_caller_id.value() != 0) &&
1006 (
context().current_switchstmt() !=
nullptr)) {
1009 diagram().add_case_stmt_message(std::move(m));
1012 RecursiveASTVisitor<translation_unit_visitor>::TraverseDefaultStmt(stmt);
1018 clang::ConditionalOperator *stmt)
1024 std::string condition_text;
1025 if (
config().generate_condition_statements())
1028 if (current_caller_id.value() != 0) {
1032 m.condition_text(condition_text);
1034 *
context().get_ast_context(), current_caller_id, stmt));
1035 diagram().add_block_message(std::move(m));
1038 RecursiveASTVisitor<translation_unit_visitor>::TraverseStmt(
1041 RecursiveASTVisitor<translation_unit_visitor>::TraverseStmt(
1042 stmt->getTrueExpr());
1044 if (current_caller_id.value() != 0) {
1045 model::message m{message_t::kConditionalElse, current_caller_id};
1047 diagram().add_message(std::move(m));
1050 RecursiveASTVisitor<translation_unit_visitor>::TraverseStmt(
1051 stmt->getFalseExpr());
1053 if (current_caller_id.value() != 0) {
1056 {message_t::kConditionalEnd, current_caller_id},
1057 message_t::kConditional);
1071 if (!
context().valid() ||
context().get_ast_context() ==
nullptr)
1074 LOG_TRACE(
"Visiting call expression at {} [caller_id = {}]",
1087 raw_expr_comment,
context().get_ast_context()->getDiagnostics(), m);
1095 LOG_DBG(
"Skipping call expression due to filter at: {}",
1102 if (
context().is_expr_in_current_control_statement_condition(expr)) {
1106 if (generated_message_from_comment) {
1108 "Message for this call expression is taken from comment directive");
1113 else if (
const auto *cuda_call_expr =
1114 clang::dyn_cast_or_null<clang::CUDAKernelCallExpr>(expr);
1115 cuda_call_expr !=
nullptr) {
1122 else if (
const auto *operator_call_expr =
1123 clang::dyn_cast_or_null<clang::CXXOperatorCallExpr>(expr);
1124 operator_call_expr !=
nullptr) {
1132 else if (
const auto *method_call_expr =
1133 clang::dyn_cast_or_null<clang::CXXMemberCallExpr>(expr);
1134 method_call_expr !=
nullptr) {
1143 auto *callee_decl = expr->getCalleeDecl();
1145 if (callee_decl ==
nullptr) {
1146 LOG_DBG(
"Cannot get callee declaration - trying direct function "
1149 callee_decl = expr->getDirectCallee();
1151 if (callee_decl !=
nullptr)
1152 LOG_DBG(
"Found function/method callee in: {}",
1156 if (callee_decl ==
nullptr) {
1160 if (clang::dyn_cast_or_null<clang::CXXDependentScopeMemberExpr>(
1161 expr->getCallee()) !=
nullptr) {
1170 else if (clang::dyn_cast_or_null<clang::UnresolvedLookupExpr>(
1171 expr->getCallee()) !=
nullptr) {
1175 else if (clang::dyn_cast_or_null<clang::LambdaExpr>(
1176 expr->getCallee()) !=
nullptr) {
1177 LOG_DBG(
"Processing lambda expression callee");
1182 LOG_DBG(
"Found unsupported callee decl type for: {} at {}",
1191 LOG_DBG(
"Skipping call expression at: {}",
1200 if (m.from().value() > 0 && m.to().value() > 0) {
1201 if (raw_expr_comment !=
nullptr)
1202 m.set_comment(raw_expr_comment->getBeginLoc().getHashValue(),
1205 if (
diagram().sequences().find(m.from()) ==
1206 diagram().sequences().end()) {
1207 activity a{m.from()};
1208 diagram().sequences().insert({m.from(), std::move(a)});
1211 diagram().add_active_participant(m.from());
1212 diagram().add_active_participant(m.to());
1214 LOG_DBG(
"Found call {} from {} [{}] to {} [{}] ", m.message_name(),
1215 m.from(), m.from(), m.to(), m.to());
1226 auto generated_message_from_comment{
false};
1227 for (
const auto &decorator : m.
decorators()) {
1228 auto call_decorator =
1229 std::dynamic_pointer_cast<decorators::call>(decorator);
1230 if (call_decorator &&
1231 call_decorator->applies_to_diagram(
config().name)) {
1233 generated_message_from_comment =
true;
1237 return generated_message_from_comment;
1242 if (decl->isStaticLocal())
1245 RecursiveASTVisitor::TraverseVarDecl(decl);
1247 if (decl->isStaticLocal())
1254 clang::CXXConstructExpr *expr)
1262 if (expr ==
nullptr)
1265 if (
const auto *ctor = expr->getConstructor();
1269 LOG_TRACE(
"Visiting cxx construct expression at {} [caller_id = {}]",
1279 if (
context().is_expr_in_current_control_statement_condition(expr)) {
1286 if (m.from().value() > 0 && m.to().value() > 0) {
1287 if (
diagram().sequences().find(m.from()) ==
1288 diagram().sequences().end()) {
1289 activity a{m.from()};
1290 diagram().sequences().insert({m.from(), std::move(a)});
1293 diagram().add_active_participant(m.from());
1294 diagram().add_active_participant(m.to());
1296 LOG_DBG(
"Found constructor call {} from {} [{}] to {} [{}] ",
1297 m.message_name(), m.from(), m.from(), m.to(), m.to());
1308 const auto *callee_decl = expr->getCalleeDecl();
1310 if (callee_decl ==
nullptr)
1313 const auto *callee_function = callee_decl->getAsFunction();
1315 if (callee_function ==
nullptr)
1322 if (
config().combine_free_functions_into_file_participants() &&
1326 auto callee_name = callee_function->getQualifiedNameAsString() +
"()";
1335 model::message &m,
const clang::CXXOperatorCallExpr *operator_call_expr)
1337 if (operator_call_expr->getCalleeDecl() ==
nullptr)
1340 LOG_DBG(
"Operator '{}' call expression to {} at {}",
1341 getOperatorSpelling(operator_call_expr->getOperator()),
1342 operator_call_expr->getCalleeDecl()->getID(),
1343 operator_call_expr->getBeginLoc().printToString(
source_manager()));
1346 if (
const auto *lambda_method = clang::dyn_cast<clang::CXXMethodDecl>(
1347 operator_call_expr->getCalleeDecl());
1348 lambda_method !=
nullptr && lambda_method->getParent()->isLambda()) {
1350 LOG_DBG(
"Operator callee is a lambda: {}",
1353 const auto source_location{
1358 m.
set_to(
eid_t{lambda_method->getParent()->getID()});
1361 const auto operator_ast_id =
1362 operator_call_expr->getCalleeDecl()->getID();
1367 "operator{}", getOperatorSpelling(operator_call_expr->getOperator())));
1373 model::message &m,
const clang::CXXConstructExpr *construct_expr)
1375 const auto *constructor = construct_expr->getConstructor();
1376 if (constructor ==
nullptr)
1379 const auto *constructor_parent = constructor->getParent();
1380 if (constructor_parent ==
nullptr)
1383 LOG_DBG(
"Constructor '{}' call expression to {} at {}",
1384 construct_expr->getConstructor()->getNameAsString(),
1385 constructor->getID(),
1390 fmt::format(
"{}::{}", constructor_parent->getQualifiedNameAsString(),
1391 constructor_parent->getNameAsString()));
1393 diagram().add_active_participant(
eid_t{constructor->getID()});
1399 model::message &m,
const clang::CXXMemberCallExpr *method_call_expr)
1402 const auto *method_decl = method_call_expr->getMethodDecl();
1404 if (method_decl ==
nullptr)
1407 std::string method_name = method_decl->getQualifiedNameAsString();
1409 const auto *callee_decl =
1410 method_decl !=
nullptr ? method_decl->getParent() :
nullptr;
1412 if (callee_decl ==
nullptr)
1421 method_call_expr->getCallReturnType(*
context().get_ast_context())
1424 LOG_TRACE(
"Set callee method id {} for method name {}", m.
to(),
1425 method_decl->getQualifiedNameAsString());
1427 diagram().add_active_participant(
eid_t{method_decl->getID()});
1435 const auto *dependent_member_callee =
1436 clang::dyn_cast_or_null<clang::CXXDependentScopeMemberExpr>(
1439 if (dependent_member_callee ==
nullptr)
1443 if (
const auto *tst = dependent_member_callee->getBaseType()
1444 ->getAs<clang::TemplateSpecializationType>();
1446 const auto *template_declaration =
1447 tst->getTemplateName().getAsTemplateDecl();
1449 std::string callee_method_full_name;
1457 "::" + dependent_member_callee->getMember().getAsString();
1459 for (
const auto &[
id, p] :
diagram().participants()) {
1460 const auto p_full_name = p->full_name(
false);
1462 if (p_full_name.find(callee_method_full_name +
"(") == 0) {
1472 const auto *argument_template =
1473 template_declaration->getTemplateParameters()
1482 dependent_member_callee->getMember().getAsString();
1484 for (
const auto &[
id, p] :
diagram().participants()) {
1485 const auto p_full_name = p->full_name(
false);
1486 if (p_full_name.find(callee_method_full_name +
"(") ==
1500 dependent_member_callee->getMember().getAsString());
1502 if (
const auto maybe_id =
1504 maybe_id.has_value())
1505 diagram().add_active_participant(maybe_id.value());
1509 LOG_DBG(
"Skipping call due to unresolvable "
1510 "CXXDependentScopeMemberExpr at {}",
1520 const auto *callee_decl = expr->getCalleeDecl();
1522 if (callee_decl ==
nullptr)
1525 const auto *callee_function = callee_decl->getAsFunction();
1527 if (callee_function ==
nullptr)
1534 if (
config().combine_free_functions_into_file_participants() &&
1538 auto callee_name = callee_function->getQualifiedNameAsString() +
"()";
1549 const auto *lambda_expr =
1550 clang::dyn_cast_or_null<clang::LambdaExpr>(expr->getCallee());
1552 if (lambda_expr ==
nullptr)
1555 const auto lambda_class_id =
eid_t{lambda_expr->getLambdaClass()->getID()};
1565 const auto *unresolved_expr =
1566 clang::dyn_cast_or_null<clang::UnresolvedLookupExpr>(expr->getCallee());
1568 if (unresolved_expr !=
nullptr) {
1569 for (
const auto *decl : unresolved_expr->decls()) {
1570 if (clang::dyn_cast_or_null<clang::FunctionTemplateDecl>(decl) !=
1573 clang::dyn_cast_or_null<clang::FunctionTemplateDecl>(decl);
1578 if (clang::dyn_cast_or_null<clang::FunctionDecl>(decl) !=
nullptr) {
1580 clang::dyn_cast_or_null<clang::FunctionDecl>(decl);
1585 LOG_DBG(
"Unknown unresolved lookup expression");
1593 const clang::CXXDependentScopeMemberExpr *dependent_member_expr)
const
1595 if (dependent_member_expr ==
nullptr)
1598 if (dependent_member_expr->getBaseType().isNull())
1601 const auto *tst = dependent_member_expr->getBaseType()
1602 ->getAs<clang::TemplateSpecializationType>();
1607 return !(tst->isPointerType());
1611 const clang::TemplateDecl *primary_template)
const
1613 return primary_template->getQualifiedNameAsString().find(
1614 "std::unique_ptr") == 0 ||
1615 primary_template->getQualifiedNameAsString().find(
"std::shared_ptr") ==
1617 primary_template->getQualifiedNameAsString().find(
"std::weak_ptr") == 0;
1620std::unique_ptr<clanguml::sequence_diagram::model::class_>
1623 assert(cls !=
nullptr);
1625 auto c_ptr{std::make_unique<clanguml::sequence_diagram::model::class_>(
1626 config().using_namespace())};
1629 auto qualified_name = cls->getQualifiedNameAsString();
1631 if (!cls->isLambda())
1640 const auto *parent = cls->getParent();
1642 if ((parent !=
nullptr) && parent->isRecord()) {
1647 std::optional<eid_t> id_opt;
1648 const auto *parent_record_decl =
1649 clang::dyn_cast<clang::RecordDecl>(parent);
1651 assert(parent_record_decl !=
nullptr);
1653 const eid_t ast_id{parent_record_decl->getID()};
1661 (parent_record_decl->getDescribedTemplate() !=
nullptr)) {
1662 parent_record_decl->getDescribedTemplate()->getID();
1663 if (parent_record_decl->getDescribedTemplate() !=
nullptr)
1675 if (!parent_class) {
1680 if (cls->getNameAsString().empty()) {
1683 const auto &[label, hint, access] =
1686 c.set_name(parent_class.value().name() +
1687 "::" + fmt::format(
"({})", label));
1689 parent_class.value().add_relationship(
1693 c.set_name(parent_class.value().name() +
"::" +
1695 "(anonymous_{})", std::to_string(cls->getID())));
1699 parent_class.value().name() +
"::" + cls->getNameAsString());
1706 else if (cls->isLambda()) {
1708 if (cls->getParent() !=
nullptr) {
1711 c.set_name(type_name);
1712 c.set_namespace(ns);
1716 LOG_WARN(
"Cannot find parent declaration for lambda {}",
1717 cls->getQualifiedNameAsString());
1723 c.set_namespace(ns);
1727 c.is_struct(cls->isStruct());
1735 c.set_style(c.style_spec());
1742 LOG_TRACE(
"Setting local element mapping {} --> {}", local_id, global_id);
1750 eid_t local_id)
const
1755std::unique_ptr<model::function_template>
1757 const clang::FunctionTemplateDecl &declaration)
1759 auto function_template_model_ptr =
1760 std::make_unique<sequence_diagram::model::function_template>(
1761 config().using_namespace());
1766 *function_template_model_ptr, declaration);
1768 function_template_model_ptr->return_type(
1770 declaration.getASTContext()));
1772 for (
const auto *param : declaration.getTemplatedDecl()->parameters()) {
1773 function_template_model_ptr->add_parameter(
1775 param->getType(), declaration.getASTContext(),
false)));
1778 return function_template_model_ptr;
1781std::unique_ptr<model::function_template>
1783 const clang::FunctionDecl &decl)
1785 auto template_instantiation_ptr =
1786 std::make_unique<model::function_template>(
config().using_namespace());
1787 auto &template_instantiation = *template_instantiation_ptr;
1791 tbuilder().
build(template_instantiation, &decl, decl.getPrimaryTemplate(),
1792 decl.getTemplateSpecializationArgs()->asArray(),
1796 for (
const auto *param : decl.parameters()) {
1797 template_instantiation_ptr->add_parameter(
1801 return template_instantiation_ptr;
1805 const clang::FunctionDecl &declaration)
1807 auto function_model_ptr =
1808 std::make_unique<sequence_diagram::model::function>(
1809 config().using_namespace());
1812 function_model_ptr->set_name(ns.name());
1814 function_model_ptr->set_namespace(ns);
1817 declaration.getReturnType(), declaration.getASTContext()));
1819 for (
const auto *param : declaration.parameters()) {
1820 function_model_ptr->add_parameter(
1822 param->getType(), declaration.getASTContext(),
false)));
1825 return function_model_ptr;
1828std::unique_ptr<model::class_>
1830 clang::ClassTemplateSpecializationDecl *cls)
1832 auto c_ptr{std::make_unique<model::class_>(
config().using_namespace())};
1836 auto &template_instantiation = *c_ptr;
1839 auto qualified_name = cls->getQualifiedNameAsString();
1845 template_instantiation.set_name(cls->getNameAsString());
1846 template_instantiation.set_namespace(ns);
1848 template_instantiation.is_struct(cls->isStruct());
1854 if (template_instantiation.skip())
1857 template_instantiation.set_id(
1866 const std::string &full_name)
const
1868 return config().simplify_template_type(full_name);
1872 const clang::SourceLocation &source_location)
const
1874 const auto file_line =
1876 const auto file_column =
1878 const std::string file_name =
1880 .make_path_relative(
1883 return fmt::format(
"{}:{}:{}", file_name, file_line, file_column);
1887 const clang::CXXRecordDecl *cls)
const
1890 const auto location = cls->getLocation();
1894 if (maybe_lambda_caller_id.has_value()) {
1896 std::string parent_lambda_class_name{
"()"};
1897 if (
diagram().get_participant<model::method>(
1898 maybe_lambda_caller_id.value())) {
1899 auto parent_lambda_class_id =
1902 maybe_lambda_caller_id.value())
1907 parent_lambda_class_id)) {
1908 parent_lambda_class_name =
1916 result = fmt::format(
1917 "{}##(lambda {})", parent_lambda_class_name, source_location);
1919 else if (
context().caller_id().value() != 0 &&
1921 auto parent_full_name =
1925 fmt::format(
"{}##(lambda {})", parent_full_name, source_location);
1928 result = fmt::format(
"(lambda {})", source_location);
1948 assert(expr !=
nullptr);
1957 auto caller_id = msg.from();
1962 if (
diagram().has_activity(caller_id))
1963 diagram().get_activity(caller_id).add_message(std::move(msg));
1969 clang::CXXConstructExpr *expr)
1971 assert(expr !=
nullptr);
1981 auto caller_id = msg.from();
1982 diagram().get_activity(caller_id).add_message(std::move(msg));
1997 if (
config().inline_lambda_messages())
1998 diagram().inline_lambda_operator_calls();
2003 for (
auto &[
id, activity] :
diagram().sequences()) {
2004 for (
auto &m : activity.messages()) {
2007 if (participant && participant.value().is_lambda() &&
2008 participant.value().lambda_operator_id().value() != 0) {
2009 LOG_DBG(
"Changing lambda expression target id from {} to {}",
2010 m.to(), participant.value().lambda_operator_id());
2012 m.set_to(participant.value().lambda_operator_id());
2013 m.set_message_name(
"operator()");
2021 std::set<eid_t> active_participants_unique;
2024 for (
auto id :
diagram().active_participants()) {
2026 !
id.is_global() && unique_id.has_value()) {
2027 active_participants_unique.emplace(unique_id.value());
2029 else if (
id.is_global()) {
2030 active_participants_unique.emplace(
id);
2034 diagram().active_participants() = std::move(active_participants_unique);
2037 for (
auto &[
id, activity] :
diagram().sequences()) {
2038 for (
auto &m : activity.messages()) {
2040 !m.to().is_global() && unique_id.has_value()) {
2041 m.set_to(unique_id.value());
2042 assert(m.to().is_global());
2048std::unique_ptr<clanguml::sequence_diagram::model::method>
2050 clang::CXXMethodDecl *declaration)
2052 auto method_model_ptr = std::make_unique<sequence_diagram::model::method>(
2053 config().using_namespace());
2056 auto method_name = ns.
name();
2057 method_model_ptr->set_method_name(method_name);
2059 method_model_ptr->set_name(ns.name());
2061 method_model_ptr->set_namespace(ns);
2063 method_model_ptr->is_defaulted(declaration->isDefaulted());
2064 method_model_ptr->is_assignment(declaration->isCopyAssignmentOperator() ||
2065 declaration->isMoveAssignmentOperator());
2066 method_model_ptr->is_const(declaration->isConst());
2067 method_model_ptr->is_static(declaration->isStatic());
2068 method_model_ptr->is_operator(declaration->isOverloadedOperator());
2069 method_model_ptr->is_constructor(
2070 clang::dyn_cast<clang::CXXConstructorDecl>(declaration) !=
nullptr);
2072 method_model_ptr->is_void(declaration->getReturnType()->isVoidType());
2075 declaration->getReturnType(), declaration->getASTContext()));
2077 for (
const auto *param : declaration->parameters()) {
2078 auto parameter_type =
2082 method_model_ptr->add_parameter(
config().using_namespace().relative(
2086 return method_model_ptr;
2089std::unique_ptr<clanguml::sequence_diagram::model::method>
2092 auto method_model_ptr = std::make_unique<sequence_diagram::model::method>(
2093 config().using_namespace());
2096 auto method_name = ns.
name();
2097 method_model_ptr->set_method_name(method_name);
2099 method_model_ptr->set_name(ns.name());
2101 method_model_ptr->set_namespace(ns);
2103 method_model_ptr->is_defaulted(declaration->isDefaulted());
2104 method_model_ptr->is_assignment(declaration->isCopyAssignmentOperator() ||
2105 declaration->isMoveAssignmentOperator());
2106 method_model_ptr->is_const(declaration->isConst());
2107 method_model_ptr->is_static(declaration->isStatic());
2108 method_model_ptr->is_operator(declaration->isOverloadedOperator());
2109 method_model_ptr->is_constructor(
2110 clang::dyn_cast<clang::CXXConstructorDecl>(declaration) !=
nullptr);
2112 clang::Decl *parent_decl = declaration->getParent();
2114 if (
context().current_class_template_decl_ !=
nullptr)
2117 LOG_DBG(
"Getting method's class with local id {}", parent_decl->getID());
2119 const auto maybe_method_class = get_participant<model::class_>(parent_decl);
2121 if (!maybe_method_class) {
2122 LOG_DBG(
"Cannot find parent class_ for method {} in class {}",
2123 declaration->getQualifiedNameAsString(),
2124 declaration->getParent()->getQualifiedNameAsString());
2128 const auto &method_class = maybe_method_class.value();
2130 method_model_ptr->is_void(declaration->getReturnType()->isVoidType());
2132 method_model_ptr->set_class_id(method_class.id());
2133 method_model_ptr->set_class_full_name(method_class.full_name(
false));
2134 method_model_ptr->set_name(
get_participant(method_model_ptr->class_id())
2136 .full_name_no_ns() +
2137 "::" + declaration->getNameAsString());
2140 declaration->getReturnType(), declaration->getASTContext()));
2142 for (
const auto *param : declaration->parameters()) {
2143 auto parameter_type =
2147 method_model_ptr->add_parameter(
config().using_namespace().relative(
2151 return method_model_ptr;
2157 dynamic_cast<const clang::NamedDecl *
>(decl));
2161 const clang::LambdaExpr *expr)
const
2163 const auto expr_file = expr->getBeginLoc().printToString(
source_manager());
2169 if (
context().caller_id() == 0)
2173 if (expr->isCallToStdMove())
2176 if (expr->isImplicitCXXThis())
2179 if (clang::dyn_cast_or_null<clang::ImplicitCastExpr>(expr) !=
nullptr)
2185 const auto expr_file = expr->getBeginLoc().printToString(
source_manager());
2190 const auto *callee_decl = expr->getCalleeDecl();
2192 if (callee_decl !=
nullptr) {
2193 const auto *callee_function = callee_decl->getAsFunction();
2195 if ((callee_function ==
nullptr) || !
should_include(callee_function)) {
2196 LOG_DBG(
"Skipping call expression at {}",
2208 const clang::CXXMethodDecl *decl)
const
2217 LOG_DBG(
"Including method {}", decl->getQualifiedNameAsString());
2223 const clang::FunctionDecl *decl)
const
2229 const clang::FunctionTemplateDecl *decl)
const
2235 const clang::ClassTemplateDecl *decl)
const
2240std::optional<std::pair<unsigned int, std::string>>
2242 const clang::ASTContext &context,
const eid_t caller_id,
2243 const clang::Stmt *stmt)
2245 const auto *raw_comment =
2248 if (raw_comment ==
nullptr)
2259 raw_comment->getFormattedText(sm, sm.getDiagnostics()));
2261 if (stripped_comment.empty())
2264 return {{raw_comment->getBeginLoc().getHashValue(), stripped_comment}};