[clang] [clang-format] Preserve trailing NOLINTEND placement with SeparateDefinitionBlocks (PR #190741)

Jiaqi He via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 16 19:04:23 PDT 2026


https://github.com/heturing updated https://github.com/llvm/llvm-project/pull/190741

>From 862abd37c0b0760d496c1b91e6665a8c65cd22da Mon Sep 17 00:00:00 2001
From: Jiaqi He <heturing at gmail.com>
Date: Mon, 6 Apr 2026 23:36:15 -0600
Subject: [PATCH 1/3] [clang-format] Preserve trailing NOLINTEND placement with
 SeparateDefinitionBlocks

---
 clang/include/clang/Format/Format.h           |  2 ++
 clang/lib/Format/DefinitionBlockSeparator.cpp |  3 ++-
 clang/lib/Format/Format.cpp                   | 20 +++++++++++++++++++
 .../Format/DefinitionBlockSeparatorTest.cpp   |  8 ++++++++
 4 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index 48ce5aa2bdfa1..cdd704e199cff 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -6430,6 +6430,8 @@ inline StringRef getLanguageName(FormatStyle::LanguageKind Language) {
 
 bool isClangFormatOn(StringRef Comment);
 bool isClangFormatOff(StringRef Comment);
+bool isNoLintEnd(StringRef Comment);
+bool isNoLintBegin(StringRef Comment);
 
 } // end namespace format
 } // end namespace clang
diff --git a/clang/lib/Format/DefinitionBlockSeparator.cpp b/clang/lib/Format/DefinitionBlockSeparator.cpp
index 855f2efad1e53..e1fab2b088225 100644
--- a/clang/lib/Format/DefinitionBlockSeparator.cpp
+++ b/clang/lib/Format/DefinitionBlockSeparator.cpp
@@ -147,7 +147,8 @@ void DefinitionBlockSeparator::separateBlocks(
         return false;
 
       if (const auto *Tok = OperateLine->First;
-          Tok->is(tok::comment) && !isClangFormatOn(Tok->TokenText)) {
+          Tok->is(tok::comment) && !isClangFormatOn(Tok->TokenText) &&
+          !isNoLintEnd(Tok->TokenText)) {
         return true;
       }
 
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 42190604b3881..e68b867c73f82 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -4768,5 +4768,25 @@ bool isClangFormatOff(StringRef Comment) {
   return isClangFormatOnOff(Comment, /*On=*/false);
 }
 
+static bool isNoLintBeginEnd(StringRef Comment, bool On) {
+  if (Comment == (On ? "/* NOLINTBEGIN */" : "/* NOLINTEND */"))
+    return true;
+
+  static const char NoLintBegin[] = "// NOLINTBEGIN";
+  static const char NoLintEnd[] = "// NOLINTEND";
+  const unsigned Size = (On ? sizeof NoLintBegin : sizeof NoLintEnd) - 1;
+
+  return Comment.starts_with(On ? NoLintBegin : NoLintEnd) &&
+         (Comment.size() == Size || Comment[Size] == ':');
+}
+
+bool isNoLintEnd(StringRef Comment) {
+  return isNoLintBeginEnd(Comment, /*On=*/false);
+}
+
+bool isNoLintBegin(StringRef Comment) {
+  return isNoLintBeginEnd(Comment, /*On=*/true);
+}
+
 } // namespace format
 } // namespace clang
diff --git a/clang/unittests/Format/DefinitionBlockSeparatorTest.cpp b/clang/unittests/Format/DefinitionBlockSeparatorTest.cpp
index b1b4b1d047523..e5b7a2b256395 100644
--- a/clang/unittests/Format/DefinitionBlockSeparatorTest.cpp
+++ b/clang/unittests/Format/DefinitionBlockSeparatorTest.cpp
@@ -291,6 +291,14 @@ TEST_F(DefinitionBlockSeparatorTest, Always) {
                "struct E {};",
                Style);
 
