Author: mitchell
Date: 2025-11-20T07:52:39+08:00
New Revision: 2aa2290af51a033849878b30ee30aae5d11394f3

URL: 
https://github.com/llvm/llvm-project/commit/2aa2290af51a033849878b30ee30aae5d11394f3
DIFF: 
https://github.com/llvm/llvm-project/commit/2aa2290af51a033849878b30ee30aae5d11394f3.diff

LOG: [clang-tidy] Add `IgnoredFilesList` option to 
`readability-duplicate-include` (#168196)

Closes [#166938](https://github.com/llvm/llvm-project/issues/166938)

Added: 
    
clang-tools-extra/test/clang-tidy/checkers/readability/Inputs/duplicate-include/pack_begin.h
    
clang-tools-extra/test/clang-tidy/checkers/readability/Inputs/duplicate-include/pack_end.h
    
clang-tools-extra/test/clang-tidy/checkers/readability/duplicate-include-ignored-files.cpp

Modified: 
    clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.cpp
    clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.h
    clang-tools-extra/docs/ReleaseNotes.rst
    clang-tools-extra/docs/clang-tidy/checks/readability/duplicate-include.rst

Removed: 
    


################################################################################
diff  --git 
a/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.cpp 
b/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.cpp
index cc9ae471a926d..4842fe22a8890 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,11 +35,8 @@ using FileList = SmallVector<StringRef>;
 class DuplicateIncludeCallbacks : public PPCallbacks {
 public:
   DuplicateIncludeCallbacks(DuplicateIncludeCheck &Check,
-                            const SourceManager &SM)
-      : Check(Check), SM(SM) {
-    // The main file doesn't participate in the FileChanged notification.
-    Files.emplace_back();
-  }
+                            const SourceManager &SM,
+                            llvm::ArrayRef<StringRef> IgnoredList);
 
   void FileChanged(SourceLocation Loc, FileChangeReason Reason,
                    SrcMgr::CharacteristicKind FileType,
@@ -62,10 +61,31 @@ class DuplicateIncludeCallbacks : public PPCallbacks {
   SmallVector<FileList> Files;
   DuplicateIncludeCheck &Check;
   const SourceManager &SM;
+  SmallVector<llvm::Regex> AllowedRegexes;
 };
 
 } // namespace
 
+DuplicateIncludeCheck::DuplicateIncludeCheck(StringRef Name,
+                                             ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      IgnoredFilesList(utils::options::parseStringList(
+          Options.get("IgnoredFilesList", ""))) {}
+
+DuplicateIncludeCallbacks::DuplicateIncludeCallbacks(
+    DuplicateIncludeCheck &Check, const SourceManager &SM,
+    llvm::ArrayRef<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 DuplicateIncludeCallbacks::FileChanged(SourceLocation Loc,
                                             FileChangeReason Reason,
                                             SrcMgr::CharacteristicKind 
FileType,
@@ -78,7 +98,7 @@ void DuplicateIncludeCallbacks::FileChanged(SourceLocation 
Loc,
 
 void DuplicateIncludeCallbacks::InclusionDirective(
     SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
-    bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,
+    bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef 
/*File*/,
     StringRef SearchPath, StringRef RelativePath, const Module 
*SuggestedModule,
     bool ModuleImported, SrcMgr::CharacteristicKind FileType) {
   // Skip includes behind macros
@@ -86,6 +106,10 @@ void DuplicateIncludeCallbacks::InclusionDirective(
       FilenameRange.getEnd().isMacroID())
     return;
   if (llvm::is_contained(Files.back(), FileName)) {
+    if (llvm::any_of(AllowedRegexes, [&FileName](const llvm::Regex &R) {
+          return R.match(FileName);
+        }))
+      return;
     // We want to delete the entire line, so make sure that [Start,End] covers
     // everything.
     const SourceLocation Start =
@@ -111,7 +135,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..1ee5b1c209ff7 100644
--- a/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.h
@@ -19,11 +19,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 dc8abd88899a4..a6f80e3721db1 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -527,6 +527,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..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
@@ -33,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/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..cdc2f44432d76
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/readability/duplicate-include-ignored-files.cpp
@@ -0,0 +1,24 @@
+// RUN: %check_clang_tidy %s readability-duplicate-include %t -- \
+// RUN:   -config="{CheckOptions: 
{readability-duplicate-include.IgnoredFilesList: 'pack_.*\\.h'}}" \
+// RUN:   -header-filter='' -- -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"
+
+#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