[docs] Add LICENSE.txt to the root of the mono-repo
[llvm-project.git] / clang-tools-extra / clang-tidy / readability / DuplicateIncludeCheck.cpp
blob22a4e4eeec6d7d1bb6343856a79788b24d7f321e
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 {
17 namespace tidy {
18 namespace readability {
20 static SourceLocation advanceBeyondCurrentLine(const SourceManager &SM,
21 SourceLocation Start,
22 int Offset) {
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);
28 return Start;
31 namespace {
33 using FileList = SmallVector<StringRef>;
35 class DuplicateIncludeCallbacks : public PPCallbacks {
36 public:
37 DuplicateIncludeCallbacks(DuplicateIncludeCheck &Check,
38 const SourceManager &SM)
39 : Check(Check), SM(SM) {
40 // The main file doesn't participate in the FileChanged notification.
41 Files.emplace_back();
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;
61 private:
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,
71 FileID PrevFID) {
72 if (Reason == EnterFile)
73 Files.emplace_back();
74 else if (Reason == ExitFile)
75 Files.pop_back();
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
85 // everything.
86 SourceLocation Start =
87 advanceBeyondCurrentLine(SM, HashLoc, -1).getLocWithOffset(-1);
88 SourceLocation End =
89 advanceBeyondCurrentLine(SM, FilenameRange.getEnd(), 1);
90 Check.diag(HashLoc, "duplicate include")
91 << FixItHint::CreateRemoval(SourceRange{Start, End});
92 } else
93 Files.back().push_back(FileName);
96 void DuplicateIncludeCallbacks::MacroDefined(const Token &MacroNameTok,
97 const MacroDirective *MD) {
98 Files.back().clear();
101 void DuplicateIncludeCallbacks::MacroUndefined(const Token &MacroNameTok,
102 const MacroDefinition &MD,
103 const MacroDirective *Undef) {
104 Files.back().clear();
107 } // namespace
109 void DuplicateIncludeCheck::registerPPCallbacks(
110 const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
111 PP->addPPCallbacks(std::make_unique<DuplicateIncludeCallbacks>(*this, SM));
114 } // namespace readability
115 } // namespace tidy
116 } // namespace clang