clang 23.0.0git
ModuleManager.cpp
Go to the documentation of this file.
1//===- ModuleManager.cpp - Module Manager ---------------------------------===//
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// This file defines the ModuleManager class, which manages a set of loaded
10// modules for the ASTReader.
11//
12//===----------------------------------------------------------------------===//
13
16#include "clang/Basic/LLVM.h"
18#include "clang/Lex/ModuleMap.h"
24#include "llvm/ADT/STLExtras.h"
25#include "llvm/ADT/SetVector.h"
26#include "llvm/ADT/SmallPtrSet.h"
27#include "llvm/ADT/SmallVector.h"
28#include "llvm/ADT/StringRef.h"
29#include "llvm/ADT/iterator.h"
30#include "llvm/Support/DOTGraphTraits.h"
31#include "llvm/Support/Error.h"
32#include "llvm/Support/ErrorOr.h"
33#include "llvm/Support/GraphWriter.h"
34#include "llvm/Support/MemoryBuffer.h"
35#include "llvm/Support/VirtualFileSystem.h"
36#include <cassert>
37#include <memory>
38#include <string>
39#include <system_error>
40
41using namespace clang;
42using namespace serialization;
43
44std::optional<ModuleFileKey>
46 if (unsigned SuffixLen = Name.getImplicitModuleSuffixLength()) {
47 StringRef ModuleCachePath = StringRef(Name).drop_back(SuffixLen);
48 StringRef ImplicitModuleSuffix = StringRef(Name).take_back(SuffixLen);
49 if (auto *ModuleCacheDir = ModCache.getDirectoryPtr(ModuleCachePath))
50 return ModuleFileKey(ModuleCacheDir, ImplicitModuleSuffix);
51 } else {
52 if (auto ModuleFile = FileMgr.getOptionalFileRef(Name, /*OpenFile=*/true,
53 /*CacheFailure=*/false,
54 /*IsText=*/false))
56 }
57
58 return std::nullopt;
59}
60
62 if (const Module *Mod = HeaderSearchInfo.getModuleMap().findModule(Name))
63 if (const ModuleFileName *FileName = Mod->getASTFileName())
65
66 return nullptr;
67}
68
70 std::optional<ModuleFileKey> Key = makeKey(Name);
71 return Key ? lookup(*Key) : nullptr;
72}
73
75 return Modules.lookup(Key);
76}
77
78std::unique_ptr<llvm::MemoryBuffer>
79ModuleManager::lookupBuffer(StringRef Name, off_t &Size, time_t &ModTime) {
80 auto Entry = FileMgr.getOptionalFileRef(Name, /*OpenFile=*/false,
81 /*CacheFailure=*/false,
82 /*IsText=*/false);
83 if (!Entry)
84 return nullptr;
85 Size = Entry->getSize();
86 ModTime = Entry->getModificationTime();
87 return std::move(InMemoryBuffers[*Entry]);
88}
89
90bool ModuleManager::isModuleFileOutOfDate(off_t Size, time_t ModTime,
91 off_t ExpectedSize,
92 time_t ExpectedModTime,
94 bool OutOfDate = false;
95 if (ExpectedSize && ExpectedSize != Size) {
96 Result.Changes.push_back({Change::Size, ExpectedSize, Size});
97 OutOfDate = true;
98 }
99
100 if (ExpectedModTime && ExpectedModTime != ModTime) {
101 Result.Changes.push_back({Change::ModTime, ExpectedModTime, ModTime});
102 OutOfDate = true;
103 }
104
105 return OutOfDate;
106}
107
108bool ModuleManager::checkSignature(ASTFileSignature Signature,
109 ASTFileSignature ExpectedSignature,
111 if (!ExpectedSignature || Signature == ExpectedSignature)
112 return false;
113 Result.SignatureError =
114 Signature ? "signature mismatch" : "could not read module signature";
115 return true;
116}
117
118static void updateModuleImports(ModuleFile &MF, ModuleFile *ImportedBy,
119 SourceLocation ImportLoc) {
120 if (ImportedBy) {
121 MF.ImportedBy.insert(ImportedBy);
122 ImportedBy->Imports.insert(&MF);
123 } else {
124 if (!MF.DirectlyImported)
125 MF.ImportLoc = ImportLoc;
126
127 MF.DirectlyImported = true;
128 }
129}
130
133 ModuleFile *ImportedBy, unsigned Generation, off_t ExpectedSize,
134 time_t ExpectedModTime, ASTFileSignature ExpectedSignature,
135 ASTFileSignatureReader ReadSignature) {
137
138 uint64_t InputFilesValidationTimestamp = 0;
139 if (Type == MK_ImplicitModule)
140 InputFilesValidationTimestamp = ModCache.getModuleTimestamp(FileName);
141
142 bool IgnoreModTime = Type == MK_ExplicitModule || Type == MK_PrebuiltModule;
143 if (ImportedBy)
144 IgnoreModTime &= ImportedBy->Kind == MK_ExplicitModule ||
145 ImportedBy->Kind == MK_PrebuiltModule;
146 if (IgnoreModTime) {
147 // If neither this file nor the importer are in the module cache, this file
148 // might have a different mtime due to being moved across filesystems in
149 // a distributed build. The size must still match, though. (As must the
150 // contents, but we can't check that.)
151 ExpectedModTime = 0;
152 }
153
154 std::optional<ModuleFileKey> FileKey = makeKey(FileName);
155 if (!FileKey) {
157 return Result;
158 }
159
160 // Check whether we already loaded this module before.
161 // Note: `isModuleFileOutOfDate` and `checkSignature` are mutually exclusive
162 // in practice. If a signature is stored, it means size/mtime values have been
163 // zeroed out. If size/mtime are non-NULL, the signature is empty.
164 if (ModuleFile *ModuleEntry = lookup(*FileKey)) {
165 if (isModuleFileOutOfDate(ModuleEntry->Size, ModuleEntry->ModTime,
166 ExpectedSize, ExpectedModTime, Result)) {
167 Result.setOutOfDate(ModuleEntry->InputFilesValidationStatus);
168 return Result;
169 }
170
171 // Check the stored signature.
172 if (checkSignature(ModuleEntry->Signature, ExpectedSignature, Result)) {
173 Result.setOutOfDate(ModuleEntry->InputFilesValidationStatus);
174 return Result;
175 }
176
177 Result.Module = ModuleEntry;
178 updateModuleImports(*ModuleEntry, ImportedBy, ImportLoc);
180 return Result;
181 }
182
183 // Load the contents of the module
184 off_t Size = ExpectedSize;
185 time_t ModTime = ExpectedModTime;
186 llvm::MemoryBuffer *ModuleBuffer = nullptr;
187 std::unique_ptr<llvm::MemoryBuffer> NewFileBuffer = nullptr;
188 if (std::unique_ptr<llvm::MemoryBuffer> Buffer =
189 lookupBuffer(FileName, Size, ModTime)) {
190 // The buffer was already provided for us.
192 FileName, std::move(Buffer), Size, ModTime);
193 } else if (llvm::MemoryBuffer *Buffer =
194 getModuleCache().getInMemoryModuleCache().lookupPCM(
195 FileName, Size, ModTime)) {
196 ModuleBuffer = Buffer;
197 } else if (getModuleCache().getInMemoryModuleCache().shouldBuildPCM(
198 FileName)) {
199 // Report that the module is out of date, since we tried (and failed) to
200 // import it earlier. No ModuleFile exists yet, so derive the validation
201 // status from the module kind being loaded.
205 return Result;
206 } else {
207 auto Buf = [&]() -> Expected<std::unique_ptr<llvm::MemoryBuffer>> {
208 // Implicit modules live in the module cache.
209 if (FileName.getImplicitModuleSuffixLength())
210 return ModCache.read(FileName, Size, ModTime);
211
212 // Explicit modules are treated as any other compiler input file, load
213 // them via FileManager.
215 FileName == StringRef("-")
216 ? FileMgr.getSTDIN()
217 : FileMgr.getFileRef(FileName, /*OpenFile=*/true,
218 /*CacheFailure=*/false,
219 /*IsText=*/false);
220 if (!Entry)
221 return Entry.takeError();
222
223 Size = Entry->getSize();
224 ModTime = Entry->getModificationTime();
225
226 // RequiresNullTerminator is false because module files don't need it, and
227 // this allows the file to still be mmapped.
228 return llvm::errorOrToExpected(
229 FileMgr.getBufferForFile(*Entry, /*IsVolatile=*/false,
230 /*RequiresNullTerminator=*/false,
231 /*MaybeLimit=*/std::nullopt,
232 /*IsText=*/false));
233 }();
234
235 if (!Buf) {
236 Result.BufferError = llvm::toString(Buf.takeError());
238 return Result;
239 }
240
241 NewFileBuffer = std::move(*Buf);
242 ModuleBuffer = NewFileBuffer.get();
243 }
244
245 // Allocate bookkeeping for a module file not yet loaded into this reader.
246 auto NewModule = std::make_unique<ModuleFile>(Type, *FileKey, Generation);
247 NewModule->Index = Chain.size();
248 NewModule->FileName = FileName;
249 NewModule->ImportLoc = ImportLoc;
250 NewModule->InputFilesValidationTimestamp = InputFilesValidationTimestamp;
251 NewModule->Size = Size;
252 NewModule->ModTime = ModTime;
253 NewModule->Buffer = ModuleBuffer;
254 // Initialize the stream.
255 NewModule->Data = PCHContainerRdr.ExtractPCH(*NewModule->Buffer);
256
257 // Check file properties.
258 if (isModuleFileOutOfDate(Size, ModTime, ExpectedSize, ExpectedModTime,
259 Result)) {
260 Result.setOutOfDate(NewModule->InputFilesValidationStatus);
261 return Result;
262 }
263
264 // Read the signature eagerly now so that we can check it. Avoid calling
265 // ReadSignature unless there's something to check though.
266 if (ExpectedSignature && checkSignature(ReadSignature(NewModule->Data),
267 ExpectedSignature, Result)) {
268 Result.setOutOfDate(NewModule->InputFilesValidationStatus);
269 return Result;
270 }
271
272 if (NewFileBuffer)
274 FileName, std::move(NewFileBuffer), Size, ModTime);
275
276 // We're keeping this module. Store it in the map.
277 Result.Module = Modules[*FileKey] = NewModule.get();
278
279 updateModuleImports(*NewModule, ImportedBy, ImportLoc);
280
281 if (!NewModule->isModule())
282 PCHChain.push_back(NewModule.get());
283 if (!ImportedBy)
284 Roots.push_back(NewModule.get());
285
286 Chain.push_back(std::move(NewModule));
288 return Result;
289}
290
292 auto Last = end();
293 if (First == Last)
294 return;
295
296 // Explicitly clear VisitOrder since we might not notice it is stale.
297 VisitOrder.clear();
298
299 // Collect the set of module file pointers that we'll be removing.
301 (llvm::pointer_iterator<ModuleIterator>(First)),
302 (llvm::pointer_iterator<ModuleIterator>(Last)));
303
304 auto IsVictim = [&](ModuleFile *MF) {
305 return victimSet.count(MF);
306 };
307 // Remove any references to the now-destroyed modules.
308 for (auto I = begin(); I != First; ++I) {
309 I->Imports.remove_if(IsVictim);
310 I->ImportedBy.remove_if(IsVictim);
311 }
312 llvm::erase_if(Roots, IsVictim);
313
314 // Remove the modules from the PCH chain.
315 for (auto I = First; I != Last; ++I) {
316 if (!I->isModule()) {
317 PCHChain.erase(llvm::find(PCHChain, &*I), PCHChain.end());
318 break;
319 }
320 }
321
322 // Delete the modules.
323 for (ModuleIterator victim = First; victim != Last; ++victim)
324 Modules.erase(victim->FileKey);
325
326 Chain.erase(Chain.begin() + (First - begin()), Chain.end());
327}
328
329void
331 std::unique_ptr<llvm::MemoryBuffer> Buffer) {
332 FileEntryRef Entry =
333 FileMgr.getVirtualFileRef(FileName, Buffer->getBufferSize(), 0);
334 InMemoryBuffers[Entry] = std::move(Buffer);
335}
336
337std::unique_ptr<ModuleManager::VisitState> ModuleManager::allocateVisitState() {
338 // Fast path: if we have a cached state, use it.
339 if (FirstVisitState) {
340 auto Result = std::move(FirstVisitState);
341 FirstVisitState = std::move(Result->NextState);
342 return Result;
343 }
344
345 // Allocate and return a new state.
346 return std::make_unique<VisitState>(size());
347}
348
349void ModuleManager::returnVisitState(std::unique_ptr<VisitState> State) {
350 assert(State->NextState == nullptr && "Visited state is in list?");
351 State->NextState = std::move(FirstVisitState);
352 FirstVisitState = std::move(State);
353}
354
356 GlobalIndex = Index;
357 if (!GlobalIndex) {
358 ModulesInCommonWithGlobalIndex.clear();
359 return;
360 }
361
362 // Notify the global module index about all of the modules we've already
363 // loaded.
364 for (ModuleFile &M : *this)
365 if (!GlobalIndex->loadedModuleFile(&M))
366 ModulesInCommonWithGlobalIndex.push_back(&M);
367}
368
370 if (!GlobalIndex || GlobalIndex->loadedModuleFile(MF))
371 return;
372
373 ModulesInCommonWithGlobalIndex.push_back(MF);
374}
375
377 const PCHContainerReader &PCHContainerRdr,
378 const HeaderSearch &HeaderSearchInfo)
379 : FileMgr(FileMgr), ModCache(ModCache), PCHContainerRdr(PCHContainerRdr),
380 HeaderSearchInfo(HeaderSearchInfo) {}
381
382void ModuleManager::visit(llvm::function_ref<bool(ModuleFile &M)> Visitor,
383 llvm::SmallPtrSetImpl<ModuleFile *> *ModuleFilesHit) {
384 // If the visitation order vector is the wrong size, recompute the order.
385 if (VisitOrder.size() != Chain.size()) {
386 unsigned N = size();
387 VisitOrder.clear();
388 VisitOrder.reserve(N);
389
390 // Record the number of incoming edges for each module. When we
391 // encounter a module with no incoming edges, push it into the queue
392 // to seed the queue.
394 Queue.reserve(N);
395 llvm::SmallVector<unsigned, 4> UnusedIncomingEdges;
396 UnusedIncomingEdges.resize(size());
397 for (ModuleFile &M : llvm::reverse(*this)) {
398 unsigned Size = M.ImportedBy.size();
399 UnusedIncomingEdges[M.Index] = Size;
400 if (!Size)
401 Queue.push_back(&M);
402 }
403
404 // Traverse the graph, making sure to visit a module before visiting any
405 // of its dependencies.
406 while (!Queue.empty()) {
407 ModuleFile *CurrentModule = Queue.pop_back_val();
408 VisitOrder.push_back(CurrentModule);
409
410 // For any module that this module depends on, push it on the
411 // stack (if it hasn't already been marked as visited).
412 for (ModuleFile *M : llvm::reverse(CurrentModule->Imports)) {
413 // Remove our current module as an impediment to visiting the
414 // module we depend on. If we were the last unvisited module
415 // that depends on this particular module, push it into the
416 // queue to be visited.
417 unsigned &NumUnusedEdges = UnusedIncomingEdges[M->Index];
418 if (NumUnusedEdges && (--NumUnusedEdges == 0))
419 Queue.push_back(M);
420 }
421 }
422
423 assert(VisitOrder.size() == N && "Visitation order is wrong?");
424
425 FirstVisitState = nullptr;
426 }
427
428 auto State = allocateVisitState();
429 unsigned VisitNumber = State->NextVisitNumber++;
430
431 // If the caller has provided us with a hit-set that came from the global
432 // module index, mark every module file in common with the global module
433 // index that is *not* in that set as 'visited'.
434 if (ModuleFilesHit && !ModulesInCommonWithGlobalIndex.empty()) {
435 for (unsigned I = 0, N = ModulesInCommonWithGlobalIndex.size(); I != N; ++I)
436 {
437 ModuleFile *M = ModulesInCommonWithGlobalIndex[I];
438 if (!ModuleFilesHit->count(M))
439 State->VisitNumber[M->Index] = VisitNumber;
440 }
441 }
442
443 for (unsigned I = 0, N = VisitOrder.size(); I != N; ++I) {
444 ModuleFile *CurrentModule = VisitOrder[I];
445 // Should we skip this module file?
446 if (State->VisitNumber[CurrentModule->Index] == VisitNumber)
447 continue;
448
449 // Visit the module.
450 assert(State->VisitNumber[CurrentModule->Index] == VisitNumber - 1);
451 State->VisitNumber[CurrentModule->Index] = VisitNumber;
452 if (!Visitor(*CurrentModule))
453 continue;
454
455 // The visitor has requested that cut off visitation of any
456 // module that the current module depends on. To indicate this
457 // behavior, we mark all of the reachable modules as having been visited.
458 ModuleFile *NextModule = CurrentModule;
459 do {
460 // For any module that this module depends on, push it on the
461 // stack (if it hasn't already been marked as visited).
462 for (llvm::SetVector<ModuleFile *>::iterator
463 M = NextModule->Imports.begin(),
464 MEnd = NextModule->Imports.end();
465 M != MEnd; ++M) {
466 if (State->VisitNumber[(*M)->Index] != VisitNumber) {
467 State->Stack.push_back(*M);
468 State->VisitNumber[(*M)->Index] = VisitNumber;
469 }
470 }
471
472 if (State->Stack.empty())
473 break;
474
475 // Pop the next module off the stack.
476 NextModule = State->Stack.pop_back_val();
477 } while (true);
478 }
479
480 returnVisitState(std::move(State));
481}
482
483#ifndef NDEBUG
484namespace llvm {
485
486 template<>
487 struct GraphTraits<ModuleManager> {
489 using ChildIteratorType = llvm::SetVector<ModuleFile *>::const_iterator;
490 using nodes_iterator = pointer_iterator<ModuleManager::ModuleConstIterator>;
491
493 return Node->Imports.begin();
494 }
495
497 return Node->Imports.end();
498 }
499
500 static nodes_iterator nodes_begin(const ModuleManager &Manager) {
501 return nodes_iterator(Manager.begin());
502 }
503
504 static nodes_iterator nodes_end(const ModuleManager &Manager) {
505 return nodes_iterator(Manager.end());
506 }
507 };
508
509 template<>
511 explicit DOTGraphTraits(bool IsSimple = false)
512 : DefaultDOTGraphTraits(IsSimple) {}
513
514 static bool renderGraphFromBottomUp() { return true; }
515
516 std::string getNodeLabel(ModuleFile *M, const ModuleManager&) {
517 return M->ModuleName;
518 }
519 };
520
521} // namespace llvm
522
524 llvm::ViewGraph(*this, "Modules");
525}
526#endif
Defines the clang::FileManager interface and associated types.
Result
Implement __builtin_bit_cast and related operations.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
static void updateModuleImports(ModuleFile &MF, ModuleFile *ImportedBy, SourceLocation ImportLoc)
A reference to a FileEntry that includes the name of the file as it was accessed by the FileManager's...
Definition FileEntry.h:57
Implements support for file system lookup, file system caching, and directory search management.
Definition FileManager.h:53
A global index for a set of module files, providing information about the identifiers within those mo...
Encapsulates the information needed to find the file referenced by a #include or #include_next,...
llvm::MemoryBuffer & addPCM(llvm::StringRef Filename, std::unique_ptr< llvm::MemoryBuffer > Buffer, off_t Size, time_t ModTime)
Store the PCM under the Filename.
llvm::MemoryBuffer & addBuiltPCM(llvm::StringRef Filename, std::unique_ptr< llvm::MemoryBuffer > Buffer, off_t Size, time_t ModTime)
Store a just-built PCM under the Filename.
The module cache used for compiling modules implicitly.
Definition ModuleCache.h:37
virtual InMemoryModuleCache & getInMemoryModuleCache()=0
Returns this process's view of the module cache.
Deduplication key for a loaded module file in ModuleManager.
Definition Module.h:77
Identifies a module file to be loaded.
Definition Module.h:107
unsigned getImplicitModuleSuffixLength() const
Returns the suffix length for an implicit module name, zero otherwise.
Definition Module.h:144
Describes a module or submodule.
Definition Module.h:301
This abstract interface provides operations for unwrapping containers for serialized ASTs (precompile...
Encodes a location in the source.
The base class of the type hierarchy.
Definition TypeBase.h:1871
The result of attempting to add a new module.
@ Missing
The module file is missing.
@ NewlyLoaded
The module file was just loaded in response to this call.
@ AlreadyLoaded
The module file had already been loaded.
Information about a module that has been loaded by the ASTReader.
Definition ModuleFile.h:158
bool DirectlyImported
Whether this module has been directly imported by the user.
Definition ModuleFile.h:241
llvm::SetVector< ModuleFile * > ImportedBy
List of modules which depend on this module.
Definition ModuleFile.h:552
SourceLocation ImportLoc
The source location where this module was first imported.
Definition ModuleFile.h:277
unsigned Index
The index of this module in the list of modules.
Definition ModuleFile.h:171
llvm::SetVector< ModuleFile * > Imports
List of modules which this module directly imported.
Definition ModuleFile.h:555
ModuleKind Kind
The type of this module.
Definition ModuleFile.h:174
std::string ModuleName
The name of the module.
Definition ModuleFile.h:183
Manages the set of modules loaded by an AST reader.
std::unique_ptr< llvm::MemoryBuffer > lookupBuffer(StringRef Name, off_t &Size, time_t &ModTime)
Returns the in-memory (virtual file) buffer with the given name.
AddModuleResult addModule(ModuleFileName FileName, ModuleKind Type, SourceLocation ImportLoc, ModuleFile *ImportedBy, unsigned Generation, off_t ExpectedSize, time_t ExpectedModTime, ASTFileSignature ExpectedSignature, ASTFileSignatureReader ReadSignature)
Attempts to create a new module and add it to the list of known modules.
ModuleFile * lookup(ModuleFileKey Key) const
Returns the module associated with the given module file key.
llvm::pointee_iterator< SmallVectorImpl< std::unique_ptr< ModuleFile > >::iterator > ModuleIterator
void moduleFileAccepted(ModuleFile *MF)
Notification from the AST reader that the given module file has been "accepted", and will not (can no...
ModuleManager(FileManager &FileMgr, ModuleCache &ModCache, const PCHContainerReader &PCHContainerRdr, const HeaderSearch &HeaderSearchInfo)
void viewGraph()
View the graphviz representation of the module graph.
ModuleCache & getModuleCache() const
ModuleIterator begin()
Forward iterator to traverse all loaded modules.
std::optional< ModuleFileKey > makeKey(const ModuleFileName &Name) const
Creates the deduplication key for use in ModuleManager.
void setGlobalIndex(GlobalModuleIndex *Index)
Set the global module index.
void removeModules(ModuleIterator First)
Remove the modules starting from First (to the end).
ModuleIterator end()
Forward iterator end-point to traverse all loaded modules.
void addInMemoryBuffer(StringRef FileName, std::unique_ptr< llvm::MemoryBuffer > Buffer)
Add an in-memory buffer the list of known buffers.
void visit(llvm::function_ref< bool(ModuleFile &M)> Visitor, llvm::SmallPtrSetImpl< ModuleFile * > *ModuleFilesHit=nullptr)
Visit each of the modules.
unsigned size() const
Number of modules loaded.
ModuleFile * lookupByFileName(ModuleFileName FileName) const
Returns the module associated with the given module file name.
ASTFileSignature(*)(StringRef) ASTFileSignatureReader
ModuleFile * lookupByModuleName(StringRef ModName) const
Returns the module associated with the given module name.
@ Disabled
When the validation is disabled. For example, for a precompiled header.
Definition ModuleFile.h:141
@ NotStarted
Initial value, before the validation has been performed.
Definition ModuleFile.h:139
ModuleKind
Specifies the kind of module that has been loaded.
Definition ModuleFile.h:44
@ MK_ExplicitModule
File is an explicitly-loaded module.
Definition ModuleFile.h:49
@ MK_ImplicitModule
File is an implicitly-loaded module.
Definition ModuleFile.h:46
@ MK_PrebuiltModule
File is from a prebuilt module path.
Definition ModuleFile.h:61
The JSON file list parser is used to communicate input to InstallAPI.
@ Result
The result type of a method or function.
Definition TypeBase.h:905
Diagnostic wrappers for TextAPI types for error reporting.
Definition Dominators.h:30
The signature of a module, which is a hash of the AST content.
Definition Module.h:159
std::string getNodeLabel(ModuleFile *M, const ModuleManager &)
static ChildIteratorType child_end(NodeRef Node)
static nodes_iterator nodes_begin(const ModuleManager &Manager)
static ChildIteratorType child_begin(NodeRef Node)
pointer_iterator< ModuleManager::ModuleConstIterator > nodes_iterator
llvm::SetVector< ModuleFile * >::const_iterator ChildIteratorType
static nodes_iterator nodes_end(const ModuleManager &Manager)