diff --git a/src/sequence_diagram/visitor/translation_unit_visitor.cc b/src/sequence_diagram/visitor/translation_unit_visitor.cc index 8f04b263..b1b81a63 100644 --- a/src/sequence_diagram/visitor/translation_unit_visitor.cc +++ b/src/sequence_diagram/visitor/translation_unit_visitor.cc @@ -201,7 +201,7 @@ bool translation_unit_visitor::VisitClassTemplateSpecializationDecl( if (!diagram().should_include(cls->getQualifiedNameAsString())) return true; - LOG_DBG("= Visiting template specialization declaration {} at {}", + LOG_DBG("##### Visiting template specialization declaration {} at {}", cls->getQualifiedNameAsString(), cls->getLocation().printToString(source_manager())); @@ -251,6 +251,10 @@ bool translation_unit_visitor::VisitCXXMethodDecl(clang::CXXMethodDecl *m) nullptr) return true; + LOG_DBG("= Processing method {} in class {} [{}]", + m->getQualifiedNameAsString(), + m->getParent()->getQualifiedNameAsString(), (void *)m->getParent()); + call_expression_context_.update(m); auto m_ptr = std::make_unique( @@ -262,45 +266,24 @@ bool translation_unit_visitor::VisitCXXMethodDecl(clang::CXXMethodDecl *m) ns.pop_back(); m_ptr->set_name(ns.name()); ns.pop_back(); - // m_ptr->set_namespace(ns); - if (call_expression_context_.current_class_decl_) { - const auto ¤t_class = - diagram() - .get_participant(get_ast_local_id( - call_expression_context_.current_class_decl_->getID()) - .value()) - .value(); + clang::Decl *parent_decl = m->getParent(); - m_ptr->set_class_id(current_class.id()); - m_ptr->set_class_full_name(current_class.full_name(false)); - } - else if (call_expression_context_.current_class_template_decl_) { - const auto ¤t_template_class = - diagram() - .get_participant( - get_ast_local_id(call_expression_context_ - .current_class_template_decl_->getID()) - .value()) - .value(); + if (call_expression_context_.current_class_template_decl_) + parent_decl = call_expression_context_.current_class_template_decl_; - m_ptr->set_class_id(current_template_class.id()); - m_ptr->set_class_full_name(current_template_class.full_name(false)); - } - else { - const auto ¤t_template_specialization_class = - diagram() - .get_participant(get_ast_local_id( - call_expression_context_ - .current_class_template_specialization_decl_->getID()) - .value()) - .value(); + call_expression_context_.dump(); - m_ptr->set_class_id(current_template_specialization_class.id()); - m_ptr->set_class_full_name( - current_template_specialization_class.full_name(false)); - } + LOG_DBG("Getting method's class with local id {}", parent_decl->getID()); + const auto &method_class = + diagram() + .get_participant( + get_ast_local_id(parent_decl->getID()).value()) + .value(); + + m_ptr->set_class_id(method_class.id()); + m_ptr->set_class_full_name(method_class.full_name(false)); m_ptr->set_name( diagram().participants.at(m_ptr->class_id())->full_name_no_ns() + "::" + m->getNameAsString()); @@ -434,8 +417,6 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr) if (clang::dyn_cast_or_null(expr)) return true; - call_expression_context_.dump(); - if (!call_expression_context_.valid()) return true; @@ -480,27 +461,6 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr) LOG_DBG("Callee is a template specialization declaration {}", callee_template_specialization->getQualifiedNameAsString()); - if (!get_ast_local_id(callee_template_specialization->getID())) { - call_expression_context context_backup = - call_expression_context_; - - // Since this visitor will overwrite the - // call_expression_context_ we need to back it up and restore it - // later - VisitClassTemplateSpecializationDecl( - const_cast( - callee_template_specialization)); - - call_expression_context_ = context_backup; - - diagram() - .get_participant(get_ast_local_id( - callee_template_specialization->getID()) - .value()) - .value() - .set_implicit(true); - } - const auto &participant = diagram() .get_participant(get_ast_local_id( @@ -509,6 +469,7 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr) .value(); if (participant.is_implicit()) { + /* const auto *parent_template = callee_template_specialization->getSpecializedTemplate(); @@ -525,6 +486,32 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr) m.to = common::to_id(parent_method_name); m.message_name = participant.full_name_no_ns() + "::" + method_decl->getNameAsString(); + */ + const auto specialization_method_name = + participant.full_name(false) + + "::" + method_decl->getNameAsString(); + + m.to = common::to_id(method_name); + m.message_name = method_decl->getNameAsString(); + + // Since this is an implicit instantiation it might not exist + // so we have to create this participant here and it to the + // diagram + if (!diagram() + .get_participant(m.to) + .has_value()) { + auto m_ptr = + std::make_unique( + config().using_namespace()); + m_ptr->set_id(m.to); + m_ptr->set_method_name(method_decl->getNameAsString()); + m_ptr->set_name(method_decl->getNameAsString()); + m_ptr->set_class_id(participant.id()); + m_ptr->set_class_full_name(participant.full_name(false)); + set_ast_local_id(method_decl->getID(), m_ptr->id()); + diagram().add_active_participant(m_ptr->id()); + diagram().add_participant(std::move(m_ptr)); + } } else { const auto &specialization_participant = @@ -676,19 +663,14 @@ bool translation_unit_visitor::VisitCallExpr(clang::CallExpr *expr) callee_function->getTemplateSpecializationArgs()->size() > 0) { f_ptr = build_function_template_instantiation(*callee_function); - callee_name = f_ptr->full_name(false); - f_ptr->set_id(common::to_id(f_ptr->full_name(false))); set_ast_local_id(callee_function->getID(), f_ptr->id()); } - if (is_implicit) + if (is_implicit) { LOG_DBG("Processing implicit template specialization {}", f_ptr->full_name(false)); - // m.to_name = - // callee_function->getQualifiedNameAsString(); - if (is_implicit) { // If this is an implicit template specialization/instantiation // for now we just redirect the call to it's primary template // (TODO: this is not correct in a general case) @@ -1061,29 +1043,28 @@ void translation_unit_visitor:: // template arguments if (arg.getAsType()->getAs()) { - for (const auto ¶m_type : - arg.getAsType()->getAs()->param_types()) { - - if (!param_type->getAs()) - continue; - - // auto classTemplateSpecialization = - // llvm::dyn_cast( - // param_type->getAsRecordDecl()); - - // if (classTemplateSpecialization) { - // // Read arg info as needed. - // auto nested_template_instantiation = - // build_template_instantiation_from_class_template_specialization( - // *classTemplateSpecialization, - // *param_type->getAs(), - // diagram().should_include( - // full_template_specialization_name) - // ? - // std::make_optional(&template_instantiation) - // : parent); - // } - } +// for (const auto ¶m_type : +// arg.getAsType()->getAs()->param_types()) { +// +// if (!param_type->getAs()) +// continue; +// +// auto classTemplateSpecialization = +// llvm::dyn_cast( +// param_type->getAsRecordDecl()); +// +// if (classTemplateSpecialization) { +// // Read arg info as needed. +// auto nested_template_instantiation = +// build_template_instantiation_from_class_template_specialization( +// *classTemplateSpecialization, +// *param_type->getAs(), +// diagram().should_include( +// full_template_specialization_name) +// ? std::make_optional(&template_instantiation) +// : parent); +// } +// } } else if (arg.getAsType()->getAs()) { const auto *nested_template_type = diff --git a/src/sequence_diagram/visitor/translation_unit_visitor.h b/src/sequence_diagram/visitor/translation_unit_visitor.h index d9009c8a..1bd94353 100644 --- a/src/sequence_diagram/visitor/translation_unit_visitor.h +++ b/src/sequence_diagram/visitor/translation_unit_visitor.h @@ -122,10 +122,6 @@ struct call_expression_context { function->getQualifiedNameAsString()) { current_function_template_decl_ = nullptr; } - // else { - // call_expression_context_.current_class_method_ = - // process_class_method(method); - // } } void update(clang::FunctionTemplateDecl *function_template) @@ -180,6 +176,10 @@ public: clanguml::sequence_diagram::model::diagram &diagram, const clanguml::config::sequence_diagram &config); + bool shouldVisitTemplateInstantiations() { + return true; + } + virtual bool VisitCallExpr(clang::CallExpr *expr); virtual bool VisitCXXMethodDecl(clang::CXXMethodDecl *method); diff --git a/tests/t20004/test_case.h b/tests/t20004/test_case.h index 0d386f6b..89ee5353 100644 --- a/tests/t20004/test_case.h +++ b/tests/t20004/test_case.h @@ -32,27 +32,24 @@ TEST_CASE("t20004", "[test-case][sequence]") AliasMatcher _A(puml); REQUIRE_THAT(puml, StartsWith("@startuml")); - REQUIRE_THAT(puml, HasCall(_A("main()"), _A("m1()"), "m1")); - REQUIRE_THAT(puml, !HasCall(_A("m1()"), _A("m1()"), "m2")); - REQUIRE_THAT( - puml, !HasCall(_A("m1()"), _A("m1()"), "m2")); + REQUIRE_THAT(puml, HasCall(_A("main()"), _A("m1()"), "m1")); + REQUIRE_THAT(puml, !HasCall(_A("m1()"), _A("m1()"), "m2")); + REQUIRE_THAT(puml, !HasCall(_A("m1()"), _A("m1()"), "m2")); - REQUIRE_THAT(puml, - HasCall(_A("main()"), _A("m1()"), "m1")); + REQUIRE_THAT(puml, HasCall(_A("main()"), _A("m1()"), "m1")); REQUIRE_THAT(puml, HasCall(_A("m1()"), _A("m4()"), - "m4")); + "m4")); - REQUIRE_THAT(puml, - HasCall(_A("main()"), _A("m1()"), "m1")); + REQUIRE_THAT(puml, HasCall(_A("main()"), _A("m1()"), "m1")); REQUIRE_THAT(puml, HasCall(_A("m1()"), _A("m2()"), - "m2")); + "m2")); - REQUIRE_THAT(puml, HasCall(_A("main()"), _A("m1()"), "m1")); - REQUIRE_THAT(puml, HasCall(_A("m1()"), _A("m2()"), "m2")); - REQUIRE_THAT(puml, HasCall(_A("m2()"), _A("m3()"), "m3")); - REQUIRE_THAT(puml, HasCall(_A("m3()"), _A("m4()"), "m4")); + REQUIRE_THAT(puml, HasCall(_A("main()"), _A("m1()"), "m1")); + REQUIRE_THAT(puml, HasCall(_A("m1()"), _A("m2()"), "m2")); + REQUIRE_THAT(puml, HasCall(_A("m2()"), _A("m3()"), "m3")); + REQUIRE_THAT(puml, HasCall(_A("m3()"), _A("m4()"), "m4")); REQUIRE_THAT(puml, EndsWith("@enduml\n")); save_puml( diff --git a/tests/t20006/t20006.cc b/tests/t20006/t20006.cc index 20729063..d2dfc302 100644 --- a/tests/t20006/t20006.cc +++ b/tests/t20006/t20006.cc @@ -4,20 +4,41 @@ namespace clanguml { namespace t20006 { template struct A { - T a_int(T arg) { return arg + 1; } - T a_string(T arg) { return arg + "_string"; } + T a1(T arg) { return arg; } + T a2(T arg) { return arg + arg; } }; template struct B { - T b(T arg) { return a_.a_int(arg); } + T b(T arg) { return a_.a1(arg); } A a_; }; template <> struct B { - std::string b(std::string arg) { return a_.a_string(arg); } + std::string b(std::string arg) { return a_.a2(arg); } A a_; }; +template struct AA { + void aa1(T t) { } + void aa2(T t) { } +}; + + +template struct BB { + void bb1(T t, F f) { aa_.aa1(t); } + void bb2(T t, F f) { aa_.aa2(t); } + + AA aa_; +}; + +template struct BB { + void bb1(T t, std::string f) { aa_.aa2(t); } + void bb2(T t, std::string f) { aa_.aa1(t); } + + AA aa_; +}; + + void tmain() { B bint; @@ -25,6 +46,15 @@ void tmain() bint.b(1); bstring.b("bstring"); + + BB bbint; + BB bbstring; + + bbint.bb1(1, 1); + bbint.bb2(2, 2); + + bbstring.bb1(1, "calling aa2"); + bbstring.bb2(1, "calling aa1"); } } } \ No newline at end of file diff --git a/tests/t20006/test_case.h b/tests/t20006/test_case.h index 9c5e9c8d..539f8ffc 100644 --- a/tests/t20006/test_case.h +++ b/tests/t20006/test_case.h @@ -35,12 +35,28 @@ TEST_CASE("t20006", "[test-case][sequence]") REQUIRE_THAT(puml, EndsWith("@enduml\n")); // Check if all calls exist - REQUIRE_THAT(puml, HasCall(_A("tmain()"), _A("B"), "B::b")); - REQUIRE_THAT(puml, HasCall(_A("B"), _A("A"), "a_int")); + REQUIRE_THAT(puml, HasCall(_A("tmain()"), _A("B"), "b")); + REQUIRE_THAT(puml, HasCall(_A("B"), _A("A"), "a1")); REQUIRE_THAT(puml, HasCall(_A("tmain()"), _A("B"), "b")); - REQUIRE_THAT(puml, - HasCall(_A("B"), _A("A"), "A::a_string")); + REQUIRE_THAT( + puml, HasCall(_A("B"), _A("A"), "a2")); + + REQUIRE_THAT(puml, HasCall(_A("tmain()"), _A("BB"), "bb1")); + REQUIRE_THAT(puml, HasCall(_A("BB"), _A("AA"), "aa1")); + + REQUIRE_THAT(puml, HasCall(_A("tmain()"), _A("BB"), "bb2")); + REQUIRE_THAT(puml, HasCall(_A("BB"), _A("AA"), "aa2")); + + REQUIRE_THAT( + puml, HasCall(_A("tmain()"), _A("BB"), "bb1")); + REQUIRE_THAT( + puml, HasCall(_A("BB"), _A("AA"), "aa2")); + + REQUIRE_THAT( + puml, HasCall(_A("tmain()"), _A("BB"), "bb2")); + REQUIRE_THAT( + puml, HasCall(_A("BB"), _A("AA"), "aa1")); save_puml( "./" + config.output_directory() + "/" + diagram->name + ".puml", puml);