Index: include/clang/Format/Format.h =================================================================== --- include/clang/Format/Format.h +++ include/clang/Format/Format.h @@ -738,6 +738,23 @@ /// } /// \endcode bool BeforeElse; + /// \brief Wrap lambda block inside function parameters list. + /// \code + /// true: + /// connect( + /// []() + /// { + /// foo(); + /// bar(); + /// }); + /// + /// false: + /// connect([]() { + /// foo(); + /// bar(); + /// }); + /// \endcode + bool BeforeLambdaBody; /// \brief Indent the wrapped braces themselves. bool IndentBraces; /// \brief If ``false``, empty function body can be put on a single line. @@ -871,7 +888,7 @@ /// }; /// \endcode bool BreakBeforeInheritanceComma; - + /// \brief If ``true``, consecutive namespace declarations will be on the same /// line. If ``false``, each namespace is declared on a new line. /// \code Index: lib/Format/ContinuationIndenter.cpp =================================================================== --- lib/Format/ContinuationIndenter.cpp +++ lib/Format/ContinuationIndenter.cpp @@ -1066,7 +1066,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.BraceWrapping.BeforeLambdaBody && + State.Line->containsAfter(*Previous, TT_LambdaLSquare)))); } moveStatePastFakeLParens(State, Newline); @@ -1299,7 +1302,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.BraceWrapping.BeforeLambdaBody && + 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 @@ -447,6 +447,7 @@ IO.mapOptional("AfterExternBlock", Wrapping.AfterExternBlock); IO.mapOptional("BeforeCatch", Wrapping.BeforeCatch); IO.mapOptional("BeforeElse", Wrapping.BeforeElse); + IO.mapOptional("BeforeLambdaBody", Wrapping.BeforeLambdaBody); IO.mapOptional("IndentBraces", Wrapping.IndentBraces); IO.mapOptional("SplitEmptyFunction", Wrapping.SplitEmptyFunction); IO.mapOptional("SplitEmptyRecord", Wrapping.SplitEmptyRecord); @@ -543,9 +544,9 @@ if (Style.BreakBeforeBraces == FormatStyle::BS_Custom) return Style; FormatStyle Expanded = Style; - Expanded.BraceWrapping = {false, false, false, false, false, - false, false, false, false, false, - false, false, true, true, true}; + Expanded.BraceWrapping = {false, false, false, false, false, false, + false, false, false, false, false, false, + false, true, true, true}; switch (Style.BreakBeforeBraces) { case FormatStyle::BS_Linux: Expanded.BraceWrapping.AfterClass = true; @@ -578,6 +579,7 @@ Expanded.BraceWrapping.AfterExternBlock = true; Expanded.BraceWrapping.BeforeCatch = true; Expanded.BraceWrapping.BeforeElse = true; + Expanded.BraceWrapping.BeforeLambdaBody = true; break; case FormatStyle::BS_GNU: Expanded.BraceWrapping = {true, true, true, true, true, true, true, true, @@ -617,9 +619,9 @@ LLVMStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_None; LLVMStyle.BreakBeforeTernaryOperators = true; LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach; - LLVMStyle.BraceWrapping = {false, false, false, false, false, - false, false, false, false, false, - false, false, true, true, true}; + LLVMStyle.BraceWrapping = {false, false, false, false, false, false, + false, false, false, false, false, false, + false, true, true, true}; LLVMStyle.BreakAfterJavaFieldAnnotations = false; LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon; LLVMStyle.BreakBeforeInheritanceComma = false; Index: lib/Format/FormatToken.h =================================================================== --- lib/Format/FormatToken.h +++ lib/Format/FormatToken.h @@ -66,6 +66,7 @@ TYPE(JsTypeOptionalQuestion) \ TYPE(LambdaArrow) \ TYPE(LambdaLSquare) \ + TYPE(LambdaLBrace) \ TYPE(LeadingJavaAnnotation) \ TYPE(LineComment) \ TYPE(MacroBlockBegin) \ Index: lib/Format/TokenAnnotator.h =================================================================== --- lib/Format/TokenAnnotator.h +++ lib/Format/TokenAnnotator.h @@ -95,6 +95,17 @@ 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 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 @@ -1108,11 +1108,11 @@ // Reset token type in case we have already looked at it and then // recovered from an error (e.g. failure to find the matching >). - if (!CurrentToken->isOneOf(TT_LambdaLSquare, TT_ForEachMacro, - TT_FunctionLBrace, TT_ImplicitStringLiteral, - TT_InlineASMBrace, TT_JsFatArrow, TT_LambdaArrow, - TT_OverloadedOperator, TT_RegexLiteral, - TT_TemplateString, TT_ObjCStringLiteral)) + if (!CurrentToken->isOneOf( + TT_LambdaLSquare, TT_LambdaLBrace, TT_ForEachMacro, + TT_FunctionLBrace, TT_ImplicitStringLiteral, TT_InlineASMBrace, + TT_JsFatArrow, TT_LambdaArrow, TT_OverloadedOperator, + TT_RegexLiteral, TT_TemplateString, TT_ObjCStringLiteral)) CurrentToken->Type = TT_Unknown; CurrentToken->Role.reset(); CurrentToken->MatchingParen = nullptr; @@ -2896,7 +2896,9 @@ if (Right.is(TT_InlineASMBrace)) return Right.HasUnescapedNewline; if (isAllmanBrace(Left) || isAllmanBrace(Right)) - return (Line.startsWith(tok::kw_enum) && Style.BraceWrapping.AfterEnum) || + return ((Left.is(TT_LambdaLBrace) || Right.is(TT_LambdaLBrace)) && + Style.BraceWrapping.BeforeLambdaBody) || + (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: lib/Format/UnwrappedLineParser.cpp =================================================================== --- lib/Format/UnwrappedLineParser.cpp +++ lib/Format/UnwrappedLineParser.cpp @@ -1404,6 +1404,7 @@ return true; } } + FormatTok->Type = TT_LambdaLBrace; LSquare.Type = TT_LambdaLSquare; parseChildBlock(); return true; Index: unittests/Format/FormatTest.cpp =================================================================== --- unittests/Format/FormatTest.cpp +++ unittests/Format/FormatTest.cpp @@ -10461,6 +10461,7 @@ CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterExternBlock); CHECK_PARSE_NESTED_BOOL(BraceWrapping, BeforeCatch); CHECK_PARSE_NESTED_BOOL(BraceWrapping, BeforeElse); + CHECK_PARSE_NESTED_BOOL(BraceWrapping, BeforeLambdaBody); CHECK_PARSE_NESTED_BOOL(BraceWrapping, IndentBraces); CHECK_PARSE_NESTED_BOOL(BraceWrapping, SplitEmptyFunction); CHECK_PARSE_NESTED_BOOL(BraceWrapping, SplitEmptyRecord); @@ -11403,6 +11404,49 @@ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa> {\n" " //\n" " });"); + + // Check option "BraceWrapping.BeforeLambdaBody" + FormatStyle LLVMWithBeforeLambdaBody = getLLVMStyle(); + LLVMWithBeforeLambdaBody.BreakBeforeBraces = FormatStyle::BS_Custom; + LLVMWithBeforeLambdaBody.BraceWrapping.BeforeLambdaBody = true; + verifyFormat("FunctionWithOneParam(\n" + " []()\n" + " {\n" + " // A cool function...\n" + " return 43;\n" + " },\n" + " 87);", + LLVMWithBeforeLambdaBody); + verifyFormat("FunctionWithTwoParams(\n" + " []()\n" + " {\n" + " // A cool function...\n" + " return 43;\n" + " },\n" + " 87);", + LLVMWithBeforeLambdaBody); + verifyFormat("FunctionWithOneNestedLambdas(\n" + " []()\n" + " {\n" + " return 17;\n" + " });", + LLVMWithBeforeLambdaBody); + verifyFormat("TwoNestedLambdas(\n" + " []()\n" + " {\n" + " return Call(\n" + " []()\n" + " {\n" + " return 17;\n" + " });\n" + " });", + LLVMWithBeforeLambdaBody); + verifyFormat("auto array = {[]()\n" + " {\n" + " return 43;\n" + " },\n" + " MyFunctor};", + LLVMWithBeforeLambdaBody); } TEST_F(FormatTest, EmptyLinesInLambdas) {