Skip to content

Commit 5c002ef

Browse files
committed
[clang-tidy] Add IgnoredFilesList option to readability-duplicate-include
1 parent e7b41df commit 5c002ef

File tree

7 files changed

+78
-5
lines changed

7 files changed

+78
-5
lines changed

clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.cpp

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "DuplicateIncludeCheck.h"
10+
#include "../utils/OptionsUtils.h"
1011
#include "clang/Frontend/CompilerInstance.h"
1112
#include "clang/Lex/Preprocessor.h"
1213
#include "llvm/ADT/STLExtras.h"
1314
#include "llvm/ADT/SmallVector.h"
15+
#include "llvm/Support/Regex.h"
1416
#include <memory>
1517

1618
namespace clang::tidy::readability {
@@ -33,10 +35,17 @@ using FileList = SmallVector<StringRef>;
3335
class DuplicateIncludeCallbacks : public PPCallbacks {
3436
public:
3537
DuplicateIncludeCallbacks(DuplicateIncludeCheck &Check,
36-
const SourceManager &SM)
38+
const SourceManager &SM,
39+
const std::vector<StringRef> &IgnoredList)
3740
: Check(Check), SM(SM) {
3841
// The main file doesn't participate in the FileChanged notification.
3942
Files.emplace_back();
43+
44+
AllowedRegexes.reserve(IgnoredList.size());
45+
for (const StringRef &It : IgnoredList) {
46+
if (!It.empty())
47+
AllowedRegexes.emplace_back(It);
48+
}
4049
}
4150

4251
void FileChanged(SourceLocation Loc, FileChangeReason Reason,
@@ -62,10 +71,32 @@ class DuplicateIncludeCallbacks : public PPCallbacks {
6271
SmallVector<FileList> Files;
6372
DuplicateIncludeCheck &Check;
6473
const SourceManager &SM;
74+
std::vector<llvm::Regex> AllowedRegexes;
75+
76+
bool isAllowedDuplicate(StringRef FileName, OptionalFileEntryRef File) const {
77+
if (llvm::any_of(AllowedRegexes,
78+
[&](const llvm::Regex &R) { return R.match(FileName); }))
79+
return true;
80+
81+
if (File) {
82+
const StringRef Resolved = File->getName();
83+
if (llvm::any_of(AllowedRegexes,
84+
[&](const llvm::Regex &R) { return R.match(Resolved); }))
85+
return true;
86+
}
87+
88+
return false;
89+
}
6590
};
6691

6792
} // namespace
6893

94+
DuplicateIncludeCheck::DuplicateIncludeCheck(StringRef Name,
95+
ClangTidyContext *Context)
96+
: ClangTidyCheck(Name, Context),
97+
IgnoredFilesList(utils::options::parseStringList(
98+
Options.get("IgnoredFilesList", ""))) {}
99+
69100
void DuplicateIncludeCallbacks::FileChanged(SourceLocation Loc,
70101
FileChangeReason Reason,
71102
SrcMgr::CharacteristicKind FileType,
@@ -86,6 +117,9 @@ void DuplicateIncludeCallbacks::InclusionDirective(
86117
FilenameRange.getEnd().isMacroID())
87118
return;
88119
if (llvm::is_contained(Files.back(), FileName)) {
120+
if (isAllowedDuplicate(FileName, File)) {
121+
return;
122+
}
89123
// We want to delete the entire line, so make sure that [Start,End] covers
90124
// everything.
91125
const SourceLocation Start =
@@ -111,7 +145,13 @@ void DuplicateIncludeCallbacks::MacroUndefined(const Token &MacroNameTok,
111145

112146
void DuplicateIncludeCheck::registerPPCallbacks(
113147
const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
114-
PP->addPPCallbacks(std::make_unique<DuplicateIncludeCallbacks>(*this, SM));
148+
PP->addPPCallbacks(
149+
std::make_unique<DuplicateIncludeCallbacks>(*this, SM, IgnoredFilesList));
150+
}
151+
152+
void DuplicateIncludeCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
153+
Options.store(Opts, "IgnoredFilesList",
154+
utils::options::serializeStringList(IgnoredFilesList));
115155
}
116156

117157
} // namespace clang::tidy::readability

clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_DUPLICATEINCLUDECHECK_H
1111

1212
#include "../ClangTidyCheck.h"
13+
#include <vector>
1314

1415
namespace clang::tidy::readability {
1516

@@ -19,11 +20,16 @@ namespace clang::tidy::readability {
1920
/// directives between them are analyzed.
2021
class DuplicateIncludeCheck : public ClangTidyCheck {
2122
public:
22-
DuplicateIncludeCheck(StringRef Name, ClangTidyContext *Context)
23-
: ClangTidyCheck(Name, Context) {}
23+
DuplicateIncludeCheck(StringRef Name, ClangTidyContext *Context);
2424

2525
void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
2626
Preprocessor *ModuleExpanderPP) override;
27+
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
28+
29+
private:
30+
// Semicolon-separated list of regexes or file names to ignore from duplicate
31+
// warnings.
32+
const std::vector<StringRef> IgnoredFilesList;
2733
};
2834

2935
} // namespace clang::tidy::readability

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ Changes in existing checks
316316
exceptions from captures are now diagnosed, exceptions in the bodies of
317317
lambdas that aren't actually invoked are not. Additionally, fixed an issue
318318
where the check wouldn't diagnose throws in arguments to functions or
319-
constructors. Added fine-grained configuration via options
319+
constructors. Added fine-grained configuration via options
320320
`CheckDestructors`, `CheckMoveMemberFunctions`, `CheckMain`,
321321
`CheckedSwapFunctions`, and `CheckNothrowFunctions`.
322322

@@ -505,6 +505,11 @@ Changes in existing checks
505505
ignoring default constructors with user provided arguments and adding
506506
detection in container's method except ``empty``.
507507

508+
- Improved :doc:`readability-duplicate-include
509+
<clang-tidy/checks/readability/duplicate-include>` check by adding
510+
the ``IgnoredFilesList`` option (semicolon-separated list of regexes or
511+
filenames) to allow intentional duplicates.
512+
508513
- Improved :doc:`readability-identifier-naming
509514
<clang-tidy/checks/readability/identifier-naming>` check by ignoring
510515
declarations and macros in system headers. The documentation is also improved

clang-tools-extra/docs/clang-tidy/checks/readability/duplicate-include.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,17 @@ Looks for duplicate includes and removes them. The check maintains a list of
77
included files and looks for duplicates. If a macro is defined or undefined
88
then the list of included files is cleared.
99

10+
Options
11+
-------
12+
13+
.. option:: IgnoredFilesList
14+
15+
A semicolon-separated list of regular expressions or filenames that are
16+
allowed to be included multiple times without diagnostics. Matching is
17+
performed against the textual include name. If the header can be
18+
resolved, its full path is also matched against the patterns.
19+
Default is empty.
20+
1021
Examples:
1122

1223
.. code-block:: c++
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// Intentionally unguarded begin-pack header used in tests
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// Intentionally unguarded end-pack header used in tests
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: %check_clang_tidy %s readability-duplicate-include %t -- \
2+
// RUN: -config="{CheckOptions: {readability-duplicate-include.IgnoredFilesList: 'pack_.*\\.h'}}" \
3+
// RUN: -- -I %S/Inputs/duplicate-include
4+
5+
#include "pack_begin.h"
6+
struct A { int x; };
7+
#include "pack_end.h"
8+
9+
// no warning

0 commit comments

Comments
 (0)