Author: Gedare Bloom Date: 2024-07-02T00:00:14-07:00 New Revision: 54f040fff301a629f2ed032863408ed119789b0e
URL: https://github.com/llvm/llvm-project/commit/54f040fff301a629f2ed032863408ed119789b0e DIFF: https://github.com/llvm/llvm-project/commit/54f040fff301a629f2ed032863408ed119789b0e.diff LOG: [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 <owenpi...@gmail.com> Added: Modified: clang/docs/ClangFormatStyleOptions.rst clang/docs/ReleaseNotes.rst clang/include/clang/Format/Format.h clang/lib/Format/Format.cpp clang/lib/Format/TokenAnnotator.cpp clang/unittests/Format/ConfigParseTest.cpp clang/unittests/Format/FormatTest.cpp Removed: ################################################################################ diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index 080cba90c4a8b..6c2e6da594847 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -6242,6 +6242,7 @@ the configuration (without a prefix: ``Auto``). # Example of usage: SpacesInParens: Custom SpacesInParensOptions: + ExceptDoubleParentheses: false InConditionalStatements: true InEmptyParentheses: true @@ -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...``). @@ -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. ``()``. @@ -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: diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 90c2469c1c89a..fd8d9ad34fb10 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -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 -------- diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index efc2e450b723f..c454ab2bc0ce2 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -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 @@ -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. ``()``. @@ -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; } @@ -4744,6 +4760,7 @@ struct FormatStyle { /// # Example of usage: /// SpacesInParens: Custom /// SpacesInParensOptions: + /// ExceptDoubleParentheses: false /// InConditionalStatements: true /// InEmptyParentheses: true /// \endcode diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 259ef1dd00e3f..6a8883b77a730 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -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); @@ -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; diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 03082cd2742c8..0fd0214d16615 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -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)) diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp index 2466677a3740d..cc044153b7c9b 100644 --- a/clang/unittests/Format/ConfigParseTest.cpp +++ b/clang/unittests/Format/ConfigParseTest.cpp @@ -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); @@ -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 = {}; diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 5276e79d75981..283843ad7ab47 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -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 = {}; @@ -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 = {}; @@ -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; @@ -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; @@ -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) { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits