[clang-format] Don't annotate left brace of class as FunctionLBrace

The l_brace of class/struct/union was incorrectly annotated as
TT_FunctionLBrace in the presence of attributes. This in turn
would cause the RemoveSemicolon option to remove the semicolon
at the end of the declaration, resulting in invalid code being
generated.

Fixes #61188.

Differential Revision: https://reviews.llvm.org/D145344
This commit is contained in:
Owen Pan
2023-03-05 17:52:42 -08:00
parent a00801d94b
commit a02c3af9f1
3 changed files with 12 additions and 8 deletions

View File

@@ -3701,13 +3701,13 @@ void UnwrappedLineParser::parseJavaEnumBody() {
void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
const FormatToken &InitialToken = *FormatTok;
nextToken();
handleAttributes();
// The actual identifier can be a nested name specifier, and in macros
// it is often token-pasted.
// An [[attribute]] can be before the identifier.
while (FormatTok->isOneOf(tok::identifier, tok::coloncolon, tok::hashhash,
tok::kw___attribute, tok::kw___declspec,
tok::kw_alignas, tok::l_square, tok::r_square) ||
tok::kw_alignas) ||
((Style.Language == FormatStyle::LK_Java || Style.isJavaScript()) &&
FormatTok->isOneOf(tok::period, tok::comma))) {
if (Style.isJavaScript() &&
@@ -3725,15 +3725,10 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
FormatTok->is(tok::identifier) &&
FormatTok->TokenText != FormatTok->TokenText.upper();
nextToken();
// We can have macros or attributes in between 'class' and the class name.
// We can have macros in between 'class' and the class name.
if (!IsNonMacroIdentifier) {
if (FormatTok->is(tok::l_paren)) {
parseParens();
} else if (FormatTok->is(TT_AttributeSquare)) {
parseSquare();
// Consume the closing TT_AttributeSquare.
if (FormatTok->Next && FormatTok->is(TT_AttributeSquare))
nextToken();
}
}
}

View File

@@ -25233,6 +25233,11 @@ TEST_F(FormatTest, RemoveSemicolon) {
"}",
Style);
verifyFormat("class [[deprecated(\"\")]] C {\n"
" int i;\n"
"};",
Style);
verifyIncompleteFormat("class C final [[deprecated(l]] {});", Style);
// These tests are here to show a problem that may not be easily

View File

@@ -345,6 +345,10 @@ TEST_F(TokenAnnotatorTest, UnderstandsClasses) {
Tokens = annotate("const class {} c;");
EXPECT_EQ(Tokens.size(), 7u) << Tokens;
EXPECT_TOKEN(Tokens[2], tok::l_brace, TT_ClassLBrace);
Tokens = annotate("class [[deprecated(\"\")]] C { int i; };");
EXPECT_EQ(Tokens.size(), 17u) << Tokens;
EXPECT_TOKEN(Tokens[10], tok::l_brace, TT_ClassLBrace);
}
TEST_F(TokenAnnotatorTest, UnderstandsStructs) {