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
