0.6.3
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 782 of file translation_unit_visitor.cc.

783{
784 if (!config().include_system_headers() &&
785 source_manager().isInSystemHeader(expr->getSourceRange().getBegin()))
786 return true;
787
788 LOG_TRACE("Entering call expression at {}",
789 expr->getBeginLoc().printToString(source_manager()));
790
791 context().enter_callexpr(expr);
792
793 RecursiveASTVisitor<translation_unit_visitor>::TraverseCallExpr(expr);
794
795 LOG_TRACE("Leaving call expression at {}",
796 expr->getBeginLoc().printToString(source_manager()));
797
799
801
802 return true;
803}

◆ TraverseCaseStmt()

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

Definition at line 1265 of file translation_unit_visitor.cc.

1266{
1268
1269 const auto current_caller_id = context().caller_id();
1270
1271 if ((current_caller_id.value() != 0) &&
1272 (context().current_switchstmt() != nullptr)) {
1273 model::message m{message_t::kCase, current_caller_id};
1274 m.set_message_name(common::to_string(stmt->getLHS()));
1275 diagram().add_case_stmt_message(std::move(m));
1276 }
1277
1278 RecursiveASTVisitor<translation_unit_visitor>::TraverseCaseStmt(stmt);
1279
1280 return true;
1281}

◆ TraverseCoawaitExpr()

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

Definition at line 736 of file translation_unit_visitor.cc.

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

◆ TraverseCompoundStmt()

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

Definition at line 929 of file translation_unit_visitor.cc.

930{
935
936 if (stmt == nullptr)
937 return true;
938
939 const auto *current_ifstmt = context().current_ifstmt();
940 const auto *current_elseifstmt =
941 current_ifstmt != nullptr ? context().current_elseifstmt() : nullptr;
942
943 //
944 // Add final else block (not else if)
945 //
946 if (current_elseifstmt != nullptr) {
947 if (current_elseifstmt->getElse() == stmt) {
948 const auto current_caller_id = context().caller_id();
949
950 if (current_caller_id.value() != 0) {
951 model::message m{message_t::kElse, current_caller_id};
952 set_source_location(*stmt, m);
953 diagram().add_message(std::move(m));
954 }
955 }
956 }
957 else if (current_ifstmt != nullptr) {
958 if (current_ifstmt->getElse() == stmt) {
959 const auto current_caller_id = context().caller_id();
960
961 if (current_caller_id.value() != 0) {
962 model::message m{message_t::kElse, current_caller_id};
963 set_source_location(*stmt, m);
964 diagram().add_message(std::move(m));
965 }
966 }
967 }
968
969 RecursiveASTVisitor<translation_unit_visitor>::TraverseCompoundStmt(stmt);
970
971 return true;
972}

◆ TraverseConceptDecl()

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

Definition at line 494 of file translation_unit_visitor.cc.

495{
496 if (!should_include(cpt))
497 return true;
498
499 LOG_DBG("= Visiting concept (isType: {}) declaration {} at {}",
500 cpt->isTypeConcept(), cpt->getQualifiedNameAsString(),
501 cpt->getLocation().printToString(source_manager()));
502
503 auto concept_model = create_concept_declaration(cpt);
504
505 if (!concept_model)
506 return true;
507
508 const auto concept_id = concept_model->id();
509
510 id_mapper().add(cpt->getID(), concept_id);
511
512 tbuilder().build_from_template_declaration(*concept_model, *cpt);
513
514 constexpr auto kMaxConstraintCount = 24U;
515
516#if LLVM_VERSION_MAJOR < 21
517 llvm::SmallVector<const clang::Expr *, kMaxConstraintCount> constraints{};
518 if (cpt->hasAssociatedConstraints()) {
519 cpt->getAssociatedConstraints(constraints);
520 }
521
522 for (const auto *expr : constraints) {
524 }
525#else
526 llvm::SmallVector<clang::AssociatedConstraint, kMaxConstraintCount>
527 constraints{};
528 if (cpt->hasAssociatedConstraints()) {
529 cpt->getAssociatedConstraints(constraints);
530 }
531 for (const auto &constraint : constraints) {
533 *concept_model, constraint.ConstraintExpr);
534 }
535#endif
536
537 if (cpt->getConstraintExpr() != nullptr) {
539 cpt, cpt->getConstraintExpr(), *concept_model);
540
542 *concept_model, cpt->getConstraintExpr());
543 }
544
545 if (diagram().should_include(*concept_model)) {
546 LOG_DBG("Adding concept {} with id {}", concept_model->full_name(false),
547 concept_model->id());
548
549 add_concept(std::move(concept_model));
550 }
551 else {
552 LOG_DBG("Skipping concept {} with id {}",
553 concept_model->full_name(true), concept_model->id());
554 }
555
556 return true;
557}

◆ TraverseConditionalOperator()

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

Definition at line 1301 of file translation_unit_visitor.cc.

1303{
1305
1306 const auto current_caller_id = context().caller_id();
1307
1308 std::string condition_text;
1309 if (config().generate_condition_statements())
1310 condition_text = common::get_condition_text(source_manager(), stmt);
1311
1312 if (current_caller_id.value() != 0) {
1314 model::message m{message_t::kConditional, current_caller_id};
1315 set_source_location(*stmt, m);
1316 m.condition_text(condition_text);
1317 m.set_comment(get_expression_comment(source_manager(),
1318 *context().get_ast_context(), current_caller_id, stmt));
1319 diagram().add_block_message(std::move(m));
1320 }
1321
1322 RecursiveASTVisitor<translation_unit_visitor>::TraverseStmt(
1323 stmt->getCond());
1324
1325 RecursiveASTVisitor<translation_unit_visitor>::TraverseStmt(
1326 stmt->getTrueExpr());
1327
1328 if (current_caller_id.value() != 0) {
1329 model::message m{message_t::kConditionalElse, current_caller_id};
1330 set_source_location(*stmt, m);
1331 diagram().add_message(std::move(m));
1332 }
1333
1334 RecursiveASTVisitor<translation_unit_visitor>::TraverseStmt(
1335 stmt->getFalseExpr());
1336
1337 if (current_caller_id.value() != 0) {
1339 diagram().end_block_message(
1340 {message_t::kConditionalEnd, current_caller_id},
1341 message_t::kConditional);
1342 }
1343
1344 return true;
1345}

◆ TraverseCoreturnStmt()

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

Definition at line 759 of file translation_unit_visitor.cc.

760{
761 if (!config().include_system_headers() &&
762 source_manager().isInSystemHeader(stmt->getSourceRange().getBegin()))
763 return true;
764
765 LOG_TRACE("Entering co_return statement at {}",
766 stmt->getBeginLoc().printToString(source_manager()));
767
768 context().enter_callexpr(stmt);
769
770 RecursiveASTVisitor<translation_unit_visitor>::TraverseCoreturnStmt(stmt);
771
772 LOG_TRACE("Leaving co_return statement at {}",
773 stmt->getBeginLoc().printToString(source_manager()));
774
776
778
779 return true;
780}

◆ TraverseCoyieldExpr()

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

Definition at line 713 of file translation_unit_visitor.cc.

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

◆ TraverseCUDAKernelCallExpr()

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

Definition at line 805 of file translation_unit_visitor.cc.

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

◆ TraverseCXXCatchStmt()

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

Definition at line 1177 of file translation_unit_visitor.cc.

