PriMee created this revision.
Herald added a subscriber: klimek.

**Short overview:**

Fixed bug: https://bugs.llvm.org/show_bug.cgi?id=34001
Clang-format bug resulting in a strange behavior of control statements short 
blocks. Different flags combinations do not guarantee expected result. Turned 
on option AllowShortBlocksOnASingleLine does not work as intended.

**Description of the problem:**

Cpp source file UnwrappedLineFormatter does not handle 
AllowShortBlocksOnASingleLine flag as it should. Putting a single-line control 
statement without any braces, clang-format works as expected (depending on 
AllowShortIfStatementOnASingleLine or AllowShortLoopsOnASingleLine value). 
Putting a single-line control statement in braces, we can observe strange and 
incorrect behavior.
Our short block is intercepted by tryFitMultipleLinesInOne function. The 
function returns a number of lines to be merged. Unfortunately, our control 
statement block is not covered properly. There are several if-return 
statements, but none of them handles our block. A block is identified by the 
line first token and by left and right braces. A function block works as 
expected, there is such an if-return statement doing proper job. A control 
statement block, from the other hand, falls into strange conditional construct, 
which depends on BraceWrapping.AfterFunction flag (with condition that the 
line’s last token is left brace, what is possible in our case) or goes even 
further. That should definitely not happen.

**Description of the patch:**

By adding three different if statements, we guarantee that our short control 
statement block, however it looks like (different brace wrapping flags may be 
turned on), is handled properly and does not fall into wrong conditional 
construct. Depending on appropriate options we return either 0 (when something 
disturbs our merging attempt) or let another function (tryMergeSimpleBlock) 
take the responsibility of returned result (number of merged lines). 
Nevertheless, one more correction is required in mentioned tryMergeSimpleBlock 
function. The function, previously, returned either 0 or 2. The problem was 
that this did not handle the case when our block had the left brace in a 
separate line, not the header one. After change, after adding condition, we 
return the result compatible with block’s structure. In case of left brace in 
the header’s line we do everything as before the patch. In case of left brace 
in a separate line we do the job similar to the one we do in case of a 
“non-header left brace” function short block. To be precise, we try to merge 
the block ignoring the header line. Then, if success, we increment our returned 
result.

**After fix:**

**CONFIG:**

  AllowShortBlocksOnASingleLine: true 
  AllowShortIfStatementsOnASingleLine: true 
  BreakBeforeBraces: Custom
  BraceWrapping: { 
  AfterClass: true, AfterControlStatement: true, AfterEnum: true, 
AfterFunction: true, AfterNamespace: false, AfterStruct: true, AfterUnion: 
true, BeforeCatch: true, BeforeElse: true 
  }

**BEFORE:**

  if (statement) doSomething();
  if (statement) { doSomething(); }
  if (statement) {
      doSomething();
  }
  if (statement)
  {
      doSomething();
  }
  if (statement)
      doSomething();
  if (statement) {
      doSomething1();
      doSomething2();
  }

**AFTER:**

  if (statement) doSomething();
  if (statement) { doSomething(); }
  if (statement) { doSomething(); }
  if (statement) { doSomething(); }
  if (statement) doSomething();
  if (statement)
  {
    doSomething1();
    doSomething2();
  }


https://reviews.llvm.org/D37140

Files:
  lib/Format/UnwrappedLineFormatter.cpp

Index: lib/Format/UnwrappedLineFormatter.cpp
===================================================================
--- lib/Format/UnwrappedLineFormatter.cpp
+++ lib/Format/UnwrappedLineFormatter.cpp
@@ -283,6 +283,21 @@
         TheLine->First != TheLine->Last) {
       return MergeShortFunctions ? tryMergeSimpleBlock(I, E, Limit) : 0;
     }
+    if (TheLine->Last->is(tok::l_brace) &&
+        TheLine->First != TheLine->Last &&
+        TheLine->First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for)) { 
+      return Style.AllowShortBlocksOnASingleLine ? tryMergeSimpleBlock(I, E, Limit) : 0;
+    }
+    if (I[1]->First->is(tok::l_brace) && 
+        TheLine->First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for)) { 
+      return Style.BraceWrapping.AfterControlStatement ? tryMergeSimpleBlock(I, E, Limit) : 0;
+    }
+    if (TheLine->First->is(tok::l_brace) &&
+       (TheLine->First == TheLine->Last) &&
+       (I != AnnotatedLines.begin()) &&
+       (I[-1]->First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for))) { 
+      return Style.AllowShortBlocksOnASingleLine ? tryMergeSimpleBlock(I-1, E, Limit) : 0;
+    }
     if (TheLine->Last->is(tok::l_brace)) {
       return !Style.BraceWrapping.AfterFunction
                  ? tryMergeSimpleBlock(I, E, Limit)
@@ -459,53 +474,74 @@
                               Keywords.kw___except, tok::kw___finally))
         return 0;
     }
