aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/include/clang/Serialization/ModuleManager.h
blob: 3bd379acf7eda47336cd133a32b5f67994bafa39 (plain) (blame)
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
//===- ModuleManager.cpp - Module Manager -----------------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
//  This file defines the ModuleManager class, which manages a set of loaded
//  modules for the ASTReader.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_SERIALIZATION_MODULEMANAGER_H
#define LLVM_CLANG_SERIALIZATION_MODULEMANAGER_H

#include "clang/Basic/LLVM.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Serialization/ModuleFile.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/iterator.h"
#include "llvm/ADT/iterator_range.h"
#include <cstdint>
#include <ctime>
#include <memory>
#include <string>
#include <utility>

namespace clang {

class FileEntry;
class FileManager;
class GlobalModuleIndex;
class HeaderSearch;
class InMemoryModuleCache;
class PCHContainerReader;

namespace serialization {

/// Manages the set of modules loaded by an AST reader.
class ModuleManager {
  /// The chain of AST files, in the order in which we started to load
  /// them (this order isn't really useful for anything).
  SmallVector<std::unique_ptr<ModuleFile>, 2> Chain;

  /// The chain of non-module PCH files. The first entry is the one named
  /// by the user, the last one is the one that doesn't depend on anything
  /// further.
  SmallVector<ModuleFile *, 2> PCHChain;

  // The roots of the dependency DAG of AST files. This is used
  // to implement short-circuiting logic when running DFS over the dependencies.
  SmallVector<ModuleFile *, 2> Roots;

  /// All loaded modules, indexed by name.
  llvm::DenseMap<const FileEntry *, ModuleFile *> Modules;

  /// FileManager that handles translating between filenames and
  /// FileEntry *.
  FileManager &FileMgr;

  /// Cache of PCM files.
  IntrusiveRefCntPtr<InMemoryModuleCache> ModuleCache;

  /// Knows how to unwrap module containers.
  const PCHContainerReader &PCHContainerRdr;

  /// Preprocessor's HeaderSearchInfo containing the module map.
  const HeaderSearch &HeaderSearchInfo;

  /// A lookup of in-memory (virtual file) buffers
  llvm::DenseMap<const FileEntry *, std::unique_ptr<llvm::MemoryBuffer>>
      InMemoryBuffers;

  /// The visitation order.
  SmallVector<ModuleFile *, 4> VisitOrder;

  /// The list of module files that both we and the global module index
  /// know about.
  ///
  /// Either the global index or the module manager may have modules that the
  /// other does not know about, because the global index can be out-of-date
  /// (in which case the module manager could have modules it does not) and
  /// this particular translation unit might not have loaded all of the modules
  /// known to the global index.
  SmallVector<ModuleFile *, 4> ModulesInCommonWithGlobalIndex;

  /// The global module index, if one is attached.
  ///
  /// The global module index will actually be owned by the ASTReader; this is
  /// just an non-owning pointer.
  GlobalModuleIndex *GlobalIndex = nullptr;

  /// State used by the "visit" operation to avoid malloc traffic in
  /// calls to visit().
  struct VisitState {
    explicit VisitState(unsigned N) : VisitNumber(N, 0) {
      Stack.reserve(N);
    }

    /// The stack used when marking the imports of a particular module
    /// as not-to-be-visited.
    SmallVector<ModuleFile *, 4> Stack;

    /// The visit number of each module file, which indicates when
    /// this module file was last visited.
    SmallVector<unsigned, 4> VisitNumber;

    /// The next visit number to use to mark visited module files.
    unsigned NextVisitNumber = 1;

    /// The next visit state.
    std::unique_ptr<VisitState> NextState;
  };

  /// The first visit() state in the chain.
  std::unique_ptr<VisitState> FirstVisitState;

  std::unique_ptr<VisitState> allocateVisitState();
  void returnVisitState(std::unique_ptr<VisitState> State);

public:
  using ModuleIterator = llvm::pointee_iterator<
      SmallVectorImpl<std::unique_ptr<ModuleFile>>::iterator>;
  using ModuleConstIterator = llvm::pointee_iterator<
      SmallVectorImpl<std::unique_ptr<ModuleFile>>::const_iterator>;
  using ModuleReverseIterator = llvm::pointee_iterator<
      SmallVectorImpl<std::unique_ptr<ModuleFile>>::reverse_iterator>;
  using ModuleOffset = std::pair<uint32_t, StringRef>;

  explicit ModuleManager(FileManager &FileMgr, InMemoryModuleCache &ModuleCache,
                         const PCHContainerReader &PCHContainerRdr,
                         const HeaderSearch &HeaderSearchInfo);

  /// Forward iterator to traverse all loaded modules.
  ModuleIterator begin() { return Chain.begin(); }

  /// Forward iterator end-point to traverse all loaded modules
  ModuleIterator end() { return Chain.end(); }

  /// Const forward iterator to traverse all loaded modules.
  ModuleConstIterator begin() const { return Chain.begin(); }

  /// Const forward iterator end-point to traverse all loaded modules
  ModuleConstIterator end() const { return Chain.end(); }

  /// Reverse iterator to traverse all loaded modules.
  ModuleReverseIterator rbegin() { return Chain.rbegin(); }

  /// Reverse iterator end-point to traverse all loaded modules.
  ModuleReverseIterator rend() { return Chain.rend(); }

  /// A range covering the PCH and preamble module files loaded.
  llvm::iterator_range<SmallVectorImpl<ModuleFile *>::const_iterator>
  pch_modules() const {
    return llvm::make_range(PCHChain.begin(), PCHChain.end());
  }

