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::ObjCProtocolDecl *declaration)
64 LOG_TRACE(
"Visiting ObjC interface declaration at {}",
69 if (!objc_protocol_model_ptr)
74 const auto class_id = objc_protocol_model_ptr->id();
78 auto &class_model =
get_participant(class_id, *objc_protocol_model_ptr);
81 LOG_DBG(
"Adding ObjC protocol participant {} with id {}",
82 class_model.full_name(
false), class_model.id());
84 assert(class_model.id() == class_id);
89 diagram().add_participant(std::move(objc_protocol_model_ptr));
92 LOG_DBG(
"Skipping ObjC protocol {} with id {}",
93 class_model.full_name(
true), class_id);
100 clang::ObjCInterfaceDecl *declaration)
105 LOG_TRACE(
"Visiting ObjC interface declaration at {}",
112 if (!objc_interface_model_ptr)
117 const auto class_id = objc_interface_model_ptr->id();
121 auto &class_model =
get_participant(class_id, *objc_interface_model_ptr);
124 LOG_DBG(
"Adding ObjC interface participant {} with id {}",
125 class_model.full_name(
false), class_model.id());
127 assert(class_model.id() == class_id);
132 diagram().add_participant(std::move(objc_interface_model_ptr));
135 LOG_DBG(
"Skipping ObjC interface {} with id {}",
136 class_model.full_name(
true), class_id);
143 clang::CXXRecordDecl *declaration)
145 auto context_backup =
context();
147 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXRecordDecl(
156 clang::CXXRecordDecl *declaration)
162 if (declaration->isTemplated() &&
163 declaration->getDescribedTemplate() !=
nullptr) {
168 LOG_TRACE(
"Visiting class declaration at {}",
175 if (!class_model_ptr)
180 const auto class_id = class_model_ptr->id();
186 if (!declaration->isCompleteDefinition()) {
194 LOG_DBG(
"Adding class participant {} with id {}",
195 class_model.full_name(
false), class_model.id());
197 assert(class_model.id() == class_id);
202 diagram().add_participant(std::move(class_model_ptr));
205 LOG_DBG(
"Skipping class {} with id {}", class_model.full_name(
true),
213 clang::ClassTemplateDecl *declaration)
218 LOG_TRACE(
"Visiting class template declaration {} at {} [{}]",
219 declaration->getQualifiedNameAsString(),
221 (
void *)declaration);
225 if (!class_model_ptr)
230 const auto class_full_name = class_model_ptr->full_name(
false);
235 class_model_ptr->set_id(
id);
239 if (!declaration->getTemplatedDecl()->isCompleteDefinition()) {
246 LOG_DBG(
"Adding class template participant {} with id {}",
247 class_full_name,
id);
252 diagram().add_participant(std::move(class_model_ptr));
259 clang::ClassTemplateSpecializationDecl *declaration)
264 LOG_TRACE(
"Visiting template specialization declaration {} at {}",
265 declaration->getQualifiedNameAsString(),
268 if (declaration->isLocalClass() !=
nullptr)
271 auto template_specialization_ptr =
274 if (!template_specialization_ptr)
277 const auto class_full_name = template_specialization_ptr->full_name(
false);
280 template_specialization_ptr->set_id(
id);
284 if (!declaration->isCompleteDefinition()) {
286 id, std::move(template_specialization_ptr));
293 "Adding class template specialization participant {} with id {}",
294 class_full_name,
id);
299 diagram().add_participant(std::move(template_specialization_ptr));
306 clang::ObjCMethodDecl *declaration)
311 auto context_backup =
context();
313 RecursiveASTVisitor<translation_unit_visitor>::TraverseObjCMethodDecl(
322 clang::ObjCMethodDecl *declaration)
327 LOG_TRACE(
"Visiting ObjC method {} in class",
328 declaration->getQualifiedNameAsString());
334 if (!method_model_ptr)
341 const auto method_full_name = method_model_ptr->full_name(
false);
347 LOG_TRACE(
"Set id {} --> {} for method name {} [{}]", declaration->getID(),
348 method_model_ptr->id(), method_full_name,
349 declaration->isThisDeclarationADefinition());
355 diagram().add_participant(std::move(method_model_ptr));
361 clang::CXXMethodDecl *declaration)
366 auto context_backup =
context();
368 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXMethodDecl(
377 clang::CXXMethodDecl *declaration)
382 if (!declaration->isThisDeclarationADefinition()) {
383 if (
auto *declaration_definition = declaration->getDefinition();
384 declaration_definition !=
nullptr) {
385 if (
auto *method_definition = clang::dyn_cast<clang::CXXMethodDecl>(
386 declaration_definition);
387 method_definition !=
nullptr) {
388 LOG_DBG(
"Calling VisitCXXMethodDecl recursively for forward "
396 LOG_TRACE(
"Visiting method {} in class {} [{}]",
397 declaration->getQualifiedNameAsString(),
398 declaration->getParent()->getQualifiedNameAsString(),
399 (
void *)declaration->getParent());
405 if (!method_model_ptr)
412 const auto method_full_name = method_model_ptr->full_name(
false);
418 if (declaration->isThisDeclarationADefinition()) {
420 declaration->getFirstDecl()->getID(), method_model_ptr->id());
425 LOG_TRACE(
"Set id {} --> {} for method name {} [{}]", declaration->getID(),
426 method_model_ptr->id(), method_full_name,
427 declaration->isThisDeclarationADefinition());
433 diagram().add_participant(std::move(method_model_ptr));
439 clang::FunctionDecl *declaration)
444 auto context_backup =
context();
446 RecursiveASTVisitor<translation_unit_visitor>::TraverseFunctionDecl(
455 clang::FunctionDecl *declaration)
457 if (declaration->isCXXClassMember())
463 if (!declaration->isThisDeclarationADefinition()) {
464 if (
auto *declaration_definition = declaration->getDefinition();
465 declaration_definition !=
nullptr)
467 static_cast<clang::FunctionDecl *
>(declaration_definition));
470 LOG_TRACE(
"Visiting function declaration {} at {}",
471 declaration->getQualifiedNameAsString(),
474 if (declaration->isTemplated()) {
475 if (declaration->getDescribedTemplate() !=
nullptr) {
479 eid_t{declaration->getDescribedTemplate()->getID()}))
484 std::unique_ptr<model::function> function_model_ptr{};
486 if (declaration->isFunctionTemplateSpecialization()) {
494 if (!function_model_ptr)
497 function_model_ptr->set_id(
500 function_model_ptr->is_void(declaration->getReturnType()->isVoidType());
502 function_model_ptr->is_operator(declaration->isOverloadedOperator());
504 function_model_ptr->is_cuda_kernel(
507 function_model_ptr->is_cuda_device(
516 if (declaration->isThisDeclarationADefinition()) {
518 declaration->getFirstDecl()->getID(), function_model_ptr->id());
521 set_unique_id(declaration->getID(), function_model_ptr->id());
527 diagram().add_participant(std::move(function_model_ptr));
533 clang::FunctionTemplateDecl *declaration)
538 auto context_backup =
context();
540 RecursiveASTVisitor<translation_unit_visitor>::TraverseFunctionTemplateDecl(
549 clang::FunctionTemplateDecl *declaration)
554 const auto function_name = declaration->getQualifiedNameAsString();
556 LOG_TRACE(
"Visiting function template declaration {} at {}", function_name,
566 function_template_model->is_void(
567 declaration->getAsFunction()->getReturnType()->isVoidType());
569 function_template_model->set_id(
572 function_template_model->is_operator(
573 declaration->getAsFunction()->isOverloadedOperator());
579 set_unique_id(declaration->getID(), function_template_model->id());
581 diagram().add_participant(std::move(function_template_model));
591 const auto lambda_full_name =
592 expr->getLambdaClass()->getCanonicalDecl()->getNameAsString();
594 LOG_TRACE(
"Visiting lambda expression {} at {} [caller_id = {}]",
595 lambda_full_name, expr->getBeginLoc().printToString(
source_manager()),
598 LOG_TRACE(
"Lambda call operator ID {} - lambda class ID {}, class call "
600 expr->getCallOperator()->getID(), expr->getLambdaClass()->getID(),
601 expr->getLambdaClass()->getLambdaCallOperator()->getID());
604 auto *cls = expr->getLambdaClass();
607 if (!lambda_class_model_ptr)
610 lambda_class_model_ptr->is_lambda(
true);
612 const auto cls_id = lambda_class_model_ptr->id();
616 auto lambda_method_model_ptr =
619 lambda_method_model_ptr->set_class_id(cls_id);
622 auto lambda_class_full_name = lambda_class_model_ptr->full_name(
false);
623 lambda_method_model_ptr->set_class_full_name(lambda_class_full_name);
625 diagram().add_participant(std::move(lambda_class_model_ptr));
627 lambda_method_model_ptr->set_id(
629 "::" + lambda_method_model_ptr->full_name_no_ns()));
631 get_participant<model::class_>(cls_id).value().set_lambda_operator_id(
632 lambda_method_model_ptr->id());
637 if (std::holds_alternative<clang::CallExpr *>(
638 context().current_callexpr()) &&
639 (!
context().lambda_caller_id().has_value()) &&
641 std::get<clang::CallExpr *>(
context().current_callexpr()))) {
647 m.set_from(
context().caller_id());
648 m.set_to(lambda_method_model_ptr->id());
652 diagram().add_active_participant(m.from());
653 diagram().add_active_participant(m.to());
655 LOG_DBG(
"Found call in lambda expression {} from {} [{}] to {} [{}]",
656 m.message_name(), m.from(), m.from(), m.to(), m.to());
665 expr->getCallOperator()->getID(), lambda_method_model_ptr->id());
667 diagram().add_participant(std::move(lambda_method_model_ptr));
669 [[maybe_unused]]
const auto is_generic_lambda = expr->isGenericLambda();
676 auto context_backup =
context();
678 RecursiveASTVisitor<translation_unit_visitor>::TraverseLambdaExpr(expr);
689 clang::ObjCMessageExpr *expr)
691 if (!
config().include_system_headers() &&
692 source_manager().isInSystemHeader(expr->getSourceRange().getBegin()))
695 LOG_TRACE(
"Entering ObjC message expression at {}",
700 RecursiveASTVisitor<translation_unit_visitor>::TraverseObjCMessageExpr(
703 LOG_TRACE(
"Leaving ObjC message expression at {}",
715 if (!
config().include_system_headers() &&
716 source_manager().isInSystemHeader(expr->getSourceRange().getBegin()))
719 LOG_TRACE(
"Entering co_yield expression at {}",
724 RecursiveASTVisitor<translation_unit_visitor>::TraverseCoyieldExpr(expr);
726 LOG_TRACE(
"Leaving co_yield expression at {}",
738 if (!
config().include_system_headers() &&
739 source_manager().isInSystemHeader(expr->getSourceRange().getBegin()))
742 LOG_TRACE(
"Entering co_await expression at {}",
747 RecursiveASTVisitor<translation_unit_visitor>::TraverseCoawaitExpr(expr);
749 LOG_TRACE(
"Leaving co_await expression at {}",
761 if (!
config().include_system_headers() &&
762 source_manager().isInSystemHeader(stmt->getSourceRange().getBegin()))
765 LOG_TRACE(
"Entering co_return statement at {}",
770 RecursiveASTVisitor<translation_unit_visitor>::TraverseCoreturnStmt(stmt);
772 LOG_TRACE(
"Leaving co_return statement at {}",
784 if (!
config().include_system_headers() &&
785 source_manager().isInSystemHeader(expr->getSourceRange().getBegin()))
788 LOG_TRACE(
"Entering call expression at {}",
793 RecursiveASTVisitor<translation_unit_visitor>::TraverseCallExpr(expr);
795 LOG_TRACE(
"Leaving call expression at {}",
806 clang::CUDAKernelCallExpr *expr)
808 if (!
config().include_system_headers() &&
809 source_manager().isInSystemHeader(expr->getSourceRange().getBegin()))
812 LOG_TRACE(
"Entering CUDA kernel call expression at {}",
817 RecursiveASTVisitor<translation_unit_visitor>::TraverseCallExpr(expr);
819 LOG_TRACE(
"Leaving CUDA kernel call expression at {}",
830 clang::CXXMemberCallExpr *expr)
832 if (!
config().include_system_headers() &&
833 source_manager().isInSystemHeader(expr->getSourceRange().getBegin()))
836 LOG_TRACE(
"Entering member call expression at {}",
841 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXMemberCallExpr(
844 LOG_TRACE(
"Leaving member call expression at {}",
855 clang::CXXOperatorCallExpr *expr)
859 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXOperatorCallExpr(
870 clang::CXXTemporaryObjectExpr *expr)
878 clang::dyn_cast<clang::CXXConstructExpr>(expr));
888 clang::CXXConstructExpr *expr)
890 LOG_TRACE(
"Entering cxx construct call expression at {}",
895 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXConstructExpr(
900 LOG_TRACE(
"Leaving cxx construct call expression at {}",
912 LOG_TRACE(
"Entering return statement at {}",
917 RecursiveASTVisitor<translation_unit_visitor>::TraverseReturnStmt(stmt);
919 LOG_TRACE(
"Leaving return statement at {}",
940 const auto *current_elseifstmt =
946 if (current_elseifstmt !=
nullptr) {
947 if (current_elseifstmt->getElse() == stmt) {
950 if (current_caller_id.value() != 0) {
953 diagram().add_message(std::move(m));
957 else if (current_ifstmt !=
nullptr) {
958 if (current_ifstmt->getElse() == stmt) {
961 if (current_caller_id.value() != 0) {
964 diagram().add_message(std::move(m));
969 RecursiveASTVisitor<translation_unit_visitor>::TraverseCompoundStmt(stmt);
981 bool elseif_block{
false};
985 const auto *current_elseifstmt =
988 std::string condition_text;
989 if (
config().generate_condition_statements())
994 auto child_stmt_compare = [stmt](
auto *child_stmt) {
995 return child_stmt == stmt;
998 if (current_ifstmt !=
nullptr)
999 elseif_block = elseif_block ||
1000 std::any_of(current_ifstmt->children().begin(),
1001 current_ifstmt->children().end(), child_stmt_compare);
1002 if (current_elseifstmt !=
nullptr)
1003 elseif_block = elseif_block ||
1004 std::any_of(current_elseifstmt->children().begin(),
1005 current_elseifstmt->children().end(), child_stmt_compare);
1007 if ((current_caller_id.value() != 0) && !stmt->isConstexpr()) {
1011 message m{message_t::kElseIf, current_caller_id};
1013 m.condition_text(condition_text);
1015 *
context().get_ast_context(), current_caller_id, stmt));
1016 diagram().add_block_message(std::move(m));
1023 message m{message_t::kIf, current_caller_id};
1025 m.condition_text(condition_text);
1027 *
context().get_ast_context(), current_caller_id, stmt));
1028 diagram().add_block_message(std::move(m));
1032 RecursiveASTVisitor<translation_unit_visitor>::TraverseIfStmt(stmt);
1034 if ((current_caller_id.value() != 0) && !stmt->isConstexpr()) {
1035 if (!elseif_block) {
1037 {message_t::kIfEnd, current_caller_id}, message_t::kIf);
1053 std::string condition_text;
1054 if (
config().generate_condition_statements())
1057 if (current_caller_id.value() != 0) {
1058 LOG_TRACE(
"Entering while statement at {}",
1062 message m{message_t::kWhile, current_caller_id};
1064 m.condition_text(condition_text);
1066 *
context().get_ast_context(), current_caller_id, stmt));
1067 diagram().add_block_message(std::move(m));
1070 RecursiveASTVisitor<translation_unit_visitor>::TraverseWhileStmt(stmt);
1072 if (current_caller_id.value() != 0) {
1074 {message_t::kWhileEnd, current_caller_id}, message_t::kWhile);
1089 std::string condition_text;
1090 if (
config().generate_condition_statements())
1093 if (current_caller_id.value() != 0) {
1095 message m{message_t::kDo, current_caller_id};
1097 m.condition_text(condition_text);
1099 *
context().get_ast_context(), current_caller_id, stmt));
1100 diagram().add_block_message(std::move(m));
1103 RecursiveASTVisitor<translation_unit_visitor>::TraverseDoStmt(stmt);
1105 if (current_caller_id.value() != 0) {
1107 {message_t::kDoEnd, current_caller_id}, message_t::kDo);
1122 std::string condition_text;
1123 if (
config().generate_condition_statements())
1126 if (current_caller_id.value() != 0) {
1128 message m{message_t::kFor, current_caller_id};
1130 m.condition_text(condition_text);
1133 *
context().get_ast_context(), current_caller_id, stmt));
1135 diagram().add_block_message(std::move(m));
1138 RecursiveASTVisitor<translation_unit_visitor>::TraverseForStmt(stmt);
1140 if (current_caller_id.value() != 0) {
1142 {message_t::kForEnd, current_caller_id}, message_t::kFor);
1157 if (current_caller_id.value() != 0) {
1159 message m{message_t::kTry, current_caller_id};
1162 *
context().get_ast_context(), current_caller_id, stmt));
1163 diagram().add_block_message(std::move(m));
1166 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXTryStmt(stmt);
1168 if (current_caller_id.value() != 0) {
1170 {message_t::kTryEnd, current_caller_id}, message_t::kTry);
1185 if ((current_caller_id.value() != 0) &&
1186 (
context().current_trystmt() !=
nullptr)) {
1187 std::string caught_type;
1188 if (stmt->getCaughtType().isNull())
1189 caught_type =
"...";
1192 stmt->getCaughtType(), *
context().get_ast_context());
1196 diagram().add_message(std::move(m));
1199 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXCatchStmt(stmt);
1205 clang::CXXForRangeStmt *stmt)
1213 std::string condition_text;
1214 if (
config().generate_condition_statements())
1217 if (current_caller_id.value() != 0) {
1219 message m{message_t::kFor, current_caller_id};
1221 m.condition_text(condition_text);
1223 *
context().get_ast_context(), current_caller_id, stmt));
1224 diagram().add_block_message(std::move(m));
1227 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXForRangeStmt(
1230 if (current_caller_id.value() != 0) {
1232 {message_t::kForEnd, current_caller_id}, message_t::kFor);
1245 if (current_caller_id.value() != 0) {
1250 *
context().get_ast_context(), current_caller_id, stmt));
1251 diagram().add_block_message(std::move(m));
1254 RecursiveASTVisitor<translation_unit_visitor>::TraverseSwitchStmt(stmt);
1256 if (current_caller_id.value() != 0) {
1259 {message_t::kSwitchEnd, current_caller_id}, message_t::kSwitch);
1271 if ((current_caller_id.value() != 0) &&
1272 (
context().current_switchstmt() !=
nullptr)) {
1275 diagram().add_case_stmt_message(std::move(m));
1278 RecursiveASTVisitor<translation_unit_visitor>::TraverseCaseStmt(stmt);
1289 if ((current_caller_id.value() != 0) &&
1290 (
context().current_switchstmt() !=
nullptr)) {
1293 diagram().add_case_stmt_message(std::move(m));
1296 RecursiveASTVisitor<translation_unit_visitor>::TraverseDefaultStmt(stmt);
1302 clang::ConditionalOperator *stmt)
1308 std::string condition_text;
1309 if (
config().generate_condition_statements())
1312 if (current_caller_id.value() != 0) {
1316 m.condition_text(condition_text);
1318 *
context().get_ast_context(), current_caller_id, stmt));
1319 diagram().add_block_message(std::move(m));
1322 RecursiveASTVisitor<translation_unit_visitor>::TraverseStmt(
1325 RecursiveASTVisitor<translation_unit_visitor>::TraverseStmt(
1326 stmt->getTrueExpr());
1328 if (current_caller_id.value() != 0) {
1329 model::message m{message_t::kConditionalElse, current_caller_id};
1331 diagram().add_message(std::move(m));
1334 RecursiveASTVisitor<translation_unit_visitor>::TraverseStmt(
1335 stmt->getFalseExpr());
1337 if (current_caller_id.value() != 0) {
1340 {message_t::kConditionalEnd, current_caller_id},
1341 message_t::kConditional);
1348 clang::ObjCMessageExpr *expr)
1356 if (!
context().valid() ||
context().get_ast_context() ==
nullptr)
1359 LOG_TRACE(
"Visiting ObjC message expression at {} [caller_id = {}]",
1370 raw_expr_comment,
context().get_ast_context()->getDiagnostics(), m);
1378 LOG_DBG(
"Skipping call expression due to filter at: {}",
1385 if (
context().is_expr_in_current_control_statement_condition(expr)) {
1389 if (generated_message_from_comment) {
1391 "Message for this call expression is taken from comment directive");
1398 if (m.from().value() > 0 && m.to().value() > 0) {
1399 if (raw_expr_comment !=
nullptr)
1400 m.set_comment(raw_expr_comment->getBeginLoc().getHashValue(),
1405 diagram().add_active_participant(m.from());
1406 diagram().add_active_participant(m.to());
1408 LOG_DBG(
"Found ObjC message {} from {} [{}] to {} [{}] ",
1409 m.message_name(), m.from(), m.from(), m.to(), m.to());
1418 clang::ObjCPropertyRefExpr *expr)
1426 if (!
context().valid() ||
context().get_ast_context() ==
nullptr)
1429 LOG_TRACE(
"Visiting ObjC property ref expression at {} [caller_id = {}]",
1444 if (!
context().valid() ||
context().get_ast_context() ==
nullptr)
1447 LOG_TRACE(
"Visiting call expression at {} [caller_id = {}]",
1460 raw_expr_comment,
context().get_ast_context()->getDiagnostics(), m);
1468 LOG_DBG(
"Skipping call expression due to filter at: {}",
1475 if (
context().is_expr_in_current_control_statement_condition(expr)) {
1479 auto result =
process_callee(expr, m, generated_message_from_comment);
1485 if (m.from().value() > 0 && m.to().value() > 0) {
1486 if (raw_expr_comment !=
nullptr)
1487 m.set_comment(raw_expr_comment->getBeginLoc().getHashValue(),
1492 diagram().add_active_participant(m.from());
1493 diagram().add_active_participant(m.to());
1495 LOG_DBG(
"Found call {} from {} [{}] to {} [{}] ", m.message_name(),
1496 m.from(), m.from(), m.to(), m.to());
1509 if (expr ==
nullptr)
1512 if (generated_message_from_comment) {
1514 "Message for this call expression is taken from comment directive");
1519 else if (
const auto *cuda_call_expr =
1520 llvm::dyn_cast_or_null<clang::CUDAKernelCallExpr>(expr);
1521 cuda_call_expr !=
nullptr) {
1527 else if (
const auto *operator_call_expr =
1528 llvm::dyn_cast_or_null<clang::CXXOperatorCallExpr>(expr);
1529 operator_call_expr !=
nullptr) {
1536 else if (
const auto *method_call_expr =
1537 llvm::dyn_cast_or_null<clang::CXXMemberCallExpr>(expr);
1538 method_call_expr !=
nullptr) {
1546 auto *callee_decl = expr->getCalleeDecl();
1548 if (callee_decl ==
nullptr) {
1549 LOG_DBG(
"Cannot get callee declaration - trying direct function "
1552 callee_decl = expr->getDirectCallee();
1554 if (callee_decl !=
nullptr)
1555 LOG_DBG(
"Found function/method callee in: {}",
1559 if (callee_decl ==
nullptr) {
1563 if (llvm::dyn_cast_or_null<clang::CXXDependentScopeMemberExpr>(
1564 expr->getCallee()) !=
nullptr) {
1571 else if (llvm::dyn_cast_or_null<clang::UnresolvedLookupExpr>(
1572 expr->getCallee()) !=
nullptr) {
1576 LOG_DBG(
"Processing lambda expression callee");
1579 else if (llvm::dyn_cast_or_null<clang::DependentScopeDeclRefExpr>(
1580 expr->getCallee()) !=
nullptr) {
1581 LOG_DBG(
"Processing dependent scope declaration expression "
1582 "callee - not able to infer the template parameter "
1583 "type at this point: {}",
1587 LOG_DBG(
"Found unsupported callee decl type for: {} at {}",
1596 LOG_DBG(
"Skipping call expression at: {}",
1615 if (!
context().valid() ||
context().get_ast_context() ==
nullptr)
1618 LOG_TRACE(
"Visiting co_await expression at {} [caller_id = {}]",
1625 if (expr->getOperand() !=
nullptr) {
1633 raw_expr_comment,
context().get_ast_context()->getDiagnostics(), m);
1640 if (!generated_message_from_comment &&
1642 clang::dyn_cast_or_null<clang::CallExpr>(expr->getResumeExpr()))) {
1643 LOG_DBG(
"Skipping call expression due to filter at: {}",
1650 if (
context().is_expr_in_current_control_statement_condition(expr)) {
1655 clang::dyn_cast_or_null<clang::CallExpr>(expr->getResumeExpr()), m,
1656 generated_message_from_comment);
1663 if (m.from().value() > 0) {
1664 if (raw_expr_comment !=
nullptr)
1665 m.set_comment(raw_expr_comment->getBeginLoc().getHashValue(),
1670 diagram().add_active_participant(m.from());
1672 LOG_DBG(
"Found return call {} from {} [{}] to {} [{}] ",
1673 m.message_name(), m.from(), m.from(), m.to(), m.to());
1689 if (!
context().valid() ||
context().get_ast_context() ==
nullptr)
1692 LOG_TRACE(
"Visiting return statement at {}",
1702 raw_expr_comment,
context().get_ast_context()->getDiagnostics(), m);
1707 if (stmt->getRetValue() !=
nullptr) {
1712 if (
context().lambda_caller_id().has_value() &&
1713 !
context().is_local_class()) {
1714 const auto &lambda_model = get_participant<model::method>(
1715 *
context().lambda_caller_id());
1717 if (lambda_model.has_value()) {
1718 if (lambda_model.has_value())
1719 m.set_return_type(lambda_model.value().return_type());
1722 else if (
context().current_function_decl_ !=
nullptr) {
1724 context().current_function_decl_->getReturnType().getAsString());
1726 else if (
context().current_function_template_decl_ !=
nullptr) {
1728 .current_function_template_decl_->getAsFunction()
1732 else if (
context().current_method_decl_ !=
nullptr) {
1734 context().current_method_decl_->getReturnType().getAsString());
1736 else if (
context().current_objc_method_decl_ !=
nullptr) {
1738 context().current_objc_method_decl_->getReturnType().getAsString());
1743 if (m.from().value() > 0) {
1744 if (raw_expr_comment !=
nullptr)
1745 m.set_comment(raw_expr_comment->getBeginLoc().getHashValue(),
1750 diagram().add_active_participant(m.from());
1752 LOG_DBG(
"Found return call {} from {} [{}] to {} [{}] ",
1753 m.message_name(), m.from(), m.from(), m.to(), m.to());
1769 if (!
context().valid() ||
context().get_ast_context() ==
nullptr)
1772 LOG_TRACE(
"Visiting co_yield expression at {}",
1782 raw_expr_comment,
context().get_ast_context()->getDiagnostics(), m);
1787 if (expr->getOperand() !=
nullptr) {
1792 if (
context().current_function_decl_ !=
nullptr) {
1794 context().current_function_decl_->getReturnType().getAsString());
1796 else if (
context().current_function_template_decl_ !=
nullptr) {
1798 .current_function_template_decl_->getAsFunction()
1802 else if (
context().current_method_decl_ !=
nullptr) {
1804 context().current_method_decl_->getReturnType().getAsString());
1809 if (m.from().value() > 0) {
1810 if (raw_expr_comment !=
nullptr)
1811 m.set_comment(raw_expr_comment->getBeginLoc().getHashValue(),
1816 diagram().add_active_participant(m.from());
1818 LOG_DBG(
"Found co_yield call {} from {} [{}] to {} [{}] ",
1819 m.message_name(), m.from(), m.from(), m.to(), m.to());
1835 if (!
context().valid() ||
context().get_ast_context() ==
nullptr)
1838 LOG_TRACE(
"Visiting co_return statement at {}",
1848 raw_expr_comment,
context().get_ast_context()->getDiagnostics(), m);
1853 if (stmt->getOperand() !=
nullptr) {
1858 if (
context().current_function_decl_ !=
nullptr) {
1860 context().current_function_decl_->getReturnType().getAsString());
1862 else if (
context().current_function_template_decl_ !=
nullptr) {
1864 .current_function_template_decl_->getAsFunction()
1868 else if (
context().current_method_decl_ !=
nullptr) {
1870 context().current_method_decl_->getReturnType().getAsString());
1872 else if (
context().current_objc_method_decl_ !=
nullptr) {
1874 context().current_objc_method_decl_->getReturnType().getAsString());
1879 if (m.from().value() > 0) {
1880 if (raw_expr_comment !=
nullptr)
1881 m.set_comment(raw_expr_comment->getBeginLoc().getHashValue(),
1886 diagram().add_active_participant(m.from());
1888 LOG_DBG(
"Found co_return call {} from {} [{}] to {} [{}] ",
1889 m.message_name(), m.from(), m.from(), m.to(), m.to());
1901 diagram().sequences().insert({m.
from(), std::move(a)});
1911 auto generated_message_from_comment{
false};
1912 for (
const auto &decorator : m.
decorators()) {
1913 auto call_decorator =
1914 std::dynamic_pointer_cast<decorators::call>(decorator);
1915 if (call_decorator &&
1916 call_decorator->applies_to_diagram(
config().name)) {
1918 generated_message_from_comment =
true;
1922 return generated_message_from_comment;
1927 if (decl->isStaticLocal())
1930 RecursiveASTVisitor::TraverseVarDecl(decl);
1932 if (decl->isStaticLocal())
1939 clang::CXXConstructExpr *expr)
1947 if (expr ==
nullptr)
1950 if (
const auto *ctor = expr->getConstructor();
1954 LOG_TRACE(
"Visiting cxx construct expression at {} [caller_id = {}]",
1964 if (
context().is_expr_in_current_control_statement_condition(expr)) {
1971 if (m.from().value() > 0 && m.to().value() > 0) {
1974 diagram().add_active_participant(m.from());
1975 diagram().add_active_participant(m.to());
1977 LOG_DBG(
"Found constructor call {} from {} [{}] to {} [{}] ",
1978 m.message_name(), m.from(), m.from(), m.to(), m.to());
1989 const auto *callee_decl = expr->getCalleeDecl();
1991 if (callee_decl ==
nullptr)
1994 const auto *callee_function = callee_decl->getAsFunction();
1996 if (callee_function ==
nullptr)
2003 if (
config().combine_free_functions_into_file_participants() &&
2007 auto callee_name = callee_function->getQualifiedNameAsString() +
"()";
2016 model::message &m,
const clang::CXXOperatorCallExpr *operator_call_expr)
2018 if (operator_call_expr->getCalleeDecl() ==
nullptr)
2021 LOG_DBG(
"Operator '{}' call expression to {} at {}",
2022 getOperatorSpelling(operator_call_expr->getOperator()),
2023 operator_call_expr->getCalleeDecl()->getID(),
2024 operator_call_expr->getBeginLoc().printToString(
source_manager()));
2027 if (
const auto *lambda_method = clang::dyn_cast<clang::CXXMethodDecl>(
2028 operator_call_expr->getCalleeDecl());
2029 lambda_method !=
nullptr && lambda_method->getParent()->isLambda()) {
2031 LOG_DBG(
"Operator callee is a lambda: {}",
2034 const auto source_location{
2039 m.
set_to(
eid_t{lambda_method->getParent()->getID()});
2042 const auto operator_ast_id =
2043 operator_call_expr->getCalleeDecl()->getID();
2048 "operator{}", getOperatorSpelling(operator_call_expr->getOperator())));
2054 model::message &m,
const clang::CXXConstructExpr *construct_expr)
2056 const auto *constructor = construct_expr->getConstructor();
2057 if (constructor ==
nullptr)
2060 const auto *constructor_parent = constructor->getParent();
2061 if (constructor_parent ==
nullptr)
2064 LOG_DBG(
"Constructor '{}' call expression to {} at {}",
2065 construct_expr->getConstructor()->getNameAsString(),
2066 constructor->getID(),
2071 fmt::format(
"{}::{}", constructor_parent->getQualifiedNameAsString(),
2072 constructor_parent->getNameAsString()));
2074 diagram().add_active_participant(
eid_t{constructor->getID()});
2082 const auto *method_decl = message_expr->getMethodDecl();
2084 if (method_decl ==
nullptr)
2087 std::string method_name = method_decl->getQualifiedNameAsString();
2089 if (message_expr->getReceiverInterface() ==
nullptr)
2092 const auto *callee_decl = message_expr->getReceiverInterface();
2094 if (callee_decl ==
nullptr)
2100 if (callee_decl->getImplementation() !=
nullptr &&
2101 callee_decl->getImplementation()->getMethod(method_decl->getSelector(),
2102 method_decl->isInstanceMethod(),
true) !=
nullptr) {
2103 const auto *impl_method_decl =
2104 callee_decl->getImplementation()->getMethod(
2105 method_decl->getSelector(), method_decl->isInstanceMethod(),
2115 message_expr->getCallReturnType(*
context().get_ast_context())
2118 LOG_TRACE(
"Set callee ObjC method id {} for method name {}", m.
to(),
2119 method_decl->getQualifiedNameAsString());
2121 diagram().add_active_participant(
eid_t{method_decl->getID()});
2127 model::message &m,
const clang::CXXMemberCallExpr *method_call_expr)
2130 const auto *method_decl = method_call_expr->getMethodDecl();
2132 if (method_decl ==
nullptr)
2135 std::string method_name = method_decl->getQualifiedNameAsString();
2137 const auto *callee_decl =
2138 method_decl !=
nullptr ? method_decl->getParent() :
nullptr;
2140 if (callee_decl ==
nullptr)
2149 method_call_expr->getCallReturnType(*
context().get_ast_context())
2152 LOG_TRACE(
"Set callee method id {} for method name {}", m.
to(),
2153 method_decl->getQualifiedNameAsString());
2155 diagram().add_active_participant(
eid_t{method_decl->getID()});
2163 const auto *dependent_member_callee =
2164 clang::dyn_cast_or_null<clang::CXXDependentScopeMemberExpr>(
2167 if (dependent_member_callee ==
nullptr)
2171 if (
const auto *tst = dependent_member_callee->getBaseType()
2172 ->getAs<clang::TemplateSpecializationType>();
2174 const auto *template_declaration =
2175 tst->getTemplateName().getAsTemplateDecl();
2177 std::string callee_method_full_name;
2185 "::" + dependent_member_callee->getMember().getAsString();
2187 for (
const auto &[
id, p] :
diagram().participants()) {
2188 const auto p_full_name = p->full_name(
false);
2190 if (p_full_name.find(callee_method_full_name +
"(") == 0) {
2200 const auto *argument_template =
2201 template_declaration->getTemplateParameters()
2210 dependent_member_callee->getMember().getAsString();
2212 for (
const auto &[
id, p] :
diagram().participants()) {
2213 const auto p_full_name = p->full_name(
false);
2214 if (p_full_name.find(callee_method_full_name +
"(") ==
2228 dependent_member_callee->getMember().getAsString());
2230 if (
const auto maybe_id =
2232 maybe_id.has_value())
2233 diagram().add_active_participant(maybe_id.value());
2237 LOG_DBG(
"Skipping call due to unresolvable "
2238 "CXXDependentScopeMemberExpr at {}",
2248 const auto *callee_decl = expr->getCalleeDecl();
2250 if (callee_decl ==
nullptr)
2253 const auto *callee_function = callee_decl->getAsFunction();
2255 if (callee_function ==
nullptr)
2262 if (
config().combine_free_functions_into_file_participants() &&
2266 auto callee_name = callee_function->getQualifiedNameAsString() +
"()";
2277 const auto *lambda_expr =
2278 clang::dyn_cast_or_null<clang::LambdaExpr>(expr->getCallee());
2280 if (lambda_expr ==
nullptr)
2283 const auto lambda_class_id =
eid_t{lambda_expr->getLambdaClass()->getID()};
2293 const auto *unresolved_expr =
2294 clang::dyn_cast_or_null<clang::UnresolvedLookupExpr>(expr->getCallee());
2296 if (unresolved_expr !=
nullptr) {
2297 for (
const auto *decl : unresolved_expr->decls()) {
2298 if (clang::dyn_cast_or_null<clang::FunctionTemplateDecl>(decl) !=
2301 clang::dyn_cast_or_null<clang::FunctionTemplateDecl>(decl);
2306 if (clang::dyn_cast_or_null<clang::FunctionDecl>(decl) !=
nullptr) {
2308 clang::dyn_cast_or_null<clang::FunctionDecl>(decl);
2313 LOG_DBG(
"Unknown unresolved lookup expression");
2321 const clang::CXXDependentScopeMemberExpr *dependent_member_expr)
const
2323 if (dependent_member_expr ==
nullptr)
2326 if (dependent_member_expr->getBaseType().isNull())
2329 const auto *tst = dependent_member_expr->getBaseType()
2330 ->getAs<clang::TemplateSpecializationType>();
2335 return !(tst->isPointerType());
2339 const clang::TemplateDecl *primary_template)
const
2341 return primary_template->getQualifiedNameAsString().find(
2342 "std::unique_ptr") == 0 ||
2343 primary_template->getQualifiedNameAsString().find(
"std::shared_ptr") ==
2345 primary_template->getQualifiedNameAsString().find(
"std::weak_ptr") == 0;
2348std::unique_ptr<clanguml::sequence_diagram::model::class_>
2350 clang::ObjCProtocolDecl *cls)
2352 assert(cls !=
nullptr);
2354 auto c_ptr{std::make_unique<clanguml::sequence_diagram::model::class_>(
2355 config().using_namespace())};
2358 auto qualified_name = cls->getQualifiedNameAsString();
2360 c.is_objc_interface();
2362 c.set_name(cls->getQualifiedNameAsString());
2371 c.set_style(c.style_spec());
2376std::unique_ptr<clanguml::sequence_diagram::model::class_>
2378 clang::ObjCInterfaceDecl *cls)
2380 assert(cls !=
nullptr);
2382 auto c_ptr{std::make_unique<clanguml::sequence_diagram::model::class_>(
2383 config().using_namespace())};
2386 auto qualified_name = cls->getQualifiedNameAsString();
2388 c.is_objc_interface(
true);
2390 c.set_name(cls->getQualifiedNameAsString());
2399 c.set_style(c.style_spec());
2404std::unique_ptr<clanguml::sequence_diagram::model::class_>
2407 assert(cls !=
nullptr);
2409 auto c_ptr{std::make_unique<clanguml::sequence_diagram::model::class_>(
2410 config().using_namespace())};
2413 auto qualified_name = cls->getQualifiedNameAsString();
2415 if (!cls->isLambda())
2424 const auto *parent = cls->getParent();
2426 if ((parent !=
nullptr) && parent->isRecord()) {
2431 std::optional<eid_t> id_opt;
2432 const auto *parent_record_decl =
2433 clang::dyn_cast<clang::RecordDecl>(parent);
2435 assert(parent_record_decl !=
nullptr);
2437 const eid_t ast_id{parent_record_decl->getID()};
2445 (parent_record_decl->getDescribedTemplate() !=
nullptr)) {
2446 parent_record_decl->getDescribedTemplate()->getID();
2447 if (parent_record_decl->getDescribedTemplate() !=
nullptr)
2459 if (!parent_class) {
2464 if (cls->getNameAsString().empty()) {
2465 c.set_name(parent_class.value().name() +
"::" +
2466 fmt::format(
"(anonymous_{})", std::to_string(cls->getID())));
2470 parent_class.value().name() +
"::" + cls->getNameAsString());
2477 else if (cls->isLambda()) {
2479 if (cls->getParent() !=
nullptr) {
2482 c.set_name(type_name);
2483 c.set_namespace(ns);
2487 LOG_WARN(
"Cannot find parent declaration for lambda {}",
2488 cls->getQualifiedNameAsString());
2493 else if (cls->isLocalClass() !=
nullptr) {
2494 const auto *func_declaration = cls->isLocalClass();
2496 eid_t local_parent_id{int64_t{}};
2499 LOG_DBG(
"The local class is defined in a lambda operator()");
2500 const auto *method_declaration =
2501 clang::dyn_cast<clang::CXXMethodDecl>(func_declaration);
2503 if (method_declaration !=
nullptr &&
2504 method_declaration->getParent() !=
nullptr) {
2505 local_parent_id = method_declaration->getParent()->getID();
2509 local_parent_id = func_declaration->getID();
2516 const auto &func_model =
2519 if (!func_model.has_value())
2522 LOG_DBG(
"Visiting local class declaration: {} in {}",
2523 cls->getQualifiedNameAsString(),
2524 func_model.value().full_name(
false));
2526 auto local_cls_ns = func_model.value().get_namespace();
2530 c.set_namespace(local_cls_ns);
2536 c.set_namespace(ns);
2540 c.is_struct(cls->isStruct());
2548 c.set_style(c.style_spec());
2555 LOG_TRACE(
"Setting local element mapping {} --> {}", local_id, global_id);
2563 eid_t local_id)
const
2571std::unique_ptr<model::function_template>
2573 const clang::FunctionTemplateDecl &declaration)
2575 auto function_template_model_ptr =
2576 std::make_unique<sequence_diagram::model::function_template>(
2577 config().using_namespace());
2582 *function_template_model_ptr, declaration);
2584 function_template_model_ptr->return_type(
2586 declaration.getASTContext()));
2588 if (declaration.getAsFunction() !=
nullptr) {
2590 *declaration.getAsFunction(), *function_template_model_ptr);
2593 return function_template_model_ptr;
2596std::unique_ptr<model::function_template>
2598 const clang::FunctionDecl &declaration)
2600 auto template_instantiation_ptr =
2601 std::make_unique<model::function_template>(
config().using_namespace());
2602 auto &template_instantiation = *template_instantiation_ptr;
2606 tbuilder().
build(declaration, template_instantiation, &declaration,
2607 declaration.getPrimaryTemplate(),
2608 declaration.getTemplateSpecializationArgs()->asArray(),
2613 return template_instantiation_ptr;
2617 const clang::FunctionDecl &declaration)
2619 auto function_model_ptr =
2620 std::make_unique<sequence_diagram::model::function>(
2621 config().using_namespace());
2624 function_model_ptr->set_name(ns.name());
2626 function_model_ptr->set_namespace(ns);
2629 declaration.getReturnType(), declaration.getASTContext()));
2633 if (declaration.isVariadic()) {
2634 function_model_ptr->add_parameter(
"...");
2637 return function_model_ptr;
2640std::unique_ptr<model::class_>
2642 clang::ClassTemplateSpecializationDecl *cls)
2644 auto c_ptr{std::make_unique<model::class_>(
config().using_namespace())};
2648 auto &template_instantiation = *c_ptr;
2651 auto qualified_name = cls->getQualifiedNameAsString();
2657 template_instantiation.set_name(cls->getNameAsString());
2658 template_instantiation.set_namespace(ns);
2660 template_instantiation.is_struct(cls->isStruct());
2666 if (template_instantiation.skip())
2669 template_instantiation.set_id(
2678 const std::string &full_name)
const
2680 return config().simplify_template_type(full_name);
2684 const clang::SourceLocation &source_location)
const
2686 const auto file_line =
2688 const auto file_column =
2690 const std::string file_name =
2692 .make_path_relative(
2695 return fmt::format(
"{}:{}:{}", file_name, file_line, file_column);
2699 const clang::CXXRecordDecl *cls)
const
2702 const auto location = cls->getLocation();
2706 if (maybe_lambda_caller_id.has_value()) {
2708 std::string parent_lambda_class_name{
"()"};
2709 if (
diagram().get_participant<model::method>(
2710 maybe_lambda_caller_id.value())) {
2711 auto parent_lambda_class_id =
2714 maybe_lambda_caller_id.value())
2719 parent_lambda_class_id)) {
2720 parent_lambda_class_name =
2728 result = fmt::format(
2729 "{}##(lambda {})", parent_lambda_class_name, source_location);
2731 else if (
context().caller_id().value() != 0 &&
2733 auto parent_full_name =
2737 fmt::format(
"{}##(lambda {})", parent_full_name, source_location);
2740 result = fmt::format(
"(lambda {})", source_location);
2790 assert(expr !=
nullptr);
2803 auto caller_id = msg.from();
2808 if (
diagram().has_activity(caller_id))
2809 diagram().get_activity(caller_id).add_message(std::move(msg));
2811 LOG_DBG(
"Skipping message due to missing activity: {}", caller_id);
2820 clang::CXXConstructExpr *expr)
2822 assert(expr !=
nullptr);
2832 auto caller_id = msg.from();
2833 diagram().get_activity(caller_id).add_message(std::move(msg));
2840 assert(stmt !=
nullptr);
2849 auto caller_id = msg.from();
2850 diagram().get_activity(caller_id).add_message(std::move(msg));
2857 assert(stmt !=
nullptr);
2867 auto caller_id = msg.from();
2868 diagram().get_activity(caller_id).add_message(std::move(msg));
2875 assert(expr !=
nullptr);
2885 auto caller_id = msg.from();
2886 diagram().get_activity(caller_id).add_message(std::move(msg));
2893 assert(expr !=
nullptr);
2903 auto caller_id = msg.from();
2904 diagram().get_activity(caller_id).add_message(std::move(msg));
2910 clang::ObjCMessageExpr *expr)
2912 assert(expr !=
nullptr);
2921 auto caller_id = msg.from();
2922 diagram().get_activity(caller_id).add_message(std::move(msg));
2939 if (
config().inline_lambda_messages())
2940 diagram().inline_lambda_operator_calls();
2945 for (
auto &[
id, activity] :
diagram().sequences()) {
2946 for (
auto &m : activity.messages()) {
2949 if (participant && participant.value().is_lambda() &&
2950 participant.value().lambda_operator_id().value() != 0) {
2951 LOG_DBG(
"Changing lambda expression target id from {} to {}",
2952 m.to(), participant.value().lambda_operator_id());
2954 m.set_to(participant.value().lambda_operator_id());
2955 m.set_message_name(
"operator()");
2965 std::set<eid_t> active_participants_unique;
2968 for (
auto id :
diagram().active_participants()) {
2970 !
id.is_global() && unique_id.has_value()) {
2971 active_participants_unique.emplace(unique_id.value());
2973 else if (
id.is_global()) {
2974 active_participants_unique.emplace(
id);
2978 diagram().active_participants() = std::move(active_participants_unique);
2981 for (
auto &[
id, activity] :
diagram().sequences()) {
2982 for (
auto &m : activity.messages()) {
2984 !m.to().is_global() && unique_id.has_value()) {
2985 m.set_to(unique_id.value());
2986 assert(m.to().is_global());
2995 std::map<eid_t, std::set<eid_t>> acs;
3000 std::set<eid_t> unique_caller_ids;
3001 for (
const auto &caller_id : caller_ids) {
3003 if (unique_caller_id)
3004 unique_caller_ids.emplace(*unique_caller_id);
3006 acs.emplace(*unique_id, std::move(unique_caller_ids));
3010 for (
auto &[
id, activity] :
diagram().sequences()) {
3011 assert(
id.is_global());
3013 if (acs.count(
id) > 0) {
3014 activity.set_callers(acs.at(
id));
3019std::unique_ptr<clanguml::sequence_diagram::model::method>
3021 clang::CXXMethodDecl *declaration)
3023 auto method_model_ptr = std::make_unique<sequence_diagram::model::method>(
3024 config().using_namespace());
3027 auto method_name = ns.
name();
3028 method_model_ptr->set_method_name(method_name);
3030 method_model_ptr->set_name(ns.name());
3032 method_model_ptr->set_namespace(ns);
3034 method_model_ptr->is_defaulted(declaration->isDefaulted());
3035 method_model_ptr->is_assignment(declaration->isCopyAssignmentOperator() ||
3036 declaration->isMoveAssignmentOperator());
3037 method_model_ptr->is_const(declaration->isConst());
3038 method_model_ptr->is_static(declaration->isStatic());
3039 method_model_ptr->is_operator(declaration->isOverloadedOperator());
3040 method_model_ptr->is_constructor(
3041 clang::dyn_cast<clang::CXXConstructorDecl>(declaration) !=
nullptr);
3043 method_model_ptr->is_void(declaration->getReturnType()->isVoidType());
3046 declaration->getReturnType(), declaration->getASTContext()));
3050 return method_model_ptr;
3053std::unique_ptr<clanguml::sequence_diagram::model::objc_method>
3055 clang::ObjCMethodDecl *declaration)
3057 auto method_model_ptr =
3058 std::make_unique<sequence_diagram::model::objc_method>(
3059 config().using_namespace());
3062 auto method_name = ns.
name();
3063 method_model_ptr->set_method_name(method_name);
3065 method_model_ptr->set_name(ns.name());
3066 method_model_ptr->set_namespace({});
3068 clang::Decl *parent_decl = declaration->getClassInterface();
3070 if (parent_decl ==
nullptr) {
3071 LOG_DBG(
"Cannot find ObjC interface for method, probably it is a "
3078 LOG_DBG(
"Getting ObjC method's interface with local id {}",
3079 parent_decl->getID());
3081 const auto maybe_method_class = get_participant<model::class_>(parent_decl);
3083 if (!maybe_method_class) {
3084 LOG_DBG(
"Cannot find parent class_ for method {} in class {}",
3085 declaration->getQualifiedNameAsString(),
3086 declaration->getClassInterface()->getQualifiedNameAsString());
3090 const auto &method_class = maybe_method_class.value();
3092 method_model_ptr->is_void(declaration->getReturnType()->isVoidType());
3094 method_model_ptr->set_class_id(method_class.id());
3095 method_model_ptr->set_class_full_name(method_class.full_name(
false));
3096 method_model_ptr->set_name(
get_participant(method_model_ptr->class_id())
3098 .full_name_no_ns() +
3099 "::" + declaration->getNameAsString());
3102 declaration->getReturnType(), declaration->getASTContext()));
3104 for (
const auto *param : declaration->parameters()) {
3105 auto parameter_type =
3110 std::string parameter_str = parameter_type;
3111 if (
config().generate_method_argument_names()) {
3112 parameter_str +=
" " + param->getNameAsString();
3115 method_model_ptr->add_parameter(parameter_type);
3118 return method_model_ptr;
3121std::unique_ptr<clanguml::sequence_diagram::model::method>
3124 auto method_model_ptr = std::make_unique<sequence_diagram::model::method>(
3125 config().using_namespace());
3128 auto method_name = ns.
name();
3129 method_model_ptr->set_method_name(method_name);
3131 method_model_ptr->set_name(ns.name());
3133 method_model_ptr->set_namespace(ns);
3135 method_model_ptr->is_defaulted(declaration->isDefaulted());
3136 method_model_ptr->is_assignment(declaration->isCopyAssignmentOperator() ||
3137 declaration->isMoveAssignmentOperator());
3138 method_model_ptr->is_const(declaration->isConst());
3139 method_model_ptr->is_static(declaration->isStatic());
3140 method_model_ptr->is_operator(declaration->isOverloadedOperator());
3141 method_model_ptr->is_constructor(
3142 clang::dyn_cast<clang::CXXConstructorDecl>(declaration) !=
nullptr);
3145 clang::Decl *parent_decl = declaration->getParent();
3147 if (
context().current_class_template_decl_ !=
nullptr)
3150 LOG_DBG(
"Getting method's class with local id {}", parent_decl->getID());
3152 const auto maybe_method_class = get_participant<model::class_>(parent_decl);
3154 if (!maybe_method_class) {
3155 LOG_DBG(
"Cannot find parent class_ for method {} in class {}",
3156 declaration->getQualifiedNameAsString(),
3157 declaration->getParent()->getQualifiedNameAsString());
3162 "Found method class: {}", maybe_method_class.value().full_name(
false));
3164 const auto &method_class = maybe_method_class.value();
3166 method_model_ptr->is_void(declaration->getReturnType()->isVoidType());
3168 method_model_ptr->set_class_id(method_class.id());
3169 method_model_ptr->set_class_full_name(method_class.full_name(
false));
3170 method_model_ptr->set_name(
get_participant(method_model_ptr->class_id())
3172 .full_name_no_ns() +
3173 "::" + declaration->getNameAsString());
3176 declaration->getReturnType(), declaration->getASTContext()));
3180 return method_model_ptr;
3184 const clang::FunctionDecl &declaration,
model::function &method_model)
const
3186 for (
const auto *param : declaration.parameters()) {
3187 auto parameter_type =
3192 std::string parameter_str =
config().using_namespace().relative(
3194 if (
config().generate_method_argument_names()) {
3195 parameter_str +=
" " + param->getNameAsString();
3205 dynamic_cast<const clang::NamedDecl *
>(decl));
3209 const clang::ObjCContainerDecl *decl)
const
3212 dynamic_cast<const clang::NamedDecl *
>(decl));
3216 const clang::LambdaExpr *expr)
const
3218 if (
context().caller_id() == 0)
3224 const auto expr_file = expr->getBeginLoc().printToString(
source_manager());
3234 const clang::ObjCMessageExpr *expr)
const
3236 if (
context().caller_id() == 0)
3242 const auto expr_file = expr->getBeginLoc().printToString(
source_manager());
3253 if (
context().caller_id() == 0)
3257 if (expr->isCallToStdMove())
3260 if (expr->isImplicitCXXThis())
3263 if (clang::dyn_cast_or_null<clang::ImplicitCastExpr>(expr) !=
nullptr)
3269 const auto expr_file = expr->getBeginLoc().printToString(
source_manager());
3275 const auto *callee_decl = expr->getCalleeDecl();
3277 if (callee_decl !=
nullptr) {
3278 const auto *callee_function = callee_decl->getAsFunction();
3280 if ((callee_function ==
nullptr) || !
should_include(callee_function)) {
3281 LOG_DBG(
"Skipping call expression at {}",
3293 const clang::CXXMethodDecl *decl)
const
3302 LOG_DBG(
"Including method {}", decl->getQualifiedNameAsString());
3308 const clang::ObjCMethodDecl *decl)
const
3314 LOG_DBG(
"Including ObjC method {}", decl->getQualifiedNameAsString());
3320 const clang::FunctionDecl *decl)
const
3326 const clang::FunctionTemplateDecl *decl)
const
3332 const clang::ClassTemplateDecl *decl)
const
3337std::optional<std::pair<unsigned int, std::string>>
3339 const clang::ASTContext &context,
const eid_t caller_id,
3340 const clang::Stmt *stmt)
3342 const auto *raw_comment =
3345 if (raw_comment ==
nullptr)
3356 raw_comment->getFormattedText(sm, sm.getDiagnostics()));
3358 if (stripped_comment.empty())
3361 return {{raw_comment->getBeginLoc().getHashValue(), stripped_comment}};