diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h index 5877b0a612474..527f1d744a580 100644 --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -42,6 +42,7 @@ namespace format { TYPE(CaseLabelColon) \ TYPE(CastRParen) \ TYPE(ClassLBrace) \ + TYPE(ClassRBrace) \ /* ternary ?: expression */ \ TYPE(ConditionalExpr) \ /* the condition in an if statement */ \ @@ -67,6 +68,7 @@ namespace format { TYPE(DictLiteral) \ TYPE(ElseLBrace) \ TYPE(EnumLBrace) \ + TYPE(EnumRBrace) \ TYPE(FatArrow) \ TYPE(ForEachMacro) \ TYPE(FunctionAnnotationRParen) \ @@ -125,6 +127,7 @@ namespace format { TYPE(PureVirtualSpecifier) \ TYPE(RangeBasedForLoopColon) \ TYPE(RecordLBrace) \ + TYPE(RecordRBrace) \ TYPE(RegexLiteral) \ TYPE(RequiresClause) \ TYPE(RequiresClauseInARequiresExpression) \ @@ -141,6 +144,7 @@ namespace format { * braces need to be added to split it. Not used for other languages. */ \ TYPE(StringInConcatenation) \ TYPE(StructLBrace) \ + TYPE(StructRBrace) \ TYPE(StructuredBindingLSquare) \ TYPE(TemplateCloser) \ TYPE(TemplateOpener) \ @@ -153,6 +157,7 @@ namespace format { TYPE(TypenameMacro) \ TYPE(UnaryOperator) \ TYPE(UnionLBrace) \ + TYPE(UnionRBrace) \ TYPE(UntouchableMacroFunc) \ /* Like in 'assign x = 0, y = 1;' . */ \ TYPE(VerilogAssignComma) \ diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index dda5fd077e590..3275d7b6a71aa 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -3713,6 +3713,10 @@ bool UnwrappedLineParser::parseEnum() { nextToken(); addUnwrappedLine(); } + if (auto Prev = FormatTok->getPreviousNonComment(); + Prev && Prev->is(tok::r_brace)) { + Prev->setFinalizedType(TT_EnumRBrace); + } return true; // There is no addUnwrappedLine() here so that we fall through to parsing a @@ -3920,21 +3924,23 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) { } while (!eof()); } - auto GetBraceType = [](const FormatToken &RecordTok) { + auto GetBraceTypes = + [](const FormatToken &RecordTok) -> std::pair { switch (RecordTok.Tok.getKind()) { case tok::kw_class: - return TT_ClassLBrace; + return {TT_ClassLBrace, TT_ClassRBrace}; case tok::kw_struct: - return TT_StructLBrace; + return {TT_StructLBrace, TT_StructRBrace}; case tok::kw_union: - return TT_UnionLBrace; + return {TT_UnionLBrace, TT_UnionRBrace}; default: // Useful for e.g. interface. - return TT_RecordLBrace; + return {TT_RecordLBrace, TT_RecordRBrace}; } }; if (FormatTok->is(tok::l_brace)) { - FormatTok->setFinalizedType(GetBraceType(InitialToken)); + auto [OpenBraceType, ClosingBraceType] = GetBraceTypes(InitialToken); + FormatTok->setFinalizedType(OpenBraceType); if (ParseAsExpr) { parseChildBlock(); } else { @@ -3944,6 +3950,10 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) { unsigned AddLevels = Style.IndentAccessModifiers ? 2u : 1u; parseBlock(/*MustBeDeclaration=*/true, AddLevels, /*MunchSemi=*/false); } + if (auto Prev = FormatTok->getPreviousNonComment(); + Prev && Prev->is(tok::r_brace)) { + Prev->setFinalizedType(ClosingBraceType); + } } // There is no addUnwrappedLine() here so that we fall through to parsing a // structural element afterwards. Thus, in "class A {} n, m;", diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp index 62ec460eba7fd..2d590f2af05e6 100644 --- a/clang/unittests/Format/TokenAnnotatorTest.cpp +++ b/clang/unittests/Format/TokenAnnotatorTest.cpp @@ -393,32 +393,39 @@ TEST_F(TokenAnnotatorTest, UnderstandsClasses) { auto Tokens = annotate("class C {};"); EXPECT_EQ(Tokens.size(), 6u) << Tokens; EXPECT_TOKEN(Tokens[2], tok::l_brace, TT_ClassLBrace); + EXPECT_TOKEN(Tokens[3], tok::r_brace, TT_ClassRBrace); Tokens = annotate("const class C {} c;"); EXPECT_EQ(Tokens.size(), 8u) << Tokens; EXPECT_TOKEN(Tokens[3], tok::l_brace, TT_ClassLBrace); + EXPECT_TOKEN(Tokens[4], tok::r_brace, TT_ClassRBrace); Tokens = annotate("const class {} c;"); EXPECT_EQ(Tokens.size(), 7u) << Tokens; EXPECT_TOKEN(Tokens[2], tok::l_brace, TT_ClassLBrace); + EXPECT_TOKEN(Tokens[3], tok::r_brace, TT_ClassRBrace); Tokens = annotate("class [[deprecated(\"\")]] C { int i; };"); EXPECT_EQ(Tokens.size(), 17u) << Tokens; EXPECT_TOKEN(Tokens[10], tok::l_brace, TT_ClassLBrace); + EXPECT_TOKEN(Tokens[14], tok::r_brace, TT_ClassRBrace); } TEST_F(TokenAnnotatorTest, UnderstandsStructs) { auto Tokens = annotate("struct S {};"); EXPECT_EQ(Tokens.size(), 6u) << Tokens; EXPECT_TOKEN(Tokens[2], tok::l_brace, TT_StructLBrace); + EXPECT_TOKEN(Tokens[3], tok::r_brace, TT_StructRBrace); Tokens = annotate("struct EXPORT_MACRO [[nodiscard]] C { int i; };"); EXPECT_EQ(Tokens.size(), 15u) << Tokens; EXPECT_TOKEN(Tokens[8], tok::l_brace, TT_StructLBrace); + EXPECT_TOKEN(Tokens[12], tok::r_brace, TT_StructRBrace); Tokens = annotate("struct [[deprecated]] [[nodiscard]] C { int i; };"); EXPECT_EQ(Tokens.size(), 19u) << Tokens; EXPECT_TOKEN(Tokens[12], tok::l_brace, TT_StructLBrace); + EXPECT_TOKEN(Tokens[16], tok::r_brace, TT_StructRBrace); Tokens = annotate("template struct S {};"); EXPECT_EQ(Tokens.size(), 18u) << Tokens; @@ -426,6 +433,7 @@ TEST_F(TokenAnnotatorTest, UnderstandsStructs) { EXPECT_TOKEN(Tokens[10], tok::l_square, TT_ArraySubscriptLSquare); EXPECT_TOKEN(Tokens[13], tok::greater, TT_TemplateCloser); EXPECT_TOKEN(Tokens[14], tok::l_brace, TT_StructLBrace); + EXPECT_TOKEN(Tokens[15], tok::r_brace, TT_StructRBrace); Tokens = annotate("template struct S {};"); EXPECT_EQ(Tokens.size(), 18u) << Tokens; @@ -433,6 +441,7 @@ TEST_F(TokenAnnotatorTest, UnderstandsStructs) { EXPECT_TOKEN(Tokens[10], tok::l_square, TT_ArraySubscriptLSquare); EXPECT_TOKEN(Tokens[13], tok::greater, TT_TemplateCloser); EXPECT_TOKEN(Tokens[14], tok::l_brace, TT_StructLBrace); + EXPECT_TOKEN(Tokens[15], tok::r_brace, TT_StructRBrace); Tokens = annotate("template struct S {\n" " void f(T const (&a)[n]);\n" @@ -445,23 +454,27 @@ TEST_F(TokenAnnotatorTest, UnderstandsStructs) { EXPECT_TOKEN(Tokens[23], tok::l_paren, TT_FunctionTypeLParen); EXPECT_TOKEN(Tokens[24], tok::amp, TT_UnaryOperator); EXPECT_TOKEN(Tokens[27], tok::l_square, TT_ArraySubscriptLSquare); + EXPECT_TOKEN(Tokens[32], tok::r_brace, TT_StructRBrace); } TEST_F(TokenAnnotatorTest, UnderstandsUnions) { auto Tokens = annotate("union U {};"); EXPECT_EQ(Tokens.size(), 6u) << Tokens; EXPECT_TOKEN(Tokens[2], tok::l_brace, TT_UnionLBrace); + EXPECT_TOKEN(Tokens[3], tok::r_brace, TT_UnionRBrace); Tokens = annotate("union U { void f() { return; } };"); EXPECT_EQ(Tokens.size(), 14u) << Tokens; EXPECT_TOKEN(Tokens[2], tok::l_brace, TT_UnionLBrace); EXPECT_TOKEN(Tokens[7], tok::l_brace, TT_FunctionLBrace); + EXPECT_TOKEN(Tokens[11], tok::r_brace, TT_UnionRBrace); } TEST_F(TokenAnnotatorTest, UnderstandsEnums) { auto Tokens = annotate("enum E {};"); EXPECT_EQ(Tokens.size(), 6u) << Tokens; EXPECT_TOKEN(Tokens[2], tok::l_brace, TT_EnumLBrace); + EXPECT_TOKEN(Tokens[3], tok::r_brace, TT_EnumRBrace); } TEST_F(TokenAnnotatorTest, UnderstandsDefaultedAndDeletedFunctions) {