Add support for member pointer types

This commit is contained in:
Jonathan Müller 2017-02-23 15:39:12 +01:00
commit 23a7248964
4 changed files with 160 additions and 30 deletions

View file

@ -94,7 +94,7 @@ bool cppast::is_valid(const cpp_type& type) noexcept
{
auto& func = static_cast<const cpp_member_function_type&>(type);
if (func.class_type().kind() != cpp_type_kind::user_defined)
if (!can_compose(func.class_type()) || !is_valid(func.class_type()))
return false;
else if (!can_compose(func.return_type()) || !is_valid(func.return_type()))
return false;

View file

@ -59,6 +59,7 @@ namespace
}
// const/volatile at the end (because people do that apparently!)
// also used on member function pointers
cpp_cv suffix_cv(std::string& spelling)
{
auto cv = cpp_cv_none;
@ -207,6 +208,25 @@ namespace
size_expr.rend()));
}
std::unique_ptr<cpp_type> parse_type_impl(const detail::parse_context& context,
const CXType& type);
template <class Builder>
std::unique_ptr<cpp_type> add_parameters(Builder& builder, const detail::parse_context& context,
const CXType& type)
{
auto no_args = clang_getNumArgTypes(type);
DEBUG_ASSERT(no_args >= 0, detail::parse_error_handler{}, type,
"invalid number of arguments");
for (auto i = 0u; i != unsigned(no_args); ++i)
builder.add_parameter(parse_type_impl(context, clang_getArgType(type, i)));
if (clang_isFunctionTypeVariadic(type))
builder.is_variadic();
return builder.finish();
}
std::unique_ptr<cpp_type> try_parse_function_type(const detail::parse_context& context,
const CXType& type)
{
@ -215,18 +235,51 @@ namespace
// not a function type
return nullptr;
cpp_function_type::builder builder(parse_type(context, result));
cpp_function_type::builder builder(parse_type_impl(context, result));
return add_parameters(builder, context, type);
}
auto no_args = clang_getNumArgTypes(type);
DEBUG_ASSERT(no_args >= 0, detail::parse_error_handler{}, type,
"invalid number of arguments");
for (auto i = 0u; i != unsigned(no_args); ++i)
builder.add_parameter(detail::parse_type(context, clang_getArgType(type, i)));
cpp_reference member_function_ref_qualifier(std::string& spelling)
{
if (remove_suffix(spelling, "&&"))
return cpp_ref_rvalue;
else if (remove_suffix(spelling, "&"))
return cpp_ref_lvalue;
return cpp_ref_none;
}
if (clang_isFunctionTypeVariadic(type))
builder.is_variadic();
std::unique_ptr<cpp_type> make_ref_qualified(std::unique_ptr<cpp_type> type, cpp_reference ref)
{
if (ref == cpp_ref_none)
return std::move(type);
return cpp_reference_type::build(std::move(type), ref);
}
return builder.finish();
std::unique_ptr<cpp_type> parse_member_pointee_type(const detail::parse_context& context,
const CXType& type)
{
auto spelling = get_type_spelling(type);
auto ref = member_function_ref_qualifier(spelling);
auto cv = suffix_cv(spelling);
auto class_t = clang_Type_getClassType(type);
auto class_entity =
make_ref_qualified(make_cv_qualified(parse_type_impl(context, class_t), cv), ref);
auto pointee = clang_getPointeeType(type); // for everything except the class type
auto result = clang_getResultType(pointee);
if (result.kind == CXType_Invalid)
{
// member data pointer
return cpp_member_object_type::build(std::move(class_entity),
parse_type_impl(context, pointee));
}
else
{
cpp_member_function_type::builder builder(std::move(class_entity),
parse_type_impl(context, result));
return add_parameters(builder, context, pointee);
}
}
std::unique_ptr<cpp_type> parse_type_impl(const detail::parse_context& context,
@ -300,7 +353,7 @@ namespace
case CXType_Pointer:
{
auto pointee = parse_type(context, clang_getPointeeType(type));
auto pointee = parse_type_impl(context, clang_getPointeeType(type));
auto pointer = cpp_pointer_type::build(std::move(pointee));
auto spelling = get_type_spelling(type);
@ -310,7 +363,7 @@ namespace
case CXType_LValueReference:
case CXType_RValueReference:
{
auto referee = parse_type(context, clang_getPointeeType(type));
auto referee = parse_type_impl(context, clang_getPointeeType(type));
return cpp_reference_type::build(std::move(referee), get_reference_kind(type));
}
@ -320,7 +373,7 @@ namespace
case CXType_ConstantArray:
{
auto size = parse_array_size(type);
auto value_type = parse_type(context, clang_getArrayElementType(type));
auto value_type = parse_type_impl(context, clang_getArrayElementType(type));
return cpp_array_type::build(std::move(value_type), std::move(size));
}
@ -328,16 +381,18 @@ namespace
case CXType_FunctionProto:
return try_parse_function_type(context, type);
case CXType_MemberPointer:
return cpp_pointer_type::build(parse_member_pointee_type(context, type));
// TODO
case CXType_Dependent:
break;
case CXType_MemberPointer:
break;
case CXType_Auto:
break;
}
DEBUG_UNREACHABLE(detail::assert_handler{});
return nullptr;
}
}
@ -346,8 +401,7 @@ std::unique_ptr<cpp_type> detail::parse_type(const detail::parse_context& contex
const CXType& type) try
{
auto result = parse_type_impl(context, type);
DEBUG_ASSERT(result && is_valid(*result), detail::parse_error_handler{}, type,
"invalid type parsed");
DEBUG_ASSERT(result && is_valid(*result), detail::parse_error_handler{}, type, "invalid type");
return std::move(result);
}
catch (parse_error& ex)
@ -370,5 +424,7 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_type_alias(const detail::parse_con
detail::skip(stream, "=");
auto type = parse_type(context, clang_getTypedefDeclUnderlyingType(cur));
if (!type)
return nullptr;
return cpp_type_alias::build(*context.idx, get_entity_id(cur), name.c_str(), std::move(type));
}