https://github.com/r4nt updated https://github.com/llvm/llvm-project/pull/76245
>From 52cb11f0279dbd9f65f15e81f44869cfac00d544 Mon Sep 17 00:00:00 2001 From: Manuel Klimek <kli...@google.com> Date: Thu, 2 Mar 2023 14:00:35 +0000 Subject: [PATCH 1/2] [ClangFormat] Fix formatting bugs. 1. There are multiple calls to addFakeParenthesis; move the guard to not assign fake parenthesis into the function to make sure we cover all calls. 2. MustBreakBefore can be set on a token in two cases: either during unwrapped line parsing, or later, during token annotation. We must keep the latter, but reset the former. 3. Added a test to document that the intended behavior of preferring not to break between a return type and a function identifier. For example, with MOCK_METHOD(r, n, a)=r n a, the code MOCK_METHOD(void, f, (int a, int b)) should prefer the same breaks as the expanded void f(int a, int b). --- clang/lib/Format/FormatToken.h | 26 +++++++++---- clang/lib/Format/TokenAnnotator.cpp | 13 +++---- clang/lib/Format/UnwrappedLineFormatter.cpp | 10 +++-- clang/lib/Format/UnwrappedLineParser.cpp | 2 + .../Format/FormatTestMacroExpansion.cpp | 38 +++++++++++++++++++ 5 files changed, 70 insertions(+), 19 deletions(-) diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h index 3f9664f8f78a3e..b1e3ae8ab303d6 100644 --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -275,14 +275,15 @@ class AnnotatedLine; struct FormatToken { FormatToken() : HasUnescapedNewline(false), IsMultiline(false), IsFirst(false), - MustBreakBefore(false), IsUnterminatedLiteral(false), - CanBreakBefore(false), ClosesTemplateDeclaration(false), - StartsBinaryExpression(false), EndsBinaryExpression(false), - PartOfMultiVariableDeclStmt(false), ContinuesLineCommentSection(false), - Finalized(false), ClosesRequiresClause(false), - EndsCppAttributeGroup(false), BlockKind(BK_Unknown), - Decision(FD_Unformatted), PackingKind(PPK_Inconclusive), - TypeIsFinalized(false), Type(TT_Unknown) {} + MustBreakBefore(false), MustBreakBeforeFinalized(false), + IsUnterminatedLiteral(false), CanBreakBefore(false), + ClosesTemplateDeclaration(false), StartsBinaryExpression(false), + EndsBinaryExpression(false), PartOfMultiVariableDeclStmt(false), + ContinuesLineCommentSection(false), Finalized(false), + ClosesRequiresClause(false), EndsCppAttributeGroup(false), + BlockKind(BK_Unknown), Decision(FD_Unformatted), + PackingKind(PPK_Inconclusive), TypeIsFinalized(false), + Type(TT_Unknown) {} /// The \c Token. Token Tok; @@ -318,6 +319,10 @@ struct FormatToken { /// before the token. unsigned MustBreakBefore : 1; + /// Whether MustBreakBefore is finalized during parsing and must not + /// be reset between runs. + unsigned MustBreakBeforeFinalized : 1; + /// Set to \c true if this token is an unterminated literal. unsigned IsUnterminatedLiteral : 1; @@ -416,10 +421,15 @@ struct FormatToken { /// to another one please use overwriteFixedType, or even better remove the /// need to reassign the type. void setFinalizedType(TokenType T) { + if (MacroCtx && MacroCtx->Role == MR_UnexpandedArg) + return; + Type = T; TypeIsFinalized = true; } void overwriteFixedType(TokenType T) { + if (MacroCtx && MacroCtx->Role == MR_UnexpandedArg) + return; TypeIsFinalized = false; setType(T); } diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index f3551af3424396..c26b248a3b2d40 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -2769,13 +2769,6 @@ class ExpressionParser { // Consume operators with higher precedence. parse(Precedence + 1); - // Do not assign fake parenthesis to tokens that are part of an - // unexpanded macro call. The line within the macro call contains - // the parenthesis and commas, and we will not find operators within - // that structure. - if (Current && Current->MacroParent) - break; - int CurrentPrecedence = getCurrentPrecedence(); if (Precedence == CurrentPrecedence && Current && @@ -2919,6 +2912,12 @@ class ExpressionParser { void addFakeParenthesis(FormatToken *Start, prec::Level Precedence, FormatToken *End = nullptr) { + // Do not assign fake parenthesis to tokens that are part of an + // unexpanded macro call. The line within the macro call contains + // the parenthesis and commas, and we will not find operators within + // that structure. + if (Start->MacroParent) return; + Start->FakeLParens.push_back(Precedence); if (Precedence > prec::Unknown) Start->StartsBinaryExpression = true; diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp index 56077499c39d53..27983a330ac40a 100644 --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -954,13 +954,15 @@ static void markFinalized(FormatToken *Tok) { // will be modified as unexpanded arguments (as part of the macro call // formatting) in the next pass. Tok->MacroCtx->Role = MR_UnexpandedArg; - // Reset whether spaces are required before this token, as that is context - // dependent, and that context may change when formatting the macro call. - // For example, given M(x) -> 2 * x, and the macro call M(var), - // the token 'var' will have SpacesRequiredBefore = 1 after being + // Reset whether spaces or a line break are required before this token, as + // that is context dependent, and that context may change when formatting + // the macro call. For example, given M(x) -> 2 * x, and the macro call + // M(var), the token 'var' will have SpacesRequiredBefore = 1 after being // formatted as part of the expanded macro, but SpacesRequiredBefore = 0 // for its position within the macro call. Tok->SpacesRequiredBefore = 0; + if (!Tok->MustBreakBeforeFinalized) + Tok->MustBreakBefore = 0; } else { Tok->Finalized = true; } diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 684609747a5513..942aaff3c456df 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -4675,6 +4675,7 @@ void UnwrappedLineParser::readToken(int LevelDifference) { conditionalCompilationEnd(); FormatTok = Tokens->getNextToken(); FormatTok->MustBreakBefore = true; + FormatTok->MustBreakBeforeFinalized = true; } auto IsFirstNonCommentOnLine = [](bool FirstNonCommentOnLine, @@ -4891,6 +4892,7 @@ void UnwrappedLineParser::pushToken(FormatToken *Tok) { Line->Tokens.push_back(UnwrappedLineNode(Tok)); if (MustBreakBeforeNextToken) { Line->Tokens.back().Tok->MustBreakBefore = true; + Line->Tokens.back().Tok->MustBreakBeforeFinalized = true; MustBreakBeforeNextToken = false; } } diff --git a/clang/unittests/Format/FormatTestMacroExpansion.cpp b/clang/unittests/Format/FormatTestMacroExpansion.cpp index 68250234f4201e..afc88f0eb75673 100644 --- a/clang/unittests/Format/FormatTestMacroExpansion.cpp +++ b/clang/unittests/Format/FormatTestMacroExpansion.cpp @@ -255,6 +255,44 @@ TEST_F(FormatTestMacroExpansion, Style); } +TEST_F(FormatTestMacroExpansion, CommaAsOperator) { + FormatStyle Style = getGoogleStyle(); + Style.Macros.push_back("ASSIGN_OR_RETURN(a, b, c)=a=(b); if(x) c"); + verifyFormat(R"(ASSIGN_OR_RETURN(auto reader, + logs::proxy::Reader::NewReader(log_filename, access_options, + reader_options), + _ << aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa << aaaaaa << aaaaaaaaa + << aaaaaaaaaaaa << aaaaaaaaaaa << aaaaaaaaaaaa); +)", Style); +} + +TEST_F(FormatTestMacroExpansion, ForcedBreakDiffers) { + FormatStyle Style = getGoogleStyle(); + Style.Macros.push_back("ASSIGN_OR_RETURN(a, b)=a=(b)"); + EXPECT_EQ(R"( +// +ASSIGN_OR_RETURN(const lllllllllllllllllllllllllll xxxxxxxxxxxxxxx, + aaaaaaaaaaaaaaaaaaaaaa( + bbbbbbbbb, ccccccccccccccccccccccccccccc, dddddddddddd)); +)", format(R"( +// +ASSIGN_OR_RETURN(const lllllllllllllllllllllllllll xxxxxxxxxxxxxxx, + aaaaaaaaaaaaaaaaaaaaaa( + bbbbbbbbb, ccccccccccccccccccccccccccccc, dddddddddddd)); +)", Style)); +} + +TEST_F(FormatTestMacroExpansion, PreferNotBreakingBetweenReturnTypeAndFunction) { + FormatStyle Style = getGoogleStyle(); + Style.Macros.push_back("MOCK_METHOD(r, n, a, s)=r n a s"); + // In the expanded code, we parse a full function signature, and afterwards + // know that we prefer not to break before the function name. + verifyFormat(R"(MOCK_METHOD( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, + (cccccccccccccccccccccccccccccc), (const, override)); +)", Style); +} + } // namespace } // namespace test } // namespace format >From dec1fb75495461efc9ea370a058ce17d9ca352d4 Mon Sep 17 00:00:00 2001 From: Manuel Klimek <kli...@google.com> Date: Tue, 9 Jan 2024 13:28:34 +0000 Subject: [PATCH 2/2] fixup! [ClangFormat] Fix formatting bugs. --- clang/lib/Format/FormatToken.h | 1 - clang/lib/Format/TokenAnnotator.cpp | 3 +- .../Format/FormatTestMacroExpansion.cpp | 47 +++++++++---------- 3 files changed, 24 insertions(+), 27 deletions(-) diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h index b1e3ae8ab303d6..981592aa094a7a 100644 --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -423,7 +423,6 @@ struct FormatToken { void setFinalizedType(TokenType T) { if (MacroCtx && MacroCtx->Role == MR_UnexpandedArg) return; - Type = T; TypeIsFinalized = true; } diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index c26b248a3b2d40..6b153759ad6982 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -2916,7 +2916,8 @@ class ExpressionParser { // unexpanded macro call. The line within the macro call contains // the parenthesis and commas, and we will not find operators within // that structure. - if (Start->MacroParent) return; + if (Start->MacroParent) + return; Start->FakeLParens.push_back(Precedence); if (Precedence > prec::Unknown) diff --git a/clang/unittests/Format/FormatTestMacroExpansion.cpp b/clang/unittests/Format/FormatTestMacroExpansion.cpp index afc88f0eb75673..f17e0adcfc21eb 100644 --- a/clang/unittests/Format/FormatTestMacroExpansion.cpp +++ b/clang/unittests/Format/FormatTestMacroExpansion.cpp @@ -257,40 +257,37 @@ TEST_F(FormatTestMacroExpansion, TEST_F(FormatTestMacroExpansion, CommaAsOperator) { FormatStyle Style = getGoogleStyle(); - Style.Macros.push_back("ASSIGN_OR_RETURN(a, b, c)=a=(b); if(x) c"); - verifyFormat(R"(ASSIGN_OR_RETURN(auto reader, - logs::proxy::Reader::NewReader(log_filename, access_options, - reader_options), - _ << aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa << aaaaaa << aaaaaaaaa - << aaaaaaaaaaaa << aaaaaaaaaaa << aaaaaaaaaaaa); -)", Style); + Style.ColumnLimit = 42; + Style.Macros.push_back("MACRO(a, b, c)=a=(b); if(x) c"); + verifyFormat("MACRO(auto a,\n" + " looooongfunction(first, second,\n" + " third),\n" + " fourth);", + Style); } TEST_F(FormatTestMacroExpansion, ForcedBreakDiffers) { FormatStyle Style = getGoogleStyle(); - Style.Macros.push_back("ASSIGN_OR_RETURN(a, b)=a=(b)"); - EXPECT_EQ(R"( -// -ASSIGN_OR_RETURN(const lllllllllllllllllllllllllll xxxxxxxxxxxxxxx, - aaaaaaaaaaaaaaaaaaaaaa( - bbbbbbbbb, ccccccccccccccccccccccccccccc, dddddddddddd)); -)", format(R"( -// -ASSIGN_OR_RETURN(const lllllllllllllllllllllllllll xxxxxxxxxxxxxxx, - aaaaaaaaaaaaaaaaaaaaaa( - bbbbbbbbb, ccccccccccccccccccccccccccccc, dddddddddddd)); -)", Style)); + Style.ColumnLimit = 40; + Style.Macros.push_back("MACRO(a, b)=a=(b)"); + verifyFormat("//\n" + "MACRO(const type variable,\n" + " functtioncall(\n" + " first, longsecondarg, third));\n", + Style); } -TEST_F(FormatTestMacroExpansion, PreferNotBreakingBetweenReturnTypeAndFunction) { +TEST_F(FormatTestMacroExpansion, + PreferNotBreakingBetweenReturnTypeAndFunction) { FormatStyle Style = getGoogleStyle(); - Style.Macros.push_back("MOCK_METHOD(r, n, a, s)=r n a s"); + Style.ColumnLimit = 22; + Style.Macros.push_back("MOCK_METHOD(r, n, a)=r n a"); // In the expanded code, we parse a full function signature, and afterwards // know that we prefer not to break before the function name. - verifyFormat(R"(MOCK_METHOD( - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, - (cccccccccccccccccccccccccccccc), (const, override)); -)", Style); + verifyFormat("MOCK_METHOD(\n" + " type, variable,\n" + " (type));\n", + Style); } } // namespace _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits