23#include "llvm/ADT/STLExtras.h"
24#include "llvm/ADT/SetVector.h"
25#include "llvm/ADT/SmallPtrSet.h"
26#include "llvm/ADT/SmallVector.h"
27#include "llvm/ADT/StringRef.h"
28#include "llvm/ADT/iterator.h"
29#include "llvm/Support/Chrono.h"
30#include "llvm/Support/DOTGraphTraits.h"
31#include "llvm/Support/ErrorOr.h"
32#include "llvm/Support/GraphWriter.h"
33#include "llvm/Support/MemoryBuffer.h"
34#include "llvm/Support/VirtualFileSystem.h"
39#include <system_error>
42using namespace serialization;
62 return Modules.lookup(
File);
65std::unique_ptr<llvm::MemoryBuffer>
71 return std::move(InMemoryBuffers[*Entry]);
76 std::string &ErrorStr) {
77 if (!ExpectedSignature || Signature == ExpectedSignature)
81 Signature ?
"signature mismatch" :
"could not read module signature";
89 ImportedBy->
Imports.insert(&MF);
102 off_t ExpectedSize, time_t ExpectedModTime,
106 std::string &ErrorStr) {
122 ErrorStr =
"module file out of date";
127 ErrorStr =
"module file not found";
149 return Entry.getName() == MF->FileName;
153 if (
ModuleFile *ModuleEntry = Modules.lookup(*Entry)) {
154 if (implicitModuleNamesMatch(
Type, ModuleEntry, *Entry)) {
156 if (
checkSignature(ModuleEntry->Signature, ExpectedSignature, ErrorStr))
166 auto NewModule = std::make_unique<ModuleFile>(
Type, *Entry, Generation);
167 NewModule->Index = Chain.size();
168 NewModule->FileName =
FileName.str();
169 NewModule->ImportLoc = ImportLoc;
170 NewModule->InputFilesValidationTimestamp = 0;
173 std::string TimestampFilename =
175 llvm::vfs::Status Status;
178 NewModule->InputFilesValidationTimestamp =
179 llvm::sys::toTimeT(Status.getLastModificationTime());
185 NewModule->Buffer = &ModuleCache->addBuiltPCM(
FileName, std::move(Buffer));
190 }
else if (llvm::MemoryBuffer *Buffer =
192 NewModule->Buffer = Buffer;
212 ErrorStr = Buf.getError().message();
220 NewModule->Data = PCHContainerRdr.
ExtractPCH(*NewModule->Buffer);
224 if (ExpectedSignature &&
checkSignature(ReadSignature(NewModule->Data),
225 ExpectedSignature, ErrorStr))
229 Module = Modules[*Entry] = NewModule.get();
233 if (!NewModule->isModule())
234 PCHChain.push_back(NewModule.get());
236 Roots.push_back(NewModule.get());
238 Chain.push_back(std::move(NewModule));
252 (llvm::pointer_iterator<ModuleIterator>(
First)),
253 (llvm::pointer_iterator<ModuleIterator>(
Last)));
256 return victimSet.count(MF);
260 I->Imports.remove_if(IsVictim);
261 I->ImportedBy.remove_if(IsVictim);
263 llvm::erase_if(Roots, IsVictim);
267 if (!I->isModule()) {
268 PCHChain.erase(llvm::find(PCHChain, &*I), PCHChain.end());
275 Modules.erase(victim->File);
277 Chain.erase(Chain.begin() + (
First -
begin()), Chain.end());
282 std::unique_ptr<llvm::MemoryBuffer> Buffer) {
285 InMemoryBuffers[Entry] = std::move(Buffer);
288std::unique_ptr<ModuleManager::VisitState> ModuleManager::allocateVisitState() {
290 if (FirstVisitState) {
291 auto Result = std::move(FirstVisitState);
292 FirstVisitState = std::move(
Result->NextState);
297 return std::make_unique<VisitState>(
size());
300void ModuleManager::returnVisitState(std::unique_ptr<VisitState> State) {
301 assert(State->NextState ==
nullptr &&
"Visited state is in list?");
302 State->NextState = std::move(FirstVisitState);
303 FirstVisitState = std::move(State);
309 ModulesInCommonWithGlobalIndex.clear();
317 ModulesInCommonWithGlobalIndex.push_back(&M);
324 ModulesInCommonWithGlobalIndex.push_back(MF);
331 : FileMgr(FileMgr), ModuleCache(&ModuleCache),
332 PCHContainerRdr(PCHContainerRdr), HeaderSearchInfo(HeaderSearchInfo) {}
335 llvm::SmallPtrSetImpl<ModuleFile *> *ModuleFilesHit) {
337 if (VisitOrder.size() != Chain.size()) {
340 VisitOrder.reserve(N);
348 UnusedIncomingEdges.resize(
size());
351 UnusedIncomingEdges[M.
Index] = Size;
358 while (!Queue.empty()) {
359 ModuleFile *CurrentModule = Queue.pop_back_val();
360 VisitOrder.push_back(CurrentModule);
369 unsigned &NumUnusedEdges = UnusedIncomingEdges[M->
Index];
370 if (NumUnusedEdges && (--NumUnusedEdges == 0))
375 assert(VisitOrder.size() == N &&
"Visitation order is wrong?");
377 FirstVisitState =
nullptr;
380 auto State = allocateVisitState();
381 unsigned VisitNumber = State->NextVisitNumber++;
386 if (ModuleFilesHit && !ModulesInCommonWithGlobalIndex.empty()) {
387 for (
unsigned I = 0, N = ModulesInCommonWithGlobalIndex.size(); I != N; ++I)
389 ModuleFile *M = ModulesInCommonWithGlobalIndex[I];
390 if (!ModuleFilesHit->count(M))
391 State->VisitNumber[M->
Index] = VisitNumber;
395 for (
unsigned I = 0, N = VisitOrder.size(); I != N; ++I) {
398 if (State->VisitNumber[CurrentModule->
Index] == VisitNumber)
402 assert(State->VisitNumber[CurrentModule->
Index] == VisitNumber - 1);
403 State->VisitNumber[CurrentModule->
Index] = VisitNumber;
404 if (!Visitor(*CurrentModule))
414 for (llvm::SetVector<ModuleFile *>::iterator
415 M = NextModule->
Imports.begin(),
416 MEnd = NextModule->
Imports.end();
418 if (State->VisitNumber[(*M)->Index] != VisitNumber) {
419 State->Stack.push_back(*M);
420 State->VisitNumber[(*M)->Index] = VisitNumber;
424 if (State->Stack.empty())
428 NextModule = State->Stack.pop_back_val();
432 returnVisitState(std::move(State));
436 time_t ExpectedModTime,
449 ((ExpectedSize && ExpectedSize !=
File->getSize()) ||
450 (ExpectedModTime && ExpectedModTime !=
File->getModificationTime())))
468 return Node->Imports.begin();
472 return Node->Imports.end();
499 llvm::ViewGraph(*
this,
"Modules");
Defines the clang::FileManager interface and associated types.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
static bool checkSignature(ASTFileSignature Signature, ASTFileSignature ExpectedSignature, std::string &ErrorStr)
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...
Cached information about one file (either on disk or in the virtual file system).
Implements support for file system lookup, file system caching, and directory search management.
llvm::ErrorOr< std::unique_ptr< llvm::MemoryBuffer > > getBufferForFile(FileEntryRef Entry, bool isVolatile=false, bool RequiresNullTerminator=true, std::optional< int64_t > MaybeLimit=std::nullopt, bool IsText=true)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful,...
std::error_code getNoncachedStatValue(StringRef Path, llvm::vfs::Status &Result)
Get the 'stat' information for the given Path.
OptionalFileEntryRef getOptionalFileRef(StringRef Filename, bool OpenFile=false, bool CacheFailure=true)
Get a FileEntryRef if it exists, without doing anything on error.
llvm::Expected< FileEntryRef > getSTDIN()
Get the FileEntryRef for stdin, returning an error if stdin cannot be read.
FileEntryRef getVirtualFileRef(StringRef Filename, off_t Size, time_t ModificationTime)
Retrieve a file entry for a "virtual" file that acts as if there were a file with the given name on d...
A global index for a set of module files, providing information about the identifiers within those mo...
bool loadedModuleFile(ModuleFile *File)
Note that the given module file has been loaded.
In-memory cache for modules.
llvm::MemoryBuffer & addPCM(llvm::StringRef Filename, std::unique_ptr< llvm::MemoryBuffer > Buffer)
Store the PCM under the Filename.
Module * findModule(StringRef Name) const
Retrieve a module with the given name.
Describes a module or submodule.
This abstract interface provides operations for unwrapping containers for serialized ASTs (precompile...
virtual llvm::StringRef ExtractPCH(llvm::MemoryBufferRef Buffer) const =0
Returns the serialized AST inside the PCH container Buffer.
Encodes a location in the source.
The base class of the type hierarchy.
Information about a module that has been loaded by the ASTReader.
bool DirectlyImported
Whether this module has been directly imported by the user.
llvm::SetVector< ModuleFile * > ImportedBy
List of modules which depend on this module.
SourceLocation ImportLoc
The source location where this module was first imported.
static std::string getTimestampFilename(StringRef FileName)
unsigned Index
The index of this module in the list of modules.
llvm::SetVector< ModuleFile * > Imports
List of modules which this module directly imported.
std::string ModuleName
The name of the module.
Manages the set of modules loaded by an AST reader.
ModuleManager(FileManager &FileMgr, InMemoryModuleCache &ModuleCache, const PCHContainerReader &PCHContainerRdr, const HeaderSearch &HeaderSearchInfo)
bool lookupModuleFile(StringRef FileName, off_t ExpectedSize, time_t ExpectedModTime, OptionalFileEntryRef &File)
Attempt to resolve the given module file name to a file entry.
AddModuleResult
The result of attempting to add a new module.
@ Missing
The module file is missing.
@ OutOfDate
The module file is out-of-date.
@ NewlyLoaded
The module file was just loaded in response to this call.
@ AlreadyLoaded
The module file had already been loaded.
void moduleFileAccepted(ModuleFile *MF)
Notification from the AST reader that the given module file has been "accepted", and will not (can no...
ModuleFile * lookup(const FileEntry *File) const
Returns the module associated with the given module file.
void viewGraph()
View the graphviz representation of the module graph.
ModuleIterator begin()
Forward iterator to traverse all loaded modules.
void setGlobalIndex(GlobalModuleIndex *Index)
Set the global module index.
ModuleFile * lookupByFileName(StringRef FileName) const
Returns the module associated with the given file name.
void removeModules(ModuleIterator First)
Remove the modules starting from First (to the end).
ModuleIterator end()
Forward iterator end-point to traverse all loaded modules.
std::unique_ptr< llvm::MemoryBuffer > lookupBuffer(StringRef Name)
Returns the in-memory (virtual file) buffer with the given name.
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.
InMemoryModuleCache & getModuleCache() const
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)
Attempts to create a new module and add it to the list of known modules.
ASTFileSignature(*)(StringRef) ASTFileSignatureReader
llvm::pointee_iterator< SmallVectorImpl< std::unique_ptr< ModuleFile > >::iterator > ModuleIterator
ModuleFile * lookupByModuleName(StringRef ModName) const
Returns the module associated with the given module name.
ModuleKind
Specifies the kind of module that has been loaded.
@ MK_ExplicitModule
File is an explicitly-loaded module.
@ MK_ImplicitModule
File is an implicitly-loaded module.
@ MK_PrebuiltModule
File is from a prebuilt module path.
The JSON file list parser is used to communicate input to InstallAPI.
@ Result
The result type of a method or function.
Diagnostic wrappers for TextAPI types for error reporting.
The signature of a module, which is a hash of the AST content.
DOTGraphTraits(bool IsSimple=false)
std::string getNodeLabel(ModuleFile *M, const ModuleManager &)
static bool renderGraphFromBottomUp()
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)