[clang] [ClangFormat] Fix formatting bugs. (PR #76245)

via cfe-commits cfe-commits at lists.llvm.org
Tue Jan 9 05:29:01 PST 2024


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 <klimek at 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 <klimek at 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



More information about the cfe-commits mailing list