0.6.1
C++ to UML diagram generator based on Clang
Loading...
Searching...
No Matches
Functions
of ResursiveASTVisitor methods

Detailed Description

Functions

bool clanguml::class_diagram::visitor::translation_unit_visitor::shouldVisitTemplateInstantiations () const
 
bool clanguml::class_diagram::visitor::translation_unit_visitor::shouldVisitImplicitCode () const
 
virtual bool clanguml::class_diagram::visitor::translation_unit_visitor::VisitNamespaceDecl (clang::NamespaceDecl *ns)
 
virtual bool clanguml::class_diagram::visitor::translation_unit_visitor::VisitRecordDecl (clang::RecordDecl *D)
 
virtual bool clanguml::class_diagram::visitor::translation_unit_visitor::VisitCXXRecordDecl (clang::CXXRecordDecl *d)
 
virtual bool clanguml::class_diagram::visitor::translation_unit_visitor::VisitTypedefDecl (clang::TypedefDecl *decl)
 
virtual bool clanguml::class_diagram::visitor::translation_unit_visitor::VisitEnumDecl (clang::EnumDecl *e)
 
virtual bool clanguml::class_diagram::visitor::translation_unit_visitor::VisitClassTemplateDecl (clang::ClassTemplateDecl *class_template_declaration)
 
virtual bool clanguml::class_diagram::visitor::translation_unit_visitor::VisitClassTemplateSpecializationDecl (clang::ClassTemplateSpecializationDecl *cls)
 
virtual bool clanguml::class_diagram::visitor::translation_unit_visitor::VisitTypeAliasTemplateDecl (clang::TypeAliasTemplateDecl *cls)
 
virtual bool clanguml::class_diagram::visitor::translation_unit_visitor::TraverseConceptDecl (clang::ConceptDecl *cpt)
 
virtual bool clanguml::class_diagram::visitor::translation_unit_visitor::VisitObjCCategoryDecl (clang::ObjCCategoryDecl *decl)
 
virtual bool clanguml::class_diagram::visitor::translation_unit_visitor::VisitObjCProtocolDecl (clang::ObjCProtocolDecl *decl)
 
virtual bool clanguml::class_diagram::visitor::translation_unit_visitor::VisitObjCInterfaceDecl (clang::ObjCInterfaceDecl *decl)
 
virtual bool clanguml::package_diagram::visitor::translation_unit_visitor::VisitNamespaceDecl (clang::NamespaceDecl *ns)
 
virtual bool clanguml::package_diagram::visitor::translation_unit_visitor::VisitEnumDecl (clang::EnumDecl *decl)
 
virtual bool clanguml::package_diagram::visitor::translation_unit_visitor::VisitCXXRecordDecl (clang::CXXRecordDecl *cls)
 
virtual bool clanguml::package_diagram::visitor::translation_unit_visitor::VisitRecordDecl (clang::RecordDecl *cls)
 
virtual bool clanguml::package_diagram::visitor::translation_unit_visitor::VisitClassTemplateDecl (clang::ClassTemplateDecl *decl)
 
virtual bool clanguml::package_diagram::visitor::translation_unit_visitor::VisitFunctionDecl (clang::FunctionDecl *function_declaration)
 
virtual bool clanguml::package_diagram::visitor::translation_unit_visitor::VisitObjCCategoryDecl (clang::ObjCCategoryDecl *decl)
 
virtual bool clanguml::package_diagram::visitor::translation_unit_visitor::VisitObjCProtocolDecl (clang::ObjCProtocolDecl *decl)
 
virtual bool clanguml::package_diagram::visitor::translation_unit_visitor::VisitObjCInterfaceDecl (clang::ObjCInterfaceDecl *decl)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::shouldVisitTemplateInstantiations ()
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitReturnStmt (clang::ReturnStmt *stmt)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitCallExpr (clang::CallExpr *expr)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitObjCMessageExpr (clang::ObjCMessageExpr *expr)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitObjCPropertyRefExpr (clang::ObjCPropertyRefExpr *expr)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseVarDecl (clang::VarDecl *VD)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseCoyieldExpr (clang::CoyieldExpr *expr)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseCoawaitExpr (clang::CoawaitExpr *expr)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseCoreturnStmt (clang::CoreturnStmt *stmt)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseCallExpr (clang::CallExpr *expr)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseObjCMessageExpr (clang::ObjCMessageExpr *expr)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseCUDAKernelCallExpr (clang::CUDAKernelCallExpr *expr)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseCXXMemberCallExpr (clang::CXXMemberCallExpr *expr)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseCXXOperatorCallExpr (clang::CXXOperatorCallExpr *expr)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitCXXConstructExpr (clang::CXXConstructExpr *expr)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseCXXConstructExpr (clang::CXXConstructExpr *expr)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseCXXTemporaryObjectExpr (clang::CXXTemporaryObjectExpr *expr)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseReturnStmt (clang::ReturnStmt *stmt)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitCoreturnStmt (clang::CoreturnStmt *stmt)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitCoyieldExpr (clang::CoyieldExpr *expr)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitCoawaitExpr (clang::CoawaitExpr *expr)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitLambdaExpr (clang::LambdaExpr *expr)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseLambdaExpr (clang::LambdaExpr *expr)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseCXXMethodDecl (clang::CXXMethodDecl *declaration)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseObjCMethodDecl (clang::ObjCMethodDecl *declaration)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitObjCMethodDecl (clang::ObjCMethodDecl *declaration)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitCXXMethodDecl (clang::CXXMethodDecl *declaration)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseCXXRecordDecl (clang::CXXRecordDecl *declaration)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitCXXRecordDecl (clang::CXXRecordDecl *declaration)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitClassTemplateDecl (clang::ClassTemplateDecl *declaration)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitClassTemplateSpecializationDecl (clang::ClassTemplateSpecializationDecl *declaration)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseFunctionDecl (clang::FunctionDecl *declaration)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitFunctionDecl (clang::FunctionDecl *declaration)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseFunctionTemplateDecl (clang::FunctionTemplateDecl *declaration)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitFunctionTemplateDecl (clang::FunctionTemplateDecl *function_declaration)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitObjCInterfaceDecl (clang::ObjCInterfaceDecl *interface_declaration)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitObjCProtocolDecl (clang::ObjCProtocolDecl *protocol_declaration)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseCompoundStmt (clang::CompoundStmt *stmt)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseIfStmt (clang::IfStmt *stmt)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseWhileStmt (clang::WhileStmt *stmt)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseDoStmt (clang::DoStmt *stmt)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseForStmt (clang::ForStmt *stmt)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseCXXForRangeStmt (clang::CXXForRangeStmt *stmt)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseCXXTryStmt (clang::CXXTryStmt *stmt)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseCXXCatchStmt (clang::CXXCatchStmt *stmt)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseSwitchStmt (clang::SwitchStmt *stmt)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseCaseStmt (clang::CaseStmt *stmt)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseDefaultStmt (clang::DefaultStmt *stmt)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseConditionalOperator (clang::ConditionalOperator *stmt)
 

Function Documentation

◆ shouldVisitImplicitCode()

bool clanguml::class_diagram::visitor::translation_unit_visitor::shouldVisitImplicitCode ( ) const
inline

Definition at line 115 of file translation_unit_visitor.h.

115{ return false; }

◆ shouldVisitTemplateInstantiations() [1/2]

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::shouldVisitTemplateInstantiations ( )

Definition at line 43 of file translation_unit_visitor.cc.

44{
45 return true;
46}

◆ shouldVisitTemplateInstantiations() [2/2]

bool clanguml::class_diagram::visitor::translation_unit_visitor::shouldVisitTemplateInstantiations ( ) const
inline

Definition at line 113 of file translation_unit_visitor.h.

113{ return false; }

◆ TraverseCallExpr()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseCallExpr ( clang::CallExpr *  expr)

Definition at line 803 of file translation_unit_visitor.cc.

804{
805 if (!config().include_system_headers() &&
806 source_manager().isInSystemHeader(expr->getSourceRange().getBegin()))
807 return true;
808
809 LOG_TRACE("Entering call expression at {}",
810 expr->getBeginLoc().printToString(source_manager()));
811
812 context().enter_callexpr(expr);
813
814 RecursiveASTVisitor<translation_unit_visitor>::TraverseCallExpr(expr);
815
816 LOG_TRACE("Leaving call expression at {}",
817 expr->getBeginLoc().printToString(source_manager()));
818
820
822
823 return true;
824}

◆ TraverseCaseStmt()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseCaseStmt ( clang::CaseStmt *  stmt)

Definition at line 1286 of file translation_unit_visitor.cc.

1287{
1289
1290 const auto current_caller_id = context().caller_id();
1291
1292 if ((current_caller_id.value() != 0) &&
1293 (context().current_switchstmt() != nullptr)) {
1294 model::message m{message_t::kCase, current_caller_id};
1295 m.set_message_name(common::to_string(stmt->getLHS()));
1296 diagram().add_case_stmt_message(std::move(m));
1297 }
1298
1299 RecursiveASTVisitor<translation_unit_visitor>::TraverseCaseStmt(stmt);
1300
1301 return true;
1302}

◆ TraverseCoawaitExpr()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseCoawaitExpr ( clang::CoawaitExpr *  expr)

Definition at line 757 of file translation_unit_visitor.cc.

758{
759 if (!config().include_system_headers() &&
760 source_manager().isInSystemHeader(expr->getSourceRange().getBegin()))
761 return true;
762
763 LOG_TRACE("Entering co_await expression at {}",
764 expr->getBeginLoc().printToString(source_manager()));
765
766 context().enter_callexpr(expr);
767
768 RecursiveASTVisitor<translation_unit_visitor>::TraverseCoawaitExpr(expr);
769
770 LOG_TRACE("Leaving co_await expression at {}",
771 expr->getBeginLoc().printToString(source_manager()));
772
774
776
777 return true;
778}

◆ TraverseCompoundStmt()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseCompoundStmt ( clang::CompoundStmt *  stmt)

Definition at line 950 of file translation_unit_visitor.cc.

951{
956
957 if (stmt == nullptr)
958 return true;
959
960 const auto *current_ifstmt = context().current_ifstmt();
961 const auto *current_elseifstmt =
962 current_ifstmt != nullptr ? context().current_elseifstmt() : nullptr;
963
964 //
965 // Add final else block (not else if)
966 //
967 if (current_elseifstmt != nullptr) {
968 if (current_elseifstmt->getElse() == stmt) {
969 const auto current_caller_id = context().caller_id();
970
971 if (current_caller_id.value() != 0) {
972 model::message m{message_t::kElse, current_caller_id};
973 set_source_location(*stmt, m);
974 diagram().add_message(std::move(m));
975 }
976 }
977 }
978 else if (current_ifstmt != nullptr) {
979 if (current_ifstmt->getElse() == stmt) {
980 const auto current_caller_id = context().caller_id();
981
982 if (current_caller_id.value() != 0) {
983 model::message m{message_t::kElse, current_caller_id};
984 set_source_location(*stmt, m);
985 diagram().add_message(std::move(m));
986 }
987 }
988 }
989
990 RecursiveASTVisitor<translation_unit_visitor>::TraverseCompoundStmt(stmt);
991
992 return true;
993}

◆ TraverseConceptDecl()

bool clanguml::class_diagram::visitor::translation_unit_visitor::TraverseConceptDecl ( clang::ConceptDecl *  cpt)
virtual

Definition at line 482 of file translation_unit_visitor.cc.

483{
484 if (!should_include(cpt))
485 return true;
486
487 LOG_DBG("= Visiting concept (isType: {}) declaration {} at {}",
488 cpt->isTypeConcept(), cpt->getQualifiedNameAsString(),
489 cpt->getLocation().printToString(source_manager()));
490
491 auto concept_model = create_concept_declaration(cpt);
492
493 if (!concept_model)
494 return true;
495
496 const auto concept_id = concept_model->id();
497
498 id_mapper().add(cpt->getID(), concept_id);
499
500 tbuilder().build_from_template_declaration(*concept_model, *cpt);
501
502 constexpr auto kMaxConstraintCount = 24U;
503 llvm::SmallVector<const clang::Expr *, kMaxConstraintCount> constraints{};
504 if (cpt->hasAssociatedConstraints()) {
505 cpt->getAssociatedConstraints(constraints);
506 }
507
508 for (const auto *expr : constraints) {
510 }
511
512 if (cpt->getConstraintExpr() != nullptr) {
514 cpt, cpt->getConstraintExpr(), *concept_model);
515
517 *concept_model, cpt->getConstraintExpr());
518 }
519
520 if (diagram().should_include(*concept_model)) {
521 LOG_DBG("Adding concept {} with id {}", concept_model->full_name(false),
522 concept_model->id());
523
524 add_concept(std::move(concept_model));
525 }
526 else {
527 LOG_DBG("Skipping concept {} with id {}",
528 concept_model->full_name(true), concept_model->id());
529 }
530
531 return true;
532}

◆ TraverseConditionalOperator()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseConditionalOperator ( clang::ConditionalOperator *  stmt)

Definition at line 1322 of file translation_unit_visitor.cc.

1324{
1326
1327 const auto current_caller_id = context().caller_id();
1328
1329 std::string condition_text;
1330 if (config().generate_condition_statements())
1331 condition_text = common::get_condition_text(source_manager(), stmt);
1332
1333 if (current_caller_id.value() != 0) {
1335 model::message m{message_t::kConditional, current_caller_id};
1336 set_source_location(*stmt, m);
1337 m.condition_text(condition_text);
1338 m.set_comment(get_expression_comment(source_manager(),
1339 *context().get_ast_context(), current_caller_id, stmt));
1340 diagram().add_block_message(std::move(m));
1341 }
1342
1343 RecursiveASTVisitor<translation_unit_visitor>::TraverseStmt(
1344 stmt->getCond());
1345
1346 RecursiveASTVisitor<translation_unit_visitor>::TraverseStmt(
1347 stmt->getTrueExpr());
1348
1349 if (current_caller_id.value() != 0) {
1350 model::message m{message_t::kConditionalElse, current_caller_id};
1351 set_source_location(*stmt, m);
1352 diagram().add_message(std::move(m));
1353 }
1354
1355 RecursiveASTVisitor<translation_unit_visitor>::TraverseStmt(
1356 stmt->getFalseExpr());
1357
1358 if (current_caller_id.value() != 0) {
1360 diagram().end_block_message(
1361 {message_t::kConditionalEnd, current_caller_id},
1362 message_t::kConditional);
1363 }
1364
1365 return true;
1366}

◆ TraverseCoreturnStmt()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseCoreturnStmt ( clang::CoreturnStmt *  stmt)

Definition at line 780 of file translation_unit_visitor.cc.

781{
782 if (!config().include_system_headers() &&
783 source_manager().isInSystemHeader(stmt->getSourceRange().getBegin()))
784 return true;
785
786 LOG_TRACE("Entering co_return statement at {}",
787 stmt->getBeginLoc().printToString(source_manager()));
788
789 context().enter_callexpr(stmt);
790
791 RecursiveASTVisitor<translation_unit_visitor>::TraverseCoreturnStmt(stmt);
792
793 LOG_TRACE("Leaving co_return statement at {}",
794 stmt->getBeginLoc().printToString(source_manager()));
795
797
799
800 return true;
801}

◆ TraverseCoyieldExpr()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseCoyieldExpr ( clang::CoyieldExpr *  expr)

Definition at line 734 of file translation_unit_visitor.cc.

735{
736 if (!config().include_system_headers() &&
737 source_manager().isInSystemHeader(expr->getSourceRange().getBegin()))
738 return true;
739
740 LOG_TRACE("Entering co_yield expression at {}",
741 expr->getBeginLoc().printToString(source_manager()));
742
743 context().enter_callexpr(expr);
744
745 RecursiveASTVisitor<translation_unit_visitor>::TraverseCoyieldExpr(expr);
746
747 LOG_TRACE("Leaving co_yield expression at {}",
748 expr->getBeginLoc().printToString(source_manager()));
749
751
753
754 return true;
755}

◆ TraverseCUDAKernelCallExpr()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseCUDAKernelCallExpr ( clang::CUDAKernelCallExpr *  expr)

Definition at line 826 of file translation_unit_visitor.cc.

828{
829 if (!config().include_system_headers() &&
830 source_manager().isInSystemHeader(expr->getSourceRange().getBegin()))
831 return true;
832
833 LOG_TRACE("Entering CUDA kernel call expression at {}",
834 expr->getBeginLoc().printToString(source_manager()));
835
836 context().enter_callexpr(expr);
837
838 RecursiveASTVisitor<translation_unit_visitor>::TraverseCallExpr(expr);
839
840 LOG_TRACE("Leaving CUDA kernel call expression at {}",
841 expr->getBeginLoc().printToString(source_manager()));
842
844
846
847 return true;
848}

◆ TraverseCXXCatchStmt()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseCXXCatchStmt ( clang::CXXCatchStmt *  stmt)

Definition at line 1198 of file translation_unit_visitor.cc.

1199{
1203
1204 const auto current_caller_id = context().caller_id();
1205
1206 if ((current_caller_id.value() != 0) &&
1207 (context().current_trystmt() != nullptr)) {
1208 std::string caught_type;
1209 if (stmt->getCaughtType().isNull())
1210 caught_type = "...";
1211 else
1212 caught_type = common::to_string(
1213 stmt->getCaughtType(), *context().get_ast_context());
1214
1215 model::message m{message_t::kCatch, current_caller_id};
1216 m.set_message_name(std::move(caught_type));
1217 diagram().add_message(std::move(m));
1218 }
1219
1220 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXCatchStmt(stmt);
1221
1222 return true;
1223}

◆ TraverseCXXConstructExpr()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseCXXConstructExpr ( clang::CXXConstructExpr *  expr)

Definition at line 908 of file translation_unit_visitor.cc.

910{
911 LOG_TRACE("Entering cxx construct call expression at {}",
912 expr->getBeginLoc().printToString(source_manager()));
913
914 context().enter_callexpr(expr);
915
916 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXConstructExpr(
917 expr);
918
920
921 LOG_TRACE("Leaving cxx construct call expression at {}",
922 expr->getBeginLoc().printToString(source_manager()));
923
925
927
928 return true;
929}

◆ TraverseCXXForRangeStmt()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseCXXForRangeStmt ( clang::CXXForRangeStmt *  stmt)

Definition at line 1225 of file translation_unit_visitor.cc.

1227{
1231
1232 const auto current_caller_id = context().caller_id();
1233
1234 std::string condition_text;
1235 if (config().generate_condition_statements())
1236 condition_text = common::get_condition_text(source_manager(), stmt);
1237
1238 if (current_caller_id.value() != 0) {
1239 context().enter_loopstmt(stmt);
1240 message m{message_t::kFor, current_caller_id};
1241 set_source_location(*stmt, m);
1242 m.condition_text(condition_text);
1243 m.set_comment(get_expression_comment(source_manager(),
1244 *context().get_ast_context(), current_caller_id, stmt));
1245 diagram().add_block_message(std::move(m));
1246 }
1247
1248 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXForRangeStmt(
1249 stmt);
1250
1251 if (current_caller_id.value() != 0) {
1252 diagram().end_block_message(
1253 {message_t::kForEnd, current_caller_id}, message_t::kFor);
1255 }
1256
1257 return true;
1258}

◆ TraverseCXXMemberCallExpr()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseCXXMemberCallExpr ( clang::CXXMemberCallExpr *  expr)

Definition at line 850 of file translation_unit_visitor.cc.

852{
853 if (!config().include_system_headers() &&
854 source_manager().isInSystemHeader(expr->getSourceRange().getBegin()))
855 return true;
856
857 LOG_TRACE("Entering member call expression at {}",
858 expr->getBeginLoc().printToString(source_manager()));
859
860 context().enter_callexpr(expr);
861
862 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXMemberCallExpr(
863 expr);
864
865 LOG_TRACE("Leaving member call expression at {}",
866 expr->getBeginLoc().printToString(source_manager()));
867
869
871
872 return true;
873}

◆ TraverseCXXMethodDecl()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseCXXMethodDecl ( clang::CXXMethodDecl *  declaration)

Definition at line 381 of file translation_unit_visitor.cc.

383{
384 // We need to backup the context, since other methods or functions can
385 // be traversed during this traversal (e.g. template function/method
386 // specializations)
387 auto context_backup = context();
388
389 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXMethodDecl(
390 declaration);
391
392 call_expression_context_ = context_backup;
393
394 return true;
395}

◆ TraverseCXXOperatorCallExpr()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseCXXOperatorCallExpr ( clang::CXXOperatorCallExpr *  expr)

Definition at line 875 of file translation_unit_visitor.cc.

877{
878 context().enter_callexpr(expr);
879
880 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXOperatorCallExpr(
881 expr);
882
884
886
887 return true;
888}

◆ TraverseCXXRecordDecl()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseCXXRecordDecl ( clang::CXXRecordDecl *  declaration)

Definition at line 156 of file translation_unit_visitor.cc.

158{
159 auto context_backup = context();
160
161 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXRecordDecl(
162 declaration);
163
164 call_expression_context_ = context_backup;
165
166 return true;
167}

◆ TraverseCXXTemporaryObjectExpr()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseCXXTemporaryObjectExpr ( clang::CXXTemporaryObjectExpr *  expr)

Definition at line 890 of file translation_unit_visitor.cc.

892{
893 context().enter_callexpr(expr);
894
895 RecursiveASTVisitor<
897
899 clang::dyn_cast<clang::CXXConstructExpr>(expr));
900
902
904
905 return true;
906}

◆ TraverseCXXTryStmt()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseCXXTryStmt ( clang::CXXTryStmt *  stmt)

Definition at line 1170 of file translation_unit_visitor.cc.

1171{
1175
1176 const auto current_caller_id = context().caller_id();
1177
1178 if (current_caller_id.value() != 0) {
1179 context().enter_trystmt(stmt);
1180 message m{message_t::kTry, current_caller_id};
1181 set_source_location(*stmt, m);
1182 m.set_comment(get_expression_comment(source_manager(),
1183 *context().get_ast_context(), current_caller_id, stmt));
1184 diagram().add_block_message(std::move(m));
1185 }
1186
1187 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXTryStmt(stmt);
1188
1189 if (current_caller_id.value() != 0) {
1190 diagram().end_block_message(
1191 {message_t::kTryEnd, current_caller_id}, message_t::kTry);
1193 }
1194
1195 return true;
1196}

◆ TraverseDefaultStmt()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseDefaultStmt ( clang::DefaultStmt *  stmt)

Definition at line 1304 of file translation_unit_visitor.cc.

1305{
1307
1308 const auto current_caller_id = context().caller_id();
1309
1310 if ((current_caller_id.value() != 0) &&
1311 (context().current_switchstmt() != nullptr)) {
1312 model::message m{message_t::kCase, current_caller_id};
1313 m.set_message_name("default");
1314 diagram().add_case_stmt_message(std::move(m));
1315 }
1316
1317 RecursiveASTVisitor<translation_unit_visitor>::TraverseDefaultStmt(stmt);
1318
1319 return true;
1320}

