[clang] a70549a - [clang-format] Fix DefSeparator empty line issues

via cfe-commits cfe-commits at lists.llvm.org
Mon Feb 7 06:23:26 PST 2022


Author: ksyx
Date: 2022-02-07T14:23:21Z
New Revision: a70549ae43dfa551f3eacdfa7a7f2c0df073be8e

URL: https://github.com/llvm/llvm-project/commit/a70549ae43dfa551f3eacdfa7a7f2c0df073be8e
DIFF: https://github.com/llvm/llvm-project/commit/a70549ae43dfa551f3eacdfa7a7f2c0df073be8e.diff

LOG: [clang-format] Fix DefSeparator empty line issues

- Add or remove empty lines surrounding union blocks.
- Fixes https://github.com/llvm/llvm-project/issues/53229, in which
  keywords like class and struct in a line ending with left brace or
  whose next line is left brace only, will be falsely recognized as
  definition line, causing extra empty lines inserted surrounding blocks
  with no need to be formatted.

Reviewed By: MyDeveloperDay, curdeius, HazardyKnusperkeks, owenpan
Differential Revision: https://reviews.llvm.org/D119067

Added: 
    

Modified: 
    clang/lib/Format/DefinitionBlockSeparator.cpp
    clang/unittests/Format/DefinitionBlockSeparatorTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Format/DefinitionBlockSeparator.cpp b/clang/lib/Format/DefinitionBlockSeparator.cpp
index b7fca864efc6..b7b1123773ce 100644
--- a/clang/lib/Format/DefinitionBlockSeparator.cpp
+++ b/clang/lib/Format/DefinitionBlockSeparator.cpp
@@ -35,19 +35,31 @@ void DefinitionBlockSeparator::separateBlocks(
   const bool IsNeverStyle =
       Style.SeparateDefinitionBlocks == FormatStyle::SDS_Never;
   const AdditionalKeywords &ExtraKeywords = Tokens.getKeywords();
-  auto LikelyDefinition = [this, ExtraKeywords](const AnnotatedLine *Line,
-                                                bool ExcludeEnum = false) {
+  auto GetBracketLevelChange = [](const FormatToken *Tok) {
+    if (Tok->isOneOf(tok::l_brace, tok::l_paren, tok::l_square))
+      return 1;
+    if (Tok->isOneOf(tok::r_brace, tok::r_paren, tok::r_square))
+      return -1;
+    return 0;
+  };
+  auto LikelyDefinition = [&](const AnnotatedLine *Line,
+                              bool ExcludeEnum = false) {
     if ((Line->MightBeFunctionDecl && Line->mightBeFunctionDefinition()) ||
         Line->startsWithNamespace())
       return true;
-    FormatToken *CurrentToken = Line->First;
-    while (CurrentToken) {
-      if (CurrentToken->isOneOf(tok::kw_class, tok::kw_struct) ||
-          (Style.isJavaScript() && CurrentToken->is(ExtraKeywords.kw_function)))
-        return true;
-      if (!ExcludeEnum && CurrentToken->is(tok::kw_enum))
-        return true;
-      CurrentToken = CurrentToken->Next;
+    int BracketLevel = 0;
+    for (const FormatToken *CurrentToken = Line->First; CurrentToken;
+         CurrentToken = CurrentToken->Next) {
+      if (BracketLevel == 0) {
+        if ((CurrentToken->isOneOf(tok::kw_class, tok::kw_struct,
+                                   tok::kw_union) ||
+             (Style.isJavaScript() &&
+              CurrentToken->is(ExtraKeywords.kw_function))))
+          return true;
+        if (!ExcludeEnum && CurrentToken->is(tok::kw_enum))
+          return true;
+      }
+      BracketLevel += GetBracketLevelChange(CurrentToken);
     }
     return false;
   };
@@ -102,14 +114,17 @@ void DefinitionBlockSeparator::separateBlocks(
              IsPPConditional(OpeningLineIndex - 1);
     };
     const auto HasEnumOnLine = [&]() {
-      FormatToken *CurrentToken = CurrentLine->First;
       bool FoundEnumKeyword = false;
-      while (CurrentToken) {
-        if (CurrentToken->is(tok::kw_enum))
-          FoundEnumKeyword = true;
-        else if (FoundEnumKeyword && CurrentToken->is(tok::l_brace))
-          return true;
-        CurrentToken = CurrentToken->Next;
+      int BracketLevel = 0;
+      for (const FormatToken *CurrentToken = CurrentLine->First; CurrentToken;
+           CurrentToken = CurrentToken->Next) {
+        if (BracketLevel == 0) {
+          if (CurrentToken->is(tok::kw_enum))
+            FoundEnumKeyword = true;
+          else if (FoundEnumKeyword && CurrentToken->is(tok::l_brace))
+            return true;
+        }
+        BracketLevel += GetBracketLevelChange(CurrentToken);
       }
       return FoundEnumKeyword && I + 1 < Lines.size() &&
              Lines[I + 1]->First->is(tok::l_brace);

diff  --git a/clang/unittests/Format/DefinitionBlockSeparatorTest.cpp b/clang/unittests/Format/DefinitionBlockSeparatorTest.cpp
index 4cbae0f55b03..582b62e445df 100644
--- a/clang/unittests/Format/DefinitionBlockSeparatorTest.cpp
+++ b/clang/unittests/Format/DefinitionBlockSeparatorTest.cpp
@@ -109,6 +109,15 @@ TEST_F(DefinitionBlockSeparatorTest, Basic) {
                "};",
                Style);
 
+  verifyFormat("union foo {\n"
+               "  int i, j;\n"
+               "};\n"
+               "\n"
+               "union bar {\n"
+               "  int j, k;\n"
+               "};",
+               Style);
+
   verifyFormat("class foo {\n"
                "  int i, j;\n"
                "};\n"
@@ -311,6 +320,9 @@ TEST_F(DefinitionBlockSeparatorTest, Always) {
                       "int bar3(int j, int k, const enum Bar b) {\n"
                       "  // A comment\n"
                       "  int r = j % k;\n"
+                      "  if (struct S = getS()) {\n"
+                      "    // if condition\n"
+                      "  }\n"
                       "  return r;\n"
                       "}\n";
   std::string Postfix = "\n"
@@ -364,6 +376,9 @@ TEST_F(DefinitionBlockSeparatorTest, Never) {
                         "int bar3(int j, int k, const enum Bar b) {\n"
                         "  // A comment\n"
                         "  int r = j % k;\n"
+                        "  if (struct S = getS()) {\n"
+                        "    // if condition\n"
+                        "  }\n"
                         "  return r;\n"
                         "}\n"
                         "} // namespace";
@@ -425,6 +440,10 @@ TEST_F(DefinitionBlockSeparatorTest, OpeningBracketOwnsLine) {
                "{\n"
                "  // A comment\n"
                "  int r = j % k;\n"
+               "  if (struct S = getS())\n"
+               "  {\n"
+               "    // if condition\n"
+               "  }\n"
                "  return r;\n"
                "}\n"
                "} // namespace NS",
@@ -473,6 +492,9 @@ TEST_F(DefinitionBlockSeparatorTest, Leave) {
                         "int bar3(int j, int k, const enum Bar b) {\n"
                         "  // A comment\n"
                         "  int r = j % k;\n"
+                        "  if (struct S = getS()) {\n"
+                        "    // if condition\n"
+                        "  }\n"
                         "  return r;\n"
                         "}\n"
                         "} // namespace";


        


More information about the cfe-commits mailing list