diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -3537,6 +3537,11 @@ return; }); + someMethod(someOtherMethod( + [](SomeReallyLongLambdaSignatureArgument foo) { + return; + })); + .. _Language: diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -1125,8 +1125,15 @@ Style.IndentWidth; } - if (NextNonComment->is(tok::l_brace) && NextNonComment->is(BK_Block)) - return Current.NestingLevel == 0 ? State.FirstIndent : CurrentState.Indent; + if (NextNonComment->is(tok::l_brace) && NextNonComment->is(BK_Block)) { + if (Current.NestingLevel == 0 || + (Style.LambdaBodyIndentation == FormatStyle::LBI_OuterScope && + State.NextToken->is(TT_LambdaLBrace) && State.Line && + State.Line->Level != 0)) { + return State.FirstIndent; + } + return CurrentState.Indent; + } if ((Current.isOneOf(tok::r_brace, tok::r_square) || (Current.is(tok::greater) && (Style.Language == FormatStyle::LK_Proto || @@ -1830,6 +1837,11 @@ } void ContinuationIndenter::moveStateToNewBlock(LineState &State) { + if (Style.LambdaBodyIndentation == FormatStyle::LBI_OuterScope && + State.NextToken->is(TT_LambdaLBrace) && State.Line && + State.Line->Level != 0) { + State.Stack.back().NestedBlockIndent = State.FirstIndent; + } unsigned NestedBlockIndent = State.Stack.back().NestedBlockIndent; // ObjC block sometimes follow special indentation rules. unsigned NewIndent = diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -511,9 +511,10 @@ ShouldMerge = !Style.BraceWrapping.AfterClass || (NextLine.First->is(tok::r_brace) && !Style.BraceWrapping.SplitEmptyRecord); - } if(TheLine->InPPDirective || - !TheLine->First->isOneOf(tok::kw_class, tok::kw_enum, - tok::kw_struct)) { + } + if (TheLine->InPPDirective || + !TheLine->First->isOneOf(tok::kw_class, tok::kw_enum, + tok::kw_struct)) { // Try to merge a block with left brace unwrapped that wasn't yet // covered. ShouldMerge = !Style.BraceWrapping.AfterFunction || @@ -1002,17 +1003,6 @@ int AdditionalIndent = P.Indent - Previous.Children[0]->Level * Style.IndentWidth; - - if (Style.LambdaBodyIndentation == FormatStyle::LBI_OuterScope && - P.NestedBlockIndent == P.LastSpace) { - if (State.NextToken->MatchingParen && - State.NextToken->MatchingParen->is(TT_LambdaLBrace)) { - State.Stack.pop_back(); - } - if (LBrace->is(TT_LambdaLBrace)) - AdditionalIndent = 0; - } - Penalty += BlockFormatter->format(Previous.Children, DryRun, AdditionalIndent, /*FixBadIndentation=*/true); diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -21914,60 +21914,61 @@ LLVMWithBeforeLambdaBody); // Lambdas with different indentation styles. - Style = getLLVMStyleWithColumns(100); - EXPECT_EQ("SomeResult doSomething(SomeObject promise) {\n" - " return promise.then(\n" - " [this, &someVariable, someObject = " - "std::mv(s)](std::vector evaluated) mutable {\n" - " return someObject.startAsyncAction().then(\n" - " [this, &someVariable](AsyncActionResult result) " - "mutable { result.processMore(); });\n" - " });\n" - "}\n", - format("SomeResult doSomething(SomeObject promise) {\n" - " return promise.then([this, &someVariable, someObject = " - "std::mv(s)](std::vector evaluated) mutable {\n" - " return someObject.startAsyncAction().then([this, " - "&someVariable](AsyncActionResult result) mutable {\n" - " result.processMore();\n" - " });\n" - " });\n" - "}\n", - Style)); + Style = getLLVMStyleWithColumns(60); + verifyFormat("Result doSomething(Promise promise) {\n" + " return promise.then(\n" + " [this, obj = std::move(s)](int evaluated) mutable {\n" + " return someObject.startAsyncAction().then(\n" + " [this, &obj](Result result) mutable {\n" + " result.processMore();\n" + " });\n" + " });\n" + "}\n", + Style); Style.LambdaBodyIndentation = FormatStyle::LBI_OuterScope; - verifyFormat("test() {\n" - " ([]() -> {\n" + verifyFormat("Result doSomething(Promise promise) {\n" + " return promise.then(\n" + " [this, obj = std::move(s)](int bar) mutable {\n" + " return obj.startAsyncAction().then(\n" + " [this, &obj](Result result) mutable {\n" + " result.processMore();\n" + " });\n" + " });\n" + "}\n", + Style); + verifyFormat("void test() {\n" + " ([]() -> auto {\n" " int b = 32;\n" " return 3;\n" " }).foo();\n" "}", Style); - verifyFormat("test() {\n" - " []() -> {\n" + verifyFormat("void test() {\n" + " []() -> auto {\n" " int b = 32;\n" " return 3;\n" " }\n" "}", Style); - verifyFormat("std::sort(v.begin(), v.end(),\n" - " [](const auto &someLongArgumentName, const auto " - "&someOtherLongArgumentName) {\n" - " return someLongArgumentName.someMemberVariable < " - "someOtherLongArgumentName.someMemberVariable;\n" - "});", + verifyFormat("void test() {\n" + " std::sort(v.begin(), v.end(),\n" + " [](const auto &foo, const auto &bar) {\n" + " return foo.baz < bar.baz;\n" + " });\n" + "}\n", Style); - verifyFormat("test() {\n" + verifyFormat("void test() {\n" " (\n" - " []() -> {\n" - " int b = 32;\n" - " return 3;\n" - " },\n" + " []() -> auto {\n" + " int b = 32;\n" + " return 3;\n" + " },\n" " foo, bar)\n" " .foo();\n" "}", Style); - verifyFormat("test() {\n" - " ([]() -> {\n" + verifyFormat("void test() {\n" + " ([]() -> auto {\n" " int b = 32;\n" " return 3;\n" " })\n" @@ -21975,54 +21976,82 @@ " .bar();\n" "}", Style); - EXPECT_EQ("SomeResult doSomething(SomeObject promise) {\n" - " return promise.then(\n" - " [this, &someVariable, someObject = " - "std::mv(s)](std::vector evaluated) mutable {\n" - " return someObject.startAsyncAction().then(\n" - " [this, &someVariable](AsyncActionResult result) mutable { " - "result.processMore(); });\n" - " });\n" - "}\n", - format("SomeResult doSomething(SomeObject promise) {\n" - " return promise.then([this, &someVariable, someObject = " - "std::mv(s)](std::vector evaluated) mutable {\n" - " return someObject.startAsyncAction().then([this, " - "&someVariable](AsyncActionResult result) mutable {\n" - " result.processMore();\n" - " });\n" - " });\n" - "}\n", - Style)); - EXPECT_EQ("SomeResult doSomething(SomeObject promise) {\n" - " return promise.then([this, &someVariable] {\n" - " return someObject.startAsyncAction().then(\n" - " [this, &someVariable](AsyncActionResult result) mutable { " - "result.processMore(); });\n" - " });\n" - "}\n", - format("SomeResult doSomething(SomeObject promise) {\n" - " return promise.then([this, &someVariable] {\n" - " return someObject.startAsyncAction().then([this, " - "&someVariable](AsyncActionResult result) mutable {\n" - " result.processMore();\n" - " });\n" - " });\n" - "}\n", - Style)); - Style = getGoogleStyle(); - Style.LambdaBodyIndentation = FormatStyle::LBI_OuterScope; - EXPECT_EQ("#define A \\\n" - " [] { \\\n" - " xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx( \\\n" - " xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx); \\\n" - " }", - format("#define A [] { xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx( \\\n" - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx); }", - Style)); - // TODO: The current formatting has a minor issue that's not worth fixing - // right now whereby the closing brace is indented relative to the signature - // instead of being aligned. This only happens with macros. + verifyFormat("void foo() {\n" + " aFunction(1, b(c(foo, bar, baz, [](d) {\n" + " auto f = e(d);\n" + " return f;\n" + " })));\n" + "}\n", + Style); + Style.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak; + verifyFormat("void foo() {\n" + " aFunction(\n" + " 1, b(c(\n" + " [](d) -> Foo {\n" + " auto f = e(d);\n" + " return f;\n" + " },\n" + " foo, Bar{},\n" + " [] {\n" + " auto g = h();\n" + " return g;\n" + " },\n" + " baz)));\n" + "}\n", + Style); + verifyFormat("void foo() {\n" + " aFunction(1, b(c(foo, Bar{}, baz, [](d) -> Foo {\n" + " auto f = e(\n" + " foo,\n" + " [&] {\n" + " auto g = h();\n" + " return g;\n" + " },\n" + " qux,\n" + " [&] -> Bar {\n" + " auto i = j();\n" + " return i;\n" + " });\n" + " return f;\n" + " })));\n" + "}\n", + Style); + verifyFormat("#define A \\\n" + " [] { \\\n" + " xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx( \\\n" + " xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx); \\\n" + " }", + Style); + verifyFormat("Namespace::Foo::Foo(\n" + " LongClassName bar, AnotherLongClassName baz)\n" + " : baz{baz}, func{[&] {\n" + " auto qux = bar;\n" + " return aFunkyFunctionCall(qux);\n" + " }} {}\n", + Style); + Style.BreakBeforeBraces = FormatStyle::BS_Custom; + Style.BraceWrapping.BeforeLambdaBody = true; + verifyFormat("void foo() {\n" + " aFunction(\n" + " 1, b(c(foo, Bar{}, baz,\n" + " [](d) -> Foo\n" + " {\n" + " auto f = e(\n" + " [&]\n" + " {\n" + " auto g = h();\n" + " return g;\n" + " },\n" + " qux,\n" + " [&] -> Bar\n" + " {\n" + " auto i = j();\n" + " return i;\n" + " });\n" + " return f;\n" + " })));\n" + "}\n", + Style); } TEST_F(FormatTest, LambdaWithLineComments) {