From 2e65e1ae92a3c54f32a60664cc71e6ce0efccf00 Mon Sep 17 00:00:00 2001 From: Krasimir Georgiev Date: Wed, 8 Mar 2017 12:54:50 +0000 Subject: [PATCH] [clang-format] Look at NoLineBreak and NoLineBreakInOperand before breakProtrudingToken Summary: This patch makes ContinuationIndenter call breakProtrudingToken only if NoLineBreak and NoLineBreakInOperand is false. Previously, clang-format required two runs to converge on the following example with 24 columns: Note that the second operand shouldn't be splitted according to NoLineBreakInOperand, but the token breaker doesn't take that into account: ``` func(a, "long long long long", c); ``` After first run: ``` func(a, "long long " "long long", c); ``` After second run, where NoLineBreakInOperand is taken into account: ``` func(a, "long long " "long long", c); ``` With the patch, clang-format now obtains in one run: ``` func(a, "long long long" "long", c); ``` which is a better token split overall. Reviewers: djasper Reviewed By: djasper Subscribers: cfe-commits, klimek Differential Revision: https://reviews.llvm.org/D30575 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@297274 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Format/ContinuationIndenter.cpp | 6 +- unittests/Format/FormatTest.cpp | 89 ++++++++++++++++++++++++++++- 2 files changed, 92 insertions(+), 3 deletions(-) diff --git a/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp index b887df7c55..0561cdbdaf 100644 --- a/lib/Format/ContinuationIndenter.cpp +++ b/lib/Format/ContinuationIndenter.cpp @@ -848,6 +848,8 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State, (Current.IsMultiline ? Current.LastLineColumnWidth : State.Column + Current.ColumnWidth) - strlen("${"); + bool CanBreakProtrudingToken = !State.Stack.back().NoLineBreak && + !State.Stack.back().NoLineBreakInOperand; moveStatePastScopeOpener(State, Newline); moveStatePastFakeRParens(State); @@ -861,7 +863,9 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State, State.Column += Current.ColumnWidth; State.NextToken = State.NextToken->Next; - unsigned Penalty = breakProtrudingToken(Current, State, DryRun); + unsigned Penalty = 0; + if (CanBreakProtrudingToken) + Penalty = breakProtrudingToken(Current, State, DryRun); if (State.Column > getColumnLimit(State)) { unsigned ExcessCharacters = State.Column - getColumnLimit(State); Penalty += Style.PenaltyExcessCharacter * ExcessCharacters; diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp index 506de3b7f7..0c91b63a52 100644 --- a/unittests/Format/FormatTest.cpp +++ b/unittests/Format/FormatTest.cpp @@ -6471,8 +6471,9 @@ TEST_F(FormatTest, BreaksStringLiteralsWithin_TMacro) { "_T(\"aaaaaaaaaaaaaa\")\n" "_T(\"aaaaaaaaaaaa\")", format(" _T(\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\")", Style)); - EXPECT_EQ("f(x, _T(\"aaaaaaaaa\")\n" - " _T(\"aaaaaa\"),\n" + EXPECT_EQ("f(x,\n" + " _T(\"aaaaaaaaaaaa\")\n" + " _T(\"aaa\"),\n" " z);", format("f(x, _T(\"aaaaaaaaaaaaaaa\"), z);", Style)); @@ -6504,6 +6505,90 @@ TEST_F(FormatTest, BreaksStringLiteralsWithin_TMacro) { "_T(\"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXn\"));")); } +TEST_F(FormatTest, BreaksStringLiteralOperands) { + // In a function call with two operands, the second can be broken with no line + // break before it. + EXPECT_EQ("func(a, \"long long \"\n" + " \"long long\");", + format("func(a, \"long long long long\");", + getLLVMStyleWithColumns(24))); + // In a function call with three operands, the second must be broken with a + // line break before it. + EXPECT_EQ("func(a,\n" + " \"long long long \"\n" + " \"long\",\n" + " c);", + format("func(a, \"long long long long\", c);", + getLLVMStyleWithColumns(24))); + // In a function call with three operands, the third must be broken with a + // line break before it. + EXPECT_EQ("func(a, b,\n" + " \"long long long \"\n" + " \"long\");", + format("func(a, b, \"long long long long\");", + getLLVMStyleWithColumns(24))); + // In a function call with three operands, both the second and the third must + // be broken with a line break before them. + EXPECT_EQ("func(a,\n" + " \"long long long \"\n" + " \"long\",\n" + " \"long long long \"\n" + " \"long\");", + format("func(a, \"long long long long\", \"long long long long\");", + getLLVMStyleWithColumns(24))); + // In a chain of << with two operands, the second can be broken with no line + // break before it. + EXPECT_EQ("a << \"line line \"\n" + " \"line\";", + format("a << \"line line line\";", + getLLVMStyleWithColumns(20))); + // In a chain of << with three operands, the second can be broken with no line + // break before it. + EXPECT_EQ("abcde << \"line \"\n" + " \"line line\"\n" + " << c;", + format("abcde << \"line line line\" << c;", + getLLVMStyleWithColumns(20))); + // In a chain of << with three operands, the third must be broken with a line + // break before it. + EXPECT_EQ("a << b\n" + " << \"line line \"\n" + " \"line\";", + format("a << b << \"line line line\";", + getLLVMStyleWithColumns(20))); + // In a chain of << with three operands, the second can be broken with no line + // break before it and the third must be broken with a line break before it. + EXPECT_EQ("abcd << \"line line \"\n" + " \"line\"\n" + " << \"line line \"\n" + " \"line\";", + format("abcd << \"line line line\" << \"line line line\";", + getLLVMStyleWithColumns(20))); + // In a chain of binary operators with two operands, the second can be broken + // with no line break before it. + EXPECT_EQ("abcd + \"line line \"\n" + " \"line line\";", + format("abcd + \"line line line line\";", + getLLVMStyleWithColumns(20))); + // In a chain of binary operators with three operands, the second must be + // broken with a line break before it. + EXPECT_EQ("abcd +\n" + " \"line line \"\n" + " \"line line\" +\n" + " e;", + format("abcd + \"line line line line\" + e;", + getLLVMStyleWithColumns(20))); + // In a function call with two operands, with AlignAfterOpenBracket enabled, + // the first must be broken with a line break before it. + FormatStyle Style = getLLVMStyleWithColumns(25); + Style.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak; + EXPECT_EQ("someFunction(\n" + " \"long long long \"\n" + " \"long\",\n" + " a);", + format("someFunction(\"long long long long\", a);", Style)); +} + TEST_F(FormatTest, DontSplitStringLiteralsWithEscapedNewlines) { EXPECT_EQ( "aaaaaaaaaaa = \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\\n" -- 2.40.0