Index: lib/Format/ContinuationIndenter.cpp =================================================================== --- lib/Format/ContinuationIndenter.cpp +++ lib/Format/ContinuationIndenter.cpp @@ -1133,7 +1133,8 @@ // }, 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; Index: lib/Format/FormatToken.h =================================================================== --- lib/Format/FormatToken.h +++ lib/Format/FormatToken.h @@ -594,6 +594,8 @@ /// 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; }; @@ -616,6 +618,12 @@ 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. Index: lib/Format/TokenAnnotator.cpp =================================================================== --- lib/Format/TokenAnnotator.cpp +++ lib/Format/TokenAnnotator.cpp @@ -3041,6 +3041,23 @@ 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)) { + if (Left.BlockParameterCount > 1) + return true; + if (Left.BlockParameterCount == 1 && Left.Role) { + auto Comma = Left.Role->lastComma(); + if (Comma && Comma->Next && + !Comma->Next->isOneOf(TT_LambdaLSquare, tok::l_brace, tok::caret)) + return true; + } + } + return false; } Index: lib/Format/UnwrappedLineFormatter.cpp =================================================================== --- lib/Format/UnwrappedLineFormatter.cpp +++ lib/Format/UnwrappedLineFormatter.cpp @@ -982,8 +982,7 @@ Path.push_front(Best); Best = Best->Previous; } - for (std::deque::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); @@ -992,8 +991,8 @@ 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"; } }); } Index: unittests/Format/FormatTest.cpp =================================================================== --- unittests/Format/FormatTest.cpp +++ unittests/Format/FormatTest.cpp @@ -3178,11 +3178,12 @@ "});"); 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});"); @@ -3191,12 +3192,13 @@ } TEST_F(FormatTest, FormatNestedBlocksInMacros) { - EXPECT_EQ("#define MACRO() \\\n" - " Debug(aaa, /* force line break */ \\\n" - " { \\\n" - " int i; \\\n" - " int j; \\\n" - " })", + EXPECT_EQ("#define MACRO() \\\n" + " Debug( \\\n" + " aaa, /* force line break */ \\\n" + " { \\\n" + " int i; \\\n" + " int j; \\\n" + " })", format("#define MACRO() Debug(aaa, /* force line break */ \\\n" " { int i; int j; })", getGoogleStyle())); @@ -11596,9 +11598,10 @@ " other(x.begin(), x.end(), [&](int, int) { return 1; });\n" "}\n"); verifyFormat("void f() {\n" - " other(x.begin(), //\n" - " x.end(), //\n" - " [&](int, int) { return 1; });\n" + " other(\n" + " x.begin(), //\n" + " x.end(), //\n" + " [&](int, int) { return 1; });\n" "}\n"); verifyFormat("SomeFunction([]() { // A cool function...\n" " return 43;\n" @@ -11651,9 +11654,9 @@ verifyFormat("SomeFunction({[&] {\n" " // comment\n" "}});"); - verifyFormat("virtual aaaaaaaaaaaaaaaa(std::function bbbbbbbbbbbb =\n" - " [&]() { return true; },\n" - " aaaaa aaaaaaaaa);"); + verifyFormat("virtual aaaaaaaaaaaaaaaa(\n" + " std::function bbbbbbbbbbbb = [&]() { return true; },\n" + " aaaaa aaaaaaaaa);"); // Lambdas with return types. verifyFormat("int c = []() -> int { return 2; }();\n"); @@ -11680,17 +11683,74 @@ " 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"); + + // 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...] {};");