1//===-------- IncludeInserter.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
9#include "IncludeInserter.h"
10#include "clang/Lex/PPCallbacks.h"
11#include "clang/Lex/Preprocessor.h"
12#include "clang/Lex/Token.h"
13#include <optional>
14
15namespace clang::tidy::utils {
16
17class IncludeInserterCallback : public PPCallbacks {
18public:
19 explicit IncludeInserterCallback(IncludeInserter *Inserter)
20 : Inserter(Inserter) {}
21 // Implements PPCallbacks::InclusionDirective(). Records the names and source
22 // locations of the inclusions in the main source file being processed.
23 void InclusionDirective(SourceLocation HashLocation,
24 const Token &IncludeToken, StringRef FileNameRef,
25 bool IsAngled, CharSourceRange FileNameRange,
26 OptionalFileEntryRef /*IncludedFile*/,
27 StringRef /*SearchPath*/, StringRef /*RelativePath*/,
28 const Module * /*SuggestedModule*/,
29 bool /*ModuleImported*/,
30 SrcMgr::CharacteristicKind /*FileType*/) override {
31 Inserter->addInclude(FileName: FileNameRef, IsAngled, HashLocation,
32 EndLocation: IncludeToken.getEndLoc());
33 }
34
35private:
36 IncludeInserter *Inserter;
37};
38
39IncludeInserter::IncludeInserter(IncludeSorter::IncludeStyle Style,
40 bool SelfContainedDiags)
41 : Style(Style), SelfContainedDiags(SelfContainedDiags) {}
42
43void IncludeInserter::registerPreprocessor(Preprocessor *PP) {
44 assert(PP && "PP shouldn't be null");
45 SourceMgr = &PP->getSourceManager();
46
47 // If this gets registered multiple times, clear the maps
48 if (!IncludeSorterByFile.empty())
49 IncludeSorterByFile.clear();
50 if (!InsertedHeaders.empty())
51 InsertedHeaders.clear();
52 PP->addPPCallbacks(C: std::make_unique<IncludeInserterCallback>(args: this));
53}
54
55IncludeSorter &IncludeInserter::getOrCreate(FileID FileID) {
56 assert(SourceMgr && "SourceMgr shouldn't be null; did you remember to call "
57 "registerPreprocessor()?");
58 // std::unique_ptr is cheap to construct, so force a construction now to save
59 // the lookup needed if we were to insert into the map.
60 std::unique_ptr<IncludeSorter> &Entry = IncludeSorterByFile[FileID];
61 if (!Entry) {
62 // If it wasn't found, Entry will be default constructed to nullptr.
63 Entry = std::make_unique<IncludeSorter>(
64 args&: SourceMgr, args&: FileID,
65 args: SourceMgr->getFilename(SpellingLoc: SourceMgr->getLocForStartOfFile(FID: FileID)), args: Style);
66 }
67 return *Entry;
68}
69
70std::optional<FixItHint>
71IncludeInserter::createIncludeInsertion(FileID FileID, llvm::StringRef Header) {
72 bool IsAngled = Header.consume_front(Prefix: "<");
73 if (IsAngled != Header.consume_back(Suffix: ">"))
74 return std::nullopt;
75 // We assume the same Header will never be included both angled and not
76 // angled.
77 // In self contained diags mode we don't track what headers we have already
78 // inserted.
79 if (!SelfContainedDiags && !InsertedHeaders[FileID].insert(key: Header).second)
80 return std::nullopt;
81
82 return getOrCreate(FileID).createIncludeInsertion(FileName: Header, IsAngled);
83}
84
85std::optional<FixItHint>
86IncludeInserter::createMainFileIncludeInsertion(StringRef Header) {
87 assert(SourceMgr && "SourceMgr shouldn't be null; did you remember to call "
88 "registerPreprocessor()?");
89 return createIncludeInsertion(FileID: SourceMgr->getMainFileID(), Header);
90}
91
92void IncludeInserter::addInclude(StringRef FileName, bool IsAngled,
93 SourceLocation HashLocation,
94 SourceLocation EndLocation) {
95 assert(SourceMgr && "SourceMgr shouldn't be null; did you remember to call "
96 "registerPreprocessor()?");
97 FileID FileID = SourceMgr->getFileID(SpellingLoc: HashLocation);
98 getOrCreate(FileID).addInclude(FileName, IsAngled, HashLocation, EndLocation);
99}
100
101} // namespace clang::tidy::utils
102

source code of clang-tools-extra/clang-tidy/utils/IncludeInserter.cpp