Add support for type definitions in using/alias
This commit is contained in:
parent
c87b296d4e
commit
a635f5dd05
5 changed files with 85 additions and 11 deletions
|
|
@ -31,11 +31,17 @@ std::unique_ptr<cpp_expression> detail::parse_expression(const detail::parse_con
|
||||||
|
|
||||||
auto type = parse_type(context, clang_getCursorType(cur));
|
auto type = parse_type(context, clang_getCursorType(cur));
|
||||||
auto expr = get_expression_str(stream);
|
auto expr = get_expression_str(stream);
|
||||||
|
if (kind == CXCursor_CallExpr && (expr.empty() || expr.back() != ')'))
|
||||||
if (kind == CXCursor_CharacterLiteral || kind == CXCursor_CompoundLiteralExpr
|
{
|
||||||
|| kind == CXCursor_FloatingLiteral || kind == CXCursor_ImaginaryLiteral
|
// we have a call expression that doesn't end in a closing parentheses
|
||||||
|| kind == CXCursor_IntegerLiteral || kind == CXCursor_StringLiteral
|
// this means default constructor, don't parse it at all
|
||||||
|| kind == CXCursor_CXXBoolLiteralExpr || kind == CXCursor_CXXNullPtrLiteralExpr)
|
// 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));
|
return cpp_literal_expression::build(std::move(type), std::move(expr));
|
||||||
else
|
else
|
||||||
return cpp_unexposed_expression::build(std::move(type), std::move(expr));
|
return cpp_unexposed_expression::build(std::move(type), std::move(expr));
|
||||||
|
|
|
||||||
|
|
@ -164,6 +164,12 @@ namespace
|
||||||
auto suffix = suffix_cv(spelling);
|
auto suffix = suffix_cv(spelling);
|
||||||
auto cv = merge_cv(prefix, suffix);
|
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));
|
auto entity = b(std::move(spelling));
|
||||||
return make_cv_qualified(std::move(entity), cv);
|
return make_cv_qualified(std::move(entity), cv);
|
||||||
}
|
}
|
||||||
|
|
@ -347,6 +353,8 @@ namespace
|
||||||
case CXType_Elaborated:
|
case CXType_Elaborated:
|
||||||
return make_leave_type(type, [&](std::string&& spelling) {
|
return make_leave_type(type, [&](std::string&& spelling) {
|
||||||
auto decl = clang_getTypeDeclaration(type);
|
auto decl = clang_getTypeDeclaration(type);
|
||||||
|
if (remove_prefix(spelling, "(anonymous"))
|
||||||
|
spelling = ""; // anonymous type
|
||||||
return cpp_user_defined_type::build(
|
return cpp_user_defined_type::build(
|
||||||
cpp_type_ref(detail::get_entity_id(decl), std::move(spelling)));
|
cpp_type_ref(detail::get_entity_id(decl), std::move(spelling)));
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ namespace
|
||||||
{
|
{
|
||||||
std::unique_ptr<cpp_expression> expression;
|
std::unique_ptr<cpp_expression> expression;
|
||||||
detail::visit_children(cur, [&](const CXCursor& child) {
|
detail::visit_children(cur, [&](const CXCursor& child) {
|
||||||
|
if (clang_isDeclaration(clang_getCursorKind(child)))
|
||||||
|
return;
|
||||||
DEBUG_ASSERT(clang_isExpression(child.kind) && !expression,
|
DEBUG_ASSERT(clang_isExpression(child.kind) && !expression,
|
||||||
detail::parse_error_handler{}, cur, "unexpected child cursor of variable");
|
detail::parse_error_handler{}, cur, "unexpected child cursor of variable");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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())
|
if (user_parsed.name() != user_synthesized.name())
|
||||||
return false;
|
return false;
|
||||||
auto entity = user_parsed.get(idx);
|
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:
|
case cpp_type_kind::cv_qualified:
|
||||||
|
|
@ -192,6 +193,11 @@ using r = void(foo::*)(int,...) const &;
|
||||||
|
|
||||||
// member data pointers
|
// member data pointers
|
||||||
using s = int(foo::*);
|
using s = int(foo::*);
|
||||||
|
|
||||||
|
// user-defined types inline definition
|
||||||
|
using t = struct t_ {};
|
||||||
|
using u = const struct u_ {}*;
|
||||||
|
using v = struct {};
|
||||||
)";
|
)";
|
||||||
}
|
}
|
||||||
SECTION("typedef")
|
SECTION("typedef")
|
||||||
|
|
@ -233,6 +239,11 @@ typedef void(foo::*r)(int,...) const &;
|
||||||
|
|
||||||
// member data pointers
|
// member data pointers
|
||||||
typedef int(foo::*s);
|
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));
|
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
|
else
|
||||||
REQUIRE(false);
|
REQUIRE(false);
|
||||||
});
|
});
|
||||||
REQUIRE(count == 19u);
|
REQUIRE(count == 22u);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ using namespace cppast;
|
||||||
TEST_CASE("cpp_variable")
|
TEST_CASE("cpp_variable")
|
||||||
{
|
{
|
||||||
auto code = R"(
|
auto code = R"(
|
||||||
// basic - global scope, so external storage
|
// basic
|
||||||
int a;
|
int a;
|
||||||
unsigned long long b = 42;
|
unsigned long long b = 42;
|
||||||
float c = 3.f + 0.14f;
|
float c = 3.f + 0.14f;
|
||||||
|
|
@ -24,6 +24,12 @@ thread_local static int g;
|
||||||
|
|
||||||
// constexpr
|
// constexpr
|
||||||
constexpr int h = 12;
|
constexpr int h = 12;
|
||||||
|
|
||||||
|
// inline definition
|
||||||
|
struct foo {} i;
|
||||||
|
const struct bar {} j = bar();
|
||||||
|
struct baz {} k{};
|
||||||
|
static struct {} l;
|
||||||
)";
|
)";
|
||||||
|
|
||||||
cpp_entity_index idx;
|
cpp_entity_index idx;
|
||||||
|
|
@ -43,11 +49,10 @@ constexpr int h = 12;
|
||||||
REQUIRE(var.is_constexpr() == is_constexpr);
|
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 int_type = cpp_builtin_type::build("int");
|
||||||
auto count = test_visit<cpp_variable>(*file, [&](const cpp_variable& var) {
|
auto count = test_visit<cpp_variable>(*file, [&](const cpp_variable& var) {
|
||||||
INFO(var.name());
|
|
||||||
if (var.name() == "a")
|
if (var.name() == "a")
|
||||||
check_variable(var, *int_type, nullptr, cpp_storage_class_none, false);
|
check_variable(var, *int_type, nullptr, cpp_storage_class_none, false);
|
||||||
else if (var.name() == "b")
|
else if (var.name() == "b")
|
||||||
|
|
@ -74,8 +79,33 @@ constexpr int h = 12;
|
||||||
cpp_cv_const),
|
cpp_cv_const),
|
||||||
*cpp_literal_expression::build(cpp_builtin_type::build("int"), "12"),
|
*cpp_literal_expression::build(cpp_builtin_type::build("int"), "12"),
|
||||||
cpp_storage_class_none, true);
|
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
|
else
|
||||||
REQUIRE(false);
|
REQUIRE(false);
|
||||||
});
|
});
|
||||||
REQUIRE(count == 8u);
|
REQUIRE(count == 12u);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue