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;
45 auto Entry = FileMgr.
getFile(Name,
false,
62 auto Known = Modules.find(
File);
63 if (Known == Modules.end())
69std::unique_ptr<llvm::MemoryBuffer>
71 auto Entry = FileMgr.
getFile(Name,
false,
75 return std::move(InMemoryBuffers[*Entry]);
80 std::string &ErrorStr) {
81 if (!ExpectedSignature || Signature == ExpectedSignature)
85 Signature ?
"signature mismatch" :
"could not read module signature";
93 ImportedBy->
Imports.insert(&MF);
106 off_t ExpectedSize, time_t ExpectedModTime,
110 std::string &ErrorStr) {
126 ErrorStr =
"module file out of date";
130 if (!Entry && FileName !=
"-") {
131 ErrorStr =
"module file not found";
153 return Entry->getName() == MF->FileName;
157 if (
ModuleFile *ModuleEntry = Modules.lookup(Entry)) {
158 if (implicitModuleNamesMatch(
Type, ModuleEntry, Entry)) {
160 if (
checkSignature(ModuleEntry->Signature, ExpectedSignature, ErrorStr))
170 auto NewModule = std::make_unique<ModuleFile>(
Type, Generation);
171 NewModule->Index = Chain.size();
172 NewModule->FileName = FileName.str();
173 NewModule->File = Entry;
174 NewModule->ImportLoc = ImportLoc;
175 NewModule->InputFilesValidationTimestamp = 0;
178 std::string TimestampFilename = NewModule->getTimestampFilename();
179 llvm::vfs::Status Status;
182 NewModule->InputFilesValidationTimestamp =
183 llvm::sys::toTimeT(Status.getLastModificationTime());
187 if (std::unique_ptr<llvm::MemoryBuffer> Buffer =
lookupBuffer(FileName)) {
189 NewModule->Buffer = &ModuleCache->addBuiltPCM(FileName, std::move(Buffer));
194 }
else if (llvm::MemoryBuffer *Buffer =
196 NewModule->Buffer = Buffer;
206 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buf((std::error_code()));
207 if (FileName ==
"-") {
208 Buf = llvm::MemoryBuffer::getSTDIN();
222 ErrorStr = Buf.getError().message();
230 NewModule->Data = PCHContainerRdr.
ExtractPCH(*NewModule->Buffer);
234 if (ExpectedSignature &&
checkSignature(ReadSignature(NewModule->Data),
235 ExpectedSignature, ErrorStr))
239 Module = Modules[Entry] = NewModule.get();
243 if (!NewModule->isModule())
244 PCHChain.push_back(NewModule.get());
246 Roots.push_back(NewModule.get());
248 Chain.push_back(std::move(NewModule));
262 (llvm::pointer_iterator<ModuleIterator>(
First)),
263 (llvm::pointer_iterator<ModuleIterator>(
Last)));
266 return victimSet.count(MF);
270 I->Imports.remove_if(IsVictim);
271 I->ImportedBy.remove_if(IsVictim);
273 llvm::erase_if(Roots, IsVictim);
277 if (!I->isModule()) {
278 PCHChain.erase(llvm::find(PCHChain, &*I), PCHChain.end());
285 Modules.erase(victim->File);
287 Chain.erase(Chain.begin() + (
First -
begin()), Chain.end());
292 std::unique_ptr<llvm::MemoryBuffer> Buffer) {
295 InMemoryBuffers[Entry] = std::move(Buffer);
298std::unique_ptr<ModuleManager::VisitState> ModuleManager::allocateVisitState() {
300 if (FirstVisitState) {
301 auto Result = std::move(FirstVisitState);
302 FirstVisitState = std::move(
Result->NextState);
307 return std::make_unique<VisitState>(
size());
310void ModuleManager::returnVisitState(std::unique_ptr<VisitState> State) {
311 assert(State->NextState ==
nullptr &&
"Visited state is in list?");
312 State->NextState = std::move(FirstVisitState);
313 FirstVisitState = std::move(State);
319 ModulesInCommonWithGlobalIndex.clear();
327 ModulesInCommonWithGlobalIndex.push_back(&M);
334 ModulesInCommonWithGlobalIndex.push_back(MF);
341 : FileMgr(FileMgr), ModuleCache(&ModuleCache),
342 PCHContainerRdr(PCHContainerRdr), HeaderSearchInfo(HeaderSearchInfo) {}
345 llvm::SmallPtrSetImpl<ModuleFile *> *ModuleFilesHit) {
347 if (VisitOrder.size() != Chain.size()) {
350 VisitOrder.reserve(N);
358 UnusedIncomingEdges.resize(
size());
361 UnusedIncomingEdges[M.
Index] = Size;
368 while (!Queue.empty()) {
369 ModuleFile *CurrentModule = Queue.pop_back_val();
370 VisitOrder.push_back(CurrentModule);
379 unsigned &NumUnusedEdges = UnusedIncomingEdges[M->
Index];
380 if (NumUnusedEdges && (--NumUnusedEdges == 0))
385 assert(VisitOrder.size() == N &&
"Visitation order is wrong?");
387 FirstVisitState =
nullptr;
390 auto State = allocateVisitState();
391 unsigned VisitNumber = State->NextVisitNumber++;
396 if (ModuleFilesHit && !ModulesInCommonWithGlobalIndex.empty()) {
397 for (
unsigned I = 0, N = ModulesInCommonWithGlobalIndex.size(); I != N; ++I)
399 ModuleFile *M = ModulesInCommonWithGlobalIndex[I];
400 if (!ModuleFilesHit->count(M))
401 State->VisitNumber[M->
Index] = VisitNumber;
405 for (
unsigned I = 0, N = VisitOrder.size(); I != N; ++I) {
408 if (State->VisitNumber[CurrentModule->
Index] == VisitNumber)
412 assert(State->VisitNumber[CurrentModule->
Index] == VisitNumber - 1);
413 State->VisitNumber[CurrentModule->
Index] = VisitNumber;
414 if (!Visitor(*CurrentModule))
424 for (llvm::SetVector<ModuleFile *>::iterator
425 M = NextModule->
Imports.begin(),
426 MEnd = NextModule->
Imports.end();
428 if (State->VisitNumber[(*M)->Index] != VisitNumber) {
429 State->Stack.push_back(*M);
430 State->VisitNumber[(*M)->Index] = VisitNumber;
434 if (State->Stack.empty())
438 NextModule = State->Stack.pop_back_val();
442 returnVisitState(std::move(State));
446 time_t ExpectedModTime,
455 expectedToOptional(FileMgr.
getFileRef(FileName,
true,
462 if ((ExpectedSize && ExpectedSize !=
File->getSize()) ||
463 (ExpectedModTime && ExpectedModTime !=
File->getModificationTime()))
481 return Node->Imports.begin();
485 return Node->Imports.end();
512 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)
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.
std::error_code getNoncachedStatValue(StringRef Path, llvm::vfs::Status &Result)
Get the 'stat' information for the given Path.
llvm::ErrorOr< std::unique_ptr< llvm::MemoryBuffer > > getBufferForFile(const FileEntry *Entry, bool isVolatile=false, bool RequiresNullTerminator=true)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful,...
const FileEntry * getVirtualFile(StringRef Filename, off_t Size, time_t ModificationTime)
llvm::ErrorOr< const FileEntry * > getFile(StringRef Filename, bool OpenFile=false, bool CacheFailure=true)
Lookup, cache, and verify the specified file (real or virtual).
llvm::Expected< FileEntryRef > getFileRef(StringRef Filename, bool OpenFile=false, bool CacheFailure=true)
Lookup, cache, and verify the specified file (real or virtual).
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.
Wrapper around OptionalFileEntryRef that degrades to 'const FileEntry*', facilitating incremental pat...
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.
unsigned Index
The index of this module in the list of modules.
llvm::SetVector< ModuleFile * > Imports
List of modules which this module depends on.
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.
@ Result
The result type of a method or function.
YAML serialization mapping.
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)