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 <[email protected]>
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 };",

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to