Skip to content

[clang-format] Adjust requires clause wrapping (#101550) #102078

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 31 additions & 5 deletions clang/docs/ClangFormatStyleOptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4147,7 +4147,8 @@ the configuration (without a prefix: ``Auto``).

**IndentRequiresClause** (``Boolean``) :versionbadge:`clang-format 15` :ref:`¶ <IndentRequiresClause>`
Indent the requires clause in a template. This only applies when
``RequiresClausePosition`` is ``OwnLine``, or ``WithFollowing``.
``RequiresClausePosition`` is ``OwnLine``, ``OwnLineWithBrace``,
or ``WithFollowing``.

In clang-format 12, 13 and 14 it was named ``IndentRequires``.

Expand Down Expand Up @@ -5379,23 +5380,48 @@ the configuration (without a prefix: ``Auto``).
Possible values:

* ``RCPS_OwnLine`` (in configuration: ``OwnLine``)
Always put the ``requires`` clause on its own line.
Always put the ``requires`` clause on its own line (possibly followed by
a semicolon).

.. code-block:: c++

template <typename T>
requires C<T>
requires C<T>
struct Foo {...

template <typename T>
requires C<T>
void bar(T t)
requires C<T>;

template <typename T>
requires C<T>
void bar(T t) {...

template <typename T>
void baz(T t)
requires C<T>
requires C<T>
{...

* ``RCPS_OwnLineWithBrace`` (in configuration: ``OwnLineWithBrace``)
As with ``OwnLine``, except, unless otherwise prohibited, place a
following open brace (of a function definition) to follow on the same
line.

.. code-block:: c++

void bar(T t)
requires C<T> {
return;
}

void bar(T t)
requires C<T> {}

template <typename T>
requires C<T>
void baz(T t) {
...

* ``RCPS_WithPreceding`` (in configuration: ``WithPreceding``)
Try to put the clause together with the preceding part of a declaration.
For class templates: stick to the template declaration.
Expand Down
34 changes: 29 additions & 5 deletions clang/include/clang/Format/Format.h
Original file line number Diff line number Diff line change
Expand Up @@ -2823,7 +2823,8 @@ struct FormatStyle {
PPDirectiveIndentStyle IndentPPDirectives;

/// Indent the requires clause in a template. This only applies when
/// ``RequiresClausePosition`` is ``OwnLine``, or ``WithFollowing``.
/// ``RequiresClausePosition`` is ``OwnLine``, ``OwnLineWithBrace``,
/// or ``WithFollowing``.
///
/// In clang-format 12, 13 and 14 it was named ``IndentRequires``.
/// \code
Expand Down Expand Up @@ -3909,22 +3910,45 @@ struct FormatStyle {
/// ``IndentRequires`` option is only used if the ``requires`` is put on the
/// start of a line.
enum RequiresClausePositionStyle : int8_t {
/// Always put the ``requires`` clause on its own line.
/// Always put the ``requires`` clause on its own line (possibly followed by
/// a semicolon).
/// \code
/// template <typename T>
/// requires C<T>
/// requires C<T>
/// struct Foo {...
///
/// template <typename T>
/// requires C<T>
/// void bar(T t)
/// requires C<T>;
///
/// template <typename T>
/// requires C<T>
/// void bar(T t) {...
///
/// template <typename T>
/// void baz(T t)
/// requires C<T>
/// requires C<T>
/// {...
/// \endcode
RCPS_OwnLine,
/// As with ``OwnLine``, except, unless otherwise prohibited, place a
/// following open brace (of a function definition) to follow on the same
/// line.
/// \code
/// void bar(T t)
/// requires C<T> {
/// return;
/// }
///
/// void bar(T t)
/// requires C<T> {}
///
/// template <typename T>
/// requires C<T>
/// void baz(T t) {
/// ...
/// \endcode
RCPS_OwnLineWithBrace,
/// Try to put the clause together with the preceding part of a declaration.
/// For class templates: stick to the template declaration.
/// For function templates: stick to the template declaration.
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Format/ContinuationIndenter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1395,6 +1395,7 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
switch (Style.RequiresClausePosition) {
case FormatStyle::RCPS_OwnLine:
case FormatStyle::RCPS_WithFollowing:
case FormatStyle::RCPS_OwnLineWithBrace:
return CurrentState.Indent;
default:
break;
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Format/Format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,7 @@ struct ScalarEnumerationTraits<FormatStyle::RequiresClausePositionStyle> {
static void enumeration(IO &IO,
FormatStyle::RequiresClausePositionStyle &Value) {
IO.enumCase(Value, "OwnLine", FormatStyle::RCPS_OwnLine);
IO.enumCase(Value, "OwnLineWithBrace", FormatStyle::RCPS_OwnLineWithBrace);
IO.enumCase(Value, "WithPreceding", FormatStyle::RCPS_WithPreceding);
IO.enumCase(Value, "WithFollowing", FormatStyle::RCPS_WithFollowing);
IO.enumCase(Value, "SingleLine", FormatStyle::RCPS_SingleLine);
Expand Down
7 changes: 5 additions & 2 deletions clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5664,6 +5664,7 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
if (Right.is(TT_RequiresClause)) {
switch (Style.RequiresClausePosition) {
case FormatStyle::RCPS_OwnLine:
case FormatStyle::RCPS_OwnLineWithBrace:
case FormatStyle::RCPS_WithFollowing:
return true;
default:
Expand All @@ -5682,11 +5683,13 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
(Style.BreakTemplateDeclarations == FormatStyle::BTDS_Leave &&
Right.NewlinesBefore > 0);
}
if (Left.ClosesRequiresClause && Right.isNot(tok::semi)) {
if (Left.ClosesRequiresClause) {
switch (Style.RequiresClausePosition) {
case FormatStyle::RCPS_OwnLine:
case FormatStyle::RCPS_WithPreceding:
return true;
return Right.isNot(tok::semi);
case FormatStyle::RCPS_OwnLineWithBrace:
return !Right.isOneOf(tok::semi, tok::l_brace);
default:
break;
}
Expand Down
83 changes: 83 additions & 0 deletions clang/unittests/Format/FormatTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25857,7 +25857,90 @@ TEST_F(FormatTest, RequiresClausesPositions) {
"}",
Style);

Style.RequiresClausePosition = FormatStyle::RCPS_OwnLineWithBrace;
Style.IndentRequiresClause = true;

verifyFormat("template <typename T>\n"
" requires(Foo<T> && std::trait<T>)\n"
"struct Bar;",
Style);

verifyFormat("template <typename T>\n"
" requires(Foo<T> && std::trait<T>)\n"
"class Bar {\n"
"public:\n"
" Bar(T t);\n"
" bool baz();\n"
"};",
Style);

verifyFormat(
"template <typename T>\n"
" requires requires(T &&t) {\n"
" typename T::I;\n"
" requires(F<typename T::I> && std::trait<typename T::I>);\n"
" }\n"
"Bar(T) -> Bar<typename T::I>;",
Style);

verifyFormat("template <typename T>\n"
" requires(Foo<T> && std::trait<T>)\n"
"constexpr T MyGlobal;",
Style);

verifyFormat("template <typename T>\n"
" requires Foo<T> && requires(T t) {\n"
" { t.baz() } -> std::same_as<bool>;\n"
" requires std::same_as<T::Factor, int>;\n"
" }\n"
"inline int bar(T t) {\n"
" return t.baz() ? T::Factor : 5;\n"
"}",
Style);

verifyFormat("template <typename T>\n"
"inline int bar(T t)\n"
" requires Foo<T> && requires(T t) {\n"
" { t.baz() } -> std::same_as<bool>;\n"
" requires std::same_as<T::Factor, int>;\n"
" } {\n"
" return t.baz() ? T::Factor : 5;\n"
"}",
Style);

verifyFormat("template <typename T>\n"
" requires F<T>\n"
"int bar(T t) {\n"
" return 5;\n"
"}",
Style);

verifyFormat("template <typename T>\n"
"int bar(T t)\n"
" requires F<T> {\n"
" return 5;\n"
"}",
Style);

verifyFormat("template <typename T>\n"
"int S::bar(T t) &&\n"
" requires F<T> {\n"
" return 5;\n"
"}",
Style);

verifyFormat("template <typename T>\n"
"int bar(T t)\n"
" requires F<T>;",
Style);

verifyFormat("template <typename T>\n"
"int bar(T t)\n"
" requires F<T> {}",
Style);

Style.RequiresClausePosition = FormatStyle::RCPS_SingleLine;
Style.IndentRequiresClause = false;
verifyFormat("template <typename T> requires Foo<T> struct Bar {};\n"
"template <typename T> requires Foo<T> void bar() {}\n"
"template <typename T> void bar() requires Foo<T> {}\n"
Expand Down
Loading