Index: lib/Format/BreakableToken.h =================================================================== --- lib/Format/BreakableToken.h +++ lib/Format/BreakableToken.h @@ -121,7 +121,8 @@ /// For breakable tokens that never use extra space at the end of a line, this /// is equivalent to getRangeLength with a Length of StringRef::npos. virtual unsigned getRemainingLength(unsigned LineIndex, unsigned Offset, - unsigned StartColumn) const { + unsigned StartColumn, + bool CanBreakAfter) const { return getRangeLength(LineIndex, Offset, StringRef::npos, StartColumn); } @@ -253,7 +254,8 @@ StringRef::size_type Length, unsigned StartColumn) const override; unsigned getRemainingLength(unsigned LineIndex, unsigned Offset, - unsigned StartColumn) const override; + unsigned StartColumn, + bool CanBreakAfter) const override; unsigned getContentStartColumn(unsigned LineIndex, bool Break) const override; protected: @@ -352,7 +354,8 @@ StringRef::size_type Length, unsigned StartColumn) const override; unsigned getRemainingLength(unsigned LineIndex, unsigned Offset, - unsigned StartColumn) const override; + unsigned StartColumn, + bool CanBreakAfter) const override; unsigned getContentStartColumn(unsigned LineIndex, bool Break) const override; void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split, WhitespaceManager &Whitespaces) const override; Index: lib/Format/BreakableToken.cpp =================================================================== --- lib/Format/BreakableToken.cpp +++ lib/Format/BreakableToken.cpp @@ -199,10 +199,11 @@ "indicates that the code tries to reflow it."); } -unsigned -BreakableStringLiteral::getRemainingLength(unsigned LineIndex, unsigned Offset, - unsigned StartColumn) const { - return UnbreakableTailLength + Postfix.size() + +unsigned BreakableStringLiteral::getRemainingLength(unsigned LineIndex, + unsigned Offset, + unsigned StartColumn, + bool CanBreakAfter) const { + return (CanBreakAfter ? 0 : UnbreakableTailLength) + Postfix.size() + encoding::columnWidthWithTabs(Line.substr(Offset, StringRef::npos), StartColumn, Style.TabWidth, Encoding); } @@ -497,7 +498,8 @@ unsigned BreakableBlockComment::getRemainingLength(unsigned LineIndex, unsigned Offset, - unsigned StartColumn) const { + unsigned StartColumn, + bool CanBreakAfter) const { return UnbreakableTailLength + getRangeLength(LineIndex, Offset, StringRef::npos, StartColumn); } Index: lib/Format/ContinuationIndenter.cpp =================================================================== --- lib/Format/ContinuationIndenter.cpp +++ lib/Format/ContinuationIndenter.cpp @@ -1619,7 +1619,8 @@ // We don't insert backslashes when breaking line comments. ColumnLimit = Style.ColumnLimit; } - if (Current.UnbreakableTailLength >= ColumnLimit) + bool CanBreakAfter = State.NextToken && canBreak(State); + if (!CanBreakAfter && Current.UnbreakableTailLength >= ColumnLimit) return {0, false}; // ColumnWidth was already accounted into State.Column before calling // breakProtrudingToken. @@ -1646,8 +1647,8 @@ unsigned ContentStartColumn = Token->getContentStartColumn(0, /*Break=*/false); // The number of columns left in the current logical line after TailOffset. - unsigned RemainingTokenColumns = - Token->getRemainingLength(0, TailOffset, ContentStartColumn); + unsigned RemainingTokenColumns = Token->getRemainingLength( + 0, TailOffset, ContentStartColumn, CanBreakAfter); // Adapt the start of the token, for example indent. if (!DryRun) Token->adaptStartOfLine(0, Whitespaces); @@ -1721,8 +1722,8 @@ // into the current line. unsigned ToNextSplitColumns = 0; if (NextSplit.first == StringRef::npos) { - ToNextSplitColumns = Token->getRemainingLength(LineIndex, TailOffset, - ContentStartColumn); + ToNextSplitColumns = Token->getRemainingLength( + LineIndex, TailOffset, ContentStartColumn, CanBreakAfter); } else { ToNextSplitColumns = Token->getRangeLength( LineIndex, TailOffset, @@ -1767,7 +1768,7 @@ Penalty += ExcessCharactersPenalty; TailOffset += Split.first + Split.second; RemainingTokenColumns = Token->getRemainingLength( - LineIndex, TailOffset, ContentStartColumn); + LineIndex, TailOffset, ContentStartColumn, CanBreakAfter); continue; } } @@ -1776,7 +1777,7 @@ Token->getContentStartColumn(LineIndex, /*Break=*/true); unsigned NewRemainingTokenColumns = Token->getRemainingLength( LineIndex, TailOffset + Split.first + Split.second, - ContentStartColumn); + ContentStartColumn, CanBreakAfter); // When breaking before a tab character, it may be moved by a few columns, // but will still be expanded to the next tab stop, so we don't save any @@ -1835,7 +1836,7 @@ // If the rest of the next line fits into the current line below the // column limit, we can safely reflow. RemainingTokenColumns = Token->getRemainingLength( - NextLineIndex, TailOffset, ContentStartColumn); + NextLineIndex, TailOffset, ContentStartColumn, CanBreakAfter); Reflow = true; if (ContentStartColumn + RemainingTokenColumns > ColumnLimit) { DEBUG(llvm::dbgs() << " Over limit after reflow, need: " @@ -1884,7 +1885,7 @@ ContentStartColumn = Token->getContentStartColumn(NextLineIndex, /*Break=*/false); RemainingTokenColumns = Token->getRemainingLength( - NextLineIndex, TailOffset, ContentStartColumn); + NextLineIndex, TailOffset, ContentStartColumn, CanBreakAfter); // Adapt the start of the token, for example indent. if (!DryRun) Token->adaptStartOfLine(NextLineIndex, Whitespaces); @@ -1924,7 +1925,7 @@ RemainingTokenColumns = Token->getRemainingLength( Token->getLineCount() - 1, TailOffset + SplitAfterLastLine.first + SplitAfterLastLine.second, - ContentStartColumn); + ContentStartColumn, CanBreakAfter); } State.Column = ContentStartColumn + RemainingTokenColumns - Index: unittests/Format/FormatTestTextProto.cpp =================================================================== --- unittests/Format/FormatTestTextProto.cpp +++ unittests/Format/FormatTestTextProto.cpp @@ -290,5 +290,17 @@ " product_data \n" ">"); } + +TEST_F(FormatTestTextProto, DiscardsUnbreakableTailIfCanBreakAfter) { + // The two closing braces count towards the string UnbreakableTailLength, but + // since we have broken after the corresponding opening braces, we don't + // consider that length for string breaking. + verifyFormat( + "foo: {\n" + " bar: {\n" + " text: \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"\n" + " }\n" + "}"); +} } // end namespace tooling } // end namespace clang