1 //===-------- IncludeInserter.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 "IncludeInserter.h"
10 #include "clang/Lex/PPCallbacks.h"
11 #include "clang/Lex/Preprocessor.h"
12 #include "clang/Lex/Token.h"
15 namespace clang::tidy::utils
{
17 class IncludeInserterCallback
: public PPCallbacks
{
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
* /*ImportedModule*/,
29 SrcMgr::CharacteristicKind
/*FileType*/) override
{
30 Inserter
->addInclude(FileNameRef
, IsAngled
, HashLocation
,
31 IncludeToken
.getEndLoc());
35 IncludeInserter
*Inserter
;
38 IncludeInserter::IncludeInserter(IncludeSorter::IncludeStyle Style
,
39 bool SelfContainedDiags
)
40 : Style(Style
), SelfContainedDiags(SelfContainedDiags
) {}
42 void IncludeInserter::registerPreprocessor(Preprocessor
*PP
) {
43 assert(PP
&& "PP shouldn't be null");
44 SourceMgr
= &PP
->getSourceManager();
46 // If this gets registered multiple times, clear the maps
47 if (!IncludeSorterByFile
.empty())
48 IncludeSorterByFile
.clear();
49 if (!InsertedHeaders
.empty())
50 InsertedHeaders
.clear();
51 PP
->addPPCallbacks(std::make_unique
<IncludeInserterCallback
>(this));
54 IncludeSorter
&IncludeInserter::getOrCreate(FileID FileID
) {
55 assert(SourceMgr
&& "SourceMgr shouldn't be null; did you remember to call "
56 "registerPreprocessor()?");
57 // std::unique_ptr is cheap to construct, so force a construction now to save
58 // the lookup needed if we were to insert into the map.
59 std::unique_ptr
<IncludeSorter
> &Entry
= IncludeSorterByFile
[FileID
];
61 // If it wasn't found, Entry will be default constructed to nullptr.
62 Entry
= std::make_unique
<IncludeSorter
>(
64 SourceMgr
->getFilename(SourceMgr
->getLocForStartOfFile(FileID
)), Style
);
69 std::optional
<FixItHint
>
70 IncludeInserter::createIncludeInsertion(FileID FileID
, llvm::StringRef Header
) {
71 bool IsAngled
= Header
.consume_front("<");
72 if (IsAngled
!= Header
.consume_back(">"))
74 // We assume the same Header will never be included both angled and not
76 // In self contained diags mode we don't track what headers we have already
78 if (!SelfContainedDiags
&& !InsertedHeaders
[FileID
].insert(Header
).second
)
81 return getOrCreate(FileID
).createIncludeInsertion(Header
, IsAngled
);
84 std::optional
<FixItHint
>
85 IncludeInserter::createMainFileIncludeInsertion(StringRef Header
) {
86 assert(SourceMgr
&& "SourceMgr shouldn't be null; did you remember to call "
87 "registerPreprocessor()?");
88 return createIncludeInsertion(SourceMgr
->getMainFileID(), Header
);
91 void IncludeInserter::addInclude(StringRef FileName
, bool IsAngled
,
92 SourceLocation HashLocation
,
93 SourceLocation EndLocation
) {
94 assert(SourceMgr
&& "SourceMgr shouldn't be null; did you remember to call "
95 "registerPreprocessor()?");
96 FileID FileID
= SourceMgr
->getFileID(HashLocation
);
97 getOrCreate(FileID
).addInclude(FileName
, IsAngled
, HashLocation
, EndLocation
);
100 } // namespace clang::tidy::utils