+  verifyFormat("// NOLINTBEGIN\n"
+              "int x = 1;\n"
+              "int y = 2;\n"
+              "// NOLINTEND\n"
+              "\n"
+              "void some_function() {}\n",
+              Style);
+
   std::string Prefix = "namespace {\n";
   std::string Infix = "\n"
                       "// Enum test1\n"

>From e779368d776e922ff7f58fa04a6e593e878b2dde Mon Sep 17 00:00:00 2001
From: Jiaqi He <heturing at gmail.com>
Date: Tue, 7 Apr 2026 17:55:03 -0600
Subject: [PATCH 2/3] [clang-format] Removed unused function and unsupported
 comment type

---
 clang/include/clang/Format/Format.h           |  1 -
 clang/lib/Format/Format.cpp                   | 21 ++++---------------
 .../Format/DefinitionBlockSeparatorTest.cpp   | 12 +++++------
 3 files changed, 10 insertions(+), 24 deletions(-)

diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index cdd704e199cff..6a14fc995efd6 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -6431,7 +6431,6 @@ inline StringRef getLanguageName(FormatStyle::LanguageKind Language) {
 bool isClangFormatOn(StringRef Comment);
 bool isClangFormatOff(StringRef Comment);
 bool isNoLintEnd(StringRef Comment);
-bool isNoLintBegin(StringRef Comment);
 
 } // end namespace format
 } // end namespace clang
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index e68b867c73f82..0a080bbece682 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -4768,24 +4768,11 @@ bool isClangFormatOff(StringRef Comment) {
   return isClangFormatOnOff(Comment, /*On=*/false);
 }
 
-static bool isNoLintBeginEnd(StringRef Comment, bool On) {
-  if (Comment == (On ? "/* NOLINTBEGIN */" : "/* NOLINTEND */"))
-    return true;
-
-  static const char NoLintBegin[] = "// NOLINTBEGIN";
-  static const char NoLintEnd[] = "// NOLINTEND";
-  const unsigned Size = (On ? sizeof NoLintBegin : sizeof NoLintEnd) - 1;
-
-  return Comment.starts_with(On ? NoLintBegin : NoLintEnd) &&
-         (Comment.size() == Size || Comment[Size] == ':');
-}
-
 bool isNoLintEnd(StringRef Comment) {
-  return isNoLintBeginEnd(Comment, /*On=*/false);
-}
-
-bool isNoLintBegin(StringRef Comment) {
-  return isNoLintBeginEnd(Comment, /*On=*/true);
+  static const char NoLintEnd[] = "// NOLINTEND";
+  const unsigned Size = sizeof NoLintEnd - 1;
+  return Comment.starts_with(NoLintEnd) &&
+         (Comment.size() == Size || Comment[Size] == '(');
 }
 
 } // namespace format
diff --git a/clang/unittests/Format/DefinitionBlockSeparatorTest.cpp b/clang/unittests/Format/DefinitionBlockSeparatorTest.cpp
index e5b7a2b256395..32aea2f4d2b14 100644
--- a/clang/unittests/Format/DefinitionBlockSeparatorTest.cpp
+++ b/clang/unittests/Format/DefinitionBlockSeparatorTest.cpp
@@ -292,12 +292,12 @@ TEST_F(DefinitionBlockSeparatorTest, Always) {
                Style);
 
   verifyFormat("// NOLINTBEGIN\n"
-              "int x = 1;\n"
-              "int y = 2;\n"
-              "// NOLINTEND\n"
-              "\n"
-              "void some_function() {}\n",
-              Style);
+               "int x = 1;\n"
+               "int y = 2;\n"
+               "// NOLINTEND\n"
+               "\n"
+               "void some_function() {}\n",
+               Style);
 
   std::string Prefix = "namespace {\n";
   std::string Infix = "\n"

>From 9e2ce0c5e50d44218bb44a449cc122669f82aebe Mon Sep 17 00:00:00 2001
From: Jiaqi He <heturing at gmail.com>
Date: Thu, 16 Apr 2026 19:57:49 -0600
Subject: [PATCH 3/3] [clang-format] Preserve clearly trailing comment blocks

