[clang-format] Fix indent of trailing raw string param after newline
authorKrasimir Georgiev <krasimir@google.com>
Thu, 18 Apr 2019 17:14:05 +0000 (17:14 +0000)
committerKrasimir Georgiev <krasimir@google.com>
Thu, 18 Apr 2019 17:14:05 +0000 (17:14 +0000)
Summary:
Currently clang-format uses ContinuationIndent to indent the contents of a raw
string literal that is the last parameter of the function call. This is to
achieve formatting similar to trailing:
```
f(1, 2, R"pb(
    x: y)pb");
```
However this had the unfortunate consequence of producing format like this:
```
fffffff(1, 2,
        R"pb(
    a: b
        )pb");
```

This patch makes clang-format consider indenting a trailing raw string param
after a newline based off the start of the format delimiter, producing:
```
fffffff(1, 2,
        R"pb(
          a: b
        )pb");
```

Reviewers: djasper

Reviewed By: djasper

Subscribers: cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D60558

llvm-svn: 358689

clang/lib/Format/ContinuationIndenter.cpp
clang/lib/Format/ContinuationIndenter.h
clang/unittests/Format/FormatTestRawStrings.cpp

index 6be7f7e..01665cd 100644 (file)
@@ -1196,7 +1196,8 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
   State.Column += Current.ColumnWidth;
   State.NextToken = State.NextToken->Next;
 
-  unsigned Penalty = handleEndOfLine(Current, State, DryRun, AllowBreak);
+  unsigned Penalty =
+      handleEndOfLine(Current, State, DryRun, AllowBreak, Newline);
 
   if (Current.Role)
     Current.Role->formatFromToken(State, this, DryRun);
@@ -1490,7 +1491,7 @@ static unsigned getLastLineEndColumn(StringRef Text, unsigned StartColumn,
 
 unsigned ContinuationIndenter::reformatRawStringLiteral(
     const FormatToken &Current, LineState &State,
-    const FormatStyle &RawStringStyle, bool DryRun) {
+    const FormatStyle &RawStringStyle, bool DryRun, bool Newline) {
   unsigned StartColumn = State.Column - Current.ColumnWidth;
   StringRef OldDelimiter = *getRawStringDelimiter(Current.TokenText);
   StringRef NewDelimiter =
@@ -1530,8 +1531,10 @@ unsigned ContinuationIndenter::reformatRawStringLiteral(
   // source.
   bool ContentStartsOnNewline = Current.TokenText[OldPrefixSize] == '\n';
   // If this token is the last parameter (checked by looking if it's followed by
-  // `)`, the base the indent off the line's nested block indent. Otherwise,
-  // base the indent off the arguments indent, so we can achieve:
+  // `)` and is not on a newline, the base the indent off the line's nested
+  // block indent. Otherwise, base the indent off the arguments indent, so we
+  // can achieve:
+  //
   // fffffffffff(1, 2, 3, R"pb(
   //     key1: 1  #
   //     key2: 2)pb");
@@ -1540,11 +1543,18 @@ unsigned ContinuationIndenter::reformatRawStringLiteral(
   //             R"pb(
   //               key1: 1  #
   //               key2: 2
+  //             )pb");
+  //
+  // fffffffffff(1, 2, 3,
+  //             R"pb(
+  //               key1: 1  #
+  //               key2: 2
   //             )pb",
   //             5);
-  unsigned CurrentIndent = (Current.Next && Current.Next->is(tok::r_paren))
-                               ? State.Stack.back().NestedBlockIndent
-                               : State.Stack.back().Indent;
+  unsigned CurrentIndent =
+      (!Newline && Current.Next && Current.Next->is(tok::r_paren))
+          ? State.Stack.back().NestedBlockIndent
+          : State.Stack.back().Indent;
   unsigned NextStartColumn = ContentStartsOnNewline
                                  ? CurrentIndent + Style.IndentWidth
                                  : FirstStartColumn;
@@ -1646,13 +1656,14 @@ unsigned ContinuationIndenter::addMultilineToken(const FormatToken &Current,
 
 unsigned ContinuationIndenter::handleEndOfLine(const FormatToken &Current,
                                                LineState &State, bool DryRun,
-                                               bool AllowBreak) {
+                                               bool AllowBreak, bool Newline) {
   unsigned Penalty = 0;
   // Compute the raw string style to use in case this is a raw string literal
   // that can be reformatted.
   auto RawStringStyle = getRawStringStyle(Current, State);
   if (RawStringStyle && !Current.Finalized) {
-    Penalty = reformatRawStringLiteral(Current, State, *RawStringStyle, DryRun);
+    Penalty = reformatRawStringLiteral(Current, State, *RawStringStyle, DryRun,
+                                       Newline);
   } else if (Current.IsMultiline && Current.isNot(TT_BlockComment)) {
     // Don't break multi-line tokens other than block comments and raw string
     // literals. Instead, just update the state.
index bf85192..11df619 100644 (file)
@@ -111,12 +111,12 @@ private:
   unsigned reformatRawStringLiteral(const FormatToken &Current,
                                     LineState &State,
                                     const FormatStyle &RawStringStyle,
-                                    bool DryRun);
+                                    bool DryRun, bool Newline);
 
   /// If the current token is at the end of the current line, handle
   /// the transition to the next line.
   unsigned handleEndOfLine(const FormatToken &Current, LineState &State,
-                           bool DryRun, bool AllowBreak);
+                           bool DryRun, bool AllowBreak, bool Newline);
 
   /// If \p Current is a raw string that is configured to be reformatted,
   /// return the style to be used.
index 04b53c5..dc2f6b5 100644 (file)
@@ -981,6 +981,20 @@ int f() {
 })test", Style));
 }
 
+TEST_F(FormatTestRawStrings, IndentsLastParamAfterNewline) {
+  FormatStyle Style = getRawStringPbStyleWithColumns(60);
+  expect_eq(R"test(
+fffffffffffffffffffff("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+                      R"pb(
+                        b: c
+                      )pb");)test",
+            format(R"test(
+fffffffffffffffffffff("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+                      R"pb(
+                      b: c
+                      )pb");)test",
+                   Style));
+}
 } // end namespace
 } // end namespace format
 } // end namespace clang