From bda8482abaa87376f08700876504267bafa09880 Mon Sep 17 00:00:00 2001 From: Krasimir Georgiev Date: Thu, 18 Apr 2019 17:14:05 +0000 Subject: [PATCH] [clang-format] Fix indent of trailing raw string param after newline 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 | 29 +++++++++++++++++-------- clang/lib/Format/ContinuationIndenter.h | 4 ++-- clang/unittests/Format/FormatTestRawStrings.cpp | 14 ++++++++++++ 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp index 6be7f7e..01665cd 100644 --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -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. diff --git a/clang/lib/Format/ContinuationIndenter.h b/clang/lib/Format/ContinuationIndenter.h index bf85192..11df619 100644 --- a/clang/lib/Format/ContinuationIndenter.h +++ b/clang/lib/Format/ContinuationIndenter.h @@ -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. diff --git a/clang/unittests/Format/FormatTestRawStrings.cpp b/clang/unittests/Format/FormatTestRawStrings.cpp index 04b53c5..dc2f6b5 100644 --- a/clang/unittests/Format/FormatTestRawStrings.cpp +++ b/clang/unittests/Format/FormatTestRawStrings.cpp @@ -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 -- 2.7.4