diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -4248,7 +4248,7 @@ true: false: IF (...) vs. IF(...) - + * ``bool AfterOverloadedOperator`` If ``true``, put a space between operator overloading and opening parentheses. @@ -4258,6 +4258,31 @@ void operator++ (int a); vs. void operator++(int a); object.operator++ (10); object.operator++(10); + **AfterPlacementOperator** (``AfterPlacementOperatorStyle``) :versionbadge:`clang-format 14` + Defines in which cases to put a space between new/delete operators and opening parentheses. + + Possible values: + + * ``APO_Never`` (in configuration: ``Never``) + Remove spaces between new/delete operators and opening parentheses. + + .. code-block:: c++ + + new(placement) Type; + delete(placement) Type; + + * ``APO_Always`` (in configuration: ``Always``) + Add space between new/delete operators and opening parentheses. + + .. code-block:: c++ + + new (placement) Type; + delete (placement) Type; + + * ``APO_Leave`` (in configuration: ``Always``) + Leave placement ``new/delete`` expressions as they are.. + + * ``bool AfterRequiresInClause`` If ``true``, put space between requires keyword in a requires clause and opening parentheses, if there is one. 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 @@ -3490,6 +3490,11 @@ /// /// \endcode bool AfterIfMacros; + /// If ``true``, put space between placement new and opening parentheses. + /// \code + /// true: false: + /// new (buf) T; vs. new(buf) T; + /// \endcode /// If ``true``, put a space between operator overloading and opening /// parentheses. /// \code @@ -3498,6 +3503,27 @@ /// object.operator++ (10); object.operator++(10); /// \endcode bool AfterOverloadedOperator; + /// Styles for adding spacing between ``new/delete`` operators and opening + /// parentheses. + enum AfterPlacementOperatorStyle : int8_t { + /// Never add space after ``new/delete`` operators and before ``(``. + /// \code + /// new(buf) T; + /// delete(buf) T; + /// \endcode + APO_Never, + /// Always add space after ``new/delete`` operators and before ``(``. + /// \code + /// new (buf) T; + /// delete (buf) T; + /// \endcode + APO_Always, + /// Leave placement ``new/delete`` expressions as they are. + APO_Leave + }; + /// Defines in which cases to put a space between ``new/delete`` operators + /// and opening parentheses. \version 3.5 + AfterPlacementOperatorStyle AfterPlacementOperator; /// If ``true``, put space between requires keyword in a requires clause and /// opening parentheses, if there is one. /// \code @@ -3530,8 +3556,9 @@ : AfterControlStatements(false), AfterForeachMacros(false), AfterFunctionDeclarationName(false), AfterFunctionDefinitionName(false), AfterIfMacros(false), - AfterOverloadedOperator(false), AfterRequiresInClause(false), - AfterRequiresInExpression(false), BeforeNonEmptyParentheses(false) {} + AfterOverloadedOperator(false), AfterPlacementOperator(APO_Always), + AfterRequiresInClause(false), AfterRequiresInExpression(false), + BeforeNonEmptyParentheses(false) {} bool operator==(const SpaceBeforeParensCustom &Other) const { return AfterControlStatements == Other.AfterControlStatements && @@ -3541,6 +3568,7 @@ AfterFunctionDefinitionName == Other.AfterFunctionDefinitionName && AfterIfMacros == Other.AfterIfMacros && AfterOverloadedOperator == Other.AfterOverloadedOperator && + AfterPlacementOperator == Other.AfterPlacementOperator && AfterRequiresInClause == Other.AfterRequiresInClause && AfterRequiresInExpression == Other.AfterRequiresInExpression && BeforeNonEmptyParentheses == Other.BeforeNonEmptyParentheses; 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 @@ -936,6 +936,7 @@ Spacing.AfterFunctionDeclarationName); IO.mapOptional("AfterIfMacros", Spacing.AfterIfMacros); IO.mapOptional("AfterOverloadedOperator", Spacing.AfterOverloadedOperator); + IO.mapOptional("AfterPlacementOperator", Spacing.AfterPlacementOperator); IO.mapOptional("AfterRequiresInClause", Spacing.AfterRequiresInClause); IO.mapOptional("AfterRequiresInExpression", Spacing.AfterRequiresInExpression); @@ -944,6 +945,22 @@ } }; +template <> +struct MappingTraits< + FormatStyle::SpaceBeforeParensCustom::AfterPlacementOperatorStyle> { + static void + mapping(IO &IO, + FormatStyle::SpaceBeforeParensCustom::AfterPlacementOperatorStyle + &Value) { + IO.enumCase(Value, "Always", + FormatStyle::SpaceBeforeParensCustom::APO_Always); + IO.enumCase(Value, "Never", + FormatStyle::SpaceBeforeParensCustom::APO_Never); + IO.enumCase(Value, "Leave", + FormatStyle::SpaceBeforeParensCustom::APO_Leave); + } +}; + template <> struct MappingTraits { static void mapping(IO &IO, FormatStyle::RawStringFormat &Format) { IO.mapOptional("Language", Format.Language); 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 @@ -3393,6 +3393,18 @@ if (Left.is(TT_IfMacro)) return Style.SpaceBeforeParensOptions.AfterIfMacros || spaceRequiredBeforeParens(Right); + if (Style.SpaceBeforeParens == FormatStyle::SBPO_Custom && + Left.isOneOf(tok::kw_new, tok::kw_delete) && + Right.isNot(TT_OverloadedOperatorLParen) && + !(Line.MightBeFunctionDecl && Left.is(TT_FunctionDeclarationName))) { + if (Style.SpaceBeforeParensOptions.AfterPlacementOperator == + FormatStyle::SpaceBeforeParensCustom::APO_Always || + (Style.SpaceBeforeParensOptions.AfterPlacementOperator == + FormatStyle::SpaceBeforeParensCustom::APO_Leave && + Right.hasWhitespaceBefore())) + return true; + return false; + } if (Line.Type == LT_ObjCDecl) return true; if (Left.is(tok::semi)) 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 @@ -10130,6 +10130,37 @@ "void delete(link p);\n", format("void new (link p);\n" "void delete (link p);\n")); + + FormatStyle AfterPlacementOperator = getLLVMStyle(); + AfterPlacementOperator.SpaceBeforeParens = FormatStyle::SBPO_Custom; + EXPECT_EQ( + AfterPlacementOperator.SpaceBeforeParensOptions.AfterPlacementOperator, + FormatStyle::SpaceBeforeParensCustom::APO_Always); + verifyFormat("new (buf) T;", AfterPlacementOperator); + verifyFormat("T *p = new (buf) T;", AfterPlacementOperator); + verifyFormat("T *p = new (buf) T(3);", AfterPlacementOperator); + verifyFormat("T *p = delete (buf)T(3);", AfterPlacementOperator); + verifyFormat("struct A {\n" + " void *a;\n" + " A(void *p) : a(new (p) int) {}\n" + "};", + AfterPlacementOperator); + + AfterPlacementOperator.SpaceBeforeParensOptions.AfterPlacementOperator = + FormatStyle::SpaceBeforeParensCustom::APO_Never; + verifyFormat("new(buf) T;", AfterPlacementOperator); + verifyFormat("T *p = new(buf) T;", AfterPlacementOperator); + verifyFormat("T *p = delete(buf)T(3);", AfterPlacementOperator); + verifyFormat("struct A {\n" + " void *a;\n" + " A(void *p) : a(new(p) int) {}\n" + "};", + AfterPlacementOperator); + + AfterPlacementOperator.SpaceBeforeParensOptions.AfterPlacementOperator = + FormatStyle::SpaceBeforeParensCustom::APO_Leave; + EXPECT_EQ("new (buf) T;", format("new (buf) T;", AfterPlacementOperator)); + EXPECT_EQ("new(buf) T;", format("new(buf) T;", AfterPlacementOperator)); } TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {