1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-14 06:14:58 +00:00

LibCpp: Support for parsing c-style fixed arrays (arr[2])

Also adds tests for finding declaration of arrays inside
CppComprehension which requires proper parsing for passing.

Side-effect of this patch: if we ctrl+click on array variables, it
should jump to the correct declaration inside HackStudio.
This commit is contained in:
iyush 2023-04-15 16:40:40 +02:00 committed by Sam Atkins
parent 34b04271f4
commit ac435f914c
7 changed files with 184 additions and 8 deletions

View file

@ -33,6 +33,12 @@ static bool s_some_test_failed = false;
return; \
} while (0)
#define RUN(function) \
function; \
if (s_some_test_failed) { \
return 1; \
}
constexpr auto TESTS_ROOT_DIR = "/home/anon/Tests/cpp-tests/comprehension"sv;
class FileDB : public CodeComprehension::FileDB {
@ -61,18 +67,24 @@ static void test_complete_local_args();
static void test_complete_local_vars();
static void test_complete_type();
static void test_find_variable_definition();
static void test_find_array_variable_declaration_single();
static void test_find_array_variable_declaration_single_empty();
static void test_find_array_variable_declaration_double();
static void test_complete_includes();
static void test_parameters_hint();
int run_tests()
{
test_complete_local_args();
test_complete_local_vars();
test_complete_type();
test_find_variable_definition();
test_complete_includes();
test_parameters_hint();
return s_some_test_failed ? 1 : 0;
RUN(test_complete_local_args());
RUN(test_complete_local_vars());
RUN(test_complete_type());
RUN(test_find_variable_definition());
RUN(test_find_array_variable_declaration_single());
RUN(test_find_array_variable_declaration_single_empty());
RUN(test_find_array_variable_declaration_double());
RUN(test_complete_includes());
RUN(test_parameters_hint());
return 0;
}
static void add_file(FileDB& filedb, DeprecatedString const& name)
@ -145,6 +157,60 @@ void test_find_variable_definition()
FAIL("wrong declaration location");
}
void test_find_array_variable_declaration_single()
{
I_TEST(Find 1D Array as a Variable Declaration)
FileDB filedb;
auto filename = "find_array_variable_declaration.cpp";
add_file(filedb, filename);
CodeComprehension::Cpp::CppComprehensionEngine engine(filedb);
auto position = engine.find_declaration_of(filename, { 3, 6 });
if (!position.has_value())
FAIL("declaration not found");
if (position.value().file == filename && position.value().line == 2 && position.value().column >= 4)
PASS;
printf("Found at position %zu %zu\n", position.value().line, position.value().column);
FAIL("wrong declaration location");
}
void test_find_array_variable_declaration_single_empty()
{
I_TEST(Find 1D Empty size Array as a Variable Declaration)
FileDB filedb;
auto filename = "find_array_variable_declaration.cpp";
add_file(filedb, filename);
CodeComprehension::Cpp::CppComprehensionEngine engine(filedb);
auto position = engine.find_declaration_of(filename, { 6, 6 });
if (!position.has_value())
FAIL("declaration not found");
if (position.value().file == filename && position.value().line == 5 && position.value().column >= 4)
PASS;
printf("Found at position %zu %zu\n", position.value().line, position.value().column);
FAIL("wrong declaration location");
}
void test_find_array_variable_declaration_double()
{
I_TEST(Find 2D Array as a Variable Declaration)
FileDB filedb;
auto filename = "find_array_variable_declaration.cpp";
add_file(filedb, filename);
CodeComprehension::Cpp::CppComprehensionEngine engine(filedb);
auto position = engine.find_declaration_of(filename, { 9, 6 });
if (!position.has_value())
FAIL("declaration not found");
if (position.value().file == filename && position.value().line == 8 && position.value().column >= 4)
PASS;
printf("Found at position %zu %zu\n", position.value().line, position.value().column);
FAIL("wrong declaration location");
}
void test_complete_includes()
{
I_TEST(Complete include statements)

View file

@ -0,0 +1,11 @@
void foo()
{
int arr[2] = {1,2};
arr[1] = 0;
int arr2[] = {5,6};
arr2[0] = 11;
int arr3[1][2] = {{3,4}};
arr3[0][0] = 72;
}

View file

@ -572,6 +572,24 @@ StringView TemplatizedName::full_name() const
return *m_full_name;
}
void SizedName::dump(FILE* output, size_t indent) const
{
Name::dump(output, indent);
print_indent(output, indent + 1);
StringBuilder dimension_info;
for (auto const& dim : m_dimensions) {
dimension_info.append('[');
dimension_info.append(dim);
dimension_info.append(']');
}
if (dimension_info.is_empty()) {
dimension_info.append("[]"sv);
}
outln(output, "{}", dimension_info.to_deprecated_string());
}
void CppCastExpression::dump(FILE* output, size_t indent) const
{
ASTNode::dump(output, indent);

View file

@ -434,6 +434,7 @@ public:
virtual void dump(FILE* = stdout, size_t indent = 0) const override;
virtual bool is_name() const override { return true; }
virtual bool is_templatized() const { return false; }
virtual bool is_sized() const { return false; }
Name(ASTNode const* parent, Optional<Position> start, Optional<Position> end, DeprecatedString const& filename)
: Expression(parent, start, end, filename)
@ -453,6 +454,25 @@ private:
mutable Optional<DeprecatedString> m_full_name;
};
class SizedName : public Name {
public:
virtual ~SizedName() override = default;
virtual StringView class_name() const override { return "SizedName"sv; }
virtual bool is_sized() const override { return true; }
void dump(FILE* output, size_t indent) const override;
SizedName(ASTNode const* parent, Optional<Position> start, Optional<Position> end, DeprecatedString const& filename)
: Name(parent, start, end, filename)
{
}
void append_dimension(StringView dim) { m_dimensions.append(dim); };
private:
Vector<StringView> m_dimensions;
mutable Optional<DeprecatedString> m_full_name;
};
class TemplatizedName : public Name {
public:
virtual ~TemplatizedName() override = default;
@ -1020,5 +1040,6 @@ template<>
inline bool ASTNode::fast_is<NamedType>() const { return is_type() && verify_cast<Type>(*this).is_named_type(); }
template<>
inline bool ASTNode::fast_is<TemplatizedName>() const { return is_name() && verify_cast<Name>(*this).is_templatized(); }
template<>
inline bool ASTNode::fast_is<SizedName>() const { return is_name() && verify_cast<Name>(*this).is_sized(); }
}

