clang-tools 17.0.0git
DuplicateIncludeCheck.cpp
Go to the documentation of this file.
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//===----------------------------------------------------------------------===//
8
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>
15
17
18static 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;
27}
28
29namespace {
30
31using FileList = SmallVector<StringRef>;
32
33class DuplicateIncludeCallbacks : public PPCallbacks {
34public:
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();
40 }
41
42 void FileChanged(SourceLocation Loc, FileChangeReason Reason,
43 SrcMgr::CharacteristicKind FileType,
44 FileID PrevFID) override;
45
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 *Imported,
51 SrcMgr::CharacteristicKind FileType) override;
52
53 void MacroDefined(const Token &MacroNameTok,
54 const MacroDirective *MD) override;
55
56 void MacroUndefined(const Token &MacroNameTok, const MacroDefinition &MD,
57 const MacroDirective *Undef) override;
58
59private:
60 // A list of included files is kept for each file we enter.
61 SmallVector<FileList> Files;
62 DuplicateIncludeCheck &Check;
63 const SourceManager &SM;
64};
65
66void DuplicateIncludeCallbacks::FileChanged(SourceLocation Loc,
67 FileChangeReason Reason,
68 SrcMgr::CharacteristicKind FileType,
69 FileID PrevFID) {
70 if (Reason == EnterFile)
71 Files.emplace_back();
72 else if (Reason == ExitFile)
73 Files.pop_back();
74}
75
76void DuplicateIncludeCallbacks::InclusionDirective(
77 SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
78 bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,
79 StringRef SearchPath, StringRef RelativePath, const Module *Imported,
80 SrcMgr::CharacteristicKind FileType) {
81 if (llvm::is_contained(Files.back(), FileName)) {
82 // We want to delete the entire line, so make sure that [Start,End] covers
83 // everything.
84 SourceLocation Start =
85 advanceBeyondCurrentLine(SM, HashLoc, -1).getLocWithOffset(-1);
86 SourceLocation End =
87 advanceBeyondCurrentLine(SM, FilenameRange.getEnd(), 1);
88 Check.diag(HashLoc, "duplicate include")
89 << FixItHint::CreateRemoval(SourceRange{Start, End});
90 } else
91 Files.back().push_back(FileName);
92}
93
94void DuplicateIncludeCallbacks::MacroDefined(const Token &MacroNameTok,
95 const MacroDirective *MD) {
96 Files.back().clear();
97}
98
99void DuplicateIncludeCallbacks::MacroUndefined(const Token &MacroNameTok,
100 const MacroDefinition &MD,
101 const MacroDirective *Undef) {
102 Files.back().clear();
103}
104
105} // namespace
106
108 const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
109 PP->addPPCallbacks(std::make_unique<DuplicateIncludeCallbacks>(*this, SM));
110}
111
112} // namespace clang::tidy::readability
size_t Offset
bool IsAngled
true if this was an include with angle brackets
StringRef FileName
SourceLocation Loc
void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) override
Override this to register PPCallbacks in the preprocessor.
static SourceLocation advanceBeyondCurrentLine(const SourceManager &SM, SourceLocation Start, int Offset)