Skip to content

Commit

Permalink
[clang-format] Add SpacesInParensOption for filtering repeated parens (
Browse files Browse the repository at this point in the history
…llvm#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 <owenpiano@gmail.com>
  • Loading branch information
gedare and owenca authored Jul 2, 2024
1 parent 135483b commit 54f040f
Show file tree
Hide file tree
Showing 7 changed files with 182 additions and 23 deletions.
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

0 comments on commit 54f040f

Please sign in to comment.