diff --git a/include/cppast/cpp_entity_ref.hpp b/include/cppast/cpp_entity_ref.hpp index 6c2a8c2..0a63d07 100644 --- a/include/cppast/cpp_entity_ref.hpp +++ b/include/cppast/cpp_entity_ref.hpp @@ -11,23 +11,6 @@ namespace cppast { enum class cpp_entity_kind; - /// \exclude - namespace detail - { - void check_entity_cast_impl(const cpp_entity& e, cpp_entity_kind expected_kind); - - template - void check_entity_cast(const cpp_entity& e) - { - check_entity_cast_impl(e, T::kind()); - } - - template <> - inline void check_entity_cast(const cpp_entity&) - { - } - } // namespace detail - /// A basic reference to some kind of [cppast::cpp_entity](). template class basic_cpp_entity_ref @@ -57,7 +40,8 @@ namespace cppast auto entity = idx.lookup(target_); if (!entity) return type_safe::nullopt; - detail::check_entity_cast(entity.value()); + DEBUG_ASSERT(Predicate{}(entity.value()), detail::precondition_error_handler{}, + "predicate not fulfilled"); return static_cast(entity.value()); } diff --git a/src/cpp_entity_ref.cpp b/src/cpp_entity_ref.cpp deleted file mode 100644 index 6b67f31..0000000 --- a/src/cpp_entity_ref.cpp +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (C) 2017 Jonathan Müller -// This file is subject to the license terms in the LICENSE file -// found in the top-level directory of this distribution. - -#include - -#include - -using namespace cppast; - -void detail::check_entity_cast_impl(const cpp_entity& e, cpp_entity_kind expected_kind) -{ - DEBUG_ASSERT(e.kind() == expected_kind, detail::precondition_error_handler{}, - "mismatched entity kind"); -} diff --git a/src/libclang/type_parser.cpp b/src/libclang/type_parser.cpp index fa4e39f..3d03a1c 100644 --- a/src/libclang/type_parser.cpp +++ b/src/libclang/type_parser.cpp @@ -9,6 +9,7 @@ #include #include #include +#include using namespace cppast; @@ -206,6 +207,28 @@ namespace size_expr.rend())); } + std::unique_ptr try_parse_function_type(const detail::parse_context& context, + const CXType& type) + { + auto result = clang_getResultType(type); + if (result.kind == CXType_Invalid) + // not a function type + return nullptr; + + cpp_function_type::builder builder(parse_type(context, result)); + + 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))); + + if (clang_isFunctionTypeVariadic(type)) + builder.is_variadic(); + + return builder.finish(); + } + std::unique_ptr parse_type_impl(const detail::parse_context& context, const CXType& type) { @@ -231,6 +254,10 @@ namespace } // fallthrough case CXType_Unexposed: + if (auto ftype = try_parse_function_type(context, type)) + // guess what: after you've called clang_getPointeeType() on a function pointer + // you'll get an unexposed type + return ftype; return cpp_unexposed_type::build(get_type_spelling(type).c_str()); case CXType_Void: @@ -273,7 +300,7 @@ namespace case CXType_Pointer: { - auto pointee = parse_type_impl(context, clang_getPointeeType(type)); + auto pointee = parse_type(context, clang_getPointeeType(type)); auto pointer = cpp_pointer_type::build(std::move(pointee)); auto spelling = get_type_spelling(type); @@ -283,7 +310,7 @@ namespace case CXType_LValueReference: case CXType_RValueReference: { - auto referee = parse_type_impl(context, clang_getPointeeType(type)); + auto referee = parse_type(context, clang_getPointeeType(type)); return cpp_reference_type::build(std::move(referee), get_reference_kind(type)); } @@ -293,18 +320,17 @@ namespace case CXType_ConstantArray: { auto size = parse_array_size(type); - auto value_type = parse_type_impl(context, clang_getArrayElementType(type)); + auto value_type = parse_type(context, clang_getArrayElementType(type)); return cpp_array_type::build(std::move(value_type), std::move(size)); } + case CXType_FunctionNoProto: + case CXType_FunctionProto: + return try_parse_function_type(context, type); + // TODO case CXType_Dependent: break; - - case CXType_FunctionNoProto: - break; - case CXType_FunctionProto: - break; case CXType_MemberPointer: break; diff --git a/test/cpp_type_alias.cpp b/test/cpp_type_alias.cpp index 599cf7a..7b5a572 100644 --- a/test/cpp_type_alias.cpp +++ b/test/cpp_type_alias.cpp @@ -5,6 +5,7 @@ #include #include +#include #include "test_parser.hpp" @@ -78,9 +79,29 @@ bool equal_types(const cpp_entity_index& idx, const cpp_type& parsed, const cpp_ break; } - // TODO case cpp_type_kind::function: - break; + { + auto& func_a = static_cast(parsed); + auto& func_b = static_cast(synthesized); + + if (!equal_types(idx, func_a.return_type(), func_b.return_type())) + return false; + else if (func_a.is_variadic() != func_b.is_variadic()) + return false; + + auto iter_a = func_a.parameter_types().begin(); + auto iter_b = func_a.parameter_types().begin(); + while (iter_a != func_a.parameter_types().end() && iter_b != func_b.parameter_types().end()) + { + if (!equal_types(idx, *iter_a, *iter_b)) + return false; + ++iter_a; + ++iter_b; + } + return iter_a == func_a.parameter_types().end() && iter_b == func_b.parameter_types().end(); + } + + // TODO case cpp_type_kind::member_function: break; case cpp_type_kind::member_object: @@ -127,6 +148,11 @@ using j = e*; using k = int[42]; using l = float*[]; using m = char[3 * 2 + 4 ? 42 : 43]; + +// function pointers +using n = void(*)(int); +using o = char*(&)(int&,...); +using p = n(*)(int, o); )"; auto add_cv = [](std::unique_ptr type, cpp_cv cv) { @@ -220,8 +246,38 @@ using m = char[3 * 2 + 4 ? 42 : 43]; cpp_array_type::build(cpp_builtin_type::build("char"), make_size("42", true)); REQUIRE(equal_types(idx, alias.underlying_type(), *type)); } + else if (alias.name() == "n") + { + cpp_function_type::builder builder(cpp_builtin_type::build("void")); + builder.add_parameter(cpp_builtin_type::build("int")); + auto type = cpp_pointer_type::build(builder.finish()); + + REQUIRE(equal_types(idx, alias.underlying_type(), *type)); + } + else if (alias.name() == "o") + { + cpp_function_type::builder builder( + cpp_pointer_type::build(cpp_builtin_type::build("char"))); + builder.add_parameter( + cpp_reference_type::build(cpp_builtin_type::build("int"), cpp_ref_lvalue)); + builder.is_variadic(); + auto type = cpp_reference_type::build(builder.finish(), cpp_ref_lvalue); + + REQUIRE(equal_types(idx, alias.underlying_type(), *type)); + } + else if (alias.name() == "p") + { + cpp_function_type::builder builder( + cpp_user_defined_type::build(cpp_type_ref(cpp_entity_id(""), "n"))); + builder.add_parameter(cpp_builtin_type::build("int")); + builder.add_parameter( + cpp_user_defined_type::build(cpp_type_ref(cpp_entity_id(""), "o"))); + auto type = cpp_pointer_type::build(builder.finish()); + + REQUIRE(equal_types(idx, alias.underlying_type(), *type)); + } else REQUIRE(false); }); - REQUIRE(count == 13u); + REQUIRE(count == 16u); }