◆ TraverseDoStmt()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseDoStmt ( clang::DoStmt *  stmt)

Definition at line 1102 of file translation_unit_visitor.cc.

1103{
1107
1108 const auto current_caller_id = context().caller_id();
1109
1110 std::string condition_text;
1111 if (config().generate_condition_statements())
1112 condition_text = common::get_condition_text(source_manager(), stmt);
1113
1114 if (current_caller_id.value() != 0) {
1115 context().enter_loopstmt(stmt);
1116 message m{message_t::kDo, current_caller_id};
1117 set_source_location(*stmt, m);
1118 m.condition_text(condition_text);
1119 m.set_comment(get_expression_comment(source_manager(),
1120 *context().get_ast_context(), current_caller_id, stmt));
1121 diagram().add_block_message(std::move(m));
1122 }
1123
1124 RecursiveASTVisitor<translation_unit_visitor>::TraverseDoStmt(stmt);
1125
1126 if (current_caller_id.value() != 0) {
1127 diagram().end_block_message(
1128 {message_t::kDoEnd, current_caller_id}, message_t::kDo);
1130 }
1131
1132 return true;
1133}

◆ TraverseForStmt()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseForStmt ( clang::ForStmt *  stmt)

Definition at line 1135 of file translation_unit_visitor.cc.

1136{
1140
1141 const auto current_caller_id = context().caller_id();
1142
1143 std::string condition_text;
1144 if (config().generate_condition_statements())
1145 condition_text = common::get_condition_text(source_manager(), stmt);
1146
1147 if (current_caller_id.value() != 0) {
1148 context().enter_loopstmt(stmt);
1149 message m{message_t::kFor, current_caller_id};
1150 set_source_location(*stmt, m);
1151 m.condition_text(condition_text);
1152
1153 m.set_comment(get_expression_comment(source_manager(),
1154 *context().get_ast_context(), current_caller_id, stmt));
1155
1156 diagram().add_block_message(std::move(m));
1157 }
1158
1159 RecursiveASTVisitor<translation_unit_visitor>::TraverseForStmt(stmt);
1160
1161 if (current_caller_id.value() != 0) {
1162 diagram().end_block_message(
1163 {message_t::kForEnd, current_caller_id}, message_t::kFor);
1165 }
1166
1167 return true;
1168}

◆ TraverseFunctionDecl()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseFunctionDecl ( clang::FunctionDecl *  declaration)

Definition at line 459 of file translation_unit_visitor.cc.

461{
462 // We need to backup the context, since other methods or functions can
463 // be traversed during this traversal (e.g. template function/method
464 // specializations)
465 auto context_backup = context();
466
467 RecursiveASTVisitor<translation_unit_visitor>::TraverseFunctionDecl(
468 declaration);
469
470 call_expression_context_ = context_backup;
471
472 return true;
473}

◆ TraverseFunctionTemplateDecl()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseFunctionTemplateDecl ( clang::FunctionTemplateDecl *  declaration)

Definition at line 553 of file translation_unit_visitor.cc.

555{
556 // We need to backup the context, since other methods or functions can
557 // be traversed during this traversal (e.g. template function/method
558 // specializations)
559 auto context_backup = context();
560
561 RecursiveASTVisitor<translation_unit_visitor>::TraverseFunctionTemplateDecl(
562 declaration);
563
564 call_expression_context_ = context_backup;
565
566 return true;
567}

◆ TraverseIfStmt()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseIfStmt ( clang::IfStmt *  stmt)

Definition at line 995 of file translation_unit_visitor.cc.

996{
1001
1002 bool elseif_block{false};
1003
1004 const auto current_caller_id = context().caller_id();
1005 const auto *current_ifstmt = context().current_ifstmt();
1006 const auto *current_elseifstmt =
1007 current_ifstmt != nullptr ? context().current_elseifstmt() : nullptr;
1008
1009 std::string condition_text;
1010 if (config().generate_condition_statements())
1011 condition_text = common::get_condition_text(source_manager(), stmt);
1012
1013 // Check if this is a beginning of a new if statement, or an
1014 // else if condition of the current if statement
1015 auto child_stmt_compare = [stmt](auto *child_stmt) {
1016 return child_stmt == stmt;
1017 };
1018
1019 if (current_ifstmt != nullptr)
1020 elseif_block = elseif_block ||
1021 std::any_of(current_ifstmt->children().begin(),
1022 current_ifstmt->children().end(), child_stmt_compare);
1023 if (current_elseifstmt != nullptr)
1024 elseif_block = elseif_block ||
1025 std::any_of(current_elseifstmt->children().begin(),
1026 current_elseifstmt->children().end(), child_stmt_compare);
1027
1028 if ((current_caller_id.value() != 0) && !stmt->isConstexpr()) {
1029 if (elseif_block) {
1030 context().enter_elseifstmt(stmt);
1031
1032 message m{message_t::kElseIf, current_caller_id};
1033 set_source_location(*stmt, m);
1034 m.condition_text(condition_text);
1035 m.set_comment(get_expression_comment(source_manager(),
1036 *context().get_ast_context(), current_caller_id, stmt));
1037 diagram().add_block_message(std::move(m));
1038 }
1039 else {
1040 context().enter_ifstmt(stmt);
1041 LOG_TRACE("Entered if statement at {}",
1042 stmt->getBeginLoc().printToString(source_manager()));
1043
1044 message m{message_t::kIf, current_caller_id};
1045 set_source_location(*stmt, m);
1046 m.condition_text(condition_text);
1047 m.set_comment(get_expression_comment(source_manager(),
1048 *context().get_ast_context(), current_caller_id, stmt));
1049 diagram().add_block_message(std::move(m));
1050 }
1051 }
1052
1053 RecursiveASTVisitor<translation_unit_visitor>::TraverseIfStmt(stmt);
1054
1055 if ((current_caller_id.value() != 0) && !stmt->isConstexpr()) {
1056 if (!elseif_block) {
1057 diagram().end_block_message(
1058 {message_t::kIfEnd, current_caller_id}, message_t::kIf);
1060 }
1061 }
1062
1063 return true;
1064}

◆ TraverseLambdaExpr()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseLambdaExpr ( clang::LambdaExpr *  expr)

Definition at line 695 of file translation_unit_visitor.cc.

696{
697 auto context_backup = context();
698
699 RecursiveASTVisitor<translation_unit_visitor>::TraverseLambdaExpr(expr);
700
701 // lambda context is entered inside the visitor
703
704 call_expression_context_ = context_backup;
705
706 return true;
707}

◆ TraverseObjCMessageExpr()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseObjCMessageExpr ( clang::ObjCMessageExpr *  expr)

Definition at line 709 of file translation_unit_visitor.cc.

711{
712 if (!config().include_system_headers() &&
713 source_manager().isInSystemHeader(expr->getSourceRange().getBegin()))
714 return true;
715
716 LOG_TRACE("Entering ObjC message expression at {}",
717 expr->getBeginLoc().printToString(source_manager()));
718
719 context().enter_callexpr(expr);
720
721 RecursiveASTVisitor<translation_unit_visitor>::TraverseObjCMessageExpr(
722 expr);
723
724 LOG_TRACE("Leaving ObjC message expression at {}",
725 expr->getBeginLoc().printToString(source_manager()));
726
728
730
731 return true;
732}

◆ TraverseObjCMethodDecl()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseObjCMethodDecl ( clang::ObjCMethodDecl *  declaration)

Definition at line 326 of file translation_unit_visitor.cc.

328{
329 // We need to backup the context, since other methods or functions can
330 // be traversed during this traversal (e.g. template function/method
331 // specializations)
332 auto context_backup = context();
333
334 RecursiveASTVisitor<translation_unit_visitor>::TraverseObjCMethodDecl(
335 declaration);
336
337 call_expression_context_ = context_backup;
338
339 return true;
340}

◆ TraverseReturnStmt()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseReturnStmt ( clang::ReturnStmt *  stmt)

Definition at line 931 of file translation_unit_visitor.cc.

932{
933 LOG_TRACE("Entering return statement at {}",
934 stmt->getBeginLoc().printToString(source_manager()));
935
936 context().enter_callexpr(stmt);
937
938 RecursiveASTVisitor<translation_unit_visitor>::TraverseReturnStmt(stmt);
939
940 LOG_TRACE("Leaving return statement at {}",
941 stmt->getBeginLoc().printToString(source_manager()));
942
944
946
947 return true;
948}

◆ TraverseSwitchStmt()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseSwitchStmt ( clang::SwitchStmt *  stmt)

Definition at line 1260 of file translation_unit_visitor.cc.

1261{
1263
1264 const auto current_caller_id = context().caller_id();
1265
1266 if (current_caller_id.value() != 0) {
1267 context().enter_switchstmt(stmt);
1268 model::message m{message_t::kSwitch, current_caller_id};
1269 set_source_location(*stmt, m);
1270 m.set_comment(get_expression_comment(source_manager(),
1271 *context().get_ast_context(), current_caller_id, stmt));
1272 diagram().add_block_message(std::move(m));
1273 }
1274
1275 RecursiveASTVisitor<translation_unit_visitor>::TraverseSwitchStmt(stmt);
1276
1277 if (current_caller_id.value() != 0) {
1279 diagram().end_block_message(
1280 {message_t::kSwitchEnd, current_caller_id}, message_t::kSwitch);
1281 }
1282
1283 return true;
1284}

◆ TraverseVarDecl()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseVarDecl ( clang::VarDecl *  VD)

Definition at line 1950 of file translation_unit_visitor.cc.

1951{
1952 if (decl->isStaticLocal())
1954
1955 RecursiveASTVisitor::TraverseVarDecl(decl);
1956
1957 if (decl->isStaticLocal())
1959
1960 return true;
1961}

◆ TraverseWhileStmt()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseWhileStmt ( clang::WhileStmt *  stmt)

Definition at line 1066 of file translation_unit_visitor.cc.

1067{
1071
1072 const auto current_caller_id = context().caller_id();
1073
1074 std::string condition_text;
1075 if (config().generate_condition_statements())
1076 condition_text = common::get_condition_text(source_manager(), stmt);
1077
1078 if (current_caller_id.value() != 0) {
1079 LOG_TRACE("Entering while statement at {}",
1080 stmt->getBeginLoc().printToString(source_manager()));
1081
1082 context().enter_loopstmt(stmt);
1083 message m{message_t::kWhile, current_caller_id};
1084 set_source_location(*stmt, m);
1085 m.condition_text(condition_text);
1086 m.set_comment(get_expression_comment(source_manager(),
1087 *context().get_ast_context(), current_caller_id, stmt));
1088 diagram().add_block_message(std::move(m));
1089 }
1090
1091 RecursiveASTVisitor<translation_unit_visitor>::TraverseWhileStmt(stmt);
1092
1093 if (current_caller_id.value() != 0) {
1094 diagram().end_block_message(
1095 {message_t::kWhileEnd, current_caller_id}, message_t::kWhile);
1097 }
1098
1099 return true;
1100}

◆ VisitCallExpr()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitCallExpr ( clang::CallExpr *  expr)

Definition at line 1457 of file translation_unit_visitor.cc.

