diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -4004,6 +4004,27 @@ void operator++ (int a); vs. void operator++(int a); object.operator++ (10); object.operator++(10); + * ``bool AfterRequiresInClause`` If ``true``, put space between requires keyword in a requires clause and + opening parentheses, if there is one. + + .. code-block:: c++ + + true: false: + template vs. template + requires (A && B) requires(A && B) + ... ... + + * ``bool AfterRequiresInExpression`` If ``true``, put space between requires keyword in a requires expression + and opening parentheses. + + .. code-block:: c++ + + true: false: + template vs. template + concept C = requires (T t) { concept C = requires(T t) { + ... ... + } } + * ``bool BeforeNonEmptyParentheses`` If ``true``, put a space before opening parentheses only if the parentheses are not empty. diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -3594,6 +3594,25 @@ /// object.operator++ (10); object.operator++(10); /// \endcode bool AfterOverloadedOperator; + /// If ``true``, put space between requires keyword in a requires clause and + /// opening parentheses, if there is one. + /// \code + /// true: false: + /// template vs. template + /// requires (A && B) requires(A && B) + /// ... ... + /// \endcode + bool AfterRequiresInClause; + /// If ``true``, put space between requires keyword in a requires expression + /// and opening parentheses. + /// \code + /// true: false: + /// template vs. template + /// concept C = requires (T t) { concept C = requires(T t) { + /// ... ... + /// } } + /// \endcode + bool AfterRequiresInExpression; /// If ``true``, put a space before opening parentheses only if the /// parentheses are not empty. /// \code @@ -3607,7 +3626,8 @@ : AfterControlStatements(false), AfterForeachMacros(false), AfterFunctionDeclarationName(false), AfterFunctionDefinitionName(false), AfterIfMacros(false), - AfterOverloadedOperator(false), BeforeNonEmptyParentheses(false) {} + AfterOverloadedOperator(false), AfterRequiresInClause(false), + AfterRequiresInExpression(false), BeforeNonEmptyParentheses(false) {} bool operator==(const SpaceBeforeParensCustom &Other) const { return AfterControlStatements == Other.AfterControlStatements && @@ -3617,6 +3637,8 @@ AfterFunctionDefinitionName == Other.AfterFunctionDefinitionName && AfterIfMacros == Other.AfterIfMacros && AfterOverloadedOperator == Other.AfterOverloadedOperator && + AfterRequiresInClause == Other.AfterRequiresInClause && + AfterRequiresInExpression == Other.AfterRequiresInExpression && BeforeNonEmptyParentheses == Other.BeforeNonEmptyParentheses; } }; diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -898,6 +898,9 @@ Spacing.AfterFunctionDeclarationName); IO.mapOptional("AfterIfMacros", Spacing.AfterIfMacros); IO.mapOptional("AfterOverloadedOperator", Spacing.AfterOverloadedOperator); + IO.mapOptional("AfterRequiresInClause", Spacing.AfterRequiresInClause); + IO.mapOptional("AfterRequiresInExpression", + Spacing.AfterRequiresInExpression); IO.mapOptional("BeforeNonEmptyParentheses", Spacing.BeforeNonEmptyParentheses); } @@ -1259,6 +1262,7 @@ LLVMStyle.SpaceBeforeCtorInitializerColon = true; LLVMStyle.SpaceBeforeInheritanceColon = true; LLVMStyle.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements; + LLVMStyle.SpaceBeforeParensOptions = {}; LLVMStyle.SpaceBeforeParensOptions.AfterControlStatements = true; LLVMStyle.SpaceBeforeParensOptions.AfterForeachMacros = true; LLVMStyle.SpaceBeforeParensOptions.AfterIfMacros = true; diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -3247,8 +3247,12 @@ if (Right.is(tok::l_paren)) { if (Left.is(TT_TemplateCloser) && Right.isNot(TT_FunctionTypeLParen)) return spaceRequiredBeforeParens(Right); - if (Left.is(tok::kw_requires)) - return spaceRequiredBeforeParens(Right); + if (Left.isOneOf(TT_RequiresClause, TT_RequiresClauseInARequiresExpression)) + return Style.SpaceBeforeParensOptions.AfterRequiresInClause || + spaceRequiredBeforeParens(Right); + if (Left.is(TT_RequiresExpression)) + return Style.SpaceBeforeParensOptions.AfterRequiresInExpression || + spaceRequiredBeforeParens(Right); if ((Left.is(tok::r_paren) && Left.is(TT_AttributeParen)) || (Left.is(tok::r_square) && Left.is(TT_AttributeSquare))) return 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 @@ -15012,6 +15012,84 @@ verifyFormat("X A::operator++();", SpaceAfterOverloadedOperator); verifyFormat("some_object.operator++();", SpaceAfterOverloadedOperator); verifyFormat("auto func() -> int;", SpaceAfterOverloadedOperator); + + auto SpaceAfterRequires = getLLVMStyle(); + SpaceAfterRequires.SpaceBeforeParens = FormatStyle::SBPO_Custom; + EXPECT_FALSE( + SpaceAfterRequires.SpaceBeforeParensOptions.AfterRequiresInClause); + EXPECT_FALSE( + SpaceAfterRequires.SpaceBeforeParensOptions.AfterRequiresInExpression); + verifyFormat("void f(auto x)\n" + " requires requires(int i) { x + i; }\n" + "{}", + SpaceAfterRequires); + verifyFormat("void f(auto x)\n" + " requires(requires(int i) { x + i; })\n" + "{}", + SpaceAfterRequires); + verifyFormat("if (requires(int i) { x + i; })\n" + " return;", + SpaceAfterRequires); + verifyFormat("bool b = requires(int i) { x + i; };", SpaceAfterRequires); + verifyFormat("template \n" + " requires(Foo)\n" + "class Bar;", + SpaceAfterRequires); + + SpaceAfterRequires.SpaceBeforeParensOptions.AfterRequiresInClause = true; + verifyFormat("void f(auto x)\n" + " requires requires(int i) { x + i; }\n" + "{}", + SpaceAfterRequires); + verifyFormat("void f(auto x)\n" + " requires (requires(int i) { x + i; })\n" + "{}", + SpaceAfterRequires); + verifyFormat("if (requires(int i) { x + i; })\n" + " return;", + SpaceAfterRequires); + verifyFormat("bool b = requires(int i) { x + i; };", SpaceAfterRequires); + verifyFormat("template \n" + " requires (Foo)\n" + "class Bar;", + SpaceAfterRequires); + + SpaceAfterRequires.SpaceBeforeParensOptions.AfterRequiresInClause = false; + SpaceAfterRequires.SpaceBeforeParensOptions.AfterRequiresInExpression = true; + verifyFormat("void f(auto x)\n" + " requires requires (int i) { x + i; }\n" + "{}", + SpaceAfterRequires); + verifyFormat("void f(auto x)\n" + " requires(requires (int i) { x + i; })\n" + "{}", + SpaceAfterRequires); + verifyFormat("if (requires (int i) { x + i; })\n" + " return;", + SpaceAfterRequires); + verifyFormat("bool b = requires (int i) { x + i; };", SpaceAfterRequires); + verifyFormat("template \n" + " requires(Foo)\n" + "class Bar;", + SpaceAfterRequires); + + SpaceAfterRequires.SpaceBeforeParensOptions.AfterRequiresInClause = true; + verifyFormat("void f(auto x)\n" + " requires requires (int i) { x + i; }\n" + "{}", + SpaceAfterRequires); + verifyFormat("void f(auto x)\n" + " requires (requires (int i) { x + i; })\n" + "{}", + SpaceAfterRequires); + verifyFormat("if (requires (int i) { x + i; })\n" + " return;", + SpaceAfterRequires); + verifyFormat("bool b = requires (int i) { x + i; };", SpaceAfterRequires); + verifyFormat("template \n" + " requires (Foo)\n" + "class Bar;", + SpaceAfterRequires); } TEST_F(FormatTest, SpaceAfterLogicalNot) {