1178{
1182
1183 const auto current_caller_id = context().caller_id();
1184
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 = "...";
1190 else
1191 caught_type = common::to_string(
1192 stmt->getCaughtType(), *context().get_ast_context());
1193
1194 model::message m{message_t::kCatch, current_caller_id};
1195 m.set_message_name(std::move(caught_type));
1196 diagram().add_message(std::move(m));
1197 }
1198
1199 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXCatchStmt(stmt);
1200
1201 return true;
1202}

◆ TraverseCXXConstructExpr()

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

Definition at line 887 of file translation_unit_visitor.cc.

889{
890 LOG_TRACE("Entering cxx construct call expression at {}",
891 expr->getBeginLoc().printToString(source_manager()));
892
893 context().enter_callexpr(expr);
894
895 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXConstructExpr(
896 expr);
897
899
900 LOG_TRACE("Leaving cxx construct call expression at {}",
901 expr->getBeginLoc().printToString(source_manager()));
902
904
906
907 return true;
908}

◆ TraverseCXXForRangeStmt()

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

Definition at line 1204 of file translation_unit_visitor.cc.

1206{
1210
1211 const auto current_caller_id = context().caller_id();
1212
1213 std::string condition_text;
1214 if (config().generate_condition_statements())
1215 condition_text = common::get_condition_text(source_manager(), stmt);
1216
1217 if (current_caller_id.value() != 0) {
1218 context().enter_loopstmt(stmt);
1219 message m{message_t::kFor, current_caller_id};
1220 set_source_location(*stmt, m);
1221 m.condition_text(condition_text);
1222 m.set_comment(get_expression_comment(source_manager(),
1223 *context().get_ast_context(), current_caller_id, stmt));
1224 diagram().add_block_message(std::move(m));
1225 }
1226
1227 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXForRangeStmt(
1228 stmt);
1229
1230 if (current_caller_id.value() != 0) {
1231 diagram().end_block_message(
1232 {message_t::kForEnd, current_caller_id}, message_t::kFor);
1234 }
1235
1236 return true;
1237}

◆ TraverseCXXMemberCallExpr()

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

Definition at line 829 of file translation_unit_visitor.cc.

831{
832 if (!config().include_system_headers() &&
833 source_manager().isInSystemHeader(expr->getSourceRange().getBegin()))
834 return true;
835
836 LOG_TRACE("Entering member call expression at {}",
837 expr->getBeginLoc().printToString(source_manager()));
838
839 context().enter_callexpr(expr);
840
841 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXMemberCallExpr(
842 expr);
843
844 LOG_TRACE("Leaving member call expression at {}",
845 expr->getBeginLoc().printToString(source_manager()));
846
848
850
851 return true;
852}

◆ TraverseCXXMethodDecl()

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

Definition at line 360 of file translation_unit_visitor.cc.

362{
363 // We need to backup the context, since other methods or functions can
364 // be traversed during this traversal (e.g. template function/method
365 // specializations)
366 auto context_backup = context();
367
368 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXMethodDecl(
369 declaration);
370
371 call_expression_context_ = context_backup;
372
373 return true;
374}

◆ TraverseCXXOperatorCallExpr()

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

Definition at line 854 of file translation_unit_visitor.cc.

856{
857 context().enter_callexpr(expr);
858
859 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXOperatorCallExpr(
860 expr);
861
863
865
866 return true;
867}

◆ TraverseCXXRecordDecl()

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

Definition at line 142 of file translation_unit_visitor.cc.

144{
145 auto context_backup = context();
146
147 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXRecordDecl(
148 declaration);
149
150 call_expression_context_ = context_backup;
151
152 return true;
153}

◆ TraverseCXXTemporaryObjectExpr()

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

Definition at line 869 of file translation_unit_visitor.cc.

871{
872 context().enter_callexpr(expr);
873
874 RecursiveASTVisitor<
876
878 clang::dyn_cast<clang::CXXConstructExpr>(expr));
879
881
883
884 return true;
885}

◆ TraverseCXXTryStmt()

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

Definition at line 1149 of file translation_unit_visitor.cc.

1150{
1154
1155 const auto current_caller_id = context().caller_id();
1156
1157 if (current_caller_id.value() != 0) {
1158 context().enter_trystmt(stmt);
1159 message m{message_t::kTry, current_caller_id};
1160 set_source_location(*stmt, m);
1161 m.set_comment(get_expression_comment(source_manager(),
1162 *context().get_ast_context(), current_caller_id, stmt));
1163 diagram().add_block_message(std::move(m));
1164 }
1165
1166 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXTryStmt(stmt);
1167
1168 if (current_caller_id.value() != 0) {
1169 diagram().end_block_message(
1170 {message_t::kTryEnd, current_caller_id}, message_t::kTry);
1172 }
1173
1174 return true;
1175}

◆ TraverseDefaultStmt()

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

Definition at line 1283 of file translation_unit_visitor.cc.

1284{
1286
1287 const auto current_caller_id = context().caller_id();
1288
1289 if ((current_caller_id.value() != 0) &&
1290 (context().current_switchstmt() != nullptr)) {
1291 model::message m{message_t::kCase, current_caller_id};
1292 m.set_message_name("default");
1293 diagram().add_case_stmt_message(std::move(m));
1294 }
1295
1296 RecursiveASTVisitor<translation_unit_visitor>::TraverseDefaultStmt(stmt);
1297
1298 return true;
1299}

◆ TraverseDoStmt()

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

Definition at line 1081 of file translation_unit_visitor.cc.

1082{
1086
1087 const auto current_caller_id = context().caller_id();
1088
1089 std::string condition_text;
1090 if (config().generate_condition_statements())
1091 condition_text = common::get_condition_text(source_manager(), stmt);
1092
1093 if (current_caller_id.value() != 0) {
1094 context().enter_loopstmt(stmt);
1095 message m{message_t::kDo, current_caller_id};
1096 set_source_location(*stmt, m);
1097 m.condition_text(condition_text);
1098 m.set_comment(get_expression_comment(source_manager(),
1099 *context().get_ast_context(), current_caller_id, stmt));
1100 diagram().add_block_message(std::move(m));
1101 }
1102
1103 RecursiveASTVisitor<translation_unit_visitor>::TraverseDoStmt(stmt);
1104
1105 if (current_caller_id.value() != 0) {
1106 diagram().end_block_message(
1107 {message_t::kDoEnd, current_caller_id}, message_t::kDo);
1109 }
1110
1111 return true;
1112}

◆ TraverseForStmt()

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

Definition at line 1114 of file translation_unit_visitor.cc.

1115{
1119
1120 const auto current_caller_id = context().caller_id();
1121
1122 std::string condition_text;
1123 if (config().generate_condition_statements())
1124 condition_text = common::get_condition_text(source_manager(), stmt);
1125
1126 if (current_caller_id.value() != 0) {
1127 context().enter_loopstmt(stmt);
1128 message m{message_t::kFor, current_caller_id};
1129 set_source_location(*stmt, m);
1130 m.condition_text(condition_text);
1131
1132 m.set_comment(get_expression_comment(source_manager(),
1133 *context().get_ast_context(), current_caller_id, stmt));
1134
1135 diagram().add_block_message(std::move(m));
1136 }
1137
1138 RecursiveASTVisitor<translation_unit_visitor>::TraverseForStmt(stmt);
1139
1140 if (current_caller_id.value() != 0) {
1141 diagram().end_block_message(
1142 {message_t::kForEnd, current_caller_id}, message_t::kFor);
1144 }
1145
1146 return true;
1147}

◆ TraverseFunctionDecl()

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

Definition at line 438 of file translation_unit_visitor.cc.

