0.5.4
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::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::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)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::shouldVisitTemplateInstantiations ()
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::VisitCallExpr (clang::CallExpr *expr)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseVarDecl (clang::VarDecl *VD)
 
bool clanguml::sequence_diagram::visitor::translation_unit_visitor::TraverseCallExpr (clang::CallExpr *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::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::VisitCXXMethodDecl (clang::CXXMethodDecl *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::VisitFunctionTemplateDecl (clang::FunctionTemplateDecl *function_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 94 of file translation_unit_visitor.h.

94{ 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 92 of file translation_unit_visitor.h.

92{ return false; }

◆ TraverseCallExpr()

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

Definition at line 519 of file translation_unit_visitor.cc.

520{
521 if (!config().include_system_headers() &&
522 source_manager().isInSystemHeader(expr->getSourceRange().getBegin()))
523 return true;
524
525 LOG_TRACE("Entering call expression at {}",
526 expr->getBeginLoc().printToString(source_manager()));
527
528 context().enter_callexpr(expr);
529
530 RecursiveASTVisitor<translation_unit_visitor>::TraverseCallExpr(expr);
531
532 LOG_TRACE("Leaving call expression at {}",
533 expr->getBeginLoc().printToString(source_manager()));
534
536
538
539 return true;
540}

◆ TraverseCaseStmt()

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

Definition at line 981 of file translation_unit_visitor.cc.

982{
984
985 const auto current_caller_id = context().caller_id();
986
987 if ((current_caller_id.value() != 0) &&
988 (context().current_switchstmt() != nullptr)) {
989 model::message m{message_t::kCase, current_caller_id};
990 m.set_message_name(common::to_string(stmt->getLHS()));
991 diagram().add_case_stmt_message(std::move(m));
992 }
993
994 RecursiveASTVisitor<translation_unit_visitor>::TraverseCaseStmt(stmt);
995
996 return true;
997}

◆ TraverseCompoundStmt()

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

Definition at line 647 of file translation_unit_visitor.cc.

648{
653
654 if (stmt == nullptr)
655 return true;
656
657 const auto *current_ifstmt = context().current_ifstmt();
658 const auto *current_elseifstmt =
659 current_ifstmt != nullptr ? context().current_elseifstmt() : nullptr;
660
661 //
662 // Add final else block (not else if)
663 //
664 if (current_elseifstmt != nullptr) {
665 if (current_elseifstmt->getElse() == stmt) {
666 const auto current_caller_id = context().caller_id();
667
668 if (current_caller_id.value() != 0) {
669 model::message m{message_t::kElse, current_caller_id};
670 set_source_location(*stmt, m);
671 diagram().add_message(std::move(m));
672 }
673 }
674 }
675 else if (current_ifstmt != nullptr) {
676 if (current_ifstmt->getElse() == stmt) {
677 const auto current_caller_id = context().caller_id();
678
679 if (current_caller_id.value() != 0) {
680 model::message m{message_t::kElse, current_caller_id};
681 set_source_location(*stmt, m);
682 diagram().add_message(std::move(m));
683 }
684 }
685 }
686
687 RecursiveASTVisitor<translation_unit_visitor>::TraverseCompoundStmt(stmt);
688
689 return true;
690}

◆ TraverseConceptDecl()

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

Definition at line 389 of file translation_unit_visitor.cc.

390{
391 if (!should_include(cpt))
392 return true;
393
394 LOG_DBG("= Visiting concept (isType: {}) declaration {} at {}",
395 cpt->isTypeConcept(), cpt->getQualifiedNameAsString(),
396 cpt->getLocation().printToString(source_manager()));
397
398 auto concept_model = create_concept_declaration(cpt);
399
400 if (!concept_model)
401 return true;
402
403 const auto concept_id = concept_model->id();
404
405 id_mapper().add(cpt->getID(), concept_id);
406
407 tbuilder().build_from_template_declaration(*concept_model, *cpt);
408
409 constexpr auto kMaxConstraintCount = 24U;
410 llvm::SmallVector<const clang::Expr *, kMaxConstraintCount> constraints{};
411 if (cpt->hasAssociatedConstraints()) {
412 cpt->getAssociatedConstraints(constraints);
413 }
414
415 for (const auto *expr : constraints) {
417 }
418
419 if (cpt->getConstraintExpr() != nullptr) {
421 cpt, cpt->getConstraintExpr(), *concept_model);
422
424 *concept_model, cpt->getConstraintExpr());
425 }
426
427 if (diagram().should_include(*concept_model)) {
428 LOG_DBG("Adding concept {} with id {}", concept_model->full_name(false),
429 concept_model->id());
430
431 add_concept(std::move(concept_model));
432 }
433 else {
434 LOG_DBG("Skipping concept {} with id {}", concept_model->full_name(),
435 concept_model->id());
436 }
437
438 return true;
439}

◆ TraverseConditionalOperator()

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

Definition at line 1017 of file translation_unit_visitor.cc.

1019{
1021
1022 const auto current_caller_id = context().caller_id();
1023
1024 std::string condition_text;
1025 if (config().generate_condition_statements())
1026 condition_text = common::get_condition_text(source_manager(), stmt);
1027
1028 if (current_caller_id.value() != 0) {
1030 model::message m{message_t::kConditional, current_caller_id};
1031 set_source_location(*stmt, m);
1032 m.condition_text(condition_text);
1033 m.set_comment(get_expression_comment(source_manager(),
1034 *context().get_ast_context(), current_caller_id, stmt));
1035 diagram().add_block_message(std::move(m));
1036 }
1037
1038 RecursiveASTVisitor<translation_unit_visitor>::TraverseStmt(
1039 stmt->getCond());
1040
1041 RecursiveASTVisitor<translation_unit_visitor>::TraverseStmt(
1042 stmt->getTrueExpr());
1043
1044 if (current_caller_id.value() != 0) {
1045 model::message m{message_t::kConditionalElse, current_caller_id};
1046 set_source_location(*stmt, m);
1047 diagram().add_message(std::move(m));
1048 }
1049
1050 RecursiveASTVisitor<translation_unit_visitor>::TraverseStmt(
1051 stmt->getFalseExpr());
1052
1053 if (current_caller_id.value() != 0) {
1055 diagram().end_block_message(
1056 {message_t::kConditionalEnd, current_caller_id},
1057 message_t::kConditional);
1058 }
1059
1060 return true;
1061}

◆ TraverseCUDAKernelCallExpr()

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

Definition at line 542 of file translation_unit_visitor.cc.

544{
545 if (!config().include_system_headers() &&
546 source_manager().isInSystemHeader(expr->getSourceRange().getBegin()))
547 return true;
548
549 LOG_TRACE("Entering CUDA kernel call expression at {}",
550 expr->getBeginLoc().printToString(source_manager()));
551
552 context().enter_callexpr(expr);
553
554 RecursiveASTVisitor<translation_unit_visitor>::TraverseCallExpr(expr);
555
556 LOG_TRACE("Leaving CUDA kernel call expression at {}",
557 expr->getBeginLoc().printToString(source_manager()));
558
560
562
563 return true;
564}

◆ TraverseCXXCatchStmt()

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

Definition at line 893 of file translation_unit_visitor.cc.

894{
898
899 const auto current_caller_id = context().caller_id();
900
901 if ((current_caller_id.value() != 0) &&
902 (context().current_trystmt() != nullptr)) {
903 std::string caught_type;
904 if (stmt->getCaughtType().isNull())
905 caught_type = "...";
906 else
907 caught_type = common::to_string(
908 stmt->getCaughtType(), *context().get_ast_context());
909
910 model::message m{message_t::kCatch, current_caller_id};
911 m.set_message_name(std::move(caught_type));
912 diagram().add_message(std::move(m));
913 }
914
915 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXCatchStmt(stmt);
916
917 return true;
918}

◆ TraverseCXXConstructExpr()

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

Definition at line 624 of file translation_unit_visitor.cc.

626{
627 LOG_TRACE("Entering cxx construct call expression at {}",
628 expr->getBeginLoc().printToString(source_manager()));
629
630 context().enter_callexpr(expr);
631
632 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXConstructExpr(
633 expr);
634
636
637 LOG_TRACE("Leaving cxx construct call expression at {}",
638 expr->getBeginLoc().printToString(source_manager()));
639
641
643
644 return true;
645}

◆ TraverseCXXForRangeStmt()

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

Definition at line 920 of file translation_unit_visitor.cc.

922{
926
927 const auto current_caller_id = context().caller_id();
928
929 std::string condition_text;
930 if (config().generate_condition_statements())
931 condition_text = common::get_condition_text(source_manager(), stmt);
932
933 if (current_caller_id.value() != 0) {
934 context().enter_loopstmt(stmt);
935 message m{message_t::kFor, current_caller_id};
936 set_source_location(*stmt, m);
937 m.condition_text(condition_text);
939 *context().get_ast_context(), current_caller_id, stmt));
940 diagram().add_block_message(std::move(m));
941 }
942
943 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXForRangeStmt(
944 stmt);
945
946 if (current_caller_id.value() != 0) {
947 diagram().end_block_message(
948 {message_t::kForEnd, current_caller_id}, message_t::kFor);
950 }
951
952 return true;
953}

