Skip to content

[clang-format] Add SpacesInParensOption for filtering repeated parens #77522

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 6 commits into from
Jul 2, 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
23 changes: 19 additions & 4 deletions clang/docs/ClangFormatStyleOptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6242,6 +6242,7 @@ the configuration (without a prefix: ``Auto``).
# Example of usage:
SpacesInParens: Custom
SpacesInParensOptions:
ExceptDoubleParentheses: false
InConditionalStatements: true
InEmptyParentheses: true

Expand All @@ -6254,9 +6255,22 @@ the configuration (without a prefix: ``Auto``).
# Should be declared this way:
SpacesInParens: Custom
SpacesInParensOptions:
ExceptDoubleParentheses: false
InConditionalStatements: true
Other: true

* ``bool ExceptDoubleParentheses`` Override any of the following options to prevent addition of space
when both opening and closing parentheses use multiple parentheses.

.. code-block:: c++

true:
__attribute__(( noreturn ))
__decltype__(( x ))
if (( a = b ))
false:
Uses the applicable option.

* ``bool InConditionalStatements`` Put a space in parentheses only inside conditional statements
(``for/if/while/switch...``).

Expand All @@ -6270,8 +6284,9 @@ the configuration (without a prefix: ``Auto``).

.. code-block:: c++

true: false:
x = ( int32 )y vs. x = (int32)y
true: false:
x = ( int32 )y vs. x = (int32)y
y = (( int (*)(int) )foo)(x); y = ((int (*)(int))foo)(x);

* ``bool InEmptyParentheses`` Insert a space in empty parentheses, i.e. ``()``.

Expand All @@ -6289,8 +6304,8 @@ the configuration (without a prefix: ``Auto``).

.. code-block:: c++

true: false:
t f( Deleted & ) & = delete; vs. t f(Deleted &) & = delete;
true: false:
t f( Deleted & ) & = delete; vs. t f(Deleted &) & = delete;


.. _SpacesInParentheses:
Expand Down
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1130,6 +1130,9 @@ clang-format
- Adds ``LeftWithLastLine`` suboption to ``AlignEscapedNewlines``.
- Adds ``KeepEmptyLines`` option to deprecate ``KeepEmptyLinesAtEOF``
and ``KeepEmptyLinesAtTheStartOfBlocks``.
- Add ``ExceptDoubleParentheses`` sub-option for ``SpacesInParensOptions``
to override addition of spaces between multiple, non-redundant parentheses
similar to the rules used for ``RemoveParentheses``.