440{
441 // We need to backup the context, since other methods or functions can
442 // be traversed during this traversal (e.g. template function/method
443 // specializations)
444 auto context_backup = context();
445
446 RecursiveASTVisitor<translation_unit_visitor>::TraverseFunctionDecl(
447 declaration);
448
449 call_expression_context_ = context_backup;
450
451 return true;
452}

◆ TraverseFunctionTemplateDecl()

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

Definition at line 532 of file translation_unit_visitor.cc.

534{
535 // We need to backup the context, since other methods or functions can
536 // be traversed during this traversal (e.g. template function/method
537 // specializations)
538 auto context_backup = context();
539
540 RecursiveASTVisitor<translation_unit_visitor>::TraverseFunctionTemplateDecl(
541 declaration);
542
543 call_expression_context_ = context_backup;
544
545 return true;
546}

◆ TraverseIfStmt()

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

Definition at line 974 of file translation_unit_visitor.cc.

975{
980
981 bool elseif_block{false};
982
983 const auto current_caller_id = context().caller_id();
984 const auto *current_ifstmt = context().current_ifstmt();
985 const auto *current_elseifstmt =
986 current_ifstmt != nullptr ? context().current_elseifstmt() : nullptr;
987
988 std::string condition_text;
989 if (config().generate_condition_statements())
990 condition_text = common::get_condition_text(source_manager(), stmt);
991
992 // Check if this is a beginning of a new if statement, or an
993 // else if condition of the current if statement
994 auto child_stmt_compare = [stmt](auto *child_stmt) {
995 return child_stmt == stmt;
996 };
997
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);
1006
1007 if ((current_caller_id.value() != 0) && !stmt->isConstexpr()) {
1008 if (elseif_block) {
1009 context().enter_elseifstmt(stmt);
1010
1011 message m{message_t::kElseIf, current_caller_id};
1012 set_source_location(*stmt, m);
1013 m.condition_text(condition_text);
1014 m.set_comment(get_expression_comment(source_manager(),
1015 *context().get_ast_context(), current_caller_id, stmt));
1016 diagram().add_block_message(std::move(m));
1017 }
1018 else {
1019 context().enter_ifstmt(stmt);
1020 LOG_TRACE("Entered if statement at {}",
1021 stmt->getBeginLoc().printToString(source_manager()));
1022
1023 message m{message_t::kIf, current_caller_id};
1024 set_source_location(*stmt, m);
1025 m.condition_text(condition_text);
1026 m.set_comment(get_expression_comment(source_manager(),
1027 *context().get_ast_context(), current_caller_id, stmt));
1028 diagram().add_block_message(std::move(m));
1029 }
1030 }
1031
1032 RecursiveASTVisitor<translation_unit_visitor>::TraverseIfStmt(stmt);
1033
1034 if ((current_caller_id.value() != 0) && !stmt->isConstexpr()) {
1035 if (!elseif_block) {
1036 diagram().end_block_message(
1037 {message_t::kIfEnd, current_caller_id}, message_t::kIf);
1039 }
1040 }
1041
1042 return true;
1043}

◆ TraverseLambdaExpr()

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

Definition at line 674 of file translation_unit_visitor.cc.

675{
676 auto context_backup = context();
677
678 RecursiveASTVisitor<translation_unit_visitor>::TraverseLambdaExpr(expr);
679
680 // lambda context is entered inside the visitor
682
683 call_expression_context_ = context_backup;
684
685 return true;
686}

◆ TraverseObjCMessageExpr()

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

Definition at line 688 of file translation_unit_visitor.cc.

690{
691 if (!config().include_system_headers() &&
692 source_manager().isInSystemHeader(expr->getSourceRange().getBegin()))
693 return true;
694
695 LOG_TRACE("Entering ObjC message expression at {}",
696 expr->getBeginLoc().printToString(source_manager()));
697
698 context().enter_callexpr(expr);
699
700 RecursiveASTVisitor<translation_unit_visitor>::TraverseObjCMessageExpr(
701 expr);
702
703 LOG_TRACE("Leaving ObjC message expression at {}",
704 expr->getBeginLoc().printToString(source_manager()));
705
707
709
710 return true;
711}

◆ TraverseObjCMethodDecl()

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

Definition at line 305 of file translation_unit_visitor.cc.

307{
308 // We need to backup the context, since other methods or functions can
309 // be traversed during this traversal (e.g. template function/method
310 // specializations)
311 auto context_backup = context();
312
313 RecursiveASTVisitor<translation_unit_visitor>::TraverseObjCMethodDecl(
314 declaration);
315
316 call_expression_context_ = context_backup;
317
318 return true;
319}

◆ TraverseReturnStmt()

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

Definition at line 910 of file translation_unit_visitor.cc.

911{
912 LOG_TRACE("Entering return statement at {}",
913 stmt->getBeginLoc().printToString(source_manager()));
914
915 context().enter_callexpr(stmt);
916
917 RecursiveASTVisitor<translation_unit_visitor>::TraverseReturnStmt(stmt);
918
919 LOG_TRACE("Leaving return statement at {}",
920 stmt->getBeginLoc().printToString(source_manager()));
921
923
925
926 return true;
927}

◆ TraverseSwitchStmt()

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

Definition at line 1239 of file translation_unit_visitor.cc.

1240{
1242
1243 const auto current_caller_id = context().caller_id();
1244
1245 if (current_caller_id.value() != 0) {
1246 context().enter_switchstmt(stmt);
1247 model::message m{message_t::kSwitch, current_caller_id};
1248 set_source_location(*stmt, m);
1249 m.set_comment(get_expression_comment(source_manager(),
1250 *context().get_ast_context(), current_caller_id, stmt));
1251 diagram().add_block_message(std::move(m));
1252 }
1253
1254 RecursiveASTVisitor<translation_unit_visitor>::TraverseSwitchStmt(stmt);
1255
1256 if (current_caller_id.value() != 0) {
1258 diagram().end_block_message(
1259 {message_t::kSwitchEnd, current_caller_id}, message_t::kSwitch);
1260 }
1261
1262 return true;
1263}

◆ TraverseVarDecl()

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

Definition at line 1925 of file translation_unit_visitor.cc.

1926{
1927 if (decl->isStaticLocal())
1929
1930 RecursiveASTVisitor::TraverseVarDecl(decl);
1931
1932 if (decl->isStaticLocal())
1934
1935 return true;
1936}

◆ TraverseWhileStmt()

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

Definition at line 1045 of file translation_unit_visitor.cc.

1046{
1050
1051 const auto current_caller_id = context().caller_id();
1052
1053 std::string condition_text;
1054 if (config().generate_condition_statements())
1055 condition_text = common::get_condition_text(source_manager(), stmt);
1056
1057 if (current_caller_id.value() != 0) {
1058 LOG_TRACE("Entering while statement at {}",
1059 stmt->getBeginLoc().printToString(source_manager()));
1060
1061 context().enter_loopstmt(stmt);
1062 message m{message_t::kWhile, current_caller_id};
1063 set_source_location(*stmt, m);
1064 m.condition_text(condition_text);
1065 m.set_comment(get_expression_comment(source_manager(),
1066 *context().get_ast_context(), current_caller_id, stmt));
1067 diagram().add_block_message(std::move(m));
1068 }
1069
1070 RecursiveASTVisitor<translation_unit_visitor>::TraverseWhileStmt(stmt);
1071
1072 if (current_caller_id.value() != 0) {
1073 diagram().end_block_message(
1074 {message_t::kWhileEnd, current_caller_id}, message_t::kWhile);
1076 }
1077
1078 return true;
1079}

◆ VisitCallExpr()

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

Definition at line 1436 of file translation_unit_visitor.cc.

1437{
1443
1444 if (!context().valid() || context().get_ast_context() == nullptr)
1445 return true;
1446
1447 LOG_TRACE("Visiting call expression at {} [caller_id = {}]",
1448 expr->getBeginLoc().printToString(source_manager()),
1449 context().caller_id());
1450
1451 message m{message_t::kCall, context().caller_id()};
1452
1453 m.in_static_declaration_context(within_static_variable_declaration_ > 0);
1454
1455 set_source_location(*expr, m);
1456
1457 const auto *raw_expr_comment = clanguml::common::get_expression_raw_comment(
1458 source_manager(), *context().get_ast_context(), expr);
1459 const auto stripped_comment = process_comment(
1460 raw_expr_comment, context().get_ast_context()->getDiagnostics(), m);
1461
1462 if (m.skip())
1463 return true;
1464
1465 auto generated_message_from_comment = generate_message_from_comment(m);
1466
1467 if (!generated_message_from_comment && !should_include(expr)) {
1468 LOG_DBG("Skipping call expression due to filter at: {}",
1469 expr->getBeginLoc().printToString(source_manager()));
1470
1471 processed_comments().erase(raw_expr_comment);
1472 return true;
1473 }
1474
1475 if (context().is_expr_in_current_control_statement_condition(expr)) {
1476 m.set_message_scope(common::model::message_scope_t::kCondition);
1477 }
1478
1479 auto result = process_callee(expr, m, generated_message_from_comment);
1480
1481 if (!result)
1482 return true;
1483
1484 // Add message to diagram
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(),
1488 stripped_comment);
1489
1491
1492 diagram().add_active_participant(m.from());
1493 diagram().add_active_participant(m.to());
1494
1495 LOG_DBG("Found call {} from {} [{}] to {} [{}] ", m.message_name(),
1496 m.from(), m.from(), m.to(), m.to());
1497
1498 push_message(expr, std::move(m));
1499 }
1500
1501 return true;
1502}

◆ 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
325#if LLVM_VERSION_MAJOR < 21
326 llvm::SmallVector<const clang::Expr *, kMaxConstraintCount> constraints{};
327 if (cls->hasAssociatedConstraints()) {
328 cls->getAssociatedConstraints(constraints);
329 }
330 for (const auto *expr : constraints) {
332 }
333#else
334 llvm::SmallVector<clang::AssociatedConstraint, kMaxConstraintCount>
335 constraints{};
336 if (cls->hasAssociatedConstraints()) {
337 cls->getAssociatedConstraints(constraints);
338 }
339 for (const auto &constraint : constraints) {
341 *c_ptr, constraint.ConstraintExpr);
342 }
343#endif
344
345 return add_or_update(cls->getTemplatedDecl(), std::move(c_ptr));
346}

◆ 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 212 of file translation_unit_visitor.cc.

214{
215 if (!should_include(declaration))
216 return true;
217
218 LOG_TRACE("Visiting class template declaration {} at {} [{}]",
219 declaration->getQualifiedNameAsString(),
220 declaration->getLocation().printToString(source_manager()),
221 (void *)declaration);
222
223 auto class_model_ptr = create_class_model(declaration->getTemplatedDecl());
224
225 if (!class_model_ptr)
226 return true;
227
228 tbuilder().build_from_template_declaration(*class_model_ptr, *declaration);
229
230 const auto class_full_name = class_model_ptr->full_name(false);
231 const auto id = common::to_id(class_full_name);
232
233 // Override the id with the template id, for now we don't care about the
234 // underlying templated class id
235 class_model_ptr->set_id(id);
236
237 set_unique_id(declaration->getID(), id);
238
239 if (!declaration->getTemplatedDecl()->isCompleteDefinition()) {
240 forward_declarations_.emplace(id, std::move(class_model_ptr));
241 return true;
242 }
243 forward_declarations_.erase(id);
244
245 if (diagram().should_include(*class_model_ptr)) {
246 LOG_DBG("Adding class template participant {} with id {}",
247 class_full_name, id);
248
250 context().update(declaration);
251
252 diagram().add_participant(std::move(class_model_ptr));
253 }
254
255 return true;
256}

◆ 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 258 of file translation_unit_visitor.cc.

260{
261 if (!should_include(declaration))
262 return true;
263
264 LOG_TRACE("Visiting template specialization declaration {} at {}",
265 declaration->getQualifiedNameAsString(),
266 declaration->getLocation().printToString(source_manager()));
267
268 if (declaration->isLocalClass() != nullptr)
269 return true;
270
271 auto template_specialization_ptr =
273
274 if (!template_specialization_ptr)
275 return true;
276
277 const auto class_full_name = template_specialization_ptr->full_name(false);
278 const auto id = common::to_id(class_full_name);
279
280 template_specialization_ptr->set_id(id);
281
282 set_unique_id(declaration->getID(), id);
283
284 if (!declaration->isCompleteDefinition()) {
285 forward_declarations_.emplace(
286 id, std::move(template_specialization_ptr));
287 return true;
288 }
289 forward_declarations_.erase(id);
290
291 if (diagram().should_include(*template_specialization_ptr)) {
292 LOG_DBG(
293 "Adding class template specialization participant {} with id {}",
294 class_full_name, id);
295
297 context().update(declaration);
298
299 diagram().add_participant(std::move(template_specialization_ptr));
300 }
301
302 return true;
303}

◆ VisitCoawaitExpr()

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

Definition at line 1607 of file translation_unit_visitor.cc.

1608{
1614
1615 if (!context().valid() || context().get_ast_context() == nullptr)
1616 return true;
1617
1618 LOG_TRACE("Visiting co_await expression at {} [caller_id = {}]",
1619 expr->getBeginLoc().printToString(source_manager()),
1620 context().caller_id());
1621
1622 message m{message_t::kCoAwait, context().caller_id()};
1623 set_source_location(*expr, m);
1624
1625 if (expr->getOperand() != nullptr) {
1626 std::string message_name = common::to_string(expr->getOperand());
1627 m.set_message_name(util::condense_whitespace(message_name));
1628 }
1629
1630 const auto *raw_expr_comment = clanguml::common::get_expression_raw_comment(
1631 source_manager(), *context().get_ast_context(), expr);
1632 const auto stripped_comment = process_comment(
1633 raw_expr_comment, context().get_ast_context()->getDiagnostics(), m);
1634
1635 if (m.skip())
1636 return true;
1637
1638 auto generated_message_from_comment = generate_message_from_comment(m);
1639
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: {}",
1644 expr->getBeginLoc().printToString(source_manager()));
1645
1646 processed_comments().erase(raw_expr_comment);
1647 return true;
1648 }
1649
1650 if (context().is_expr_in_current_control_statement_condition(expr)) {
1651 m.set_message_scope(common::model::message_scope_t::kCondition);
1652 }
1653
1654 auto result = process_callee(
1655 clang::dyn_cast_or_null<clang::CallExpr>(expr->getResumeExpr()), m,
1656 generated_message_from_comment);
1657
1658 if (!result)
1659 return true;
1660
1661 // We can skip the ID of the return activity here, we'll just add it during
1662 // diagram generation
1663 if (m.from().value() > 0) {
1664 if (raw_expr_comment != nullptr)
1665 m.set_comment(raw_expr_comment->getBeginLoc().getHashValue(),
1666 stripped_comment);
1667
1669
1670 diagram().add_active_participant(m.from());
1671
1672 LOG_DBG("Found return call {} from {} [{}] to {} [{}] ",
1673 m.message_name(), m.from(), m.from(), m.to(), m.to());
1674
1675 push_message(expr, std::move(m));
1676 }
1677
1678 return true;
1679}