+    
+    if (Line.Last->is(tok::l_brace)) {
+      FormatToken *Tok = I[1]->First;
+      if (Tok->is(tok::r_brace) && !Tok->MustBreakBefore &&
+          (Tok->getNextNonComment() == nullptr ||
+          Tok->getNextNonComment()->is(tok::semi))) {
+        // We merge empty blocks even if the line exceeds the column limit.
+        Tok->SpacesRequiredBefore = 0;
+        Tok->CanBreakBefore = true;
+        return 1;
+      } else if (Limit != 0 && !Line.startsWith(tok::kw_namespace) &&
+                 !startsExternCBlock(Line)) {
+        // We don't merge short records.
+        FormatToken *RecordTok =
+            Line.First->is(tok::kw_typedef) ? Line.First->Next : Line.First;
+        if (RecordTok &&
+            RecordTok->isOneOf(tok::kw_class, tok::kw_union, tok::kw_struct,
+                               Keywords.kw_interface))
+          return 0;
 
-    FormatToken *Tok = I[1]->First;
-    if (Tok->is(tok::r_brace) && !Tok->MustBreakBefore &&
-        (Tok->getNextNonComment() == nullptr ||
-         Tok->getNextNonComment()->is(tok::semi))) {
-      // We merge empty blocks even if the line exceeds the column limit.
-      Tok->SpacesRequiredBefore = 0;
-      Tok->CanBreakBefore = true;
-      return 1;
-    } else if (Limit != 0 && !Line.startsWith(tok::kw_namespace) &&
-               !startsExternCBlock(Line)) {
-      // We don't merge short records.
-      FormatToken *RecordTok =
-          Line.First->is(tok::kw_typedef) ? Line.First->Next : Line.First;
-      if (RecordTok &&
-          RecordTok->isOneOf(tok::kw_class, tok::kw_union, tok::kw_struct,
-                             Keywords.kw_interface))
-        return 0;
+        // Check that we still have three lines and they fit into the limit.
+        if (I + 2 == E || I[2]->Type == LT_Invalid)
+          return 0;
+        Limit = limitConsideringMacros(I + 2, E, Limit);
 
-      // Check that we still have three lines and they fit into the limit.
-      if (I + 2 == E || I[2]->Type == LT_Invalid)
-        return 0;
-      Limit = limitConsideringMacros(I + 2, E, Limit);
+        if (!nextTwoLinesFitInto(I, Limit))
+          return 0;
 
-      if (!nextTwoLinesFitInto(I, Limit))
-        return 0;
+        // Second, check that the next line does not contain any braces - if it
+        // does, readability declines when putting it into a single line.
+        if (I[1]->Last->is(TT_LineComment))
+          return 0;
+        do {
+          if (Tok->is(tok::l_brace) && Tok->BlockKind != BK_BracedInit)
+            return 0;
+          Tok = Tok->Next;
+        } while (Tok);
 
-      // Second, check that the next line does not contain any braces - if it
-      // does, readability declines when putting it into a single line.
-      if (I[1]->Last->is(TT_LineComment))
-        return 0;
-      do {
-        if (Tok->is(tok::l_brace) && Tok->BlockKind != BK_BracedInit)
+        // Last, check that the third line starts with a closing brace.
+        Tok = I[2]->First;
+        if (Tok->isNot(tok::r_brace))
           return 0;
-        Tok = Tok->Next;
-      } while (Tok);
 
-      // Last, check that the third line starts with a closing brace.
-      Tok = I[2]->First;
-      if (Tok->isNot(tok::r_brace))
-        return 0;
+        // Don't merge "if (a) { .. } else {".
+        if (Tok->Next && Tok->Next->is(tok::kw_else))
+          return 0;
 
-      // Don't merge "if (a) { .. } else {".
-      if (Tok->Next && Tok->Next->is(tok::kw_else))
+        return 2;
+      }
+    } else if (I[1]->First->is(tok::l_brace)) {
+      if (I[1]->Last->is(TT_LineComment))
         return 0;
 
-      return 2;
+      // Check for Limit <= 2 to account for the " {".
+      if (Limit <= 2 || (Style.ColumnLimit == 0 && containsMustBreak(*I)))
+        return 0;
+      Limit -= 2;
+      unsigned MergedLines = 0;
+      if ((Style.AllowShortBlocksOnASingleLine ||
+          (I[1]->First == I[1]->Last && I + 2 != E &&
+          I[2]->First->is(tok::r_brace)))) {
+      MergedLines = tryMergeSimpleBlock(I + 1, E, Limit);
+      // If we managed to merge the block, count the statement header, which is
+      // on a separate line.
+      if (MergedLines > 0)
+        ++MergedLines;
+      }
+      return MergedLines;
     }
     return 0;
   }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to