[clang] [clang-format] Add the style option `SpaceBeforeEnumColon` (PR #188748)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Mar 26 06:52:44 PDT 2026
https://github.com/misopeth created https://github.com/llvm/llvm-project/pull/188748
None
>From 4e0ffa564ff943e36219ae8083460a23ceaaaa25 Mon Sep 17 00:00:00 2001
From: Francesco Galizzi <francesco at artiria-medical.com>
Date: Thu, 26 Mar 2026 14:50:28 +0100
Subject: [PATCH] Add the style option `SpaceBeforeEnumColon`
---
clang/docs/ClangFormatStyleOptions.rst | 12 ++++
clang/include/clang/Format/Format.h | 13 +++++
clang/lib/Format/Format.cpp | 3 +
clang/lib/Format/FormatToken.h | 1 +
clang/lib/Format/TokenAnnotator.cpp | 23 ++++++++
clang/unittests/Format/ConfigParseTest.cpp | 1 +
clang/unittests/Format/FormatTest.cpp | 58 +++++++++++++++++++
clang/unittests/Format/TokenAnnotatorTest.cpp | 2 +-
8 files changed, 112 insertions(+), 1 deletion(-)
diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index f637b81bb75bc..fc375251dc6c0 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -6841,6 +6841,18 @@ the configuration (without a prefix: ``Auto``).
true: false:
class Foo : Bar {} vs. class Foo: Bar {}
+.. _SpaceBeforeEnumColon:
+
+**_SpaceBeforeEnumColon** (``Boolean``) :versionbadge:`clang-format 24` :ref:`¶ <_SpaceBeforeEnumColon>`
+ If ``false``, spaces will be removed before the colon specifying the
+ underlying type of an enum.
+
+ .. code-block:: c++
+
+ true: false:
+ enum Foo : int {} vs. enum Foo: int {}
+ enum class Bar : unsigned {} enum class Bar: unsigned {}
+
.. _SpaceBeforeJsonColon:
**SpaceBeforeJsonColon** (``Boolean``) :versionbadge:`clang-format 17` :ref:`¶ <SpaceBeforeJsonColon>`
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index 8c90cc2e98121..9242306bbcdbd 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -5129,6 +5129,18 @@ struct FormatStyle {
/// \version 7
bool SpaceBeforeInheritanceColon;
+ /// If ``false``, spaces will be removed before the colon specifying the
+ /// underlying type of an enum.
+ /// \code
+ /// true: false:
+ /// enum Foo : int {} vs. enum Foo: int {}
+ /// enum class Bar : unsigned {} enum class Bar: unsigned {}
+ /// enum struct Baz : char {}; enum struct Baz: char {};
+ /// enum Qux : short; enum Qux: short;
+ /// \endcode
+ /// \version 24
+ bool SpaceBeforeEnumColon;
+
/// If ``true``, a space will be added before a JSON colon. For other
/// languages, e.g. JavaScript, use ``SpacesInContainerLiterals`` instead.
/// \code
@@ -6077,6 +6089,7 @@ struct FormatStyle {
SpaceBeforeCtorInitializerColon ==
R.SpaceBeforeCtorInitializerColon &&
SpaceBeforeInheritanceColon == R.SpaceBeforeInheritanceColon &&
+ SpaceBeforeEnumColon == R.SpaceBeforeEnumColon &&
SpaceBeforeJsonColon == R.SpaceBeforeJsonColon &&
SpaceBeforeParens == R.SpaceBeforeParens &&
SpaceBeforeParensOptions == R.SpaceBeforeParensOptions &&
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 2b0aa1735c895..56f447a94a6c6 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -1400,6 +1400,8 @@ template <> struct MappingTraits<FormatStyle> {
Style.SpaceBeforeCtorInitializerColon);
IO.mapOptional("SpaceBeforeInheritanceColon",
Style.SpaceBeforeInheritanceColon);
+ IO.mapOptional("SpaceBeforeEnumColon",
+ Style.SpaceBeforeEnumColon);
IO.mapOptional("SpaceBeforeJsonColon", Style.SpaceBeforeJsonColon);
IO.mapOptional("SpaceBeforeParens", Style.SpaceBeforeParens);
IO.mapOptional("SpaceBeforeParensOptions", Style.SpaceBeforeParensOptions);
@@ -1919,6 +1921,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.SpaceBeforeCpp11BracedList = false;
LLVMStyle.SpaceBeforeCtorInitializerColon = true;
LLVMStyle.SpaceBeforeInheritanceColon = true;
+ LLVMStyle.SpaceBeforeEnumColon = true;
LLVMStyle.SpaceBeforeJsonColon = false;
LLVMStyle.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements;
LLVMStyle.SpaceBeforeParensOptions = {};
diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h
index ba9a95440f0c2..e75d1affaa862 100644
--- a/clang/lib/Format/FormatToken.h
+++ b/clang/lib/Format/FormatToken.h
@@ -78,6 +78,7 @@ namespace format {
TYPE(ElseRBrace) \
TYPE(EnumLBrace) \
TYPE(EnumRBrace) \
+ TYPE(EnumUnderlyingTypeColon) \
TYPE(FatArrow) \
TYPE(ForEachMacro) \
TYPE(FunctionAnnotationRParen) \
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index d2cdc28a7da7b..b4de3efd2316a 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -1347,6 +1347,27 @@ class AnnotatingParser {
return false;
// Goto labels and case labels are already identified in
// UnwrappedLineParser.
+ // Identify colons specifying the underlying type of an enum.
+ // e.g. enum Foo : int { ... }
+ // enum class Bar : unsigned { ... }
+ // enum Qux : short;
+ if (Style.isCpp() && (Line.First->is(tok::kw_enum) ||
+ Line.startsWith(tok::kw_typedef, tok::kw_enum))) {
+ // Make sure we're not inside the enum body (past the opening brace).
+ bool InsideBraces = false;
+ for (auto *T = Tok->Previous; T; T = T->Previous) {
+ if (T->is(tok::l_brace)) {
+ InsideBraces = true;
+ break;
+ }
+ if (T->is(tok::r_brace))
+ break;
+ }
+ if (!InsideBraces) {
+ Tok->setType(TT_EnumUnderlyingTypeColon);
+ break;
+ }
+ }
if (Tok->isTypeFinalized())
break;
// Colons from ?: are handled in parseConditional().
@@ -5551,6 +5572,8 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
return Style.SpaceBeforeCtorInitializerColon;
if (Right.is(TT_InheritanceColon) && !Style.SpaceBeforeInheritanceColon)
return false;
+ if (Right.is(TT_EnumUnderlyingTypeColon) && !Style.SpaceBeforeEnumColon)
+ return false;
if (Right.is(TT_RangeBasedForLoopColon) &&
!Style.SpaceBeforeRangeBasedForLoopColon) {
return false;
diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp
index 953f57da26cd9..d961461d66c89 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -220,6 +220,7 @@ TEST(ConfigParseTest, ParsesConfigurationBools) {
CHECK_PARSE_BOOL(SpaceBeforeCpp11BracedList);
CHECK_PARSE_BOOL(SpaceBeforeCtorInitializerColon);
CHECK_PARSE_BOOL(SpaceBeforeInheritanceColon);
+ CHECK_PARSE_BOOL(SpaceBeforeEnumColon);
CHECK_PARSE_BOOL(SpaceBeforeJsonColon);
CHECK_PARSE_BOOL(SpaceBeforeRangeBasedForLoopColon);
CHECK_PARSE_BOOL(SpaceBeforeSquareBrackets);
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 2701a7fca7346..3b898d54ca5e8 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -18632,6 +18632,64 @@ TEST_F(FormatTest, ConfigurableSpaceBeforeColon) {
InvertedSpaceStyle);
}
+TEST_F(FormatTest, SpaceBeforeEnumColon) {
+ FormatStyle Style = getLLVMStyle();
+
+ // Default: SpaceBeforeEnumColon is true
+ EXPECT_TRUE(Style.SpaceBeforeEnumColon);
+ verifyFormat("enum Foo : int {};", Style);
+ verifyFormat("enum class Foo : int {};", Style);
+ verifyFormat("enum struct Foo : int {};", Style);
+ verifyFormat("enum Foo : int;", Style);
+ verifyFormat("enum Foo : unsigned int { A, B, C };", Style);
+ verifyFormat("enum class Foo : unsigned char { A, B, C };", Style);
+
+ // SpaceBeforeEnumColon set to false
+ Style.SpaceBeforeEnumColon = false;
+ verifyFormat("enum Foo: int {};", Style);
+ verifyFormat("enum class Foo: int {};", Style);
+ verifyFormat("enum struct Foo: int {};", Style);
+ verifyFormat("enum Foo: int;", Style);
+ verifyFormat("enum Foo: unsigned int { A, B, C };", Style);
+ verifyFormat("enum class Foo: unsigned char { A, B, C };", Style);
+
+ // Ensure typedef enum also works
+ verifyFormat("typedef enum Foo: int {} Foo_t;", Style);
+
+ // Ensure other colons are not affected
+ verifyFormat("class Foo : Bar {};", Style);
+ Style.SpaceBeforeInheritanceColon = true;
+ verifyFormat("class Foo : Bar {};", Style);
+
+ // Ensure ternary and case colons are not affected
+ verifyFormat("int x = a ? b : c;", Style);
+ verifyFormat("switch (x) {\n"
+ "case 1:\n"
+ "default:\n"
+ "}",
+ Style);
+
+ // Ensure ctor initializer colons are not affected
+ Style.SpaceBeforeCtorInitializerColon = true;
+ verifyFormat("Foo::Foo() : a(a) {}", Style);
+
+ // Ensure range-based for colons are not affected
+ Style.SpaceBeforeRangeBasedForLoopColon = true;
+ verifyFormat("for (auto a : b) {\n}", Style);
+
+ // Combined: all colon spaces off
+ FormatStyle NoSpaceStyle = getLLVMStyle();
+ NoSpaceStyle.SpaceBeforeEnumColon = false;
+ NoSpaceStyle.SpaceBeforeCtorInitializerColon = false;
+ NoSpaceStyle.SpaceBeforeInheritanceColon = false;
+ NoSpaceStyle.SpaceBeforeRangeBasedForLoopColon = false;
+ verifyFormat("enum Foo: int {};", NoSpaceStyle);
+ verifyFormat("class Foo: Bar {};", NoSpaceStyle);
+ verifyFormat("Foo::Foo(): foo(1) {}", NoSpaceStyle);
+ verifyFormat("for (auto a: b) {\n}", NoSpaceStyle);
+ verifyFormat("int x = a ? b : c;", NoSpaceStyle);
+}
+
TEST_F(FormatTest, ConfigurableSpaceAroundPointerQualifiers) {
FormatStyle Style = getLLVMStyle();
diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp
index efb361387bb1e..18681e6923dbf 100644
--- a/clang/unittests/Format/TokenAnnotatorTest.cpp
+++ b/clang/unittests/Format/TokenAnnotatorTest.cpp
@@ -4342,7 +4342,7 @@ TEST_F(TokenAnnotatorTest, UserDefinedLiteral) {
TEST_F(TokenAnnotatorTest, EnumColonInTypedef) {
auto Tokens = annotate("typedef enum : int {} foo;");
ASSERT_EQ(Tokens.size(), 9u) << Tokens;
- EXPECT_TOKEN(Tokens[2], tok::colon, TT_Unknown); // Not TT_InheritanceColon.
+ EXPECT_TOKEN(Tokens[2], tok::colon, TT_EnumUnderlyingTypeColon);
}
TEST_F(TokenAnnotatorTest, BitFieldColon) {
More information about the cfe-commits
mailing list