From a635f5dd0569f93b529b57fd53c04e1944057646 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20M=C3=BCller?= Date: Thu, 2 Mar 2017 16:16:02 +0100 Subject: [PATCH] Add support for type definitions in using/alias --- src/libclang/expression_parser.cpp | 16 +++++++++---- src/libclang/type_parser.cpp | 8 +++++++ src/libclang/variable_parser.cpp | 2 ++ test/cpp_type_alias.cpp | 32 +++++++++++++++++++++++-- test/cpp_variable.cpp | 38 ++++++++++++++++++++++++++---- 5 files changed, 85 insertions(+), 11 deletions(-) diff --git a/src/libclang/expression_parser.cpp b/src/libclang/expression_parser.cpp index b9bb537..569a31e 100644 --- a/src/libclang/expression_parser.cpp +++ b/src/libclang/expression_parser.cpp @@ -31,11 +31,17 @@ std::unique_ptr detail::parse_expression(const detail::parse_con auto type = parse_type(context, clang_getCursorType(cur)); auto expr = get_expression_str(stream); - - if (kind == CXCursor_CharacterLiteral || kind == CXCursor_CompoundLiteralExpr - || kind == CXCursor_FloatingLiteral || kind == CXCursor_ImaginaryLiteral - || kind == CXCursor_IntegerLiteral || kind == CXCursor_StringLiteral - || kind == CXCursor_CXXBoolLiteralExpr || kind == CXCursor_CXXNullPtrLiteralExpr) + if (kind == CXCursor_CallExpr && (expr.empty() || expr.back() != ')')) + { + // we have a call expression that doesn't end in a closing parentheses + // this means default constructor, don't parse it at all + // so, for example a variable doesn't have a default value + return nullptr; + } + else if (kind == CXCursor_CharacterLiteral || kind == CXCursor_CompoundLiteralExpr + || kind == CXCursor_FloatingLiteral || kind == CXCursor_ImaginaryLiteral + || kind == CXCursor_IntegerLiteral || kind == CXCursor_StringLiteral + || kind == CXCursor_CXXBoolLiteralExpr || kind == CXCursor_CXXNullPtrLiteralExpr) return cpp_literal_expression::build(std::move(type), std::move(expr)); else return cpp_unexposed_expression::build(std::move(type), std::move(expr)); diff --git a/src/libclang/type_parser.cpp b/src/libclang/type_parser.cpp index 3d1698d..386d59b 100644 --- a/src/libclang/type_parser.cpp +++ b/src/libclang/type_parser.cpp @@ -164,6 +164,12 @@ namespace auto suffix = suffix_cv(spelling); auto cv = merge_cv(prefix, suffix); + // remove struct/class/union prefix on inline type definition + // i.e. C's typedef struct idiom + remove_prefix(spelling, "struct"); + remove_prefix(spelling, "class"); + remove_prefix(spelling, "union"); + auto entity = b(std::move(spelling)); return make_cv_qualified(std::move(entity), cv); } @@ -347,6 +353,8 @@ namespace case CXType_Elaborated: return make_leave_type(type, [&](std::string&& spelling) { auto decl = clang_getTypeDeclaration(type); + if (remove_prefix(spelling, "(anonymous")) + spelling = ""; // anonymous type return cpp_user_defined_type::build( cpp_type_ref(detail::get_entity_id(decl), std::move(spelling))); }); diff --git a/src/libclang/variable_parser.cpp b/src/libclang/variable_parser.cpp index 0846ed4..6fe5bd5 100644 --- a/src/libclang/variable_parser.cpp +++ b/src/libclang/variable_parser.cpp @@ -19,6 +19,8 @@ namespace { std::unique_ptr expression; detail::visit_children(cur, [&](const CXCursor& child) { + if (clang_isDeclaration(clang_getCursorKind(child))) + return; DEBUG_ASSERT(clang_isExpression(child.kind) && !expression, detail::parse_error_handler{}, cur, "unexpected child cursor of variable"); diff --git a/test/cpp_type_alias.cpp b/test/cpp_type_alias.cpp index 22d9d53..a0fe92e 100644 --- a/test/cpp_type_alias.cpp +++ b/test/cpp_type_alias.cpp @@ -29,7 +29,8 @@ bool equal_types(const cpp_entity_index& idx, const cpp_type& parsed, const cpp_ if (user_parsed.name() != user_synthesized.name()) return false; auto entity = user_parsed.get(idx); - return entity.has_value() && entity.value().name() == user_parsed.name(); + return entity.has_value() && entity.value().name().empty() + || entity.value().name() == user_parsed.name(); } case cpp_type_kind::cv_qualified: @@ -192,6 +193,11 @@ using r = void(foo::*)(int,...) const &; // member data pointers using s = int(foo::*); + +// user-defined types inline definition +using t = struct t_ {}; +using u = const struct u_ {}*; +using v = struct {}; )"; } SECTION("typedef") @@ -233,6 +239,11 @@ typedef void(foo::*r)(int,...) const &; // member data pointers typedef int(foo::*s); + +// user-defined types inline definition +typedef struct t_ {} t; +typedef const struct u_ {}* u; +typedef struct {} v; )"; } @@ -393,8 +404,25 @@ typedef int(foo::*s); REQUIRE(equal_types(idx, alias.underlying_type(), *type)); } + 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)); + } + 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)); + } + else if (alias.name() == "v") + { + auto type = cpp_user_defined_type::build(cpp_type_ref(cpp_entity_id(""), "v")); + REQUIRE(equal_types(idx, alias.underlying_type(), *type)); + } else REQUIRE(false); }); - REQUIRE(count == 19u); + REQUIRE(count == 22u); } diff --git a/test/cpp_variable.cpp b/test/cpp_variable.cpp index c4bb11f..90cf130 100644 --- a/test/cpp_variable.cpp +++ b/test/cpp_variable.cpp @@ -11,7 +11,7 @@ using namespace cppast; TEST_CASE("cpp_variable") { auto code = R"( -// basic - global scope, so external storage +// basic int a; unsigned long long b = 42; float c = 3.f + 0.14f; @@ -24,6 +24,12 @@ thread_local static int g; // constexpr constexpr int h = 12; + +// inline definition +struct foo {} i; +const struct bar {} j = bar(); +struct baz {} k{}; +static struct {} l; )"; cpp_entity_index idx; @@ -43,11 +49,10 @@ constexpr int h = 12; REQUIRE(var.is_constexpr() == is_constexpr); }; - auto file = parse({}, "cpp_variable.cpp", code); + auto file = parse(idx, "cpp_variable.cpp", code); auto int_type = cpp_builtin_type::build("int"); auto count = test_visit(*file, [&](const cpp_variable& var) { - INFO(var.name()); if (var.name() == "a") check_variable(var, *int_type, nullptr, cpp_storage_class_none, false); else if (var.name() == "b") @@ -74,8 +79,33 @@ constexpr int h = 12; cpp_cv_const), *cpp_literal_expression::build(cpp_builtin_type::build("int"), "12"), cpp_storage_class_none, true); + else if (var.name() == "i") + check_variable(var, + *cpp_user_defined_type::build(cpp_type_ref(cpp_entity_id(""), "foo")), + nullptr, cpp_storage_class_none, false); + else if (var.name() == "j") + check_variable(var, *cpp_cv_qualified_type::build(cpp_user_defined_type::build( + cpp_type_ref(cpp_entity_id(""), + "bar")), + cpp_cv_const), + *cpp_unexposed_expression::build(cpp_user_defined_type::build( + cpp_type_ref(cpp_entity_id(""), + "bar")), + "bar()"), + cpp_storage_class_none, false); + else if (var.name() == "k") + check_variable(var, + *cpp_user_defined_type::build(cpp_type_ref(cpp_entity_id(""), "baz")), + *cpp_unexposed_expression::build(cpp_user_defined_type::build( + cpp_type_ref(cpp_entity_id(""), + "baz")), + "{}"), + cpp_storage_class_none, false); + else if (var.name() == "l") + check_variable(var, *cpp_user_defined_type::build(cpp_type_ref(cpp_entity_id(""), "")), + nullptr, cpp_storage_class_static, false); else REQUIRE(false); }); - REQUIRE(count == 8u); + REQUIRE(count == 12u); }