1458{
1464
1465 if (!context().valid() || context().get_ast_context() == nullptr)
1466 return true;
1467
1468 LOG_TRACE("Visiting call expression at {} [caller_id = {}]",
1469 expr->getBeginLoc().printToString(source_manager()),
1470 context().caller_id());
1471
1472 message m{message_t::kCall, context().caller_id()};
1473
1474 m.in_static_declaration_context(within_static_variable_declaration_ > 0);
1475
1476 set_source_location(*expr, m);
1477
1478 const auto *raw_expr_comment = clanguml::common::get_expression_raw_comment(
1479 source_manager(), *context().get_ast_context(), expr);
1480 const auto stripped_comment = process_comment(
1481 raw_expr_comment, context().get_ast_context()->getDiagnostics(), m);
1482
1483 if (m.skip())
1484 return true;
1485
1486 auto generated_message_from_comment = generate_message_from_comment(m);
1487
1488 if (!generated_message_from_comment && !should_include(expr)) {
1489 LOG_DBG("Skipping call expression due to filter at: {}",
1490 expr->getBeginLoc().printToString(source_manager()));
1491
1492 processed_comments().erase(raw_expr_comment);
1493 return true;
1494 }
1495
1496 if (context().is_expr_in_current_control_statement_condition(expr)) {
1497 m.set_message_scope(common::model::message_scope_t::kCondition);
1498 }
1499
1500 auto result = process_callee(expr, m, generated_message_from_comment);
1501
1502 if (!result)
1503 return true;
1504
1505 // Add message to diagram
1506 if (m.from().value() > 0 && m.to().value() > 0) {
1507 if (raw_expr_comment != nullptr)
1508 m.set_comment(raw_expr_comment->getBeginLoc().getHashValue(),
1509 stripped_comment);
1510
1512
1513 diagram().add_active_participant(m.from());
1514 diagram().add_active_participant(m.to());
1515
1516 LOG_DBG("Found call {} from {} [{}] to {} [{}] ", m.message_name(),
1517 m.from(), m.from(), m.to(), m.to());
1518
1519 push_message(expr, std::move(m));
1520 }
1521
1522 return true;
1523}

◆ VisitClassTemplateDecl() [1/3]

bool clanguml::class_diagram::visitor::translation_unit_visitor::VisitClassTemplateDecl ( clang::ClassTemplateDecl *  class_template_declaration)
virtual

Definition at line 294 of file translation_unit_visitor.cc.

296{
297 if (!should_include(cls))
298 return true;
299
300 LOG_DBG("= Visiting class template declaration {} at {}",
301 cls->getQualifiedNameAsString(),
302 cls->getLocation().printToString(source_manager()));
303
304 auto c_ptr = create_declaration(cls->getTemplatedDecl());
305
306 if (!c_ptr)
307 return true;
308
309 add_processed_template_class(cls->getQualifiedNameAsString());
310
311 tbuilder().build_from_template_declaration(*c_ptr, *cls, *c_ptr);
312
313 // Override the id with the template id, for now we don't care about the
314 // underlying templated class id
315 const auto cls_full_name = c_ptr->full_name(false);
316 const auto id = common::to_id(cls_full_name);
317
318 c_ptr->set_id(id);
319 c_ptr->is_template(true);
320
321 id_mapper().add(cls->getID(), id);
322
323 constexpr auto kMaxConstraintCount = 24U;
324 llvm::SmallVector<const clang::Expr *, kMaxConstraintCount> constraints{};
325 if (cls->hasAssociatedConstraints()) {
326 cls->getAssociatedConstraints(constraints);
327 }
328
329 for (const auto *expr : constraints) {
331 }
332
333 return add_or_update(cls->getTemplatedDecl(), std::move(c_ptr));
334}

◆ VisitClassTemplateDecl() [2/3]

bool clanguml::package_diagram::visitor::translation_unit_visitor::VisitClassTemplateDecl ( clang::ClassTemplateDecl *  decl)
virtual

Definition at line 194 of file translation_unit_visitor.cc.

196{
197 assert(decl != nullptr);
198
199 // Skip system headers
200 if (source_manager().isInSystemHeader(decl->getSourceRange().getBegin()))
201 return true;
202
203 found_relationships_t relationships;
204
205 util::if_not_null(decl->getTemplatedDecl(),
206 [this, &relationships, decl](const auto *template_decl) {
207 if (template_decl->isCompleteDefinition()) {
208 process_class_declaration(*template_decl, relationships);
209 add_relationships(decl, relationships);
210 }
211 });
212
213 return true;
214}

◆ VisitClassTemplateDecl() [3/3]

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitClassTemplateDecl ( clang::ClassTemplateDecl *  declaration)

Definition at line 233 of file translation_unit_visitor.cc.

235{
236 if (!should_include(declaration))
237 return true;
238
239 LOG_TRACE("Visiting class template declaration {} at {} [{}]",
240 declaration->getQualifiedNameAsString(),
241 declaration->getLocation().printToString(source_manager()),
242 (void *)declaration);
243
244 auto class_model_ptr = create_class_model(declaration->getTemplatedDecl());
245
246 if (!class_model_ptr)
247 return true;
248
249 tbuilder().build_from_template_declaration(*class_model_ptr, *declaration);
250
251 const auto class_full_name = class_model_ptr->full_name(false);
252 const auto id = common::to_id(class_full_name);
253
254 // Override the id with the template id, for now we don't care about the
255 // underlying templated class id
256 class_model_ptr->set_id(id);
257
258 set_unique_id(declaration->getID(), id);
259
260 if (!declaration->getTemplatedDecl()->isCompleteDefinition()) {
261 forward_declarations_.emplace(id, std::move(class_model_ptr));
262 return true;
263 }
264 forward_declarations_.erase(id);
265
266 if (diagram().should_include(*class_model_ptr)) {
267 LOG_DBG("Adding class template participant {} with id {}",
268 class_full_name, id);
269
271 context().update(declaration);
272
273 diagram().add_participant(std::move(class_model_ptr));
274 }
275
276 return true;
277}

◆ VisitClassTemplateSpecializationDecl() [1/2]

bool clanguml::class_diagram::visitor::translation_unit_visitor::VisitClassTemplateSpecializationDecl ( clang::ClassTemplateSpecializationDecl *  cls)
virtual

Definition at line 228 of file translation_unit_visitor.cc.

230{
231 if (!should_include(cls))
232 return true;
233
234 LOG_DBG("= Visiting template specialization declaration {} at {} "
235 "(described class id {})",
236 cls->getQualifiedNameAsString(),
237 cls->getLocation().printToString(source_manager()),
238 cls->getSpecializedTemplate()
239 ? cls->getSpecializedTemplate()->getTemplatedDecl()->getID()
240 : 0);
241
242 // TODO: Add support for classes defined in function/method bodies
243 if (cls->isLocalClass() != nullptr)
244 return true;
245
246 auto template_specialization_ptr = process_template_specialization(cls);
247
248 if (!template_specialization_ptr)
249 return true;
250
251 return add_or_update(cls, std::move(template_specialization_ptr));
252}

◆ VisitClassTemplateSpecializationDecl() [2/2]

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitClassTemplateSpecializationDecl ( clang::ClassTemplateSpecializationDecl *  declaration)

Definition at line 279 of file translation_unit_visitor.cc.

281{
282 if (!should_include(declaration))
283 return true;
284
285 LOG_TRACE("Visiting template specialization declaration {} at {}",
286 declaration->getQualifiedNameAsString(),
287 declaration->getLocation().printToString(source_manager()));
288
289 if (declaration->isLocalClass() != nullptr)
290 return true;
291
292 auto template_specialization_ptr =
294
295 if (!template_specialization_ptr)
296 return true;
297
298 const auto class_full_name = template_specialization_ptr->full_name(false);
299 const auto id = common::to_id(class_full_name);
300
301 template_specialization_ptr->set_id(id);
302
303 set_unique_id(declaration->getID(), id);
304
305 if (!declaration->isCompleteDefinition()) {
306 forward_declarations_.emplace(
307 id, std::move(template_specialization_ptr));
308 return true;
309 }
310 forward_declarations_.erase(id);
311
312 if (diagram().should_include(*template_specialization_ptr)) {
313 LOG_DBG(
314 "Adding class template specialization participant {} with id {}",
315 class_full_name, id);
316
318 context().update(declaration);
319
320 diagram().add_participant(std::move(template_specialization_ptr));
321 }
322
323 return true;
324}

◆ VisitCoawaitExpr()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitCoawaitExpr ( clang::CoawaitExpr *  expr)

Definition at line 1628 of file translation_unit_visitor.cc.

1629{
1635
1636 if (!context().valid() || context().get_ast_context() == nullptr)
1637 return true;
1638
1639 LOG_TRACE("Visiting co_await expression at {} [caller_id = {}]",
1640 expr->getBeginLoc().printToString(source_manager()),
1641 context().caller_id());
1642
1643 message m{message_t::kCoAwait, context().caller_id()};
1644 set_source_location(*expr, m);
1645
1646 if (expr->getOperand() != nullptr) {
1647 std::string message_name = common::to_string(expr->getOperand());
1648 m.set_message_name(util::condense_whitespace(message_name));
1649 }
1650
1651 const auto *raw_expr_comment = clanguml::common::get_expression_raw_comment(
1652 source_manager(), *context().get_ast_context(), expr);
1653 const auto stripped_comment = process_comment(
1654 raw_expr_comment, context().get_ast_context()->getDiagnostics(), m);
1655
1656 if (m.skip())
1657 return true;
1658
1659 auto generated_message_from_comment = generate_message_from_comment(m);
1660
1661 if (!generated_message_from_comment &&
1663 clang::dyn_cast_or_null<clang::CallExpr>(expr->getResumeExpr()))) {
1664 LOG_DBG("Skipping call expression due to filter at: {}",
1665 expr->getBeginLoc().printToString(source_manager()));
1666
1667 processed_comments().erase(raw_expr_comment);
1668 return true;
1669 }
1670
1671 if (context().is_expr_in_current_control_statement_condition(expr)) {
1672 m.set_message_scope(common::model::message_scope_t::kCondition);
1673 }
1674
1675 auto result = process_callee(
1676 clang::dyn_cast_or_null<clang::CallExpr>(expr->getResumeExpr()), m,
1677 generated_message_from_comment);
1678
1679 if (!result)
1680 return true;
1681
1682 // We can skip the ID of the return activity here, we'll just add it during
1683 // diagram generation
1684 if (m.from().value() > 0) {
1685 if (raw_expr_comment != nullptr)
1686 m.set_comment(raw_expr_comment->getBeginLoc().getHashValue(),
1687 stripped_comment);
1688
1690
1691 diagram().add_active_participant(m.from());
1692
1693 LOG_DBG("Found return call {} from {} [{}] to {} [{}] ",
1694 m.message_name(), m.from(), m.from(), m.to(), m.to());
1695
1696 push_message(expr, std::move(m));
1697 }
1698
1699 return true;
1700}

◆ VisitCoreturnStmt()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitCoreturnStmt ( clang::CoreturnStmt *  stmt)

Definition at line 1852 of file translation_unit_visitor.cc.

