diff --git a/include/cppast/cpp_array_type.hpp b/include/cppast/cpp_array_type.hpp index 808e7a9..2db9edd 100644 --- a/include/cppast/cpp_array_type.hpp +++ b/include/cppast/cpp_array_type.hpp @@ -15,6 +15,7 @@ namespace cppast { public: /// \returns A newly created array. + /// \notes `size` may be `nullptr`. static std::unique_ptr build(std::unique_ptr type, std::unique_ptr size) { @@ -28,10 +29,11 @@ namespace cppast return *type_; } - /// \returns A [cppast::cpp_expression]() that is the size of the array. - const cpp_expression& size() const noexcept + /// \returns An optional reference to the [cppast::cpp_expression]() that is the size of the array. + /// \notes An unsized array - `T[]` - does not have a size. + type_safe::optional_ref size() const noexcept { - return *size_; + return type_safe::opt_cref(size_.get()); } private: diff --git a/include/cppast/cpp_expression.hpp b/include/cppast/cpp_expression.hpp index a1e722c..8b8dbc0 100644 --- a/include/cppast/cpp_expression.hpp +++ b/include/cppast/cpp_expression.hpp @@ -58,7 +58,7 @@ namespace cppast /// An unexposed [cppast::cpp_expression](). /// /// There is no further information than a string available. - class cpp_unexposed_expression final : cpp_expression + class cpp_unexposed_expression final : public cpp_expression { public: /// \returns A newly created unexposed expression. @@ -90,7 +90,7 @@ namespace cppast }; /// A [cppast::cpp_expression]() that is a literal. - class cpp_literal_expression final : cpp_expression + class cpp_literal_expression final : public cpp_expression { public: /// \returns A newly created literal expression. diff --git a/src/libclang/type_parser.cpp b/src/libclang/type_parser.cpp index bcc978b..fa4e39f 100644 --- a/src/libclang/type_parser.cpp +++ b/src/libclang/type_parser.cpp @@ -5,6 +5,7 @@ #include "parse_functions.hpp" #include +#include #include #include #include @@ -174,6 +175,37 @@ namespace return cpp_ref_none; } + std::unique_ptr parse_array_size(const CXType& type) + { + auto size = clang_getArraySize(type); + if (size != -1) + return cpp_literal_expression::build(cpp_builtin_type::build("unsigned long long"), + std::to_string(size)); + + auto spelling = get_type_spelling(type); + DEBUG_ASSERT(spelling.size() > 2u && spelling.back() == ']', detail::parse_error_handler{}, + 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; + } + + return size_expr.empty() ? + nullptr : + cpp_unexposed_expression::build(cpp_builtin_type::build("unsigned long long"), + std::string(size_expr.rbegin(), + size_expr.rend())); + } + std::unique_ptr parse_type_impl(const detail::parse_context& context, const CXType& type) { @@ -255,15 +287,17 @@ namespace return cpp_reference_type::build(std::move(referee), get_reference_kind(type)); } - // TODO case CXType_IncompleteArray: case CXType_VariableArray: case CXType_DependentSizedArray: case CXType_ConstantArray: { - break; + auto size = parse_array_size(type); + auto value_type = parse_type_impl(context, clang_getArrayElementType(type)); + return cpp_array_type::build(std::move(value_type), std::move(size)); } + // TODO case CXType_Dependent: break; @@ -283,13 +317,18 @@ namespace } std::unique_ptr detail::parse_type(const detail::parse_context& context, - const CXType& type) + 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"); return std::move(result); } +catch (parse_error& ex) +{ + context.logger->log("libclang parser", ex.get_diagnostic()); + return nullptr; +} std::unique_ptr detail::parse_cpp_type_alias(const detail::parse_context& context, const CXCursor& cur) diff --git a/test/cpp_type_alias.cpp b/test/cpp_type_alias.cpp index 2bf6f68..599cf7a 100644 --- a/test/cpp_type_alias.cpp +++ b/test/cpp_type_alias.cpp @@ -4,6 +4,8 @@ #include +#include + #include "test_parser.hpp" using namespace cppast; @@ -49,9 +51,34 @@ bool equal_types(const cpp_entity_index& idx, const cpp_type& parsed, const cpp_ && equal_types(idx, ref_a.referee(), ref_b.referee()); } - // TODO case cpp_type_kind::array: - break; + { + auto& array_a = static_cast(parsed); + auto& array_b = static_cast(synthesized); + + // check value type + if (!equal_types(idx, array_a.value_type(), array_b.value_type())) + return false; + + // check size + if (!array_a.size().has_value() && !array_b.size().has_value()) + return true; + + auto& size_a = array_a.size().value(); + auto& size_b = array_b.size().value(); + if (size_a.kind() != size_b.kind()) + return false; + else if (size_a.kind() == cpp_expression_kind::literal) + return static_cast(size_a).value() + == static_cast(size_b).value(); + else if (size_a.kind() == cpp_expression_kind::unexposed) + return static_cast(size_a).expression() + == static_cast(size_b).expression(); + else + break; + } + + // TODO case cpp_type_kind::function: break; case cpp_type_kind::member_function: @@ -95,12 +122,25 @@ using g = const int&&; using h = c; using i = const d; using j = e*; + +// arrays +using k = int[42]; +using l = float*[]; +using m = char[3 * 2 + 4 ? 42 : 43]; )"; auto add_cv = [](std::unique_ptr type, cpp_cv cv) { return cpp_cv_qualified_type::build(std::move(type), cv); }; + auto make_size = [](std::string size, bool literal) -> std::unique_ptr { + auto type = cpp_builtin_type::build("unsigned long long"); + if (literal) + return cpp_literal_expression::build(std::move(type), std::move(size)); + else + return cpp_unexposed_expression::build(std::move(type), std::move(size)); + }; + cpp_entity_index idx; auto file = parse(idx, "cpp_type_alias.cpp", code); auto count = test_visit(*file, [&](const cpp_type_alias& alias) { @@ -161,8 +201,27 @@ using j = e*; cpp_user_defined_type::build(cpp_type_ref(cpp_entity_id(""), "e"))); REQUIRE(equal_types(idx, alias.underlying_type(), *type)); } + else if (alias.name() == "k") + { + auto type = + cpp_array_type::build(cpp_builtin_type::build("int"), make_size("42", true)); + REQUIRE(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("float")), + nullptr); + REQUIRE(equal_types(idx, alias.underlying_type(), *type)); + } + else if (alias.name() == "m") + { + auto type = + cpp_array_type::build(cpp_builtin_type::build("char"), make_size("42", true)); + REQUIRE(equal_types(idx, alias.underlying_type(), *type)); + } else REQUIRE(false); }); - REQUIRE(count == 10u); + REQUIRE(count == 13u); }