https://github.com/zeyi2 updated 
https://github.com/llvm/llvm-project/pull/168196

>From 5c002ef06bf8cb79e0138358fd6ca8222d809231 Mon Sep 17 00:00:00 2001
From: mtx <[email protected]>
Date: Sat, 15 Nov 2025 18:38:51 +0800
Subject: [PATCH 1/2] [clang-tidy] Add `IgnoredFilesList` option to
 `readability-duplicate-include`

---
 .../readability/DuplicateIncludeCheck.cpp     | 44 ++++++++++++++++++-
 .../readability/DuplicateIncludeCheck.h       | 10 ++++-
 clang-tools-extra/docs/ReleaseNotes.rst       |  7 ++-
 .../checks/readability/duplicate-include.rst  | 11 +++++
 .../Inputs/duplicate-include/pack_begin.h     |  1 +
 .../Inputs/duplicate-include/pack_end.h       |  1 +
 .../duplicate-include-ignored-files.cpp       |  9 ++++
 7 files changed, 78 insertions(+), 5 deletions(-)
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/readability/Inputs/duplicate-include/pack_begin.h
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/readability/Inputs/duplicate-include/pack_end.h
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/readability/duplicate-include-ignored-files.cpp

diff --git a/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.cpp 
b/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.cpp
index cc9ae471a926d..6a7324c446cfe 100644
--- a/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.cpp
@@ -7,10 +7,12 @@
 
//===----------------------------------------------------------------------===//
 
 #include "DuplicateIncludeCheck.h"