◆ TraverseCXXMemberCallExpr()

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

Definition at line 566 of file translation_unit_visitor.cc.

568{
569 if (!config().include_system_headers() &&
570 source_manager().isInSystemHeader(expr->getSourceRange().getBegin()))
571 return true;
572
573 LOG_TRACE("Entering member call expression at {}",
574 expr->getBeginLoc().printToString(source_manager()));
575
576 context().enter_callexpr(expr);
577
578 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXMemberCallExpr(
579 expr);
580
581 LOG_TRACE("Leaving member call expression at {}",
582 expr->getBeginLoc().printToString(source_manager()));
583
585
587
588 return true;
589}

◆ TraverseCXXMethodDecl()

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

Definition at line 220 of file translation_unit_visitor.cc.

222{
223 // We need to backup the context, since other methods or functions can
224 // be traversed during this traversal (e.g. template function/method
225 // specializations)
226 auto context_backup = context();
227
228 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXMethodDecl(
229 declaration);
230
231 call_expression_context_ = context_backup;
232
233 return true;
234}

◆ TraverseCXXOperatorCallExpr()

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

Definition at line 591 of file translation_unit_visitor.cc.

593{
594 context().enter_callexpr(expr);
595
596 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXOperatorCallExpr(
597 expr);
598
600
602
603 return true;
604}

◆ TraverseCXXTemporaryObjectExpr()

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

Definition at line 606 of file translation_unit_visitor.cc.

608{
609 context().enter_callexpr(expr);
610
611 RecursiveASTVisitor<
613
615 clang::dyn_cast<clang::CXXConstructExpr>(expr));
616
618
620
621 return true;
622}

◆ TraverseCXXTryStmt()

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

Definition at line 865 of file translation_unit_visitor.cc.

866{
870
871 const auto current_caller_id = context().caller_id();
872
873 if (current_caller_id.value() != 0) {
874 context().enter_trystmt(stmt);
875 message m{message_t::kTry, current_caller_id};
876 set_source_location(*stmt, m);
878 *context().get_ast_context(), current_caller_id, stmt));
879 diagram().add_block_message(std::move(m));
880 }
881
882 RecursiveASTVisitor<translation_unit_visitor>::TraverseCXXTryStmt(stmt);
883
884 if (current_caller_id.value() != 0) {
885 diagram().end_block_message(
886 {message_t::kTryEnd, current_caller_id}, message_t::kTry);
888 }
889
890 return true;
891}

◆ TraverseDefaultStmt()

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

Definition at line 999 of file translation_unit_visitor.cc.

1000{
1002
1003 const auto current_caller_id = context().caller_id();
1004
1005 if ((current_caller_id.value() != 0) &&
1006 (context().current_switchstmt() != nullptr)) {
1007 model::message m{message_t::kCase, current_caller_id};
1008 m.set_message_name("default");
1009 diagram().add_case_stmt_message(std::move(m));
1010 }
1011
1012 RecursiveASTVisitor<translation_unit_visitor>::TraverseDefaultStmt(stmt);
1013
1014 return true;
1015}

◆ TraverseDoStmt()

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

Definition at line 797 of file translation_unit_visitor.cc.

798{
802
803 const auto current_caller_id = context().caller_id();
804
805 std::string condition_text;
806 if (config().generate_condition_statements())
807 condition_text = common::get_condition_text(source_manager(), stmt);
808
809 if (current_caller_id.value() != 0) {
810 context().enter_loopstmt(stmt);
811 message m{message_t::kDo, current_caller_id};
812 set_source_location(*stmt, m);
813 m.condition_text(condition_text);
815 *context().get_ast_context(), current_caller_id, stmt));
816 diagram().add_block_message(std::move(m));
817 }
818
819 RecursiveASTVisitor<translation_unit_visitor>::TraverseDoStmt(stmt);
820
821 if (current_caller_id.value() != 0) {
822 diagram().end_block_message(
823 {message_t::kDoEnd, current_caller_id}, message_t::kDo);
825 }
826
827 return true;
828}