1853{
1859
1860 if (!context().valid() || context().get_ast_context() == nullptr)
1861 return true;
1862
1863 LOG_TRACE("Visiting co_return statement at {}",
1864 stmt->getBeginLoc().printToString(source_manager()));
1865
1866 message m{message_t::kCoReturn, context().caller_id()};
1867
1868 set_source_location(*stmt, m);
1869
1870 const auto *raw_expr_comment = clanguml::common::get_expression_raw_comment(
1871 source_manager(), *context().get_ast_context(), stmt);
1872 const auto stripped_comment = process_comment(
1873 raw_expr_comment, context().get_ast_context()->getDiagnostics(), m);
1874
1875 if (m.skip())
1876 return true;
1877
1878 if (stmt->getOperand() != nullptr) {
1879 std::string message_name = common::to_string(stmt->getOperand());
1880 m.set_message_name(util::condense_whitespace(message_name));
1881 }
1882
1883 if (context().current_function_decl_ != nullptr) {
1884 m.set_return_type(
1885 context().current_function_decl_->getReturnType().getAsString());
1886 }
1887 else if (context().current_function_template_decl_ != nullptr) {
1888 m.set_return_type(context()
1889 .current_function_template_decl_->getAsFunction()
1890 ->getReturnType()
1891 .getAsString());
1892 }
1893 else if (context().current_method_decl_ != nullptr) {
1894 m.set_return_type(
1895 context().current_method_decl_->getReturnType().getAsString());
1896 }
1897 else if (context().current_objc_method_decl_ != nullptr) {
1898 m.set_return_type(
1899 context().current_objc_method_decl_->getReturnType().getAsString());
1900 }
1901
1902 // We can skip the ID of the return activity here, we'll just add it during
1903 // diagram generation
1904 if (m.from().value() > 0) {
1905 if (raw_expr_comment != nullptr)
1906 m.set_comment(raw_expr_comment->getBeginLoc().getHashValue(),
1907 stripped_comment);
1908
1910
1911 diagram().add_active_participant(m.from());
1912
1913 LOG_DBG("Found co_return call {} from {} [{}] to {} [{}] ",
1914 m.message_name(), m.from(), m.from(), m.to(), m.to());
1915
1916 push_message(stmt, std::move(m));
1917 }
1918
1919 return true;
1920}

◆ VisitCoyieldExpr()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitCoyieldExpr ( clang::CoyieldExpr *  expr)

Definition at line 1782 of file translation_unit_visitor.cc.

1783{
1789
1790 if (!context().valid() || context().get_ast_context() == nullptr)
1791 return true;
1792
1793 LOG_TRACE("Visiting co_yield expression at {}",
1794 expr->getBeginLoc().printToString(source_manager()));
1795
1796 message m{message_t::kCoYield, context().caller_id()};
1797
1798 set_source_location(*expr, m);
1799
1800 const auto *raw_expr_comment = clanguml::common::get_expression_raw_comment(
1801 source_manager(), *context().get_ast_context(), expr);
1802 const auto stripped_comment = process_comment(
1803 raw_expr_comment, context().get_ast_context()->getDiagnostics(), m);
1804
1805 if (m.skip())
1806 return true;
1807
1808 if (expr->getOperand() != nullptr) {
1809 std::string message_name = common::to_string(expr->getOperand());
1810 m.set_message_name(util::condense_whitespace(message_name));
1811 }
1812
1813 if (context().current_function_decl_ != nullptr) {
1814 m.set_return_type(
1815 context().current_function_decl_->getReturnType().getAsString());
1816 }
1817 else if (context().current_function_template_decl_ != nullptr) {
1818 m.set_return_type(context()
1819 .current_function_template_decl_->getAsFunction()
1820 ->getReturnType()
1821 .getAsString());
1822 }
1823 else if (context().current_method_decl_ != nullptr) {
1824 m.set_return_type(
1825 context().current_method_decl_->getReturnType().getAsString());
1826 }
1827 else if (context().current_objc_method_decl_ != nullptr) {
1828 m.set_return_type(
1829 context().current_objc_method_decl_->getReturnType().getAsString());
1830 }
1831
1832 // We can skip the ID of the return activity here, we'll just add it during
1833 // diagram generation
1834 if (m.from().value() > 0) {
1835 if (raw_expr_comment != nullptr)
1836 m.set_comment(raw_expr_comment->getBeginLoc().getHashValue(),
1837 stripped_comment);
1838
1840
1841 diagram().add_active_participant(m.from());
1842
1843 LOG_DBG("Found co_yield call {} from {} [{}] to {} [{}] ",
1844 m.message_name(), m.from(), m.from(), m.to(), m.to());
1845
1846 push_message(expr, std::move(m));
1847 }
1848
1849 return true;
1850}

◆ VisitCXXConstructExpr()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitCXXConstructExpr ( clang::CXXConstructExpr *  expr)

Definition at line 1963 of file translation_unit_visitor.cc.

1965{
1971
1972 if (expr == nullptr)
1973 return true;
1974
1975 if (const auto *ctor = expr->getConstructor();
1976 ctor != nullptr && !should_include(ctor))
1977 return true;
1978
1979 LOG_TRACE("Visiting cxx construct expression at {} [caller_id = {}]",
1980 expr->getBeginLoc().printToString(source_manager()),
1981 context().caller_id());
1982
1983 message m{message_t::kCall, context().caller_id()};
1984
1985 m.in_static_declaration_context(within_static_variable_declaration_ > 0);
1986
1987 set_source_location(*expr, m);
1988
1989 if (context().is_expr_in_current_control_statement_condition(expr)) {
1990 m.set_message_scope(common::model::message_scope_t::kCondition);
1991 }
1992
1993 if (!process_construct_expression(m, expr))
1994 return true;
1995
1996 if (m.from().value() > 0 && m.to().value() > 0) {
1998
1999 diagram().add_active_participant(m.from());
2000 diagram().add_active_participant(m.to());
2001
2002 LOG_DBG("Found constructor call {} from {} [{}] to {} [{}] ",
2003 m.message_name(), m.from(), m.from(), m.to(), m.to());
2004
2005 push_message(expr, std::move(m));
2006 }
2007
2008 return true;
2009}

◆ VisitCXXMethodDecl()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitCXXMethodDecl ( clang::CXXMethodDecl *  declaration)

Definition at line 397 of file translation_unit_visitor.cc.

399{
400 if (!should_include(declaration))
401 return true;
402
403 if (!declaration->isThisDeclarationADefinition()) {
404 if (auto *declaration_definition = declaration->getDefinition();
405 declaration_definition != nullptr) {
406 if (auto *method_definition = clang::dyn_cast<clang::CXXMethodDecl>(
407 declaration_definition);
408 method_definition != nullptr) {
409 LOG_DBG("Calling VisitCXXMethodDecl recursively for forward "
410 "declaration");
411
412 return VisitCXXMethodDecl(method_definition);
413 }
414 }
415 }
416
417 LOG_TRACE("Visiting method {} in class {} [{}]",
418 declaration->getQualifiedNameAsString(),
419 declaration->getParent()->getQualifiedNameAsString(),
420 (void *)declaration->getParent());
421
422 context().update(declaration);
423
424 auto method_model_ptr = create_method_model(declaration);
425
426 if (!method_model_ptr)
427 return true;
428
429 process_comment(*declaration, *method_model_ptr);
430
431 set_source_location(*declaration, *method_model_ptr);
432
433 const auto method_full_name = method_model_ptr->full_name(false);
434
435 method_model_ptr->set_id(common::to_id(method_full_name));
436
437 // Callee methods in call expressions are referred to by first declaration
438 // id, so they should both be mapped to method_model
439 if (declaration->isThisDeclarationADefinition()) {
441 declaration->getFirstDecl()->getID(), method_model_ptr->id());
442 }
443
444 set_unique_id(declaration->getID(), method_model_ptr->id());
445
446 LOG_TRACE("Set id {} --> {} for method name {} [{}]", declaration->getID(),
447 method_model_ptr->id(), method_full_name,
448 declaration->isThisDeclarationADefinition());
449
450 context().update(declaration);
451
452 context().set_caller_id(method_model_ptr->id());
453
454 diagram().add_participant(std::move(method_model_ptr));
455
456 return true;
457}

◆ VisitCXXRecordDecl() [1/3]

bool clanguml::package_diagram::visitor::translation_unit_visitor::VisitCXXRecordDecl ( clang::CXXRecordDecl *  cls)
virtual

Definition at line 135 of file translation_unit_visitor.cc.

136{
137 assert(cls != nullptr);
138
139 // Skip system headers
140 if (source_manager().isInSystemHeader(cls->getSourceRange().getBegin()))
141 return true;
142
143 // Templated records are handled by VisitClassTemplateDecl()
144 if (cls->isTemplated() || cls->isTemplateDecl() ||
145 (clang::dyn_cast_or_null<clang::ClassTemplateSpecializationDecl>(cls) !=
146 nullptr))
147 return true;
148
149 found_relationships_t relationships;
150
151 if (cls->isCompleteDefinition()) {
152 process_class_declaration(*cls, relationships);
153 add_relationships(cls, relationships);
154 }
155
156 return true;
157}

◆ VisitCXXRecordDecl() [2/3]

bool clanguml::class_diagram::visitor::translation_unit_visitor::VisitCXXRecordDecl ( clang::CXXRecordDecl *  d)
virtual

Definition at line 770 of file translation_unit_visitor.cc.

771{
772 if (!should_include(cls))
773 return true;
774
775 LOG_DBG("= Visiting class declaration {} at {}",
776 cls->getQualifiedNameAsString(),
777 cls->getLocation().printToString(source_manager()));
778
779 LOG_DBG(
780 "== getQualifiedNameAsString() = {}", cls->getQualifiedNameAsString());
781 if (cls->getOwningModule() != nullptr)
782 LOG_DBG(
783 "== getOwningModule()->Name = {}", cls->getOwningModule()->Name);
784 LOG_DBG("== getID() = {}", cls->getID());
785 LOG_DBG("== isTemplateDecl() = {}", cls->isTemplateDecl());
786 LOG_DBG("== isTemplated() = {}", cls->isTemplated());
787 LOG_DBG("== getParent()->isRecord()() = {}", cls->getParent()->isRecord());
788 LOG_DBG("== isCompleteDefinition() = {}", cls->isCompleteDefinition());
789
790 if (const auto *parent_record =
791 clang::dyn_cast<clang::RecordDecl>(cls->getParent());
792 parent_record != nullptr) {
793 LOG_DBG("== getParent()->getQualifiedNameAsString() = {}",
794 parent_record->getQualifiedNameAsString());
795 }
796
797 if (has_processed_template_class(cls->getQualifiedNameAsString()))
798 // If we have already processed the template of this class
799 // skip it
800 return true;
801
802 if (cls->isTemplated() && (cls->getDescribedTemplate() != nullptr)) {
803 // If the described templated of this class is already in the model
804 // skip it:
805 const eid_t ast_id{cls->getDescribedTemplate()->getID()};
806 if (id_mapper().get_global_id(ast_id))
807 return true;
808 }
809
810 // TODO: Add support for classes defined in function/method bodies
811 if (cls->isLocalClass() != nullptr)
812 return true;
813
814 auto c_ptr = create_declaration(cls);
815
816 if (!c_ptr)
817 return true;
818
819 return add_or_update(cls, std::move(c_ptr));
820}

◆ VisitCXXRecordDecl() [3/3]

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitCXXRecordDecl ( clang::CXXRecordDecl *  declaration)

Definition at line 169 of file translation_unit_visitor.cc.

171{
172 if (!should_include(declaration))
173 return true;
174
175 // Skip this class if it's parent template is already in the model
176 if (declaration->isTemplated() &&
177 declaration->getDescribedTemplate() != nullptr) {
178 if (get_unique_id(eid_t{declaration->getDescribedTemplate()->getID()}))
179 return true;
180 }
181
182 LOG_TRACE("Visiting class declaration at {}",
183 declaration->getBeginLoc().printToString(source_manager()));
184
185 // Build the class declaration and store it in the diagram, even
186 // if we don't need it for any of the participants of this diagram
187 auto class_model_ptr = create_class_model(declaration);
188
189 if (!class_model_ptr)
190 return true;
191
192 context().reset();
193
194 const auto class_id = class_model_ptr->id();
195
196 set_unique_id(declaration->getID(), class_id);
197
198 auto &class_model =
199 diagram()
200 .get_participant<sequence_diagram::model::class_>(class_id)
201 .has_value()
202 ? *diagram()
203 .get_participant<sequence_diagram::model::class_>(class_id)
204 .get()
205 : *class_model_ptr;
206
207 if (!declaration->isCompleteDefinition()) {
208 forward_declarations_.emplace(class_id, std::move(class_model_ptr));
209 return true;
210 }
211
212 forward_declarations_.erase(class_id);
213
214 if (diagram().should_include(class_model)) {
215 LOG_DBG("Adding class participant {} with id {}",
216 class_model.full_name(false), class_model.id());
217
218 assert(class_model.id() == class_id);
219
220 context().set_caller_id(class_id);
221 context().update(declaration);
222
223 diagram().add_participant(std::move(class_model_ptr));
224 }
225 else {
226 LOG_DBG("Skipping class {} with id {}", class_model.full_name(true),
227 class_id);
228 }
229
230 return true;
231}