◆ VisitCoreturnStmt()

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

Definition at line 1827 of file translation_unit_visitor.cc.

1828{
1834
1835 if (!context().valid() || context().get_ast_context() == nullptr)
1836 return true;
1837
1838 LOG_TRACE("Visiting co_return statement at {}",
1839 stmt->getBeginLoc().printToString(source_manager()));
1840
1841 message m{message_t::kCoReturn, context().caller_id()};
1842
1843 set_source_location(*stmt, m);
1844
1845 const auto *raw_expr_comment = clanguml::common::get_expression_raw_comment(
1846 source_manager(), *context().get_ast_context(), stmt);
1847 const auto stripped_comment = process_comment(
1848 raw_expr_comment, context().get_ast_context()->getDiagnostics(), m);
1849
1850 if (m.skip())
1851 return true;
1852
1853 if (stmt->getOperand() != nullptr) {
1854 std::string message_name = common::to_string(stmt->getOperand());
1855 m.set_message_name(util::condense_whitespace(message_name));
1856 }
1857
1858 if (context().current_function_decl_ != nullptr) {
1859 m.set_return_type(
1860 context().current_function_decl_->getReturnType().getAsString());
1861 }
1862 else if (context().current_function_template_decl_ != nullptr) {
1863 m.set_return_type(context()
1864 .current_function_template_decl_->getAsFunction()
1865 ->getReturnType()
1866 .getAsString());
1867 }
1868 else if (context().current_method_decl_ != nullptr) {
1869 m.set_return_type(
1870 context().current_method_decl_->getReturnType().getAsString());
1871 }
1872 else if (context().current_objc_method_decl_ != nullptr) {
1873 m.set_return_type(
1874 context().current_objc_method_decl_->getReturnType().getAsString());
1875 }
1876
1877 // We can skip the ID of the return activity here, we'll just add it during
1878 // diagram generation
1879 if (m.from().value() > 0) {
1880 if (raw_expr_comment != nullptr)
1881 m.set_comment(raw_expr_comment->getBeginLoc().getHashValue(),
1882 stripped_comment);
1883
1885
1886 diagram().add_active_participant(m.from());
1887
1888 LOG_DBG("Found co_return call {} from {} [{}] to {} [{}] ",
1889 m.message_name(), m.from(), m.from(), m.to(), m.to());
1890
1891 push_message(stmt, std::move(m));
1892 }
1893
1894 return true;
1895}

◆ VisitCoyieldExpr()

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

Definition at line 1761 of file translation_unit_visitor.cc.

1762{
1768
1769 if (!context().valid() || context().get_ast_context() == nullptr)
1770 return true;
1771
1772 LOG_TRACE("Visiting co_yield expression at {}",
1773 expr->getBeginLoc().printToString(source_manager()));
1774
1775 message m{message_t::kCoYield, context().caller_id()};
1776
1777 set_source_location(*expr, m);
1778
1779 const auto *raw_expr_comment = clanguml::common::get_expression_raw_comment(
1780 source_manager(), *context().get_ast_context(), expr);
1781 const auto stripped_comment = process_comment(
1782 raw_expr_comment, context().get_ast_context()->getDiagnostics(), m);
1783
1784 if (m.skip())
1785 return true;
1786
1787 if (expr->getOperand() != nullptr) {
1788 std::string message_name = common::to_string(expr->getOperand());
1789 m.set_message_name(util::condense_whitespace(message_name));
1790 }
1791
1792 if (context().current_function_decl_ != nullptr) {
1793 m.set_return_type(
1794 context().current_function_decl_->getReturnType().getAsString());
1795 }
1796 else if (context().current_function_template_decl_ != nullptr) {
1797 m.set_return_type(context()
1798 .current_function_template_decl_->getAsFunction()
1799 ->getReturnType()
1800 .getAsString());
1801 }
1802 else if (context().current_method_decl_ != nullptr) {
1803 m.set_return_type(
1804 context().current_method_decl_->getReturnType().getAsString());
1805 }
1806
1807 // We can skip the ID of the return activity here, we'll just add it during
1808 // diagram generation
1809 if (m.from().value() > 0) {
1810 if (raw_expr_comment != nullptr)
1811 m.set_comment(raw_expr_comment->getBeginLoc().getHashValue(),
1812 stripped_comment);
1813
1815
1816 diagram().add_active_participant(m.from());
1817
1818 LOG_DBG("Found co_yield call {} from {} [{}] to {} [{}] ",
1819 m.message_name(), m.from(), m.from(), m.to(), m.to());
1820
1821 push_message(expr, std::move(m));
1822 }
1823
1824 return true;
1825}

◆ VisitCXXConstructExpr()

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

Definition at line 1938 of file translation_unit_visitor.cc.

1940{
1946
1947 if (expr == nullptr)
1948 return true;
1949
1950 if (const auto *ctor = expr->getConstructor();
1951 ctor != nullptr && !should_include(ctor))
1952 return true;
1953
1954 LOG_TRACE("Visiting cxx construct expression at {} [caller_id = {}]",
1955 expr->getBeginLoc().printToString(source_manager()),
1956 context().caller_id());
1957
1958 message m{message_t::kCall, context().caller_id()};
1959
1960 m.in_static_declaration_context(within_static_variable_declaration_ > 0);
1961
1962 set_source_location(*expr, m);
1963
1964 if (context().is_expr_in_current_control_statement_condition(expr)) {
1965 m.set_message_scope(common::model::message_scope_t::kCondition);
1966 }
1967
1968 if (!process_construct_expression(m, expr))
1969 return true;
1970
1971 if (m.from().value() > 0 && m.to().value() > 0) {
1973
1974 diagram().add_active_participant(m.from());
1975 diagram().add_active_participant(m.to());
1976
1977 LOG_DBG("Found constructor call {} from {} [{}] to {} [{}] ",
1978 m.message_name(), m.from(), m.from(), m.to(), m.to());
1979
1980 push_message(expr, std::move(m));
1981 }
1982
1983 return true;
1984}

◆ VisitCXXMethodDecl()

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

Definition at line 376 of file translation_unit_visitor.cc.

378{
379 if (!should_include(declaration))
380 return true;
381
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 "
389 "declaration");
390
391 return VisitCXXMethodDecl(method_definition);
392 }
393 }
394 }
395
396 LOG_TRACE("Visiting method {} in class {} [{}]",
397 declaration->getQualifiedNameAsString(),
398 declaration->getParent()->getQualifiedNameAsString(),
399 (void *)declaration->getParent());
400
401 context().update(declaration);
402
403 auto method_model_ptr = create_method_model(declaration);
404
405 if (!method_model_ptr)
406 return true;
407
408 process_comment(*declaration, *method_model_ptr);
409
410 set_source_location(*declaration, *method_model_ptr);
411
412 const auto method_full_name = method_model_ptr->full_name(false);
413
414 method_model_ptr->set_id(common::to_id(method_full_name));
415
416 // Callee methods in call expressions are referred to by first declaration
417 // id, so they should both be mapped to method_model
418 if (declaration->isThisDeclarationADefinition()) {
420 declaration->getFirstDecl()->getID(), method_model_ptr->id());
421 }
422
423 set_unique_id(declaration->getID(), method_model_ptr->id());
424
425 LOG_TRACE("Set id {} --> {} for method name {} [{}]", declaration->getID(),
426 method_model_ptr->id(), method_full_name,
427 declaration->isThisDeclarationADefinition());
428
429 context().update(declaration);
430
431 context().set_caller_id(method_model_ptr->id());
432
433 diagram().add_participant(std::move(method_model_ptr));
434
435 return true;
436}

