Skip to content

Commit 0fba838

Browse files
authored
[clang-format] Introduce "ReflowComments: IndentOnly" to re-indent comments without breaking internal structure (think Doxygen). (#96804)
* Convert `ReflowComments` from boolean into a new `enum` which can take on the value `RCS_Never`, `RCS_IndentOnly`, or `RCS_Always`. The first one is equivalent to the old `false`, the third one is `true`, and the middle one means that multiline comments should only have their indentation corrected, which is what Doxygen users will want. * Preserve backward compatibility while parsing `ReflowComments`.
1 parent 1c28f31 commit 0fba838

File tree

11 files changed

+142
-46
lines changed

11 files changed

+142
-46
lines changed

clang/docs/ClangFormatStyleOptions.rst

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5406,22 +5406,46 @@ the configuration (without a prefix: ``Auto``).
54065406

54075407
.. _ReflowComments:
54085408

5409-
**ReflowComments** (``Boolean``) :versionbadge:`clang-format 3.8` :ref:`<ReflowComments>`
5410-
If ``true``, clang-format will attempt to re-flow comments. That is it
5411-
will touch a comment and *reflow* long comments into new lines, trying to
5412-
obey the ``ColumnLimit``.
5409+
**ReflowComments** (``ReflowCommentsStyle``) :versionbadge:`clang-format 3.8` :ref:`<ReflowComments>`
5410+
Comment reformatting style.
54135411

5414-
.. code-block:: c++
5412+
Possible values:
5413+
5414+
* ``RCS_Never`` (in configuration: ``Never``)
5415+
Leave comments untouched.
5416+
5417+
.. code-block:: c++
5418+
5419+
// veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information
5420+
/* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */
5421+
/* third veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information
5422+
* and a misaligned second line */
5423+
5424+
* ``RCS_IndentOnly`` (in configuration: ``IndentOnly``)
5425+
Only apply indentation rules, moving comments left or right, without
5426+
changing formatting inside the comments.
5427+
5428+
.. code-block:: c++
5429+
5430+
// veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information
5431+
/* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */
5432+
/* third veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information
5433+
* and a misaligned second line */
5434+
5435+
* ``RCS_Always`` (in configuration: ``Always``)
5436+
Apply indentation rules and reflow long comments into new lines, trying
5437+
to obey the ``ColumnLimit``.
5438+
5439+
.. code-block:: c++
5440+
5441+
// veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
5442+
// information
5443+
/* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
5444+
* information */
5445+
/* third veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
5446+
* information and a misaligned second line */
54155447
5416-
false:
5417-
// veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information
5418-
/* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */
54195448

5420-
true:
5421-
// veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
5422-
// information
5423-
/* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
5424-
* information */
54255449

54265450
.. _RemoveBracesLLVM:
54275451

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,8 @@ clang-format
663663
- Adds ``BreakBinaryOperations`` option.
664664
- Adds ``TemplateNames`` option.
665665
- Adds ``AlignFunctionDeclarations`` option to ``AlignConsecutiveDeclarations``.
666+
- Adds ``IndentOnly`` suboption to ``ReflowComments`` to fix the indentation of multi-line comments
667+
without touching their contents, renames ``false`` to ``Never``, and ``true`` to ``Always``.
666668

667669
libclang
668670
--------

clang/include/clang/Format/Format.h

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3847,24 +3847,43 @@ struct FormatStyle {
38473847
ReferenceAlignmentStyle ReferenceAlignment;
38483848

38493849
// clang-format off
3850-
/// If ``true``, clang-format will attempt to re-flow comments. That is it
3851-
/// will touch a comment and *reflow* long comments into new lines, trying to
3852-
/// obey the ``ColumnLimit``.
3853-
/// \code
3854-
/// false:
3855-
/// // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information
3856-
/// /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */
3857-
///
3858-
/// true:
3859-
/// // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
3860-
/// // information
3861-
/// /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
3862-
/// * information */
3863-
/// \endcode
3864-
/// \version 3.8
3865-
bool ReflowComments;
3850+
/// \brief Types of comment reflow style.
3851+
enum ReflowCommentsStyle : int8_t {
3852+
/// Leave comments untouched.
3853+
/// \code
3854+
/// // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information
3855+
/// /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */
3856+
/// /* third veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information
3857+
/// * and a misaligned second line */
3858+
/// \endcode
3859+
RCS_Never,
3860+
/// Only apply indentation rules, moving comments left or right, without
3861+
/// changing formatting inside the comments.
3862+
/// \code
3863+
/// // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information
3864+
/// /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */
3865+
/// /* third veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information
3866+
/// * and a misaligned second line */
3867+
/// \endcode
3868+
RCS_IndentOnly,
3869+
/// Apply indentation rules and reflow long comments into new lines, trying
3870+
/// to obey the ``ColumnLimit``.
3871+
/// \code
3872+
/// // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
3873+
/// // information
3874+
/// /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
3875+
/// * information */
3876+
/// /* third veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
3877+
/// * information and a misaligned second line */
3878+
/// \endcode
3879+
RCS_Always
3880+
};
38663881
// clang-format on
38673882

3883+
/// \brief Comment reformatting style.
3884+
/// \version 3.8
3885+
ReflowCommentsStyle ReflowComments;
3886+
38683887
/// Remove optional braces of control statements (``if``, ``else``, ``for``,
38693888
/// and ``while``) in C++ according to the LLVM coding style.
38703889
/// \warning

clang/lib/Format/BreakableToken.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ BreakableComment::getSplit(unsigned LineIndex, unsigned TailOffset,
420420
unsigned ColumnLimit, unsigned ContentStartColumn,
421421
const llvm::Regex &CommentPragmasRegex) const {
422422
// Don't break lines matching the comment pragmas regex.
423-
if (CommentPragmasRegex.match(Content[LineIndex]))
423+
if (!AlwaysReflow || CommentPragmasRegex.match(Content[LineIndex]))
424424
return Split(StringRef::npos, 0);
425425
return getCommentSplit(Content[LineIndex].substr(TailOffset),
426426
ContentStartColumn, ColumnLimit, Style.TabWidth,
@@ -608,7 +608,7 @@ BreakableToken::Split BreakableBlockComment::getSplit(
608608
unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit,
609609
unsigned ContentStartColumn, const llvm::Regex &CommentPragmasRegex) const {
610610
// Don't break lines matching the comment pragmas regex.
611-
if (CommentPragmasRegex.match(Content[LineIndex]))
611+
if (!AlwaysReflow || CommentPragmasRegex.match(Content[LineIndex]))
612612
return Split(StringRef::npos, 0);
613613
return getCommentSplit(Content[LineIndex].substr(TailOffset),
614614
ContentStartColumn, ColumnLimit, Style.TabWidth,
@@ -855,7 +855,8 @@ bool BreakableBlockComment::mayReflow(
855855
StringRef IndentContent = Content[LineIndex];
856856
if (Lines[LineIndex].ltrim(Blanks).starts_with("*"))
857857
IndentContent = Lines[LineIndex].ltrim(Blanks).substr(1);
858-
return LineIndex > 0 && !CommentPragmasRegex.match(IndentContent) &&
858+
return LineIndex > 0 && AlwaysReflow &&
859+
!CommentPragmasRegex.match(IndentContent) &&
859860
mayReflowContent(Content[LineIndex]) && !Tok.Finalized &&
860861
!switchesFormatting(tokenAt(LineIndex));
861862
}
@@ -1160,7 +1161,8 @@ bool BreakableLineCommentSection::mayReflow(
11601161
// // text that protrudes
11611162
// // into text with different indent
11621163
// We do reflow in that case in block comments.
1163-
return LineIndex > 0 && !CommentPragmasRegex.match(IndentContent) &&
1164+
return LineIndex > 0 && AlwaysReflow &&
1165+
!CommentPragmasRegex.match(IndentContent) &&
11641166
mayReflowContent(Content[LineIndex]) && !Tok.Finalized &&
11651167
!switchesFormatting(tokenAt(LineIndex)) &&
11661168
OriginalPrefix[LineIndex] == OriginalPrefix[LineIndex - 1];

clang/lib/Format/BreakableToken.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,8 @@ class BreakableComment : public BreakableToken {
384384
// The intended start column of the first line of text from this section.
385385
unsigned StartColumn;
386386

387+
const bool AlwaysReflow = Style.ReflowComments == FormatStyle::RCS_Always;
388+
387389
// The prefix to use in front a line that has been reflown up.
388390
// For example, when reflowing the second line after the first here:
389391
// // comment 1

clang/lib/Format/ContinuationIndenter.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2471,7 +2471,7 @@ ContinuationIndenter::createBreakableToken(const FormatToken &Current,
24712471
State.Line->InPPDirective, Encoding, Style);
24722472
}
24732473
} else if (Current.is(TT_BlockComment)) {
2474-
if (!Style.ReflowComments ||
2474+
if (Style.ReflowComments == FormatStyle::RCS_Never ||
24752475
// If a comment token switches formatting, like
24762476
// /* clang-format on */, we don't want to break it further,
24772477
// but we may still want to adjust its indentation.
@@ -2492,7 +2492,7 @@ ContinuationIndenter::createBreakableToken(const FormatToken &Current,
24922492
}
24932493
return true;
24942494
}();
2495-
if (!Style.ReflowComments ||
2495+
if (Style.ReflowComments == FormatStyle::RCS_Never ||
24962496
CommentPragmasRegex.match(Current.TokenText.substr(2)) ||
24972497
switchesFormatting(Current) || !RegularComments) {
24982498
return nullptr;

clang/lib/Format/Format.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,17 @@ template <> struct MappingTraits<FormatStyle::RawStringFormat> {
527527
}
528528
};
529529

530+
template <> struct ScalarEnumerationTraits<FormatStyle::ReflowCommentsStyle> {
531+
static void enumeration(IO &IO, FormatStyle::ReflowCommentsStyle &Value) {
532+
IO.enumCase(Value, "Never", FormatStyle::RCS_Never);
533+
IO.enumCase(Value, "IndentOnly", FormatStyle::RCS_IndentOnly);
534+
IO.enumCase(Value, "Always", FormatStyle::RCS_Always);
535+
// For backward compatibility:
536+
IO.enumCase(Value, "false", FormatStyle::RCS_Never);
537+
IO.enumCase(Value, "true", FormatStyle::RCS_Always);
538+
}
539+
};
540+
530541
template <>
531542
struct ScalarEnumerationTraits<FormatStyle::ReferenceAlignmentStyle> {
532543
static void enumeration(IO &IO, FormatStyle::ReferenceAlignmentStyle &Value) {
@@ -1569,7 +1580,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
15691580
LLVMStyle.PPIndentWidth = -1;
15701581
LLVMStyle.QualifierAlignment = FormatStyle::QAS_Leave;
15711582
LLVMStyle.ReferenceAlignment = FormatStyle::RAS_Pointer;
1572-
LLVMStyle.ReflowComments = true;
1583+
LLVMStyle.ReflowComments = FormatStyle::RCS_Always;
15731584
LLVMStyle.RemoveBracesLLVM = false;
15741585
LLVMStyle.RemoveParentheses = FormatStyle::RPS_Leave;
15751586
LLVMStyle.RemoveSemicolon = false;

clang/lib/Format/UnwrappedLineParser.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4623,9 +4623,9 @@ bool UnwrappedLineParser::isOnNewLine(const FormatToken &FormatTok) {
46234623
// section on \p Line.
46244624
static bool
46254625
continuesLineCommentSection(const FormatToken &FormatTok,
4626-
const UnwrappedLine &Line,
4626+
const UnwrappedLine &Line, const FormatStyle &Style,
46274627
const llvm::Regex &CommentPragmasRegex) {
4628-
if (Line.Tokens.empty())
4628+
if (Line.Tokens.empty() || Style.ReflowComments != FormatStyle::RCS_Always)
46294629
return false;
46304630

46314631
StringRef IndentContent = FormatTok.TokenText;
@@ -4738,7 +4738,7 @@ void UnwrappedLineParser::flushComments(bool NewlineBeforeNext) {
47384738
// FIXME: Consider putting separate line comment sections as children to the
47394739
// unwrapped line instead.
47404740
Tok->ContinuesLineCommentSection =
4741-
continuesLineCommentSection(*Tok, *Line, CommentPragmasRegex);
4741+
continuesLineCommentSection(*Tok, *Line, Style, CommentPragmasRegex);
47424742
if (isOnNewLine(*Tok) && JustComments && !Tok->ContinuesLineCommentSection)
47434743
addUnwrappedLine();
47444744
pushToken(Tok);
@@ -4811,8 +4811,8 @@ void UnwrappedLineParser::distributeComments(
48114811
if (HasTrailAlignedWithNextToken && i == StartOfTrailAlignedWithNextToken) {
48124812
FormatTok->ContinuesLineCommentSection = false;
48134813
} else {
4814-
FormatTok->ContinuesLineCommentSection =
4815-
continuesLineCommentSection(*FormatTok, *Line, CommentPragmasRegex);
4814+
FormatTok->ContinuesLineCommentSection = continuesLineCommentSection(
4815+
*FormatTok, *Line, Style, CommentPragmasRegex);
48164816
}
48174817
if (!FormatTok->ContinuesLineCommentSection &&
48184818
(isOnNewLine(*FormatTok) || FormatTok->IsFirst)) {

clang/unittests/Format/ConfigParseTest.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,6 @@ TEST(ConfigParseTest, ParsesConfigurationBools) {
183183
CHECK_PARSE_BOOL(ObjCSpaceAfterProperty);
184184
CHECK_PARSE_BOOL(ObjCSpaceBeforeProtocolList);
185185
CHECK_PARSE_BOOL(Cpp11BracedListStyle);
186-
CHECK_PARSE_BOOL(ReflowComments);
187186
CHECK_PARSE_BOOL(RemoveBracesLLVM);
188187
CHECK_PARSE_BOOL(RemoveSemicolon);
189188
CHECK_PARSE_BOOL(SkipMacroDefinitionBody);
@@ -381,6 +380,16 @@ TEST(ConfigParseTest, ParsesConfiguration) {
381380
CHECK_PARSE("PointerBindsToType: Middle", PointerAlignment,
382381
FormatStyle::PAS_Middle);
383382

383+
Style.ReflowComments = FormatStyle::RCS_Always;
384+
CHECK_PARSE("ReflowComments: Never", ReflowComments, FormatStyle::RCS_Never);
385+
CHECK_PARSE("ReflowComments: IndentOnly", ReflowComments,
386+
FormatStyle::RCS_IndentOnly);
387+
CHECK_PARSE("ReflowComments: Always", ReflowComments,
388+
FormatStyle::RCS_Always);
389+
// For backward compatibility:
390+
CHECK_PARSE("ReflowComments: false", ReflowComments, FormatStyle::RCS_Never);
391+
CHECK_PARSE("ReflowComments: true", ReflowComments, FormatStyle::RCS_Always);
392+
384393
Style.Standard = FormatStyle::LS_Auto;
385394
CHECK_PARSE("Standard: c++03", Standard, FormatStyle::LS_Cpp03);
386395
CHECK_PARSE("Standard: c++11", Standard, FormatStyle::LS_Cpp11);

clang/unittests/Format/FormatTest.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18108,7 +18108,7 @@ TEST_F(FormatTest, AlignConsecutiveMacros) {
1810818108

1810918109
// Test across comments
1811018110
Style.MaxEmptyLinesToKeep = 10;
18111-
Style.ReflowComments = false;
18111+
Style.ReflowComments = FormatStyle::RCS_Never;
1811218112
Style.AlignConsecutiveMacros.AcrossComments = true;
1811318113
verifyFormat("#define a 3\n"
1811418114
"// line comment\n"
@@ -18855,7 +18855,7 @@ TEST_F(FormatTest, AlignConsecutiveAssignmentsAcrossEmptyLinesAndComments) {
1885518855
"y = 1;",
1885618856
Alignment);
1885718857

18858-
Alignment.ReflowComments = true;
18858+
Alignment.ReflowComments = FormatStyle::RCS_Always;
1885918859
Alignment.ColumnLimit = 50;
1886018860
verifyFormat("int x = 0;\n"
1886118861
"int yy = 1; /// specificlennospace\n"
@@ -19253,7 +19253,7 @@ TEST_F(FormatTest, AlignConsecutiveAssignments) {
1925319253
"y = 1;",
1925419254
Alignment);
1925519255

19256-
EXPECT_EQ(Alignment.ReflowComments, true);
19256+
EXPECT_EQ(Alignment.ReflowComments, FormatStyle::RCS_Always);
1925719257
Alignment.ColumnLimit = 50;
1925819258
verifyFormat("int x = 0;\n"
1925919259
"int yy = 1; /// specificlennospace\n"

clang/unittests/Format/FormatTestComments.cpp

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -520,9 +520,36 @@ TEST_F(FormatTestComments, AlignsBlockComments) {
520520

521521
TEST_F(FormatTestComments, CommentReflowingCanBeTurnedOff) {
522522
FormatStyle Style = getLLVMStyleWithColumns(20);
523-
Style.ReflowComments = false;
523+
Style.ReflowComments = FormatStyle::RCS_Never;
524524
verifyFormat("// aaaaaaaaa aaaaaaaaaa aaaaaaaaaa", Style);
525525
verifyFormat("/* aaaaaaaaa aaaaaaaaaa aaaaaaaaaa */", Style);
526+
verifyNoChange("/* aaaaaaaaa aaaaaaaaaa aaaaaaaaaa\n"
527+
"aaaaaaaaa*/",
528+
Style);
529+
verifyNoChange("/* aaaaaaaaa aaaaaaaaaa aaaaaaaaaa\n"
530+
" aaaaaaaaa*/",
531+
Style);
532+
verifyNoChange("/* aaaaaaaaa aaaaaaaaaa aaaaaaaaaa\n"
533+
" * aaaaaaaaa*/",
534+
Style);
535+
}
536+
537+
TEST_F(FormatTestComments, CommentReflowingCanApplyOnlyToIndents) {
538+
FormatStyle Style = getLLVMStyleWithColumns(20);
539+
Style.ReflowComments = FormatStyle::RCS_IndentOnly;
540+
verifyFormat("// aaaaaaaaa aaaaaaaaaa aaaaaaaaaa", Style);
541+
verifyFormat("/* aaaaaaaaa aaaaaaaaaa aaaaaaaaaa */", Style);
542+
verifyNoChange("/* aaaaaaaaa aaaaaaaaaa aaaaaaaaaa\n"
543+
"aaaaaaaaa*/",
544+
Style);
545+
verifyNoChange("/* aaaaaaaaa aaaaaaaaaa aaaaaaaaaa\n"
546+
" aaaaaaaaa*/",
547+
Style);
548+
verifyFormat("/* aaaaaaaaa aaaaaaaaaa aaaaaaaaaa\n"
549+
" * aaaaaaaaa*/",
550+
"/* aaaaaaaaa aaaaaaaaaa aaaaaaaaaa\n"
551+
" * aaaaaaaaa*/",
552+
Style);
526553
}
527554

528555
TEST_F(FormatTestComments, CorrectlyHandlesLengthOfBlockComments) {

0 commit comments

Comments
 (0)