Parse cpp_constructor
This commit is contained in:
parent
8691628ec5
commit
68c74a9f07
8 changed files with 136 additions and 14 deletions
|
|
@ -24,6 +24,11 @@ namespace cppast
|
|||
const cpp_entity_index& idx, cpp_entity_id id, std::string name,
|
||||
std::unique_ptr<cpp_type> type, std::unique_ptr<cpp_expression> 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<cpp_function_parameter> build(
|
||||
std::unique_ptr<cpp_type> type, std::unique_ptr<cpp_expression> def = nullptr);
|
||||
|
||||
private:
|
||||
cpp_function_parameter(std::string name, std::unique_ptr<cpp_type> type,
|
||||
std::unique_ptr<cpp_expression> def)
|
||||
|
|
|
|||
|
|
@ -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<cpp_constructor>
|
||||
{
|
||||
|
|
@ -284,6 +286,8 @@ namespace cppast
|
|||
|
||||
bool explicit_;
|
||||
bool constexpr_;
|
||||
|
||||
friend basic_builder<cpp_constructor>;
|
||||
};
|
||||
|
||||
/// A [cppast::cpp_entity]() modelling a C++ destructor.
|
||||
|
|
|
|||
|
|
@ -23,6 +23,13 @@ std::unique_ptr<cpp_function_parameter> cpp_function_parameter::build(
|
|||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<cpp_function_parameter> cpp_function_parameter::build(
|
||||
std::unique_ptr<cpp_type> type, std::unique_ptr<cpp_expression> def)
|
||||
{
|
||||
return std::unique_ptr<cpp_function_parameter>(
|
||||
new cpp_function_parameter("", std::move(type), std::move(def)));
|
||||
}
|
||||
|
||||
cpp_entity_kind cpp_function_parameter::do_get_entity_kind() const noexcept
|
||||
{
|
||||
return kind();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 <class Builder>
|
||||
|
|
@ -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: <attribute> <cv> <ref> <exception>
|
||||
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: <virtuals> <body>
|
||||
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<cpp_entity> detail::parse_cpp_conversion_op(const detail::parse_
|
|||
|
||||
return handle_suffix(context, cur, builder, stream, is_virtual);
|
||||
}
|
||||
|
||||
std::unique_ptr<cpp_entity> 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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,6 +94,8 @@ std::unique_ptr<cpp_entity> 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;
|
||||
|
|
|
|||
|
|
@ -91,6 +91,8 @@ namespace cppast
|
|||
const CXCursor& cur);
|
||||
std::unique_ptr<cpp_entity> parse_cpp_conversion_op(const parse_context& context,
|
||||
const CXCursor& cur);
|
||||
std::unique_ptr<cpp_entity> parse_cpp_constructor(const parse_context& context,
|
||||
const CXCursor& cur);
|
||||
|
||||
std::unique_ptr<cpp_entity> parse_entity(const parse_context& context, const CXCursor& cur);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<cpp_constructor>(*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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue