diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 08fda7a2ffa51..3b4b0b78e8bf1 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -2633,12 +2633,20 @@ class AnnotatingParser { PreviousNotConst->MatchingParen->Previous->isNot(tok::kw_template); } - if ((PreviousNotConst->is(tok::r_paren) && - PreviousNotConst->is(TT_TypeDeclarationParen)) || - PreviousNotConst->is(TT_AttributeRParen)) { + if (PreviousNotConst->is(tok::r_paren) && + PreviousNotConst->is(TT_TypeDeclarationParen)) { return true; } + auto InTypeDecl = [&]() { + for (auto Next = Tok.Next; Next; Next = Next->Next) + if (Next->isOneOf(TT_ClassLBrace, TT_StructLBrace)) + return true; + return false; + }; + if (PreviousNotConst->is(TT_AttributeRParen) && (!IsCpp || !InTypeDecl())) + return true; + // If is a preprocess keyword like #define. if (IsPPKeyword) return false; diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp index fc77e277947c5..1b4a1eccdb9b6 100644 --- a/clang/unittests/Format/TokenAnnotatorTest.cpp +++ b/clang/unittests/Format/TokenAnnotatorTest.cpp @@ -3123,6 +3123,15 @@ TEST_F(TokenAnnotatorTest, UnderstandsAttributes) { EXPECT_TOKEN(Tokens[7], tok::identifier, TT_FunctionDeclarationName); EXPECT_TOKEN(Tokens[8], tok::l_paren, TT_FunctionDeclarationLParen); + Tokens = annotate("struct __attribute__((x)) foo {};"); + ASSERT_EQ(Tokens.size(), 12u) << Tokens; + EXPECT_TOKEN(Tokens[2], tok::l_paren, TT_AttributeLParen); + EXPECT_TOKEN(Tokens[3], tok::l_paren, TT_Unknown); + EXPECT_TOKEN(Tokens[5], tok::r_paren, TT_Unknown); + EXPECT_TOKEN(Tokens[6], tok::r_paren, TT_AttributeRParen); + EXPECT_TOKEN(Tokens[7], tok::identifier, TT_Unknown); + EXPECT_TOKEN(Tokens[8], tok::l_brace, TT_StructLBrace); + FormatStyle Style = getLLVMStyle(); Style.AttributeMacros.push_back("FOO"); Tokens = annotate("bool foo FOO(unused);", Style);