View file

@ -294,6 +294,19 @@ bool Parser::match_variable_declaration()
(void)parse_name(get_dummy_node());
while (!eof() && (peek().type() == Token::Type::LeftBracket)) {
consume(Token::Type::LeftBracket);
if (match(Token::Type::Integer)) {
consume(Token::Type::Integer);
}
if (!match(Token::Type::RightBracket)) {
error("No closing right bracket"sv);
return false;
}
consume(Token::Type::RightBracket);
}
if (match(Token::Type::Equals)) {
consume(Token::Type::Equals);
if (!match_expression()) {
@ -1449,7 +1462,9 @@ NonnullRefPtr<Name const> Parser::parse_name(ASTNode const& parent)
return name_node;
}
bool is_templatized = false;
if (match_template_arguments()) {
is_templatized = true;
consume(Token::Type::Less);
NonnullRefPtr<TemplatizedName> templatized_name = create_ast_node<TemplatizedName>(parent, name_node->start(), {});
templatized_name->set_name(name_node->name());
@ -1464,6 +1479,27 @@ NonnullRefPtr<Name const> Parser::parse_name(ASTNode const& parent)
consume(Token::Type::Greater);
}
if (!is_templatized && (peek().type() == Token::Type::LeftBracket)) {
NonnullRefPtr<SizedName> sized_name = create_ast_node<SizedName>(parent, name_node->start(), {});
sized_name->set_name(name_node->name());
sized_name->set_scope(name_node->scope());
while (peek().type() == Token::Type::LeftBracket) {
consume(Token::Type::LeftBracket);
StringView size = "0"sv;
if (peek().type() == Token::Type::Integer) {
auto token = consume(Token::Type::Integer);
size = token.text();
}
sized_name->append_dimension(size);
consume(Token::Type::RightBracket);
}
name_node->set_end(position());
name_node = sized_name;
}
name_node->set_end(previous_token_end());
return name_node;
}
@ -1564,6 +1600,8 @@ NonnullRefPtr<BracedInitList const> Parser::parse_braced_init_list(ASTNode const
consume(Token::Type::LeftCurly);
while (!eof() && peek().type() != Token::Type::RightCurly) {
init_list->add_expression(parse_expression(*init_list));
if (peek().type() == Token::Type::Comma)
consume(Token::Type::Comma);
}
consume(Token::Type::RightCurly);
init_list->set_end(position());

View file

@ -0,0 +1,19 @@
TranslationUnit[0:0->2:0]
FunctionDeclaration[0:0->2:0]
NamedType[0:0->0:3]
void
foo
(
)
FunctionDefinition[0:11->2:0]
{
VariableDeclaration[1:4->1:20]
NamedType[1:4->1:6]
int
x
BracedInitList[1:15->1:20]
NumericLiteral[1:16->1:16]
1
NumericLiteral[1:18->1:18]
2
}

View file

@ -0,0 +1,3 @@
void foo() {
int x[0] = {1,2};
}