From 1bbc962b8c51c89381bbb062452d210a5454874b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20M=C3=BCller?= Date: Mon, 27 Mar 2017 11:51:30 +0200 Subject: [PATCH] Parse cpp_class_template_specialization --- include/cppast/cpp_class_template.hpp | 5 +-- src/cpp_class_template.cpp | 7 +++- src/libclang/class_parser.cpp | 7 +++- src/libclang/parse_functions.cpp | 4 ++ src/libclang/parse_functions.hpp | 6 +++ src/libclang/template_parser.cpp | 42 ++++++++++++++++++++ test/cpp_class_template.cpp | 55 +++++++++++++++++++++++++++ 7 files changed, 120 insertions(+), 6 deletions(-) diff --git a/include/cppast/cpp_class_template.hpp b/include/cppast/cpp_class_template.hpp index 5bae936..2a32454 100644 --- a/include/cppast/cpp_class_template.hpp +++ b/include/cppast/cpp_class_template.hpp @@ -44,14 +44,13 @@ namespace cppast class cpp_class_template_specialization final : public cpp_template_specialization { public: + static cpp_entity_kind kind() noexcept; + /// Builder for [cppast::cpp_class_template_specialization](). class builder : public specialization_builder { public: using specialization_builder::specialization_builder; - - private: - using specialization_builder::add_parameter; }; /// A reference to the class that is being specialized. diff --git a/src/cpp_class_template.cpp b/src/cpp_class_template.cpp index 263e8ac..4556e43 100644 --- a/src/cpp_class_template.cpp +++ b/src/cpp_class_template.cpp @@ -18,7 +18,12 @@ cpp_entity_kind cpp_class_template::do_get_entity_kind() const noexcept return kind(); } -cpp_entity_kind cpp_class_template_specialization::do_get_entity_kind() const noexcept +cpp_entity_kind cpp_class_template_specialization::kind() noexcept { return cpp_entity_kind::class_template_specialization_t; } + +cpp_entity_kind cpp_class_template_specialization::do_get_entity_kind() const noexcept +{ + return kind(); +} diff --git a/src/libclang/class_parser.cpp b/src/libclang/class_parser.cpp index 7acf38a..9f58e5d 100644 --- a/src/libclang/class_parser.cpp +++ b/src/libclang/class_parser.cpp @@ -104,12 +104,15 @@ std::unique_ptr detail::parse_cpp_class(const detail::parse_context& else if (kind == CXCursor_CXXFinalAttr) builder.is_final(); else if (kind == CXCursor_TemplateTypeParameter || kind == CXCursor_NonTypeTemplateParameter - || kind == CXCursor_TemplateTemplateParameter) + || kind == CXCursor_TemplateTemplateParameter || clang_isExpression(kind) + || clang_isReference(kind)) + // other children due to templates and stuff return; else if (auto entity = parse_entity(context, child)) builder.add_child(std::move(entity)); }); - auto is_templated = clang_getTemplateCursorKind(cur) != CXCursor_NoDeclFound; + auto is_templated = (clang_getTemplateCursorKind(cur) != CXCursor_NoDeclFound + || !clang_Cursor_isNull(clang_getSpecializedCursorTemplate(cur))); if (clang_isCursorDefinition(cur)) return is_templated ? builder.finish() : builder.finish(*context.idx, get_entity_id(cur)); else diff --git a/src/libclang/parse_functions.cpp b/src/libclang/parse_functions.cpp index 38af015..5fbf3ec 100644 --- a/src/libclang/parse_functions.cpp +++ b/src/libclang/parse_functions.cpp @@ -100,6 +100,8 @@ std::unique_ptr detail::parse_entity(const detail::parse_context& co case CXCursor_ClassDecl: case CXCursor_StructDecl: case CXCursor_UnionDecl: + if (auto spec = try_parse_full_cpp_class_template_specialization(context, cur)) + return spec; return parse_cpp_class(context, cur); case CXCursor_VarDecl: @@ -134,6 +136,8 @@ std::unique_ptr detail::parse_entity(const detail::parse_context& co return parse_cpp_function_template(context, cur); case CXCursor_ClassTemplate: return parse_cpp_class_template(context, cur); + case CXCursor_ClassTemplatePartialSpecialization: + return parse_cpp_class_template_specialization(context, cur); default: break; diff --git a/src/libclang/parse_functions.hpp b/src/libclang/parse_functions.hpp index a48b800..964a2dd 100644 --- a/src/libclang/parse_functions.hpp +++ b/src/libclang/parse_functions.hpp @@ -95,6 +95,10 @@ namespace cppast std::unique_ptr try_parse_cpp_function_template_specialization( const parse_context& context, const CXCursor& cur); + // on class cursors + std::unique_ptr try_parse_full_cpp_class_template_specialization( + const parse_context& context, const CXCursor& cur); + std::unique_ptr parse_cpp_namespace(const parse_context& context, const CXCursor& cur); std::unique_ptr parse_cpp_namespace_alias(const parse_context& context, @@ -135,6 +139,8 @@ namespace cppast const CXCursor& cur); std::unique_ptr parse_cpp_class_template(const parse_context& context, const CXCursor& cur); + std::unique_ptr parse_cpp_class_template_specialization( + const parse_context& context, const CXCursor& cur); // as_template: true, iff currently parsing a template std::unique_ptr parse_entity( diff --git a/src/libclang/template_parser.cpp b/src/libclang/template_parser.cpp index 3e01020..fb32eaa 100644 --- a/src/libclang/template_parser.cpp +++ b/src/libclang/template_parser.cpp @@ -355,3 +355,45 @@ std::unique_ptr detail::parse_cpp_class_template(const detail::parse return builder.finish(*context.idx, detail::get_entity_id(cur), builder.get().class_().is_definition()); } + +std::unique_ptr detail::try_parse_full_cpp_class_template_specialization( + const detail::parse_context& context, const CXCursor& cur) +{ + DEBUG_ASSERT(clang_getCursorKind(cur) == CXCursor_ClassDecl + || clang_getCursorKind(cur) == CXCursor_StructDecl + || clang_getCursorKind(cur) == CXCursor_UnionDecl, + detail::assert_handler{}); + + auto templ = clang_getSpecializedCursorTemplate(cur); + if (clang_Cursor_isNull(templ)) + return nullptr; + return detail::parse_cpp_class_template_specialization(context, cur); +} + +std::unique_ptr detail::parse_cpp_class_template_specialization( + const detail::parse_context& context, const CXCursor& cur) +{ + DEBUG_ASSERT(clang_getCursorKind(cur) == CXCursor_ClassTemplatePartialSpecialization + || clang_getCursorKind(cur) == CXCursor_ClassDecl + || clang_getCursorKind(cur) == CXCursor_StructDecl + || clang_getCursorKind(cur) == CXCursor_UnionDecl, + detail::assert_handler{}); + + auto primary = clang_getSpecializedCursorTemplate(cur); + auto c = detail::parse_cpp_class(context, cur); + if (!c) + return nullptr; + + // steal comment + auto comment = type_safe::copy(c->comment()); + c->set_comment(type_safe::nullopt); + + cpp_class_template_specialization::builder + builder(std::unique_ptr(static_cast(c.release())), + cpp_template_ref(detail::get_entity_id(primary), "")); + builder.get().set_comment(std::move(comment)); + parse_parameters(builder, context, cur); + parse_arguments(builder, context, cur); + return builder.finish(*context.idx, detail::get_entity_id(cur), + builder.get().class_().is_definition()); +} diff --git a/test/cpp_class_template.cpp b/test/cpp_class_template.cpp index 3b31647..a8de989 100644 --- a/test/cpp_class_template.cpp +++ b/test/cpp_class_template.cpp @@ -41,6 +41,20 @@ struct e template T func(U); }; + +// full specialization +template <> +class a {}; + +template <> +struct b<0, int> {}; + +// partial specialization +template +class a {}; + +template +struct b<0, T> {}; )"; cpp_entity_index idx; @@ -168,4 +182,45 @@ struct e } }); REQUIRE(count == 5u); + + count = test_visit( + *file, [&](const cpp_class_template_specialization& templ) { + REQUIRE(!templ.arguments_exposed()); + + if (templ.name() == "a") + { + REQUIRE(equal_ref(idx, templ.primary_template(), + cpp_template_ref(cpp_entity_id(""), "a"))); + if (templ.is_full_specialization()) + { + check_template_parameters(templ, {}); + REQUIRE(templ.unexposed_arguments() == "int"); + } + else + { + check_template_parameters(templ, + {{cpp_entity_kind::template_type_parameter_t, "T"}}); + REQUIRE(templ.unexposed_arguments() == "T*"); + } + } + else if (templ.name() == "b") + { + REQUIRE(equal_ref(idx, templ.primary_template(), + cpp_template_ref(cpp_entity_id(""), "b"))); + if (templ.is_full_specialization()) + { + check_template_parameters(templ, {}); + REQUIRE(templ.unexposed_arguments() == "0,int"); + } + else + { + check_template_parameters(templ, + {{cpp_entity_kind::template_type_parameter_t, "T"}}); + REQUIRE(templ.unexposed_arguments() == "0,T"); + } + } + else + REQUIRE(false); + }); + REQUIRE(count == 4u); }