◆ VisitEnumDecl() [1/2]

bool clanguml::package_diagram::visitor::translation_unit_visitor::VisitEnumDecl ( clang::EnumDecl *  decl)
virtual

Definition at line 177 of file translation_unit_visitor.cc.

178{
179 assert(decl != nullptr);
180
181 // Skip system headers
182 if (source_manager().isInSystemHeader(decl->getSourceRange().getBegin()))
183 return true;
184
185 found_relationships_t relationships;
186
187 if (decl->isCompleteDefinition()) {
188 add_relationships(decl, relationships);
189 }
190
191 return true;
192}

◆ VisitEnumDecl() [2/2]

bool clanguml::class_diagram::visitor::translation_unit_visitor::VisitEnumDecl ( clang::EnumDecl *  e)
virtual

Definition at line 134 of file translation_unit_visitor.cc.

135{
136 assert(enm != nullptr);
137
138 // Anonymous enum values are either class fields with type enum or
139 // `typedef enum` declarations
140 if (enm->getNameAsString().empty()) {
141 return true;
142 }
143
144 if (!should_include(enm))
145 return true;
146
147 LOG_DBG("= Visiting enum declaration {} at {}",
148 enm->getQualifiedNameAsString(),
149 enm->getLocation().printToString(source_manager()));
150
151 auto e_ptr = create_declaration(enm, nullptr);
152 if (!e_ptr)
153 return true;
154
155 return add_or_update(enm, std::move(e_ptr));
156}

◆ VisitFunctionDecl() [1/2]

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitFunctionDecl ( clang::FunctionDecl *  declaration)

Definition at line 475 of file translation_unit_visitor.cc.

477{
478 if (declaration->isCXXClassMember())
479 return true;
480
481 if (!should_include(declaration))
482 return true;
483
484 if (!declaration->isThisDeclarationADefinition()) {
485 if (auto *declaration_definition = declaration->getDefinition();
486 declaration_definition != nullptr)
487 return VisitFunctionDecl(
488 static_cast<clang::FunctionDecl *>(declaration_definition));
489 }
490
491 LOG_TRACE("Visiting function declaration {} at {}",
492 declaration->getQualifiedNameAsString(),
493 declaration->getLocation().printToString(source_manager()));
494
495 if (declaration->isTemplated()) {
496 if (declaration->getDescribedTemplate() != nullptr) {
497 // If the described templated of this function is already in the
498 // model skip it:
499 if (get_unique_id(
500 eid_t{declaration->getDescribedTemplate()->getID()}))
501 return true;
502 }
503 }
504
505 std::unique_ptr<model::function> function_model_ptr{};
506
507 if (declaration->isFunctionTemplateSpecialization()) {
508 function_model_ptr =
510 }
511 else {
512 function_model_ptr = build_function_model(*declaration);
513 }
514
515 if (!function_model_ptr)
516 return true;
517
518 function_model_ptr->set_id(
519 common::to_id(function_model_ptr->full_name(false)));
520
521 function_model_ptr->is_void(declaration->getReturnType()->isVoidType());
522
523 function_model_ptr->is_operator(declaration->isOverloadedOperator());
524
525 function_model_ptr->is_cuda_kernel(
526 common::has_attr(declaration, clang::attr::CUDAGlobal));
527
528 function_model_ptr->is_cuda_device(
529 common::has_attr(declaration, clang::attr::CUDADevice));
530
531 function_model_ptr->is_coroutine(common::is_coroutine(*declaration));
532
533 context().update(declaration);
534
535 context().set_caller_id(function_model_ptr->id());
536
537 if (declaration->isThisDeclarationADefinition()) {
539 declaration->getFirstDecl()->getID(), function_model_ptr->id());
540 }
541
542 set_unique_id(declaration->getID(), function_model_ptr->id());
543
544 process_comment(*declaration, *function_model_ptr);
545
546 set_source_location(*declaration, *function_model_ptr);
547
548 diagram().add_participant(std::move(function_model_ptr));
549
550 return true;
551}

◆ VisitFunctionDecl() [2/2]

bool clanguml::package_diagram::visitor::translation_unit_visitor::VisitFunctionDecl ( clang::FunctionDecl *  function_declaration)
virtual

Definition at line 109 of file translation_unit_visitor.cc.

111{
112 assert(function_declaration != nullptr);
113
114 // Skip system headers
115 if (source_manager().isInSystemHeader(
116 function_declaration->getSourceRange().getBegin()))
117 return true;
118
119 found_relationships_t relationships;
120
121 find_relationships(function_declaration,
122 function_declaration->getReturnType(), relationships);
123
124 for (const auto *param : function_declaration->parameters()) {
125 if (param != nullptr)
127 function_declaration, param->getType(), relationships);
128 }
129
130 add_relationships(function_declaration, relationships);
131
132 return true;
133}

◆ VisitFunctionTemplateDecl()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitFunctionTemplateDecl ( clang::FunctionTemplateDecl *  function_declaration)

Definition at line 569 of file translation_unit_visitor.cc.

571{
572 if (!should_include(declaration))
573 return true;
574
575 const auto function_name = declaration->getQualifiedNameAsString();
576
577 LOG_TRACE("Visiting function template declaration {} at {}", function_name,
578 declaration->getLocation().printToString(source_manager()));
579
580 auto function_template_model = build_function_template(*declaration);
581
582 process_comment(*declaration, *function_template_model);
583
584 set_source_location(*declaration, *function_template_model);
585 set_owning_module(*declaration, *function_template_model);
586
587 function_template_model->is_void(
588 declaration->getAsFunction()->getReturnType()->isVoidType());
589
590 function_template_model->set_id(
591 common::to_id(function_template_model->full_name(false)));
592
593 function_template_model->is_operator(
594 declaration->getAsFunction()->isOverloadedOperator());
595
596 context().update(declaration);
597
598 context().set_caller_id(function_template_model->id());
599
600 set_unique_id(declaration->getID(), function_template_model->id());
601
602 diagram().add_participant(std::move(function_template_model));
603
604 return true;
605}

◆ VisitLambdaExpr()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitLambdaExpr ( clang::LambdaExpr *  expr)

Definition at line 607 of file translation_unit_visitor.cc.

608{
609 if (!should_include(expr))
610 return true;
611
612 const auto lambda_full_name =
613 expr->getLambdaClass()->getCanonicalDecl()->getNameAsString();
614
615 LOG_TRACE("Visiting lambda expression {} at {} [caller_id = {}]",
616 lambda_full_name, expr->getBeginLoc().printToString(source_manager()),
617 context().caller_id());
618
619 LOG_TRACE("Lambda call operator ID {} - lambda class ID {}, class call "
620 "operator ID {}",
621 expr->getCallOperator()->getID(), expr->getLambdaClass()->getID(),
622 expr->getLambdaClass()->getLambdaCallOperator()->getID());
623
624 // Create lambda class participant
625 auto *cls = expr->getLambdaClass();
626 auto lambda_class_model_ptr = create_class_model(cls);
627
628 if (!lambda_class_model_ptr)
629 return true;
630
631 lambda_class_model_ptr->is_lambda(true);
632
633 const auto cls_id = lambda_class_model_ptr->id();
634
635 set_unique_id(cls->getID(), cls_id);
636
637 auto lambda_method_model_ptr =
638 create_lambda_method_model(expr->getCallOperator());
639
640 lambda_method_model_ptr->set_class_id(cls_id);
641
642 // If this is a nested lambda, prepend the parent lambda name to this lambda
643 auto lambda_class_full_name = lambda_class_model_ptr->full_name(false);
644 lambda_method_model_ptr->set_class_full_name(lambda_class_full_name);
645
646 diagram().add_participant(std::move(lambda_class_model_ptr));
647
648 lambda_method_model_ptr->set_id(
649 common::to_id(get_participant(cls_id).value().full_name(false) +
650 "::" + lambda_method_model_ptr->full_name_no_ns()));
651
652 get_participant<model::class_>(cls_id).value().set_lambda_operator_id(
653 lambda_method_model_ptr->id());
654
655 // If lambda expression is in an argument to a method/function, and that
656 // method function would be excluded by filters and if it is not a lambda
657 // call itself
658 if (std::holds_alternative<clang::CallExpr *>(
659 context().current_callexpr()) &&
660 (!context().lambda_caller_id().has_value()) &&
662 std::get<clang::CallExpr *>(context().current_callexpr()))) {
665
666 message m{message_t::kCall, context().caller_id()};
667 set_source_location(*expr, m);
668 m.set_from(context().caller_id());
669 m.set_to(lambda_method_model_ptr->id());
670
672
673 diagram().add_active_participant(m.from());
674 diagram().add_active_participant(m.to());
675
676 LOG_DBG("Found call in lambda expression {} from {} [{}] to {} [{}]",
677 m.message_name(), m.from(), m.from(), m.to(), m.to());
678
679 push_message(std::get<clang::CallExpr *>(context().current_callexpr()),
680 std::move(m));
681 }
682
683 context().enter_lambda_expression(lambda_method_model_ptr->id());
684
686 expr->getCallOperator()->getID(), lambda_method_model_ptr->id());
687
688 diagram().add_participant(std::move(lambda_method_model_ptr));
689
690 [[maybe_unused]] const auto is_generic_lambda = expr->isGenericLambda();
691
692 return true;
693}

◆ VisitNamespaceDecl() [1/2]

bool clanguml::class_diagram::visitor::translation_unit_visitor::VisitNamespaceDecl ( clang::NamespaceDecl *  ns)
virtual

Definition at line 45 of file translation_unit_visitor.cc.

46{
47 assert(ns != nullptr);
48
49 if (config().package_type() == config::package_type_t::kDirectory)
50 return true;
51
52 if (ns->isAnonymousNamespace() || ns->isInline())
53 return true;
54
55 LOG_DBG("= Visiting namespace declaration {} at {}",
56 ns->getQualifiedNameAsString(),
57 ns->getLocation().printToString(source_manager()));
58
59 auto package_path = namespace_{common::get_qualified_name(*ns)};
60
61 auto package_parent = package_path;
62 bool is_root =
63 (package_path.size() == 1) && !config().using_namespace().is_empty();
64 package_path.is_root(is_root);
65
66 std::string name;
67 if (!package_path.is_empty())
68 name = package_path.name();
69
70 if (!package_parent.is_empty())
71 package_parent.pop_back();
72
73 const auto usn = config().using_namespace();
74
75 auto p = std::make_unique<common::model::package>(usn);
76 package_path = package_path.relative_to(usn);
77
78 p->set_name(name);
79 p->set_namespace(package_parent);
80 p->set_id(common::to_id(*ns));
81 p->is_root(is_root);
82 id_mapper().add(ns->getID(), p->id());
83
84 if (config().filter_mode() == config::filter_mode_t::advanced ||
85 (diagram().should_include(*p) && !diagram().get(p->id()))) {
86 process_comment(*ns, *p);
87 set_source_location(*ns, *p);
88
89 p->set_style(p->style_spec());
90
91 for (const auto *attr : ns->attrs()) {
92 if (attr->getKind() == clang::attr::Kind::Deprecated) {
93 p->set_deprecated(true);
94 break;
95 }
96 }
97
98 if (!p->skip()) {
99 diagram().add(package_path, std::move(p));
100 }
101 }
102
103 return true;
104}

