Skip to content

Commit 54f040f

Browse files
gedareowenca
andauthored
[clang-format] Add SpacesInParensOption for filtering repeated parens (#77522)
The __attribute((specifier-list)) currently is formatted based on the SpacesInParensOptions.Other (previously, SpacesInParentheses). This change allows finer control over addition of spaces between the consecutive parens, and between the inner parens and the list of attribute specifiers. Differential Revision: https://reviews.llvm.org/D155529 This is migrated from Phabricator, see more discussion there. --------- Co-authored-by: Owen Pan <[email protected]>
1 parent 135483b commit 54f040f

File tree

7 files changed

+182
-23
lines changed

7 files changed

+182
-23
lines changed

clang/docs/ClangFormatStyleOptions.rst

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6242,6 +6242,7 @@ the configuration (without a prefix: ``Auto``).
62426242
# Example of usage:
62436243
SpacesInParens: Custom
62446244
SpacesInParensOptions:
6245+
ExceptDoubleParentheses: false
62456246
InConditionalStatements: true
62466247
InEmptyParentheses: true
62476248
@@ -6254,9 +6255,22 @@ the configuration (without a prefix: ``Auto``).
62546255
# Should be declared this way:
62556256
SpacesInParens: Custom
62566257
SpacesInParensOptions:
6258+
ExceptDoubleParentheses: false
62576259
InConditionalStatements: true
62586260
Other: true
62596261

6262+
* ``bool ExceptDoubleParentheses`` Override any of the following options to prevent addition of space
6263+
when both opening and closing parentheses use multiple parentheses.
6264+
6265+
.. code-block:: c++
6266+
6267+
true:
6268+
__attribute__(( noreturn ))
6269+
__decltype__(( x ))
6270+
if (( a = b ))
6271+
false:
6272+
Uses the applicable option.
6273+
62606274
* ``bool InConditionalStatements`` Put a space in parentheses only inside conditional statements
62616275
(``for/if/while/switch...``).
62626276

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

62716285
.. code-block:: c++
62726286

6273-
true: false:
6274-
x = ( int32 )y vs. x = (int32)y
6287+
true: false:
6288+
x = ( int32 )y vs. x = (int32)y
6289+
y = (( int (*)(int) )foo)(x); y = ((int (*)(int))foo)(x);
62756290

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

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

62906305
.. code-block:: c++
62916306

6292-
true: false:
6293-
t f( Deleted & ) & = delete; vs. t f(Deleted &) & = delete;
6307+
true: false:
6308+
t f( Deleted & ) & = delete; vs. t f(Deleted &) & = delete;
62946309

62956310

62966311
.. _SpacesInParentheses:

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1130,6 +1130,9 @@ clang-format
11301130
- Adds ``LeftWithLastLine`` suboption to ``AlignEscapedNewlines``.
11311131
- Adds ``KeepEmptyLines`` option to deprecate ``KeepEmptyLinesAtEOF``
11321132
and ``KeepEmptyLinesAtTheStartOfBlocks``.
1133+
- Add ``ExceptDoubleParentheses`` sub-option for ``SpacesInParensOptions``
1134+
to override addition of spaces between multiple, non-redundant parentheses
1135+
similar to the rules used for ``RemoveParentheses``.
11331136

11341137
libclang
11351138
--------

clang/include/clang/Format/Format.h

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4679,10 +4679,22 @@ struct FormatStyle {
46794679
/// # Should be declared this way:
46804680
/// SpacesInParens: Custom
46814681
/// SpacesInParensOptions:
4682+
/// ExceptDoubleParentheses: false
46824683
/// InConditionalStatements: true
46834684
/// Other: true
46844685
/// \endcode
46854686
struct SpacesInParensCustom {
4687+
/// Override any of the following options to prevent addition of space
4688+
/// when both opening and closing parentheses use multiple parentheses.
4689+
/// \code
4690+
/// true:
4691+
/// __attribute__(( noreturn ))
4692+
/// __decltype__(( x ))
4693+
/// if (( a = b ))
4694+
/// \endcode
4695+
/// false:
4696+
/// Uses the applicable option.
4697+
bool ExceptDoubleParentheses;
46864698
/// Put a space in parentheses only inside conditional statements
46874699
/// (``for/if/while/switch...``).
46884700
/// \code
@@ -4693,8 +4705,9 @@ struct FormatStyle {
46934705
bool InConditionalStatements;
46944706
/// Put a space in C style casts.
46954707
/// \code
4696-
/// true: false:
4697-
/// x = ( int32 )y vs. x = (int32)y
4708+
/// true: false:
4709+
/// x = ( int32 )y vs. x = (int32)y
4710+
/// y = (( int (*)(int) )foo)(x); y = ((int (*)(int))foo)(x);
46984711
/// \endcode
46994712
bool InCStyleCasts;
47004713
/// Insert a space in empty parentheses, i.e. ``()``.
@@ -4710,23 +4723,26 @@ struct FormatStyle {
47104723
bool InEmptyParentheses;
47114724
/// Put a space in parentheses not covered by preceding options.
47124725
/// \code
4713-
/// true: false:
4714-
/// t f( Deleted & ) & = delete; vs. t f(Deleted &) & = delete;
4726+
/// true: false:
4727+
/// t f( Deleted & ) & = delete; vs. t f(Deleted &) & = delete;
47154728
/// \endcode
47164729
bool Other;
47174730

47184731
SpacesInParensCustom()
4719-
: InConditionalStatements(false), InCStyleCasts(false),
4720-
InEmptyParentheses(false), Other(false) {}
4732+
: ExceptDoubleParentheses(false), InConditionalStatements(false),
4733+
InCStyleCasts(false), InEmptyParentheses(false), Other(false) {}
47214734

4722-
SpacesInParensCustom(bool InConditionalStatements, bool InCStyleCasts,
4735+
SpacesInParensCustom(bool ExceptDoubleParentheses,
4736+
bool InConditionalStatements, bool InCStyleCasts,
47234737
bool InEmptyParentheses, bool Other)
4724-
: InConditionalStatements(InConditionalStatements),
4738+
: ExceptDoubleParentheses(ExceptDoubleParentheses),
4739+
InConditionalStatements(InConditionalStatements),
47254740
InCStyleCasts(InCStyleCasts), InEmptyParentheses(InEmptyParentheses),
47264741
Other(Other) {}
47274742

47284743
bool operator==(const SpacesInParensCustom &R) const {
4729-
return InConditionalStatements == R.InConditionalStatements &&
4744+
return ExceptDoubleParentheses == R.ExceptDoubleParentheses &&
4745+
InConditionalStatements == R.InConditionalStatements &&
47304746
InCStyleCasts == R.InCStyleCasts &&
47314747
InEmptyParentheses == R.InEmptyParentheses && Other == R.Other;
47324748
}
@@ -4744,6 +4760,7 @@ struct FormatStyle {
47444760
/// # Example of usage:
47454761
/// SpacesInParens: Custom
47464762
/// SpacesInParensOptions:
4763+
/// ExceptDoubleParentheses: false
47474764
/// InConditionalStatements: true
47484765
/// InEmptyParentheses: true
47494766
/// \endcode

clang/lib/Format/Format.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,7 @@ template <> struct MappingTraits<FormatStyle::SpacesInLineComment> {
729729

730730
template <> struct MappingTraits<FormatStyle::SpacesInParensCustom> {
731731
static void mapping(IO &IO, FormatStyle::SpacesInParensCustom &Spaces) {
732+
IO.mapOptional("ExceptDoubleParentheses", Spaces.ExceptDoubleParentheses);
732733
IO.mapOptional("InCStyleCasts", Spaces.InCStyleCasts);
733734
IO.mapOptional("InConditionalStatements", Spaces.InConditionalStatements);
734735
IO.mapOptional("InEmptyParentheses", Spaces.InEmptyParentheses);
@@ -1184,8 +1185,8 @@ template <> struct MappingTraits<FormatStyle> {
11841185
(SpacesInParentheses || SpaceInEmptyParentheses ||
11851186
SpacesInConditionalStatement || SpacesInCStyleCastParentheses)) {
11861187
if (SpacesInParentheses) {
1187-
// set all options except InCStyleCasts and InEmptyParentheses
1188-
// to true for backward compatibility.
1188+
// For backward compatibility.
1189+
Style.SpacesInParensOptions.ExceptDoubleParentheses = false;
11891190
Style.SpacesInParensOptions.InConditionalStatements = true;
11901191
Style.SpacesInParensOptions.InCStyleCasts =
11911192
SpacesInCStyleCastParentheses;

clang/lib/Format/TokenAnnotator.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4361,6 +4361,15 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
43614361
Right.is(tok::r_brace) && Right.isNot(BK_Block))) {
43624362
return Style.SpacesInParensOptions.InEmptyParentheses;
43634363
}
4364+
if (Style.SpacesInParens == FormatStyle::SIPO_Custom &&
4365+
Style.SpacesInParensOptions.ExceptDoubleParentheses &&
4366+
Left.is(tok::r_paren) && Right.is(tok::r_paren)) {
4367+
auto *InnerLParen = Left.MatchingParen;
4368+
if (InnerLParen && InnerLParen->Previous == Right.MatchingParen) {
4369+
InnerLParen->SpacesRequiredBefore = 0;
4370+
return false;
4371+
}
4372+
}
43644373
if (Style.SpacesInParensOptions.InConditionalStatements) {
43654374
const FormatToken *LeftParen = nullptr;
43664375
if (Left.is(tok::l_paren))

clang/unittests/Format/ConfigParseTest.cpp

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ TEST(ConfigParseTest, ParsesConfigurationBools) {
240240
CHECK_PARSE_NESTED_BOOL(SpaceBeforeParensOptions, AfterOverloadedOperator);
241241
CHECK_PARSE_NESTED_BOOL(SpaceBeforeParensOptions, AfterPlacementOperator);
242242
CHECK_PARSE_NESTED_BOOL(SpaceBeforeParensOptions, BeforeNonEmptyParentheses);
243+
CHECK_PARSE_NESTED_BOOL(SpacesInParensOptions, ExceptDoubleParentheses);
243244
CHECK_PARSE_NESTED_BOOL(SpacesInParensOptions, InCStyleCasts);
244245
CHECK_PARSE_NESTED_BOOL(SpacesInParensOptions, InConditionalStatements);
245246
CHECK_PARSE_NESTED_BOOL(SpacesInParensOptions, InEmptyParentheses);
@@ -626,20 +627,24 @@ TEST(ConfigParseTest, ParsesConfiguration) {
626627
FormatStyle::SIPO_Custom);
627628
Style.SpacesInParens = FormatStyle::SIPO_Never;
628629
Style.SpacesInParensOptions = {};
629-
CHECK_PARSE("SpacesInParentheses: true", SpacesInParensOptions,
630-
FormatStyle::SpacesInParensCustom(true, false, false, true));
630+
CHECK_PARSE(
631+
"SpacesInParentheses: true", SpacesInParensOptions,
632+
FormatStyle::SpacesInParensCustom(false, true, false, false, true));
631633
Style.SpacesInParens = FormatStyle::SIPO_Never;
632634
Style.SpacesInParensOptions = {};
633-
CHECK_PARSE("SpacesInConditionalStatement: true", SpacesInParensOptions,
634-
FormatStyle::SpacesInParensCustom(true, false, false, false));
635+
CHECK_PARSE(
636+
"SpacesInConditionalStatement: true", SpacesInParensOptions,
637+
FormatStyle::SpacesInParensCustom(false, true, false, false, false));
635638
Style.SpacesInParens = FormatStyle::SIPO_Never;
636639
Style.SpacesInParensOptions = {};
637-
CHECK_PARSE("SpacesInCStyleCastParentheses: true", SpacesInParensOptions,
638-
FormatStyle::SpacesInParensCustom(false, true, false, false));
640+
CHECK_PARSE(
641+
"SpacesInCStyleCastParentheses: true", SpacesInParensOptions,
642+
FormatStyle::SpacesInParensCustom(false, false, true, false, false));
639643
Style.SpacesInParens = FormatStyle::SIPO_Never;
640644
Style.SpacesInParensOptions = {};
641-
CHECK_PARSE("SpaceInEmptyParentheses: true", SpacesInParensOptions,
642-
FormatStyle::SpacesInParensCustom(false, false, true, false));
645+
CHECK_PARSE(
646+
"SpaceInEmptyParentheses: true", SpacesInParensOptions,
647+
FormatStyle::SpacesInParensCustom(false, false, false, true, false));
643648
Style.SpacesInParens = FormatStyle::SIPO_Never;
644649
Style.SpacesInParensOptions = {};
645650

clang/unittests/Format/FormatTest.cpp

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17129,6 +17129,23 @@ TEST_F(FormatTest, ConfigurableSpacesInParens) {
1712917129
verifyFormat("SomeType *__attribute__((attr)) *a = NULL;", Spaces);
1713017130
verifyFormat("void __attribute__((naked)) foo(int bar)", Spaces);
1713117131
verifyFormat("void f() __attribute__((asdf));", Spaces);
17132+
verifyFormat("x = (int32)y;", Spaces);
17133+
verifyFormat("y = ((int (*)(int))foo)(x);", Spaces);
17134+
verifyFormat("decltype(x) y = 42;", Spaces);
17135+
verifyFormat("decltype((x)) y = z;", Spaces);
17136+
verifyFormat("decltype((foo())) a = foo();", Spaces);
17137+
verifyFormat("decltype((bar(10))) a = bar(11);", Spaces);
17138+
verifyFormat("if ((x - y) && (a ^ b))\n"
17139+
" f();",
17140+
Spaces);
17141+
verifyFormat("for (int i = 0; i < 10; i = (i + 1))\n"
17142+
" foo(i);",
17143+
Spaces);
17144+
verifyFormat("switch (x / (y + z)) {\n"
17145+
"default:\n"
17146+
" break;\n"
17147+
"}",
17148+
Spaces);
1713217149

1713317150
Spaces.SpacesInParens = FormatStyle::SIPO_Custom;
1713417151
Spaces.SpacesInParensOptions = {};
@@ -17163,6 +17180,23 @@ TEST_F(FormatTest, ConfigurableSpacesInParens) {
1716317180
verifyFormat("SomeType *__attribute__( ( attr ) ) *a = NULL;", Spaces);
1716417181
verifyFormat("void __attribute__( ( naked ) ) foo( int bar )", Spaces);
1716517182
verifyFormat("void f() __attribute__( ( asdf ) );", Spaces);
17183+
verifyFormat("x = (int32)y;", Spaces);
17184+
verifyFormat("y = ( (int ( * )( int ))foo )( x );", Spaces);
17185+
verifyFormat("decltype( x ) y = 42;", Spaces);
17186+
verifyFormat("decltype( ( x ) ) y = z;", Spaces);
17187+
verifyFormat("decltype( ( foo() ) ) a = foo();", Spaces);
17188+
verifyFormat("decltype( ( bar( 10 ) ) ) a = bar( 11 );", Spaces);
17189+
verifyFormat("if ( ( x - y ) && ( a ^ b ) )\n"
17190+
" f();",
17191+
Spaces);
17192+
verifyFormat("for ( int i = 0; i < 10; i = ( i + 1 ) )\n"
17193+
" foo( i );",
17194+
Spaces);
17195+
verifyFormat("switch ( x / ( y + z ) ) {\n"
17196+
"default:\n"
17197+
" break;\n"
17198+
"}",
17199+
Spaces);
1716617200

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

1717917214
// Run the first set of tests again with:
1718017215
Spaces.SpacesInParens = FormatStyle::SIPO_Custom;
@@ -17207,6 +17242,23 @@ TEST_F(FormatTest, ConfigurableSpacesInParens) {
1720717242
verifyFormat("SomeType *__attribute__((attr)) *a = NULL;", Spaces);
1720817243
verifyFormat("void __attribute__((naked)) foo(int bar)", Spaces);
1720917244
verifyFormat("void f( ) __attribute__((asdf));", Spaces);
17245+
verifyFormat("x = ( int32 )y;", Spaces);
17246+
verifyFormat("y = (( int (*)(int) )foo)(x);", Spaces);
17247+
verifyFormat("decltype(x) y = 42;", Spaces);
17248+
verifyFormat("decltype((x)) y = z;", Spaces);
17249+
verifyFormat("decltype((foo( ))) a = foo( );", Spaces);
17250+
verifyFormat("decltype((bar(10))) a = bar(11);", Spaces);
17251+
verifyFormat("if ((x - y) && (a ^ b))\n"
17252+
" f( );",
17253+
Spaces);
17254+
verifyFormat("for (int i = 0; i < 10; i = (i + 1))\n"
17255+
" foo(i);",
17256+
Spaces);
17257+
verifyFormat("switch (x / (y + z)) {\n"
17258+
"default:\n"
17259+
" break;\n"
17260+
"}",
17261+
Spaces);
1721017262

1721117263
// Run the first set of tests again with:
1721217264
Spaces.SpaceAfterCStyleCast = true;
@@ -17314,6 +17366,63 @@ TEST_F(FormatTest, ConfigurableSpacesInParens) {
1731417366
verifyFormat("size_t idx = (a->foo)(a - 1);", Spaces);
1731517367
verifyFormat("size_t idx = (*foo)(a - 1);", Spaces);
1731617368
verifyFormat("size_t idx = (*(foo))(a - 1);", Spaces);
17369+
17370+
// Check ExceptDoubleParentheses spaces
17371+
Spaces.IndentWidth = 2;
17372+
Spaces.SpacesInParens = FormatStyle::SIPO_Custom;
17373+
Spaces.SpacesInParensOptions = {};
17374+
Spaces.SpacesInParensOptions.Other = true;
17375+
Spaces.SpacesInParensOptions.ExceptDoubleParentheses = true;
17376+
verifyFormat("SomeType *__attribute__(( attr )) *a = NULL;", Spaces);
17377+
verifyFormat("void __attribute__(( naked )) foo( int bar )", Spaces);
17378+
verifyFormat("void f() __attribute__(( asdf ));", Spaces);
17379+
verifyFormat("__attribute__(( __aligned__( x ) )) z;", Spaces);
17380+
verifyFormat("int x __attribute__(( aligned( 16 ) )) = 0;", Spaces);
17381+
verifyFormat("class __declspec( dllimport ) X {};", Spaces);
17382+
verifyFormat("class __declspec(( dllimport )) X {};", Spaces);
17383+
verifyFormat("int x = ( ( a - 1 ) * 3 );", Spaces);
17384+
verifyFormat("int x = ( 3 * ( a - 1 ) );", Spaces);
17385+
verifyFormat("decltype( x ) y = 42;", Spaces);
17386+
verifyFormat("decltype(( bar( 10 ) )) a = bar( 11 );", Spaces);
17387+
verifyFormat("if (( i = j ))\n"
17388+
" do_something( i );",
17389+
Spaces);
17390+
17391+
Spaces.SpacesInParens = FormatStyle::SIPO_Custom;
17392+
Spaces.SpacesInParensOptions = {};
17393+
Spaces.SpacesInParensOptions.InConditionalStatements = true;
17394+
Spaces.SpacesInParensOptions.ExceptDoubleParentheses = true;
17395+
verifyFormat("while ( (bool)1 )\n"
17396+
" continue;",
17397+
Spaces);
17398+
verifyFormat("while ((i = j))\n"
17399+
" continue;",
17400+
Spaces);
17401+
verifyFormat("do {\n"
17402+
" do_something((int)i);\n"
17403+
"} while ( something() );",
17404+
Spaces);
17405+
verifyFormat("do {\n"
17406+
" do_something((int)i);\n"
17407+
"} while ((i = i + 1));",
17408+
Spaces);
17409+
verifyFormat("if ( (x - y) && (a ^ b) )\n"
17410+
" f();",
17411+
Spaces);
17412+
verifyFormat("if ((i = j))\n"
17413+
" do_something(i);",
17414+
Spaces);
17415+
verifyFormat("for ( int i = 0; i < 10; i = (i + 1) )\n"
17416+
" foo(i);",
17417+
Spaces);
17418+
verifyFormat("switch ( x / (y + z) ) {\n"
17419+
"default:\n"
17420+
" break;\n"
17421+
"}",
17422+
Spaces);
17423+
verifyFormat("if constexpr ((a = b))\n"
17424+
" c;",
17425+
Spaces);
1731717426
}
1731817427

1731917428
TEST_F(FormatTest, ConfigurableSpacesInSquareBrackets) {

0 commit comments

Comments
 (0)