mirror of
https://github.com/llvm/llvm-project.git
synced 2025-05-02 21:46: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.
|
/// and thereby e.g. leave an empty line between two function definitions.
|
||||||
unsigned NewlinesBefore = 0;
|
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
|
/// The offset just past the last '\n' in this token's leading
|
||||||
/// whitespace (relative to \c WhiteSpaceStart). 0 if there is no '\n'.
|
/// whitespace (relative to \c WhiteSpaceStart). 0 if there is no '\n'.
|
||||||
unsigned LastNewlineOffset = 0;
|
unsigned LastNewlineOffset = 0;
|
||||||
|
@ -1418,22 +1418,13 @@ unsigned UnwrappedLineFormatter::format(
|
|||||||
return Penalty;
|
return Penalty;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnwrappedLineFormatter::formatFirstToken(
|
static auto computeNewlines(const AnnotatedLine &Line,
|
||||||
const AnnotatedLine &Line, const AnnotatedLine *PreviousLine,
|
const AnnotatedLine *PreviousLine,
|
||||||
const AnnotatedLine *PrevPrevLine,
|
const AnnotatedLine *PrevPrevLine,
|
||||||
const SmallVectorImpl<AnnotatedLine *> &Lines, unsigned Indent,
|
const SmallVectorImpl<AnnotatedLine *> &Lines,
|
||||||
unsigned NewlineIndent) {
|
const FormatStyle &Style) {
|
||||||
FormatToken &RootToken = *Line.First;
|
const auto &RootToken = *Line.First;
|
||||||
if (RootToken.is(tok::eof)) {
|
auto Newlines =
|
||||||
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 =
|
|
||||||
std::min(RootToken.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1);
|
std::min(RootToken.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1);
|
||||||
// Remove empty lines before "}" where applicable.
|
// Remove empty lines before "}" where applicable.
|
||||||
if (RootToken.is(tok::r_brace) &&
|
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;
|
Indent = NewlineIndent;
|
||||||
|
|
||||||
// Preprocessor directives get indented before the hash only if specified. In
|
// Preprocessor directives get indented before the hash only if specified. In
|
||||||
@ -1524,7 +1540,7 @@ void UnwrappedLineFormatter::formatFirstToken(
|
|||||||
Indent = 0;
|
Indent = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Whitespaces->replaceWhitespace(RootToken, Newlines, Indent, Indent,
|
Whitespaces->replaceWhitespace(RootToken, RootToken.Newlines, Indent, Indent,
|
||||||
/*IsAligned=*/false,
|
/*IsAligned=*/false,
|
||||||
Line.InPPDirective &&
|
Line.InPPDirective &&
|
||||||
!RootToken.HasUnescapedNewline);
|
!RootToken.HasUnescapedNewline);
|
||||||
|
@ -12841,6 +12841,64 @@ TEST_F(FormatTest, FormatsAfterAccessModifiers) {
|
|||||||
" void f() {}\n"
|
" void f() {}\n"
|
||||||
"};\n",
|
"};\n",
|
||||||
Style);
|
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;
|
Style.EmptyLineAfterAccessModifier = FormatStyle::ELAAMS_Always;
|
||||||
verifyFormat("struct foo {\n"
|
verifyFormat("struct foo {\n"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user