[clang] [clang-format] Stop inserting blank line in disabled region (PR #201995)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 5 19:53:18 PDT 2026
https://github.com/sstwcw created https://github.com/llvm/llvm-project/pull/201995
Previously, a blank got inserted before the `// clang-format off` comment with the `SeparateDefinitionBlocks` option set.
Fixes #106983 and #146317.
>From 91eae68f296772d06ca1ab418bd219366b58b20a Mon Sep 17 00:00:00 2001
From: sstwcw <su3e8a96kzlver at posteo.net>
Date: Sat, 6 Jun 2026 02:46:08 +0000
Subject: [PATCH] [clang-format] Stop inserting blank line in disabled region
Previously, a blank got inserted before the `// clang-format off`
comment with the `SeparateDefinitionBlocks` option set.
Fixes #106983 and #146317.
---
clang/lib/Format/DefinitionBlockSeparator.cpp | 2 ++
clang/lib/Format/FormatToken.h | 15 ++++++----
clang/lib/Format/FormatTokenLexer.cpp | 4 ++-
.../Format/DefinitionBlockSeparatorTest.cpp | 30 +++++++++++++++++++
4 files changed, 45 insertions(+), 6 deletions(-)
diff --git a/clang/lib/Format/DefinitionBlockSeparator.cpp b/clang/lib/Format/DefinitionBlockSeparator.cpp
index d16f8ddd5a2ec..96833a24d66ce 100644
--- a/clang/lib/Format/DefinitionBlockSeparator.cpp
+++ b/clang/lib/Format/DefinitionBlockSeparator.cpp
@@ -88,6 +88,8 @@ void DefinitionBlockSeparator::separateBlocks(
assert(TargetLine);
assert(TargetToken);
+ if (TargetToken->FinalizedNewLinesBefore)
+ return;
// Do not handle EOF newlines.
if (TargetToken->is(tok::eof))
return;
diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h
index 556bb0f3dd0af..7fb1b6a1d6f46 100644
--- a/clang/lib/Format/FormatToken.h
+++ b/clang/lib/Format/FormatToken.h
@@ -328,11 +328,11 @@ struct FormatToken {
IsUnterminatedLiteral(false), CanBreakBefore(false),
ClosesTemplateDeclaration(false), StartsBinaryExpression(false),
EndsBinaryExpression(false), PartOfMultiVariableDeclStmt(false),
- ContinuesLineCommentSection(false), Finalized(false),
- ClosesRequiresClause(false), EndsCppAttributeGroup(false),
- BlockKind(BK_Unknown), Decision(FD_Unformatted),
- PackingKind(PPK_Inconclusive), TypeIsFinalized(false),
- Type(TT_Unknown) {}
+ ContinuesLineCommentSection(false), FinalizedNewLinesBefore(false),
+ Finalized(false), ClosesRequiresClause(false),
+ EndsCppAttributeGroup(false), BlockKind(BK_Unknown),
+ Decision(FD_Unformatted), PackingKind(PPK_Inconclusive),
+ TypeIsFinalized(false), Type(TT_Unknown) {}
/// The \c Token.
Token Tok;
@@ -397,6 +397,11 @@ struct FormatToken {
/// Only set to true if \c Type == \c TT_LineComment.
unsigned ContinuesLineCommentSection : 1;
+ /// Empty lines should not be added before the token. But its indentation may
+ /// be changed. Set for the comment that ends a region where formatting is
+ /// disabled.
+ unsigned FinalizedNewLinesBefore : 1;
+
/// If \c true, this token has been fully formatted (indented and
/// potentially re-formatted inside), and we do not allow further formatting
/// changes.
diff --git a/clang/lib/Format/FormatTokenLexer.cpp b/clang/lib/Format/FormatTokenLexer.cpp
index 92571c012bdb2..5ac35b5a98680 100644
--- a/clang/lib/Format/FormatTokenLexer.cpp
+++ b/clang/lib/Format/FormatTokenLexer.cpp
@@ -1598,8 +1598,10 @@ void FormatTokenLexer::readRawToken(FormatToken &Tok) {
if ((Style.isJavaScript() || Style.isProto()) && Tok.is(tok::char_constant))
Tok.Tok.setKind(tok::string_literal);
- if (Tok.is(tok::comment) && isClangFormatOn(Tok.TokenText))
+ if (Tok.is(tok::comment) && isClangFormatOn(Tok.TokenText)) {
FormattingDisabled = false;
+ Tok.FinalizedNewLinesBefore = true;
+ }
Tok.Finalized = FormattingDisabled;
diff --git a/clang/unittests/Format/DefinitionBlockSeparatorTest.cpp b/clang/unittests/Format/DefinitionBlockSeparatorTest.cpp
index d2b43ca2d70aa..5e4c574d68dbb 100644
--- a/clang/unittests/Format/DefinitionBlockSeparatorTest.cpp
+++ b/clang/unittests/Format/DefinitionBlockSeparatorTest.cpp
@@ -137,6 +137,36 @@ TEST_F(DefinitionBlockSeparatorTest, Basic) {
"}",
Style);
+ // There should not be an extra line when formatting is disabled.
+ verifyFormat("// clang-format off\n"
+ "void function()\n"
+ "{\n"
+ "\n"
+ "}\n"
+ "// clang-format on",
+ Style,
+ "// clang-format off\n"
+ "void function()\n"
+ "{\n"
+ "\n"
+ "}\n"
+ "// clang-format on",
+ /*Inverse=*/false);
+ verifyFormat("class X {\n"
+ " // clang-format off\n"
+ "#pragma warning(suppress : 4373)\n"
+ " void foo() {}\n"
+ " // clang-format on\n"
+ "};\n",
+ Style,
+ "class X {\n"
+ " // clang-format off\n"
+ "#pragma warning(suppress : 4373)\n"
+ " void foo() {}\n"
+ " // clang-format on\n"
+ "};\n",
+ /*Inverse=*/false);
+
verifyFormat("enum Foo { FOO, BAR };\n"
"\n"
"enum Bar { FOOBAR, BARFOO };",
More information about the cfe-commits
mailing list