Add basic support for splitting before function calls if it can't be
avoided.
This required a minor modification of the memoization as now the
"CurrentPenalty" depends on whether or not we break before the current
token. Therefore, the CurrentPenalty should not be memoized but added
after retrieving a value from memory. This should not affect the runtime
behavior.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@170337 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
index eb077d3..46af06f 100644
--- a/lib/Format/Format.cpp
+++ b/lib/Format/Format.cpp
@@ -198,7 +198,9 @@
else if (Current.Tok.is(tok::lessless) &&
State.FirstLessLess[ParenLevel] != 0)
State.Column = State.FirstLessLess[ParenLevel];
- else if (Previous.Tok.is(tok::equal) && ParenLevel != 0)
+ else if (ParenLevel != 0 &&
+ (Previous.Tok.is(tok::equal) || Current.Tok.is(tok::arrow) ||
+ Current.Tok.is(tok::period)))
// Indent and extra 4 spaces after '=' as it continues an expression.
// Don't do that on the top level, as we already indent 4 there.
State.Column = State.Indent[ParenLevel] + 4;
@@ -271,14 +273,23 @@
++State.ConsumedTokens;
}
- unsigned splitPenalty(const FormatToken &Token) {
- if (Token.Tok.is(tok::semi))
+ /// \brief Calculate the panelty for splitting after the token at \p Index.
+ unsigned splitPenalty(unsigned Index) {
+ assert(Index < Line.Tokens.size() &&
+ "Tried to calculate penalty for splitting after the last token");
+ const FormatToken &Left = Line.Tokens[Index];
+ const FormatToken &Right = Line.Tokens[Index + 1];
+ if (Left.Tok.is(tok::semi))
return 0;
- if (Token.Tok.is(tok::comma))
+ if (Left.Tok.is(tok::comma))
return 1;
- if (Token.Tok.is(tok::equal) || Token.Tok.is(tok::l_paren) ||
- Token.Tok.is(tok::pipepipe) || Token.Tok.is(tok::ampamp))
+ if (Left.Tok.is(tok::equal) || Left.Tok.is(tok::l_paren) ||
+ Left.Tok.is(tok::pipepipe) || Left.Tok.is(tok::ampamp))
return 2;
+
+ if (Right.Tok.is(tok::arrow) || Right.Tok.is(tok::period))
+ return 200;
+
return 3;
}
@@ -313,8 +324,7 @@
unsigned CurrentPenalty = 0;
if (NewLine) {
CurrentPenalty += Parameters.PenaltyIndentLevel * State.Indent.size() +
- Parameters.PenaltyExtraLine +
- splitPenalty(Line.Tokens[State.ConsumedTokens - 1]);
+ Parameters.PenaltyExtraLine + splitPenalty(State.ConsumedTokens - 1);
}
addTokenToState(NewLine, true, State);
@@ -335,17 +345,21 @@
// - are now computing for a smaller or equal StopAt.
unsigned SavedResult = I->second.first;
unsigned SavedStopAt = I->second.second;
- if (SavedResult != UINT_MAX || StopAt <= SavedStopAt)
- return SavedResult;
+ if (SavedResult != UINT_MAX)
+ return SavedResult + CurrentPenalty;
+ else if (StopAt <= SavedStopAt)
+ return UINT_MAX;
}
unsigned NoBreak = calcPenalty(State, false, StopAt);
unsigned WithBreak = calcPenalty(State, true, std::min(StopAt, NoBreak));
unsigned Result = std::min(NoBreak, WithBreak);
- if (Result != UINT_MAX)
- Result += CurrentPenalty;
+
+ // We have to store 'Result' without adding 'CurrentPenalty' as the latter
+ // can depend on 'NewLine'.
Memory[State] = std::pair<unsigned, unsigned>(Result, StopAt);
- return Result;
+
+ return Result == UINT_MAX ? UINT_MAX : Result + CurrentPenalty;
}
/// \brief Replaces the whitespace in front of \p Tok. Only call once for
@@ -737,9 +751,8 @@
if (Right.Tok.is(tok::r_paren) || Right.Tok.is(tok::l_brace) ||
Right.Tok.is(tok::comment) || Right.Tok.is(tok::greater))
return false;
- if (isBinaryOperator(Left))
- return true;
- if (Right.Tok.is(tok::lessless))
+ if (isBinaryOperator(Left) || Right.Tok.is(tok::lessless) ||
+ Right.Tok.is(tok::arrow) || Right.Tok.is(tok::period))
return true;
return Right.Tok.is(tok::colon) || Left.Tok.is(tok::comma) || Left.Tok.is(
tok::semi) || Left.Tok.is(tok::equal) || Left.Tok.is(tok::ampamp) ||
diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp
index 5ce1022..bcac37c 100644
--- a/unittests/Format/FormatTest.cpp
+++ b/unittests/Format/FormatTest.cpp
@@ -444,6 +444,37 @@
" 100000000 + 100000000) {\n}");
}
+TEST_F(FormatTest, WrapsAtFunctionCallsIfNecessary) {
+ verifyFormat(
+ "LoooooooooooooooooooooooooooooooooooooongObject\n"
+ " .looooooooooooooooooooooooooooooooooooooongFunction();");
+
+ verifyFormat(
+ "LoooooooooooooooooooooooooooooooooooooongObject\n"
+ " ->looooooooooooooooooooooooooooooooooooooongFunction();");
+
+ verifyFormat(
+ "LooooooooooooooooooooooooooooooooongObject->shortFunction(Parameter1,\n"
+ " Parameter2);");
+
+ verifyFormat(
+ "ShortObject->shortFunction(\n"
+ " LooooooooooooooooooooooooooooooooooooooooooooooongParameter1,\n"
+ " LooooooooooooooooooooooooooooooooooooooooooooooongParameter2);");
+
+ verifyFormat("loooooooooooooongFunction(\n"
+ " LoooooooooooooongObject->looooooooooooooooongFunction());");
+
+ verifyFormat(
+ "function(LoooooooooooooooooooooooooooooooooooongObject\n"
+ " ->loooooooooooooooooooooooooooooooooooooooongFunction());");
+
+ verifyFormat(
+ "if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaa) ||\n"
+ " aaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {\n"
+ "}");
+}
+
TEST_F(FormatTest, UnderstandsTemplateParameters) {
verifyFormat("A<int> a;");
verifyFormat("A<A<A<int> > > a;");