◆ TraverseForStmt()

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

Definition at line 830 of file translation_unit_visitor.cc.

831{
835
836 const auto current_caller_id = context().caller_id();
837
838 std::string condition_text;
839 if (config().generate_condition_statements())
840 condition_text = common::get_condition_text(source_manager(), stmt);
841
842 if (current_caller_id.value() != 0) {
843 context().enter_loopstmt(stmt);
844 message m{message_t::kFor, current_caller_id};
845 set_source_location(*stmt, m);
846 m.condition_text(condition_text);
847
849 *context().get_ast_context(), current_caller_id, stmt));
850
851 diagram().add_block_message(std::move(m));
852 }
853
854 RecursiveASTVisitor<translation_unit_visitor>::TraverseForStmt(stmt);
855
856 if (current_caller_id.value() != 0) {
857 diagram().end_block_message(
858 {message_t::kForEnd, current_caller_id}, message_t::kFor);
860 }
861
862 return true;
863}

◆ TraverseFunctionDecl()

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

Definition at line 298 of file translation_unit_visitor.cc.

300{
301 // We need to backup the context, since other methods or functions can
302 // be traversed during this traversal (e.g. template function/method
303 // specializations)
304 auto context_backup = context();
305
306 RecursiveASTVisitor<translation_unit_visitor>::TraverseFunctionDecl(
307 declaration);
308
309 call_expression_context_ = context_backup;
310
311 return true;
312}

◆ TraverseIfStmt()

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

Definition at line 692 of file translation_unit_visitor.cc.

693{
698
699 bool elseif_block{false};
700
701 const auto current_caller_id = context().caller_id();
702 const auto *current_ifstmt = context().current_ifstmt();
703 const auto *current_elseifstmt =
704 current_ifstmt != nullptr ? context().current_elseifstmt() : nullptr;
705
706 std::string condition_text;
707 if (config().generate_condition_statements())
708 condition_text = common::get_condition_text(source_manager(), stmt);
709
710 // Check if this is a beginning of a new if statement, or an
711 // else if condition of the current if statement
712 auto child_stmt_compare = [stmt](auto *child_stmt) {
713 return child_stmt == stmt;
714 };
715
716 if (current_ifstmt != nullptr)
717 elseif_block = elseif_block ||
718 std::any_of(current_ifstmt->children().begin(),
719 current_ifstmt->children().end(), child_stmt_compare);
720 if (current_elseifstmt != nullptr)
721 elseif_block = elseif_block ||
722 std::any_of(current_elseifstmt->children().begin(),
723 current_elseifstmt->children().end(), child_stmt_compare);
724
725 if ((current_caller_id.value() != 0) && !stmt->isConstexpr()) {
726 if (elseif_block) {
728
729 message m{message_t::kElseIf, current_caller_id};
730 set_source_location(*stmt, m);
731 m.condition_text(condition_text);
733 *context().get_ast_context(), current_caller_id, stmt));
734 diagram().add_block_message(std::move(m));
735 }
736 else {
737 context().enter_ifstmt(stmt);
738
739 message m{message_t::kIf, current_caller_id};
740 set_source_location(*stmt, m);
741 m.condition_text(condition_text);
743 *context().get_ast_context(), current_caller_id, stmt));
744 diagram().add_block_message(std::move(m));
745 }
746 }
747
748 RecursiveASTVisitor<translation_unit_visitor>::TraverseIfStmt(stmt);
749
750 if ((current_caller_id.value() != 0) && !stmt->isConstexpr()) {
751 if (!elseif_block) {
752 diagram().end_block_message(
753 {message_t::kIfEnd, current_caller_id}, message_t::kIf);
755 }
756 }
757
758 return true;
759}

◆ TraverseLambdaExpr()

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

Definition at line 509 of file translation_unit_visitor.cc.

510{
511 RecursiveASTVisitor<translation_unit_visitor>::TraverseLambdaExpr(expr);
512
513 // lambda context is entered inside the visitor
515
516 return true;
517}

◆ TraverseSwitchStmt()

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

Definition at line 955 of file translation_unit_visitor.cc.

956{
958
959 const auto current_caller_id = context().caller_id();
960
961 if (current_caller_id.value() != 0) {
963 model::message m{message_t::kSwitch, current_caller_id};
964 set_source_location(*stmt, m);
966 *context().get_ast_context(), current_caller_id, stmt));
967 diagram().add_block_message(std::move(m));
968 }
969
970 RecursiveASTVisitor<translation_unit_visitor>::TraverseSwitchStmt(stmt);
971
972 if (current_caller_id.value() != 0) {
974 diagram().end_block_message(
975 {message_t::kSwitchEnd, current_caller_id}, message_t::kSwitch);
976 }
977
978 return true;
979}

◆ TraverseVarDecl()

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

Definition at line 1240 of file translation_unit_visitor.cc.

1241{
1242 if (decl->isStaticLocal())
1244
1245 RecursiveASTVisitor::TraverseVarDecl(decl);
1246
1247 if (decl->isStaticLocal())
1249
1250 return true;
1251}

◆ TraverseWhileStmt()

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

Definition at line 761 of file translation_unit_visitor.cc.

762{
766
767 const auto current_caller_id = context().caller_id();
768
769 std::string condition_text;
770 if (config().generate_condition_statements())
771 condition_text = common::get_condition_text(source_manager(), stmt);
772
773 if (current_caller_id.value() != 0) {
774 LOG_TRACE("Entering while statement at {}",
775 stmt->getBeginLoc().printToString(source_manager()));
776
777 context().enter_loopstmt(stmt);
778 message m{message_t::kWhile, current_caller_id};
779 set_source_location(*stmt, m);
780 m.condition_text(condition_text);
782 *context().get_ast_context(), current_caller_id, stmt));
783 diagram().add_block_message(std::move(m));
784 }
785
786 RecursiveASTVisitor<translation_unit_visitor>::TraverseWhileStmt(stmt);
787
788 if (current_caller_id.value() != 0) {
789 diagram().end_block_message(
790 {message_t::kWhileEnd, current_caller_id}, message_t::kWhile);
792 }
793
794 return true;
795}

◆ VisitCallExpr()

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

Definition at line 1063 of file translation_unit_visitor.cc.

1064{
1070
1071 if (!context().valid() || context().get_ast_context() == nullptr)
1072 return true;
1073
1074 LOG_TRACE("Visiting call expression at {} [caller_id = {}]",
1075 expr->getBeginLoc().printToString(source_manager()),
1076 context().caller_id());
1077
1078 message m{message_t::kCall, context().caller_id()};
1079
1080 m.in_static_declaration_context(within_static_variable_declaration_ > 0);
1081
1082 set_source_location(*expr, m);
1083
1084 const auto *raw_expr_comment = clanguml::common::get_expression_raw_comment(
1085 source_manager(), *context().get_ast_context(), expr);
1086 const auto stripped_comment = process_comment(
1087 raw_expr_comment, context().get_ast_context()->getDiagnostics(), m);
1088
1089 if (m.skip())
1090 return true;
1091
1092 auto generated_message_from_comment = generate_message_from_comment(m);
1093
1094 if (!generated_message_from_comment && !should_include(expr)) {
1095 LOG_DBG("Skipping call expression due to filter at: {}",
1096 expr->getBeginLoc().printToString(source_manager()));
1097
1098 processed_comments().erase(raw_expr_comment);
1099 return true;
1100 }
1101
1102 if (context().is_expr_in_current_control_statement_condition(expr)) {
1103 m.set_message_scope(common::model::message_scope_t::kCondition);
1104 }
1105
1106 if (generated_message_from_comment) {
1107 LOG_DBG(
1108 "Message for this call expression is taken from comment directive");
1109 }
1110 //
1111 // Call to a CUDA kernel function
1112 //
1113 else if (const auto *cuda_call_expr =
1114 clang::dyn_cast_or_null<clang::CUDAKernelCallExpr>(expr);
1115 cuda_call_expr != nullptr) {
1116 if (!process_cuda_kernel_call_expression(m, cuda_call_expr))
1117 return true;
1118 }
1119 //
1120 // Call to an overloaded operator
1121 //
1122 else if (const auto *operator_call_expr =
1123 clang::dyn_cast_or_null<clang::CXXOperatorCallExpr>(expr);
1124 operator_call_expr != nullptr) {
1125
1126 if (!process_operator_call_expression(m, operator_call_expr))
1127 return true;
1128 }
1129 //
1130 // Call to a class method
1131 //
1132 else if (const auto *method_call_expr =
1133 clang::dyn_cast_or_null<clang::CXXMemberCallExpr>(expr);
1134 method_call_expr != nullptr) {
1135
1136 if (!process_class_method_call_expression(m, method_call_expr))
1137 return true;
1138 }
1139 //
1140 // Call to function or template
1141 //
1142 else {
1143 auto *callee_decl = expr->getCalleeDecl();
1144
1145 if (callee_decl == nullptr) {
1146 LOG_DBG("Cannot get callee declaration - trying direct function "
1147 "callee...");
1148
1149 callee_decl = expr->getDirectCallee();
1150
1151 if (callee_decl != nullptr)
1152 LOG_DBG("Found function/method callee in: {}",
1153 common::to_string(expr));
1154 }
1155
1156 if (callee_decl == nullptr) {
1157 //
1158 // Call to a method of a class template
1159 //
1160 if (clang::dyn_cast_or_null<clang::CXXDependentScopeMemberExpr>(
1161 expr->getCallee()) != nullptr) {
1163 return true;
1164 }
1165 }
1166 //
1167 // Unresolved lookup expression are sometimes calls to template
1168 // functions
1169 //
1170 else if (clang::dyn_cast_or_null<clang::UnresolvedLookupExpr>(
1171 expr->getCallee()) != nullptr) {
1173 return true;
1174 }
1175 else if (clang::dyn_cast_or_null<clang::LambdaExpr>(
1176 expr->getCallee()) != nullptr) {
1177 LOG_DBG("Processing lambda expression callee");
1178 if (!process_lambda_call_expression(m, expr))
1179 return true;
1180 }
1181 else {
1182 LOG_DBG("Found unsupported callee decl type for: {} at {}",
1183 common::to_string(expr),
1184 expr->getBeginLoc().printToString(source_manager()));
1185 }
1186 }
1187 else {
1188 auto success = process_function_call_expression(m, expr);
1189
1190 if (!success) {
1191 LOG_DBG("Skipping call expression at: {}",
1192 expr->getBeginLoc().printToString(source_manager()));
1193
1194 return true;
1195 }
1196 }
1197 }
1198
1199 // Add message to diagram
1200 if (m.from().value() > 0 && m.to().value() > 0) {
1201 if (raw_expr_comment != nullptr)
1202 m.set_comment(raw_expr_comment->getBeginLoc().getHashValue(),
1203 stripped_comment);
1204
1205 if (diagram().sequences().find(m.from()) ==
1206 diagram().sequences().end()) {
1207 activity a{m.from()};
1208 diagram().sequences().insert({m.from(), std::move(a)});
1209 }
1210
1211 diagram().add_active_participant(m.from());
1212 diagram().add_active_participant(m.to());
1213
1214 LOG_DBG("Found call {} from {} [{}] to {} [{}] ", m.message_name(),
1215 m.from(), m.from(), m.to(), m.to());
1216
1217 push_message(expr, std::move(m));
1218 }
1219
1220 return true;
1221}

◆ VisitClassTemplateDecl() [1/3]

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

Definition at line 280 of file translation_unit_visitor.cc.

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

◆ VisitClassTemplateDecl() [2/3]

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

Definition at line 188 of file translation_unit_visitor.cc.

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

◆ VisitClassTemplateDecl() [3/3]

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

Definition at line 126 of file translation_unit_visitor.cc.

128{
129 if (!should_include(declaration))
130 return true;
131
132 LOG_TRACE("Visiting class template declaration {} at {} [{}]",
133 declaration->getQualifiedNameAsString(),
134 declaration->getLocation().printToString(source_manager()),
135 (void *)declaration);
136
137 auto class_model_ptr = create_class_model(declaration->getTemplatedDecl());
138
139 if (!class_model_ptr)
140 return true;
141
142 tbuilder().build_from_template_declaration(*class_model_ptr, *declaration);
143
144 const auto class_full_name = class_model_ptr->full_name(false);
145 const auto id = common::to_id(class_full_name);
146
147 // Override the id with the template id, for now we don't care about the
148 // underlying templated class id
149 class_model_ptr->set_id(id);
150
151 set_unique_id(declaration->getID(), id);
152
153 if (!declaration->getTemplatedDecl()->isCompleteDefinition()) {
154 forward_declarations_.emplace(id, std::move(class_model_ptr));
155 return true;
156 }
157 forward_declarations_.erase(id);
158
159 if (diagram().should_include(*class_model_ptr)) {
160 LOG_DBG("Adding class template participant {} with id {}",
161 class_full_name, id);
162
164 context().update(declaration);
165
166 diagram().add_participant(std::move(class_model_ptr));
167 }
168
169 return true;
170}

◆ VisitClassTemplateSpecializationDecl() [1/2]

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

