diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -4258,6 +4258,33 @@ void operator++ (int a); vs. void operator++(int a); object.operator++ (10); object.operator++(10); + * ``AfterPlacementOperatorStyle AfterPlacementOperator`` + Defines in which cases to put a space between ``new/delete`` operators + and opening parentheses. + 14 + + Possible values: + + * ``APO_Never`` (in configuration: ``Never``) + Never add space after ``new/delete`` operators and before ``(``. + + .. code-block:: c++ + + new(buf) T; + delete(buf) T; + + * ``APO_Always`` (in configuration: ``Always``) + Always add space after ``new/delete`` operators and before ``(``. + + .. code-block:: c++ + + new (buf) T; + delete (buf) T; + + * ``APO_Leave`` (in configuration: ``Leave``) + 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/docs/tools/dump_format_style.py b/clang/docs/tools/dump_format_style.py --- a/clang/docs/tools/dump_format_style.py +++ b/clang/docs/tools/dump_format_style.py @@ -227,7 +227,7 @@ def read_options(self): class State: BeforeStruct, Finished, InStruct, InNestedStruct, InNestedFieldComment, \ - InFieldComment, InEnum, InEnumMemberComment = range(8) + InFieldComment, InEnum, InEnumMemberComment, InNestedEnum, InNestedEnumMemberComment = range(10) state = State.BeforeStruct options = [] @@ -288,6 +288,10 @@ elif state == State.InNestedFieldComment: if line.startswith('///'): comment += self.__clean_comment_line(line) + elif line.startswith('enum'): + state = State.InNestedEnum + name = re.sub(r'enum\s+(\w+)\s*(:((\s*\w+)+)\s*)?\{', '\\1', line) + enum = Enum(name, comment) else: state = State.InNestedStruct field_type, field_name = re.match(r'([<>:\w(,\s)]+)\s+(\w+);', line).groups() @@ -310,6 +314,17 @@ # Enum member without documentation. Must be documented where the enum # is used. pass + elif state == State.InNestedEnum: + if line.startswith('///'): + state = State.InNestedEnumMemberComment + comment = self.__clean_comment_line(line) + elif line == '};': + state = State.InNestedStruct + enums[enum.name] = enum + else: + # Enum member without documentation. Must be documented where the enum + # is used. + pass elif state == State.InEnumMemberComment: if line.startswith('///'): comment += self.__clean_comment_line(line) @@ -323,6 +338,19 @@ else: config = val enum.values.append(EnumValue(val, comment, config)) + elif state == State.InNestedEnumMemberComment: + if line.startswith('///'): + comment += self.__clean_comment_line(line) + else: + state = State.InNestedEnum + val = line.replace(',', '') + pos = val.find(" // ") + if pos != -1: + config = val[pos + 4:] + val = val[:pos] + else: + config = val + enum.values.append(EnumValue(val, comment, config)) if state != State.Finished: raise Exception('Not finished by the end of file') 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 @@ -3498,6 +3498,28 @@ /// 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 14 + AfterPlacementOperatorStyle AfterPlacementOperator; /// If ``true``, put space between requires keyword in a requires clause and /// opening parentheses, if there is one. /// \code @@ -3530,8 +3552,9 @@ : AfterControlStatements(false), AfterForeachMacros(false), AfterFunctionDeclarationName(false), AfterFunctionDefinitionName(false), AfterIfMacros(false), - AfterOverloadedOperator(false), AfterRequiresInClause(false), - AfterRequiresInExpression(false), BeforeNonEmptyParentheses(false) {} + AfterOverloadedOperator(false), AfterPlacementOperator(APO_Never), + AfterRequiresInClause(false), AfterRequiresInExpression(false), + BeforeNonEmptyParentheses(false) {} bool operator==(const SpaceBeforeParensCustom &Other) const { return AfterControlStatements == Other.AfterControlStatements && @@ -3541,6 +3564,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,42 @@ "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_Never); + verifyFormat("struct A {\n" + " void *a;\n" + " A(void *p) : a(new(p) int) {\n" + " new(p) int;\n" + " int *b = new(p) int;\n" + " int *c = new(p) int(3);\n" + " int *d = delete(p) int(3);\n" + " }\n" + "};", + AfterPlacementOperator); + verifyFormat("void operator new(void *foo) ATTRIB;", AfterPlacementOperator); + + AfterPlacementOperator.SpaceBeforeParensOptions.AfterPlacementOperator = + FormatStyle::SpaceBeforeParensCustom::APO_Always; + verifyFormat("struct A {\n" + " void *a;\n" + " A(void *p) : a(new (p) int) {\n" + " new (p) int;\n" + " int *b = new (p) int;\n" + " int *c = new (p) int(3);\n" + " int *d = delete (p) int(3);\n" + " }\n" + "};", + AfterPlacementOperator); + verifyFormat("void operator new(void *foo) ATTRIB;", AfterPlacementOperator); + + AfterPlacementOperator.SpaceBeforeParensOptions.AfterPlacementOperator = + FormatStyle::SpaceBeforeParensCustom::APO_Leave; + EXPECT_EQ("new (buf) int;", format("new (buf) int;", AfterPlacementOperator)); + EXPECT_EQ("new(buf) int;", format("new(buf) int;", AfterPlacementOperator)); } TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {