diff --git a/src/cx/cursor.h b/src/cx/cursor.h index 8e4edc63..8a6ddbc8 100644 --- a/src/cx/cursor.h +++ b/src/cx/cursor.h @@ -234,8 +234,32 @@ public: return clang_getSpecializedCursorTemplate(m_cursor); } + CXTranslationUnit translation_unit() const + { + return clang_Cursor_getTranslationUnit(m_cursor); + } + std::string usr() const { return to_string(clang_getCursorUSR(m_cursor)); } + CXSourceRange extent() const { return clang_getCursorExtent(m_cursor); } + + std::vector tokenize() const + { + auto range = extent(); + std::vector res; + CXToken *toks; + unsigned toks_count{0}; + auto tu = translation_unit(); + + clang_tokenize(tu, range, &toks, &toks_count); + + for (int i = 0; i < toks_count; i++) { + res.push_back(to_string(clang_getTokenSpelling(tu, toks[i]))); + } + + return res; + } + const CXCursor &get() const { return m_cursor; } private: diff --git a/src/uml/class_diagram_model.h b/src/uml/class_diagram_model.h index c747326d..fbac4341 100644 --- a/src/uml/class_diagram_model.h +++ b/src/uml/class_diagram_model.h @@ -110,6 +110,7 @@ struct class_template { std::string name; std::string type; std::string default_value; + bool is_variadic{false}; }; class class_ : public element { diff --git a/src/uml/class_diagram_visitor.h b/src/uml/class_diagram_visitor.h index 0d369ea7..bfee1e9d 100644 --- a/src/uml/class_diagram_visitor.h +++ b/src/uml/class_diagram_visitor.h @@ -330,12 +330,16 @@ static enum CXChildVisitResult class_visitor( ret = CXChildVisit_Continue; break; case CXCursor_TemplateTypeParameter: { - spdlog::info("Found template type parameter: {}: {}", - cursor.spelling(), cursor.type()); + const auto &tokens = cursor.tokenize(); + spdlog::info("Found template type parameter: {}: {}, [{}]", cursor, + cursor.type(), fmt::join(tokens, ", ")); class_template ct; ct.type = ""; - ct.name = cursor.spelling(); ct.default_value = ""; + ct.is_variadic = tokens.size() > 2 && tokens[1] == "..."; + ct.name = cursor.spelling(); + if (ct.is_variadic) + ct.name += "..."; ctx->element.templates.emplace_back(std::move(ct)); ret = CXChildVisit_Continue; diff --git a/tests/t00012/.clanguml b/tests/t00012/.clanguml new file mode 100644 index 00000000..82c7f1be --- /dev/null +++ b/tests/t00012/.clanguml @@ -0,0 +1,12 @@ +compilation_database_dir: .. +output_directory: puml +diagrams: + t00012_class: + type: class + glob: + - ../../tests/t00012/t00012.cc + using_namespace: + - clanguml::t00012 + include: + namespaces: + - clanguml::t00012 diff --git a/tests/t00012/t00012.cc b/tests/t00012/t00012.cc new file mode 100644 index 00000000..20fbc296 --- /dev/null +++ b/tests/t00012/t00012.cc @@ -0,0 +1,13 @@ +#include +#include +#include + +namespace clanguml { +namespace t00012 { + +template class A { + T value; + std::variant values; +}; +} +} diff --git a/tests/t00012/test_case.h b/tests/t00012/test_case.h new file mode 100644 index 00000000..fe770bbb --- /dev/null +++ b/tests/t00012/test_case.h @@ -0,0 +1,51 @@ +/** + * tests/t00012/test_case.cc + * + * Copyright (c) 2021 Bartek Kryza + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +TEST_CASE("Test t00012", "[unit-test]") +{ + spdlog::set_level(spdlog::level::debug); + + auto [config, db] = load_config("t00012"); + + auto diagram = config.diagrams["t00012_class"]; + + REQUIRE(diagram->name == "t00012_class"); + + REQUIRE(diagram->include.namespaces.size() == 1); + REQUIRE_THAT(diagram->include.namespaces, + VectorContains(std::string{"clanguml::t00012"})); + + REQUIRE(diagram->exclude.namespaces.size() == 0); + + REQUIRE(diagram->should_include("clanguml::t00012::A")); + REQUIRE(diagram->should_include("clanguml::t00012::B")); + + auto model = generate_class_diagram(db, diagram); + + REQUIRE(model.name == "t00012_class"); + + auto puml = generate_class_puml(diagram, model); + AliasMatcher _A(puml); + + REQUIRE_THAT(puml, StartsWith("@startuml")); + REQUIRE_THAT(puml, EndsWith("@enduml\n")); + REQUIRE_THAT(puml, IsClassTemplate("A", "T, Ts...")); + + save_puml( + "./" + config.output_directory + "/" + diagram->name + ".puml", puml); +} diff --git a/tests/test_cases.cc b/tests/test_cases.cc index 495ce895..9c8b770a 100644 --- a/tests/test_cases.cc +++ b/tests/test_cases.cc @@ -126,6 +126,7 @@ using clanguml::test::matchers::Static; #include "t00009/test_case.h" #include "t00010/test_case.h" #include "t00011/test_case.h" +#include "t00012/test_case.h" // // Sequence diagram tests