Definition at line 186 of file translation_unit_visitor.cc.

188{
189 if (!should_include(cls))
190 return true;
191
192 LOG_DBG("= Visiting template specialization declaration {} at {} "
193 "(described class id {})",
194 cls->getQualifiedNameAsString(),
195 cls->getLocation().printToString(source_manager()),
196 cls->getSpecializedTemplate()
197 ? cls->getSpecializedTemplate()->getTemplatedDecl()->getID()
198 : 0);
199
200 // TODO: Add support for classes defined in function/method bodies
201 if (cls->isLocalClass() != nullptr)
202 return true;
203
204 auto template_specialization_ptr = process_template_specialization(cls);
205
206 if (!template_specialization_ptr)
207 return true;
208
209 auto &template_specialization = *template_specialization_ptr;
210
211 if (cls->hasDefinition()) {
212 // Process template specialization bases
213 process_class_bases(cls, template_specialization);
214
215 // Process class child entities
216 process_class_children(cls, template_specialization);
217 }
218
219 if (!template_specialization.template_specialization_found()) {
220 // Only do this if we haven't found a better specialization during
221 // construction of the template specialization
222 const eid_t ast_id{cls->getSpecializedTemplate()->getID()};
223 const auto maybe_id = id_mapper().get_global_id(ast_id);
224 if (maybe_id.has_value())
225 template_specialization.add_relationship(
226 {relationship_t::kInstantiation, maybe_id.value()});
227 }
228
229 if (diagram().should_include(template_specialization)) {
230 const auto full_name = template_specialization.full_name(false);
231 const auto id = template_specialization.id();
232
233 LOG_DBG("Adding class template specialization {} with id {}", full_name,
234 id);
235
236 add_class(std::move(template_specialization_ptr));
237 }
238
239 return true;
240}

◆ VisitClassTemplateSpecializationDecl() [2/2]

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

Definition at line 172 of file translation_unit_visitor.cc.

174{
175 if (!should_include(declaration))
176 return true;
177
178 LOG_TRACE("Visiting template specialization declaration {} at {}",
179 declaration->getQualifiedNameAsString(),
180 declaration->getLocation().printToString(source_manager()));
181
182 // TODO: Add support for classes defined in function/method bodies
183 if (declaration->isLocalClass() != nullptr)
184 return true;
185
186 auto template_specialization_ptr =
188
189 if (!template_specialization_ptr)
190 return true;
191
192 const auto class_full_name = template_specialization_ptr->full_name(false);
193 const auto id = common::to_id(class_full_name);
194
195 template_specialization_ptr->set_id(id);
196
197 set_unique_id(declaration->getID(), id);
198
199 if (!declaration->isCompleteDefinition()) {
200 forward_declarations_.emplace(
201 id, std::move(template_specialization_ptr));
202 return true;
203 }
204 forward_declarations_.erase(id);
205
206 if (diagram().should_include(*template_specialization_ptr)) {
207 LOG_DBG(
208 "Adding class template specialization participant {} with id {}",
209 class_full_name, id);
210
212 context().update(declaration);
213
214 diagram().add_participant(std::move(template_specialization_ptr));
215 }
216
217 return true;
218}

◆ VisitCXXConstructExpr()

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

Definition at line 1253 of file translation_unit_visitor.cc.

1255{
1261
1262 if (expr == nullptr)
1263 return true;
1264
1265 if (const auto *ctor = expr->getConstructor();
1266 ctor != nullptr && !should_include(ctor))
1267 return true;
1268
1269 LOG_TRACE("Visiting cxx construct expression at {} [caller_id = {}]",
1270 expr->getBeginLoc().printToString(source_manager()),
1271 context().caller_id());
1272
1273 message m{message_t::kCall, context().caller_id()};
1274
1275 m.in_static_declaration_context(within_static_variable_declaration_ > 0);
1276
1277 set_source_location(*expr, m);
1278
1279 if (context().is_expr_in_current_control_statement_condition(expr)) {
1280 m.set_message_scope(common::model::message_scope_t::kCondition);
1281 }
1282
1283 if (!process_construct_expression(m, expr))
1284 return true;
1285
1286 if (m.from().value() > 0 && m.to().value() > 0) {
1287 if (diagram().sequences().find(m.from()) ==
1288 diagram().sequences().end()) {
1289 activity a{m.from()};
1290 diagram().sequences().insert({m.from(), std::move(a)});
1291 }
1292
1293 diagram().add_active_participant(m.from());
1294 diagram().add_active_participant(m.to());
1295
1296 LOG_DBG("Found constructor call {} from {} [{}] to {} [{}] ",
1297 m.message_name(), m.from(), m.from(), m.to(), m.to());
1298
1299 push_message(expr, std::move(m));
1300 }
1301
1302 return true;
1303}

◆ VisitCXXMethodDecl()

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

Definition at line 236 of file translation_unit_visitor.cc.

238{
239 if (!should_include(declaration))
240 return true;
241
242 if (!declaration->isThisDeclarationADefinition()) {
243 if (auto *declaration_definition = declaration->getDefinition();
244 declaration_definition != nullptr) {
245 if (auto *method_definition = clang::dyn_cast<clang::CXXMethodDecl>(
246 declaration_definition);
247 method_definition != nullptr) {
248 LOG_DBG("Calling VisitCXXMethodDecl recursively for forward "
249 "declaration");
250
251 return VisitCXXMethodDecl(method_definition);
252 }
253 }
254 }
255
256 LOG_TRACE("Visiting method {} in class {} [{}]",
257 declaration->getQualifiedNameAsString(),
258 declaration->getParent()->getQualifiedNameAsString(),
259 (void *)declaration->getParent());
260
261 context().update(declaration);
262
263 auto method_model_ptr = create_method_model(declaration);
264
265 if (!method_model_ptr)
266 return true;
267
268 process_comment(*declaration, *method_model_ptr);
269
270 set_source_location(*declaration, *method_model_ptr);
271
272 const auto method_full_name = method_model_ptr->full_name(false);
273
274 method_model_ptr->set_id(common::to_id(method_full_name));
275
276 // Callee methods in call expressions are referred to by first declaration
277 // id, so they should both be mapped to method_model
278 if (declaration->isThisDeclarationADefinition()) {
280 declaration->getFirstDecl()->getID(), method_model_ptr->id());
281 }
282
283 set_unique_id(declaration->getID(), method_model_ptr->id());
284
285 LOG_TRACE("Set id {} --> {} for method name {} [{}]", declaration->getID(),
286 method_model_ptr->id(), method_full_name,
287 declaration->isThisDeclarationADefinition());
288
289 context().update(declaration);
290
291 context().set_caller_id(method_model_ptr->id());
292
293 diagram().add_participant(std::move(method_model_ptr));
294
295 return true;
296}

◆ VisitCXXRecordDecl() [1/3]

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

Definition at line 129 of file translation_unit_visitor.cc.

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

◆ VisitCXXRecordDecl() [2/3]

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

Definition at line 670 of file translation_unit_visitor.cc.

671{
672 if (!should_include(cls))
673 return true;
674
675 LOG_DBG("= Visiting class declaration {} at {}",
676 cls->getQualifiedNameAsString(),
677 cls->getLocation().printToString(source_manager()));
678
679 LOG_DBG(
680 "== getQualifiedNameAsString() = {}", cls->getQualifiedNameAsString());
681 if (cls->getOwningModule() != nullptr)
682 LOG_DBG(
683 "== getOwningModule()->Name = {}", cls->getOwningModule()->Name);
684 LOG_DBG("== getID() = {}", cls->getID());
685 LOG_DBG("== isTemplateDecl() = {}", cls->isTemplateDecl());
686 LOG_DBG("== isTemplated() = {}", cls->isTemplated());
687 LOG_DBG("== getParent()->isRecord()() = {}", cls->getParent()->isRecord());
688
689 if (const auto *parent_record =
690 clang::dyn_cast<clang::RecordDecl>(cls->getParent());
691 parent_record != nullptr) {
692 LOG_DBG("== getParent()->getQualifiedNameAsString() = {}",
693 parent_record->getQualifiedNameAsString());
694 }
695
696 if (has_processed_template_class(cls->getQualifiedNameAsString()))
697 // If we have already processed the template of this class
698 // skip it
699 return true;
700
701 if (cls->isTemplated() && (cls->getDescribedTemplate() != nullptr)) {
702 // If the described templated of this class is already in the model
703 // skip it:
704 const eid_t ast_id{cls->getDescribedTemplate()->getID()};
705 if (id_mapper().get_global_id(ast_id))
706 return true;
707 }
708
709 // TODO: Add support for classes defined in function/method bodies
710 if (cls->isLocalClass() != nullptr)
711 return true;
712
713 auto c_ptr = create_class_declaration(cls);
714
715 if (!c_ptr)
716 return true;
717
718 const auto cls_id = c_ptr->id();
719
720 id_mapper().add(cls->getID(), cls_id);
721
722 auto &class_model = diagram().find<class_>(cls_id).has_value()
723 ? *diagram().find<class_>(cls_id).get()
724 : *c_ptr;
725
726 if (cls->isCompleteDefinition() && !class_model.complete())
727 process_class_declaration(*cls, class_model);
728
729 auto id = class_model.id();
730 if (!cls->isCompleteDefinition()) {
731 forward_declarations_.emplace(id, std::move(c_ptr));
732 return true;
733 }
734 forward_declarations_.erase(id);
735
736 if (diagram().should_include(class_model)) {
737 LOG_DBG("Adding class {} with id {}", class_model.full_name(false),
738 class_model.id());
739
740 add_class(std::move(c_ptr));
741 }
742 else {
743 LOG_DBG("Skipping class {} with id {}", class_model.full_name(),
744 class_model.id());
745 }
746
747 return true;
748}

◆ VisitCXXRecordDecl() [3/3]

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

Definition at line 58 of file translation_unit_visitor.cc.

60{
61 if (!should_include(declaration))
62 return true;
63
64 // Skip this class if it's parent template is already in the model
65 if (declaration->isTemplated() &&
66 declaration->getDescribedTemplate() != nullptr) {
67 if (get_unique_id(eid_t{declaration->getDescribedTemplate()->getID()}))
68 return true;
69 }
70
71 // TODO: Add support for classes defined in function/method bodies
72 if (declaration->isLocalClass() != nullptr)
73 return true;
74
75 LOG_TRACE("Visiting class declaration at {}",
76 declaration->getBeginLoc().printToString(source_manager()));
77
78 // Build the class declaration and store it in the diagram, even
79 // if we don't need it for any of the participants of this diagram
80 auto class_model_ptr = create_class_model(declaration);
81
82 if (!class_model_ptr)
83 return true;
84
85 context().reset();
86
87 const auto class_id = class_model_ptr->id();
88
89 set_unique_id(declaration->getID(), class_id);
90
91 auto &class_model =
92 diagram()
93 .get_participant<sequence_diagram::model::class_>(class_id)
94 .has_value()
95 ? *diagram()
96 .get_participant<sequence_diagram::model::class_>(class_id)
97 .get()
98 : *class_model_ptr;
99
100 if (!declaration->isCompleteDefinition()) {
101 forward_declarations_.emplace(class_id, std::move(class_model_ptr));
102 return true;
103 }
104
105 forward_declarations_.erase(class_id);
106
107 if (diagram().should_include(class_model)) {
108 LOG_DBG("Adding class participant {} with id {}",
109 class_model.full_name(false), class_model.id());
110
111 assert(class_model.id() == class_id);
112
113 context().set_caller_id(class_id);
114 context().update(declaration);
115
116 diagram().add_participant(std::move(class_model_ptr));
117 }
118 else {
119 LOG_DBG(
120 "Skipping class {} with id {}", class_model.full_name(), class_id);
121 }
122
123 return true;
124}

◆ VisitEnumDecl() [1/2]

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

Definition at line 171 of file translation_unit_visitor.cc.

172{
173 assert(decl != nullptr);
174
175 // Skip system headers
176 if (source_manager().isInSystemHeader(decl->getSourceRange().getBegin()))
177 return true;
178
179 found_relationships_t relationships;
180
181 if (decl->isCompleteDefinition()) {
182 add_relationships(decl, relationships);
183 }
184
185 return true;
186}

◆ VisitEnumDecl() [2/2]

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

Definition at line 101 of file translation_unit_visitor.cc.

102{
103 assert(enm != nullptr);
104
105 // Anonymous enum values should be rendered as class fields
106 // with type enum
107 if (enm->getNameAsString().empty())
108 return true;
109
110 if (!should_include(enm))
111 return true;
112
113 LOG_DBG("= Visiting enum declaration {} at {}",
114 enm->getQualifiedNameAsString(),
115 enm->getLocation().printToString(source_manager()));
116
117 auto e_ptr = std::make_unique<enum_>(config().using_namespace());
118 auto &e = *e_ptr;
119
120 std::string qualified_name = common::get_qualified_name(*enm);
121
122 auto ns{common::get_tag_namespace(*enm)};
123
124 const auto *parent = enm->getParent();
125
126 // Id of parent class or struct in which this enum is potentially nested
127 std::optional<eid_t> parent_id_opt;
128
129 if (parent != nullptr) {
130 const auto *parent_record_decl =
131 clang::dyn_cast<clang::RecordDecl>(parent);
132
133 if (parent_record_decl != nullptr) {
134 eid_t local_id{parent_record_decl->getID()};
135
136 // First check if the parent has been added to the diagram as
137 // regular class
138 parent_id_opt = id_mapper().get_global_id(local_id);
139
140 // If not, check if the parent template declaration is in the model
141 if (!parent_id_opt) {
142 if (parent_record_decl->getDescribedTemplate() != nullptr) {
143 local_id =
144 parent_record_decl->getDescribedTemplate()->getID();
145 parent_id_opt = id_mapper().get_global_id(local_id);
146 }
147 }
148 }
149 }
150
151 if (parent_id_opt && diagram().find<class_>(*parent_id_opt)) {
152 auto parent_class = diagram().find<class_>(*parent_id_opt);
153
154 e.set_namespace(ns);
155 e.set_name(parent_class.value().name() + "##" + enm->getNameAsString());
156 e.set_id(common::to_id(e.full_name(false)));
157 e.add_relationship({relationship_t::kContainment, *parent_id_opt});
158 e.nested(true);
159 }
160 else {
161 e.set_name(common::get_tag_name(*enm));
162 e.set_namespace(ns);
163 e.set_id(common::to_id(e.full_name(false)));
164 }
165
166 id_mapper().add(enm->getID(), e.id());
167
168 process_comment(*enm, e);
169 set_source_location(*enm, e);
170 set_owning_module(*enm, e);
171
172 if (e.skip())
173 return true;
174
175 e.set_style(e.style_spec());
176
177 for (const auto &ev : enm->enumerators()) {
178 e.constants().push_back(ev->getNameAsString());
179 }
180
181 add_enum(std::move(e_ptr));
182
183 return true;
184}

◆ VisitFunctionDecl() [1/2]

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

Definition at line 314 of file translation_unit_visitor.cc.

316{
317 if (declaration->isCXXClassMember())
318 return true;
319
320 if (!should_include(declaration))
321 return true;
322
323 if (!declaration->isThisDeclarationADefinition()) {
324 if (auto *declaration_definition = declaration->getDefinition();
325 declaration_definition != nullptr)
326 return VisitFunctionDecl(
327 static_cast<clang::FunctionDecl *>(declaration_definition));
328 }
329
330 LOG_TRACE("Visiting function declaration {} at {}",
331 declaration->getQualifiedNameAsString(),
332 declaration->getLocation().printToString(source_manager()));
333
334 if (declaration->isTemplated()) {
335 if (declaration->getDescribedTemplate() != nullptr) {
336 // If the described templated of this function is already in the
337 // model skip it:
338 if (get_unique_id(
339 eid_t{declaration->getDescribedTemplate()->getID()}))
340 return true;
341 }
342 }
343
344 std::unique_ptr<model::function> function_model_ptr{};
345
346 if (declaration->isFunctionTemplateSpecialization()) {
347 function_model_ptr =
349 }
350 else {
351 function_model_ptr = build_function_model(*declaration);
352 }
353
354 if (!function_model_ptr)
355 return true;
356
357 function_model_ptr->set_id(
358 common::to_id(function_model_ptr->full_name(false)));
359
360 function_model_ptr->is_void(declaration->getReturnType()->isVoidType());
361
362 function_model_ptr->is_operator(declaration->isOverloadedOperator());
363
364 function_model_ptr->is_cuda_kernel(
365 common::has_attr(declaration, clang::attr::CUDAGlobal));
366
367 function_model_ptr->is_cuda_device(
368 common::has_attr(declaration, clang::attr::CUDADevice));
369
370 context().update(declaration);
371
372 context().set_caller_id(function_model_ptr->id());
373
374 if (declaration->isThisDeclarationADefinition()) {
376 declaration->getFirstDecl()->getID(), function_model_ptr->id());
377 }
378
379 set_unique_id(declaration->getID(), function_model_ptr->id());
380
381 process_comment(*declaration, *function_model_ptr);
382
383 set_source_location(*declaration, *function_model_ptr);
384
385 diagram().add_participant(std::move(function_model_ptr));
386
387 return true;
388}

◆ VisitFunctionDecl() [2/2]

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

Definition at line 105 of file translation_unit_visitor.cc.

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

◆ VisitFunctionTemplateDecl()

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

Definition at line 390 of file translation_unit_visitor.cc.

392{
393 if (!should_include(declaration))
394 return true;
395
396 const auto function_name = declaration->getQualifiedNameAsString();
397
398 LOG_TRACE("Visiting function template declaration {} at {}", function_name,
399 declaration->getLocation().printToString(source_manager()));
400
401 auto function_template_model = build_function_template(*declaration);
402
403 process_comment(*declaration, *function_template_model);
404
405 set_source_location(*declaration, *function_template_model);
406 set_owning_module(*declaration, *function_template_model);
407
408 function_template_model->is_void(
409 declaration->getAsFunction()->getReturnType()->isVoidType());
410
411 function_template_model->set_id(
412 common::to_id(function_template_model->full_name(false)));
413
414 function_template_model->is_operator(
415 declaration->getAsFunction()->isOverloadedOperator());
416
417 context().update(declaration);
418
419 context().set_caller_id(function_template_model->id());
420
421 set_unique_id(declaration->getID(), function_template_model->id());
422
423 diagram().add_participant(std::move(function_template_model));
424
425 return true;
426}

◆ VisitLambdaExpr()

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

Definition at line 428 of file translation_unit_visitor.cc.

