[clang] [clang-format] Stop inserting blank line in disabled region (PR #201995)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Jun 8 06:00:14 PDT 2026
https://github.com/sstwcw updated https://github.com/llvm/llvm-project/pull/201995
>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 1/2] [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 };",
>From 83aec246c61e53f9b70cd7d9e2ee21e12d5b8bcd Mon Sep 17 00:00:00 2001
From: sstwcw <su3e8a96kzlver at posteo.net>
Date: Mon, 8 Jun 2026 12:59:57 +0000
Subject: [PATCH 2/2] Remove the field
---
clang/lib/Format/DefinitionBlockSeparator.cpp | 5 ++++-
clang/lib/Format/FormatToken.h | 15 +++++----------
clang/lib/Format/FormatTokenLexer.cpp | 4 +---
3 files changed, 10 insertions(+), 14 deletions(-)
diff --git a/clang/lib/Format/DefinitionBlockSeparator.cpp b/clang/lib/Format/DefinitionBlockSeparator.cpp
index 96833a24d66ce..6b52b1fc0deff 100644
--- a/clang/lib/Format/DefinitionBlockSeparator.cpp
+++ b/clang/lib/Format/DefinitionBlockSeparator.cpp
@@ -88,8 +88,11 @@ void DefinitionBlockSeparator::separateBlocks(
assert(TargetLine);
assert(TargetToken);
- if (TargetToken->FinalizedNewLinesBefore)
+ // Lines should not be added in the disabled region.
+ if (TargetToken->is(tok::comment) &&
+ isClangFormatOn(TargetToken->TokenText)) {
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 7fb1b6a1d6f46..556bb0f3dd0af 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), FinalizedNewLinesBefore(false),
- Finalized(false), ClosesRequiresClause(false),
- EndsCppAttributeGroup(false), BlockKind(BK_Unknown),
- Decision(FD_Unformatted), PackingKind(PPK_Inconclusive),
- TypeIsFinalized(false), Type(TT_Unknown) {}
+ ContinuesLineCommentSection(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,11 +397,6 @@ 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 5ac35b5a98680..92571c012bdb2 100644
--- a/clang/lib/Format/FormatTokenLexer.cpp
+++ b/clang/lib/Format/FormatTokenLexer.cpp
@@ -1598,10 +1598,8 @@ 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;
More information about the cfe-commits
mailing list