21 #include "llvm/ADT/STLExtras.h" 22 #include "llvm/ADT/SmallString.h" 23 #include "llvm/ADT/Statistic.h" 24 #include "llvm/Config/llvm-config.h" 25 #include "llvm/Support/FileSystem.h" 26 #include "llvm/Support/MemoryBuffer.h" 27 #include "llvm/Support/Path.h" 28 #include "llvm/Support/raw_ostream.h" 37 using namespace clang;
39 #define DEBUG_TYPE "file-search" 44 "Number of directory cache misses.");
53 : FS(
std::move(FS)), FileSystemOpts(FSO), SeenDirEntries(64),
54 SeenFileEntries(64), NextFileUID(0) {
58 this->FS = llvm::vfs::getRealFileSystem();
64 assert(statCache &&
"No stat cache provided?");
65 StatCache = std::move(statCache);
72 static llvm::ErrorOr<const DirectoryEntry *>
76 return std::errc::no_such_file_or_directory;
78 if (llvm::sys::path::is_separator(Filename[Filename.size() - 1]))
79 return std::errc::is_a_directory;
81 StringRef DirName = llvm::sys::path::parent_path(Filename);
91 void FileManager::addAncestorsAsVirtualDirs(StringRef Path) {
92 StringRef DirName = llvm::sys::path::parent_path(Path);
96 auto &NamedDirEnt = *SeenDirEntries.insert(
97 {DirName, std::errc::no_such_file_or_directory}).first;
103 if (NamedDirEnt.second)
107 auto UDE = std::make_unique<DirectoryEntry>();
108 UDE->Name = NamedDirEnt.first();
109 NamedDirEnt.second = *UDE.get();
110 VirtualDirectoryEntries.push_back(std::move(UDE));
113 addAncestorsAsVirtualDirs(DirName);
121 if (DirName.size() > 1 &&
122 DirName != llvm::sys::path::root_path(DirName) &&
123 llvm::sys::path::is_separator(DirName.back()))
124 DirName = DirName.substr(0, DirName.size()-1);
128 std::string DirNameStr;
129 if (DirName.size() > 1 && DirName.back() ==
':' &&
130 DirName.equals_lower(llvm::sys::path::root_name(DirName))) {
131 DirNameStr = DirName.str() +
'.';
132 DirName = DirNameStr;
140 auto SeenDirInsertResult =
141 SeenDirEntries.insert({DirName, std::errc::no_such_file_or_directory});
142 if (!SeenDirInsertResult.second) {
143 if (SeenDirInsertResult.first->second)
145 return llvm::errorCodeToError(SeenDirInsertResult.first->second.getError());
150 auto &NamedDirEnt = *SeenDirInsertResult.first;
151 assert(!NamedDirEnt.second &&
"should be newly-created");
155 StringRef InterndDirName = NamedDirEnt.first();
158 llvm::vfs::Status Status;
159 auto statError = getStatValue(InterndDirName, Status,
false,
164 NamedDirEnt.second = statError;
166 SeenDirEntries.erase(DirName);
167 return llvm::errorCodeToError(statError);
176 NamedDirEnt.second = UDE;
180 UDE.Name = InterndDirName;
186 llvm::ErrorOr<const DirectoryEntry *>
190 return &
Result->getDirEntry();
191 return llvm::errorToErrorCode(
Result.takeError());
194 llvm::ErrorOr<const FileEntry *>
198 return &
Result->getFileEntry();
199 return llvm::errorToErrorCode(
Result.takeError());
207 auto SeenFileInsertResult =
208 SeenFileEntries.insert({
Filename, std::errc::no_such_file_or_directory});
209 if (!SeenFileInsertResult.second) {
210 if (!SeenFileInsertResult.first->second)
211 return llvm::errorCodeToError(
212 SeenFileInsertResult.first->second.getError());
215 SeenFileEntryOrRedirect
Value = *SeenFileInsertResult.first->second;
217 if (LLVM_LIKELY(FE = Value.dyn_cast<
FileEntry *>()))
218 return FileEntryRef(SeenFileInsertResult.first->first(), *FE);
219 return getFileRef(*Value.get<
const StringRef *>(), openFile, CacheFailure);
223 ++NumFileCacheMisses;
224 auto *NamedFileEnt = &*SeenFileInsertResult.first;
225 assert(!NamedFileEnt->second &&
"should be newly-created");
229 StringRef InterndFileName = NamedFileEnt->first();
239 NamedFileEnt->second = DirInfoOrErr.getError();
241 SeenFileEntries.erase(Filename);
243 return llvm::errorCodeToError(DirInfoOrErr.getError());
251 std::unique_ptr<llvm::vfs::File> F;
252 llvm::vfs::Status Status;
253 auto statError = getStatValue(InterndFileName, Status,
true,
254 openFile ? &F :
nullptr);
258 NamedFileEnt->second = statError;
260 SeenFileEntries.erase(Filename);
262 return llvm::errorCodeToError(statError);
265 assert((openFile || !F) &&
"undesired open file");
269 FileEntry &UFE = UniqueRealFiles[Status.getUniqueID()];
271 NamedFileEnt->second = &UFE;
276 auto &NewNamedFileEnt =
277 *SeenFileEntries.insert({Status.getName(), &UFE}).first;
278 assert((*NewNamedFileEnt.second).get<
FileEntry *>() == &UFE &&
279 "filename from getStatValue() refers to wrong file");
280 InterndFileName = NewNamedFileEnt.first().data();
283 StringRef *Redirect =
new (CanonicalNameStorage) StringRef(InterndFileName);
284 auto SeenFileInsertResultIt = SeenFileEntries.find(Filename);
285 assert(SeenFileInsertResultIt != SeenFileEntries.end() &&
286 "unexpected SeenFileEntries cache miss");
287 SeenFileInsertResultIt->second = Redirect;
288 NamedFileEnt = &*SeenFileInsertResultIt;
299 if (DirInfo != UFE.Dir && Status.IsVFSMapped)
309 UFE.Name = InterndFileName;
315 UFE.Name = InterndFileName;
316 UFE.Size = Status.getSize();
317 UFE.ModTime = llvm::sys::toTimeT(Status.getLastModificationTime());
319 UFE.UID = NextFileUID++;
320 UFE.UniqueID = Status.getUniqueID();
321 UFE.IsNamedPipe = Status.getType() == llvm::sys::fs::file_type::fifo_file;
322 UFE.File = std::move(F);
326 if (
auto PathName = UFE.File->getName())
327 fillRealPathName(&UFE, *PathName);
328 }
else if (!openFile) {
330 fillRealPathName(&UFE, InterndFileName);
337 time_t ModificationTime) {
341 auto &NamedFileEnt = *SeenFileEntries.insert(
342 {
Filename, std::errc::no_such_file_or_directory}).first;
343 if (NamedFileEnt.second) {
344 SeenFileEntryOrRedirect
Value = *NamedFileEnt.second;
346 if (LLVM_LIKELY(FE = Value.dyn_cast<
FileEntry *>()))
353 ++NumFileCacheMisses;
354 addAncestorsAsVirtualDirs(Filename);
362 "The directory of a virtual file should already be in the cache.");
365 llvm::vfs::Status Status;
366 const char *InterndFileName = NamedFileEnt.first().data();
367 if (!getStatValue(InterndFileName, Status,
true,
nullptr)) {
368 UFE = &UniqueRealFiles[Status.getUniqueID()];
369 Status = llvm::vfs::Status(
370 Status.getName(), Status.getUniqueID(),
371 llvm::sys::toTimePoint(ModificationTime),
372 Status.getUser(), Status.getGroup(), Size,
373 Status.getType(), Status.getPermissions());
375 NamedFileEnt.second = UFE;
387 UFE->UniqueID = Status.getUniqueID();
388 UFE->IsNamedPipe = Status.getType() == llvm::sys::fs::file_type::fifo_file;
389 fillRealPathName(UFE, Status.
getName());
391 VirtualFileEntries.push_back(std::make_unique<FileEntry>());
392 UFE = VirtualFileEntries.back().get();
393 NamedFileEnt.second = UFE;
396 UFE->Name = InterndFileName;
398 UFE->ModTime = ModificationTime;
400 UFE->UID = NextFileUID++;
408 llvm::vfs::Status Status;
409 if (getStatValue(VF.
getName(), Status,
true,
nullptr))
413 BypassFileEntries.push_back(std::make_unique<FileEntry>());
415 FileEntry &BFE = *BypassFileEntries.back();
417 BFE.Size = Status.getSize();
419 BFE.ModTime = llvm::sys::toTimeT(Status.getLastModificationTime());
420 BFE.UID = NextFileUID++;
426 StringRef pathRef(path.data(), path.size());
429 || llvm::sys::path::is_absolute(pathRef))
433 llvm::sys::path::append(NewPath, pathRef);
441 if (!llvm::sys::path::is_absolute(StringRef(Path.data(), Path.size()))) {
442 FS->makeAbsolute(Path);
449 void FileManager::fillRealPathName(
FileEntry *UFE, llvm::StringRef FileName) {
456 llvm::sys::path::remove_dots(AbsPath,
true);
457 UFE->RealPathName = AbsPath.str();
460 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
462 uint64_t FileSize = Entry->
getSize();
472 Entry->File->getBuffer(Filename, FileSize,
479 return getBufferForFileImpl(Filename, FileSize, isVolatile);
482 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
483 FileManager::getBufferForFileImpl(StringRef
Filename, int64_t FileSize,
486 return FS->getBufferForFile(
Filename, FileSize,
491 return FS->getBufferForFile(FilePath, FileSize,
501 FileManager::getStatValue(StringRef Path, llvm::vfs::Status &Status,
502 bool isFile, std::unique_ptr<llvm::vfs::File> *F) {
507 StatCache.get(), *FS);
513 StatCache.get(), *FS);
518 llvm::vfs::Status &
Result) {
522 llvm::ErrorOr<llvm::vfs::Status> S = FS->status(FilePath.c_str());
526 return std::error_code();
532 UIDToFiles.resize(NextFileUID);
535 for (llvm::StringMap<llvm::ErrorOr<SeenFileEntryOrRedirect>,
536 llvm::BumpPtrAllocator>::const_iterator
537 FE = SeenFileEntries.begin(),
538 FEEnd = SeenFileEntries.end();
540 if (llvm::ErrorOr<SeenFileEntryOrRedirect> Entry = FE->getValue()) {
541 if (
const auto *FE = (*Entry).dyn_cast<
FileEntry *>())
542 UIDToFiles[FE->getUID()] = FE;
546 for (
const auto &VFE : VirtualFileEntries)
547 UIDToFiles[VFE->getUID()] = VFE.get();
551 llvm::DenseMap<const void *, llvm::StringRef>::iterator Known
552 = CanonicalNames.find(Dir);
553 if (Known != CanonicalNames.end())
554 return Known->second;
556 StringRef CanonicalName(Dir->
getName());
559 if (!FS->getRealPath(Dir->
getName(), CanonicalNameBuf))
560 CanonicalName = StringRef(CanonicalNameBuf).copy(CanonicalNameStorage);
562 CanonicalNames.insert({Dir, CanonicalName});
563 return CanonicalName;
567 llvm::DenseMap<const void *, llvm::StringRef>::iterator Known
568 = CanonicalNames.find(File);
569 if (Known != CanonicalNames.end())
570 return Known->second;
572 StringRef CanonicalName(File->
getName());
575 if (!FS->getRealPath(File->
getName(), CanonicalNameBuf))
576 CanonicalName = StringRef(CanonicalNameBuf).copy(CanonicalNameStorage);
578 CanonicalNames.insert({File, CanonicalName});
579 return CanonicalName;
583 llvm::errs() <<
"\n*** File Manager Stats:\n";
584 llvm::errs() << UniqueRealFiles.size() <<
" real files found, " 585 << UniqueRealDirs.size() <<
" real dirs found.\n";
586 llvm::errs() << VirtualFileEntries.size() <<
" virtual files found, " 587 << VirtualDirectoryEntries.size() <<
" virtual dirs found.\n";
588 llvm::errs() << NumDirLookups <<
" dir lookups, " 589 << NumDirCacheMisses <<
" dir cache misses.\n";
590 llvm::errs() << NumFileLookups <<
" file lookups, " 591 << NumFileCacheMisses <<
" file cache misses.\n";
ALWAYS_ENABLED_STATISTIC(NumDirLookups, "Number of directory lookups.")
Implements support for file system lookup, file system caching, and directory search management...
Defines the clang::FileManager interface and associated types.
void GetUniqueIDMapping(SmallVectorImpl< const FileEntry *> &UIDToFiles) const
Produce an array mapping from the unique IDs assigned to each file to the corresponding FileEntry poi...
Defines the FileSystemStatCache interface.
bool makeAbsolutePath(SmallVectorImpl< char > &Path) const
Makes Path absolute taking into account FileSystemOptions and the working directory option...
A reference to a FileEntry that includes the name of the file as it was accessed by the FileManager's...
const StringRef getName() const
FileManager(const FileSystemOptions &FileSystemOpts, IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS=nullptr)
Construct a file manager, optionally with a custom VFS.
llvm::ErrorOr< const DirectoryEntry * > getDirectory(StringRef DirName, bool CacheFailure=true)
Lookup, cache, and verify the specified directory (real or virtual).
llvm::Expected< DirectoryEntryRef > getDirectoryRef(StringRef DirName, bool CacheFailure=true)
Lookup, cache, and verify the specified directory (real or virtual).
bool FixupRelativePath(SmallVectorImpl< char > &path) const
If path is not absolute and FileSystemOptions set the working directory, the path is modified to be r...
std::string WorkingDir
If set, paths are resolved as if the working directory was set to the value of WorkingDir.
static llvm::ErrorOr< const DirectoryEntry * > getDirectoryFromFile(FileManager &FileMgr, StringRef Filename, bool CacheFailure)
Retrieve the directory that the given file name resides in.
The result type of a method or function.
StringRef getName() const
Cached information about one file (either on disk or in the virtual file system). ...
std::error_code getNoncachedStatValue(StringRef Path, llvm::vfs::Status &Result)
Get the 'stat' information for the given Path.
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...
StringRef getCanonicalName(const DirectoryEntry *Dir)
Retrieve the canonical name for a given directory.
Dataflow Directional Tag Classes.
void clearStatCache()
Removes the FileSystemStatCache object from the manager.
A reference to a DirectoryEntry that includes the name of the directory as it was accessed by the Fil...
llvm::ErrorOr< const FileEntry * > getFile(StringRef Filename, bool OpenFile=false, bool CacheFailure=true)
Lookup, cache, and verify the specified file (real or virtual).
Cached information about one directory (either on disk or in the virtual file system).
void setStatCache(std::unique_ptr< FileSystemStatCache > statCache)
Installs the provided FileSystemStatCache object within the FileManager.
Keeps track of options that affect how file operations are performed.
llvm::Optional< FileEntryRef > getBypassFile(FileEntryRef VFE)
Retrieve a FileEntry that bypasses VFE, which is expected to be a virtual file entry, to access the real file.
static std::error_code get(StringRef Path, llvm::vfs::Status &Status, bool isFile, std::unique_ptr< llvm::vfs::File > *F, FileSystemStatCache *Cache, llvm::vfs::FileSystem &FS)
Get the 'stat' information for the specified path, using the cache to accelerate it if possible...
llvm::ErrorOr< std::unique_ptr< llvm::MemoryBuffer > > getBufferForFile(const FileEntry *Entry, bool isVolatile=false)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful, otherwise returning null.
StringRef getName() const
const FileEntry & getFileEntry() const
llvm::Expected< FileEntryRef > getFileRef(StringRef Filename, bool OpenFile=false, bool CacheFailure=true)
Lookup, cache, and verify the specified file (real or virtual).