[clang] [clang-format] Add an option for editing enum trailing commas (PR #133576)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Mar 29 01:58:15 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Owen Pan (owenca)
<details>
<summary>Changes</summary>
---
Full diff: https://github.com/llvm/llvm-project/pull/133576.diff
6 Files Affected:
- (modified) clang/docs/ClangFormatStyleOptions.rst (+34)
- (modified) clang/docs/ReleaseNotes.rst (+2)
- (modified) clang/include/clang/Format/Format.h (+28)
- (modified) clang/lib/Format/Format.cpp (+76)
- (modified) clang/unittests/Format/ConfigParseTest.cpp (+8)
- (modified) clang/unittests/Format/FormatTest.cpp (+32)
``````````diff
diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index 9ecac68ae72bf..211bb3eeeb6e6 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -3976,6 +3976,40 @@ the configuration (without a prefix: ``Auto``).
+.. _EnumTrailingComma:
+
+**EnumTrailingComma** (``EnumTrailingCommaStyle``) :versionbadge:`clang-format 21` :ref:`¶ <EnumTrailingComma>`
+ Insert a comma (if missing) or remove the comma at the end of an ``enum``
+ enumerator list.
+
+ Possible values:
+
+ * ``ETC_Leave`` (in configuration: ``Leave``)
+ Don't insert or remove trailing commas.
+
+ .. code-block:: c++
+
+ enum { a, b, c, };
+ enum Color { red, green, blue };
+
+ * ``ETC_Insert`` (in configuration: ``Insert``)
+ Insert trailing commas.
+
+ .. code-block:: c++
+
+ enum { a, b, c, };
+ enum Color { red, green, blue, };
+
+ * ``ETC_Remove`` (in configuration: ``Remove``)
+ Remove trailing commas.
+
+ .. code-block:: c++
+
+ enum { a, b, c };
+ enum Color { red, green, blue };
+
+
+
.. _ExperimentalAutoDetectBinPacking:
**ExperimentalAutoDetectBinPacking** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`¶ <ExperimentalAutoDetectBinPacking>`
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 04ec2cfef679c..27f6a93e31643 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -480,6 +480,8 @@ clang-format
- Allow specifying the language (C, C++, or Objective-C) for a ``.h`` file by
adding a special comment (e.g. ``// clang-format Language: ObjC``) near the
top of the file.
+- Add ``EnumTrailingComma`` option for inserting/removing commas at the end of
+ ``enum`` enumerator lists.
libclang
--------
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index fec47a248abb4..c39006c0d6361 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -2704,6 +2704,33 @@ struct FormatStyle {
/// \version 12
EmptyLineBeforeAccessModifierStyle EmptyLineBeforeAccessModifier;
+ /// Styles for ``enum`` trailing commas.
+ enum EnumTrailingCommaStyle : int8_t {
+ /// Don't insert or remove trailing commas.
+ /// \code
+ /// enum { a, b, c, };
+ /// enum Color { red, green, blue };
+ /// \endcode
+ ETC_Leave,
+ /// Insert trailing commas.
+ /// \code
+ /// enum { a, b, c, };
+ /// enum Color { red, green, blue, };
+ /// \endcode
+ ETC_Insert,
+ /// Remove trailing commas.
+ /// \code
+ /// enum { a, b, c };
+ /// enum Color { red, green, blue };
+ /// \endcode
+ ETC_Remove,
+ };
+
+ /// Insert a comma (if missing) or remove the comma at the end of an ``enum``
+ /// enumerator list.
+ /// \version 21
+ EnumTrailingCommaStyle EnumTrailingComma;
+
/// If ``true``, clang-format detects whether function calls and
/// definitions are formatted with one parameter per line.
///
@@ -5323,6 +5350,7 @@ struct FormatStyle {
DisableFormat == R.DisableFormat &&
EmptyLineAfterAccessModifier == R.EmptyLineAfterAccessModifier &&
EmptyLineBeforeAccessModifier == R.EmptyLineBeforeAccessModifier &&
+ EnumTrailingComma == R.EnumTrailingComma &&
ExperimentalAutoDetectBinPacking ==
R.ExperimentalAutoDetectBinPacking &&
FixNamespaceComments == R.FixNamespaceComments &&
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 28aea86139e0d..5a875b8693574 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -361,6 +361,15 @@ struct ScalarEnumerationTraits<
}
};
+template <>
+struct ScalarEnumerationTraits<FormatStyle::EnumTrailingCommaStyle> {
+ static void enumeration(IO &IO, FormatStyle::EnumTrailingCommaStyle &Value) {
+ IO.enumCase(Value, "Leave", FormatStyle::ETC_Leave);
+ IO.enumCase(Value, "Insert", FormatStyle::ETC_Insert);
+ IO.enumCase(Value, "Remove", FormatStyle::ETC_Remove);
+ }
+};
+
template <>
struct ScalarEnumerationTraits<FormatStyle::IndentExternBlockStyle> {
static void enumeration(IO &IO, FormatStyle::IndentExternBlockStyle &Value) {
@@ -1042,6 +1051,7 @@ template <> struct MappingTraits<FormatStyle> {
Style.EmptyLineAfterAccessModifier);
IO.mapOptional("EmptyLineBeforeAccessModifier",
Style.EmptyLineBeforeAccessModifier);
+ IO.mapOptional("EnumTrailingComma", Style.EnumTrailingComma);
IO.mapOptional("ExperimentalAutoDetectBinPacking",
Style.ExperimentalAutoDetectBinPacking);
IO.mapOptional("FixNamespaceComments", Style.FixNamespaceComments);
@@ -1558,6 +1568,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.DisableFormat = false;
LLVMStyle.EmptyLineAfterAccessModifier = FormatStyle::ELAAMS_Never;
LLVMStyle.EmptyLineBeforeAccessModifier = FormatStyle::ELBAMS_LogicalBlock;
+ LLVMStyle.EnumTrailingComma = FormatStyle::ETC_Leave;
LLVMStyle.ExperimentalAutoDetectBinPacking = false;
LLVMStyle.FixNamespaceComments = true;
LLVMStyle.ForEachMacros.push_back("foreach");
@@ -2415,6 +2426,64 @@ class SemiRemover : public TokenAnalyzer {
}
};
+class EnumTrailingCommaEditor : public TokenAnalyzer {
+public:
+ EnumTrailingCommaEditor(const Environment &Env, const FormatStyle &Style)
+ : TokenAnalyzer(Env, Style) {}
+
+ std::pair<tooling::Replacements, unsigned>
+ analyze(TokenAnnotator &Annotator,
+ SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
+ FormatTokenLexer &Tokens) override {
+ AffectedRangeMgr.computeAffectedLines(AnnotatedLines);
+ tooling::Replacements Result;
+ editEnumTrailingComma(AnnotatedLines, Result);
+ return {Result, 0};
+ }
+
+private:
+ void editEnumTrailingComma(SmallVectorImpl<AnnotatedLine *> &Lines,
+ tooling::Replacements &Result) {
+ const auto &SourceMgr = Env.getSourceManager();
+ for (auto *Line : Lines) {
+ if (!Line->Children.empty())
+ editEnumTrailingComma(Line->Children, Result);
+ if (!Line->Affected)
+ continue;
+ for (const auto *Token = Line->First; Token && !Token->Finalized;
+ Token = Token->Next) {
+ if (Token->isNot(TT_EnumRBrace))
+ continue;
+ const auto *BeforeRBrace = Token->getPreviousNonComment();
+ assert(BeforeRBrace);
+ if (BeforeRBrace->is(TT_EnumLBrace)) // Empty braces.
+ continue;
+ if (Style.EnumTrailingComma == FormatStyle::ETC_Insert) {
+ if (BeforeRBrace->isNot(tok::comma)) {
+ cantFail(Result.add(tooling::Replacement(
+ SourceMgr, BeforeRBrace->Tok.getEndLoc(), 0, ",")));
+ }
+ } else {
+ assert(Style.EnumTrailingComma == FormatStyle::ETC_Remove);
+ if (BeforeRBrace->isNot(tok::comma))
+ continue;
+ auto *Next = BeforeRBrace->Next;
+ SourceLocation Start;
+ if (Next->NewlinesBefore == 0) {
+ Start = BeforeRBrace->Tok.getLocation();
+ Next->WhitespaceRange = BeforeRBrace->WhitespaceRange;
+ } else {
+ Start = BeforeRBrace->WhitespaceRange.getBegin();
+ }
+ const auto &Range = CharSourceRange::getCharRange(
+ Start, BeforeRBrace->Tok.getEndLoc());
+ cantFail(Result.add(tooling::Replacement(SourceMgr, Range, " ")));
+ }
+ }
+ }
+ }
+};
+
class JavaScriptRequoter : public TokenAnalyzer {
public:
JavaScriptRequoter(const Environment &Env, const FormatStyle &Style)
@@ -3812,6 +3881,13 @@ reformat(const FormatStyle &Style, StringRef Code,
});
}
+ if (Style.EnumTrailingComma != FormatStyle::ETC_Leave) {
+ Passes.emplace_back([&](const Environment &Env) {
+ return EnumTrailingCommaEditor(Env, Expanded)
+ .process(/*SkipAnnotation=*/true);
+ });
+ }
+
if (Style.FixNamespaceComments) {
Passes.emplace_back([&](const Environment &Env) {
return NamespaceEndCommentsFixer(Env, Expanded).process();
diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp
index 287191d04d885..2b08b794792e9 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -520,6 +520,14 @@ TEST(ConfigParseTest, ParsesConfiguration) {
CHECK_PARSE("EmptyLineBeforeAccessModifier: Always",
EmptyLineBeforeAccessModifier, FormatStyle::ELBAMS_Always);
+ Style.EnumTrailingComma = FormatStyle::ETC_Insert;
+ CHECK_PARSE("EnumTrailingComma: Leave", EnumTrailingComma,
+ FormatStyle::ETC_Leave);
+ CHECK_PARSE("EnumTrailingComma: Insert", EnumTrailingComma,
+ FormatStyle::ETC_Insert);
+ CHECK_PARSE("EnumTrailingComma: Remove", EnumTrailingComma,
+ FormatStyle::ETC_Remove);
+
Style.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak;
CHECK_PARSE("AlignAfterOpenBracket: Align", AlignAfterOpenBracket,
FormatStyle::BAS_Align);
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 0b90bd360b758..4dfa135120605 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -27902,6 +27902,38 @@ TEST_F(FormatTest, RemoveSemicolon) {
verifyFormat("STRUCT(T, B) { int i; };", Style);
}
+TEST_F(FormatTest, EnumTrailingComma) {
+ constexpr StringRef Code("enum : int { /**/ };\n"
+ "enum {\n"
+ " a,\n"
+ " b,\n"
+ " c, //\n"
+ "};\n"
+ "enum Color { red, green, blue /**/ };");
+ verifyFormat(Code);
+
+ auto Style = getLLVMStyle();
+ Style.EnumTrailingComma = FormatStyle::ETC_Insert;
+ verifyFormat("enum : int { /**/ };\n"
+ "enum {\n"
+ " a,\n"
+ " b,\n"
+ " c, //\n"
+ "};\n"
+ "enum Color { red, green, blue, /**/ };",
+ Code, Style);
+
+ Style.EnumTrailingComma = FormatStyle::ETC_Remove;
+ verifyFormat("enum : int { /**/ };\n"
+ "enum {\n"
+ " a,\n"
+ " b,\n"
+ " c //\n"
+ "};\n"
+ "enum Color { red, green, blue /**/ };",
+ Code, Style);
+}
+
TEST_F(FormatTest, BreakAfterAttributes) {
constexpr StringRef Code("[[maybe_unused]] const int i;\n"
"[[foo([[]])]] [[maybe_unused]]\n"
``````````
</details>
https://github.com/llvm/llvm-project/pull/133576
More information about the cfe-commits
mailing list