Skip to content

Commit 18f08a4

Browse files
ichaerc00136
authored andcommitted
[clang-format] Introduce "ReflowComments: IndentOnly" to re-indent comments without breaking internal structure (think Doxygen). (llvm#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 e21dc4b commit 18f08a4

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
@@ -5232,22 +5232,46 @@ the configuration (without a prefix: ``Auto``).
52325232

52335233
.. _ReflowComments:
52345234

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

5240-
.. code-block:: c++
5238+
Possible values:
5239+
5240+
* ``RCS_Never`` (in configuration: ``Never``)
5241+
Leave comments untouched.
5242+
5243+
.. code-block:: c++
5244+
5245+
// veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information
5246+
/* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */
5247+
/* third veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information
5248+
* and a misaligned second line */
5249+
5250+
* ``RCS_IndentOnly`` (in configuration: ``IndentOnly``)
5251+
Only apply indentation rules, moving comments left or right, without
5252+
changing formatting inside the comments.
5253+
5254+
.. code-block:: c++
5255+
5256+
// veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information
5257+
/* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */
5258+
/* third veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information
5259+
* and a misaligned second line */
5260+
5261+
* ``RCS_Always`` (in configuration: ``Always``)
5262+
Apply indentation rules and reflow long comments into new lines, trying
5263+
to obey the ``ColumnLimit``.
5264+
5265+
.. code-block:: c++
5266+
5267+
// veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
5268+
// information
5269+
/* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
5270+
* information */
5271+
/* third veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
5272+
* information and a misaligned second line */
52415273
5242-
false:
5243-
// veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information
5244-
/* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */
52455274

5246-
true:
5247-
// veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
5248-
// information
5249-
/* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
5250-
* information */
52515275

52525276
.. _RemoveBracesLLVM:
52535277

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1376,6 +1376,8 @@ clang-format
13761376
- Add ``ExceptDoubleParentheses`` sub-option for ``SpacesInParensOptions``
13771377
to override addition of spaces between multiple, non-redundant parentheses
13781378
similar to the rules used for ``RemoveParentheses``.
1379+
- Adds ``IndentOnly`` suboption to ``ReflowComments`` to fix the indentation of multi-line comments
1380+
without touching their contents, renames ``false`` to ``Never``, and ``true`` to ``Always``.
13791381

13801382
libclang
13811383
--------

clang/include/clang/Format/Format.h

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

37813781
// clang-format off
3782-
/// If ``true``, clang-format will attempt to re-flow comments. That is it
3783-
/// will touch a comment and *reflow* long comments into new lines, trying to
3784-
/// obey the ``ColumnLimit``.
3785-
/// \code
3786-
/// false:
3787-
/// // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information
3788-
/// /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */
3789-
///
3790-
/// true:
3791-
/// // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
3792-
/// // information
3793-
/// /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
3794-
/// * information */
3795-
/// \endcode
3796-
/// \version 3.8
3797-
bool ReflowComments;
3782+
/// \brief Types of comment reflow style.
3783+
enum ReflowCommentsStyle : int8_t {
3784+
/// Leave comments untouched.
3785+
/// \code
3786+
/// // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information
3787+
/// /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */
3788+
/// /* third veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information
3789+
/// * and a misaligned second line */
3790+
/// \endcode
3791+
RCS_Never,
3792+
/// Only apply indentation rules, moving comments left or right, without
3793+
/// changing formatting inside the comments.
3794+
/// \code
3795+
/// // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information
3796+
/// /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */
3797+
/// /* third veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information
3798+
/// * and a misaligned second line */
3799+
/// \endcode
3800+
RCS_IndentOnly,
3801+
/// Apply indentation rules and reflow long comments into new lines, trying
3802+
/// to obey the ``ColumnLimit``.
3803+
/// \code
3804+
/// // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
3805+
/// // information
3806+
/// /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
3807+
/// * information */
3808+
/// /* third veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
3809+
/// * information and a misaligned second line */
3810+
/// \endcode
3811+
RCS_Always
3812+
};
37983813
// clang-format on
37993814

3815+
/// \brief Comment reformatting style.
3816+
/// \version 3.8
3817+
ReflowCommentsStyle ReflowComments;
3818+
38003819
/// Remove optional braces of control statements (``if``, ``else``, ``for``,
38013820
/// and ``while``) in C++ according to the LLVM coding style.
38023821
/// \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
@@ -2398,7 +2398,7 @@ ContinuationIndenter::createBreakableToken(const FormatToken &Current,
23982398
State.Line->InPPDirective, Encoding, Style);
23992399
}
24002400
} else if (Current.is(TT_BlockComment)) {
2401-
if (!Style.ReflowComments ||
2401+
if (Style.ReflowComments == FormatStyle::RCS_Never ||
24022402
// If a comment token switches formatting, like
24032403
// /* clang-format on */, we don't want to break it further,
24042404
// but we may still want to adjust its indentation.
@@ -2419,7 +2419,7 @@ ContinuationIndenter::createBreakableToken(const FormatToken &Current,
24192419
}
24202420
return true;
24212421
}();
2422-
if (!Style.ReflowComments ||
2422+
if (Style.ReflowComments == FormatStyle::RCS_Never ||
24232423
CommentPragmasRegex.match(Current.TokenText.substr(2)) ||
24242424
switchesFormatting(Current) || !RegularComments) {
24252425
return nullptr;

clang/lib/Format/Format.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,17 @@ template <> struct MappingTraits<FormatStyle::RawStringFormat> {
505505
}
506506
};
507507

508+
template <> struct ScalarEnumerationTraits<FormatStyle::ReflowCommentsStyle> {
509+
static void enumeration(IO &IO, FormatStyle::ReflowCommentsStyle &Value) {
510+
IO.enumCase(Value, "Never", FormatStyle::RCS_Never);
511+
IO.enumCase(Value, "IndentOnly", FormatStyle::RCS_IndentOnly);
512+
IO.enumCase(Value, "Always", FormatStyle::RCS_Always);
513+
// For backward compatibility:
514+
IO.enumCase(Value, "false", FormatStyle::RCS_Never);
515+
IO.enumCase(Value, "true", FormatStyle::RCS_Always);
516+
}
517+
};
518+
508519
template <>
509520
struct ScalarEnumerationTraits<FormatStyle::ReferenceAlignmentStyle> {
510521
static void enumeration(IO &IO, FormatStyle::ReferenceAlignmentStyle &Value) {
@@ -1547,7 +1558,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
15471558
LLVMStyle.PPIndentWidth = -1;
15481559
LLVMStyle.QualifierAlignment = FormatStyle::QAS_Leave;
15491560
LLVMStyle.ReferenceAlignment = FormatStyle::RAS_Pointer;
1550-
LLVMStyle.ReflowComments = true;
1561+
LLVMStyle.ReflowComments = FormatStyle::RCS_Always;
15511562
LLVMStyle.RemoveBracesLLVM = false;
15521563
LLVMStyle.RemoveParentheses = FormatStyle::RPS_Leave;
15531564
LLVMStyle.RemoveSemicolon = false;

clang/lib/Format/UnwrappedLineParser.cpp

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

46264626
StringRef IndentContent = FormatTok.TokenText;
@@ -4733,7 +4733,7 @@ void UnwrappedLineParser::flushComments(bool NewlineBeforeNext) {
47334733
// FIXME: Consider putting separate line comment sections as children to the
47344734
// unwrapped line instead.
47354735
Tok->ContinuesLineCommentSection =
4736-
continuesLineCommentSection(*Tok, *Line, CommentPragmasRegex);
4736+
continuesLineCommentSection(*Tok, *Line, Style, CommentPragmasRegex);
47374737
if (isOnNewLine(*Tok) && JustComments && !Tok->ContinuesLineCommentSection)
47384738
addUnwrappedLine();
47394739
pushToken(Tok);
@@ -4806,8 +4806,8 @@ void UnwrappedLineParser::distributeComments(
48064806
if (HasTrailAlignedWithNextToken && i == StartOfTrailAlignedWithNextToken) {
48074807
FormatTok->ContinuesLineCommentSection = false;
48084808
} else {
4809-
FormatTok->ContinuesLineCommentSection =
4810-
continuesLineCommentSection(*FormatTok, *Line, CommentPragmasRegex);
4809+
FormatTok->ContinuesLineCommentSection = continuesLineCommentSection(
4810+
*FormatTok, *Line, Style, CommentPragmasRegex);
48114811
}
48124812
if (!FormatTok->ContinuesLineCommentSection &&
48134813
(isOnNewLine(*FormatTok) || FormatTok->IsFirst)) {

clang/unittests/Format/ConfigParseTest.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,6 @@ TEST(ConfigParseTest, ParsesConfigurationBools) {
184184
CHECK_PARSE_BOOL(ObjCSpaceAfterProperty);
185185
CHECK_PARSE_BOOL(ObjCSpaceBeforeProtocolList);
186186
CHECK_PARSE_BOOL(Cpp11BracedListStyle);
187-
CHECK_PARSE_BOOL(ReflowComments);
188187
CHECK_PARSE_BOOL(RemoveBracesLLVM);
189188
CHECK_PARSE_BOOL(RemoveSemicolon);
190189
CHECK_PARSE_BOOL(SkipMacroDefinitionBody);
@@ -377,6 +376,16 @@ TEST(ConfigParseTest, ParsesConfiguration) {
377376
CHECK_PARSE("PointerBindsToType: Middle", PointerAlignment,
378377
FormatStyle::PAS_Middle);
379378

379+
Style.ReflowComments = FormatStyle::RCS_Always;
380+
CHECK_PARSE("ReflowComments: Never", ReflowComments, FormatStyle::RCS_Never);
381+
CHECK_PARSE("ReflowComments: IndentOnly", ReflowComments,
382+
FormatStyle::RCS_IndentOnly);
383+
CHECK_PARSE("ReflowComments: Always", ReflowComments,
384+
FormatStyle::RCS_Always);
385+
// For backward compatibility:
386+
CHECK_PARSE("ReflowComments: false", ReflowComments, FormatStyle::RCS_Never);
387+
CHECK_PARSE("ReflowComments: true", ReflowComments, FormatStyle::RCS_Always);
388+
380389
Style.Standard = FormatStyle::LS_Auto;
381390
CHECK_PARSE("Standard: c++03", Standard, FormatStyle::LS_Cpp03);
382391
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
@@ -17966,7 +17966,7 @@ TEST_F(FormatTest, AlignConsecutiveMacros) {
1796617966

1796717967
// Test across comments
1796817968
Style.MaxEmptyLinesToKeep = 10;
17969-
Style.ReflowComments = false;
17969+
Style.ReflowComments = FormatStyle::RCS_Never;
1797017970
Style.AlignConsecutiveMacros.AcrossComments = true;
1797117971
verifyFormat("#define a 3\n"
1797217972
"// line comment\n"
@@ -18713,7 +18713,7 @@ TEST_F(FormatTest, AlignConsecutiveAssignmentsAcrossEmptyLinesAndComments) {
1871318713
"y = 1;",
1871418714
Alignment);
1871518715

18716-
Alignment.ReflowComments = true;
18716+
Alignment.ReflowComments = FormatStyle::RCS_Always;
1871718717
Alignment.ColumnLimit = 50;
1871818718
verifyFormat("int x = 0;\n"
1871918719
"int yy = 1; /// specificlennospace\n"
@@ -19111,7 +19111,7 @@ TEST_F(FormatTest, AlignConsecutiveAssignments) {
1911119111
"y = 1;",
1911219112
Alignment);
1911319113

19114-
EXPECT_EQ(Alignment.ReflowComments, true);
19114+
EXPECT_EQ(Alignment.ReflowComments, FormatStyle::RCS_Always);
1911519115
Alignment.ColumnLimit = 50;
1911619116
verifyFormat("int x = 0;\n"
1911719117
"int yy = 1; /// specificlennospace\n"

clang/unittests/Format/FormatTestComments.cpp

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

494494
TEST_F(FormatTestComments, CommentReflowingCanBeTurnedOff) {
495495
FormatStyle Style = getLLVMStyleWithColumns(20);
496-
Style.ReflowComments = false;
496+
Style.ReflowComments = FormatStyle::RCS_Never;
497497
verifyFormat("// aaaaaaaaa aaaaaaaaaa aaaaaaaaaa", Style);
498498
verifyFormat("/* aaaaaaaaa aaaaaaaaaa aaaaaaaaaa */", Style);
499+
verifyNoChange("/* aaaaaaaaa aaaaaaaaaa aaaaaaaaaa\n"
500+
"aaaaaaaaa*/",
501+
Style);
502+
verifyNoChange("/* aaaaaaaaa aaaaaaaaaa aaaaaaaaaa\n"
503+
" aaaaaaaaa*/",
504+
Style);
505+
verifyNoChange("/* aaaaaaaaa aaaaaaaaaa aaaaaaaaaa\n"
506+
" * aaaaaaaaa*/",
507+
Style);
508+
}
509+
510+
TEST_F(FormatTestComments, CommentReflowingCanApplyOnlyToIndents) {
511+
FormatStyle Style = getLLVMStyleWithColumns(20);
512+
Style.ReflowComments = FormatStyle::RCS_IndentOnly;
513+
verifyFormat("// aaaaaaaaa aaaaaaaaaa aaaaaaaaaa", Style);
514+
verifyFormat("/* aaaaaaaaa aaaaaaaaaa aaaaaaaaaa */", Style);
515+
verifyNoChange("/* aaaaaaaaa aaaaaaaaaa aaaaaaaaaa\n"
516+
"aaaaaaaaa*/",
517+
Style);
518+
verifyNoChange("/* aaaaaaaaa aaaaaaaaaa aaaaaaaaaa\n"
519+
" aaaaaaaaa*/",
520+
Style);
521+
verifyFormat("/* aaaaaaaaa aaaaaaaaaa aaaaaaaaaa\n"
522+
" * aaaaaaaaa*/",
523+
"/* aaaaaaaaa aaaaaaaaaa aaaaaaaaaa\n"
524+
" * aaaaaaaaa*/",
525+
Style);
499526
}
500527

501528
TEST_F(FormatTestComments, CorrectlyHandlesLengthOfBlockComments) {

0 commit comments

Comments
 (0)