Skip to content

[clang-format] Split line comments separated by backslashes #147648

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions clang/docs/ClangFormatStyleOptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1554,9 +1554,9 @@ the configuration (without a prefix: ``Auto``).

.. code-block:: c++

#define A \
int aaaa; \
int b; \
#define A \
int aaaa; \
int b; \
int dddddddddd;


Expand Down
6 changes: 3 additions & 3 deletions clang/include/clang/Format/Format.h
Original file line number Diff line number Diff line change
Expand Up @@ -513,9 +513,9 @@ struct FormatStyle {
ENAS_LeftWithLastLine,
/// Align escaped newlines in the right-most column.
/// \code
/// #define A \
/// int aaaa; \
/// int b; \
/// #define A \
/// int aaaa; \
/// int b; \
/// int dddddddddd;
/// \endcode
ENAS_Right,
Expand Down
21 changes: 12 additions & 9 deletions clang/lib/Format/FormatTokenLexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1329,23 +1329,26 @@ FormatToken *FormatTokenLexer::getNextToken() {
if (FormatTok->is(tok::unknown))
FormatTok->setType(TT_ImplicitStringLiteral);

const bool IsCpp = Style.isCpp();

// JavaScript and Java do not allow to escape the end of the line with a
// backslash. Backslashes are syntax errors in plain source, but can occur in
// comments. When a single line comment ends with a \, it'll cause the next
// line of code to be lexed as a comment, breaking formatting. The code below
// finds comments that contain a backslash followed by a line break, truncates
// the comment token at the backslash, and resets the lexer to restart behind
// the backslash.
if ((Style.isJavaScript() || Style.isJava()) && FormatTok->is(tok::comment) &&
FormatTok->TokenText.starts_with("//")) {
size_t BackslashPos = FormatTok->TokenText.find('\\');
while (BackslashPos != StringRef::npos) {
if (BackslashPos + 1 < FormatTok->TokenText.size() &&
FormatTok->TokenText[BackslashPos + 1] == '\n') {
truncateToken(BackslashPos + 1);
if (const auto Text = FormatTok->TokenText;
Text.starts_with("//") &&
(IsCpp || Style.isJavaScript() || Style.isJava())) {
assert(FormatTok->is(tok::comment));
for (auto Pos = Text.find('\\'); Pos++ != StringRef::npos;
Pos = Text.find('\\', Pos)) {
if (Pos < Text.size() && Text[Pos] == '\n' &&
(!IsCpp || Text.substr(Pos + 1).ltrim().starts_with("//"))) {
truncateToken(Pos);
break;
}
BackslashPos = FormatTok->TokenText.find('\\', BackslashPos + 1);
}
}

Expand Down Expand Up @@ -1450,7 +1453,7 @@ FormatToken *FormatTokenLexer::getNextToken() {
Column = FormatTok->LastLineColumnWidth;
}

if (Style.isCpp()) {
if (IsCpp) {
auto *Identifier = FormatTok->Tok.getIdentifierInfo();
auto it = Macros.find(Identifier);
if ((Tokens.empty() || !Tokens.back()->Tok.getIdentifierInfo() ||
Expand Down
18 changes: 8 additions & 10 deletions clang/unittests/Format/FormatTestComments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -747,16 +747,14 @@ TEST_F(FormatTestComments, DontSplitLineCommentsWithEscapedNewlines) {
" // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\\n"
" // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
getLLVMStyleWithColumns(50)));
// FIXME: One day we might want to implement adjustment of leading whitespace
// of the consecutive lines in this kind of comment:
EXPECT_EQ("double\n"
" a; // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\\n"
" // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\\n"
" // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
format("double a; // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\\n"
" // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\\n"
" // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
getLLVMStyleWithColumns(49)));
verifyFormat("double\n"
" a; // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\\n"
" // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\\n"
" // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"double a; // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\\n"
" // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\\n"
" // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
getLLVMStyleWithColumns(49));
}

TEST_F(FormatTestComments, DontIntroduceMultilineComments) {
Expand Down
7 changes: 7 additions & 0 deletions clang/unittests/Format/TokenAnnotatorTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4126,6 +4126,13 @@ TEST_F(TokenAnnotatorTest, JsonCodeInRawString) {
EXPECT_TOKEN(Tokens[6], tok::colon, TT_DictLiteral);
}

TEST_F(TokenAnnotatorTest, LineCommentTrailingBackslash) {
auto Tokens = annotate("// a \\\n"
"// b");
ASSERT_EQ(Tokens.size(), 3u) << Tokens;
EXPECT_TOKEN(Tokens[1], tok::comment, TT_LineComment);
}

} // namespace
} // namespace format
} // namespace clang