◆ VisitNamespaceDecl() [2/2]

bool clanguml::package_diagram::visitor::translation_unit_visitor::VisitNamespaceDecl ( clang::NamespaceDecl *  ns)
virtual

Definition at line 45 of file translation_unit_visitor.cc.

46{
47 assert(ns != nullptr);
48
49 if (config().package_type() != config::package_type_t::kNamespace)
50 return true;
51
52 if (ns->isAnonymousNamespace() || ns->isInline())
53 return true;
54
55 auto qualified_name = common::get_qualified_name(*ns);
56
57 if (!diagram().should_include(namespace_{qualified_name}))
58 return true;
59
60 LOG_DBG("Visiting namespace declaration: {}", qualified_name);
61
62 auto package_path = namespace_{qualified_name};
63 auto package_parent = package_path;
64 bool is_root =
65 (package_path.size() == 1) && !config().using_namespace().is_empty();
66
67 std::string name;
68 if (!package_path.is_empty())
69 name = package_path.name();
70
71 if (!package_parent.is_empty())
72 package_parent.pop_back();
73
74 const auto usn = config().using_namespace();
75
76 auto p = std::make_unique<common::model::package>(usn);
77 package_path = package_path.relative_to(usn);
78
79 p->set_name(name);
80 p->set_namespace(package_parent);
81 p->is_root(is_root);
82 p->set_id(common::to_id(*ns));
83 set_source_location(*ns, *p);
84
85 assert(p->id().value() > 0);
86
87 if (diagram().should_include(*p) && !diagram().get(p->id())) {
88 process_comment(*ns, *p);
89
90 p->set_style(p->style_spec());
91
92 for (const auto *attr : ns->attrs()) {
93 if (attr->getKind() == clang::attr::Kind::Deprecated) {
94 p->set_deprecated(true);
95 break;
96 }
97 }
98
99 if (!p->skip()) {
100 LOG_DBG("Adding package {}", p->full_name(false));
101
102 diagram().add(p->path(), std::move(p));
103 }
104 }
105
106 return true;
107}

◆ VisitObjCCategoryDecl() [1/2]

bool clanguml::class_diagram::visitor::translation_unit_visitor::VisitObjCCategoryDecl ( clang::ObjCCategoryDecl *  decl)
virtual

Definition at line 361 of file translation_unit_visitor.cc.

363{
364 if (!should_include(decl))
365 return true;
366
367 LOG_DBG("= Visiting ObjC category declaration {} at {}",
368 decl->getQualifiedNameAsString(),
369 decl->getLocation().printToString(source_manager()));
370
371 auto category_ptr = create_objc_category_declaration(decl);
372
373 if (!category_ptr)
374 return true;
375
376 const auto category_id = category_ptr->id();
377
378 id_mapper().add(decl->getID(), category_id);
379
380 auto &category_model =
381 diagram().find<objc_interface>(category_id).has_value()
382 ? *diagram().find<objc_interface>(category_id).get()
383 : *category_ptr;
384
385 process_objc_category_declaration(*decl, category_model);
386
387 if (diagram().should_include(category_model)) {
388 LOG_DBG("Adding ObjC category {} with id {}",
389 category_model.full_name(false), category_model.id());
390
391 add_objc_interface(std::move(category_ptr));
392 }
393 else {
394 LOG_DBG("Skipping ObjC category {} with id {}",
395 category_model.full_name(true), category_model.id());
396 }
397
398 return true;
399}

◆ VisitObjCCategoryDecl() [2/2]

bool clanguml::package_diagram::visitor::translation_unit_visitor::VisitObjCCategoryDecl ( clang::ObjCCategoryDecl *  decl)
virtual

Definition at line 216 of file translation_unit_visitor.cc.

218{
219 assert(decl != nullptr);
220
221 // Skip system headers
222 if (source_manager().isInSystemHeader(decl->getSourceRange().getBegin()))
223 return true;
224
225 found_relationships_t relationships;
226
227 const auto target_id = get_package_id(decl->getClassInterface());
228 relationships.emplace_back(target_id, relationship_t::kDependency, decl);
229
230 process_objc_container_children(*decl, relationships);
231 add_relationships(decl, relationships);
232
233 return true;
234}

◆ VisitObjCInterfaceDecl() [1/3]

bool clanguml::class_diagram::visitor::translation_unit_visitor::VisitObjCInterfaceDecl ( clang::ObjCInterfaceDecl *  decl)
virtual

Definition at line 441 of file translation_unit_visitor.cc.

443{
444 if (!should_include(decl))
445 return true;
446
447 LOG_DBG("= Visiting ObjC interface declaration {} at {}",
448 decl->getQualifiedNameAsString(),
449 decl->getLocation().printToString(source_manager()));
450
451 auto interface_ptr = create_objc_interface_declaration(decl);
452
453 if (!interface_ptr)
454 return true;
455
456 const auto protocol_id = interface_ptr->id();
457
458 id_mapper().add(decl->getID(), protocol_id);
459
460 auto &interface_model =
461 diagram().find<objc_interface>(protocol_id).has_value()
462 ? *diagram().find<objc_interface>(protocol_id).get()
463 : *interface_ptr;
464
465 if (!interface_model.complete())
466 process_objc_interface_declaration(*decl, interface_model);
467
468 if (diagram().should_include(interface_model)) {
469 LOG_DBG("Adding ObjC interface {} with id {}",
470 interface_model.full_name(false), interface_model.id());
471
472 add_objc_interface(std::move(interface_ptr));
473 }
474 else {
475 LOG_DBG("Skipping ObjC interface {} with id {}",
476 interface_model.full_name(true), interface_model.id());
477 }
478
479 return true;
480}

◆ VisitObjCInterfaceDecl() [2/3]

bool clanguml::package_diagram::visitor::translation_unit_visitor::VisitObjCInterfaceDecl ( clang::ObjCInterfaceDecl *  decl)
virtual

Definition at line 257 of file translation_unit_visitor.cc.

259{
260 assert(decl != nullptr);
261
262 // Skip system headers
263 if (source_manager().isInSystemHeader(decl->getSourceRange().getBegin()))
264 return true;
265
266 found_relationships_t relationships;
267
268 for (const auto *protocol : decl->protocols()) {
269 process_interface_protocol(*protocol, relationships);
270 }
271
272 // Iterate over regular class fields
273 for (const auto *field : decl->ivars()) {
274 if (field != nullptr)
275 process_field(*field, relationships);
276 }
277
278 process_objc_container_children(*decl, relationships);
279
280 add_relationships(decl, relationships);
281
282 return true;
283}

◆ VisitObjCInterfaceDecl() [3/3]

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitObjCInterfaceDecl ( clang::ObjCInterfaceDecl *  interface_declaration)

Definition at line 106 of file translation_unit_visitor.cc.

108{
109 if (!should_include(declaration))
110 return true;
111
112 LOG_TRACE("Visiting ObjC interface declaration at {}",
113 declaration->getBeginLoc().printToString(source_manager()));
114
115 // Build the class declaration and store it in the diagram, even
116 // if we don't need it for any of the participants of this diagram
117 auto objc_interface_model_ptr = create_objc_interface_model(declaration);
118
119 if (!objc_interface_model_ptr)
120 return true;
121
122 context().reset();
123
124 const auto class_id = objc_interface_model_ptr->id();
125
126 set_unique_id(declaration->getID(), class_id);
127
128 auto &class_model =
129 diagram()
130 .get_participant<sequence_diagram::model::class_>(class_id)
131 .has_value()
132 ? *diagram()
133 .get_participant<sequence_diagram::model::class_>(class_id)
134 .get()
135 : *objc_interface_model_ptr;
136
137 if (diagram().should_include(class_model)) {
138 LOG_DBG("Adding ObjC interface participant {} with id {}",
139 class_model.full_name(false), class_model.id());
140
141 assert(class_model.id() == class_id);
142
143 context().set_caller_id(class_id);
144 context().update(declaration);
145
146 diagram().add_participant(std::move(objc_interface_model_ptr));
147 }
148 else {
149 LOG_DBG("Skipping ObjC interface {} with id {}",
150 class_model.full_name(true), class_id);
151 }
152
153 return true;
154}

◆ VisitObjCMessageExpr()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitObjCMessageExpr ( clang::ObjCMessageExpr *  expr)

Definition at line 1368 of file translation_unit_visitor.cc.

1370{
1376
1377 if (!context().valid() || context().get_ast_context() == nullptr)
1378 return true;
1379
1380 LOG_TRACE("Visiting ObjC message expression at {} [caller_id = {}]",
1381 expr->getBeginLoc().printToString(source_manager()),
1382 context().caller_id());
1383
1384 message m{message_t::kCall, context().caller_id()};
1385
1386 set_source_location(*expr, m);
1387
1388 const auto *raw_expr_comment = clanguml::common::get_expression_raw_comment(
1389 source_manager(), *context().get_ast_context(), expr);
1390 const auto stripped_comment = process_comment(
1391 raw_expr_comment, context().get_ast_context()->getDiagnostics(), m);
1392
1393 if (m.skip())
1394 return true;
1395
1396 auto generated_message_from_comment = generate_message_from_comment(m);
1397
1398 if (!generated_message_from_comment && !should_include(expr)) {
1399 LOG_DBG("Skipping call expression due to filter at: {}",
1400 expr->getBeginLoc().printToString(source_manager()));
1401
1402 processed_comments().erase(raw_expr_comment);
1403 return true;
1404 }
1405
1406 if (context().is_expr_in_current_control_statement_condition(expr)) {
1407 m.set_message_scope(common::model::message_scope_t::kCondition);
1408 }
1409
1410 if (generated_message_from_comment) {
1411 LOG_DBG(
1412 "Message for this call expression is taken from comment directive");
1413 return true;
1414 }
1415
1417
1418 // Add message to diagram
1419 if (m.from().value() > 0 && m.to().value() > 0) {
1420 if (raw_expr_comment != nullptr)
1421 m.set_comment(raw_expr_comment->getBeginLoc().getHashValue(),
1422 stripped_comment);
1423
1425
1426 diagram().add_active_participant(m.from());
1427 diagram().add_active_participant(m.to());
1428
1429 LOG_DBG("Found ObjC message {} from {} [{}] to {} [{}] ",
1430 m.message_name(), m.from(), m.from(), m.to(), m.to());
1431
1432 push_message(expr, std::move(m));
1433 }
1434
1435 return true;
1436}

◆ VisitObjCMethodDecl()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitObjCMethodDecl ( clang::ObjCMethodDecl *  declaration)

Definition at line 342 of file translation_unit_visitor.cc.

344{
345 if (!should_include(declaration))
346 return true;
347
348 LOG_TRACE("Visiting ObjC method {} in class",
349 declaration->getQualifiedNameAsString());
350
351 context().update(declaration);
352
353 auto method_model_ptr = create_objc_method_model(declaration);
354
355 if (!method_model_ptr)
356 return true;
357
358 process_comment(*declaration, *method_model_ptr);
359
360 set_source_location(*declaration, *method_model_ptr);
361
362 const auto method_full_name = method_model_ptr->full_name(false);
363
364 method_model_ptr->set_id(common::to_id(method_full_name));
365
366 set_unique_id(declaration->getID(), method_model_ptr->id());
367
368 LOG_TRACE("Set id {} --> {} for method name {} [{}]", declaration->getID(),
369 method_model_ptr->id(), method_full_name,
370 declaration->isThisDeclarationADefinition());
371
372 context().update(declaration);
373
374 context().set_caller_id(method_model_ptr->id());
375
376 diagram().add_participant(std::move(method_model_ptr));
377
378 return true;
379}

