Index: cfe/trunk/docs/ClangFormatStyleOptions.rst =================================================================== --- cfe/trunk/docs/ClangFormatStyleOptions.rst +++ cfe/trunk/docs/ClangFormatStyleOptions.rst @@ -449,6 +449,45 @@ return; } +**AllowShortLambdasOnASingleLine** (``ShortLambdaStyle``) + Dependent on the value, ``auto lambda []() { return 0; }`` can be put on a + single line. + + Possible values: + + * ``SLS_None`` (in configuration: ``None``) + Never merge lambdas into a single line. + + * ``SLS_Empty`` (in configuration: ``Empty``) + Only merge empty lambdas. + + .. code-block:: c++ + + auto lambda = [](int a) {} + auto lambda2 = [](int a) { + return a; + }; + + * ``SLS_Inline`` (in configuration: ``Inline``) + Merge lambda into a single line if argument of a function. + + .. code-block:: c++ + + auto lambda = [](int a) { + return a; + }; + sort(a.begin(), a.end(), ()[] { return x < y; }) + + * ``SLS_All`` (in configuration: ``All``) + Merge all lambdas fitting on a single line. + + .. code-block:: c++ + + auto lambda = [](int a) {} + auto lambda2 = [](int a) { return a; }; + + + **AllowShortLoopsOnASingleLine** (``bool``) If ``true``, ``while (true) continue;`` can be put on a single line. Index: cfe/trunk/include/clang/Format/Format.h =================================================================== --- cfe/trunk/include/clang/Format/Format.h +++ cfe/trunk/include/clang/Format/Format.h @@ -306,6 +306,39 @@ /// If ``true``, ``if (a) return;`` can be put on a single line. ShortIfStyle AllowShortIfStatementsOnASingleLine; + /// Different styles for merging short lambdas containing at most one + /// statement. + enum ShortLambdaStyle { + /// Never merge lambdas into a single line. + SLS_None, + /// Only merge empty lambdas. + /// \code + /// auto lambda = [](int a) {} + /// auto lambda2 = [](int a) { + /// return a; + /// }; + /// \endcode + SLS_Empty, + /// Merge lambda into a single line if argument of a function. + /// \code + /// auto lambda = [](int a) { + /// return a; + /// }; + /// sort(a.begin(), a.end(), ()[] { return x < y; }) + /// \endcode + SLS_Inline, + /// Merge all lambdas fitting on a single line. + /// \code + /// auto lambda = [](int a) {} + /// auto lambda2 = [](int a) { return a; }; + /// \endcode + SLS_All, + }; + + /// Dependent on the value, ``auto lambda []() { return 0; }`` can be put on a + /// single line. + ShortLambdaStyle AllowShortLambdasOnASingleLine; + /// If ``true``, ``while (true) continue;`` can be put on a single /// line. bool AllowShortLoopsOnASingleLine; @@ -1805,6 +1838,7 @@ R.AllowShortFunctionsOnASingleLine && AllowShortIfStatementsOnASingleLine == R.AllowShortIfStatementsOnASingleLine && + AllowShortLambdasOnASingleLine == R.AllowShortLambdasOnASingleLine && AllowShortLoopsOnASingleLine == R.AllowShortLoopsOnASingleLine && AlwaysBreakAfterReturnType == R.AlwaysBreakAfterReturnType && AlwaysBreakBeforeMultilineStrings == Index: cfe/trunk/lib/Format/Format.cpp =================================================================== --- cfe/trunk/lib/Format/Format.cpp +++ cfe/trunk/lib/Format/Format.cpp @@ -119,6 +119,17 @@ } }; +template <> struct ScalarEnumerationTraits { + static void enumeration(IO &IO, FormatStyle::ShortLambdaStyle &Value) { + IO.enumCase(Value, "None", FormatStyle::SLS_None); + IO.enumCase(Value, "false", FormatStyle::SLS_None); + IO.enumCase(Value, "Empty", FormatStyle::SLS_Empty); + IO.enumCase(Value, "Inline", FormatStyle::SLS_Inline); + IO.enumCase(Value, "All", FormatStyle::SLS_All); + IO.enumCase(Value, "true", FormatStyle::SLS_All); + } +}; + template <> struct ScalarEnumerationTraits { static void enumeration(IO &IO, FormatStyle::BinPackStyle &Value) { IO.enumCase(Value, "Auto", FormatStyle::BPS_Auto); @@ -347,6 +358,8 @@ Style.AllowShortCaseLabelsOnASingleLine); IO.mapOptional("AllowShortFunctionsOnASingleLine", Style.AllowShortFunctionsOnASingleLine); + IO.mapOptional("AllowShortLambdasOnASingleLine", + Style.AllowShortLambdasOnASingleLine); IO.mapOptional("AllowShortIfStatementsOnASingleLine", Style.AllowShortIfStatementsOnASingleLine); IO.mapOptional("AllowShortLoopsOnASingleLine", @@ -653,6 +666,7 @@ LLVMStyle.AllowShortBlocksOnASingleLine = false; LLVMStyle.AllowShortCaseLabelsOnASingleLine = false; LLVMStyle.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never; + LLVMStyle.AllowShortLambdasOnASingleLine = FormatStyle::SLS_All; LLVMStyle.AllowShortLoopsOnASingleLine = false; LLVMStyle.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None; LLVMStyle.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None; Index: cfe/trunk/lib/Format/FormatToken.h =================================================================== --- cfe/trunk/lib/Format/FormatToken.h +++ cfe/trunk/lib/Format/FormatToken.h @@ -65,6 +65,7 @@ TYPE(JsTypeOperator) \ TYPE(JsTypeOptionalQuestion) \ TYPE(LambdaArrow) \ + TYPE(LambdaLBrace) \ TYPE(LambdaLSquare) \ TYPE(LeadingJavaAnnotation) \ TYPE(LineComment) \ Index: cfe/trunk/lib/Format/TokenAnnotator.cpp =================================================================== --- cfe/trunk/lib/Format/TokenAnnotator.cpp +++ cfe/trunk/lib/Format/TokenAnnotator.cpp @@ -1191,11 +1191,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,7 @@ // Returns 'true' if 'Tok' is a brace we'd want to break before in Allman style. static bool isAllmanBrace(const FormatToken &Tok) { return Tok.is(tok::l_brace) && Tok.BlockKind == BK_Block && - !Tok.isOneOf(TT_ObjCBlockLBrace, TT_DictLiteral); + !Tok.isOneOf(TT_ObjCBlockLBrace, TT_LambdaLBrace, TT_DictLiteral); } bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, @@ -3024,6 +3024,19 @@ if (Left.is(TT_ObjCBlockLBrace) && !Style.AllowShortBlocksOnASingleLine) return true; + if (Left.is(TT_LambdaLBrace)) { + if (Left.MatchingParen && Left.MatchingParen->Next && + Left.MatchingParen->Next->isOneOf(tok::comma, tok::r_paren) && + Style.AllowShortLambdasOnASingleLine == FormatStyle::SLS_Inline) + return false; + + if (Style.AllowShortLambdasOnASingleLine == FormatStyle::SLS_None || + Style.AllowShortLambdasOnASingleLine == FormatStyle::SLS_Inline || + (!Left.Children.empty() && + Style.AllowShortLambdasOnASingleLine == FormatStyle::SLS_Empty)) + return true; + } + // Put multiple C# attributes on a new line. if (Style.isCSharp() && ((Left.is(TT_AttributeSquare) && Left.is(tok::r_square)) || Index: cfe/trunk/lib/Format/UnwrappedLineParser.cpp =================================================================== --- cfe/trunk/lib/Format/UnwrappedLineParser.cpp +++ cfe/trunk/lib/Format/UnwrappedLineParser.cpp @@ -1475,6 +1475,7 @@ return true; } } + FormatTok->Type = TT_LambdaLBrace; LSquare.Type = TT_LambdaLSquare; parseChildBlock(); return true; Index: cfe/trunk/unittests/Format/FormatTest.cpp =================================================================== --- cfe/trunk/unittests/Format/FormatTest.cpp +++ cfe/trunk/unittests/Format/FormatTest.cpp @@ -12432,6 +12432,43 @@ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa> {\n" " //\n" " });"); + + FormatStyle DoNotMerge = getLLVMStyle(); + DoNotMerge.AllowShortLambdasOnASingleLine = FormatStyle::SLS_None; + verifyFormat("auto c = []() {\n" + " return b;\n" + "};", + "auto c = []() { return b; };", DoNotMerge); + verifyFormat("auto c = []() {\n" + "};", + " auto c = []() {};", DoNotMerge); + + FormatStyle MergeEmptyOnly = getLLVMStyle(); + MergeEmptyOnly.AllowShortLambdasOnASingleLine = FormatStyle::SLS_Empty; + verifyFormat("auto c = []() {\n" + " return b;\n" + "};", + "auto c = []() {\n" + " return b;\n" + " };", + MergeEmptyOnly); + verifyFormat("auto c = []() {};", + "auto c = []() {\n" + "};", + MergeEmptyOnly); + + FormatStyle MergeInline = getLLVMStyle(); + MergeInline.AllowShortLambdasOnASingleLine = FormatStyle::SLS_Inline; + verifyFormat("auto c = []() {\n" + " return b;\n" + "};", + "auto c = []() { return b; };", MergeInline); + verifyFormat("function([]() { return b; })", "function([]() { return b; })", + MergeInline); + verifyFormat("function([]() { return b; }, a)", + "function([]() { return b; }, a)", MergeInline); + verifyFormat("function(a, []() { return b; })", + "function(a, []() { return b; })", MergeInline); } TEST_F(FormatTest, EmptyLinesInLambdas) {