diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -5116,16 +5116,8 @@ **SpaceInEmptyParentheses** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`¶ ` If ``true``, spaces may be inserted into ``()``. - - .. code-block:: c++ - - true: false: - void f( ) { vs. void f() { - int x[] = {foo( ), bar( )}; int x[] = {foo(), bar()}; - if (true) { if (true) { - f( ); f(); - } } - } } + This option is **deprecated**. See ``EmptyParentheses`` of + ``SpacesInParens``. .. _SpacesBeforeTrailingComments: @@ -5182,23 +5174,16 @@ **SpacesInCStyleCastParentheses** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`¶ ` If ``true``, spaces may be inserted into C style casts. - - .. code-block:: c++ - - true: false: - x = ( int32 )y vs. x = (int32)y + This option is **deprecated**. See ``CStyleCasts`` of + ``SpacesInParens``. .. _SpacesInConditionalStatement: **SpacesInConditionalStatement** (``Boolean``) :versionbadge:`clang-format 10` :ref:`¶ ` If ``true``, spaces will be inserted around if/for/switch/while conditions. - - .. code-block:: c++ - - true: false: - if ( a ) { ... } vs. if (a) { ... } - while ( i < 5 ) { ... } while (i < 5) { ... } + This option is **deprecated**. See ``ConditionalStatements`` of + ``SpacesInParens``. .. _SpacesInContainerLiterals: @@ -5259,15 +5244,133 @@ * ``unsigned Maximum`` The maximum number of spaces at the start of the comment. -.. _SpacesInParentheses: +.. _SpacesInParens: -**SpacesInParentheses** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`¶ ` - If ``true``, spaces will be inserted after ``(`` and before ``)``. +**SpacesInParens** (``SpacesInParensStyle``) :versionbadge:`clang-format 17` :ref:`¶ ` + Defines in which cases spaces will be inserted after ``(`` and before + ``)``. + + Possible values: + + * ``SIPO_Never`` (in configuration: ``Never``) + Never put a space in parentheses. + + .. code-block:: c++ + + void f() { + if(true) { + f(); + } + } + + * ``SIPO_ConditionalStatements`` (in configuration: ``ConditionalStatements``) + Put a space in parentheses only inside conditional statements + (``for/if/while/switch...``). + + .. code-block:: c++ + + true: false: + if ( a ) { ... } vs. if (a) { ... } + while ( i < 5 ) { ... } while (i < 5) { ... } + + * ``SIPO_CStyleCasts`` (in configuration: ``CStyleCasts``) + Put a space in C style casts. + + .. code-block:: c++ + + true: false: + x = ( int32 )y vs. x = (int32)y + + * ``SIPO_EmptyParentheses`` (in configuration: ``EmptyParentheses``) + Put a space in parentheses only if the parentheses are empty i.e. '()' + + .. code-block:: c++ + + true: false: + void f( ) { vs. void f() { + int x[] = {foo( ), bar( )}; int x[] = {foo(), bar()}; + if (true) { if (true) { + f( ); f(); + } } + } } + + * ``SIPO_Always`` (in configuration: ``Always``) + Always put a space in parentheses. + + .. code-block:: c++ + + true: false: + t f( Deleted & ) & = delete; vs. t f(Deleted &) & = delete; + + * ``SIPO_Custom`` (in configuration: ``Custom``) + Configure each individual space in parentheses in + `SpacesInParensOptions`. + + + +.. _SpacesInParensOptions: + +**SpacesInParensOptions** (``SpacesInParensCustom``) :versionbadge:`clang-format 17` :ref:`¶ ` + Control of individual spaces in parentheses. + + If ``SpacesInParens`` is set to ``Custom``, use this to specify + how each individual space in parentheses case should be handled. + Otherwise, this is ignored. + + .. code-block:: yaml + + # Example of usage: + SpacesInParens: Custom + SpacesInParensOptions: + InConditionalStatements: true + InEmptyParentheses: true + + Nested configuration flags: + + Precise control over the spacing in parentheses. .. code-block:: c++ - true: false: - t f( Deleted & ) & = delete; vs. t f(Deleted &) & = delete; + # Should be declared this way: + SpacesInParens: Custom + SpacesInParensOptions: + InConditionalStatements: true + InEmptyParentheses: true + + * ``bool InConditionalStatements`` Put a space in parentheses only inside conditional statements + (``for/if/while/switch...``). + + .. code-block:: c++ + + true: false: + if ( a ) { ... } vs. if (a) { ... } + while ( i < 5 ) { ... } while (i < 5) { ... } + + * ``bool InCStyleCasts`` Put a space in C style casts. + + .. code-block:: c++ + + true: false: + x = ( int32 )y vs. x = (int32)y + + * ``bool InEmptyParentheses`` Put a space in parentheses only if the parentheses are empty i.e. '()' + + .. code-block:: c++ + + true: false: + void f( ) { vs. void f() { + int x[] = {foo( ), bar( )}; int x[] = {foo(), bar()}; + if (true) { if (true) { + f( ); f(); + } } + } } + + +.. _SpacesInParentheses: + +**SpacesInParentheses** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`¶ ` + If ``true'', spaces will be inserted after ``(`` and before ``)``. + This option is **deprecated**. See ``SpacesInParens``. .. _SpacesInSquareBrackets: diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -4053,15 +4053,8 @@ bool SpaceInEmptyBlock; /// If ``true``, spaces may be inserted into ``()``. - /// \code - /// true: false: - /// void f( ) { vs. void f() { - /// int x[] = {foo( ), bar( )}; int x[] = {foo(), bar()}; - /// if (true) { if (true) { - /// f( ); f(); - /// } } - /// } } - /// \endcode + /// This option is **deprecated**. See ``EmptyParentheses`` of + /// ``SpacesInParens``. /// \version 3.7 bool SpaceInEmptyParentheses; @@ -4110,11 +4103,8 @@ /// If ``true``, spaces will be inserted around if/for/switch/while /// conditions. - /// \code - /// true: false: - /// if ( a ) { ... } vs. if (a) { ... } - /// while ( i < 5 ) { ... } while (i < 5) { ... } - /// \endcode + /// This option is **deprecated**. See ``ConditionalStatements`` of + /// ``SpacesInParens``. /// \version 10 bool SpacesInConditionalStatement; @@ -4130,10 +4120,8 @@ bool SpacesInContainerLiterals; /// If ``true``, spaces may be inserted into C style casts. - /// \code - /// true: false: - /// x = ( int32 )y vs. x = (int32)y - /// \endcode + /// This option is **deprecated**. See ``CStyleCasts`` of + /// ``SpacesInParens``. /// \version 3.7 bool SpacesInCStyleCastParentheses; @@ -4179,14 +4167,124 @@ /// \version 13 SpacesInLineComment SpacesInLineCommentPrefix; - /// If ``true``, spaces will be inserted after ``(`` and before ``)``. - /// \code - /// true: false: - /// t f( Deleted & ) & = delete; vs. t f(Deleted &) & = delete; - /// \endcode + /// Different ways to put a space before opening and closing parentheses. + enum SpacesInParensStyle : int8_t { + /// Never put a space in parentheses. + /// \code + /// void f() { + /// if(true) { + /// f(); + /// } + /// } + /// \endcode + SIPO_Never, + /// Put a space in parentheses only inside conditional statements + /// (``for/if/while/switch...``). + /// \code + /// true: false: + /// if ( a ) { ... } vs. if (a) { ... } + /// while ( i < 5 ) { ... } while (i < 5) { ... } + /// \endcode + SIPO_ConditionalStatements, + /// Put a space in C style casts. + /// \code + /// true: false: + /// x = ( int32 )y vs. x = (int32)y + /// \endcode + SIPO_CStyleCasts, + /// Put a space in parentheses only if the parentheses are empty i.e. '()' + /// \code + /// true: false: + /// void f( ) { vs. void f() { + /// int x[] = {foo( ), bar( )}; int x[] = {foo(), bar()}; + /// if (true) { if (true) { + /// f( ); f(); + /// } } + /// } } + /// \endcode + SIPO_EmptyParentheses, + /// Always put a space in parentheses. + /// \code + /// true: false: + /// t f( Deleted & ) & = delete; vs. t f(Deleted &) & = delete; + /// \endcode + SIPO_Always, + /// Configure each individual space in parentheses in + /// `SpacesInParensOptions`. + SIPO_Custom, + }; + + /// If ``true'', spaces will be inserted after ``(`` and before ``)``. + /// This option is **deprecated**. See ``SpacesInParens``. /// \version 3.7 bool SpacesInParentheses; + /// Defines in which cases spaces will be inserted after ``(`` and before + /// ``)``. + /// \version 17 + SpacesInParensStyle SpacesInParens; + + /// Precise control over the spacing in parentheses. + /// \code + /// # Should be declared this way: + /// SpacesInParens: Custom + /// SpacesInParensOptions: + /// InConditionalStatements: true + /// InEmptyParentheses: true + /// \endcode + struct SpacesInParensCustom { + /// Put a space in parentheses only inside conditional statements + /// (``for/if/while/switch...``). + /// \code + /// true: false: + /// if ( a ) { ... } vs. if (a) { ... } + /// while ( i < 5 ) { ... } while (i < 5) { ... } + /// \endcode + bool InConditionalStatements; + /// Put a space in C style casts. + /// \code + /// true: false: + /// x = ( int32 )y vs. x = (int32)y + /// \endcode + bool InCStyleCasts; + /// Put a space in parentheses only if the parentheses are empty i.e. '()' + /// \code + /// true: false: + /// void f( ) { vs. void f() { + /// int x[] = {foo( ), bar( )}; int x[] = {foo(), bar()}; + /// if (true) { if (true) { + /// f( ); f(); + /// } } + /// } } + /// \endcode + bool InEmptyParentheses; + + SpacesInParensCustom() + : InConditionalStatements(false), InCStyleCasts(false), + InEmptyParentheses(false) {} + + bool operator==(const SpacesInParensCustom &Other) const { + return InConditionalStatements == Other.InConditionalStatements && + InCStyleCasts == Other.InCStyleCasts && + InEmptyParentheses == Other.InEmptyParentheses; + } + }; + + /// Control of individual spaces in parentheses. + /// + /// If ``SpacesInParens`` is set to ``Custom``, use this to specify + /// how each individual space in parentheses case should be handled. + /// Otherwise, this is ignored. + /// \code{.yaml} + /// # Example of usage: + /// SpacesInParens: Custom + /// SpacesInParensOptions: + /// InConditionalStatements: true + /// InEmptyParentheses: true + /// \endcode + /// \version 17 + SpacesInParensCustom SpacesInParensOptions; + /// If ``true``, spaces will be inserted after ``[`` and before ``]``. /// Lambdas without arguments or unspecified size array declarations will not /// be affected. @@ -4487,6 +4585,8 @@ R.SpacesInLineCommentPrefix.Minimum && SpacesInLineCommentPrefix.Maximum == R.SpacesInLineCommentPrefix.Maximum && + SpacesInParens == R.SpacesInParens && + SpacesInParensOptions == R.SpacesInParensOptions && SpacesInParentheses == R.SpacesInParentheses && SpacesInSquareBrackets == R.SpacesInSquareBrackets && Standard == R.Standard && diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -711,6 +711,33 @@ } }; +template <> struct MappingTraits { + static void mapping(IO &IO, FormatStyle::SpacesInParensCustom &Spaces) { + IO.mapOptional("InCStyleCasts", Spaces.InCStyleCasts); + IO.mapOptional("InConditionalStatements", Spaces.InConditionalStatements); + IO.mapOptional("InEmptyParentheses", Spaces.InEmptyParentheses); + } +}; + +template <> +struct ScalarEnumerationTraits { + static void enumeration(IO &IO, + FormatStyle::SpacesInParensStyle &Value) { + IO.enumCase(Value, "Never", FormatStyle::SIPO_Never); + IO.enumCase(Value, "CStyleCasts", + FormatStyle::SIPO_CStyleCasts); + IO.enumCase(Value, "ConditionalStatements", + FormatStyle::SIPO_ConditionalStatements); + IO.enumCase(Value, "EmptyParentheses", FormatStyle::SIPO_EmptyParentheses); + IO.enumCase(Value, "Always", FormatStyle::SIPO_Always); + IO.enumCase(Value, "Custom", FormatStyle::SIPO_Custom); + + // For backward compatibility. + IO.enumCase(Value, "false", FormatStyle::SIPO_Never); + IO.enumCase(Value, "true", FormatStyle::SIPO_Always); + } +}; + template <> struct ScalarEnumerationTraits { static void enumeration(IO &IO, FormatStyle::TrailingCommaStyle &Value) { IO.enumCase(Value, "None", FormatStyle::TCS_None); @@ -1044,6 +1071,9 @@ Style.SpacesInCStyleCastParentheses); IO.mapOptional("SpacesInLineCommentPrefix", Style.SpacesInLineCommentPrefix); + IO.mapOptional("SpacesInParens", Style.SpacesInParens); + IO.mapOptional("SpacesInParensOptions", + Style.SpacesInParensOptions); IO.mapOptional("SpacesInParentheses", Style.SpacesInParentheses); IO.mapOptional("SpacesInSquareBrackets", Style.SpacesInSquareBrackets); IO.mapOptional("Standard", Style.Standard); @@ -1314,6 +1344,39 @@ } } +static void expandPresetsSpacesInParens(FormatStyle &Expanded) { + if (Expanded.SpacesInParens == FormatStyle::SIPO_Custom) + return; + // Reset all flags + Expanded.SpacesInParensOptions = {}; + + switch (Expanded.SpacesInParens) { + case FormatStyle::SIPO_Never: + break; + case FormatStyle::SIPO_ConditionalStatements: + Expanded.SpacesInParensOptions.InConditionalStatements = true; + break; + case FormatStyle::SIPO_CStyleCasts: + Expanded.SpacesInParensOptions.InCStyleCasts = true; + break; + case FormatStyle::SIPO_EmptyParentheses: + Expanded.SpacesInParensOptions.InEmptyParentheses = true; + break; + case FormatStyle::SIPO_Always: + break; + default: + break; + } + + // For backward compatibility. + if (Expanded.SpaceInEmptyParentheses) + Expanded.SpacesInParensOptions.InEmptyParentheses = true; + if (Expanded.SpacesInCStyleCastParentheses) + Expanded.SpacesInParensOptions.InCStyleCasts = true; + if (Expanded.SpacesInConditionalStatement) + Expanded.SpacesInParensOptions.InConditionalStatements = true; +} + FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { FormatStyle LLVMStyle; LLVMStyle.InheritsParentConfig = false; @@ -1474,6 +1537,7 @@ LLVMStyle.SpacesInCStyleCastParentheses = false; LLVMStyle.SpacesInLineCommentPrefix = {/*Minimum=*/1, /*Maximum=*/-1u}; LLVMStyle.SpacesInParentheses = false; + LLVMStyle.SpacesInParens = FormatStyle::SIPO_Never; LLVMStyle.SpacesInSquareBrackets = false; LLVMStyle.SpacesInConditionalStatement = false; LLVMStyle.Standard = FormatStyle::LS_Latest; @@ -1957,6 +2021,7 @@ FormatStyle NonConstStyle = Style; expandPresetsBraceWrapping(NonConstStyle); expandPresetsSpaceBeforeParens(NonConstStyle); + expandPresetsSpacesInParens(NonConstStyle); Output << NonConstStyle; return Stream.str(); @@ -3482,6 +3547,7 @@ FormatStyle Expanded = Style; expandPresetsBraceWrapping(Expanded); expandPresetsSpaceBeforeParens(Expanded); + expandPresetsSpacesInParens(Expanded); Expanded.InsertBraces = false; Expanded.RemoveBracesLLVM = false; Expanded.RemoveParentheses = FormatStyle::RPS_Leave; diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -3355,7 +3355,10 @@ if (Current->is(TT_LineComment)) { if (Prev->is(BK_BracedInit) && Prev->opensScope()) { Current->SpacesRequiredBefore = - (Style.Cpp11BracedListStyle && !Style.SpacesInParentheses) ? 0 : 1; + (Style.Cpp11BracedListStyle && + !(Style.SpacesInParens || Style.SpacesInParentheses)) + ? 0 + : 1; } else if (Prev->is(TT_VerilogMultiLineListLParen)) { Current->SpacesRequiredBefore = 0; } else { @@ -3769,9 +3772,9 @@ if ((Left.is(tok::l_paren) && Right.is(tok::r_paren)) || (Left.is(tok::l_brace) && Left.isNot(BK_Block) && Right.is(tok::r_brace) && Right.isNot(BK_Block))) { - return Style.SpaceInEmptyParentheses; + return Style.SpacesInParensOptions.InEmptyParentheses; } - if (Style.SpacesInConditionalStatement) { + if (Style.SpacesInParensOptions.InConditionalStatements) { const FormatToken *LeftParen = nullptr; if (Left.is(tok::l_paren)) LeftParen = &Left; @@ -3810,8 +3813,9 @@ if (Left.is(tok::l_paren) || Right.is(tok::r_paren)) { return (Right.is(TT_CastRParen) || (Left.MatchingParen && Left.MatchingParen->is(TT_CastRParen))) - ? Style.SpacesInCStyleCastParentheses - : Style.SpacesInParentheses; + ? Style.SpacesInParensOptions.InCStyleCasts + : (Style.SpacesInParens == FormatStyle::SIPO_Always || + Style.SpacesInParentheses); } if (Right.isOneOf(tok::semi, tok::comma)) return false; @@ -4037,7 +4041,10 @@ if ((Left.is(tok::l_brace) && Left.isNot(BK_Block)) || (Right.is(tok::r_brace) && Right.MatchingParen && Right.MatchingParen->isNot(BK_Block))) { - return Style.Cpp11BracedListStyle ? Style.SpacesInParentheses : true; + return Style.Cpp11BracedListStyle + ? (Style.SpacesInParens == FormatStyle::SIPO_Always || + Style.SpacesInParentheses) + : true; } if (Left.is(TT_BlockComment)) { // No whitespace in x(/*foo=*/1), except for JavaScript. @@ -4699,7 +4706,8 @@ !(Left.isOneOf(tok::l_paren, tok::r_paren, tok::l_square, tok::kw___super, TT_TemplateOpener, TT_TemplateCloser)) || - (Left.is(tok::l_paren) && Style.SpacesInParentheses); + (Left.is(tok::l_paren) && + (Style.SpacesInParens || Style.SpacesInParentheses)); } if ((Left.is(TT_TemplateOpener)) != (Right.is(TT_TemplateCloser))) return ShouldAddSpacesInAngles(); diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp --- a/clang/unittests/Format/ConfigParseTest.cpp +++ b/clang/unittests/Format/ConfigParseTest.cpp @@ -175,7 +175,6 @@ CHECK_PARSE_BOOL(ReflowComments); CHECK_PARSE_BOOL(RemoveBracesLLVM); CHECK_PARSE_BOOL(RemoveSemicolon); - CHECK_PARSE_BOOL(SpacesInParentheses); CHECK_PARSE_BOOL(SpacesInSquareBrackets); CHECK_PARSE_BOOL(SpacesInConditionalStatement); CHECK_PARSE_BOOL(SpaceInEmptyBlock); @@ -221,6 +220,9 @@ CHECK_PARSE_NESTED_BOOL(SpaceBeforeParensOptions, AfterIfMacros); CHECK_PARSE_NESTED_BOOL(SpaceBeforeParensOptions, AfterOverloadedOperator); CHECK_PARSE_NESTED_BOOL(SpaceBeforeParensOptions, BeforeNonEmptyParentheses); + CHECK_PARSE_NESTED_BOOL(SpacesInParensOptions, InCStyleCasts); + CHECK_PARSE_NESTED_BOOL(SpacesInParensOptions, InConditionalStatements); + CHECK_PARSE_NESTED_BOOL(SpacesInParensOptions, InEmptyParentheses); } #undef CHECK_PARSE_BOOL diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -11038,7 +11038,7 @@ verifyFormat("SomeType MemberFunction(const Deleted &) &;", Spaces); Spaces.SpacesInCStyleCastParentheses = false; - Spaces.SpacesInParentheses = true; + Spaces.SpacesInParens = FormatStyle::SIPO_Always; verifyFormat("Deleted &operator=( const Deleted & ) & = default;", Spaces); verifyFormat("SomeType MemberFunction( const Deleted & ) & = delete;", Spaces); @@ -13674,7 +13674,7 @@ FormatStyle SpaceBetweenBraces = getLLVMStyle(); SpaceBetweenBraces.SpacesInAngles = FormatStyle::SIAS_Always; - SpaceBetweenBraces.SpacesInParentheses = true; + SpaceBetweenBraces.SpacesInParens = FormatStyle::SIPO_Always; SpaceBetweenBraces.SpacesInSquareBrackets = true; verifyFormat("vector< int > x{ 1, 2, 3, 4 };", SpaceBetweenBraces); verifyFormat("f( {}, { {}, {} }, MyMap[ { k, v } ] );", SpaceBetweenBraces); @@ -16707,10 +16707,10 @@ verifyFormat("! ! x", Spaces); } -TEST_F(FormatTest, ConfigurableSpacesInParentheses) { +TEST_F(FormatTest, ConfigurableSpacesInParens) { FormatStyle Spaces = getLLVMStyle(); - Spaces.SpacesInParentheses = true; + Spaces.SpacesInParens = FormatStyle::SIPO_Always; verifyFormat("do_something( ::globalVar );", Spaces); verifyFormat("call( x, y, z );", Spaces); verifyFormat("call();", Spaces); @@ -16738,7 +16738,7 @@ "}", Spaces); - Spaces.SpacesInParentheses = false; + Spaces.SpacesInParens = FormatStyle::SIPO_Never; Spaces.SpacesInCStyleCastParentheses = true; verifyFormat("Type *A = ( Type * )P;", Spaces); verifyFormat("Type *A = ( vector )P;", Spaces); @@ -16750,7 +16750,7 @@ verifyFormat("#define x (( int )-1)", Spaces); // Run the first set of tests again with: - Spaces.SpacesInParentheses = false; + Spaces.SpacesInParens = FormatStyle::SIPO_Never; Spaces.SpaceInEmptyParentheses = true; Spaces.SpacesInCStyleCastParentheses = true; verifyFormat("call(x, y, z);", Spaces); @@ -23523,10 +23523,10 @@ verifyFormat("vector<_Atomic(uint64_t)* attr> x;", Style); Style.SpacesInCStyleCastParentheses = true; - Style.SpacesInParentheses = false; + Style.SpacesInParens = FormatStyle::SIPO_Never; verifyFormat("x = ( _Atomic(uint64_t) )*a;", Style); Style.SpacesInCStyleCastParentheses = false; - Style.SpacesInParentheses = true; + Style.SpacesInParens = FormatStyle::SIPO_Always; verifyFormat("x = (_Atomic( uint64_t ))*a;", Style); verifyFormat("x = (_Atomic( uint64_t ))&a;", Style); }