Index: lib/Format/ContinuationIndenter.h =================================================================== --- lib/Format/ContinuationIndenter.h +++ lib/Format/ContinuationIndenter.h @@ -108,11 +108,12 @@ /// Reformats a raw string literal. /// - /// \returns An extra penalty induced by reformatting the token. - unsigned reformatRawStringLiteral(const FormatToken &Current, - LineState &State, - const FormatStyle &RawStringStyle, - bool DryRun); + /// \returns A pair (Penalty, IsMultiline) where Penalty is the extra penalty + /// induced by reformatting the token and IsMultiline is true if the formatted + /// token is multiline. + std::pair + reformatRawStringLiteral(const FormatToken &Current, LineState &State, + const FormatStyle &RawStringStyle, bool DryRun); /// If the current token is at the end of the current line, handle /// the transition to the next line. Index: lib/Format/ContinuationIndenter.cpp =================================================================== --- lib/Format/ContinuationIndenter.cpp +++ lib/Format/ContinuationIndenter.cpp @@ -22,6 +22,11 @@ #include "llvm/Support/Debug.h" #define DEBUG_TYPE "format-indenter" +#define DBG(A) \ + LLVM_DEBUG({ \ + llvm::errs() << __func__ << ":" << __LINE__ << "::" << #A << " = " << A \ + << "\n"; \ + }); namespace clang { namespace format { @@ -1461,7 +1466,7 @@ } } -unsigned ContinuationIndenter::reformatRawStringLiteral( +std::pair ContinuationIndenter::reformatRawStringLiteral( const FormatToken &Current, LineState &State, const FormatStyle &RawStringStyle, bool DryRun) { unsigned StartColumn = State.Column - Current.ColumnWidth; @@ -1502,10 +1507,15 @@ // violate the rectangle rule and visually flows within the surrounding // source. bool ContentStartsOnNewline = Current.TokenText[OldPrefixSize] == '\n'; - unsigned NextStartColumn = - ContentStartsOnNewline - ? State.Stack.back().NestedBlockIndent + Style.IndentWidth - : FirstStartColumn; + DBG(State.Stack.back().NestedBlockIndent); + DBG(State.Stack.back().Indent); + DBG(Current.Next->TokenText); + unsigned CurrentIndent = (Current.Next && Current.Next->is(tok::r_paren)) + ? State.Stack.back().NestedBlockIndent + : State.Stack.back().Indent; + unsigned NextStartColumn = ContentStartsOnNewline + ? CurrentIndent + Style.IndentWidth + : FirstStartColumn; // The last start column is the column the raw string suffix starts if it is // put on a newline. @@ -1517,7 +1527,7 @@ // indent. unsigned LastStartColumn = Current.NewlinesBefore ? FirstStartColumn - NewPrefixSize - : State.Stack.back().NestedBlockIndent; + : CurrentIndent; std::pair Fixes = internal::reformat( RawStringStyle, RawText, {tooling::Range(0, RawText.size())}, @@ -1528,7 +1538,7 @@ tooling::Replacements NoFixes; if (!NewCode) { State.Column += Current.ColumnWidth; - return 0; + return {0, Current.IsMultiline}; } if (!DryRun) { if (NewDelimiter != OldDelimiter) { @@ -1577,7 +1587,11 @@ unsigned PrefixExcessCharacters = StartColumn + NewPrefixSize > Style.ColumnLimit ? StartColumn + NewPrefixSize - Style.ColumnLimit : 0; - return Fixes.second + PrefixExcessCharacters * Style.PenaltyExcessCharacter; + unsigned Penalty = + Fixes.second + PrefixExcessCharacters * Style.PenaltyExcessCharacter; + bool IsMultiline = + ContentStartsOnNewline || (NewCode->find('\n') != std::string::npos); + return {Penalty, IsMultiline}; } unsigned ContinuationIndenter::addMultilineToken(const FormatToken &Current, @@ -1604,7 +1618,14 @@ // that can be reformatted. auto RawStringStyle = getRawStringStyle(Current, State); if (RawStringStyle && !Current.Finalized) { - Penalty = reformatRawStringLiteral(Current, State, *RawStringStyle, DryRun); + std::pair PenaltyAndIsMultiline = + reformatRawStringLiteral(Current, State, *RawStringStyle, DryRun); + Penalty = PenaltyAndIsMultiline.first; + if (PenaltyAndIsMultiline.second) { + // Break before further function parameters on all levels. + for (unsigned i = 0, e = State.Stack.size(); i != e; ++i) + State.Stack[i].BreakBeforeParameter = true; + } } 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: unittests/Format/FormatTestRawStrings.cpp =================================================================== --- unittests/Format/FormatTestRawStrings.cpp +++ unittests/Format/FormatTestRawStrings.cpp @@ -889,6 +889,22 @@ Style)); } +TEST_F(FormatTestRawStrings, TODOBreaksBeforeParametersWithMultilineRawStrings) { + FormatStyle Style = getRawStringPbStyleWithColumns(60); + expect_eq(R"test( + +)test", + format(R"test( +int f() { + int a = g(x, R"pb( + key: 1 # + key: 2 + )pb", 3, 4); +} +)test", + Style)); +} + } // end namespace } // end namespace format } // end namespace clang