Implement alignas parsing

This commit is contained in:
Jonathan Müller 2017-10-29 20:02:43 +01:00
commit 756fe351f1
2 changed files with 91 additions and 23 deletions

View file

@ -101,22 +101,50 @@ namespace
auto end = clang_getRangeEnd(extent);
auto kind = clang_getCursorKind(cur);
if ((cursor_is_function(kind) || cursor_is_function(clang_getTemplateCursorKind(cur))
|| kind == CXCursor_VarDecl || kind == CXCursor_FieldDecl || kind == CXCursor_ParmDecl
|| kind == CXCursor_NonTypeTemplateParameter)
&& token_after_is(tu, file, cur, begin, "]", -2)
&& token_after_is(tu, file, cur, begin, "]", -3))
if (cursor_is_function(kind) || cursor_is_function(clang_getTemplateCursorKind(cur))
|| kind == CXCursor_VarDecl || kind == CXCursor_FieldDecl || kind == CXCursor_ParmDecl
|| kind == CXCursor_NonTypeTemplateParameter)
{
while (!token_after_is(tu, file, cur, begin, "[", -1)
&& !token_after_is(tu, file, cur, begin, "[", -2))
begin = get_next_location(tu, file, begin, -1);
if (token_after_is(tu, file, cur, begin, "]", -2)
&& token_after_is(tu, file, cur, begin, "]", -3))
{
while (!token_after_is(tu, file, cur, begin, "[", -1)
&& !token_after_is(tu, file, cur, begin, "[", -2))
begin = get_next_location(tu, file, begin, -1);
begin = get_next_location(tu, file, begin, -3);
DEBUG_ASSERT(token_after_is(tu, file, cur, begin, "[")
&& token_after_is(tu, file, cur, get_next_location(tu, file, begin),
"["),
detail::parse_error_handler{}, cur,
"error in pre-function attribute parsing");
begin = get_next_location(tu, file, begin, -3);
DEBUG_ASSERT(token_after_is(tu, file, cur, begin, "[")
&& token_after_is(tu, file, cur,
get_next_location(tu, file, begin), "["),
detail::parse_error_handler{}, cur,
"error in pre-function attribute parsing");
}
else if (token_after_is(tu, file, cur, begin, ")", -2))
{
// maybe alignas specifier
auto save_begin = begin;
auto paren_count = 1;
begin = get_next_location(tu, file, begin, -1);
for (auto last_begin = begin; paren_count != 0; last_begin = begin)
{
begin = get_next_location(tu, file, begin, -1);
if (token_after_is(tu, file, cur, begin, "(", -1))
--paren_count;
else if (token_after_is(tu, file, cur, begin, ")", -1))
++paren_count;
DEBUG_ASSERT(!clang_equalLocations(last_begin, begin),
detail::parse_error_handler{}, cur,
"infinite loop in alignas parsing");
}
begin = get_next_location(tu, file, begin, -(int(std::strlen("alignas")) + 1));
if (token_after_is(tu, file, cur, begin, "alignas"))
begin = get_next_location(tu, file, begin, -1);
else
begin = save_begin;
}
}
if (cursor_is_function(kind) || cursor_is_function(clang_getTemplateCursorKind(cur)))
@ -431,6 +459,19 @@ namespace
return cpp_attribute_kind::unknown;
}
cpp_token_string parse_attribute_arguments(detail::cxtoken_stream& stream)
{
auto end = find_closing_bracket(stream);
skip(stream, "(");
auto arguments = detail::to_string(stream, end);
stream.set_cur(end);
skip(stream, ")");
return arguments;
}
cpp_attribute parse_attribute_token(detail::cxtoken_stream& stream,
type_safe::optional<std::string> scope)
{
@ -455,15 +496,7 @@ namespace
// parse arguments
type_safe::optional<cpp_token_string> arguments;
if (stream.peek() == "(")
{
auto end = find_closing_bracket(stream);
skip(stream, "(");
arguments = detail::to_string(stream, end);
stream.set_cur(end);
skip(stream, ")");
}
arguments = parse_attribute_arguments(stream);
// parse variadic token
auto is_variadic = skip_if(stream, "...");
@ -499,6 +532,14 @@ namespace
skip(stream, "]");
return true;
}
else if (skip_if(stream, "alignas"))
{
// alignas specifier
// alignas(<some arguments>)
// ^
auto arguments = parse_attribute_arguments(stream);
result.push_back(cpp_attribute(cpp_attribute_kind::alignas_, std::move(arguments)));
}
else if (skip_if(stream, "__attribute__"))
{
// GCC/clang attributes

View file

@ -5,6 +5,7 @@
#include <cppast/cpp_attribute.hpp>
#include <cppast/cpp_function.hpp>
#include <cppast/cpp_variable.hpp>
#include "test_parser.hpp"
@ -34,6 +35,10 @@ TEST_CASE("cpp_attribute")
[[maybe_unused]] void h();
[[nodiscard]] int i();
[[noreturn]] void j();
// alignas
struct alignas(8) type {};
alignas(type) int var;
)";
auto file = parse({}, "cpp_attribute.cpp", code);
@ -99,6 +104,28 @@ TEST_CASE("cpp_attribute")
},
false);
REQUIRE(count == 9);
count = test_visit<cpp_class>(*file,
[&](const cpp_entity& e) {
auto& attributes = e.attributes();
REQUIRE(attributes.size() == 1u);
auto& attr = attributes.front();
check_attribute(attr, "alignas", type_safe::nullopt, false,
"8", cpp_attribute_kind::alignas_);
},
false);
REQUIRE(count == 1u);
count = test_visit<cpp_variable>(*file,
[&](const cpp_entity& e) {
auto& attributes = e.attributes();
REQUIRE(attributes.size() == 1u);
auto& attr = attributes.front();
check_attribute(attr, "alignas", type_safe::nullopt, false,
"type", cpp_attribute_kind::alignas_);
},
false);
REQUIRE(count == 1u);
}
TEST_CASE("cpp_attribute matching")