[clang] 441108c - Reland [clang-format] Fix overlapping whitespace replacements before PPDirective
Owen Pan via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 16 17:00:19 PDT 2023
Author: Owen Pan
Date: 2023-06-16T17:00:12-07:00
New Revision: 441108ccba948d76e7002c61236e3bcbca0203ce
URL: https://github.com/llvm/llvm-project/commit/441108ccba948d76e7002c61236e3bcbca0203ce
DIFF: https://github.com/llvm/llvm-project/commit/441108ccba948d76e7002c61236e3bcbca0203ce.diff
LOG: 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
Added:
Modified:
clang/lib/Format/FormatToken.h
clang/lib/Format/UnwrappedLineFormatter.cpp
clang/unittests/Format/FormatTest.cpp
Removed:
################################################################################
diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h
index dd23bd35411dc..bba030238338f 100644
--- a/clang/lib/Format/FormatToken.h
+++ b/clang/lib/Format/FormatToken.h
@@ -418,6 +418,12 @@ struct FormatToken {
/// 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;
diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp
index 5172deb494b2e..6d9a43dea0568 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -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);
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 1b6255a6be033..ebf5850da439a 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -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"
More information about the cfe-commits
mailing list