---
 clang/include/clang/Format/Format.h           |  1 -
 clang/lib/Format/DefinitionBlockSeparator.cpp |  8 ++++---
 clang/lib/Format/Format.cpp                   |  7 ------
 .../Format/DefinitionBlockSeparatorTest.cpp   | 24 ++++++++++++++++++-
 4 files changed, 28 insertions(+), 12 deletions(-)

diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index 6a14fc995efd6..48ce5aa2bdfa1 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -6430,7 +6430,6 @@ inline StringRef getLanguageName(FormatStyle::LanguageKind Language) {
 
 bool isClangFormatOn(StringRef Comment);
 bool isClangFormatOff(StringRef Comment);
-bool isNoLintEnd(StringRef Comment);
 
 } // end namespace format
 } // end namespace clang
diff --git a/clang/lib/Format/DefinitionBlockSeparator.cpp b/clang/lib/Format/DefinitionBlockSeparator.cpp
index e1fab2b088225..0a085042b1c18 100644
--- a/clang/lib/Format/DefinitionBlockSeparator.cpp
+++ b/clang/lib/Format/DefinitionBlockSeparator.cpp
@@ -147,9 +147,11 @@ void DefinitionBlockSeparator::separateBlocks(
         return false;
 
       if (const auto *Tok = OperateLine->First;
-          Tok->is(tok::comment) && !isClangFormatOn(Tok->TokenText) &&
-          !isNoLintEnd(Tok->TokenText)) {
-        return true;
+          Tok->is(tok::comment) && !isClangFormatOn(Tok->TokenText)) {
+        const bool IsEndComment =
+            Tok->NewlinesBefore == 1 && OperateIndex + 1 < Lines.size() &&
+            Lines[OperateIndex + 1]->First->NewlinesBefore > 1;
+        return !IsEndComment;
       }
 
       // A single line identifier that is not in the last line.
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 0a080bbece682..42190604b3881 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -4768,12 +4768,5 @@ bool isClangFormatOff(StringRef Comment) {
   return isClangFormatOnOff(Comment, /*On=*/false);
 }
 
-bool isNoLintEnd(StringRef Comment) {
-  static const char NoLintEnd[] = "// NOLINTEND";
-  const unsigned Size = sizeof NoLintEnd - 1;
-  return Comment.starts_with(NoLintEnd) &&
-         (Comment.size() == Size || Comment[Size] == '(');
-}
-
 } // namespace format
 } // namespace clang
diff --git a/clang/unittests/Format/DefinitionBlockSeparatorTest.cpp b/clang/unittests/Format/DefinitionBlockSeparatorTest.cpp
index 32aea2f4d2b14..b42605927ec61 100644
--- a/clang/unittests/Format/DefinitionBlockSeparatorTest.cpp
+++ b/clang/unittests/Format/DefinitionBlockSeparatorTest.cpp
@@ -297,7 +297,29 @@ TEST_F(DefinitionBlockSeparatorTest, Always) {
                "// NOLINTEND\n"
                "\n"
                "void some_function() {}\n",
-               Style);
+               Style,
+               "// NOLINTBEGIN\n"
+               "int x = 1;\n"
+               "int y = 2;\n"
+               "// NOLINTEND\n"
+               "\n"
+               "void some_function() {}\n",
+               false);
+
+  verifyFormat("int x = 0;\n"
+               "int y = 0;\n"
+               "// trailing comment 1\n"
+               "// trailing comment 2\n"
+               "\n"
+               "void some_function() {}\n",
+               Style,
+               "int x = 0;\n"
+               "int y = 0;\n"
+               "// trailing comment 1\n"
+               "// trailing comment 2\n"
+               "\n"
+               "void some_function() {}\n",
+               false);
 
   std::string Prefix = "namespace {\n";
   std::string Infix = "\n"



More information about the cfe-commits mailing list