+#include "../utils/OptionsUtils.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Lex/Preprocessor.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Regex.h"
 #include <memory>
 
 namespace clang::tidy::readability {
@@ -33,10 +35,17 @@ using FileList = SmallVector<StringRef>;
 class DuplicateIncludeCallbacks : public PPCallbacks {
 public:
   DuplicateIncludeCallbacks(DuplicateIncludeCheck &Check,
-                            const SourceManager &SM)
+                            const SourceManager &SM,
+                            const std::vector<StringRef> &IgnoredList)
       : Check(Check), SM(SM) {
     // The main file doesn't participate in the FileChanged notification.
     Files.emplace_back();
+
+    AllowedRegexes.reserve(IgnoredList.size());
+    for (const StringRef &It : IgnoredList) {
+      if (!It.empty())
+        AllowedRegexes.emplace_back(It);
+    }
   }
 
   void FileChanged(SourceLocation Loc, FileChangeReason Reason,
@@ -62,10 +71,32 @@ class DuplicateIncludeCallbacks : public PPCallbacks {
   SmallVector<FileList> Files;
   DuplicateIncludeCheck &Check;
   const SourceManager &SM;
+  std::vector<llvm::Regex> AllowedRegexes;
+
+  bool isAllowedDuplicate(StringRef FileName, OptionalFileEntryRef File) const 
{
+    if (llvm::any_of(AllowedRegexes,
+                     [&](const llvm::Regex &R) { return R.match(FileName); }))
+      return true;
+
+    if (File) {
+      const StringRef Resolved = File->getName();
+      if (llvm::any_of(AllowedRegexes,
+                       [&](const llvm::Regex &R) { return R.match(Resolved); 
}))
+        return true;
+    }
+
+    return false;
+  }
 };
 
 } // namespace
 
+DuplicateIncludeCheck::DuplicateIncludeCheck(StringRef Name,
+                                             ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      IgnoredFilesList(utils::options::parseStringList(
+          Options.get("IgnoredFilesList", ""))) {}
+
 void DuplicateIncludeCallbacks::FileChanged(SourceLocation Loc,
                                             FileChangeReason Reason,
                                             SrcMgr::CharacteristicKind 
FileType,
@@ -86,6 +117,9 @@ void DuplicateIncludeCallbacks::InclusionDirective(
       FilenameRange.getEnd().isMacroID())
     return;
   if (llvm::is_contained(Files.back(), FileName)) {
+    if (isAllowedDuplicate(FileName, File)) {
+      return;
+    }
     // We want to delete the entire line, so make sure that [Start,End] covers
     // everything.
     const SourceLocation Start =
@@ -111,7 +145,13 @@ void DuplicateIncludeCallbacks::MacroUndefined(const Token 
&MacroNameTok,
 
 void DuplicateIncludeCheck::registerPPCallbacks(
     const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) 
{
-  PP->addPPCallbacks(std::make_unique<DuplicateIncludeCallbacks>(*this, SM));
+  PP->addPPCallbacks(
+      std::make_unique<DuplicateIncludeCallbacks>(*this, SM, 
IgnoredFilesList));
+}
+
+void DuplicateIncludeCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "IgnoredFilesList",
+                utils::options::serializeStringList(IgnoredFilesList));
 }
 
 } // namespace clang::tidy::readability
diff --git a/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.h 
b/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.h
index ca3679108e60b..816c280b1fbea 100644
--- a/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.h
@@ -10,6 +10,7 @@
 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_DUPLICATEINCLUDECHECK_H
 
 #include "../ClangTidyCheck.h"
+#include <vector>
 
 namespace clang::tidy::readability {
 
@@ -19,11 +20,16 @@ namespace clang::tidy::readability {
 /// directives between them are analyzed.
 class DuplicateIncludeCheck : public ClangTidyCheck {
 public:
-  DuplicateIncludeCheck(StringRef Name, ClangTidyContext *Context)
-      : ClangTidyCheck(Name, Context) {}
+  DuplicateIncludeCheck(StringRef Name, ClangTidyContext *Context);
 
   void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
                            Preprocessor *ModuleExpanderPP) override;
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+private:
+  // Semicolon-separated list of regexes or file names to ignore from duplicate
+  // warnings.
+  const std::vector<StringRef> IgnoredFilesList;
 };
 
 } // namespace clang::tidy::readability
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index 4096624923858..52ffc0f82537b 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -316,7 +316,7 @@ Changes in existing checks
   exceptions from captures are now diagnosed, exceptions in the bodies of
   lambdas that aren't actually invoked are not. Additionally, fixed an issue
   where the check wouldn't diagnose throws in arguments to functions or
-  constructors. Added fine-grained configuration via options 
+  constructors. Added fine-grained configuration via options
   `CheckDestructors`, `CheckMoveMemberFunctions`, `CheckMain`,
   `CheckedSwapFunctions`, and `CheckNothrowFunctions`.
 
@@ -505,6 +505,11 @@ Changes in existing checks
   ignoring default constructors with user provided arguments and adding
   detection in container's method except ``empty``.
 
+- Improved :doc:`readability-duplicate-include
+  <clang-tidy/checks/readability/duplicate-include>` check by adding
+  the ``IgnoredFilesList`` option (semicolon-separated list of regexes or
+  filenames) to allow intentional duplicates.
+
 - Improved :doc:`readability-identifier-naming
   <clang-tidy/checks/readability/identifier-naming>` check by ignoring
   declarations and macros in system headers. The documentation is also improved
diff --git 
a/clang-tools-extra/docs/clang-tidy/checks/readability/duplicate-include.rst 
b/clang-tools-extra/docs/clang-tidy/checks/readability/duplicate-include.rst
index 45df7e1b84f3f..b2b03a51b25e8 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/readability/duplicate-include.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/duplicate-include.rst
@@ -7,6 +7,17 @@ Looks for duplicate includes and removes them.  The check 
maintains a list of
 included files and looks for duplicates.  If a macro is defined or undefined
 then the list of included files is cleared.
 
+Options
+-------
+
+.. option:: IgnoredFilesList
+
+  A semicolon-separated list of regular expressions or filenames that are
+  allowed to be included multiple times without diagnostics. Matching is
+  performed against the textual include name. If the header can be
+  resolved, its full path is also matched against the patterns.
+  Default is empty.
+
 Examples:
 
 .. code-block:: c++
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/readability/Inputs/duplicate-include/pack_begin.h
 
b/clang-tools-extra/test/clang-tidy/checkers/readability/Inputs/duplicate-include/pack_begin.h
new file mode 100644
index 0000000000000..fc9369c0cfb8f
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/readability/Inputs/duplicate-include/pack_begin.h
@@ -0,0 +1 @@
+// Intentionally unguarded begin-pack header used in tests
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/readability/Inputs/duplicate-include/pack_end.h
 
b/clang-tools-extra/test/clang-tidy/checkers/readability/Inputs/duplicate-include/pack_end.h
new file mode 100644
index 0000000000000..78fd0a9adf475
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/readability/Inputs/duplicate-include/pack_end.h
@@ -0,0 +1 @@
+// Intentionally unguarded end-pack header used in tests
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/readability/duplicate-include-ignored-files.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/readability/duplicate-include-ignored-files.cpp
new file mode 100644
index 0000000000000..91fe1bbb70234
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/readability/duplicate-include-ignored-files.cpp
@@ -0,0 +1,9 @@
+// RUN: %check_clang_tidy %s readability-duplicate-include %t -- \
+// RUN:   -config="{CheckOptions: 
{readability-duplicate-include.IgnoredFilesList: 'pack_.*\\.h'}}" \
+// RUN:   -- -I %S/Inputs/duplicate-include
+
+#include "pack_begin.h"
+struct A { int x; };
+#include "pack_end.h"
+
+// no warning

>From 3a8c80e8bef6ac92a7ab77b20083c4edaa31482e Mon Sep 17 00:00:00 2001
From: mtx <[email protected]>
Date: Sat, 15 Nov 2025 22:56:47 +0800
Subject: [PATCH 2/2] Fix

---
 .../readability/DuplicateIncludeCheck.cpp     | 62 ++++++++++---------
 .../checks/readability/duplicate-include.rst  | 20 +++---
 .../duplicate-include-ignored-files.cpp       | 19 +++++-
 3 files changed, 60 insertions(+), 41 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.cpp 
b/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.cpp
index 6a7324c446cfe..80328639c4dec 100644
--- a/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.cpp
@@ -36,17 +36,7 @@ class DuplicateIncludeCallbacks : public PPCallbacks {
 public:
   DuplicateIncludeCallbacks(DuplicateIncludeCheck &Check,
                             const SourceManager &SM,
-                            const std::vector<StringRef> &IgnoredList)
-      : Check(Check), SM(SM) {
-    // The main file doesn't participate in the FileChanged notification.
-    Files.emplace_back();
-
-    AllowedRegexes.reserve(IgnoredList.size());
-    for (const StringRef &It : IgnoredList) {
-      if (!It.empty())
-        AllowedRegexes.emplace_back(It);
-    }
-  }
+                            const std::vector<StringRef> &IgnoredList);
 
   void FileChanged(SourceLocation Loc, FileChangeReason Reason,
                    SrcMgr::CharacteristicKind FileType,
@@ -67,26 +57,12 @@ class DuplicateIncludeCallbacks : public PPCallbacks {
                       const MacroDirective *Undef) override;
 
 private:
+  bool isAllowedDuplicate(StringRef FileName, OptionalFileEntryRef File) const;
   // A list of included files is kept for each file we enter.
   SmallVector<FileList> Files;
   DuplicateIncludeCheck &Check;
   const SourceManager &SM;
   std::vector<llvm::Regex> AllowedRegexes;
-
-  bool isAllowedDuplicate(StringRef FileName, OptionalFileEntryRef File) const 
{
-    if (llvm::any_of(AllowedRegexes,
-                     [&](const llvm::Regex &R) { return R.match(FileName); }))
-      return true;
-
-    if (File) {
-      const StringRef Resolved = File->getName();
-      if (llvm::any_of(AllowedRegexes,
-                       [&](const llvm::Regex &R) { return R.match(Resolved); 
}))
-        return true;
-    }
-
-    return false;
-  }
 };
 
 } // namespace
