1 //===--- DuplicateIncludeCheck.cpp - clang-tidy ---------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "DuplicateIncludeCheck.h"
10 #include "clang/Frontend/CompilerInstance.h"
11 #include "clang/Lex/Preprocessor.h"
12 #include "llvm/ADT/STLExtras.h"
13 #include "llvm/ADT/SmallVector.h"
18 namespace readability
{
20 static SourceLocation
advanceBeyondCurrentLine(const SourceManager
&SM
,
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
);
33 using FileList
= SmallVector
<StringRef
>;
35 class DuplicateIncludeCallbacks
: public PPCallbacks
{
37 DuplicateIncludeCallbacks(DuplicateIncludeCheck
&Check
,
38 const SourceManager
&SM
)
39 : Check(Check
), SM(SM
) {
40 // The main file doesn't participate in the FileChanged notification.
44 void FileChanged(SourceLocation Loc
, FileChangeReason Reason
,
45 SrcMgr::CharacteristicKind FileType
,
46 FileID PrevFID
) override
;
48 void InclusionDirective(SourceLocation HashLoc
, const Token
&IncludeTok
,
49 StringRef FileName
, bool IsAngled
,
50 CharSourceRange FilenameRange
,
51 Optional
<FileEntryRef
> File
, StringRef SearchPath
,
52 StringRef RelativePath
, const Module
*Imported
,
53 SrcMgr::CharacteristicKind FileType
) override
;
55 void MacroDefined(const Token
&MacroNameTok
,
56 const MacroDirective
*MD
) override
;
58 void MacroUndefined(const Token
&MacroNameTok
, const MacroDefinition
&MD
,
59 const MacroDirective
*Undef
) override
;
62 // A list of included files is kept for each file we enter.
63 SmallVector
<FileList
> Files
;
64 DuplicateIncludeCheck
&Check
;
65 const SourceManager
&SM
;
68 void DuplicateIncludeCallbacks::FileChanged(SourceLocation Loc
,
69 FileChangeReason Reason
,
70 SrcMgr::CharacteristicKind FileType
,
72 if (Reason
== EnterFile
)
74 else if (Reason
== ExitFile
)
78 void DuplicateIncludeCallbacks::InclusionDirective(
79 SourceLocation HashLoc
, const Token
&IncludeTok
, StringRef FileName
,
80 bool IsAngled
, CharSourceRange FilenameRange
, Optional
<FileEntryRef
> File
,
81 StringRef SearchPath
, StringRef RelativePath
, const Module
*Imported
,
82 SrcMgr::CharacteristicKind FileType
) {
83 if (llvm::is_contained(Files
.back(), FileName
)) {
84 // We want to delete the entire line, so make sure that [Start,End] covers
86 SourceLocation Start
=
87 advanceBeyondCurrentLine(SM
, HashLoc
, -1).getLocWithOffset(-1);
89 advanceBeyondCurrentLine(SM
, FilenameRange
.getEnd(), 1);
90 Check
.diag(HashLoc
, "duplicate include")
91 << FixItHint::CreateRemoval(SourceRange
{Start
, End
});
93 Files
.back().push_back(FileName
);
96 void DuplicateIncludeCallbacks::MacroDefined(const Token
&MacroNameTok
,
97 const MacroDirective
*MD
) {
101 void DuplicateIncludeCallbacks::MacroUndefined(const Token
&MacroNameTok
,
102 const MacroDefinition
&MD
,
103 const MacroDirective
*Undef
) {
104 Files
.back().clear();
109 void DuplicateIncludeCheck::registerPPCallbacks(
110 const SourceManager
&SM
, Preprocessor
*PP
, Preprocessor
*ModuleExpanderPP
) {
111 PP
->addPPCallbacks(std::make_unique
<DuplicateIncludeCallbacks
>(*this, SM
));
114 } // namespace readability