25 #include "llvm/ADT/STLExtras.h" 26 #include "llvm/ADT/SetVector.h" 27 #include "llvm/ADT/SmallPtrSet.h" 28 #include "llvm/ADT/SmallVector.h" 29 #include "llvm/ADT/StringRef.h" 30 #include "llvm/ADT/iterator.h" 31 #include "llvm/Support/Chrono.h" 32 #include "llvm/Support/DOTGraphTraits.h" 33 #include "llvm/Support/ErrorOr.h" 34 #include "llvm/Support/GraphWriter.h" 35 #include "llvm/Support/MemoryBuffer.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();
156 NewModule->InputFilesValidationTimestamp =
161 if (std::unique_ptr<llvm::MemoryBuffer> Buffer =
lookupBuffer(FileName)) {
163 NewModule->Buffer = &PCMCache->addBuffer(FileName, std::move(Buffer));
164 }
else if (llvm::MemoryBuffer *Buffer = PCMCache->lookupBuffer(FileName)) {
165 NewModule->Buffer = Buffer;
168 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buf((std::error_code()));
169 if (FileName ==
"-") {
170 Buf = llvm::MemoryBuffer::getSTDIN();
182 ErrorStr = Buf.getError().message();
186 NewModule->Buffer = &PCMCache->addBuffer(FileName, std::move(*Buf));
190 NewModule->Data = PCHContainerRdr.
ExtractPCH(*NewModule->Buffer);
194 if (ExpectedSignature &&
checkSignature(ReadSignature(NewModule->Data),
195 ExpectedSignature, ErrorStr)) {
198 if (!PCMCache->tryToRemoveBuffer(NewModule->FileName))
204 Module = Modules[Entry] = NewModule.get();
208 if (!NewModule->isModule())
209 PCHChain.push_back(NewModule.get());
211 Roots.push_back(NewModule.get());
213 Chain.push_back(std::move(NewModule));
219 llvm::SmallPtrSetImpl<ModuleFile *> &LoadedSuccessfully,
229 llvm::SmallPtrSet<ModuleFile *, 4> victimSet(
230 (llvm::pointer_iterator<ModuleIterator>(First)),
231 (llvm::pointer_iterator<ModuleIterator>(
Last)));
234 return victimSet.count(MF);
237 for (
auto I =
begin(); I != First; ++I) {
238 I->Imports.remove_if(IsVictim);
239 I->ImportedBy.remove_if(IsVictim);
241 Roots.erase(std::remove_if(Roots.begin(), Roots.end(), IsVictim),
245 for (
auto I = First; I !=
Last; ++I) {
246 if (!I->isModule()) {
247 PCHChain.erase(std::find(PCHChain.begin(), PCHChain.end(), &*I),
255 Modules.erase(victim->File);
258 StringRef ModuleName = victim->ModuleName;
260 mod->setASTFile(
nullptr);
271 if (LoadedSuccessfully.count(&*victim) == 0 &&
272 !PCMCache->tryToRemoveBuffer(victim->FileName))
277 Chain.erase(Chain.begin() + (First -
begin()), Chain.end());
282 std::unique_ptr<llvm::MemoryBuffer> Buffer) {
285 InMemoryBuffers[Entry] = std::move(Buffer);
288 ModuleManager::VisitState *ModuleManager::allocateVisitState() {
290 if (FirstVisitState) {
291 VisitState *Result = FirstVisitState;
292 FirstVisitState = FirstVisitState->NextState;
293 Result->NextState =
nullptr;
298 return new VisitState(
size());
301 void ModuleManager::returnVisitState(VisitState *
State) {
302 assert(State->NextState ==
nullptr &&
"Visited state is in list?");
303 State->NextState = FirstVisitState;
304 FirstVisitState =
State;
310 ModulesInCommonWithGlobalIndex.clear();
318 ModulesInCommonWithGlobalIndex.push_back(&M);
325 ModulesInCommonWithGlobalIndex.push_back(MF);
331 : FileMgr(FileMgr), PCMCache(&PCMCache), PCHContainerRdr(PCHContainerRdr),
332 HeaderSearchInfo(HeaderSearchInfo) {}
337 llvm::SmallPtrSetImpl<ModuleFile *> *ModuleFilesHit) {
339 if (VisitOrder.size() != Chain.size()) {
342 VisitOrder.reserve(N);
350 UnusedIncomingEdges.resize(
size());
353 UnusedIncomingEdges[M.
Index] = Size;
360 while (!Queue.empty()) {
361 ModuleFile *CurrentModule = Queue.pop_back_val();
362 VisitOrder.push_back(CurrentModule);
366 for (
auto M = CurrentModule->
Imports.rbegin(),
367 MEnd = CurrentModule->
Imports.rend();
373 unsigned &NumUnusedEdges = UnusedIncomingEdges[(*M)->Index];
374 if (NumUnusedEdges && (--NumUnusedEdges == 0))
379 assert(VisitOrder.size() == N &&
"Visitation order is wrong?");
381 delete FirstVisitState;
382 FirstVisitState =
nullptr;
385 VisitState *
State = allocateVisitState();
386 unsigned VisitNumber = State->NextVisitNumber++;
391 if (ModuleFilesHit && !ModulesInCommonWithGlobalIndex.empty()) {
392 for (
unsigned I = 0, N = ModulesInCommonWithGlobalIndex.size(); I != N; ++I)
394 ModuleFile *M = ModulesInCommonWithGlobalIndex[I];
395 if (!ModuleFilesHit->count(M))
396 State->VisitNumber[M->
Index] = VisitNumber;
400 for (
unsigned I = 0, N = VisitOrder.size(); I != N; ++I) {
403 if (State->VisitNumber[CurrentModule->
Index] == VisitNumber)
407 assert(State->VisitNumber[CurrentModule->
Index] == VisitNumber - 1);
408 State->VisitNumber[CurrentModule->
Index] = VisitNumber;
409 if (!Visitor(*CurrentModule))
419 for (llvm::SetVector<ModuleFile *>::iterator
420 M = NextModule->
Imports.begin(),
421 MEnd = NextModule->
Imports.end();
423 if (State->VisitNumber[(*M)->Index] != VisitNumber) {
424 State->Stack.push_back(*M);
425 State->VisitNumber[(*M)->Index] = VisitNumber;
429 if (State->Stack.empty())
433 NextModule = State->Stack.pop_back_val();
437 returnVisitState(State);
442 time_t ExpectedModTime,
444 if (FileName ==
"-") {
451 File = FileMgr.
getFile(FileName,
true,
false);
455 if ((ExpectedSize && ExpectedSize != File->
getSize()) ||
505 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
virtual StringRef ExtractPCH(llvm::MemoryBufferRef Buffer) const =0
Returns the serialized AST inside the PCH container Buffer.
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.
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.
The result of a status operation.
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)
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). ...
llvm::sys::TimePoint getLastModificationTime() const
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)
Defines the virtual file system interface vfs::FileSystem.
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.
bool getNoncachedStatValue(StringRef Path, vfs::Status &Result)
Get the 'stat' information for the given Path.
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)