diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index f637b81bb75bc..54c085dff2840 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -6831,6 +6831,16 @@ the configuration (without a prefix: ``Auto``). true: false: Foo::Foo() : a(a) {} Foo::Foo(): a(a) {} +.. _SpaceBeforeEnumUnderlyingTypeColon: + +**SpaceBeforeEnumUnderlyingTypeColon** (``Boolean``) :versionbadge:`clang-format 23` :ref:`¶ ` + If ``false``, spaces will be removed before enum underlying type colon. + + .. code-block:: c++ + + true: false: + enum E : int {} enum E: int {} + .. _SpaceBeforeInheritanceColon: **SpaceBeforeInheritanceColon** (``Boolean``) :versionbadge:`clang-format 7` :ref:`¶ ` diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 8c90cc2e98121..48ce5aa2bdfa1 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -5121,6 +5121,14 @@ struct FormatStyle { /// \version 7 bool SpaceBeforeCtorInitializerColon; + /// If ``false``, spaces will be removed before enum underlying type colon. + /// \code + /// true: false: + /// enum E : int {} enum E: int {} + /// \endcode + /// \version 23 + bool SpaceBeforeEnumUnderlyingTypeColon; + /// If ``false``, spaces will be removed before inheritance colon. /// \code /// true: false: diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 2b0aa1735c895..5ca1971acc1ab 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -1398,6 +1398,8 @@ template <> struct MappingTraits { Style.SpaceBeforeCpp11BracedList); IO.mapOptional("SpaceBeforeCtorInitializerColon", Style.SpaceBeforeCtorInitializerColon); + IO.mapOptional("SpaceBeforeEnumUnderlyingTypeColon", + Style.SpaceBeforeEnumUnderlyingTypeColon); IO.mapOptional("SpaceBeforeInheritanceColon", Style.SpaceBeforeInheritanceColon); IO.mapOptional("SpaceBeforeJsonColon", Style.SpaceBeforeJsonColon); @@ -1918,6 +1920,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.SpaceBeforeCaseColon = false; LLVMStyle.SpaceBeforeCpp11BracedList = false; LLVMStyle.SpaceBeforeCtorInitializerColon = true; + LLVMStyle.SpaceBeforeEnumUnderlyingTypeColon = true; LLVMStyle.SpaceBeforeInheritanceColon = true; LLVMStyle.SpaceBeforeJsonColon = false; LLVMStyle.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements; 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..3fa8ec44fa8bf 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -5551,6 +5551,10 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, return Style.SpaceBeforeCtorInitializerColon; if (Right.is(TT_InheritanceColon) && !Style.SpaceBeforeInheritanceColon) return false; + if (Right.is(TT_EnumUnderlyingTypeColon) && + !Style.SpaceBeforeEnumUnderlyingTypeColon) { + return false; + } if (Right.is(TT_RangeBasedForLoopColon) && !Style.SpaceBeforeRangeBasedForLoopColon) { return false; diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index a3e8a3e270e73..e9a5b3fb4d21c 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -3838,6 +3838,8 @@ bool UnwrappedLineParser::parseEnum() { FormatTok->isOneOf(tok::colon, tok::coloncolon, tok::less, tok::greater, tok::comma, tok::question, tok::l_square)) { + if (FormatTok->is(tok::colon)) + FormatTok->setFinalizedType(TT_EnumUnderlyingTypeColon); if (Style.isVerilog()) { FormatTok->setFinalizedType(TT_VerilogDimensionedTypeName); nextToken(); diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp index 953f57da26cd9..3cff71608cba4 100644 --- a/clang/unittests/Format/ConfigParseTest.cpp +++ b/clang/unittests/Format/ConfigParseTest.cpp @@ -219,6 +219,7 @@ TEST(ConfigParseTest, ParsesConfigurationBools) { CHECK_PARSE_BOOL(SpaceBeforeCaseColon); CHECK_PARSE_BOOL(SpaceBeforeCpp11BracedList); CHECK_PARSE_BOOL(SpaceBeforeCtorInitializerColon); + CHECK_PARSE_BOOL(SpaceBeforeEnumUnderlyingTypeColon); CHECK_PARSE_BOOL(SpaceBeforeInheritanceColon); CHECK_PARSE_BOOL(SpaceBeforeJsonColon); CHECK_PARSE_BOOL(SpaceBeforeRangeBasedForLoopColon); diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 2701a7fca7346..fbd9e0e0a4da4 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -18632,6 +18632,16 @@ TEST_F(FormatTest, ConfigurableSpaceBeforeColon) { InvertedSpaceStyle); } +TEST_F(FormatTest, EnumUnderlyingTypeColonSpacing) { + FormatStyle Style = getLLVMStyle(); + + Style.SpaceBeforeEnumUnderlyingTypeColon = true; + verifyFormat("enum A : int {};", Style); + + Style.SpaceBeforeEnumUnderlyingTypeColon = false; + verifyFormat("enum A: int {};", Style); +} + TEST_F(FormatTest, ConfigurableSpaceAroundPointerQualifiers) { FormatStyle Style = getLLVMStyle(); diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp index efb361387bb1e..2ba94636d933b 100644 --- a/clang/unittests/Format/TokenAnnotatorTest.cpp +++ b/clang/unittests/Format/TokenAnnotatorTest.cpp @@ -4339,10 +4339,26 @@ TEST_F(TokenAnnotatorTest, UserDefinedLiteral) { EXPECT_EQ(Tokens[3]->TokenText, "2_$"); } -TEST_F(TokenAnnotatorTest, EnumColonInTypedef) { - auto Tokens = annotate("typedef enum : int {} foo;"); +TEST_F(TokenAnnotatorTest, EnumColon) { + auto Tokens = annotate("enum A : int {};"); + ASSERT_EQ(Tokens.size(), 8u) << Tokens; + EXPECT_TOKEN(Tokens[2], tok::colon, TT_EnumUnderlyingTypeColon); + + Tokens = annotate("enum class B : int {};"); + ASSERT_EQ(Tokens.size(), 9u) << Tokens; + EXPECT_TOKEN(Tokens[3], tok::colon, TT_EnumUnderlyingTypeColon); + + Tokens = annotate("enum : int { E1 };"); + ASSERT_EQ(Tokens.size(), 8u) << Tokens; + EXPECT_TOKEN(Tokens[1], tok::colon, TT_EnumUnderlyingTypeColon); + + 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); + + Tokens = annotate("typedef enum A : int {} foo;"); + ASSERT_EQ(Tokens.size(), 10u) << Tokens; + EXPECT_TOKEN(Tokens[3], tok::colon, TT_EnumUnderlyingTypeColon); } TEST_F(TokenAnnotatorTest, BitFieldColon) {