clang-format: Fix corner case for string splitting ..

.. in conjunction with Style.AlwaysBreakBeforeMultilineStrings. Also,
simplify the implementation by handling newly split strings and already
split strings by the same code.

llvm-svn: 189102
This commit is contained in:
Daniel Jasper 2013-08-23 11:57:34 +00:00
parent 377496bbad
commit f438cb7619
3 changed files with 31 additions and 12 deletions

View File

@ -116,12 +116,9 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
!Current.isOneOf(tok::r_paren, tok::r_brace))
return true;
if (Style.AlwaysBreakBeforeMultilineStrings &&
State.Column > State.Stack.back().Indent &&
Current.is(tok::string_literal) && Previous.isNot(tok::lessless) &&
Previous.Type != TT_InlineASMColon &&
((Current.getNextNonComment() &&
Current.getNextNonComment()->is(tok::string_literal)) ||
(Current.TokenText.find("\\\n") != StringRef::npos)))
State.Column > State.Stack.back().Indent && // Breaking saves columns.
Previous.isNot(tok::lessless) && Previous.Type != TT_InlineASMColon &&
NextIsMultilineString(State))
return true;
if (!Style.BreakBeforeBinaryOperators) {
@ -547,13 +544,8 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
}
State.Column += Current.CodePointCount;
State.NextToken = State.NextToken->Next;
unsigned Penalty = 0;
if (Newline || !Style.AlwaysBreakBeforeMultilineStrings ||
Current.isNot(tok::string_literal) || !Current.CanBreakBefore)
Penalty += breakProtrudingToken(Current, State, DryRun);
unsigned Penalty = breakProtrudingToken(Current, State, DryRun);
// If the previous has a special role, let it consume tokens as appropriate.
// It is necessary to start at the previous token for the only implemented
@ -688,5 +680,19 @@ unsigned ContinuationIndenter::getColumnLimit() const {
return Style.ColumnLimit - (Line.InPPDirective ? 2 : 0);
}
bool ContinuationIndenter::NextIsMultilineString(const LineState &State) {
const FormatToken &Current = *State.NextToken;
if (!Current.is(tok::string_literal))
return false;
if (Current.getNextNonComment() &&
Current.getNextNonComment()->is(tok::string_literal))
return true; // Implicit concatenation.
if (State.Column + Current.CodePointCount + Current.UnbreakableTailLength >
Style.ColumnLimit)
return true; // String will be split.
// String literal might have escaped newlines.
return Current.TokenText.find("\\\n") != StringRef::npos;
}
} // namespace format
} // namespace clang

View File

@ -84,6 +84,13 @@ private:
unsigned breakProtrudingToken(const FormatToken &Current, LineState &State,
bool DryRun);
/// \brief Returns \c true if the next token starts a multiline string
/// literal.
///
/// This includes implicitly concatenated strings, strings that will be broken
/// by clang-format and string literals with escaped newlines.
bool NextIsMultilineString(const LineState &State);
FormatStyle Style;
SourceManager &SourceMgr;
const AnnotatedLine &Line;

View File

@ -5265,6 +5265,12 @@ TEST_F(FormatTest, BreakStringLiterals) {
format("llvm::outs() << "
"\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaaaaaaaaa\";"));
EXPECT_EQ("ffff(\n"
" {\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \"\n"
" \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"});",
format("ffff({\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa "
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"});",
getGoogleStyle()));
FormatStyle AlignLeft = getLLVMStyleWithColumns(12);
AlignLeft.AlignEscapedNewlinesLeft = true;