  /// Returns the primary module associated with the manager, that is,
  /// the first module loaded
  ModuleFile &getPrimaryModule() { return *Chain[0]; }

  /// Returns the primary module associated with the manager, that is,
  /// the first module loaded.
  ModuleFile &getPrimaryModule() const { return *Chain[0]; }

  /// Returns the module associated with the given index
  ModuleFile &operator[](unsigned Index) const { return *Chain[Index]; }

  /// Returns the module associated with the given file name.
  ModuleFile *lookupByFileName(StringRef FileName) const;

  /// Returns the module associated with the given module name.
  ModuleFile *lookupByModuleName(StringRef ModName) const;

  /// Returns the module associated with the given module file.
  ModuleFile *lookup(const FileEntry *File) const;

  /// Returns the in-memory (virtual file) buffer with the given name
  std::unique_ptr<llvm::MemoryBuffer> lookupBuffer(StringRef Name);

  /// Number of modules loaded
  unsigned size() const { return Chain.size(); }

  /// The result of attempting to add a new module.
  enum AddModuleResult {
    /// The module file had already been loaded.
    AlreadyLoaded,

    /// The module file was just loaded in response to this call.
    NewlyLoaded,

    /// The module file is missing.
    Missing,

    /// The module file is out-of-date.
    OutOfDate
  };

  using ASTFileSignatureReader = ASTFileSignature (*)(StringRef);

  /// Attempts to create a new module and add it to the list of known
  /// modules.
  ///
  /// \param FileName The file name of the module to be loaded.
  ///
  /// \param Type The kind of module being loaded.
  ///
  /// \param ImportLoc The location at which the module is imported.
  ///
  /// \param ImportedBy The module that is importing this module, or NULL if
  /// this module is imported directly by the user.
  ///
  /// \param Generation The generation in which this module was loaded.
  ///
  /// \param ExpectedSize The expected size of the module file, used for
  /// validation. This will be zero if unknown.
  ///
  /// \param ExpectedModTime The expected modification time of the module
  /// file, used for validation. This will be zero if unknown.
  ///
  /// \param ExpectedSignature The expected signature of the module file, used
  /// for validation. This will be zero if unknown.
  ///
  /// \param ReadSignature Reads the signature from an AST file without actually
  /// loading it.
  ///
  /// \param Module A pointer to the module file if the module was successfully
  /// loaded.
  ///
  /// \param ErrorStr Will be set to a non-empty string if any errors occurred
  /// while trying to load the module.
  ///
  /// \return A pointer to the module that corresponds to this file name,
  /// and a value indicating whether the module was loaded.
  AddModuleResult addModule(StringRef FileName, ModuleKind Type,
                            SourceLocation ImportLoc,
                            ModuleFile *ImportedBy, unsigned Generation,
                            off_t ExpectedSize, time_t ExpectedModTime,
                            ASTFileSignature ExpectedSignature,
                            ASTFileSignatureReader ReadSignature,
                            ModuleFile *&Module,
                            std::string &ErrorStr);

  /// Remove the modules starting from First (to the end).
  void removeModules(ModuleIterator First);

  /// Add an in-memory buffer the list of known buffers
  void addInMemoryBuffer(StringRef FileName,
                         std::unique_ptr<llvm::MemoryBuffer> Buffer);

  /// Set the global module index.
  void setGlobalIndex(GlobalModuleIndex *Index);

  /// Notification from the AST reader that the given module file
  /// has been "accepted", and will not (can not) be unloaded.
  void moduleFileAccepted(ModuleFile *MF);

  /// Visit each of the modules.
  ///
  /// This routine visits each of the modules, starting with the
  /// "root" modules that no other loaded modules depend on, and
  /// proceeding to the leaf modules, visiting each module only once
  /// during the traversal.
  ///
  /// This traversal is intended to support various "lookup"
  /// operations that can find data in any of the loaded modules.
  ///
  /// \param Visitor A visitor function that will be invoked with each
  /// module. The return value must be convertible to bool; when false, the
  /// visitation continues to modules that the current module depends on. When
  /// true, the visitation skips any modules that the current module depends on.
  ///
  /// \param ModuleFilesHit If non-NULL, contains the set of module files
  /// that we know we need to visit because the global module index told us to.
  /// Any module that is known to both the global module index and the module
  /// manager that is *not* in this set can be skipped.
  void visit(llvm::function_ref<bool(ModuleFile &M)> Visitor,
             llvm::SmallPtrSetImpl<ModuleFile *> *ModuleFilesHit = nullptr);

  /// Attempt to resolve the given module file name to a file entry.
  ///
  /// \param FileName The name of the module file.
  ///
  /// \param ExpectedSize The size that the module file is expected to have.
  /// If the actual size differs, the resolver should return \c true.
  ///
  /// \param ExpectedModTime The modification time that the module file is
  /// expected to have. If the actual modification time differs, the resolver
  /// should return \c true.
  ///
  /// \param File Will be set to the file if there is one, or null
  /// otherwise.
  ///
  /// \returns True if a file exists but does not meet the size/
  /// modification time criteria, false if the file is either available and
  /// suitable, or is missing.
  bool lookupModuleFile(StringRef FileName, off_t ExpectedSize,
                        time_t ExpectedModTime, OptionalFileEntryRef &File);

  /// View the graphviz representation of the module graph.
  void viewGraph();

  InMemoryModuleCache &getModuleCache() const { return *ModuleCache; }
};

} // namespace serialization

} // namespace clang

#endif // LLVM_CLANG_SERIALIZATION_MODULEMANAGER_H