From 68c74a9f07d932697353c3b7f65dfa532d37133c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20M=C3=BCller?= Date: Sun, 12 Mar 2017 18:18:26 +0100 Subject: [PATCH] Parse cpp_constructor --- include/cppast/cpp_function.hpp | 5 ++ include/cppast/cpp_member_function.hpp | 4 ++ src/cpp_function.cpp | 7 +++ src/cpp_member_function.cpp | 7 ++- src/libclang/function_parser.cpp | 75 +++++++++++++++++++++----- src/libclang/parse_functions.cpp | 2 + src/libclang/parse_functions.hpp | 2 + test/cpp_member_function.cpp | 48 +++++++++++++++++ 8 files changed, 136 insertions(+), 14 deletions(-) diff --git a/include/cppast/cpp_function.hpp b/include/cppast/cpp_function.hpp index b035205..6890f20 100644 --- a/include/cppast/cpp_function.hpp +++ b/include/cppast/cpp_function.hpp @@ -24,6 +24,11 @@ namespace cppast const cpp_entity_index& idx, cpp_entity_id id, std::string name, std::unique_ptr type, std::unique_ptr def = nullptr); + /// \returns A newly created unnamed function parameter. + /// \notes It will not be registered, as nothing can refer to it. + static std::unique_ptr build( + std::unique_ptr type, std::unique_ptr def = nullptr); + private: cpp_function_parameter(std::string name, std::unique_ptr type, std::unique_ptr def) diff --git a/include/cppast/cpp_member_function.hpp b/include/cppast/cpp_member_function.hpp index d28750d..b4f4fa2 100644 --- a/include/cppast/cpp_member_function.hpp +++ b/include/cppast/cpp_member_function.hpp @@ -243,6 +243,8 @@ namespace cppast class cpp_constructor final : public cpp_function_base { public: + static cpp_entity_kind kind() noexcept; + /// Builder for [cppast::cpp_constructor](). class builder : public basic_builder { @@ -284,6 +286,8 @@ namespace cppast bool explicit_; bool constexpr_; + + friend basic_builder; }; /// A [cppast::cpp_entity]() modelling a C++ destructor. diff --git a/src/cpp_function.cpp b/src/cpp_function.cpp index ab65060..ff96ade 100644 --- a/src/cpp_function.cpp +++ b/src/cpp_function.cpp @@ -23,6 +23,13 @@ std::unique_ptr cpp_function_parameter::build( return result; } +std::unique_ptr cpp_function_parameter::build( + std::unique_ptr type, std::unique_ptr def) +{ + return std::unique_ptr( + new cpp_function_parameter("", std::move(type), std::move(def))); +} + cpp_entity_kind cpp_function_parameter::do_get_entity_kind() const noexcept { return kind(); diff --git a/src/cpp_member_function.cpp b/src/cpp_member_function.cpp index 074fba1..5233c8d 100644 --- a/src/cpp_member_function.cpp +++ b/src/cpp_member_function.cpp @@ -28,11 +28,16 @@ cpp_entity_kind cpp_conversion_op::do_get_entity_kind() const noexcept return kind(); } -cpp_entity_kind cpp_constructor::do_get_entity_kind() const noexcept +cpp_entity_kind cpp_constructor::kind() noexcept { return cpp_entity_kind::constructor_t; } +cpp_entity_kind cpp_constructor::do_get_entity_kind() const noexcept +{ + return kind(); +} + cpp_entity_kind cpp_destructor::do_get_entity_kind() const noexcept { return cpp_entity_kind::destructor_t; diff --git a/src/libclang/function_parser.cpp b/src/libclang/function_parser.cpp index 7fb7e42..9ac10b0 100644 --- a/src/libclang/function_parser.cpp +++ b/src/libclang/function_parser.cpp @@ -26,8 +26,12 @@ namespace default_value = detail::parse_expression(context, child); }); - return cpp_function_parameter::build(*context.idx, detail::get_entity_id(cur), name.c_str(), - std::move(type), std::move(default_value)); + if (name.empty()) + return cpp_function_parameter::build(std::move(type), std::move(default_value)); + else + return cpp_function_parameter::build(*context.idx, detail::get_entity_id(cur), + name.c_str(), std::move(type), + std::move(default_value)); } template @@ -163,12 +167,14 @@ namespace return cpp_function_declaration; } - void parse_body(detail::token_stream& stream, suffix_info& result) + void parse_body(detail::token_stream& stream, suffix_info& result, bool allow_virtual) { auto pure_virtual = false; result.body_kind = parse_body_kind(stream, pure_virtual); if (pure_virtual) { + DEBUG_ASSERT(allow_virtual, detail::parse_error_handler{}, stream.cursor(), + "unexpected token"); if (result.virtual_keywords) result.virtual_keywords.value() &= cpp_virtual_flags::pure; else @@ -178,14 +184,18 @@ namespace // precondition: we've skipped the function parameters suffix_info parse_suffix_info(detail::token_stream& stream, - const detail::parse_context& context) + const detail::parse_context& context, bool allow_qualifier, + bool allow_virtual) { suffix_info result(stream.cursor()); // syntax: detail::skip_attribute(stream); - result.cv_qualifier = parse_cv(stream); - result.ref_qualifier = parse_ref(stream); + if (allow_qualifier) + { + result.cv_qualifier = parse_cv(stream); + result.ref_qualifier = parse_ref(stream); + } if (detail::skip_if(stream, "throw")) // just because I can detail::skip_brackets(stream); @@ -213,6 +223,8 @@ namespace detail::skip_brackets(stream); else if (detail::skip_if(stream, "override")) { + DEBUG_ASSERT(allow_virtual, detail::parse_error_handler{}, stream.cursor(), + "unexpected token"); if (result.virtual_keywords) result.virtual_keywords.value() |= cpp_virtual_flags::override; else @@ -220,13 +232,15 @@ namespace } else if (detail::skip_if(stream, "final")) { + DEBUG_ASSERT(allow_virtual, detail::parse_error_handler{}, stream.cursor(), + "unexpected token"); if (result.virtual_keywords) result.virtual_keywords.value() |= cpp_virtual_flags::final; else result.virtual_keywords = cpp_virtual_flags::final; } else if (detail::skip_if(stream, "=")) - parse_body(stream, result); + parse_body(stream, result, allow_virtual); else stream.bump(); } @@ -236,19 +250,23 @@ namespace // syntax: if (detail::skip_if(stream, "override")) { + DEBUG_ASSERT(allow_virtual, detail::parse_error_handler{}, stream.cursor(), + "unexpected token"); result.virtual_keywords = cpp_virtual_flags::override; if (detail::skip_if(stream, "final")) result.virtual_keywords.value() |= cpp_virtual_flags::final; } else if (detail::skip_if(stream, "final")) { + DEBUG_ASSERT(allow_virtual, detail::parse_error_handler{}, stream.cursor(), + "unexpected token"); result.virtual_keywords = cpp_virtual_flags::final; if (detail::skip_if(stream, "override")) result.virtual_keywords.value() |= cpp_virtual_flags::override; } if (detail::skip_if(stream, "=")) - parse_body(stream, result); + parse_body(stream, result, allow_virtual); } return result; @@ -277,10 +295,7 @@ namespace skip_parameters(stream); - auto suffix = parse_suffix_info(stream, context); - DEBUG_ASSERT(suffix.cv_qualifier == cpp_cv_none && suffix.ref_qualifier == cpp_ref_none - && !suffix.virtual_keywords, - detail::parse_error_handler{}, cur, "unexpected tokens in function suffix"); + auto suffix = parse_suffix_info(stream, context, false, false); if (suffix.noexcept_condition) builder.noexcept_condition(std::move(suffix.noexcept_condition)); @@ -363,7 +378,7 @@ namespace const CXCursor& cur, Builder& builder, detail::token_stream& stream, bool is_virtual) { - auto suffix = parse_suffix_info(stream, context); + auto suffix = parse_suffix_info(stream, context, true, true); builder.cv_ref_qualifier(suffix.cv_qualifier, suffix.ref_qualifier); if (suffix.noexcept_condition) builder.noexcept_condition(move(suffix.noexcept_condition)); @@ -445,3 +460,37 @@ std::unique_ptr detail::parse_cpp_conversion_op(const detail::parse_ return handle_suffix(context, cur, builder, stream, is_virtual); } + +std::unique_ptr detail::parse_cpp_constructor(const detail::parse_context& context, + const CXCursor& cur) +{ + DEBUG_ASSERT(clang_getCursorKind(cur) == CXCursor_Constructor, detail::assert_handler{}); + auto name = detail::get_cursor_name(cur); + + cpp_constructor::builder builder(name.c_str()); + add_parameters(context, builder, cur); + if (clang_Cursor_isVariadic(cur)) + builder.is_variadic(); + + detail::tokenizer tokenizer(context.tu, context.file, cur); + detail::token_stream stream(tokenizer, cur); + + // parse prefix + while (!detail::skip_if(stream, name.c_str())) + { + if (detail::skip_if(stream, "constexpr")) + builder.is_constexpr(); + else if (detail::skip_if(stream, "explicit")) + builder.is_explicit(); + else + stream.bump(); + } + + skip_parameters(stream); + + auto suffix = parse_suffix_info(stream, context, false, false); + if (suffix.noexcept_condition) + builder.noexcept_condition(std::move(suffix.noexcept_condition)); + + return builder.finish(*context.idx, detail::get_entity_id(cur), suffix.body_kind); +} diff --git a/src/libclang/parse_functions.cpp b/src/libclang/parse_functions.cpp index 808db5e..6f3d261 100644 --- a/src/libclang/parse_functions.cpp +++ b/src/libclang/parse_functions.cpp @@ -94,6 +94,8 @@ std::unique_ptr detail::parse_entity(const detail::parse_context& co return parse_cpp_member_function(context, cur); case CXCursor_ConversionFunction: return parse_cpp_conversion_op(context, cur); + case CXCursor_Constructor: + return parse_cpp_constructor(context, cur); default: break; diff --git a/src/libclang/parse_functions.hpp b/src/libclang/parse_functions.hpp index 8d7ab58..74132c8 100644 --- a/src/libclang/parse_functions.hpp +++ b/src/libclang/parse_functions.hpp @@ -91,6 +91,8 @@ namespace cppast const CXCursor& cur); std::unique_ptr parse_cpp_conversion_op(const parse_context& context, const CXCursor& cur); + std::unique_ptr parse_cpp_constructor(const parse_context& context, + const CXCursor& cur); std::unique_ptr parse_entity(const parse_context& context, const CXCursor& cur); } diff --git a/test/cpp_member_function.cpp b/test/cpp_member_function.cpp index 5a806dd..4b7041c 100644 --- a/test/cpp_member_function.cpp +++ b/test/cpp_member_function.cpp @@ -185,3 +185,51 @@ struct foo }); REQUIRE(count == 3u); } + +TEST_CASE("cpp_constructor") +{ + auto code = R"( +// only test constructor specific stuff +struct foo +{ + foo() noexcept = default; + explicit foo(int); + constexpr foo(int, char) = delete; +}; +)"; + + cpp_entity_index idx; + auto file = parse(idx, "cpp_constructor.cpp", code); + auto count = test_visit(*file, [&](const cpp_constructor& cont) { + REQUIRE(!cont.is_variadic()); + + if (count_children(cont) == 0u) + { + REQUIRE(cont.noexcept_condition()); + REQUIRE( + equal_expressions(cont.noexcept_condition().value(), + *cpp_literal_expression::build(cpp_builtin_type::build("bool"), + "true"))); + REQUIRE(!cont.is_explicit()); + REQUIRE(!cont.is_constexpr()); + REQUIRE(cont.body_kind() == cpp_function_defaulted); + } + else if (count_children(cont) == 1u) + { + REQUIRE(!cont.noexcept_condition()); + REQUIRE(cont.is_explicit()); + REQUIRE(!cont.is_constexpr()); + REQUIRE(cont.body_kind() == cpp_function_declaration); + } + else if (count_children(cont) == 2u) + { + REQUIRE(!cont.noexcept_condition()); + REQUIRE(!cont.is_explicit()); + REQUIRE(cont.is_constexpr()); + REQUIRE(cont.body_kind() == cpp_function_deleted); + } + else + REQUIRE(false); + }); + REQUIRE(count == 3u); +}