https://github.com/frank-suwen updated https://github.com/llvm/llvm-project/pull/204727
>From d2039b6757185d86f47e8185776eb332141fd887 Mon Sep 17 00:00:00 2001 From: frank-suwen <[email protected]> Date: Thu, 18 Jun 2026 21:49:51 -0700 Subject: [PATCH 1/2] [clang-format] Add SpacesInComments option for block comments --- clang/include/clang/Format/Format.h | 25 +++++++++++ clang/lib/Format/BreakableToken.cpp | 42 +++++++++++++++++++ clang/lib/Format/Format.cpp | 10 +++++ clang/unittests/Format/FormatTestComments.cpp | 34 +++++++++++++++ 4 files changed, 111 insertions(+) diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 27b2d8f4a405b..10b546506684d 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -5590,6 +5590,30 @@ struct FormatStyle { /// \version 3.4 SpacesInAnglesStyle SpacesInAngles; + /// Styles for controlling spacing after ``/*`` and before ``*/`` in block + /// comments. + enum SpacesInCommentsStyle : int8_t { + /// Remove spaces after ``/*`` and before ``*/``. + /// \code + /// /*comment*/ + /// \endcode + SICS_Never, + /// Add spaces after ``/*`` and before ``*/``. + /// \code + /// /* comment */ + /// \endcode + SICS_Always, + /// Leave existing spaces unchanged. + SICS_Leave + }; + + /// The SpacesInCommentsStyle to use for single-line ordinary block comments. + /// Documentation comments such as ``/** ... */`` and ``/*! ... */`` and + /// parameter comments ending with ``=`` before the closing ``*/`` are left + /// unchanged. + /// \version 23 + SpacesInCommentsStyle SpacesInComments; + /// If ``true``, spaces will be inserted around if/for/switch/while /// conditions. /// This option is **deprecated**. See ``InConditionalStatements`` of @@ -6241,6 +6265,7 @@ struct FormatStyle { SpaceInEmptyBraces == R.SpaceInEmptyBraces && SpacesBeforeTrailingComments == R.SpacesBeforeTrailingComments && SpacesInAngles == R.SpacesInAngles && + SpacesInComments == R.SpacesInComments && SpacesInContainerLiterals == R.SpacesInContainerLiterals && SpacesInLineCommentPrefix.Minimum == R.SpacesInLineCommentPrefix.Minimum && diff --git a/clang/lib/Format/BreakableToken.cpp b/clang/lib/Format/BreakableToken.cpp index 9571a64797a2d..aaca54a010f4a 100644 --- a/clang/lib/Format/BreakableToken.cpp +++ b/clang/lib/Format/BreakableToken.cpp @@ -778,6 +778,48 @@ void BreakableBlockComment::reflow(unsigned LineIndex, void BreakableBlockComment::adaptStartOfLine( unsigned LineIndex, WhitespaceManager &Whitespaces) const { if (LineIndex == 0) { + StringRef Text = tokenAt(LineIndex).TokenText; + if (Style.SpacesInComments != FormatStyle::SICS_Leave && + Lines.size() == 1 && Text.size() >= 4) { + const bool IsDocComment = + Text.starts_with("/**") || Text.starts_with("/*!"); + const bool IsParamComment = Text.drop_back(2).trim(Blanks).ends_with("="); + if (!IsDocComment && !IsParamComment) { + StringRef AfterOpening = Text.drop_front(2); + if (!AfterOpening.empty()) { + const bool HasSpace = isWhitespace(AfterOpening.front()); + if (Style.SpacesInComments == FormatStyle::SICS_Always && !HasSpace) { + Whitespaces.replaceWhitespaceInToken( + tokenAt(LineIndex), /*Offset=*/2, /*ReplaceChars=*/0, + /*PreviousPostfix=*/"", /*CurrentPrefix=*/"", InPPDirective, + /*Newlines=*/0, /*Spaces=*/1); + } else if (Style.SpacesInComments == FormatStyle::SICS_Never && + HasSpace) { + Whitespaces.replaceWhitespaceInToken( + tokenAt(LineIndex), /*Offset=*/2, /*ReplaceChars=*/1, + /*PreviousPostfix=*/"", /*CurrentPrefix=*/"", InPPDirective, + /*Newlines=*/0, /*Spaces=*/0); + } + } + + StringRef BeforeClosing = Text.drop_back(2); + if (!BeforeClosing.empty()) { + const bool HasSpace = isWhitespace(BeforeClosing.back()); + if (Style.SpacesInComments == FormatStyle::SICS_Always && !HasSpace) { + Whitespaces.replaceWhitespaceInToken( + tokenAt(LineIndex), Text.size() - 2, /*ReplaceChars=*/0, + /*PreviousPostfix=*/"", /*CurrentPrefix=*/"", InPPDirective, + /*Newlines=*/0, /*Spaces=*/1); + } else if (Style.SpacesInComments == FormatStyle::SICS_Never && + HasSpace) { + Whitespaces.replaceWhitespaceInToken( + tokenAt(LineIndex), Text.size() - 3, /*ReplaceChars=*/1, + /*PreviousPostfix=*/"", /*CurrentPrefix=*/"", InPPDirective, + /*Newlines=*/0, /*Spaces=*/0); + } + } + } + } if (DelimitersOnNewline) { // Since we're breaking at index 1 below, the break position and the // break length are the same. diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index a29d62c99bb95..a8801f5b5de8e 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -962,6 +962,14 @@ template <> struct ScalarEnumerationTraits<FormatStyle::SpacesInAnglesStyle> { } }; +template <> struct ScalarEnumerationTraits<FormatStyle::SpacesInCommentsStyle> { + static void enumeration(IO &IO, FormatStyle::SpacesInCommentsStyle &Value) { + IO.enumCase(Value, "Never", FormatStyle::SICS_Never); + IO.enumCase(Value, "Always", FormatStyle::SICS_Always); + IO.enumCase(Value, "Leave", FormatStyle::SICS_Leave); + } +}; + template <> struct MappingTraits<FormatStyle::SpacesInLineComment> { static void mapping(IO &IO, FormatStyle::SpacesInLineComment &Space) { // Transform the maximum to signed, to parse "-1" correctly @@ -1495,6 +1503,7 @@ template <> struct MappingTraits<FormatStyle> { IO.mapOptional("SpacesBeforeTrailingComments", Style.SpacesBeforeTrailingComments); IO.mapOptional("SpacesInAngles", Style.SpacesInAngles); + IO.mapOptional("SpacesInComments", Style.SpacesInComments); IO.mapOptional("SpacesInContainerLiterals", Style.SpacesInContainerLiterals); IO.mapOptional("SpacesInLineCommentPrefix", @@ -2019,6 +2028,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.SpaceInEmptyBraces = FormatStyle::SIEB_Never; LLVMStyle.SpacesBeforeTrailingComments = 1; LLVMStyle.SpacesInAngles = FormatStyle::SIAS_Never; + LLVMStyle.SpacesInComments = FormatStyle::SICS_Leave; LLVMStyle.SpacesInContainerLiterals = true; LLVMStyle.SpacesInLineCommentPrefix = { /*Minimum=*/1, /*Maximum=*/std::numeric_limits<unsigned>::max()}; diff --git a/clang/unittests/Format/FormatTestComments.cpp b/clang/unittests/Format/FormatTestComments.cpp index 707016096f7d2..6d10831124079 100644 --- a/clang/unittests/Format/FormatTestComments.cpp +++ b/clang/unittests/Format/FormatTestComments.cpp @@ -370,6 +370,40 @@ TEST_F(FormatTestComments, RemovesTrailingWhitespaceOfComments) { verifyFormat("// comment \\\n", "// comment \\\n \t \v \f "); } +TEST_F(FormatTestComments, SpacesInBlockComments) { + FormatStyle Style = getLLVMStyle(); + + Style.SpacesInComments = FormatStyle::SICS_Always; + verifyFormat("/* comment */", "/* comment*/", Style); + verifyFormat("/* comment */", "/*comment */", Style); + verifyFormat("/* comment */", "/*comment*/", Style); + + Style.SpacesInComments = FormatStyle::SICS_Leave; + verifyFormat("/*comment*/", Style); + verifyFormat("/* comment*/", Style); + verifyFormat("/*comment */", Style); + verifyFormat("/* comment */", Style); + + Style.SpacesInComments = FormatStyle::SICS_Never; + verifyFormat("/*comment*/", "/* comment */", Style); + verifyFormat("/*comment*/", "/* comment*/", Style); + verifyFormat("/*comment*/", "/*comment */", Style); +} + +TEST_F(FormatTestComments, SpacesInBlockCommentsIgnoreParamAndDocComments) { + FormatStyle Style = getLLVMStyle(); + + Style.SpacesInComments = FormatStyle::SICS_Always; + verifyFormat("foo(/*Arg=*/value);", Style); + verifyFormat("/**doc*/", Style); + verifyFormat("/*!doc*/", Style); + + Style.SpacesInComments = FormatStyle::SICS_Never; + verifyFormat("foo(/*Arg=*/value);", Style); + verifyFormat("/** doc */", Style); + verifyFormat("/*! doc */", Style); +} + TEST_F(FormatTestComments, UnderstandsBlockComments) { verifyFormat("f(/*noSpaceAfterParameterNamingComment=*/true);"); verifyFormat("void f() { g(/*aaa=*/x, /*bbb=*/!y, /*c=*/::c); }"); >From 41c0489a1d83b88df76609f077fa0845a6fa13b4 Mon Sep 17 00:00:00 2001 From: frank-suwen <[email protected]> Date: Mon, 29 Jun 2026 21:56:57 -0700 Subject: [PATCH 2/2] Address review feedback for SpacesInBlockComments --- clang/docs/ClangFormatStyleOptions.rst | 29 +++++++++++++++++++ clang/include/clang/Format/Format.h | 20 ++++++------- clang/lib/Format/BreakableToken.cpp | 20 +++++++------ clang/lib/Format/Format.cpp | 16 +++++----- clang/unittests/Format/ConfigParseTest.cpp | 8 +++++ clang/unittests/Format/FormatTestComments.cpp | 10 +++---- 6 files changed, 72 insertions(+), 31 deletions(-) diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index 7b1b7a7384b07..7cb98f1e8f62f 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -7393,6 +7393,35 @@ the configuration (without a prefix: ``Auto``). +.. _SpacesInBlockComments: + +**SpacesInBlockComments** (``SpacesInBlockCommentsStyle``) :versionbadge:`clang-format 23` :ref:`¶ <SpacesInBlockComments>` + The SpacesInBlockCommentsStyle to use for single-line ordinary block + comments. Documentation comments such as ``/** ... */`` and ``/*! ... */`` + and parameter comments ending with ``=`` before the closing ``*/`` are + left unchanged. + + Possible values: + + * ``SIBCS_Never`` (in configuration: ``Never``) + Remove spaces after ``/*`` and before ``*/``. + + .. code-block:: c++ + + /*comment*/ + + * ``SIBCS_Always`` (in configuration: ``Always``) + Add spaces after ``/*`` and before ``*/``. + + .. code-block:: c++ + + /* comment */ + + * ``SIBCS_Leave`` (in configuration: ``Leave``) + Leave existing spaces unchanged. + + + .. _SpacesInCStyleCastParentheses: **SpacesInCStyleCastParentheses** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`¶ <SpacesInCStyleCastParentheses>` diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 10b546506684d..28824fd6b1bd2 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -5592,27 +5592,27 @@ struct FormatStyle { /// Styles for controlling spacing after ``/*`` and before ``*/`` in block /// comments. - enum SpacesInCommentsStyle : int8_t { + enum SpacesInBlockCommentsStyle : int8_t { /// Remove spaces after ``/*`` and before ``*/``. /// \code /// /*comment*/ /// \endcode - SICS_Never, + SIBCS_Never, /// Add spaces after ``/*`` and before ``*/``. /// \code /// /* comment */ /// \endcode - SICS_Always, + SIBCS_Always, /// Leave existing spaces unchanged. - SICS_Leave + SIBCS_Leave }; - /// The SpacesInCommentsStyle to use for single-line ordinary block comments. - /// Documentation comments such as ``/** ... */`` and ``/*! ... */`` and - /// parameter comments ending with ``=`` before the closing ``*/`` are left - /// unchanged. + /// The SpacesInBlockCommentsStyle to use for single-line ordinary block + /// comments. Documentation comments such as ``/** ... */`` and ``/*! ... */`` + /// and parameter comments ending with ``=`` before the closing ``*/`` are + /// left unchanged. /// \version 23 - SpacesInCommentsStyle SpacesInComments; + SpacesInBlockCommentsStyle SpacesInBlockComments; /// If ``true``, spaces will be inserted around if/for/switch/while /// conditions. @@ -6265,7 +6265,7 @@ struct FormatStyle { SpaceInEmptyBraces == R.SpaceInEmptyBraces && SpacesBeforeTrailingComments == R.SpacesBeforeTrailingComments && SpacesInAngles == R.SpacesInAngles && - SpacesInComments == R.SpacesInComments && + SpacesInBlockComments == R.SpacesInBlockComments && SpacesInContainerLiterals == R.SpacesInContainerLiterals && SpacesInLineCommentPrefix.Minimum == R.SpacesInLineCommentPrefix.Minimum && diff --git a/clang/lib/Format/BreakableToken.cpp b/clang/lib/Format/BreakableToken.cpp index aaca54a010f4a..a2a027dd1635c 100644 --- a/clang/lib/Format/BreakableToken.cpp +++ b/clang/lib/Format/BreakableToken.cpp @@ -779,21 +779,22 @@ void BreakableBlockComment::adaptStartOfLine( unsigned LineIndex, WhitespaceManager &Whitespaces) const { if (LineIndex == 0) { StringRef Text = tokenAt(LineIndex).TokenText; - if (Style.SpacesInComments != FormatStyle::SICS_Leave && + if (Style.SpacesInBlockComments != FormatStyle::SIBCS_Leave && Lines.size() == 1 && Text.size() >= 4) { const bool IsDocComment = Text.starts_with("/**") || Text.starts_with("/*!"); const bool IsParamComment = Text.drop_back(2).trim(Blanks).ends_with("="); if (!IsDocComment && !IsParamComment) { - StringRef AfterOpening = Text.drop_front(2); - if (!AfterOpening.empty()) { + if (StringRef AfterOpening = Text.drop_front(2); + !AfterOpening.empty()) { const bool HasSpace = isWhitespace(AfterOpening.front()); - if (Style.SpacesInComments == FormatStyle::SICS_Always && !HasSpace) { + if (Style.SpacesInBlockComments == FormatStyle::SIBCS_Always && + !HasSpace) { Whitespaces.replaceWhitespaceInToken( tokenAt(LineIndex), /*Offset=*/2, /*ReplaceChars=*/0, /*PreviousPostfix=*/"", /*CurrentPrefix=*/"", InPPDirective, /*Newlines=*/0, /*Spaces=*/1); - } else if (Style.SpacesInComments == FormatStyle::SICS_Never && + } else if (Style.SpacesInBlockComments == FormatStyle::SIBCS_Never && HasSpace) { Whitespaces.replaceWhitespaceInToken( tokenAt(LineIndex), /*Offset=*/2, /*ReplaceChars=*/1, @@ -802,15 +803,16 @@ void BreakableBlockComment::adaptStartOfLine( } } - StringRef BeforeClosing = Text.drop_back(2); - if (!BeforeClosing.empty()) { + if (StringRef BeforeClosing = Text.drop_back(2); + !BeforeClosing.empty()) { const bool HasSpace = isWhitespace(BeforeClosing.back()); - if (Style.SpacesInComments == FormatStyle::SICS_Always && !HasSpace) { + if (Style.SpacesInBlockComments == FormatStyle::SIBCS_Always && + !HasSpace) { Whitespaces.replaceWhitespaceInToken( tokenAt(LineIndex), Text.size() - 2, /*ReplaceChars=*/0, /*PreviousPostfix=*/"", /*CurrentPrefix=*/"", InPPDirective, /*Newlines=*/0, /*Spaces=*/1); - } else if (Style.SpacesInComments == FormatStyle::SICS_Never && + } else if (Style.SpacesInBlockComments == FormatStyle::SIBCS_Never && HasSpace) { Whitespaces.replaceWhitespaceInToken( tokenAt(LineIndex), Text.size() - 3, /*ReplaceChars=*/1, diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index a8801f5b5de8e..a8ea7545f1db9 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -962,11 +962,13 @@ template <> struct ScalarEnumerationTraits<FormatStyle::SpacesInAnglesStyle> { } }; -template <> struct ScalarEnumerationTraits<FormatStyle::SpacesInCommentsStyle> { - static void enumeration(IO &IO, FormatStyle::SpacesInCommentsStyle &Value) { - IO.enumCase(Value, "Never", FormatStyle::SICS_Never); - IO.enumCase(Value, "Always", FormatStyle::SICS_Always); - IO.enumCase(Value, "Leave", FormatStyle::SICS_Leave); +template <> +struct ScalarEnumerationTraits<FormatStyle::SpacesInBlockCommentsStyle> { + static void enumeration(IO &IO, + FormatStyle::SpacesInBlockCommentsStyle &Value) { + IO.enumCase(Value, "Never", FormatStyle::SIBCS_Never); + IO.enumCase(Value, "Always", FormatStyle::SIBCS_Always); + IO.enumCase(Value, "Leave", FormatStyle::SIBCS_Leave); } }; @@ -1503,7 +1505,7 @@ template <> struct MappingTraits<FormatStyle> { IO.mapOptional("SpacesBeforeTrailingComments", Style.SpacesBeforeTrailingComments); IO.mapOptional("SpacesInAngles", Style.SpacesInAngles); - IO.mapOptional("SpacesInComments", Style.SpacesInComments); + IO.mapOptional("SpacesInBlockComments", Style.SpacesInBlockComments); IO.mapOptional("SpacesInContainerLiterals", Style.SpacesInContainerLiterals); IO.mapOptional("SpacesInLineCommentPrefix", @@ -2028,7 +2030,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.SpaceInEmptyBraces = FormatStyle::SIEB_Never; LLVMStyle.SpacesBeforeTrailingComments = 1; LLVMStyle.SpacesInAngles = FormatStyle::SIAS_Never; - LLVMStyle.SpacesInComments = FormatStyle::SICS_Leave; + LLVMStyle.SpacesInBlockComments = FormatStyle::SIBCS_Leave; LLVMStyle.SpacesInContainerLiterals = true; LLVMStyle.SpacesInLineCommentPrefix = { /*Minimum=*/1, /*Maximum=*/std::numeric_limits<unsigned>::max()}; diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp index eeaf5d3f66d96..6ca520c75f687 100644 --- a/clang/unittests/Format/ConfigParseTest.cpp +++ b/clang/unittests/Format/ConfigParseTest.cpp @@ -1227,6 +1227,14 @@ TEST(ConfigParseTest, ParsesConfiguration) { CHECK_PARSE("SpacesInAngles: false", SpacesInAngles, FormatStyle::SIAS_Never); CHECK_PARSE("SpacesInAngles: true", SpacesInAngles, FormatStyle::SIAS_Always); + Style.SpacesInBlockComments = FormatStyle::SIBCS_Always; + CHECK_PARSE("SpacesInBlockComments: Never", SpacesInBlockComments, + FormatStyle::SIBCS_Never); + CHECK_PARSE("SpacesInBlockComments: Always", SpacesInBlockComments, + FormatStyle::SIBCS_Always); + CHECK_PARSE("SpacesInBlockComments: Leave", SpacesInBlockComments, + FormatStyle::SIBCS_Leave); + CHECK_PARSE("RequiresClausePosition: WithPreceding", RequiresClausePosition, FormatStyle::RCPS_WithPreceding); CHECK_PARSE("RequiresClausePosition: WithFollowing", RequiresClausePosition, diff --git a/clang/unittests/Format/FormatTestComments.cpp b/clang/unittests/Format/FormatTestComments.cpp index 6d10831124079..49f2a3bd89bf8 100644 --- a/clang/unittests/Format/FormatTestComments.cpp +++ b/clang/unittests/Format/FormatTestComments.cpp @@ -373,18 +373,18 @@ TEST_F(FormatTestComments, RemovesTrailingWhitespaceOfComments) { TEST_F(FormatTestComments, SpacesInBlockComments) { FormatStyle Style = getLLVMStyle(); - Style.SpacesInComments = FormatStyle::SICS_Always; + Style.SpacesInBlockComments = FormatStyle::SIBCS_Always; verifyFormat("/* comment */", "/* comment*/", Style); verifyFormat("/* comment */", "/*comment */", Style); verifyFormat("/* comment */", "/*comment*/", Style); - Style.SpacesInComments = FormatStyle::SICS_Leave; + Style.SpacesInBlockComments = FormatStyle::SIBCS_Leave; verifyFormat("/*comment*/", Style); verifyFormat("/* comment*/", Style); verifyFormat("/*comment */", Style); verifyFormat("/* comment */", Style); - Style.SpacesInComments = FormatStyle::SICS_Never; + Style.SpacesInBlockComments = FormatStyle::SIBCS_Never; verifyFormat("/*comment*/", "/* comment */", Style); verifyFormat("/*comment*/", "/* comment*/", Style); verifyFormat("/*comment*/", "/*comment */", Style); @@ -393,12 +393,12 @@ TEST_F(FormatTestComments, SpacesInBlockComments) { TEST_F(FormatTestComments, SpacesInBlockCommentsIgnoreParamAndDocComments) { FormatStyle Style = getLLVMStyle(); - Style.SpacesInComments = FormatStyle::SICS_Always; + Style.SpacesInBlockComments = FormatStyle::SIBCS_Always; verifyFormat("foo(/*Arg=*/value);", Style); verifyFormat("/**doc*/", Style); verifyFormat("/*!doc*/", Style); - Style.SpacesInComments = FormatStyle::SICS_Never; + Style.SpacesInBlockComments = FormatStyle::SIBCS_Never; verifyFormat("foo(/*Arg=*/value);", Style); verifyFormat("/** doc */", Style); verifyFormat("/*! doc */", Style); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