◆ 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 795 of file translation_unit_visitor.cc.

796{
797 if (!should_include(cls))
798 return true;
799
800 LOG_DBG("= Visiting class declaration {} at {}",
801 cls->getQualifiedNameAsString(),
802 cls->getLocation().printToString(source_manager()));
803
804 LOG_DBG(
805 "== getQualifiedNameAsString() = {}", cls->getQualifiedNameAsString());
806 if (cls->getOwningModule() != nullptr)
807 LOG_DBG(
808 "== getOwningModule()->Name = {}", cls->getOwningModule()->Name);
809 LOG_DBG("== getID() = {}", cls->getID());
810 LOG_DBG("== isTemplateDecl() = {}", cls->isTemplateDecl());
811 LOG_DBG("== isTemplated() = {}", cls->isTemplated());
812 LOG_DBG("== getParent()->isRecord()() = {}", cls->getParent()->isRecord());
813 LOG_DBG("== isCompleteDefinition() = {}", cls->isCompleteDefinition());
814
815 if (const auto *parent_record =
816 clang::dyn_cast<clang::RecordDecl>(cls->getParent());
817 parent_record != nullptr) {
818 LOG_DBG("== getParent()->getQualifiedNameAsString() = {}",
819 parent_record->getQualifiedNameAsString());
820 }
821
822 if (has_processed_template_class(cls->getQualifiedNameAsString()))
823 // If we have already processed the template of this class
824 // skip it
825 return true;
826
827 if (cls->isTemplated() && (cls->getDescribedTemplate() != nullptr)) {
828 // If the described templated of this class is already in the model
829 // skip it:
830 const eid_t ast_id{cls->getDescribedTemplate()->getID()};
831 if (id_mapper().get_global_id(ast_id))
832 return true;
833 }
834
835 // TODO: Add support for classes defined in function/method bodies
836 if (cls->isLocalClass() != nullptr)
837 return true;
838
839 auto c_ptr = create_declaration(cls);
840
841 if (!c_ptr)
842 return true;
843
844 return add_or_update(cls, std::move(c_ptr));
845}

◆ VisitCXXRecordDecl() [3/3]

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

Definition at line 155 of file translation_unit_visitor.cc.

157{
158 if (!should_include(declaration))
159 return true;
160
161 // Skip this class if it's parent template is already in the model
162 if (declaration->isTemplated() &&
163 declaration->getDescribedTemplate() != nullptr) {
164 if (get_unique_id(eid_t{declaration->getDescribedTemplate()->getID()}))
165 return true;
166 }
167
168 LOG_TRACE("Visiting class declaration at {}",
169 declaration->getBeginLoc().printToString(source_manager()));
170
171 // Build the class declaration and store it in the diagram, even
172 // if we don't need it for any of the participants of this diagram
173 auto class_model_ptr = create_class_model(declaration);
174
175 if (!class_model_ptr)
176 return true;
177
178 context().reset();
179
180 const auto class_id = class_model_ptr->id();
181
182 set_unique_id(declaration->getID(), class_id);
183
184 auto &class_model = get_participant(class_id, *class_model_ptr);
185
186 if (!declaration->isCompleteDefinition()) {
187 forward_declarations_.emplace(class_id, std::move(class_model_ptr));
188 return true;
189 }
190
191 forward_declarations_.erase(class_id);
192
193 if (diagram().should_include(class_model)) {
194 LOG_DBG("Adding class participant {} with id {}",
195 class_model.full_name(false), class_model.id());
196
197 assert(class_model.id() == class_id);
198
199 context().set_caller_id(class_id);
200 context().update(declaration);
201
202 diagram().add_participant(std::move(class_model_ptr));
203 }
204 else {
205 LOG_DBG("Skipping class {} with id {}", class_model.full_name(true),
206 class_id);
207 }
208
209 return true;
210}

◆ 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 454 of file translation_unit_visitor.cc.

456{
457 if (declaration->isCXXClassMember())
458 return true;
459
460 if (!should_include(declaration))
461 return true;
462
463 if (!declaration->isThisDeclarationADefinition()) {
464 if (auto *declaration_definition = declaration->getDefinition();
465 declaration_definition != nullptr)
466 return VisitFunctionDecl(
467 static_cast<clang::FunctionDecl *>(declaration_definition));
468 }
469
470 LOG_TRACE("Visiting function declaration {} at {}",
471 declaration->getQualifiedNameAsString(),
472 declaration->getLocation().printToString(source_manager()));
473
474 if (declaration->isTemplated()) {
475 if (declaration->getDescribedTemplate() != nullptr) {
476 // If the described templated of this function is already in the
477 // model skip it:
478 if (get_unique_id(
479 eid_t{declaration->getDescribedTemplate()->getID()}))
480 return true;
481 }
482 }
483
484 std::unique_ptr<model::function> function_model_ptr{};
485
486 if (declaration->isFunctionTemplateSpecialization()) {
487 function_model_ptr =
489 }
490 else {
491 function_model_ptr = build_function_model(*declaration);
492 }
493
494 if (!function_model_ptr)
495 return true;
496
497 function_model_ptr->set_id(
498 common::to_id(function_model_ptr->full_name(false)));
499
500 function_model_ptr->is_void(declaration->getReturnType()->isVoidType());
501
502 function_model_ptr->is_operator(declaration->isOverloadedOperator());
503
504 function_model_ptr->is_cuda_kernel(
505 common::has_attr(declaration, clang::attr::CUDAGlobal));
506
507 function_model_ptr->is_cuda_device(
508 common::has_attr(declaration, clang::attr::CUDADevice));
509
510 function_model_ptr->is_coroutine(common::is_coroutine(*declaration));
511
512 context().update(declaration);
513
514 context().set_caller_id(function_model_ptr->id());
515
516 if (declaration->isThisDeclarationADefinition()) {
518 declaration->getFirstDecl()->getID(), function_model_ptr->id());
519 }
520
521 set_unique_id(declaration->getID(), function_model_ptr->id());
522
523 process_comment(*declaration, *function_model_ptr);
524
525 set_source_location(*declaration, *function_model_ptr);
526
527 diagram().add_participant(std::move(function_model_ptr));
528
529 return true;
530}

◆ 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 548 of file translation_unit_visitor.cc.

550{
551 if (!should_include(declaration))
552 return true;
553
554 const auto function_name = declaration->getQualifiedNameAsString();
555
556 LOG_TRACE("Visiting function template declaration {} at {}", function_name,
557 declaration->getLocation().printToString(source_manager()));
558
559 auto function_template_model = build_function_template(*declaration);
560
561 process_comment(*declaration, *function_template_model);
562
563 set_source_location(*declaration, *function_template_model);
564 set_owning_module(*declaration, *function_template_model);
565
566 function_template_model->is_void(
567 declaration->getAsFunction()->getReturnType()->isVoidType());
568
569 function_template_model->set_id(
570 common::to_id(function_template_model->full_name(false)));
571
572 function_template_model->is_operator(
573 declaration->getAsFunction()->isOverloadedOperator());
574
575 context().update(declaration);
576
577 context().set_caller_id(function_template_model->id());
578
579 set_unique_id(declaration->getID(), function_template_model->id());
580
581 diagram().add_participant(std::move(function_template_model));
582
583 return true;
584}

◆ VisitLambdaExpr()

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

Definition at line 586 of file translation_unit_visitor.cc.

587{
588 if (!should_include(expr))
589 return true;
590
591 const auto lambda_full_name =
592 expr->getLambdaClass()->getCanonicalDecl()->getNameAsString();
593
594 LOG_TRACE("Visiting lambda expression {} at {} [caller_id = {}]",
595 lambda_full_name, expr->getBeginLoc().printToString(source_manager()),
596 context().caller_id());
597
598 LOG_TRACE("Lambda call operator ID {} - lambda class ID {}, class call "
599 "operator ID {}",
600 expr->getCallOperator()->getID(), expr->getLambdaClass()->getID(),
601 expr->getLambdaClass()->getLambdaCallOperator()->getID());
602
603 // Create lambda class participant
604 auto *cls = expr->getLambdaClass();
605 auto lambda_class_model_ptr = create_class_model(cls);
606
607 if (!lambda_class_model_ptr)
608 return true;
609
610 lambda_class_model_ptr->is_lambda(true);
611
612 const auto cls_id = lambda_class_model_ptr->id();
613
614 set_unique_id(cls->getID(), cls_id);
615
616 auto lambda_method_model_ptr =
617 create_lambda_method_model(expr->getCallOperator());
618
619 lambda_method_model_ptr->set_class_id(cls_id);
620
621 // If this is a nested lambda, prepend the parent lambda name to this lambda
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);
624
625 diagram().add_participant(std::move(lambda_class_model_ptr));
626
627 lambda_method_model_ptr->set_id(
628 common::to_id(get_participant(cls_id).value().full_name(false) +
629 "::" + lambda_method_model_ptr->full_name_no_ns()));
630
631 get_participant<model::class_>(cls_id).value().set_lambda_operator_id(
632 lambda_method_model_ptr->id());
633
634 // If lambda expression is in an argument to a method/function, and that
635 // method function would be excluded by filters and if it is not a lambda
636 // call itself
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()))) {
644
645 message m{message_t::kCall, context().caller_id()};
646 set_source_location(*expr, m);
647 m.set_from(context().caller_id());
648 m.set_to(lambda_method_model_ptr->id());
649
651
652 diagram().add_active_participant(m.from());
653 diagram().add_active_participant(m.to());
654
655 LOG_DBG("Found call in lambda expression {} from {} [{}] to {} [{}]",
656 m.message_name(), m.from(), m.from(), m.to(), m.to());
657
658 push_message(std::get<clang::CallExpr *>(context().current_callexpr()),
659 std::move(m));
660 }
661
662 context().enter_lambda_expression(lambda_method_model_ptr->id());
663
665 expr->getCallOperator()->getID(), lambda_method_model_ptr->id());
666
667 diagram().add_participant(std::move(lambda_method_model_ptr));
668
669 [[maybe_unused]] const auto is_generic_lambda = expr->isGenericLambda();
670
671 return true;
672}

◆ 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 373 of file translation_unit_visitor.cc.

375{
376 if (!should_include(decl))
377 return true;
378
379 LOG_DBG("= Visiting ObjC category declaration {} at {}",
380 decl->getQualifiedNameAsString(),
381 decl->getLocation().printToString(source_manager()));
382
383 auto category_ptr = create_objc_category_declaration(decl);
384
385 if (!category_ptr)
386 return true;
387
388 const auto category_id = category_ptr->id();
389
390 id_mapper().add(decl->getID(), category_id);
391
392 auto &category_model =
393 diagram().find<objc_interface>(category_id).has_value()
394 ? *diagram().find<objc_interface>(category_id).get()
395 : *category_ptr;
396
397 process_objc_category_declaration(*decl, category_model);
398
399 if (diagram().should_include(category_model)) {
400 LOG_DBG("Adding ObjC category {} with id {}",
401 category_model.full_name(false), category_model.id());
402
403 add_objc_interface(std::move(category_ptr));
404 }
405 else {
406 LOG_DBG("Skipping ObjC category {} with id {}",
407 category_model.full_name(true), category_model.id());
408 }
409
410 return true;
411}

◆ 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 453 of file translation_unit_visitor.cc.

455{
456 if (!should_include(decl))
457 return true;
458
459 LOG_DBG("= Visiting ObjC interface declaration {} at {}",
460 decl->getQualifiedNameAsString(),
461 decl->getLocation().printToString(source_manager()));
462
463 auto interface_ptr = create_objc_interface_declaration(decl);
464
465 if (!interface_ptr)
466 return true;
467
468 const auto protocol_id = interface_ptr->id();
469
470 id_mapper().add(decl->getID(), protocol_id);
471
472 auto &interface_model =
473 diagram().find<objc_interface>(protocol_id).has_value()
474 ? *diagram().find<objc_interface>(protocol_id).get()
475 : *interface_ptr;
476
477 if (!interface_model.complete())
478 process_objc_interface_declaration(*decl, interface_model);
479
480 if (diagram().should_include(interface_model)) {
481 LOG_DBG("Adding ObjC interface {} with id {}",
482 interface_model.full_name(false), interface_model.id());
483
484 add_objc_interface(std::move(interface_ptr));
485 }
486 else {
487 LOG_DBG("Skipping ObjC interface {} with id {}",
488 interface_model.full_name(true), interface_model.id());
489 }
490
491 return true;
492}

◆ 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 99 of file translation_unit_visitor.cc.

101{
102 if (!should_include(declaration))
103 return true;
104
105 LOG_TRACE("Visiting ObjC interface declaration at {}",
106 declaration->getBeginLoc().printToString(source_manager()));
107
108 // Build the class declaration and store it in the diagram, even
109 // if we don't need it for any of the participants of this diagram
110 auto objc_interface_model_ptr = create_objc_interface_model(declaration);
111
112 if (!objc_interface_model_ptr)
113 return true;
114
115 context().reset();
116
117 const auto class_id = objc_interface_model_ptr->id();
118
119 set_unique_id(declaration->getID(), class_id);
120
121 auto &class_model = get_participant(class_id, *objc_interface_model_ptr);
122
123 if (diagram().should_include(class_model)) {
124 LOG_DBG("Adding ObjC interface participant {} with id {}",
125 class_model.full_name(false), class_model.id());
126
127 assert(class_model.id() == class_id);
128
129 context().set_caller_id(class_id);
130 context().update(declaration);
131
132 diagram().add_participant(std::move(objc_interface_model_ptr));
133 }
134 else {
135 LOG_DBG("Skipping ObjC interface {} with id {}",
136 class_model.full_name(true), class_id);
137 }
138
139 return true;
140}

◆ VisitObjCMessageExpr()

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

Definition at line 1347 of file translation_unit_visitor.cc.

1349{
1355
1356 if (!context().valid() || context().get_ast_context() == nullptr)
1357 return true;
1358
1359 LOG_TRACE("Visiting ObjC message expression at {} [caller_id = {}]",
1360 expr->getBeginLoc().printToString(source_manager()),
1361 context().caller_id());
1362
1363 message m{message_t::kCall, context().caller_id()};
1364
1365 set_source_location(*expr, m);
1366
1367 const auto *raw_expr_comment = clanguml::common::get_expression_raw_comment(
1368 source_manager(), *context().get_ast_context(), expr);
1369 const auto stripped_comment = process_comment(
1370 raw_expr_comment, context().get_ast_context()->getDiagnostics(), m);
1371
1372 if (m.skip())
1373 return true;
1374
1375 auto generated_message_from_comment = generate_message_from_comment(m);
1376
1377 if (!generated_message_from_comment && !should_include(expr)) {
1378 LOG_DBG("Skipping call expression due to filter at: {}",
1379 expr->getBeginLoc().printToString(source_manager()));
1380
1381 processed_comments().erase(raw_expr_comment);
1382 return true;
1383 }
1384
1385 if (context().is_expr_in_current_control_statement_condition(expr)) {
1386 m.set_message_scope(common::model::message_scope_t::kCondition);
1387 }
1388
1389 if (generated_message_from_comment) {
1390 LOG_DBG(
1391 "Message for this call expression is taken from comment directive");
1392 return true;
1393 }
1394
1396
1397 // Add message to diagram
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(),
1401 stripped_comment);
1402
1404
1405 diagram().add_active_participant(m.from());
1406 diagram().add_active_participant(m.to());
1407
1408 LOG_DBG("Found ObjC message {} from {} [{}] to {} [{}] ",
1409 m.message_name(), m.from(), m.from(), m.to(), m.to());
1410
1411 push_message(expr, std::move(m));
1412 }
1413
1414 return true;
1415}

