mirror of
https://github.com/llvm/llvm-project.git
synced 2025-05-02 10:06:06 +00:00
Reland [clang-format] Fix overlapping whitespace replacements before PPDirective
If the first token of an annotated line already has a computed Newlines, reuse it to avoid potential overlapping whitespace replacements before preprocessor branching directives. Fixes #62892. Differential Revision: https://reviews.llvm.org/D151954
This commit is contained in:
parent
1b8c7ee424
commit
441108ccba
@ -418,6 +418,12 @@ public:
|
||||
/// and thereby e.g. leave an empty line between two function definitions.
|
||||
unsigned NewlinesBefore = 0;
|
||||
|
||||
/// The number of newlines immediately before the \c Token after formatting.
|
||||
///
|
||||
/// This is used to avoid overlapping whitespace replacements when \c Newlines
|
||||
/// is recomputed for a finalized preprocessor branching directive.
|
||||
int Newlines = -1;
|
||||
|
||||
/// The offset just past the last '\n' in this token's leading
|
||||
/// whitespace (relative to \c WhiteSpaceStart). 0 if there is no '\n'.
|
||||
unsigned LastNewlineOffset = 0;
|
||||
|
@ -1418,22 +1418,13 @@ unsigned UnwrappedLineFormatter::format(
|
||||
return Penalty;
|
||||
}
|
||||
|
||||
void UnwrappedLineFormatter::formatFirstToken(
|
||||
const AnnotatedLine &Line, const AnnotatedLine *PreviousLine,
|
||||
const AnnotatedLine *PrevPrevLine,
|
||||
const SmallVectorImpl<AnnotatedLine *> &Lines, unsigned Indent,
|
||||
unsigned NewlineIndent) {
|
||||
FormatToken &RootToken = *Line.First;
|
||||
if (RootToken.is(tok::eof)) {
|
||||
unsigned Newlines =
|
||||
std::min(RootToken.NewlinesBefore,
|
||||
Style.KeepEmptyLinesAtEOF ? Style.MaxEmptyLinesToKeep + 1 : 1);
|
||||
unsigned TokenIndent = Newlines ? NewlineIndent : 0;
|
||||
Whitespaces->replaceWhitespace(RootToken, Newlines, TokenIndent,
|
||||
TokenIndent);
|
||||
return;
|
||||
}
|
||||
unsigned Newlines =
|
||||
static auto computeNewlines(const AnnotatedLine &Line,
|
||||
const AnnotatedLine *PreviousLine,
|
||||
const AnnotatedLine *PrevPrevLine,
|
||||
const SmallVectorImpl<AnnotatedLine *> &Lines,
|
||||
const FormatStyle &Style) {
|
||||
const auto &RootToken = *Line.First;
|
||||
auto Newlines =
|
||||
std::min(RootToken.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1);
|
||||
// Remove empty lines before "}" where applicable.
|
||||
if (RootToken.is(tok::r_brace) &&
|
||||
@ -1512,7 +1503,32 @@ void UnwrappedLineFormatter::formatFirstToken(
|
||||
}
|
||||
}
|
||||
|
||||
if (Newlines)
|
||||
return Newlines;
|
||||
}
|
||||
|
||||
void UnwrappedLineFormatter::formatFirstToken(
|
||||
const AnnotatedLine &Line, const AnnotatedLine *PreviousLine,
|
||||
const AnnotatedLine *PrevPrevLine,
|
||||
const SmallVectorImpl<AnnotatedLine *> &Lines, unsigned Indent,
|
||||
unsigned NewlineIndent) {
|
||||
FormatToken &RootToken = *Line.First;
|
||||
if (RootToken.is(tok::eof)) {
|
||||
unsigned Newlines =
|
||||
std::min(RootToken.NewlinesBefore,
|
||||
Style.KeepEmptyLinesAtEOF ? Style.MaxEmptyLinesToKeep + 1 : 1);
|
||||
unsigned TokenIndent = Newlines ? NewlineIndent : 0;
|
||||
Whitespaces->replaceWhitespace(RootToken, Newlines, TokenIndent,
|
||||
TokenIndent);
|
||||
return;
|
||||
}
|
||||
|
||||
if (RootToken.Newlines < 0) {
|
||||
RootToken.Newlines =
|
||||
computeNewlines(Line, PreviousLine, PrevPrevLine, Lines, Style);
|
||||
assert(RootToken.Newlines >= 0);
|
||||
}
|
||||
|
||||
if (RootToken.Newlines > 0)
|
||||
Indent = NewlineIndent;
|
||||
|
||||
// Preprocessor directives get indented before the hash only if specified. In
|
||||
@ -1524,7 +1540,7 @@ void UnwrappedLineFormatter::formatFirstToken(
|
||||
Indent = 0;
|
||||
}
|
||||
|
||||
Whitespaces->replaceWhitespace(RootToken, Newlines, Indent, Indent,
|
||||
Whitespaces->replaceWhitespace(RootToken, RootToken.Newlines, Indent, Indent,
|
||||
/*IsAligned=*/false,
|
||||
Line.InPPDirective &&
|
||||
!RootToken.HasUnescapedNewline);
|
||||
|
@ -12841,6 +12841,64 @@ TEST_F(FormatTest, FormatsAfterAccessModifiers) {
|
||||
" void f() {}\n"
|
||||
"};\n",
|
||||
Style);
|
||||
verifyNoChange("struct foo {\n"
|
||||
"#ifdef FOO\n"
|
||||
"#else\n"
|
||||
"private:\n"
|
||||
"\n"
|
||||
"#endif\n"
|
||||
"};",
|
||||
Style);
|
||||
verifyFormat("struct foo {\n"
|
||||
"#ifdef FOO\n"
|
||||
"#else\n"
|
||||
"private:\n"
|
||||
"\n"
|
||||
"#endif\n"
|
||||
"};",
|
||||
"struct foo {\n"
|
||||
"#ifdef FOO\n"
|
||||
"#else\n"
|
||||
"private:\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"#endif\n"
|
||||
"};",
|
||||
Style);
|
||||
verifyFormat("struct foo {\n"
|
||||
"#ifdef FOO\n"
|
||||
"private:\n"
|
||||
"#else\n"
|
||||
"#endif\n"
|
||||
"};",
|
||||
"struct foo {\n"
|
||||
"#ifdef FOO\n"
|
||||
"private:\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"#else\n"
|
||||
"#endif\n"
|
||||
"};",
|
||||
Style);
|
||||
verifyFormat("struct foo {\n"
|
||||
"#if 0\n"
|
||||
"#else\n"
|
||||
"#endif\n"
|
||||
"#ifdef FOO\n"
|
||||
"private:\n"
|
||||
"#endif\n"
|
||||
"};",
|
||||
"struct foo {\n"
|
||||
"#if 0\n"
|
||||
"#else\n"
|
||||
"#endif\n"
|
||||
"#ifdef FOO\n"
|
||||
"private:\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"#endif\n"
|
||||
"};",
|
||||
Style);
|
||||
|
||||
Style.EmptyLineAfterAccessModifier = FormatStyle::ELAAMS_Always;
|
||||
verifyFormat("struct foo {\n"
|
||||
|
Loading…
x
Reference in New Issue
Block a user