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);
88void DuplicateIncludeCallbacks::FileChanged(SourceLocation Loc,
89 FileChangeReason Reason,
90 SrcMgr::CharacteristicKind FileType,
92 if (Reason == EnterFile)
94 else if (Reason == ExitFile)
98void DuplicateIncludeCallbacks::InclusionDirective(
99 SourceLocation HashLoc,
const Token &IncludeTok, StringRef FileName,
100 bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef ,
101 StringRef SearchPath, StringRef RelativePath,
const Module *SuggestedModule,
102 bool ModuleImported, SrcMgr::CharacteristicKind FileType) {
104 if (FilenameRange.getBegin().isMacroID() ||
105 FilenameRange.getEnd().isMacroID())
107 if (llvm::is_contained(Files.back(), FileName)) {
108 if (llvm::any_of(AllowedRegexes, [&FileName](
const llvm::Regex &R) {
109 return R.match(FileName);
114 const SourceLocation Start =
115 advanceBeyondCurrentLine(SM, HashLoc, -1).getLocWithOffset(-1);
116 const SourceLocation End =
117 advanceBeyondCurrentLine(SM, FilenameRange.getEnd(), 1);
118 Check.diag(HashLoc,
"duplicate include")
119 << FixItHint::CreateRemoval(SourceRange{Start, End});
121 Files.back().push_back(FileName);
124void DuplicateIncludeCallbacks::MacroDefined(
const Token &MacroNameTok,
125 const MacroDirective *MD) {
126 Files.back().clear();
129void DuplicateIncludeCallbacks::MacroUndefined(
const Token &MacroNameTok,
130 const MacroDefinition &MD,
131 const MacroDirective *Undef) {
132 Files.back().clear();
136 const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
138 std::make_unique<DuplicateIncludeCallbacks>(*
this, SM, IgnoredFilesList));
142 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