[clang] 7c15dd6 - [clang-format] Add space in placement new expression
Owen Pan via cfe-commits
cfe-commits at lists.llvm.org
Fri Oct 20 03:16:39 PDT 2023
Author: Omar Ahmed
Date: 2023-10-20T03:16:28-07:00
New Revision: 7c15dd60ec4549f53f1a51c5302c61f8a025a4a5
URL: https://github.com/llvm/llvm-project/commit/7c15dd60ec4549f53f1a51c5302c61f8a025a4a5
DIFF: https://github.com/llvm/llvm-project/commit/7c15dd60ec4549f53f1a51c5302c61f8a025a4a5.diff
LOG: [clang-format] Add space in placement new expression
Add AfterPlacementNew option to SpaceBeforeParensOptions to have more
control on placement new expressions.
Fixes #41501
Relates to #54703
Differential Revision: https://reviews.llvm.org/D127270
Added:
Modified:
clang/docs/ClangFormatStyleOptions.rst
clang/docs/tools/dump_format_style.py
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 c5c72c68ee9b800..cfd57f5fa8153f4 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -5224,6 +5224,33 @@ the configuration (without a prefix: ``Auto``).
void operator++ (int a); vs. void operator++(int a);
object.operator++ (10); object.operator++(10);
+ * ``AfterPlacementOperatorStyle AfterPlacementOperator`` :versionbadge:`clang-format 18`
+
+ Defines in which cases to put a space between ``new/delete`` operators
+ and opening parentheses.
+
+ Possible values:
+
+ * ``APO_Never`` (in configuration: ``Never``)
+ Remove 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
index 270ac34c03b39ca..75d4a044ef19f68 100755
--- a/clang/docs/tools/dump_format_style.py
+++ b/clang/docs/tools/dump_format_style.py
@@ -143,11 +143,18 @@ def __str__(self):
class NestedField(object):
- def __init__(self, name, comment):
+ def __init__(self, name, comment, version):
self.name = name
self.comment = comment.strip()
+ self.version = version
def __str__(self):
+ if self.version:
+ return "\n* ``%s`` :versionbadge:`clang-format %s`\n%s" % (
+ self.name,
+ self.version,
+ doxygen2rst(indent(self.comment, 2, indent_first_line=False)),
+ )
return "\n* ``%s`` %s" % (
self.name,
doxygen2rst(indent(self.comment, 2, indent_first_line=False)),
@@ -165,18 +172,28 @@ def __str__(self):
class NestedEnum(object):
- def __init__(self, name, enumtype, comment, values):
+ def __init__(self, name, enumtype, comment, version, values):
self.name = name
self.comment = comment
self.values = values
self.type = enumtype
+ self.version = version
def __str__(self):
- s = "\n* ``%s %s``\n%s" % (
- to_yaml_type(self.type),
- self.name,
- doxygen2rst(indent(self.comment, 2)),
- )
+ s = ""
+ if self.version:
+ s = "\n* ``%s %s`` :versionbadge:`clang-format %s`\n\n%s" % (
+ to_yaml_type(self.type),
+ self.name,
+ self.version,
+ doxygen2rst(indent(self.comment, 2)),
+ )
+ else:
+ s = "\n* ``%s %s``\n%s" % (
+ to_yaml_type(self.type),
+ self.name,
+ doxygen2rst(indent(self.comment, 2)),
+ )
s += indent("\nPossible values:\n\n", 2)
s += indent("\n".join(map(str, self.values)), 2)
return s
@@ -278,7 +295,9 @@ class State:
InFieldComment,
InEnum,
InEnumMemberComment,
- ) = range(8)
+ InNestedEnum,
+ InNestedEnumMemberComment,
+ ) = range(10)
state = State.BeforeStruct
@@ -344,27 +363,38 @@ class State:
state = State.InStruct
nested_structs[nested_struct.name] = nested_struct
elif state == State.InNestedFieldComment:
- if line.startswith("///"):
+ if line.startswith(r"/// \version"):
+ match = re.match(r"/// \\version\s*(?P<version>[0-9.]+)*", line)
+ if match:
+ version = match.group("version")
+ elif 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()
+ # if not version:
+ # self.__warning(f"missing version for {field_name}", line)
if field_type in enums:
nested_struct.values.append(
NestedEnum(
field_name,
field_type,
comment,
+ version,
enums[field_type].values,
)
)
else:
nested_struct.values.append(
- NestedField(field_type + " " + field_name, comment)
+ NestedField(field_type + " " + field_name, comment, version)
)
-
+ version = None
elif state == State.InEnum:
if line.startswith("///"):
state = State.InEnumMemberComment
@@ -376,6 +406,17 @@ class State:
# 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)
@@ -389,6 +430,19 @@ class State:
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
index 2707ea608c74efd..ed92ef6fc655522 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -4128,6 +4128,28 @@ struct FormatStyle {
/// object.operator++ (10); object.operator++(10);
/// \endcode
bool AfterOverloadedOperator;
+ /// Styles for adding spacing between ``new/delete`` operators and opening
+ /// parentheses.
+ enum AfterPlacementOperatorStyle : int8_t {
+ /// Remove 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 18
+ AfterPlacementOperatorStyle AfterPlacementOperator;
/// If ``true``, put space between requires keyword in a requires clause and
/// opening parentheses, if there is one.
/// \code
@@ -4160,8 +4182,9 @@ struct FormatStyle {
: AfterControlStatements(false), AfterForeachMacros(false),
AfterFunctionDeclarationName(false),
AfterFunctionDefinitionName(false), AfterIfMacros(false),
- AfterOverloadedOperator(false), AfterRequiresInClause(false),
- AfterRequiresInExpression(false), BeforeNonEmptyParentheses(false) {}
+ AfterOverloadedOperator(false), AfterPlacementOperator(APO_Leave),
+ AfterRequiresInClause(false), AfterRequiresInExpression(false),
+ BeforeNonEmptyParentheses(false) {}
bool operator==(const SpaceBeforeParensCustom &Other) const {
return AfterControlStatements == Other.AfterControlStatements &&
@@ -4171,6 +4194,7 @@ struct FormatStyle {
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
index 7b0ebe2cf621b17..acbed56a86e141f 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -504,6 +504,22 @@ struct ScalarEnumerationTraits<FormatStyle::QualifierAlignmentStyle> {
}
};
+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<FormatStyle::RawStringFormat> {
static void mapping(IO &IO, FormatStyle::RawStringFormat &Format) {
IO.mapOptional("Language", Format.Language);
@@ -679,6 +695,7 @@ template <> struct MappingTraits<FormatStyle::SpaceBeforeParensCustom> {
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);
@@ -1369,6 +1386,8 @@ static void expandPresetsSpaceBeforeParens(FormatStyle &Expanded) {
switch (Expanded.SpaceBeforeParens) {
case FormatStyle::SBPO_Never:
+ Expanded.SpaceBeforeParensOptions.AfterPlacementOperator =
+ FormatStyle::SpaceBeforeParensCustom::APO_Never;
break;
case FormatStyle::SBPO_ControlStatements:
Expanded.SpaceBeforeParensOptions.AfterControlStatements = true;
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index 293f7286abe4202..7f85f48de2ed2ed 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -4234,6 +4234,19 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
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/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp
index dedaf546ea5ff4f..c35c82955f6a558 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -591,6 +591,24 @@ TEST(ConfigParseTest, ParsesConfiguration) {
SpaceBeforeParens,
FormatStyle::SBPO_ControlStatementsExceptControlMacros);
+ Style.SpaceBeforeParens = FormatStyle::SBPO_Custom;
+ Style.SpaceBeforeParensOptions.AfterPlacementOperator =
+ FormatStyle::SpaceBeforeParensCustom::APO_Always;
+ CHECK_PARSE("SpaceBeforeParensOptions:\n"
+ " AfterPlacementOperator: Never",
+ SpaceBeforeParensOptions.AfterPlacementOperator,
+ FormatStyle::SpaceBeforeParensCustom::APO_Never);
+
+ CHECK_PARSE("SpaceBeforeParensOptions:\n"
+ " AfterPlacementOperator: Always",
+ SpaceBeforeParensOptions.AfterPlacementOperator,
+ FormatStyle::SpaceBeforeParensCustom::APO_Always);
+
+ CHECK_PARSE("SpaceBeforeParensOptions:\n"
+ " AfterPlacementOperator: Leave",
+ SpaceBeforeParensOptions.AfterPlacementOperator,
+ FormatStyle::SpaceBeforeParensCustom::APO_Leave);
+
// For backward compatibility:
Style.SpacesInParens = FormatStyle::SIPO_Never;
Style.SpacesInParensOptions = {};
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 963fb8f4d441618..0a87cfc4f1d6af9 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -11189,6 +11189,42 @@ TEST_F(FormatTest, UnderstandsNewAndDelete) {
"void delete(link p);",
"void new (link p);\n"
"void delete (link p);");
+
+ FormatStyle AfterPlacementOperator = getLLVMStyle();
+ AfterPlacementOperator.SpaceBeforeParens = FormatStyle::SBPO_Custom;
+ EXPECT_EQ(
+ AfterPlacementOperator.SpaceBeforeParensOptions.AfterPlacementOperator,
+ FormatStyle::SpaceBeforeParensCustom::APO_Leave);
+ verifyFormat("new (buf) int;", AfterPlacementOperator);
+ verifyFormat("new(buf) int;", AfterPlacementOperator);
+
+ AfterPlacementOperator.SpaceBeforeParensOptions.AfterPlacementOperator =
+ FormatStyle::SpaceBeforeParensCustom::APO_Never;
+ verifyFormat("struct A {\n"
+ " int *a;\n"
+ " A(int *p) : a(new(p) int) {\n"
+ " new(p) int;\n"
+ " int *b = new(p) int;\n"
+ " int *c = new(p) int(3);\n"
+ " delete(b);\n"
+ " }\n"
+ "};",
+ AfterPlacementOperator);
+ verifyFormat("void operator new(void *foo) ATTRIB;", AfterPlacementOperator);
+
+ AfterPlacementOperator.SpaceBeforeParensOptions.AfterPlacementOperator =
+ FormatStyle::SpaceBeforeParensCustom::APO_Always;
+ verifyFormat("struct A {\n"
+ " int *a;\n"
+ " A(int *p) : a(new (p) int) {\n"
+ " new (p) int;\n"
+ " int *b = new (p) int;\n"
+ " int *c = new (p) int(3);\n"
+ " delete (b);\n"
+ " }\n"
+ "};",
+ AfterPlacementOperator);
+ verifyFormat("void operator new(void *foo) ATTRIB;", AfterPlacementOperator);
}
TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
More information about the cfe-commits
mailing list