11#include "clang/Frontend/CompilerInstance.h"
12#include "clang/Lex/Preprocessor.h"
13#include "llvm/ADT/STLExtras.h"
14#include "llvm/ADT/SmallVector.h"
15#include "llvm/Support/Regex.h"
23 const FileID Id = SM.getFileID(Start);
24 const unsigned LineNumber = SM.getSpellingLineNumber(Start);
25 while (SM.getFileID(Start) == Id &&
26 SM.getSpellingLineNumber(Start.getLocWithOffset(Offset)) == LineNumber)
27 Start = Start.getLocWithOffset(Offset);
33using FileList = SmallVector<StringRef>;
35class DuplicateIncludeCallbacks :
public PPCallbacks {
37 DuplicateIncludeCallbacks(DuplicateIncludeCheck &Check,
38 const SourceManager &SM,
39 llvm::ArrayRef<StringRef> IgnoredList);
41 void FileChanged(SourceLocation Loc, FileChangeReason Reason,
42 SrcMgr::CharacteristicKind FileType,
43 FileID PrevFID)
override;
45 void InclusionDirective(SourceLocation HashLoc,
const Token &IncludeTok,
46 StringRef FileName,
bool IsAngled,
47 CharSourceRange FilenameRange,
48 OptionalFileEntryRef File, StringRef SearchPath,
49 StringRef RelativePath,
const Module *SuggestedModule,
51 SrcMgr::CharacteristicKind FileType)
override;
53 void MacroDefined(
const Token &MacroNameTok,
54 const MacroDirective *MD)
override;
56 void MacroUndefined(
const Token &MacroNameTok,
const MacroDefinition &MD,
57 const MacroDirective *Undef)
override;
61 SmallVector<FileList> Files;
62 DuplicateIncludeCheck &Check;
63 const SourceManager &SM;
64 SmallVector<llvm::Regex> AllowedRegexes;
72 IgnoredFilesList(
utils::options::parseStringList(
73 Options.get(
"IgnoredFilesList",
""))) {}
75DuplicateIncludeCallbacks::DuplicateIncludeCallbacks(
77 llvm::ArrayRef<StringRef> IgnoredList)
78 : Check(Check), SM(SM) {
82 AllowedRegexes.reserve(IgnoredList.size());
83 for (
const StringRef &It : IgnoredList) {
85 AllowedRegexes.emplace_back(It);
89void DuplicateIncludeCallbacks::FileChanged(SourceLocation Loc,
90 FileChangeReason Reason,
91 SrcMgr::CharacteristicKind FileType,
93 if (Reason == EnterFile)
95 else if (Reason == ExitFile)
99void DuplicateIncludeCallbacks::InclusionDirective(
100 SourceLocation HashLoc,
const Token &IncludeTok, StringRef FileName,
101 bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef ,
102 StringRef SearchPath, StringRef RelativePath,
const Module *SuggestedModule,
103 bool ModuleImported, SrcMgr::CharacteristicKind FileType) {
105 if (FilenameRange.getBegin().isMacroID() ||
106 FilenameRange.getEnd().isMacroID())
108 if (llvm::is_contained(Files.back(), FileName)) {
109 if (llvm::any_of(AllowedRegexes, [&FileName](
const llvm::Regex &R) {
110 return R.match(FileName);
115 const SourceLocation Start =
117 const SourceLocation End =
119 Check.diag(HashLoc,
"duplicate include")
120 << FixItHint::CreateRemoval(SourceRange{Start, End});
122 Files.back().push_back(FileName);
125void DuplicateIncludeCallbacks::MacroDefined(
const Token &MacroNameTok,
126 const MacroDirective *MD) {
127 Files.back().clear();
130void DuplicateIncludeCallbacks::MacroUndefined(
const Token &MacroNameTok,
131 const MacroDefinition &MD,
132 const MacroDirective *Undef) {
133 Files.back().clear();
137 const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
139 std::make_unique<DuplicateIncludeCallbacks>(*
this, SM, IgnoredFilesList));
143 Options.store(Opts,
"IgnoredFilesList",
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
Find and remove duplicate include directives.
void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) override
DuplicateIncludeCheck(StringRef Name, ClangTidyContext *Context)
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
static SourceLocation advanceBeyondCurrentLine(const SourceManager &SM, SourceLocation Start, int Offset)
std::string serializeStringList(ArrayRef< StringRef > Strings)
Serialize a sequence of names that can be parsed by parseStringList.
llvm::StringMap< ClangTidyValue > OptionMap