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 @@ -369,6 +369,17 @@ /// \version 3.5 OperandAlignmentStyle AlignOperands; + /// If ``true``, aligns requires clause bodies with `requires` keyword. + /// \code + /// true: false: + /// template template + /// concept C = requires(T t) { vs. concept C = requires(T t) { + /// ... ... + /// } } + /// \endcode + /// \version 15 + bool AlignRequiresClauseBody; + /// If ``true``, aligns trailing comments. /// \code /// true: false: @@ -3856,6 +3867,7 @@ AlignConsecutiveMacros == R.AlignConsecutiveMacros && AlignEscapedNewlines == R.AlignEscapedNewlines && AlignOperands == R.AlignOperands && + AlignRequiresClauseBody == R.AlignRequiresClauseBody && AlignTrailingComments == R.AlignTrailingComments && AllowAllArgumentsOnNextLine == R.AllowAllArgumentsOnNextLine && AllowAllParametersOfDeclarationOnNextLine == 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 @@ -1398,7 +1398,7 @@ CurrentState.NestedBlockIndent = State.Column + Current.ColumnWidth + 1; if (Current.isOneOf(TT_LambdaLSquare, TT_LambdaArrow)) CurrentState.LastSpace = State.Column; - if (Current.is(TT_RequiresExpression)) + if (Current.is(TT_RequiresExpression) && Style.AlignRequiresClauseBody) CurrentState.NestedBlockIndent = State.Column; // Insert scopes created by fake parenthesis. 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 @@ -646,6 +646,7 @@ IO.mapOptional("AlignConsecutiveMacros", Style.AlignConsecutiveMacros); IO.mapOptional("AlignEscapedNewlines", Style.AlignEscapedNewlines); IO.mapOptional("AlignOperands", Style.AlignOperands); + IO.mapOptional("AlignRequiresClauseBody", Style.AlignRequiresClauseBody); IO.mapOptional("AlignTrailingComments", Style.AlignTrailingComments); IO.mapOptional("AllowAllArgumentsOnNextLine", Style.AllowAllArgumentsOnNextLine); @@ -1181,6 +1182,7 @@ LLVMStyle.AlignAfterOpenBracket = FormatStyle::BAS_Align; LLVMStyle.AlignArrayOfStructures = FormatStyle::AIAS_None; LLVMStyle.AlignOperands = FormatStyle::OAS_Align; + LLVMStyle.AlignRequiresClauseBody = true; LLVMStyle.AlignTrailingComments = true; LLVMStyle.AlignConsecutiveAssignments = {}; LLVMStyle.AlignConsecutiveAssignments.Enabled = false; 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 @@ -20033,6 +20033,7 @@ TEST_F(FormatTest, ParsesConfigurationBools) { FormatStyle Style = {}; Style.Language = FormatStyle::LK_Cpp; + CHECK_PARSE_BOOL(AlignRequiresClauseBody); CHECK_PARSE_BOOL(AlignTrailingComments); CHECK_PARSE_BOOL(AllowAllArgumentsOnNextLine); CHECK_PARSE_BOOL(AllowAllParametersOfDeclarationOnNextLine); @@ -24719,6 +24720,74 @@ "bar(requires);"); } +TEST_F(FormatTest, AlignRequiresClauseBody) { + auto Style = getLLVMStyle(); + EXPECT_EQ(Style.AlignRequiresClauseBody, true); + + verifyFormat("template \n" + "concept C = requires(T t) {\n" + " typename T::value;\n" + " requires requires(typename T::value v) {\n" + " { t == v } -> std::same_as;\n" + " };\n" + " };", + Style); + + verifyFormat( + "template \n" + "void bar(T)\n" + " requires Foo && requires(T t) {\n" + " { t.foo() } -> std::same_as;\n" + " } && requires(T t) {\n" + " { t.bar() } -> std::same_as;\n" + " --t;\n" + " };", + Style); + + verifyFormat("template \n" + " requires Foo &&\n" + " requires(T t) {\n" + " { t.foo() } -> std::same_as;\n" + " } && requires(T t) {\n" + " { t.bar() } -> std::same_as;\n" + " --t;\n" + " }\n" + "void bar(T);", + Style); + + Style.AlignRequiresClauseBody = false; + + verifyFormat("template \n" + "concept C = requires(T t) {\n" + " typename T::value;\n" + " requires requires(typename T::value v) {\n" + " { t == v } -> std::same_as;\n" + " };\n" + "};", + Style); + + verifyFormat("template \n" + "void bar(T)\n" + " requires Foo && requires(T t) {\n" + " { t.foo() } -> std::same_as;\n" + " } && requires(T t) {\n" + " { t.bar() } -> std::same_as;\n" + " --t;\n" + " };", + Style); + + verifyFormat("template \n" + " requires Foo &&\n" + " requires(T t) {\n" + " { t.foo() } -> std::same_as;\n" + " } && requires(T t) {\n" + " { t.bar() } -> std::same_as;\n" + " --t;\n" + " }\n" + "void bar(T);", + Style); +} + TEST_F(FormatTest, StatementAttributeLikeMacros) { FormatStyle Style = getLLVMStyle(); StringRef Source = "void Foo::slot() {\n"