[clang-format] Fix crash while reflowing backslash in comments

Summary:
The added test case was currently crashing with an assertion:
```
krasimir@krasimir> cat test.cc                                                                                                                                                              ~
// How to run:
// bbbbb run \
// rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr \
// <log_file> -- --output_directory="<output_directory>"
krasimir@krasimir> ~/work/llvm-build/bin/clang-format test.cc                                                                                                                               ~
clang-format: /usr/local/google/home/krasimir/work/llvm/tools/clang/lib/Format/WhitespaceManager.cpp:117: void clang::format::WhitespaceManager::calculateLineBreakInformation(): Assertion `PreviousOriginalWhitespaceEndOffset <= OriginalWhitespaceStartOffset' failed.
```
The root cause was that BreakableToken was not considering the case of a reflow between an unescaped newline in a line comment.

Subscribers: cfe-commits

Differential Revision: https://reviews.llvm.org/D48089

llvm-svn: 334527
This commit is contained in:
Krasimir Georgiev 2018-06-12 19:33:15 +00:00
parent 4872750dd3
commit 4fc55a76b8
2 changed files with 53 additions and 7 deletions

View File

@ -789,16 +789,47 @@ BreakableComment::Split BreakableLineCommentSection::getReflowSplit(
void BreakableLineCommentSection::reflow(unsigned LineIndex,
WhitespaceManager &Whitespaces) const {
if (LineIndex > 0 && Tokens[LineIndex] != Tokens[LineIndex - 1]) {
// Reflow happens between tokens. Replace the whitespace between the
// tokens by the empty string.
Whitespaces.replaceWhitespace(
*Tokens[LineIndex], /*Newlines=*/0, /*Spaces=*/0,
/*StartOfTokenColumn=*/StartColumn, /*InPPDirective=*/false);
// Replace the indent and prefix of the token with the reflow prefix.
} else if (LineIndex > 0) {
// In case we're reflowing after the '\' in:
//
// // line comment \
// // line 2
//
// the reflow happens inside the single comment token (it is a single line
// comment with an unescaped newline).
// Replace the whitespace between the '\' and '//' with the empty string.
//
// Offset points to after the '\' relative to start of the token.
unsigned Offset = Lines[LineIndex - 1].data() +
Lines[LineIndex - 1].size() -
tokenAt(LineIndex - 1).TokenText.data();
// WhitespaceLength is the number of chars between the '\' and the '//' on
// the next line.
unsigned WhitespaceLength =
Content[LineIndex].data() - tokenAt(LineIndex).TokenText.data();
Lines[LineIndex].data() - tokenAt(LineIndex).TokenText.data() - Offset;
Whitespaces.replaceWhitespaceInToken(*Tokens[LineIndex],
/*Offset=*/0,
Offset,
/*ReplaceChars=*/WhitespaceLength,
/*PreviousPostfix=*/"",
/*CurrentPrefix=*/"",
/*InPPDirective=*/false,
/*Newlines=*/0,
/*Spaces=*/0);
}
// Replace the indent and prefix of the token with the reflow prefix.
unsigned Offset =
Lines[LineIndex].data() - tokenAt(LineIndex).TokenText.data();
unsigned WhitespaceLength =
Content[LineIndex].data() - Lines[LineIndex].data();
Whitespaces.replaceWhitespaceInToken(*Tokens[LineIndex],
Offset,
/*ReplaceChars=*/WhitespaceLength,
/*PreviousPostfix=*/"",
/*CurrentPrefix=*/ReflowPrefix,

View File

@ -3090,6 +3090,21 @@ TEST_F(FormatTestComments, BreaksBeforeTrailingUnbreakableSequence) {
getLLVMStyleWithColumns(23));
}
TEST_F(FormatTestComments, ReflowBackslashCrash) {
// clang-format off
EXPECT_EQ(
"// How to run:\n"
"// bbbbb run \\\n"
"// rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr\n"
"// \\ <log_file> -- --output_directory=\"<output_directory>\"",
format(
"// How to run:\n"
"// bbbbb run \\\n"
"// rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr \\\n"
"// <log_file> -- --output_directory=\"<output_directory>\""));
// clang-format on
}
} // end namespace
} // end namespace format
} // end namespace clang