From 756fe351f11b3668da3afc6146ab37e1785567ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20M=C3=BCller?= Date: Sun, 29 Oct 2017 20:02:43 +0100 Subject: [PATCH] Implement alignas parsing --- src/libclang/cxtokenizer.cpp | 87 ++++++++++++++++++++++++++---------- test/cpp_attribute.cpp | 27 +++++++++++ 2 files changed, 91 insertions(+), 23 deletions(-) diff --git a/src/libclang/cxtokenizer.cpp b/src/libclang/cxtokenizer.cpp index 69ab211..7d3c313 100644 --- a/src/libclang/cxtokenizer.cpp +++ b/src/libclang/cxtokenizer.cpp @@ -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 scope) { @@ -455,15 +496,7 @@ namespace // parse arguments type_safe::optional 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() + // ^ + 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 diff --git a/test/cpp_attribute.cpp b/test/cpp_attribute.cpp index b5a16b2..0a88538 100644 --- a/test/cpp_attribute.cpp +++ b/test/cpp_attribute.cpp @@ -5,6 +5,7 @@ #include #include +#include #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(*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(*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")