r345753 - [clang-format] tweaked another case of lambda formatting
Krasimir Georgiev via cfe-commits
cfe-commits at lists.llvm.org
Wed Oct 31 10:56:57 PDT 2018
Author: krasimir
Date: Wed Oct 31 10:56:57 2018
New Revision: 345753
URL: http://llvm.org/viewvc/llvm-project?rev=345753&view=rev
Log:
[clang-format] tweaked another case of lambda formatting
Summary:
This is done in order to improve cases where the lambda's body is moved too far to the right. Consider the following snippet with column limit set to 79:
```
void f() {
leader::MakeThisCallHere(&leader_service_,
cq_.get(),
[this, liveness](const leader::ReadRecordReq& req,
std::function<void()> done) {
logger_->HandleReadRecord(
req, resp, std::move(done));
});
leader::MakeAnother(&leader_service_,
cq_.get(),
[this, liveness](const leader::ReadRecordReq& req,
std::function<void()> done) {
logger_->HandleReadRecord(
req, resp, std::move(done), a);
});
}
```
The tool favors extra indentation for the lambda body and so the code incurs extra wrapping and adjacent calls are indented to a different level. I find this behavior annoying and I'd like the tool to favor new lines and, thus, use the extra width.
The fix, reduced, brings the following formatting.
Before:
function(1,
[] {
DoStuff();
//
},
1);
After:
function(
1,
[] {
DoStuff();
//
},
1);
Refer to the new tests in FormatTest.cpp
Contributed by oleg.smolsky!
Reviewers: djasper, klimek, krasimir
Subscribers: cfe-commits, owenpan
Tags: #clang
Differential Revision: https://reviews.llvm.org/D52676
Modified:
cfe/trunk/lib/Format/ContinuationIndenter.cpp
cfe/trunk/lib/Format/FormatToken.h
cfe/trunk/lib/Format/TokenAnnotator.cpp
cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp
cfe/trunk/unittests/Format/FormatTest.cpp
Modified: cfe/trunk/lib/Format/ContinuationIndenter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/ContinuationIndenter.cpp?rev=345753&r1=345752&r2=345753&view=diff
==============================================================================
--- cfe/trunk/lib/Format/ContinuationIndenter.cpp (original)
+++ cfe/trunk/lib/Format/ContinuationIndenter.cpp Wed Oct 31 10:56:57 2018
@@ -1135,7 +1135,8 @@ unsigned ContinuationIndenter::moveState
// }, a, b, c);
if (Current.isNot(tok::comment) && Previous &&
Previous->isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) &&
- !Previous->is(TT_DictLiteral) && State.Stack.size() > 1) {
+ !Previous->is(TT_DictLiteral) && State.Stack.size() > 1 &&
+ !State.Stack.back().HasMultipleNestedBlocks) {
if (State.Stack[State.Stack.size() - 2].NestedBlockInlined && Newline)
for (unsigned i = 0, e = State.Stack.size() - 1; i != e; ++i)
State.Stack[i].NoLineBreak = true;
Modified: cfe/trunk/lib/Format/FormatToken.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/FormatToken.h?rev=345753&r1=345752&r2=345753&view=diff
==============================================================================
--- cfe/trunk/lib/Format/FormatToken.h (original)
+++ cfe/trunk/lib/Format/FormatToken.h Wed Oct 31 10:56:57 2018
@@ -599,6 +599,8 @@ public:
/// Notifies the \c Role that a comma was found.
virtual void CommaFound(const FormatToken *Token) {}
+ virtual const FormatToken *lastComma() { return nullptr; }
+
protected:
const FormatStyle &Style;
};
@@ -621,6 +623,12 @@ public:
Commas.push_back(Token);
}
+ const FormatToken *lastComma() override {
+ if (Commas.empty())
+ return nullptr;
+ return Commas.back();
+ }
+
private:
/// A struct that holds information on how to format a given list with
/// a specific number of columns.
Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=345753&r1=345752&r2=345753&view=diff
==============================================================================
--- cfe/trunk/lib/Format/TokenAnnotator.cpp (original)
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp Wed Oct 31 10:56:57 2018
@@ -3049,6 +3049,30 @@ bool TokenAnnotator::mustBreakBefore(con
return true;
}
+ // Deal with lambda arguments in C++ - we want consistent line breaks whether
+ // they happen to be at arg0, arg1 or argN. The selection is a bit nuanced
+ // as aggressive line breaks are placed when the lambda is not the last arg.
+ if ((Style.Language == FormatStyle::LK_Cpp ||
+ Style.Language == FormatStyle::LK_ObjC) &&
+ Left.is(tok::l_paren) && Left.BlockParameterCount > 0 &&
+ !Right.isOneOf(tok::l_paren, TT_LambdaLSquare)) {
+ // Multiple lambdas in the same function call force line breaks.
+ if (Left.BlockParameterCount > 1)
+ return true;
+
+ // A lambda followed by another arg forces a line break.
+ if (!Left.Role)
+ return false;
+ auto Comma = Left.Role->lastComma();
+ if (!Comma)
+ return false;
+ auto Next = Comma->getNextNonComment();
+ if (!Next)
+ return false;
+ if (!Next->isOneOf(TT_LambdaLSquare, tok::l_brace, tok::caret))
+ return true;
+ }
+
return false;
}
Modified: cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp?rev=345753&r1=345752&r2=345753&view=diff
==============================================================================
--- cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp (original)
+++ cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp Wed Oct 31 10:56:57 2018
@@ -988,8 +988,7 @@ private:
Path.push_front(Best);
Best = Best->Previous;
}
- for (std::deque<StateNode *>::iterator I = Path.begin(), E = Path.end();
- I != E; ++I) {
+ for (auto I = Path.begin(), E = Path.end(); I != E; ++I) {
unsigned Penalty = 0;
formatChildren(State, (*I)->NewLine, /*DryRun=*/false, Penalty);
Penalty += Indenter->addTokenToState(State, (*I)->NewLine, false);
@@ -998,8 +997,8 @@ private:
printLineState((*I)->Previous->State);
if ((*I)->NewLine) {
llvm::dbgs() << "Penalty for placing "
- << (*I)->Previous->State.NextToken->Tok.getName() << ": "
- << Penalty << "\n";
+ << (*I)->Previous->State.NextToken->Tok.getName()
+ << " on a new line: " << Penalty << "\n";
}
});
}
Modified: cfe/trunk/unittests/Format/FormatTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTest.cpp?rev=345753&r1=345752&r2=345753&view=diff
==============================================================================
--- cfe/trunk/unittests/Format/FormatTest.cpp (original)
+++ cfe/trunk/unittests/Format/FormatTest.cpp Wed Oct 31 10:56:57 2018
@@ -3277,11 +3277,12 @@ TEST_F(FormatTest, LayoutNestedBlocks) {
"});");
FormatStyle Style = getGoogleStyle();
Style.ColumnLimit = 45;
- verifyFormat("Debug(aaaaa,\n"
- " {\n"
- " if (aaaaaaaaaaaaaaaaaaaaaaaa) return;\n"
- " },\n"
- " a);",
+ verifyFormat("Debug(\n"
+ " aaaaa,\n"
+ " {\n"
+ " if (aaaaaaaaaaaaaaaaaaaaaaaa) return;\n"
+ " },\n"
+ " a);",
Style);
verifyFormat("SomeFunction({MACRO({ return output; }), b});");
@@ -11739,6 +11740,18 @@ TEST_F(FormatTest, FormatsLambdas) {
" x.end(), //\n"
" [&](int, int) { return 1; });\n"
"}\n");
+ verifyFormat("void f() {\n"
+ " other.other.other.other.other(\n"
+ " x.begin(), x.end(),\n"
+ " [something, rather](int, int, int, int, int, int, int) { return 1; });\n"
+ "}\n");
+ verifyFormat("void f() {\n"
+ " other.other.other.other.other(\n"
+ " x.begin(), x.end(),\n"
+ " [something, rather](int, int, int, int, int, int, int) {\n"
+ " //\n"
+ " });\n"
+ "}\n");
verifyFormat("SomeFunction([]() { // A cool function...\n"
" return 43;\n"
"});");
@@ -11790,9 +11803,9 @@ TEST_F(FormatTest, FormatsLambdas) {
verifyFormat("SomeFunction({[&] {\n"
" // comment\n"
"}});");
- verifyFormat("virtual aaaaaaaaaaaaaaaa(std::function<bool()> bbbbbbbbbbbb =\n"
- " [&]() { return true; },\n"
- " aaaaa aaaaaaaaa);");
+ verifyFormat("virtual aaaaaaaaaaaaaaaa(\n"
+ " std::function<bool()> bbbbbbbbbbbb = [&]() { return true; },\n"
+ " aaaaa aaaaaaaaa);");
// Lambdas with return types.
verifyFormat("int c = []() -> int { return 2; }();\n");
@@ -11819,17 +11832,76 @@ TEST_F(FormatTest, FormatsLambdas) {
" return 1; //\n"
"};");
- // Multiple lambdas in the same parentheses change indentation rules.
+ // Multiple lambdas in the same parentheses change indentation rules. These
+ // lambdas are forced to start on new lines.
verifyFormat("SomeFunction(\n"
" []() {\n"
- " int i = 42;\n"
- " return i;\n"
+ " //\n"
" },\n"
" []() {\n"
- " int j = 43;\n"
- " return j;\n"
+ " //\n"
" });");
+ // A lambda passed as arg0 is always pushed to the next line.
+ verifyFormat("SomeFunction(\n"
+ " [this] {\n"
+ " //\n"
+ " },\n"
+ " 1);\n");
+
+ // A multi-line lambda passed as arg1 forces arg0 to be pushed out, just like the arg0
+ // case above.
+ auto Style = getGoogleStyle();
+ Style.BinPackArguments = false;
+ verifyFormat("SomeFunction(\n"
+ " a,\n"
+ " [this] {\n"
+ " //\n"
+ " },\n"
+ " b);\n",
+ Style);
+ verifyFormat("SomeFunction(\n"
+ " a,\n"
+ " [this] {\n"
+ " //\n"
+ " },\n"
+ " b);\n");
+
+ // A lambda with a very long line forces arg0 to be pushed out irrespective of
+ // the BinPackArguments value (as long as the code is wide enough).
+ verifyFormat("something->SomeFunction(\n"
+ " a,\n"
+ " [this] {\n"
+ " D0000000000000000000000000000000000000000000000000000000000001();\n"
+ " },\n"
+ " b);\n");
+
+ // A multi-line lambda is pulled up as long as the introducer fits on the previous
+ // line and there are no further args.
+ verifyFormat("function(1, [this, that] {\n"
+ " //\n"
+ "});\n");
+ verifyFormat("function([this, that] {\n"
+ " //\n"
+ "});\n");
+ // FIXME: this format is not ideal and we should consider forcing the first arg
+ // onto its own line.
+ verifyFormat("function(a, b, c, //\n"
+ " d, [this, that] {\n"
+ " //\n"
+ " });\n");
+
+ // Multiple lambdas are treated correctly even when there is a short arg0.
+ verifyFormat("SomeFunction(\n"
+ " 1,\n"
+ " [this] {\n"
+ " //\n"
+ " },\n"
+ " [this] {\n"
+ " //\n"
+ " },\n"
+ " 1);\n");
+
// More complex introducers.
verifyFormat("return [i, args...] {};");
More information about the cfe-commits
mailing list