From 373717cc5e556f71b74be64aa959663a4bf581e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20M=C3=BCller?= Date: Sun, 6 Feb 2022 21:50:54 +0100 Subject: [PATCH] Fix multidimensional array of incomplete size Fixes #129. --- src/libclang/type_parser.cpp | 46 ++++++++---- test/cpp_type_alias.cpp | 142 ++++++++++++++++++----------------- 2 files changed, 103 insertions(+), 85 deletions(-) diff --git a/src/libclang/type_parser.cpp b/src/libclang/type_parser.cpp index 327d27b..c32327d 100644 --- a/src/libclang/type_parser.cpp +++ b/src/libclang/type_parser.cpp @@ -116,8 +116,10 @@ std::string get_type_spelling(const CXCursor& cur, const CXType& type) }; */ - // auto canonical = detail::cxstring(clang_getTypeSpelling(clang_getCanonicalType(type))).std_str(); - // auto declaration = detail::cxstring(clang_getCursorSpelling(clang_getTypeDeclaration(type))).std_str(); + // auto canonical = + // detail::cxstring(clang_getTypeSpelling(clang_getCanonicalType(type))).std_str(); auto + // declaration = + // detail::cxstring(clang_getCursorSpelling(clang_getTypeDeclaration(type))).std_str(); auto spelling = detail::cxstring(clang_getTypeSpelling(type)).std_str(); if (need_to_remove_scope(cur, type)) { @@ -270,16 +272,32 @@ std::unique_ptr parse_array_size(const CXCursor& cur, const CXTy type, "unexpected token"); std::string size_expr; - auto bracket_count = 1; - for (auto ptr = spelling.c_str() + spelling.size() - 2u; bracket_count != 0; --ptr) - { - if (*ptr == ']') - ++bracket_count; - else if (*ptr == '[') - --bracket_count; - if (bracket_count != 0) - size_expr += *ptr; + auto ptr = spelling.rbegin(); + while (true) + { + // Consume the final closing ]. + ++ptr; + + auto bracket_count = 1; + while (bracket_count != 0) + { + if (*ptr == ']') + ++bracket_count; + else if (*ptr == '[') + --bracket_count; + + if (bracket_count != 0) + size_expr += *ptr; + + ++ptr; + } + + if (ptr == spelling.rend() || *ptr != ']') + // We don't have another ]. + break; + // We do have another ], as we want the innermost, we need to restart. + size_expr.clear(); } return size_expr.empty() @@ -662,8 +680,7 @@ std::unique_ptr parse_type_impl(const detail::parse_context& context, cpp_type_ref(detail::get_entity_id(decl), std::move(spelling))); }); - case CXType_Pointer: - { + case CXType_Pointer: { auto pointee = parse_type_impl(context, cur, clang_getPointeeType(type)); auto pointer = cpp_pointer_type::build(std::move(pointee)); @@ -672,8 +689,7 @@ std::unique_ptr parse_type_impl(const detail::parse_context& context, return make_cv_qualified(std::move(pointer), cv); } case CXType_LValueReference: - case CXType_RValueReference: - { + case CXType_RValueReference: { auto referee = parse_type_impl(context, cur, clang_getPointeeType(type)); return cpp_reference_type::build(std::move(referee), get_reference_kind(type)); } diff --git a/test/cpp_type_alias.cpp b/test/cpp_type_alias.cpp index 53827b0..bf669b3 100644 --- a/test/cpp_type_alias.cpp +++ b/test/cpp_type_alias.cpp @@ -25,8 +25,7 @@ bool equal_types(const cpp_entity_index& idx, const cpp_type& parsed, const cpp_ return static_cast(parsed).builtin_type_kind() == static_cast(synthesized).builtin_type_kind(); - case cpp_type_kind::user_defined_t: - { + case cpp_type_kind::user_defined_t: { auto& user_parsed = static_cast(parsed); auto& user_synthesized = static_cast(synthesized); return equal_ref(idx, user_parsed.entity(), user_synthesized.entity()); @@ -40,8 +39,7 @@ bool equal_types(const cpp_entity_index& idx, const cpp_type& parsed, const cpp_ case cpp_type_kind::decltype_auto_t: return true; - case cpp_type_kind::cv_qualified_t: - { + case cpp_type_kind::cv_qualified_t: { auto& cv_a = static_cast(parsed); auto& cv_b = static_cast(synthesized); return cv_a.cv_qualifier() == cv_b.cv_qualifier() @@ -51,16 +49,14 @@ bool equal_types(const cpp_entity_index& idx, const cpp_type& parsed, const cpp_ case cpp_type_kind::pointer_t: return equal_types(idx, static_cast(parsed).pointee(), static_cast(synthesized).pointee()); - case cpp_type_kind::reference_t: - { + case cpp_type_kind::reference_t: { auto& ref_a = static_cast(parsed); auto& ref_b = static_cast(synthesized); return ref_a.reference_kind() == ref_b.reference_kind() && equal_types(idx, ref_a.referee(), ref_b.referee()); } - case cpp_type_kind::array_t: - { + case cpp_type_kind::array_t: { auto& array_a = static_cast(parsed); auto& array_b = static_cast(synthesized); @@ -71,14 +67,15 @@ bool equal_types(const cpp_entity_index& idx, const cpp_type& parsed, const cpp_ // check size if (!array_a.size().has_value() && !array_b.size().has_value()) return true; + else if (array_a.size().has_value() != array_b.size().has_value()) + return false; auto& size_a = array_a.size().value(); auto& size_b = array_b.size().value(); return equal_expressions(size_a, size_b); } - case cpp_type_kind::function_t: - { + case cpp_type_kind::function_t: { auto& func_a = static_cast(parsed); auto& func_b = static_cast(synthesized); @@ -98,8 +95,7 @@ bool equal_types(const cpp_entity_index& idx, const cpp_type& parsed, const cpp_ } return iter_a == func_a.parameter_types().end() && iter_b == func_b.parameter_types().end(); } - case cpp_type_kind::member_function_t: - { + case cpp_type_kind::member_function_t: { auto& func_a = static_cast(parsed); auto& func_b = static_cast(synthesized); @@ -121,8 +117,7 @@ bool equal_types(const cpp_entity_index& idx, const cpp_type& parsed, const cpp_ } return iter_a == func_a.parameter_types().end() && iter_b == func_b.parameter_types().end(); } - case cpp_type_kind::member_object_t: - { + case cpp_type_kind::member_object_t: { auto& obj_a = static_cast(parsed); auto& obj_b = static_cast(synthesized); @@ -131,15 +126,13 @@ bool equal_types(const cpp_entity_index& idx, const cpp_type& parsed, const cpp_ return equal_types(idx, obj_a.object_type(), obj_b.object_type()); } - case cpp_type_kind::template_parameter_t: - { + case cpp_type_kind::template_parameter_t: { auto& entity_parsed = static_cast(parsed).entity(); auto& entity_synthesized = static_cast(synthesized).entity(); return equal_ref(idx, entity_parsed, entity_synthesized); } - case cpp_type_kind::template_instantiation_t: - { + case cpp_type_kind::template_instantiation_t: { auto& inst_parsed = static_cast(parsed); auto& inst_synthesized = static_cast(synthesized); @@ -182,8 +175,7 @@ bool equal_types(const cpp_entity_index& idx, const cpp_type& parsed, const cpp_ return iter_a == inst_parsed.arguments().value().end() && iter_b == inst_synthesized.arguments().value().end(); } - case cpp_type_kind::dependent_t: - { + case cpp_type_kind::dependent_t: { auto& dep_a = static_cast(parsed); auto& dep_b = static_cast(synthesized); return dep_a.name() == dep_b.name() && equal_types(idx, dep_a.dependee(), dep_b.dependee()); @@ -242,6 +234,8 @@ using k = int[42]; using l = float*[]; /// using m=char[42]; using m = char[3 * 2 + 4 ? 42 : 43]; +/// using m2=char[][1]; +using m2 = char[][1]; // function pointers /// using n=void(*)(int); @@ -299,6 +293,7 @@ typedef e* j; typedef int k[42]; typedef float* l[]; typedef char m[3 * 2 + 4 ? 42 : 43]; +typedef char m2[][1]; // function pointers typedef void(*n)(int); @@ -343,78 +338,85 @@ typedef decltype(0) w; if (alias.name() == "a") { auto type = cpp_builtin_type::build(cpp_int); - REQUIRE(equal_types(idx, alias.underlying_type(), *type)); + CHECK(equal_types(idx, alias.underlying_type(), *type)); } else if (alias.name() == "b") { auto type = add_cv(cpp_builtin_type::build(cpp_longdouble), cpp_cv_const_volatile); - REQUIRE(equal_types(idx, alias.underlying_type(), *type)); + CHECK(equal_types(idx, alias.underlying_type(), *type)); } else if (alias.name() == "c") { auto type = cpp_pointer_type::build(cpp_builtin_type::build(cpp_int)); - REQUIRE(equal_types(idx, alias.underlying_type(), *type)); + CHECK(equal_types(idx, alias.underlying_type(), *type)); } else if (alias.name() == "d") { auto type = cpp_pointer_type::build(add_cv(cpp_builtin_type::build(cpp_uint), cpp_cv_const)); - REQUIRE(equal_types(idx, alias.underlying_type(), *type)); + CHECK(equal_types(idx, alias.underlying_type(), *type)); } else if (alias.name() == "e") { auto type = add_cv(cpp_pointer_type::build( - add_cv(cpp_builtin_type::build(cpp_uint), cpp_cv_const)), - cpp_cv_volatile); - REQUIRE(equal_types(idx, alias.underlying_type(), *type)); + add_cv(cpp_builtin_type::build(cpp_uint), cpp_cv_const)), + cpp_cv_volatile); + CHECK(equal_types(idx, alias.underlying_type(), *type)); } else if (alias.name() == "f") { auto type = cpp_reference_type::build(cpp_builtin_type::build(cpp_int), cpp_ref_lvalue); - REQUIRE(equal_types(idx, alias.underlying_type(), *type)); + CHECK(equal_types(idx, alias.underlying_type(), *type)); } else if (alias.name() == "g") { auto type = cpp_reference_type::build(add_cv(cpp_builtin_type::build(cpp_int), cpp_cv_const), - cpp_ref_rvalue); - REQUIRE(equal_types(idx, alias.underlying_type(), *type)); + cpp_ref_rvalue); + CHECK(equal_types(idx, alias.underlying_type(), *type)); } else if (alias.name() == "h") { auto type = cpp_user_defined_type::build(cpp_type_ref(cpp_entity_id(""), "c")); - REQUIRE(equal_types(idx, alias.underlying_type(), *type)); + CHECK(equal_types(idx, alias.underlying_type(), *type)); } else if (alias.name() == "i") { auto type = add_cv(cpp_user_defined_type::build(cpp_type_ref(cpp_entity_id(""), "d")), - cpp_cv_const); - REQUIRE(equal_types(idx, alias.underlying_type(), *type)); + cpp_cv_const); + CHECK(equal_types(idx, alias.underlying_type(), *type)); } else if (alias.name() == "j") { auto type = cpp_pointer_type::build( - cpp_user_defined_type::build(cpp_type_ref(cpp_entity_id(""), "e"))); - REQUIRE(equal_types(idx, alias.underlying_type(), *type)); + cpp_user_defined_type::build(cpp_type_ref(cpp_entity_id(""), "e"))); + CHECK(equal_types(idx, alias.underlying_type(), *type)); } else if (alias.name() == "k") { auto type = cpp_array_type::build(cpp_builtin_type::build(cpp_int), make_size("42", true)); - REQUIRE(equal_types(idx, alias.underlying_type(), *type)); + CHECK(equal_types(idx, alias.underlying_type(), *type)); } else if (alias.name() == "l") { auto type = cpp_array_type::build(cpp_pointer_type::build(cpp_builtin_type::build(cpp_float)), - nullptr); - REQUIRE(equal_types(idx, alias.underlying_type(), *type)); + nullptr); + CHECK(equal_types(idx, alias.underlying_type(), *type)); } else if (alias.name() == "m") { auto type = cpp_array_type::build(cpp_builtin_type::build(cpp_char), make_size("42", true)); - REQUIRE(equal_types(idx, alias.underlying_type(), *type)); + CHECK(equal_types(idx, alias.underlying_type(), *type)); + } + else if (alias.name() == "m2") + { + auto inner + = cpp_array_type::build(cpp_builtin_type::build(cpp_char), make_size("1", true)); + auto type = cpp_array_type::build(std::move(inner), nullptr); + CHECK(equal_types(idx, alias.underlying_type(), *type)); } else if (alias.name() == "n") { @@ -422,108 +424,108 @@ typedef decltype(0) w; builder.add_parameter(cpp_builtin_type::build(cpp_int)); auto type = cpp_pointer_type::build(builder.finish()); - REQUIRE(equal_types(idx, alias.underlying_type(), *type)); + CHECK(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(cpp_char))); + cpp_pointer_type::build(cpp_builtin_type::build(cpp_char))); builder.add_parameter( - cpp_reference_type::build(add_cv(cpp_builtin_type::build(cpp_int), cpp_cv_const), - cpp_ref_lvalue)); + cpp_reference_type::build(add_cv(cpp_builtin_type::build(cpp_int), cpp_cv_const), + 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)); + CHECK(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"))); + cpp_user_defined_type::build(cpp_type_ref(cpp_entity_id(""), "n"))); builder.add_parameter(cpp_builtin_type::build(cpp_int)); builder.add_parameter( - cpp_user_defined_type::build(cpp_type_ref(cpp_entity_id(""), "o"))); + 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)); + CHECK(equal_types(idx, alias.underlying_type(), *type)); } else if (alias.name() == "q") { cpp_member_function_type::builder builder(cpp_user_defined_type::build( - cpp_type_ref(cpp_entity_id(""), "foo")), - cpp_builtin_type::build(cpp_void)); + cpp_type_ref(cpp_entity_id(""), "foo")), + cpp_builtin_type::build(cpp_void)); builder.add_parameter(cpp_builtin_type::build(cpp_int)); auto type = cpp_pointer_type::build(builder.finish()); - REQUIRE(equal_types(idx, alias.underlying_type(), *type)); + CHECK(equal_types(idx, alias.underlying_type(), *type)); } else if (alias.name() == "r") { auto obj = cpp_reference_type::build(add_cv(cpp_user_defined_type::build( - cpp_type_ref(cpp_entity_id(""), "foo")), - cpp_cv_const), - cpp_ref_lvalue); + cpp_type_ref(cpp_entity_id(""), "foo")), + cpp_cv_const), + cpp_ref_lvalue); cpp_member_function_type::builder builder(std::move(obj), - cpp_builtin_type::build(cpp_void)); + cpp_builtin_type::build(cpp_void)); builder.add_parameter(cpp_builtin_type::build(cpp_int)); builder.is_variadic(); auto type = cpp_pointer_type::build(builder.finish()); - REQUIRE(equal_types(idx, alias.underlying_type(), *type)); + CHECK(equal_types(idx, alias.underlying_type(), *type)); } else if (alias.name() == "s") { // in old libclang version, the member type isn't exposed for some reason auto pointee = cpp_member_object_type::build(cpp_user_defined_type::build( - cpp_type_ref(cpp_entity_id(""), "foo")), - cpp_unexposed_type::build("int")); + cpp_type_ref(cpp_entity_id(""), "foo")), + cpp_unexposed_type::build("int")); auto type = cpp_pointer_type::build(std::move(pointee)); auto is_unexposed = equal_types(idx, alias.underlying_type(), *type); if (!is_unexposed) { pointee = cpp_member_object_type::build(cpp_user_defined_type::build( - cpp_type_ref(cpp_entity_id(""), "foo")), - cpp_builtin_type::build(cpp_int)); + cpp_type_ref(cpp_entity_id(""), "foo")), + cpp_builtin_type::build(cpp_int)); type = cpp_pointer_type::build(std::move(pointee)); auto is_builtin = equal_types(idx, alias.underlying_type(), *type); - REQUIRE(is_builtin); + CHECK(is_builtin); } } else if (alias.name() == "t") { auto type = cpp_user_defined_type::build(cpp_type_ref(cpp_entity_id(""), "t_")); - REQUIRE(equal_types(idx, alias.underlying_type(), *type)); + CHECK(equal_types(idx, alias.underlying_type(), *type)); return false; // inhibit comment check for next three entities // as they can't be documented (will always apply to the inline type) } else if (alias.name() == "u") { auto type = cpp_pointer_type::build( - add_cv(cpp_user_defined_type::build(cpp_type_ref(cpp_entity_id(""), "u_")), - cpp_cv_const)); - REQUIRE(equal_types(idx, alias.underlying_type(), *type)); + add_cv(cpp_user_defined_type::build(cpp_type_ref(cpp_entity_id(""), "u_")), + cpp_cv_const)); + CHECK(equal_types(idx, alias.underlying_type(), *type)); return false; } else if (alias.name() == "v") { auto type = cpp_user_defined_type::build(cpp_type_ref(cpp_entity_id(""), "")); - REQUIRE(equal_types(idx, alias.underlying_type(), *type)); + CHECK(equal_types(idx, alias.underlying_type(), *type)); return false; } else if (alias.name() == "w") { auto type = cpp_decltype_type::build( - cpp_unexposed_expression::build(cpp_builtin_type::build(cpp_int), - cpp_token_string::tokenize("0"))); - REQUIRE(equal_types(idx, alias.underlying_type(), *type)); + cpp_unexposed_expression::build(cpp_builtin_type::build(cpp_int), + cpp_token_string::tokenize("0"))); + CHECK(equal_types(idx, alias.underlying_type(), *type)); } else - REQUIRE(false); + CHECK(false); return check_code; }); - REQUIRE(count == 23u); + REQUIRE(count == 24u); }