libclang
--------
Expand Down
35 changes: 26 additions & 9 deletions clang/include/clang/Format/Format.h
Original file line number Diff line number Diff line change
Expand Up @@ -4679,10 +4679,22 @@ struct FormatStyle {
/// # Should be declared this way:
/// SpacesInParens: Custom
/// SpacesInParensOptions:
/// ExceptDoubleParentheses: false
/// InConditionalStatements: true
/// Other: true
/// \endcode
struct SpacesInParensCustom {
/// Override any of the following options to prevent addition of space
/// when both opening and closing parentheses use multiple parentheses.
/// \code
/// true:
/// __attribute__(( noreturn ))
/// __decltype__(( x ))
/// if (( a = b ))
/// \endcode
/// false:
/// Uses the applicable option.
bool ExceptDoubleParentheses;
/// Put a space in parentheses only inside conditional statements
/// (``for/if/while/switch...``).
/// \code
Expand All @@ -4693,8 +4705,9 @@ struct FormatStyle {
bool InConditionalStatements;
/// Put a space in C style casts.
/// \code
/// true: false:
/// x = ( int32 )y vs. x = (int32)y
/// true: false:
/// x = ( int32 )y vs. x = (int32)y
/// y = (( int (*)(int) )foo)(x); y = ((int (*)(int))foo)(x);
/// \endcode
bool InCStyleCasts;
/// Insert a space in empty parentheses, i.e. ``()``.
Expand All @@ -4710,23 +4723,26 @@ struct FormatStyle {
bool InEmptyParentheses;
/// Put a space in parentheses not covered by preceding options.
/// \code
/// true: false:
/// t f( Deleted & ) & = delete; vs. t f(Deleted &) & = delete;
/// true: false:
/// t f( Deleted & ) & = delete; vs. t f(Deleted &) & = delete;
/// \endcode
bool Other;

SpacesInParensCustom()
: InConditionalStatements(false), InCStyleCasts(false),
InEmptyParentheses(false), Other(false) {}
: ExceptDoubleParentheses(false), InConditionalStatements(false),
InCStyleCasts(false), InEmptyParentheses(false), Other(false) {}

SpacesInParensCustom(bool InConditionalStatements, bool InCStyleCasts,
SpacesInParensCustom(bool ExceptDoubleParentheses,
bool InConditionalStatements, bool InCStyleCasts,
bool InEmptyParentheses, bool Other)
: InConditionalStatements(InConditionalStatements),
: ExceptDoubleParentheses(ExceptDoubleParentheses),
InConditionalStatements(InConditionalStatements),
InCStyleCasts(InCStyleCasts), InEmptyParentheses(InEmptyParentheses),
Other(Other) {}

bool operator==(const SpacesInParensCustom &R) const {
return InConditionalStatements == R.InConditionalStatements &&
return ExceptDoubleParentheses == R.ExceptDoubleParentheses &&
InConditionalStatements == R.InConditionalStatements &&
InCStyleCasts == R.InCStyleCasts &&
InEmptyParentheses == R.InEmptyParentheses && Other == R.Other;
}
Expand All @@ -4744,6 +4760,7 @@ struct FormatStyle {
/// # Example of usage:
/// SpacesInParens: Custom
/// SpacesInParensOptions:
/// ExceptDoubleParentheses: false
/// InConditionalStatements: true
/// InEmptyParentheses: true
/// \endcode
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/Format/Format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -729,6 +729,7 @@ template <> struct MappingTraits<FormatStyle::SpacesInLineComment> {

template <> struct MappingTraits<FormatStyle::SpacesInParensCustom> {
static void mapping(IO &IO, FormatStyle::SpacesInParensCustom &Spaces) {
IO.mapOptional("ExceptDoubleParentheses", Spaces.ExceptDoubleParentheses);
IO.mapOptional("InCStyleCasts", Spaces.InCStyleCasts);
IO.mapOptional("InConditionalStatements", Spaces.InConditionalStatements);
IO.mapOptional("InEmptyParentheses", Spaces.InEmptyParentheses);
Expand Down Expand Up @@ -1184,8 +1185,8 @@ template <> struct MappingTraits<FormatStyle> {
(SpacesInParentheses || SpaceInEmptyParentheses ||
SpacesInConditionalStatement || SpacesInCStyleCastParentheses)) {
if (SpacesInParentheses) {
// set all options except InCStyleCasts and InEmptyParentheses
// to true for backward compatibility.
// For backward compatibility.
Style.SpacesInParensOptions.ExceptDoubleParentheses = false;
Style.SpacesInParensOptions.InConditionalStatements = true;
Style.SpacesInParensOptions.InCStyleCasts =
SpacesInCStyleCastParentheses;
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4361,6 +4361,15 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
Right.is(tok::r_brace) && Right.isNot(BK_Block))) {
return Style.SpacesInParensOptions.InEmptyParentheses;
}
if (Style.SpacesInParens == FormatStyle::SIPO_Custom &&
Style.SpacesInParensOptions.ExceptDoubleParentheses &&
Left.is(tok::r_paren) && Right.is(tok::r_paren)) {
auto *InnerLParen = Left.MatchingParen;
if (InnerLParen && InnerLParen->Previous == Right.MatchingParen) {
InnerLParen->SpacesRequiredBefore = 0;
return false;
}
}
if (Style.SpacesInParensOptions.InConditionalStatements) {
const FormatToken *LeftParen = nullptr;
if (Left.is(tok::l_paren))
Expand Down
21 changes: 13 additions & 8 deletions clang/unittests/Format/ConfigParseTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ TEST(ConfigParseTest, ParsesConfigurationBools) {
CHECK_PARSE_NESTED_BOOL(SpaceBeforeParensOptions, AfterOverloadedOperator);
CHECK_PARSE_NESTED_BOOL(SpaceBeforeParensOptions, AfterPlacementOperator);
CHECK_PARSE_NESTED_BOOL(SpaceBeforeParensOptions, BeforeNonEmptyParentheses);
CHECK_PARSE_NESTED_BOOL(SpacesInParensOptions, ExceptDoubleParentheses);
CHECK_PARSE_NESTED_BOOL(SpacesInParensOptions, InCStyleCasts);
CHECK_PARSE_NESTED_BOOL(SpacesInParensOptions, InConditionalStatements);
CHECK_PARSE_NESTED_BOOL(SpacesInParensOptions, InEmptyParentheses);
Expand Down Expand Up @@ -626,20 +627,24 @@ TEST(ConfigParseTest, ParsesConfiguration) {
FormatStyle::SIPO_Custom);
Style.SpacesInParens = FormatStyle::SIPO_Never;
Style.SpacesInParensOptions = {};
CHECK_PARSE("SpacesInParentheses: true", SpacesInParensOptions,
FormatStyle::SpacesInParensCustom(true, false, false, true));
CHECK_PARSE(
"SpacesInParentheses: true", SpacesInParensOptions,
FormatStyle::SpacesInParensCustom(false, true, false, false, true));
Style.SpacesInParens = FormatStyle::SIPO_Never;
Style.SpacesInParensOptions = {};
CHECK_PARSE("SpacesInConditionalStatement: true", SpacesInParensOptions,
FormatStyle::SpacesInParensCustom(true, false, false, false));
CHECK_PARSE(
"SpacesInConditionalStatement: true", SpacesInParensOptions,
FormatStyle::SpacesInParensCustom(false, true, false, false, false));
Style.SpacesInParens = FormatStyle::SIPO_Never;
Style.SpacesInParensOptions = {};
CHECK_PARSE("SpacesInCStyleCastParentheses: true", SpacesInParensOptions,
FormatStyle::SpacesInParensCustom(false, true, false, false));
CHECK_PARSE(
"SpacesInCStyleCastParentheses: true", SpacesInParensOptions,
FormatStyle::SpacesInParensCustom(false, false, true, false, false));
Style.SpacesInParens = FormatStyle::SIPO_Never;
Style.SpacesInParensOptions = {};
CHECK_PARSE("SpaceInEmptyParentheses: true", SpacesInParensOptions,
FormatStyle::SpacesInParensCustom(false, false, true, false));
CHECK_PARSE(
"SpaceInEmptyParentheses: true", SpacesInParensOptions,
FormatStyle::SpacesInParensCustom(false, false, false, true, false));
Style.SpacesInParens = FormatStyle::SIPO_Never;
Style.SpacesInParensOptions = {};

Expand Down
109 changes: 109 additions & 0 deletions clang/unittests/Format/FormatTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17129,6 +17129,23 @@ TEST_F(FormatTest, ConfigurableSpacesInParens) {
verifyFormat("SomeType *__attribute__((attr)) *a = NULL;", Spaces);
verifyFormat("void __attribute__((naked)) foo(int bar)", Spaces);
verifyFormat("void f() __attribute__((asdf));", Spaces);
verifyFormat("x = (int32)y;", Spaces);
verifyFormat("y = ((int (*)(int))foo)(x);", Spaces);
verifyFormat("decltype(x) y = 42;", Spaces);
verifyFormat("decltype((x)) y = z;", Spaces);
verifyFormat("decltype((foo())) a = foo();", Spaces);
verifyFormat("decltype((bar(10))) a = bar(11);", Spaces);
verifyFormat("if ((x - y) && (a ^ b))\n"
" f();",
Spaces);
verifyFormat("for (int i = 0; i < 10; i = (i + 1))\n"
" foo(i);",
Spaces);
verifyFormat("switch (x / (y + z)) {\n"
"default:\n"
" break;\n"
"}",
Spaces);

Spaces.SpacesInParens = FormatStyle::SIPO_Custom;
Spaces.SpacesInParensOptions = {};
Expand Down Expand Up @@ -17163,6 +17180,23 @@ TEST_F(FormatTest, ConfigurableSpacesInParens) {
verifyFormat("SomeType *__attribute__( ( attr ) ) *a = NULL;", Spaces);
verifyFormat("void __attribute__( ( naked ) ) foo( int bar )", Spaces);
verifyFormat("void f() __attribute__( ( asdf ) );", Spaces);
verifyFormat("x = (int32)y;", Spaces);
verifyFormat("y = ( (int ( * )( int ))foo )( x );", Spaces);
verifyFormat("decltype( x ) y = 42;", Spaces);
verifyFormat("decltype( ( x ) ) y = z;", Spaces);
verifyFormat("decltype( ( foo() ) ) a = foo();", Spaces);
verifyFormat("decltype( ( bar( 10 ) ) ) a = bar( 11 );", Spaces);
verifyFormat("if ( ( x - y ) && ( a ^ b ) )\n"
" f();",
Spaces);
verifyFormat("for ( int i = 0; i < 10; i = ( i + 1 ) )\n"
" foo( i );",
Spaces);
verifyFormat("switch ( x / ( y + z ) ) {\n"
"default:\n"
" break;\n"
"}",
Spaces);

Spaces.SpacesInParens = FormatStyle::SIPO_Custom;
Spaces.SpacesInParensOptions = {};
Expand All @@ -17175,6 +17209,7 @@ TEST_F(FormatTest, ConfigurableSpacesInParens) {
verifyFormat("#define AA(X) sizeof((( X * )NULL)->a)", Spaces);
verifyFormat("my_int a = ( my_int )sizeof(int);", Spaces);
verifyFormat("#define x (( int )-1)", Spaces);
verifyFormat("y = (( int (*)(int) )foo)(x);", Spaces);

// Run the first set of tests again with:
Spaces.SpacesInParens = FormatStyle::SIPO_Custom;
Expand Down Expand Up @@ -17207,6 +17242,23 @@ TEST_F(FormatTest, ConfigurableSpacesInParens) {
verifyFormat("SomeType *__attribute__((attr)) *a = NULL;", Spaces);
verifyFormat("void __attribute__((naked)) foo(int bar)", Spaces);
verifyFormat("void f( ) __attribute__((asdf));", Spaces);
verifyFormat("x = ( int32 )y;", Spaces);
verifyFormat("y = (( int (*)(int) )foo)(x);", Spaces);
verifyFormat("decltype(x) y = 42;", Spaces);
verifyFormat("decltype((x)) y = z;", Spaces);
verifyFormat("decltype((foo( ))) a = foo( );", Spaces);
verifyFormat("decltype((bar(10))) a = bar(11);", Spaces);
verifyFormat("if ((x - y) && (a ^ b))\n"
" f( );",
Spaces);
verifyFormat("for (int i = 0; i < 10; i = (i + 1))\n"
" foo(i);",
Spaces);
verifyFormat("switch (x / (y + z)) {\n"
"default:\n"
" break;\n"
"}",
Spaces);

// Run the first set of tests again with:
Spaces.SpaceAfterCStyleCast = true;
Expand Down Expand Up @@ -17314,6 +17366,63 @@ TEST_F(FormatTest, ConfigurableSpacesInParens) {
verifyFormat("size_t idx = (a->foo)(a - 1);", Spaces);
verifyFormat("size_t idx = (*foo)(a - 1);", Spaces);
verifyFormat("size_t idx = (*(foo))(a - 1);", Spaces);

// Check ExceptDoubleParentheses spaces
Spaces.IndentWidth = 2;
Spaces.SpacesInParens = FormatStyle::SIPO_Custom;
Spaces.SpacesInParensOptions = {};
Spaces.SpacesInParensOptions.Other = true;
Spaces.SpacesInParensOptions.ExceptDoubleParentheses = true;
verifyFormat("SomeType *__attribute__(( attr )) *a = NULL;", Spaces);
verifyFormat("void __attribute__(( naked )) foo( int bar )", Spaces);
verifyFormat("void f() __attribute__(( asdf ));", Spaces);
verifyFormat("__attribute__(( __aligned__( x ) )) z;", Spaces);
verifyFormat("int x __attribute__(( aligned( 16 ) )) = 0;", Spaces);
verifyFormat("class __declspec( dllimport ) X {};", Spaces);
verifyFormat("class __declspec(( dllimport )) X {};", Spaces);
verifyFormat("int x = ( ( a - 1 ) * 3 );", Spaces);
verifyFormat("int x = ( 3 * ( a - 1 ) );", Spaces);
verifyFormat("decltype( x ) y = 42;", Spaces);
verifyFormat("decltype(( bar( 10 ) )) a = bar( 11 );", Spaces);
verifyFormat("if (( i = j ))\n"
" do_something( i );",
Spaces);

Spaces.SpacesInParens = FormatStyle::SIPO_Custom;
Spaces.SpacesInParensOptions = {};
Spaces.SpacesInParensOptions.InConditionalStatements = true;
Spaces.SpacesInParensOptions.ExceptDoubleParentheses = true;
verifyFormat("while ( (bool)1 )\n"
" continue;",
Spaces);
verifyFormat("while ((i = j))\n"
" continue;",
Spaces);
verifyFormat("do {\n"
" do_something((int)i);\n"
"} while ( something() );",
Spaces);
verifyFormat("do {\n"
" do_something((int)i);\n"
"} while ((i = i + 1));",
Spaces);
verifyFormat("if ( (x - y) && (a ^ b) )\n"
" f();",
Spaces);
verifyFormat("if ((i = j))\n"
" do_something(i);",
Spaces);
verifyFormat("for ( int i = 0; i < 10; i = (i + 1) )\n"
" foo(i);",
Spaces);
verifyFormat("switch ( x / (y + z) ) {\n"
"default:\n"
" break;\n"
"}",
Spaces);
verifyFormat("if constexpr ((a = b))\n"
" c;",
Spaces);
}

TEST_F(FormatTest, ConfigurableSpacesInSquareBrackets) {
Expand Down
Loading