diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -4699,6 +4699,32 @@ true: false: ! someExpression(); vs. !someExpression(); +.. _SpaceAfterOperatorCall: + +**SpaceAfterOperatorCall** (``Boolean``) :versionbadge:`clang-format 17` :ref:`¶ ` + If ``true``, a space will be inserted after the 'operator' keyword + in every operator call expression. + + .. code-block:: c++ + + true: false: + foo.operator ==(...); vs. foo.operator==(...); + foo.Foo::operator ==(...); vs. foo.Foo::operator==(...); + foo->operator ==(...); vs. foo->operator==(...); + foo->Foo::operator ==(...); vs. foo->Foo::operator==(...); + +.. _SpaceAfterOperatorOverload: + +**SpaceAfterOperatorOverload** (``Boolean``) :versionbadge:`clang-format 17` :ref:`¶ ` + If ``true``, a space will be inserted after the 'operator' keyword + in every operator overload declaration. + + .. code-block:: c++ + + true: false: + bool operator ==(...); vs. bool operator==(...); + bool Foo::operator ==(...); vs. bool Foo::operator ==(...); + .. _SpaceAfterTemplateKeyword: **SpaceAfterTemplateKeyword** (``Boolean``) :versionbadge:`clang-format 4` :ref:`¶ ` diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -713,6 +713,10 @@ - Fix all known issues associated with ``LambdaBodyIndentation: OuterScope``. - Add ``BracedInitializerIndentWidth`` which can be used to configure the indentation level of the contents of braced init lists. +- Add ``SpaceAfterOperatorOverload`` which if set to true will insert a space + after the ``operator`` keyword in every overload declaration. +- Add ``SpaceAfterOperatorCall`` which if set to true will insert a space + after the ``operator`` keyword in every operator call/address-of expression. libclang -------- 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 @@ -3688,6 +3688,28 @@ /// \version 9 bool SpaceAfterLogicalNot; + /// If \c true, a space will be inserted after the 'operator' keyword + /// in every operator call expression. + /// \code + /// true: false: + /// foo.operator ==(...); vs. foo.operator==(...); + /// foo.Foo::operator ==(...); vs. foo.Foo::operator==(...); + /// foo->operator ==(...); vs. foo->operator==(...); + /// foo->Foo::operator ==(...); vs. foo->Foo::operator==(...); + /// \endcode + /// \version 17 + bool SpaceAfterOperatorCall; + + /// If \c true, a space will be inserted after the 'operator' keyword + /// in every operator overload declaration. + /// \code + /// true: false: + /// bool operator ==(...); vs. bool operator==(...); + /// bool Foo::operator ==(...); vs. bool Foo::operator ==(...); + /// \endcode + /// \version 17 + bool SpaceAfterOperatorOverload; + /// If \c true, a space will be inserted after the 'template' keyword. /// \code /// true: false: @@ -4406,6 +4428,8 @@ SortJavaStaticImport == R.SortJavaStaticImport && SpaceAfterCStyleCast == R.SpaceAfterCStyleCast && SpaceAfterLogicalNot == R.SpaceAfterLogicalNot && + SpaceAfterOperatorCall == R.SpaceAfterOperatorCall && + SpaceAfterOperatorOverload == R.SpaceAfterOperatorOverload && SpaceAfterTemplateKeyword == R.SpaceAfterTemplateKeyword && SpaceBeforeAssignmentOperators == R.SpaceBeforeAssignmentOperators && SpaceBeforeCaseColon == R.SpaceBeforeCaseColon && 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 @@ -999,6 +999,9 @@ IO.mapOptional("SortUsingDeclarations", Style.SortUsingDeclarations); IO.mapOptional("SpaceAfterCStyleCast", Style.SpaceAfterCStyleCast); IO.mapOptional("SpaceAfterLogicalNot", Style.SpaceAfterLogicalNot); + IO.mapOptional("SpaceAfterOperatorCall", Style.SpaceAfterOperatorCall); + IO.mapOptional("SpaceAfterOperatorOverload", + Style.SpaceAfterOperatorOverload); IO.mapOptional("SpaceAfterTemplateKeyword", Style.SpaceAfterTemplateKeyword); IO.mapOptional("SpaceAroundPointerQualifiers", @@ -1437,6 +1440,8 @@ LLVMStyle.SortUsingDeclarations = FormatStyle::SUD_LexicographicNumeric; LLVMStyle.SpaceAfterCStyleCast = false; LLVMStyle.SpaceAfterLogicalNot = false; + LLVMStyle.SpaceAfterOperatorCall = false; + LLVMStyle.SpaceAfterOperatorOverload = false; LLVMStyle.SpaceAfterTemplateKeyword = true; LLVMStyle.SpaceAroundPointerQualifiers = FormatStyle::SAPQ_Default; LLVMStyle.SpaceBeforeCaseColon = false; 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 @@ -4200,9 +4200,26 @@ // Space in __attribute__((attr)) ::type. if (Left.is(TT_AttributeParen) && Right.is(tok::coloncolon)) return true; - - if (Left.is(tok::kw_operator)) - return Right.is(tok::coloncolon); + // Operator overloads, calls and address-of expressions + if (Left.is(tok::kw_operator)) { + FormatToken const *Token = &Left; + while (Token) { + if (!Token->hasWhitespaceBefore()) { // Skip until we reach whitespace + Token = Token->Previous; + continue; + } + Token = Token->Previous; // Skip one more token and check if it exists + if (!Token) + return Right.is(tok::coloncolon); + // This handles all overload cases; type/type*/type&/type&&/type<> + // operator..(...); + if (Token->isTypeOrIdentifier() || + Token->isOneOf(tok::star, tok::amp, tok::ampamp, tok::greater)) + return Style.SpaceAfterOperatorOverload || Right.is(tok::coloncolon); + Token = Token->Previous; + } + return Style.SpaceAfterOperatorCall || Right.is(tok::coloncolon); + } if (Right.is(tok::l_brace) && Right.is(BK_BracedInit) && !Left.opensScope() && Style.SpaceBeforeCpp11BracedList) { return true; 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 @@ -182,6 +182,8 @@ CHECK_PARSE_BOOL(SpacesInContainerLiterals); CHECK_PARSE_BOOL(SpacesInCStyleCastParentheses); CHECK_PARSE_BOOL(SpaceAfterCStyleCast); + CHECK_PARSE_BOOL(SpaceAfterOperatorCall); + CHECK_PARSE_BOOL(SpaceAfterOperatorOverload); CHECK_PARSE_BOOL(SpaceAfterTemplateKeyword); CHECK_PARSE_BOOL(SpaceAfterLogicalNot); CHECK_PARSE_BOOL(SpaceBeforeAssignmentOperators); 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 @@ -22885,6 +22885,120 @@ Spaces); } +TEST_F(FormatTest, SpaceAfterOperatorCall) { + FormatStyle Style = getLLVMStyle(); + verifyFormat("bool operator==();", Style); + verifyFormat("bool Foo::operator==();", Style); + verifyFormat("bool *operator==();", Style); + verifyFormat("bool *Foo::operator==();", Style); + verifyFormat("bool &operator==();", Style); + verifyFormat("bool &Foo::operator==();", Style); + verifyFormat("bool &&operator==();", Style); + verifyFormat("bool &&Foo::operator==();", Style); + verifyFormat("std::vector operator==();", Style); + verifyFormat("std::vector Foo::operator==();", Style); + verifyFormat("foo.operator==();", Style); + verifyFormat("foo.Foo::operator==();", Style); + verifyFormat("foo->operator==();", Style); + verifyFormat("foo->Foo::operator==();", Style); + verifyFormat("operator==();", Style); + verifyFormat("Foo::operator==();", Style); + verifyFormat("Bar{var, operator==()};", Style); + verifyFormat("Bar{var, Foo::operator==()};", Style); + verifyFormat("Bar(var, operator==());", Style); + verifyFormat("Bar(var, Foo::operator==());", Style); + verifyFormat("&operator==();", Style); + verifyFormat("&Foo::operator==();", Style); + verifyFormat("&foo.operator==();", Style); + verifyFormat("&foo.Foo::operator==();", Style); + verifyFormat("&foo->operator==();", Style); + verifyFormat("&foo->Foo::operator==();", Style); + Style.SpaceAfterOperatorCall = true; + verifyFormat("bool operator==();", Style); + verifyFormat("bool Foo::operator==();", Style); + verifyFormat("bool *operator==();", Style); + verifyFormat("bool *Foo::operator==();", Style); + verifyFormat("bool &operator==();", Style); + verifyFormat("bool &Foo::operator==();", Style); + verifyFormat("bool &&operator==();", Style); + verifyFormat("bool &&Foo::operator==();", Style); + verifyFormat("std::vector operator==();", Style); + verifyFormat("std::vector Foo::operator==();", Style); + verifyFormat("foo.operator ==();", Style); + verifyFormat("foo.Foo::operator ==();", Style); + verifyFormat("foo->operator ==();", Style); + verifyFormat("foo->Foo::operator ==();", Style); + verifyFormat("operator ==();", Style); + verifyFormat("Foo::operator ==();", Style); + verifyFormat("Bar{var, operator ==()};", Style); + verifyFormat("Bar{var, Foo::operator ==()};", Style); + verifyFormat("Bar(var, operator ==());", Style); + verifyFormat("Bar(var, Foo::operator ==());", Style); + verifyFormat("&operator ==();", Style); + verifyFormat("&Foo::operator ==();", Style); + verifyFormat("&foo.operator ==();", Style); + verifyFormat("&foo.Foo::operator ==();", Style); + verifyFormat("&foo->operator ==();", Style); + verifyFormat("&foo->Foo::operator ==();", Style); +} + +TEST_F(FormatTest, SpaceAfterOperatorOverload) { + FormatStyle Style = getLLVMStyle(); + verifyFormat("bool operator==();", Style); + verifyFormat("bool Foo::operator==();", Style); + verifyFormat("bool *operator==();", Style); + verifyFormat("bool *Foo::operator==();", Style); + verifyFormat("bool &operator==();", Style); + verifyFormat("bool &Foo::operator==();", Style); + verifyFormat("bool &&operator==();", Style); + verifyFormat("bool &&Foo::operator==();", Style); + verifyFormat("std::vector operator==();", Style); + verifyFormat("std::vector Foo::operator==();", Style); + verifyFormat("foo.operator==();", Style); + verifyFormat("foo.Foo::operator==();", Style); + verifyFormat("foo->operator==();", Style); + verifyFormat("foo->Foo::operator==();", Style); + verifyFormat("operator==();", Style); + verifyFormat("Foo::operator==();", Style); + verifyFormat("Bar{var, operator==()};", Style); + verifyFormat("Bar{var, Foo::operator==()};", Style); + verifyFormat("Bar(var, operator==());", Style); + verifyFormat("Bar(var, Foo::operator==());", Style); + verifyFormat("&operator==();", Style); + verifyFormat("&Foo::operator==();", Style); + verifyFormat("&foo.operator==();", Style); + verifyFormat("&foo.Foo::operator==();", Style); + verifyFormat("&foo->operator==();", Style); + verifyFormat("&foo->Foo::operator==();", Style); + Style.SpaceAfterOperatorOverload = true; + verifyFormat("bool operator ==();", Style); + verifyFormat("bool Foo::operator ==();", Style); + verifyFormat("bool *operator ==();", Style); + verifyFormat("bool *Foo::operator ==();", Style); + verifyFormat("bool &operator ==();", Style); + verifyFormat("bool &Foo::operator ==();", Style); + verifyFormat("bool &&operator ==();", Style); + verifyFormat("bool &&Foo::operator ==();", Style); + verifyFormat("std::vector operator ==();", Style); + verifyFormat("std::vector Foo::operator ==();", Style); + verifyFormat("foo.operator==();", Style); + verifyFormat("foo.Foo::operator==();", Style); + verifyFormat("foo->operator==();", Style); + verifyFormat("foo->Foo::operator==();", Style); + verifyFormat("operator==();", Style); + verifyFormat("Foo::operator==();", Style); + verifyFormat("Bar{var, operator==()};", Style); + verifyFormat("Bar{var, Foo::operator==()};", Style); + verifyFormat("Bar(var, operator==());", Style); + verifyFormat("Bar(var, Foo::operator==());", Style); + verifyFormat("&operator==();", Style); + verifyFormat("&Foo::operator==();", Style); + verifyFormat("&foo.operator==();", Style); + verifyFormat("&foo.Foo::operator==();", Style); + verifyFormat("&foo->operator==();", Style); + verifyFormat("&foo->Foo::operator==();", Style); +} + TEST_F(FormatTest, SpaceAfterTemplateKeyword) { FormatStyle Style = getLLVMStyle(); Style.SpaceAfterTemplateKeyword = false;