aboutsummaryrefslogtreecommitdiff
path: root/clang-tools-extra/clang-tidy/utils/IncludeInserter.cpp
blob: 144ebdf5dbbfe38fc2c2b1c078619c3b17ab08a2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
//===-------- IncludeInserter.cpp - clang-tidy ----------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "IncludeInserter.h"
#include "clang/Lex/PPCallbacks.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/Token.h"

namespace clang {
namespace tidy {
namespace utils {

class IncludeInserterCallback : public PPCallbacks {
public:
  explicit IncludeInserterCallback(IncludeInserter *Inserter)
      : Inserter(Inserter) {}
  // Implements PPCallbacks::InclusionDirective(). Records the names and source
  // locations of the inclusions in the main source file being processed.
  void InclusionDirective(SourceLocation HashLocation,
                          const Token &IncludeToken, StringRef FileNameRef,
                          bool IsAngled, CharSourceRange FileNameRange,
                          Optional<FileEntryRef> /*IncludedFile*/,
                          StringRef /*SearchPath*/, StringRef /*RelativePath*/,
                          const Module * /*ImportedModule*/,
                          SrcMgr::CharacteristicKind /*FileType*/) override {
    Inserter->addInclude(FileNameRef, IsAngled, HashLocation,
                         IncludeToken.getEndLoc());
  }

private:
  IncludeInserter *Inserter;
};

IncludeInserter::IncludeInserter(IncludeSorter::IncludeStyle Style,
                                 bool SelfContainedDiags)
    : Style(Style), SelfContainedDiags(SelfContainedDiags) {}

void IncludeInserter::registerPreprocessor(Preprocessor *PP) {
  assert(PP && "PP shouldn't be null");
  SourceMgr = &PP->getSourceManager();

  // If this gets registered multiple times, clear the maps
  if (!IncludeSorterByFile.empty())
    IncludeSorterByFile.clear();
  if (!InsertedHeaders.empty())
    InsertedHeaders.clear();
  PP->addPPCallbacks(std::make_unique<IncludeInserterCallback>(this));
}

IncludeSorter &IncludeInserter::getOrCreate(FileID FileID) {
  assert(SourceMgr && "SourceMgr shouldn't be null; did you remember to call "
                      "registerPreprocessor()?");
  // std::unique_ptr is cheap to construct, so force a construction now to save
  // the lookup needed if we were to insert into the map.
  std::unique_ptr<IncludeSorter> &Entry = IncludeSorterByFile[FileID];
  if (!Entry) {
    // If it wasn't found, Entry will be default constructed to nullptr.
    Entry = std::make_unique<IncludeSorter>(
        SourceMgr, FileID,
        SourceMgr->getFilename(SourceMgr->getLocForStartOfFile(FileID)), Style);
  }
  return *Entry;
}

llvm::Optional<FixItHint>
IncludeInserter::createIncludeInsertion(FileID FileID, llvm::StringRef Header) {
  bool IsAngled = Header.consume_front("<");
  if (IsAngled != Header.consume_back(">"))
    return llvm::None;
  // We assume the same Header will never be included both angled and not
  // angled.
  // In self contained diags mode we don't track what headers we have already
  // inserted.
  if (!SelfContainedDiags && !InsertedHeaders[FileID].insert(Header).second)
    return llvm::None;

  return getOrCreate(FileID).createIncludeInsertion(Header, IsAngled);
}

llvm::Optional<FixItHint>
IncludeInserter::createMainFileIncludeInsertion(StringRef Header) {
  assert(SourceMgr && "SourceMgr shouldn't be null; did you remember to call "
                      "registerPreprocessor()?");
  return createIncludeInsertion(SourceMgr->getMainFileID(), Header);
}

void IncludeInserter::addInclude(StringRef FileName, bool IsAngled,
                                 SourceLocation HashLocation,
                                 SourceLocation EndLocation) {
  assert(SourceMgr && "SourceMgr shouldn't be null; did you remember to call "
                      "registerPreprocessor()?");
  FileID FileID = SourceMgr->getFileID(HashLocation);
  getOrCreate(FileID).addInclude(FileName, IsAngled, HashLocation, EndLocation);
}

} // namespace utils
} // namespace tidy
} // namespace clang