◆ VisitObjCMethodDecl()

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

Definition at line 321 of file translation_unit_visitor.cc.

323{
324 if (!should_include(declaration))
325 return true;
326
327 LOG_TRACE("Visiting ObjC method {} in class",
328 declaration->getQualifiedNameAsString());
329
330 context().update(declaration);
331
332 auto method_model_ptr = create_objc_method_model(declaration);
333
334 if (!method_model_ptr)
335 return true;
336
337 process_comment(*declaration, *method_model_ptr);
338
339 set_source_location(*declaration, *method_model_ptr);
340
341 const auto method_full_name = method_model_ptr->full_name(false);
342
343 method_model_ptr->set_id(common::to_id(method_full_name));
344
345 set_unique_id(declaration->getID(), method_model_ptr->id());
346
347 LOG_TRACE("Set id {} --> {} for method name {} [{}]", declaration->getID(),
348 method_model_ptr->id(), method_full_name,
349 declaration->isThisDeclarationADefinition());
350
351 context().update(declaration);
352
353 context().set_caller_id(method_model_ptr->id());
354
355 diagram().add_participant(std::move(method_model_ptr));
356
357 return true;
358}

◆ VisitObjCPropertyRefExpr()

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

Definition at line 1417 of file translation_unit_visitor.cc.

1419{
1425
1426 if (!context().valid() || context().get_ast_context() == nullptr)
1427 return true;
1428
1429 LOG_TRACE("Visiting ObjC property ref expression at {} [caller_id = {}]",
1430 expr->getBeginLoc().printToString(source_manager()),
1431 context().caller_id());
1432
1433 return true;
1434}

◆ VisitObjCProtocolDecl() [1/3]

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

Definition at line 413 of file translation_unit_visitor.cc.

415{
416 if (!should_include(decl))
417 return true;
418
419 LOG_DBG("= Visiting ObjC protocol declaration {} at {}",
420 decl->getQualifiedNameAsString(),
421 decl->getLocation().printToString(source_manager()));
422
423 auto protocol_ptr = create_objc_protocol_declaration(decl);
424
425 if (!protocol_ptr)
426 return true;
427
428 const auto protocol_id = protocol_ptr->id();
429
430 id_mapper().add(decl->getID(), protocol_id);
431
432 auto &protocol_model =
433 diagram().find<objc_interface>(protocol_id).has_value()
434 ? *diagram().find<objc_interface>(protocol_id).get()
435 : *protocol_ptr;
436
437 process_objc_protocol_declaration(*decl, protocol_model);
438
439 if (diagram().should_include(protocol_model)) {
440 LOG_DBG("Adding ObjC protocol {} with id {}",
441 protocol_model.full_name(false), protocol_model.id());
442
443 add_objc_interface(std::move(protocol_ptr));
444 }
445 else {
446 LOG_DBG("Skipping ObjC protocol {} with id {}",
447 protocol_model.full_name(true), protocol_model.id());
448 }
449
450 return true;
451}

◆ 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 = get_participant(class_id, *objc_protocol_model_ptr);
79
80 if (diagram().should_include(class_model)) {
81 LOG_DBG("Adding ObjC protocol participant {} with id {}",
82 class_model.full_name(false), class_model.id());
83
84 assert(class_model.id() == class_id);
85
86 context().set_caller_id(class_id);
87 context().update(declaration);
88
89 diagram().add_participant(std::move(objc_protocol_model_ptr));
90 }
91 else {
92 LOG_DBG("Skipping ObjC protocol {} with id {}",
93 class_model.full_name(true), class_id);
94 }
95
96 return true;
97}

◆ 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 348 of file translation_unit_visitor.cc.

349{
350 if (rec == nullptr)
351 return true;
352
353 if (clang::dyn_cast_or_null<clang::CXXRecordDecl>(rec) != nullptr)
354 // This is handled by VisitCXXRecordDecl()
355 return true;
356
357 // It seems we are in a C (not C++) translation unit
358 if (!should_include(rec))
359 return true;
360
361 LOG_DBG("= Visiting record declaration {} at {}",
362 rec->getQualifiedNameAsString(),
363 rec->getLocation().printToString(source_manager()));
364
365 auto record_ptr = create_declaration(rec);
366
367 if (!record_ptr)
368 return true;
369
370 return add_or_update(rec, std::move(record_ptr));
371}

◆ VisitReturnStmt()

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

Definition at line 1681 of file translation_unit_visitor.cc.

1682{
1688
1689 if (!context().valid() || context().get_ast_context() == nullptr)
1690 return true;
1691
1692 LOG_TRACE("Visiting return statement at {}",
1693 stmt->getBeginLoc().printToString(source_manager()));
1694
1695 message m{message_t::kReturn, context().caller_id()};
1696
1697 set_source_location(*stmt, m);
1698
1699 const auto *raw_expr_comment = clanguml::common::get_expression_raw_comment(
1700 source_manager(), *context().get_ast_context(), stmt);
1701 const auto stripped_comment = process_comment(
1702 raw_expr_comment, context().get_ast_context()->getDiagnostics(), m);
1703
1704 if (m.skip())
1705 return true;
1706
1707 if (stmt->getRetValue() != nullptr) {
1708 std::string message_name = common::to_string(stmt->getRetValue());
1709 m.set_message_name(util::condense_whitespace(message_name));
1710 }
1711
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()); // NOLINT
1716
1717 if (lambda_model.has_value()) {
1718 if (lambda_model.has_value())
1719 m.set_return_type(lambda_model.value().return_type());
1720 }
1721 }
1722 else if (context().current_function_decl_ != nullptr) {
1723 m.set_return_type(
1724 context().current_function_decl_->getReturnType().getAsString());
1725 }
1726 else if (context().current_function_template_decl_ != nullptr) {
1727 m.set_return_type(context()
1728 .current_function_template_decl_->getAsFunction()
1729 ->getReturnType()
1730 .getAsString());
1731 }
1732 else if (context().current_method_decl_ != nullptr) {
1733 m.set_return_type(
1734 context().current_method_decl_->getReturnType().getAsString());
1735 }
1736 else if (context().current_objc_method_decl_ != nullptr) {
1737 m.set_return_type(
1738 context().current_objc_method_decl_->getReturnType().getAsString());
1739 }
1740
1741 // We can skip the ID of the return activity here, we'll just add it during
1742 // diagram generation
1743 if (m.from().value() > 0) {
1744 if (raw_expr_comment != nullptr)
1745 m.set_comment(raw_expr_comment->getBeginLoc().getHashValue(),
1746 stripped_comment);
1747
1749
1750 diagram().add_active_participant(m.from());
1751
1752 LOG_DBG("Found return call {} from {} [{}] to {} [{}] ",
1753 m.message_name(), m.from(), m.from(), m.to(), m.to());
1754
1755 push_message(stmt, std::move(m));
1756 }
1757
1758 return true;
1759}

◆ 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}