1 //===-------- IncludeInserter.cpp - clang-tidy ----------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "IncludeInserter.h"
11 #include "clang/Lex/Token.h"
12 
13 namespace clang {
14 namespace tidy {
15 namespace utils {
16 
17 class IncludeInserterCallback : public PPCallbacks {
18 public:
19   explicit IncludeInserterCallback(IncludeInserter *Inserter)
20       : Inserter(Inserter) {}
21   // Implements PPCallbacks::InclusionDerective(). 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                           const FileEntry * /*IncludedFile*/,
27                           StringRef /*SearchPath*/, StringRef /*RelativePath*/,
28                           const Module * /*ImportedModule*/) override {
29     Inserter->AddInclude(FileNameRef, IsAngled, HashLocation,
30                          IncludeToken.getEndLoc());
31   }
32 
33 private:
34   IncludeInserter *Inserter;
35 };
36 
37 IncludeInserter::IncludeInserter(const SourceManager &SourceMgr,
38                                  const LangOptions &LangOpts,
39                                  IncludeSorter::IncludeStyle Style)
40     : SourceMgr(SourceMgr), LangOpts(LangOpts), Style(Style) {}
41 
42 IncludeInserter::~IncludeInserter() {}
43 
44 std::unique_ptr<PPCallbacks> IncludeInserter::CreatePPCallbacks() {
45   return llvm::make_unique<IncludeInserterCallback>(this);
46 }
47 
48 llvm::Optional<FixItHint>
49 IncludeInserter::CreateIncludeInsertion(FileID FileID, StringRef Header,
50                                         bool IsAngled) {
51   // We assume the same Header will never be included both angled and not
52   // angled.
53   if (!InsertedHeaders[FileID].insert(Header).second)
54     return llvm::None;
55 
56   if (IncludeSorterByFile.find(FileID) == IncludeSorterByFile.end()) {
57     // This may happen if there have been no preprocessor directives in this
58     // file.
59     IncludeSorterByFile.insert(std::make_pair(
60         FileID,
61         llvm::make_unique<IncludeSorter>(
62             &SourceMgr, &LangOpts, FileID,
63             SourceMgr.getFilename(SourceMgr.getLocForStartOfFile(FileID)),
64             Style)));
65   }
66   return IncludeSorterByFile[FileID]->CreateIncludeInsertion(Header, IsAngled);
67 }
68 
69 void IncludeInserter::AddInclude(StringRef FileName, bool IsAngled,
70                                  SourceLocation HashLocation,
71                                  SourceLocation EndLocation) {
72   FileID FileID = SourceMgr.getFileID(HashLocation);
73   if (IncludeSorterByFile.find(FileID) == IncludeSorterByFile.end()) {
74     IncludeSorterByFile.insert(std::make_pair(
75         FileID, llvm::make_unique<IncludeSorter>(
76                     &SourceMgr, &LangOpts, FileID,
77                     SourceMgr.getFilename(HashLocation), Style)));
78   }
79   IncludeSorterByFile[FileID]->AddInclude(FileName, IsAngled, HashLocation,
80                                           EndLocation);
81 }
82 
83 } // namespace utils
84 } // namespace tidy
85 } // namespace clang
86