Index: include/clang/Format/Format.h =================================================================== --- include/clang/Format/Format.h +++ include/clang/Format/Format.h @@ -872,6 +872,24 @@ /// \endcode bool BreakBeforeInheritanceComma; + /// \brief Wrap lambda block inside function parameters list. + /// \code + /// true: + /// connect( + /// []() + /// { + /// foo(); + /// bar(); + /// }); + /// + /// false: + /// connect([]() { + /// foo(); + /// bar(); + /// }); + /// \endcode + bool BreakBeforeLambdaBody; + /// \brief If ``true``, consecutive namespace declarations will be on the same /// line. If ``false``, each namespace is declared on a new line. /// \code @@ -1723,6 +1741,7 @@ BreakStringLiterals == R.BreakStringLiterals && ColumnLimit == R.ColumnLimit && CommentPragmas == R.CommentPragmas && BreakBeforeInheritanceComma == R.BreakBeforeInheritanceComma && + BreakBeforeLambdaBody == R.BreakBeforeLambdaBody && ConstructorInitializerAllOnOneLineOrOnePerLine == R.ConstructorInitializerAllOnOneLineOrOnePerLine && ConstructorInitializerIndentWidth == Index: lib/Format/ContinuationIndenter.cpp =================================================================== --- lib/Format/ContinuationIndenter.cpp +++ lib/Format/ContinuationIndenter.cpp @@ -1056,7 +1056,10 @@ !Previous->isOneOf(TT_DictLiteral, TT_ObjCMethodExpr)) { State.Stack.back().NestedBlockInlined = !Newline && - (Previous->isNot(tok::l_paren) || Previous->ParameterCount > 1); + (Previous->isNot(tok::l_paren) || + (Previous->ParameterCount > 1 || + (Style.BreakBeforeLambdaBody && + State.Line->containsAfter(*Previous, TT_LambdaLSquare)))); } moveStatePastFakeLParens(State, Newline); @@ -1289,7 +1292,10 @@ ParenState(NewIndent, LastSpace, AvoidBinPacking, NoLineBreak)); State.Stack.back().NestedBlockIndent = NestedBlockIndent; State.Stack.back().BreakBeforeParameter = BreakBeforeParameter; - State.Stack.back().HasMultipleNestedBlocks = Current.BlockParameterCount > 1; + State.Stack.back().HasMultipleNestedBlocks = + (Current.BlockParameterCount > 1 || + (Style.BreakBeforeLambdaBody && + State.Line->containsAfter(Current, TT_LambdaLSquare))); State.Stack.back().IsInsideObjCArrayLiteral = Current.is(TT_ArrayInitializerLSquare) && Current.Previous && Current.Previous->is(tok::at); Index: lib/Format/Format.cpp =================================================================== --- lib/Format/Format.cpp +++ lib/Format/Format.cpp @@ -337,6 +337,7 @@ IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces); IO.mapOptional("BreakBeforeInheritanceComma", Style.BreakBeforeInheritanceComma); + IO.mapOptional("BreakBeforeLambdaBody", Style.BreakBeforeLambdaBody); IO.mapOptional("BreakBeforeTernaryOperators", Style.BreakBeforeTernaryOperators); @@ -623,6 +624,7 @@ LLVMStyle.BreakAfterJavaFieldAnnotations = false; LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon; LLVMStyle.BreakBeforeInheritanceComma = false; + LLVMStyle.BreakBeforeLambdaBody = false; LLVMStyle.BreakStringLiterals = true; LLVMStyle.ColumnLimit = 80; LLVMStyle.CommentPragmas = "^ IWYU pragma:"; Index: lib/Format/TokenAnnotator.h =================================================================== --- lib/Format/TokenAnnotator.h +++ lib/Format/TokenAnnotator.h @@ -94,6 +94,28 @@ template bool endsWith(Ts... Tokens) const { return Last && Last->endsSequence(Tokens...); } + /// \c true if this line, starting at token 'Start', contains the given tokens in reverse order, + /// ignoring comments. + template bool containsBefore(const FormatToken& Start, Ts... Tokens) const { + const FormatToken *Tok = &Start; + while (Tok) { + if(Tok->startsSequence(Tokens...)) + return true; + Tok = Tok->Previous; + } + return false; + } + /// \c true if this line, starting at token 'Start', contains the given tokens in order, + /// ignoring comments. + template bool containsAfter(const FormatToken& Start, Ts... Tokens) const { + const FormatToken *Tok = &Start; + while (Tok) { + if(Tok->startsSequence(Tokens...)) + return true; + Tok = Tok->Next; + } + return false; + } /// \c true if this line looks like a function definition instead of a /// function declaration. Asserts MightBeFunctionDecl. Index: lib/Format/TokenAnnotator.cpp =================================================================== --- lib/Format/TokenAnnotator.cpp +++ lib/Format/TokenAnnotator.cpp @@ -2841,7 +2841,8 @@ if (Right.is(TT_InlineASMBrace)) return Right.HasUnescapedNewline; if (isAllmanBrace(Left) || isAllmanBrace(Right)) - return (Line.startsWith(tok::kw_enum) && Style.BraceWrapping.AfterEnum) || + return (Line.containsBefore(Right, TT_LambdaLSquare) && Style.BreakBeforeLambdaBody) || + (Line.startsWith(tok::kw_enum) && Style.BraceWrapping.AfterEnum) || (Line.startsWith(tok::kw_typedef, tok::kw_enum) && Style.BraceWrapping.AfterEnum) || (Line.startsWith(tok::kw_class) && Style.BraceWrapping.AfterClass) || Index: unittests/Format/FormatTest.cpp =================================================================== --- unittests/Format/FormatTest.cpp +++ unittests/Format/FormatTest.cpp @@ -11357,6 +11357,42 @@ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa> {\n" " //\n" " });"); + + // Check option "BreakBeforeLambdaBody" + FormatStyle LLVMWithBreakBeforeLambdaBody = getLLVMStyle(); + LLVMWithBreakBeforeLambdaBody.BreakBeforeLambdaBody = true; + verifyFormat("FunctionWithOneParam(\n" + " []()\n" + " {\n" + " // A cool function...\n" + " return 43;\n" + " },\n" + " 87);", + LLVMWithBreakBeforeLambdaBody); + verifyFormat("FunctionWithTwoParams(\n" + " []()\n" + " {\n" + " // A cool function...\n" + " return 43;\n" + " },\n" + " 87);", + LLVMWithBreakBeforeLambdaBody); + verifyFormat("TwoNestedLambdas(\n" + " []()\n" + " {\n" + " return Call(\n" + " []()\n" + " {\n" + " return 17;\n" + " });\n" + " });", + LLVMWithBreakBeforeLambdaBody); + verifyFormat("auto array = {[]()\n" + " {\n" + " return 43;\n" + " },\n" + " MyFunctor};", + LLVMWithBreakBeforeLambdaBody); } TEST_F(FormatTest, EmptyLinesInLambdas) {