@@ -97,6 +73,37 @@ DuplicateIncludeCheck::DuplicateIncludeCheck(StringRef Name,
       IgnoredFilesList(utils::options::parseStringList(
           Options.get("IgnoredFilesList", ""))) {}
 
+DuplicateIncludeCallbacks::DuplicateIncludeCallbacks(
+    DuplicateIncludeCheck &Check, const SourceManager &SM,
+    const std::vector<StringRef> &IgnoredList)
+    : Check(Check), SM(SM) {
+  // The main file doesn't participate in the FileChanged notification.
+  Files.emplace_back();
+
+  AllowedRegexes.reserve(IgnoredList.size());
+  for (const StringRef &It : IgnoredList) {
+    if (!It.empty())
+      AllowedRegexes.emplace_back(It);
+  }
+}
+
+bool DuplicateIncludeCallbacks::isAllowedDuplicate(
+    StringRef FileName, OptionalFileEntryRef File) const {
+  if (llvm::any_of(AllowedRegexes, [&FileName](const llvm::Regex &R) {
+        return R.match(FileName);
+      }))
+    return true;
+
+  if (File) {
+    const StringRef Resolved = File->getName();
+    return llvm::any_of(AllowedRegexes, [&Resolved](const llvm::Regex &R) {
+      return R.match(Resolved);
+    });
+  }
+
+  return false;
+}
+
 void DuplicateIncludeCallbacks::FileChanged(SourceLocation Loc,
                                             FileChangeReason Reason,
                                             SrcMgr::CharacteristicKind 
FileType,
@@ -117,9 +124,8 @@ void DuplicateIncludeCallbacks::InclusionDirective(
       FilenameRange.getEnd().isMacroID())
     return;
   if (llvm::is_contained(Files.back(), FileName)) {
-    if (isAllowedDuplicate(FileName, File)) {
+    if (isAllowedDuplicate(FileName, File))
       return;
-    }
     // We want to delete the entire line, so make sure that [Start,End] covers
     // everything.
     const SourceLocation Start =
diff --git 
a/clang-tools-extra/docs/clang-tidy/checks/readability/duplicate-include.rst 
b/clang-tools-extra/docs/clang-tidy/checks/readability/duplicate-include.rst
index b2b03a51b25e8..28a4991a922f8 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/readability/duplicate-include.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/duplicate-include.rst
@@ -7,17 +7,6 @@ Looks for duplicate includes and removes them.  The check 
maintains a list of
 included files and looks for duplicates.  If a macro is defined or undefined
 then the list of included files is cleared.
 
-Options
--------
-
-.. option:: IgnoredFilesList
-
-  A semicolon-separated list of regular expressions or filenames that are
-  allowed to be included multiple times without diagnostics. Matching is
-  performed against the textual include name. If the header can be
-  resolved, its full path is also matched against the patterns.
-  Default is empty.
-
 Examples:
 
 .. code-block:: c++
@@ -44,3 +33,12 @@ Because of the intervening macro definitions, this code 
remains unchanged:
   #define NDEBUG
   #include "assertion.h"
   // ...code with assertions disabled
+
+Options
+-------
+
+.. option:: IgnoredFilesList
+
+  A semicolon-separated list of regular expressions or filenames that are
+  allowed to be included multiple times without diagnostics. Matching is
+  performed against the textual include name. Default is an empty string.
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/readability/duplicate-include-ignored-files.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/readability/duplicate-include-ignored-files.cpp
index 91fe1bbb70234..0591cc6617eec 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/readability/duplicate-include-ignored-files.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/readability/duplicate-include-ignored-files.cpp
@@ -1,9 +1,24 @@
 // RUN: %check_clang_tidy %s readability-duplicate-include %t -- \
-// RUN:   -config="{CheckOptions: 
{readability-duplicate-include.IgnoredFilesList: 'pack_.*\\.h'}}" \
+// RUN:   -config="{CheckOptions: 
{readability-duplicate-include.IgnoredFilesList: 'pack_.*\\.h'}}" 
-header-filter='' \
 // RUN:   -- -I %S/Inputs/duplicate-include
 
+int g;
+#include "duplicate-include.h"
+int h;
+#include "duplicate-include.h"
+int i;
+// CHECK-MESSAGES: :[[@LINE-2]]:1: warning: duplicate include 
[readability-duplicate-include]
+// CHECK-FIXES:      int g;
+// CHECK-FIXES-NEXT: #include "duplicate-include.h"
+// CHECK-FIXES-NEXT: int h;
+// CHECK-FIXES-NEXT: int i;
+
 #include "pack_begin.h"
 struct A { int x; };
 #include "pack_end.h"
 
-// no warning
+#include "pack_begin.h"
+struct B { int x; };
+#include "pack_end.h"
+
+// No warning here.

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

Reply via email to