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/Chrono.h" 31 #include "llvm/Support/DOTGraphTraits.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" 40 #include <system_error> 42 using namespace clang;
43 using namespace serialization;
56 if (
const FileEntry *File = Mod->getASTFile())
63 auto Known = Modules.find(File);
64 if (Known == Modules.end())
70 std::unique_ptr<llvm::MemoryBuffer>
74 return std::move(InMemoryBuffers[Entry]);
79 std::string &ErrorStr) {
80 if (!ExpectedSignature || Signature == ExpectedSignature)
84 Signature ?
"signature mismatch" :
"could not read module signature";
92 ImportedBy->
Imports.insert(&MF);
105 off_t ExpectedSize, time_t ExpectedModTime,
109 std::string &ErrorStr) {
123 ErrorStr =
"module file out of date";
127 if (!Entry && FileName !=
"-") {
128 ErrorStr =
"module file not found";
133 if (
ModuleFile *ModuleEntry = Modules.lookup(Entry)) {
135 if (
checkSignature(ModuleEntry->Signature, ExpectedSignature, ErrorStr))
138 Module = ModuleEntry;
144 auto NewModule = llvm::make_unique<ModuleFile>(Type, Generation);
145 NewModule->Index = Chain.size();
146 NewModule->FileName = FileName.str();
147 NewModule->File = Entry;
148 NewModule->ImportLoc = ImportLoc;
149 NewModule->InputFilesValidationTimestamp = 0;
152 std::string TimestampFilename = NewModule->getTimestampFilename();
153 llvm::vfs::Status Status;
156 NewModule->InputFilesValidationTimestamp =
157 llvm::sys::toTimeT(Status.getLastModificationTime());
161 if (std::unique_ptr<llvm::MemoryBuffer> Buffer =
lookupBuffer(FileName)) {
163 NewModule->Buffer = &PCMCache->addBuffer(FileName, std::move(Buffer));
168 }
else if (llvm::MemoryBuffer *Buffer = PCMCache->lookupBuffer(FileName)) {
169 NewModule->Buffer = Buffer;
174 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buf((std::error_code()));
175 if (FileName ==
"-") {
176 Buf = llvm::MemoryBuffer::getSTDIN();
185 ErrorStr = Buf.getError().message();
189 NewModule->Buffer = &PCMCache->addBuffer(FileName, std::move(*Buf));
193 NewModule->Data = PCHContainerRdr.
ExtractPCH(*NewModule->Buffer);
197 if (ExpectedSignature &&
checkSignature(ReadSignature(NewModule->Data),
198 ExpectedSignature, ErrorStr)) {
201 if (!PCMCache->tryToRemoveBuffer(NewModule->FileName))
207 Module = Modules[Entry] = NewModule.get();
211 if (!NewModule->isModule())
212 PCHChain.push_back(NewModule.get());
214 Roots.push_back(NewModule.get());
216 Chain.push_back(std::move(NewModule));
222 llvm::SmallPtrSetImpl<ModuleFile *> &LoadedSuccessfully,
232 llvm::SmallPtrSet<ModuleFile *, 4> victimSet(
233 (llvm::pointer_iterator<ModuleIterator>(First)),
234 (llvm::pointer_iterator<ModuleIterator>(
Last)));
237 return victimSet.count(MF);
240 for (
auto I =
begin(); I != First; ++I) {
241 I->Imports.remove_if(IsVictim);
242 I->ImportedBy.remove_if(IsVictim);
244 Roots.erase(std::remove_if(Roots.begin(), Roots.end(), IsVictim),
248 for (
auto I = First; I !=
Last; ++I) {
249 if (!I->isModule()) {
250 PCHChain.erase(std::find(PCHChain.begin(), PCHChain.end(), &*I),
258 Modules.erase(victim->File);
261 StringRef ModuleName = victim->ModuleName;
263 mod->setASTFile(
nullptr);
274 if (LoadedSuccessfully.count(&*victim) == 0 &&
275 !PCMCache->tryToRemoveBuffer(victim->FileName))
280 Chain.erase(Chain.begin() + (First -
begin()), Chain.end());
285 std::unique_ptr<llvm::MemoryBuffer> Buffer) {
288 InMemoryBuffers[Entry] = std::move(Buffer);
291 ModuleManager::VisitState *ModuleManager::allocateVisitState() {
293 if (FirstVisitState) {
294 VisitState *Result = FirstVisitState;
295 FirstVisitState = FirstVisitState->NextState;
296 Result->NextState =
nullptr;
301 return new VisitState(
size());
304 void ModuleManager::returnVisitState(VisitState *
State) {
305 assert(State->NextState ==
nullptr &&
"Visited state is in list?");
306 State->NextState = FirstVisitState;
307 FirstVisitState =
State;
313 ModulesInCommonWithGlobalIndex.clear();
321 ModulesInCommonWithGlobalIndex.push_back(&M);
328 ModulesInCommonWithGlobalIndex.push_back(MF);
334 : FileMgr(FileMgr), PCMCache(&PCMCache), PCHContainerRdr(PCHContainerRdr),
335 HeaderSearchInfo(HeaderSearchInfo) {}
340 llvm::SmallPtrSetImpl<ModuleFile *> *ModuleFilesHit) {
342 if (VisitOrder.size() != Chain.size()) {
345 VisitOrder.reserve(N);
353 UnusedIncomingEdges.resize(
size());
356 UnusedIncomingEdges[M.
Index] = Size;
363 while (!Queue.empty()) {
364 ModuleFile *CurrentModule = Queue.pop_back_val();
365 VisitOrder.push_back(CurrentModule);
369 for (
auto M = CurrentModule->
Imports.rbegin(),
370 MEnd = CurrentModule->
Imports.rend();
376 unsigned &NumUnusedEdges = UnusedIncomingEdges[(*M)->Index];
377 if (NumUnusedEdges && (--NumUnusedEdges == 0))
382 assert(VisitOrder.size() == N &&
"Visitation order is wrong?");
384 delete FirstVisitState;
385 FirstVisitState =
nullptr;
388 VisitState *
State = allocateVisitState();
389 unsigned VisitNumber = State->NextVisitNumber++;
394 if (ModuleFilesHit && !ModulesInCommonWithGlobalIndex.empty()) {
395 for (
unsigned I = 0, N = ModulesInCommonWithGlobalIndex.size(); I != N; ++I)
397 ModuleFile *M = ModulesInCommonWithGlobalIndex[I];
398 if (!ModuleFilesHit->count(M))
399 State->VisitNumber[M->
Index] = VisitNumber;
403 for (
unsigned I = 0, N = VisitOrder.size(); I != N; ++I) {
406 if (State->VisitNumber[CurrentModule->
Index] == VisitNumber)
410 assert(State->VisitNumber[CurrentModule->
Index] == VisitNumber - 1);
411 State->VisitNumber[CurrentModule->
Index] = VisitNumber;
412 if (!Visitor(*CurrentModule))
422 for (llvm::SetVector<ModuleFile *>::iterator
423 M = NextModule->
Imports.begin(),
424 MEnd = NextModule->
Imports.end();
426 if (State->VisitNumber[(*M)->Index] != VisitNumber) {
427 State->Stack.push_back(*M);
428 State->VisitNumber[(*M)->Index] = VisitNumber;
432 if (State->Stack.empty())
436 NextModule = State->Stack.pop_back_val();
440 returnVisitState(State);
445 time_t ExpectedModTime,
447 if (FileName ==
"-") {
454 File = FileMgr.
getFile(FileName,
true,
false);
458 if ((ExpectedSize && ExpectedSize != File->
getSize()) ||
508 llvm::ViewGraph(*
this,
"Modules");
Implements support for file system lookup, file system caching, and directory search management...
llvm::SetVector< ModuleFile * >::const_iterator ChildIteratorType
ModuleFile * lookup(const FileEntry *File) const
Returns the module associated with the given module file.
Defines the clang::FileManager interface and associated types.
time_t getModificationTime() const
DominatorTree GraphTraits specialization so the DominatorTree can be iterable by generic graph iterat...
static bool renderGraphFromBottomUp()
std::string ModuleName
The name of the module.
The module file is out-of-date.
The base class of the type hierarchy.
DOTGraphTraits(bool IsSimple=false)
unsigned Index
The index of this module in the list of modules.
ModuleFile * lookupByFileName(StringRef FileName) const
Returns the module associated with the given file name.
Manages the set of modules loaded by an AST reader.
Manage memory buffers across multiple users.
SourceLocation ImportLoc
The source location where this module was first imported.
AddModuleResult
The result of attempting to add a new module.
ModuleIterator begin()
Forward iterator to traverse all loaded modules.
ModuleManager(FileManager &FileMgr, MemoryBufferCache &PCMCache, const PCHContainerReader &PCHContainerRdr, const HeaderSearch &HeaderSearchInfo)
void viewGraph()
View the graphviz representation of the module graph.
void visit(llvm::function_ref< bool(ModuleFile &M)> Visitor, llvm::SmallPtrSetImpl< ModuleFile *> *ModuleFilesHit=nullptr)
Visit each of the modules.
The signature of a module, which is a hash of the AST content.
void setGlobalIndex(GlobalModuleIndex *Index)
Set the global module index.
Describes a module or submodule.
virtual llvm::StringRef ExtractPCH(llvm::MemoryBufferRef Buffer) const =0
Returns the serialized AST inside the PCH container Buffer.
Module * findModule(StringRef Name) const
Retrieve a module with the given name.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified...
bool lookupModuleFile(StringRef FileName, off_t ExpectedSize, time_t ExpectedModTime, const FileEntry *&File)
Attempt to resolve the given module file name to a file entry.
ModuleIterator end()
Forward iterator end-point to traverse all loaded modules.
The module file is missing.
This abstract interface provides operations for unwrapping containers for serialized ASTs (precompile...
const FileEntry * getFile(StringRef Filename, bool OpenFile=false, bool CacheFailure=true)
Lookup, cache, and verify the specified file (real or virtual).
ASTFileSignature(*)(StringRef) ASTFileSignatureReader
ModuleKind
Specifies the kind of module that has been loaded.
File is from a prebuilt module path.
static nodes_iterator nodes_end(const ModuleManager &Manager)
DOTGraphTraits(bool isSimple=false)
Information about a module that has been loaded by the ASTReader.
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.
void addInMemoryBuffer(StringRef FileName, std::unique_ptr< llvm::MemoryBuffer > Buffer)
Add an in-memory buffer the list of known buffers.
static nodes_iterator nodes_begin(const ModuleManager &Manager)
Encodes a location in the source.
File is an implicitly-loaded module.
Cached information about one file (either on disk or in the virtual file system). ...
static ChildIteratorType child_begin(NodeRef Node)
const FileEntry * getVirtualFile(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...
llvm::SetVector< ModuleFile * > ImportedBy
List of modules which depend on this module.
A global index for a set of module files, providing information about the identifiers within those mo...
The module file was just loaded in response to this call.
pointer_iterator< ModuleManager::ModuleConstIterator > nodes_iterator
ast_type_traits::DynTypedNode Node
Dataflow Directional Tag Classes.
File is an explicitly-loaded module.
ModuleFile * lookupByModuleName(StringRef ModName) const
Returns the module associated with the given module name.
llvm::ErrorOr< std::unique_ptr< llvm::MemoryBuffer > > getBufferForFile(const FileEntry *Entry, bool isVolatile=false, bool ShouldCloseOpenFile=true)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful, otherwise returning null.
static void updateModuleImports(ModuleFile &MF, ModuleFile *ImportedBy, SourceLocation ImportLoc)
bool getNoncachedStatValue(StringRef Path, llvm::vfs::Status &Result)
Get the 'stat' information for the given Path.
void removeModules(ModuleIterator First, llvm::SmallPtrSetImpl< ModuleFile *> &LoadedSuccessfully, ModuleMap *modMap)
Remove the modules starting from First (to the end).
void moduleFileAccepted(ModuleFile *MF)
Notification from the AST reader that the given module file has been "accepted", and will not (can no...
std::string getNodeLabel(ModuleFile *M, const ModuleManager &)
unsigned size() const
Number of modules loaded.
The module file had already been loaded.
void invalidateCache(const FileEntry *Entry)
Remove the real file Entry from the cache.
static ChildIteratorType child_end(NodeRef Node)
llvm::pointee_iterator< SmallVectorImpl< std::unique_ptr< ModuleFile > >::iterator > ModuleIterator
bool DirectlyImported
Whether this module has been directly imported by the user.
llvm::SetVector< ModuleFile * > Imports
List of modules which this module depends on.
std::unique_ptr< llvm::MemoryBuffer > lookupBuffer(StringRef Name)
Returns the in-memory (virtual file) buffer with the given name.
bool loadedModuleFile(ModuleFile *File)
Note that the given module file has been loaded.
static bool checkSignature(ASTFileSignature Signature, ASTFileSignature ExpectedSignature, std::string &ErrorStr)