[TargetVersion] Only enable on RISC-V and AArch64 (#115991)
[llvm-project.git] / clang-tools-extra / clang-tidy / readability / DuplicateIncludeCheck.cpp
blob229e5583846b96c0a4ddc537bc78d7a4467fa355
1 //===--- DuplicateIncludeCheck.cpp - clang-tidy ---------------------------===//
2 //
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
6 //
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"
14 #include <memory>
16 namespace clang::tidy::readability {
18 static SourceLocation advanceBeyondCurrentLine(const SourceManager &SM,
19 SourceLocation Start,
20 int Offset) {
21 const FileID Id = SM.getFileID(Start);
22 const unsigned LineNumber = SM.getSpellingLineNumber(Start);
23 while (SM.getFileID(Start) == Id &&
24 SM.getSpellingLineNumber(Start.getLocWithOffset(Offset)) == LineNumber)
25 Start = Start.getLocWithOffset(Offset);
26 return Start;
29 namespace {
31 using FileList = SmallVector<StringRef>;
33 class DuplicateIncludeCallbacks : public PPCallbacks {
34 public:
35 DuplicateIncludeCallbacks(DuplicateIncludeCheck &Check,
36 const SourceManager &SM)
37 : Check(Check), SM(SM) {
38 // The main file doesn't participate in the FileChanged notification.
39 Files.emplace_back();
42 void FileChanged(SourceLocation Loc, FileChangeReason Reason,
43 SrcMgr::CharacteristicKind FileType,
44 FileID PrevFID) override;
46 void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
47 StringRef FileName, bool IsAngled,
48 CharSourceRange FilenameRange,
49 OptionalFileEntryRef File, StringRef SearchPath,
50 StringRef RelativePath, const Module *SuggestedModule,
51 bool ModuleImported,
52 SrcMgr::CharacteristicKind FileType) override;
54 void MacroDefined(const Token &MacroNameTok,
55 const MacroDirective *MD) override;
57 void MacroUndefined(const Token &MacroNameTok, const MacroDefinition &MD,
58 const MacroDirective *Undef) override;
60 private:
61 // A list of included files is kept for each file we enter.
62 SmallVector<FileList> Files;
63 DuplicateIncludeCheck &Check;
64 const SourceManager &SM;
67 void DuplicateIncludeCallbacks::FileChanged(SourceLocation Loc,
68 FileChangeReason Reason,
69 SrcMgr::CharacteristicKind FileType,
70 FileID PrevFID) {
71 if (Reason == EnterFile)
72 Files.emplace_back();
73 else if (Reason == ExitFile)
74 Files.pop_back();
77 void DuplicateIncludeCallbacks::InclusionDirective(
78 SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
79 bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,
80 StringRef SearchPath, StringRef RelativePath, const Module *SuggestedModule,
81 bool ModuleImported, SrcMgr::CharacteristicKind FileType) {
82 // Skip includes behind macros
83 if (FilenameRange.getBegin().isMacroID() ||
84 FilenameRange.getEnd().isMacroID())
85 return;
86 if (llvm::is_contained(Files.back(), FileName)) {
87 // We want to delete the entire line, so make sure that [Start,End] covers
88 // everything.
89 SourceLocation Start =
90 advanceBeyondCurrentLine(SM, HashLoc, -1).getLocWithOffset(-1);
91 SourceLocation End =
92 advanceBeyondCurrentLine(SM, FilenameRange.getEnd(), 1);
93 Check.diag(HashLoc, "duplicate include")
94 << FixItHint::CreateRemoval(SourceRange{Start, End});
95 } else
96 Files.back().push_back(FileName);
99 void DuplicateIncludeCallbacks::MacroDefined(const Token &MacroNameTok,
100 const MacroDirective *MD) {
101 Files.back().clear();
104 void DuplicateIncludeCallbacks::MacroUndefined(const Token &MacroNameTok,
105 const MacroDefinition &MD,
106 const MacroDirective *Undef) {
107 Files.back().clear();
110 } // namespace
112 void DuplicateIncludeCheck::registerPPCallbacks(
113 const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
114 PP->addPPCallbacks(std::make_unique<DuplicateIncludeCallbacks>(*this, SM));
117 } // namespace clang::tidy::readability