◆ VisitObjCPropertyRefExpr()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitObjCPropertyRefExpr ( clang::ObjCPropertyRefExpr *  expr)

Definition at line 1438 of file translation_unit_visitor.cc.

1440{
1446
1447 if (!context().valid() || context().get_ast_context() == nullptr)
1448 return true;
1449
1450 LOG_TRACE("Visiting ObjC property ref expression at {} [caller_id = {}]",
1451 expr->getBeginLoc().printToString(source_manager()),
1452 context().caller_id());
1453
1454 return true;
1455}

◆ VisitObjCProtocolDecl() [1/3]

bool clanguml::class_diagram::visitor::translation_unit_visitor::VisitObjCProtocolDecl ( clang::ObjCProtocolDecl *  decl)
virtual

Definition at line 401 of file translation_unit_visitor.cc.

403{
404 if (!should_include(decl))
405 return true;
406
407 LOG_DBG("= Visiting ObjC protocol declaration {} at {}",
408 decl->getQualifiedNameAsString(),
409 decl->getLocation().printToString(source_manager()));
410
411 auto protocol_ptr = create_objc_protocol_declaration(decl);
412
413 if (!protocol_ptr)
414 return true;
415
416 const auto protocol_id = protocol_ptr->id();
417
418 id_mapper().add(decl->getID(), protocol_id);
419
420 auto &protocol_model =
421 diagram().find<objc_interface>(protocol_id).has_value()
422 ? *diagram().find<objc_interface>(protocol_id).get()
423 : *protocol_ptr;
424
425 process_objc_protocol_declaration(*decl, protocol_model);
426
427 if (diagram().should_include(protocol_model)) {
428 LOG_DBG("Adding ObjC protocol {} with id {}",
429 protocol_model.full_name(false), protocol_model.id());
430
431 add_objc_interface(std::move(protocol_ptr));
432 }
433 else {
434 LOG_DBG("Skipping ObjC protocol {} with id {}",
435 protocol_model.full_name(true), protocol_model.id());
436 }
437
438 return true;
439}

◆ VisitObjCProtocolDecl() [2/3]

bool clanguml::package_diagram::visitor::translation_unit_visitor::VisitObjCProtocolDecl ( clang::ObjCProtocolDecl *  decl)
virtual

Definition at line 236 of file translation_unit_visitor.cc.

238{
239 assert(decl != nullptr);
240
241 // Skip system headers
242 if (source_manager().isInSystemHeader(decl->getSourceRange().getBegin()))
243 return true;
244
245 found_relationships_t relationships;
246
247 for (const auto *protocol : decl->protocols()) {
248 process_interface_protocol(*protocol, relationships);
249 }
250
251 process_objc_container_children(*decl, relationships);
252 add_relationships(decl, relationships);
253
254 return true;
255}

◆ VisitObjCProtocolDecl() [3/3]

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitObjCProtocolDecl ( clang::ObjCProtocolDecl *  protocol_declaration)

Definition at line 58 of file translation_unit_visitor.cc.

60{
61 if (!should_include(declaration))
62 return true;
63
64 LOG_TRACE("Visiting ObjC interface declaration at {}",
65 declaration->getBeginLoc().printToString(source_manager()));
66
67 auto objc_protocol_model_ptr = create_objc_protocol_model(declaration);
68
69 if (!objc_protocol_model_ptr)
70 return true;
71
72 context().reset();
73
74 const auto class_id = objc_protocol_model_ptr->id();
75
76 set_unique_id(declaration->getID(), class_id);
77
78 auto &class_model =
79 diagram()
80 .get_participant<sequence_diagram::model::class_>(class_id)
81 .has_value()
82 ? *diagram()
83 .get_participant<sequence_diagram::model::class_>(class_id)
84 .get()
85 : *objc_protocol_model_ptr;
86
87 if (diagram().should_include(class_model)) {
88 LOG_DBG("Adding ObjC protocol participant {} with id {}",
89 class_model.full_name(false), class_model.id());
90
91 assert(class_model.id() == class_id);
92
93 context().set_caller_id(class_id);
94 context().update(declaration);
95
96 diagram().add_participant(std::move(objc_protocol_model_ptr));
97 }
98 else {
99 LOG_DBG("Skipping ObjC protocol {} with id {}",
100 class_model.full_name(true), class_id);
101 }
102
103 return true;
104}

◆ VisitRecordDecl() [1/2]

bool clanguml::package_diagram::visitor::translation_unit_visitor::VisitRecordDecl ( clang::RecordDecl *  cls)
virtual

Definition at line 159 of file translation_unit_visitor.cc.

160{
161 assert(decl != nullptr);
162
163 // Skip system headers
164 if (source_manager().isInSystemHeader(decl->getSourceRange().getBegin()))
165 return true;
166
167 found_relationships_t relationships;
168
169 if (decl->isCompleteDefinition()) {
170 process_record_children(*decl, relationships);
171 add_relationships(decl, relationships);
172 }
173
174 return true;
175}

◆ VisitRecordDecl() [2/2]

bool clanguml::class_diagram::visitor::translation_unit_visitor::VisitRecordDecl ( clang::RecordDecl *  D)
virtual

Definition at line 336 of file translation_unit_visitor.cc.

337{
338 if (rec == nullptr)
339 return true;
340
341 if (clang::dyn_cast_or_null<clang::CXXRecordDecl>(rec) != nullptr)
342 // This is handled by VisitCXXRecordDecl()
343 return true;
344
345 // It seems we are in a C (not C++) translation unit
346 if (!should_include(rec))
347 return true;
348
349 LOG_DBG("= Visiting record declaration {} at {}",
350 rec->getQualifiedNameAsString(),
351 rec->getLocation().printToString(source_manager()));
352
353 auto record_ptr = create_declaration(rec);
354
355 if (!record_ptr)
356 return true;
357
358 return add_or_update(rec, std::move(record_ptr));
359}

◆ VisitReturnStmt()

bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitReturnStmt ( clang::ReturnStmt *  stmt)

Definition at line 1702 of file translation_unit_visitor.cc.

1703{
1709
1710 if (!context().valid() || context().get_ast_context() == nullptr)
1711 return true;
1712
1713 LOG_TRACE("Visiting return statement at {}",
1714 stmt->getBeginLoc().printToString(source_manager()));
1715
1716 message m{message_t::kReturn, context().caller_id()};
1717
1718 set_source_location(*stmt, m);
1719
1720 const auto *raw_expr_comment = clanguml::common::get_expression_raw_comment(
1721 source_manager(), *context().get_ast_context(), stmt);
1722 const auto stripped_comment = process_comment(
1723 raw_expr_comment, context().get_ast_context()->getDiagnostics(), m);
1724
1725 if (m.skip())
1726 return true;
1727
1728 if (stmt->getRetValue() != nullptr) {
1729 std::string message_name = common::to_string(stmt->getRetValue());
1730 m.set_message_name(util::condense_whitespace(message_name));
1731 }
1732
1733 if (context().lambda_caller_id().has_value() &&
1734 !context().is_local_class()) {
1735 const auto &lambda_model = get_participant<model::method>(
1736 *context().lambda_caller_id()); // NOLINT
1737
1738 if (lambda_model.has_value()) {
1739 if (lambda_model.has_value())
1740 m.set_return_type(lambda_model.value().return_type());
1741 }
1742 }
1743 else if (context().current_function_decl_ != nullptr) {
1744 m.set_return_type(
1745 context().current_function_decl_->getReturnType().getAsString());
1746 }
1747 else if (context().current_function_template_decl_ != nullptr) {
1748 m.set_return_type(context()
1749 .current_function_template_decl_->getAsFunction()
1750 ->getReturnType()
1751 .getAsString());
1752 }
1753 else if (context().current_method_decl_ != nullptr) {
1754 m.set_return_type(
1755 context().current_method_decl_->getReturnType().getAsString());
1756 }
1757 else if (context().current_objc_method_decl_ != nullptr) {
1758 m.set_return_type(
1759 context().current_objc_method_decl_->getReturnType().getAsString());
1760 }
1761
1762 // We can skip the ID of the return activity here, we'll just add it during
1763 // diagram generation
1764 if (m.from().value() > 0) {
1765 if (raw_expr_comment != nullptr)
1766 m.set_comment(raw_expr_comment->getBeginLoc().getHashValue(),
1767 stripped_comment);
1768
1770
1771 diagram().add_active_participant(m.from());
1772
1773 LOG_DBG("Found return call {} from {} [{}] to {} [{}] ",
1774 m.message_name(), m.from(), m.from(), m.to(), m.to());
1775
1776 push_message(stmt, std::move(m));
1777 }
1778
1779 return true;
1780}

◆ VisitTypeAliasTemplateDecl()

bool clanguml::class_diagram::visitor::translation_unit_visitor::VisitTypeAliasTemplateDecl ( clang::TypeAliasTemplateDecl *  cls)
virtual

Definition at line 254 of file translation_unit_visitor.cc.

256{
257 if (!should_include(cls))
258 return true;
259
260 LOG_DBG("= Visiting template type alias declaration {} at {}",
261 cls->getQualifiedNameAsString(),
262 cls->getLocation().printToString(source_manager()));
263
264 const auto *template_type_specialization_ptr =
265 cls->getTemplatedDecl()
266 ->getUnderlyingType()
267 ->getAs<clang::TemplateSpecializationType>();
268
269 if (template_type_specialization_ptr == nullptr)
270 return true;
271
272 auto template_specialization_ptr =
273 std::make_unique<class_>(config().using_namespace());
274 tbuilder().build_from_template_specialization_type(*cls->getTemplatedDecl(),
275 *template_specialization_ptr, cls, *template_type_specialization_ptr);
276
277 template_specialization_ptr->is_template(true);
278
279 if (diagram().should_include(*template_specialization_ptr)) {
280 const auto name = template_specialization_ptr->full_name(true);
281 const auto id = template_specialization_ptr->id();
282
283 LOG_DBG("Adding class {} with id {}", name, id);
284
285 set_source_location(*cls, *template_specialization_ptr);
286 set_owning_module(*cls, *template_specialization_ptr);
287
288 add_class(std::move(template_specialization_ptr));
289 }
290
291 return true;
292}

◆ VisitTypedefDecl()

bool clanguml::class_diagram::visitor::translation_unit_visitor::VisitTypedefDecl ( clang::TypedefDecl *  decl)
virtual

Definition at line 106 of file translation_unit_visitor.cc.

107{
108 if (const auto *enm = common::get_typedef_enum_decl(decl)) {
109 // Associate a typedef with an anonymous declaration so that it can
110 // be later used to assign proper name to enum
111 if (!should_include(enm))
112 return true;
113
114 LOG_DBG("= Visiting typedef enum declaration {} at {}",
115 enm->getQualifiedNameAsString(),
116 enm->getLocation().printToString(source_manager()));
117
118 auto e_ptr = create_declaration(enm, decl);
119
120 if (!e_ptr)
121 return true;
122
123 if (enm->isComplete()) {
124 process_declaration(*enm, *e_ptr);
125 }
126
127 if (e_ptr && diagram().should_include(*e_ptr))
128 add_enum(std::move(e_ptr));
129 }
130
131 return true; // Continue traversing
132}