429{
430 if (!should_include(expr))
431 return true;
432
433 const auto lambda_full_name =
434 expr->getLambdaClass()->getCanonicalDecl()->getNameAsString();
435
436 LOG_TRACE("Visiting lambda expression {} at {} [caller_id = {}]",
437 lambda_full_name, expr->getBeginLoc().printToString(source_manager()),
438 context().caller_id());
439
440 LOG_TRACE("Lambda call operator ID {} - lambda class ID {}, class call "
441 "operator ID {}",
442 expr->getCallOperator()->getID(), expr->getLambdaClass()->getID(),
443 expr->getLambdaClass()->getLambdaCallOperator()->getID());
444
445 // Create lambda class participant
446 auto *cls = expr->getLambdaClass();
447 auto lambda_class_model_ptr = create_class_model(cls);
448
449 if (!lambda_class_model_ptr)
450 return true;
451
452 const auto cls_id = lambda_class_model_ptr->id();
453
454 set_unique_id(cls->getID(), cls_id);
455
456 auto lambda_method_model_ptr =
457 create_lambda_method_model(expr->getCallOperator());
458
459 lambda_method_model_ptr->set_class_id(cls_id);
460
461 // If this is a nested lambda, prepend the parent lambda name to this lambda
462 auto lambda_class_full_name = lambda_class_model_ptr->full_name(false);
463 lambda_method_model_ptr->set_class_full_name(lambda_class_full_name);
464
465 diagram().add_participant(std::move(lambda_class_model_ptr));
466
467 lambda_method_model_ptr->set_id(
468 common::to_id(get_participant(cls_id).value().full_name(false) +
469 "::" + lambda_method_model_ptr->full_name_no_ns()));
470
471 get_participant<model::class_>(cls_id).value().set_lambda_operator_id(
472 lambda_method_model_ptr->id());
473
474 // If lambda expression is in an argument to a method/function, and that
475 // method function would be excluded by filters
476 if (std::holds_alternative<clang::CallExpr *>(
477 context().current_callexpr()) &&
478 (!context().lambda_caller_id().has_value())) {
481
482 message m{message_t::kCall, context().caller_id()};
483 set_source_location(*expr, m);
484 m.set_from(context().caller_id());
485 m.set_to(lambda_method_model_ptr->id());
486
487 diagram().add_active_participant(m.from());
488 diagram().add_active_participant(m.to());
489
490 LOG_DBG("Found call {} from {} [{}] to {} [{}]", m.message_name(),
491 m.from(), m.from(), m.to(), m.to());
492
493 push_message(std::get<clang::CallExpr *>(context().current_callexpr()),
494 std::move(m));
495 }
496
497 context().enter_lambda_expression(lambda_method_model_ptr->id());
498
500 expr->getCallOperator()->getID(), lambda_method_model_ptr->id());
501
502 diagram().add_participant(std::move(lambda_method_model_ptr));
503
504 [[maybe_unused]] const auto is_generic_lambda = expr->isGenericLambda();
505
506 return true;
507}

◆ 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 auto package_parent = package_path;
61
62 std::string name;
63 if (!package_path.is_empty())
64 name = package_path.name();
65
66 if (!package_parent.is_empty())
67 package_parent.pop_back();
68
69 const auto usn = config().using_namespace();
70
71 auto p = std::make_unique<common::model::package>(usn);
72 package_path = package_path.relative_to(usn);
73
74 p->set_name(name);
75 p->set_namespace(package_parent);
76 p->set_id(common::to_id(*ns));
77 id_mapper().add(ns->getID(), p->id());
78
79 if (config().filter_mode() == config::filter_mode_t::advanced ||
80 (diagram().should_include(*p) && !diagram().get(p->id()))) {
81 process_comment(*ns, *p);
82 set_source_location(*ns, *p);
83
84 p->set_style(p->style_spec());
85
86 for (const auto *attr : ns->attrs()) {
87 if (attr->getKind() == clang::attr::Kind::Deprecated) {
88 p->set_deprecated(true);
89 break;
90 }
91 }
92
93 if (!p->skip()) {
94 diagram().add(package_path, std::move(p));
95 }
96 }
97
98 return true;
99}

◆ VisitNamespaceDecl() [2/2]

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

Definition at line 44 of file translation_unit_visitor.cc.

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

◆ VisitRecordDecl() [1/2]

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

Definition at line 153 of file translation_unit_visitor.cc.

154{
155 assert(decl != nullptr);
156
157 // Skip system headers
158 if (source_manager().isInSystemHeader(decl->getSourceRange().getBegin()))
159 return true;
160
161 found_relationships_t relationships;
162
163 if (decl->isCompleteDefinition()) {
164 process_record_children(*decl, relationships);
165 add_relationships(decl, relationships);
166 }
167
168 return true;
169}

◆ 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 (clang::dyn_cast_or_null<clang::CXXRecordDecl>(rec) != nullptr)
339 // This is handled by VisitCXXRecordDecl()
340 return true;
341
342 // It seems we are in a C (not C++) translation unit
343 if (!should_include(rec))
344 return true;
345
346 LOG_DBG("= Visiting record declaration {} at {}",
347 rec->getQualifiedNameAsString(),
348 rec->getLocation().printToString(source_manager()));
349
350 auto record_ptr = create_record_declaration(rec);
351
352 if (!record_ptr)
353 return true;
354
355 const auto rec_id = record_ptr->id();
356
357 id_mapper().add(rec->getID(), rec_id);
358
359 auto &record_model = diagram().find<class_>(rec_id).has_value()
360 ? *diagram().find<class_>(rec_id).get()
361 : *record_ptr;
362
363 if (rec->isCompleteDefinition() && !record_model.complete()) {
364 process_record_members(rec, record_model);
365 record_model.complete(true);
366 }
367
368 auto id = record_model.id();
369 if (!rec->isCompleteDefinition()) {
370 forward_declarations_.emplace(id, std::move(record_ptr));
371 return true;
372 }
373 forward_declarations_.erase(id);
374
375 if (diagram().should_include(record_model)) {
376 LOG_DBG("Adding struct/union {} with id {}",
377 record_model.full_name(false), record_model.id());
378
379 add_class(std::move(record_ptr));
380 }
381 else {
382 LOG_DBG("Skipping struct/union {} with id {}", record_model.full_name(),
383 record_model.id());
384 }
385
386 return true;
387}

◆ VisitTypeAliasTemplateDecl()

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

Definition at line 242 of file translation_unit_visitor.cc.

244{
245 if (!should_include(cls))
246 return true;
247
248 LOG_DBG("= Visiting template type alias declaration {} at {}",
249 cls->getQualifiedNameAsString(),
250 cls->getLocation().printToString(source_manager()));
251
252 const auto *template_type_specialization_ptr =
253 cls->getTemplatedDecl()
254 ->getUnderlyingType()
255 ->getAs<clang::TemplateSpecializationType>();
256
257 if (template_type_specialization_ptr == nullptr)
258 return true;
259
260 auto template_specialization_ptr =
261 std::make_unique<class_>(config().using_namespace());
263 *template_specialization_ptr, cls, *template_type_specialization_ptr);
264
265 if (diagram().should_include(*template_specialization_ptr)) {
266 const auto name = template_specialization_ptr->full_name();
267 const auto id = template_specialization_ptr->id();
268
269 LOG_DBG("Adding class {} with id {}", name, id);
270
271 set_source_location(*cls, *template_specialization_ptr);
272 set_owning_module(*cls, *template_specialization_ptr);
273
274 add_class(std::move(template_specialization_ptr));
275 }
276
277 return true;
278}