21 #include "llvm/ADT/SmallString.h" 22 #include "llvm/Config/llvm-config.h" 23 #include "llvm/ADT/STLExtras.h" 24 #include "llvm/Support/FileSystem.h" 25 #include "llvm/Support/MemoryBuffer.h" 26 #include "llvm/Support/Path.h" 27 #include "llvm/Support/raw_ostream.h" 36 using namespace clang;
44 : FS(
std::move(FS)), FileSystemOpts(FSO), SeenDirEntries(64),
45 SeenFileEntries(64), NextFileUID(0) {
46 NumDirLookups = NumFileLookups = 0;
47 NumDirCacheMisses = NumFileCacheMisses = 0;
52 this->FS = llvm::vfs::getRealFileSystem();
58 assert(statCache &&
"No stat cache provided?");
59 StatCache = std::move(statCache);
72 if (llvm::sys::path::is_separator(Filename[Filename.size() - 1]))
75 StringRef DirName = llvm::sys::path::parent_path(Filename);
85 void FileManager::addAncestorsAsVirtualDirs(StringRef Path) {
86 StringRef DirName = llvm::sys::path::parent_path(Path);
90 auto &NamedDirEnt = *SeenDirEntries.insert({DirName,
nullptr}).first;
96 if (NamedDirEnt.second)
100 auto UDE = llvm::make_unique<DirectoryEntry>();
101 UDE->Name = NamedDirEnt.first();
102 NamedDirEnt.second = UDE.get();
103 VirtualDirectoryEntries.push_back(std::move(UDE));
106 addAncestorsAsVirtualDirs(DirName);
114 if (DirName.size() > 1 &&
115 DirName != llvm::sys::path::root_path(DirName) &&
116 llvm::sys::path::is_separator(DirName.back()))
117 DirName = DirName.substr(0, DirName.size()-1);
121 std::string DirNameStr;
122 if (DirName.size() > 1 && DirName.back() ==
':' &&
123 DirName.equals_lower(llvm::sys::path::root_name(DirName))) {
124 DirNameStr = DirName.str() +
'.';
125 DirName = DirNameStr;
133 auto SeenDirInsertResult = SeenDirEntries.insert({DirName,
nullptr});
134 if (!SeenDirInsertResult.second)
135 return SeenDirInsertResult.first->second;
139 auto &NamedDirEnt = *SeenDirInsertResult.first;
140 assert(!NamedDirEnt.second &&
"should be newly-created");
144 StringRef InterndDirName = NamedDirEnt.first();
147 llvm::vfs::Status Status;
148 if (getStatValue(InterndDirName, Status,
false,
nullptr )) {
151 SeenDirEntries.erase(DirName);
161 NamedDirEnt.second = &UDE;
165 UDE.Name = InterndDirName;
176 auto SeenFileInsertResult = SeenFileEntries.insert({
Filename,
nullptr});
177 if (!SeenFileInsertResult.second)
178 return SeenFileInsertResult.first->second;
181 ++NumFileCacheMisses;
182 auto &NamedFileEnt = *SeenFileInsertResult.first;
183 assert(!NamedFileEnt.second &&
"should be newly-created");
187 StringRef InterndFileName = NamedFileEnt.first();
196 if (DirInfo ==
nullptr) {
198 SeenFileEntries.erase(Filename);
207 std::unique_ptr<llvm::vfs::File> F;
208 llvm::vfs::Status Status;
209 if (getStatValue(InterndFileName, Status,
true, openFile ? &F :
nullptr)) {
212 SeenFileEntries.erase(Filename);
217 assert((openFile || !F) &&
"undesired open file");
221 FileEntry &UFE = UniqueRealFiles[Status.getUniqueID()];
223 NamedFileEnt.second = &UFE;
229 *SeenFileEntries.insert({Status.getName(), &UFE}).first;
230 assert(NamedFileEnt.second == &UFE &&
231 "filename from getStatValue() refers to wrong file");
232 InterndFileName = NamedFileEnt.first().data();
243 if (DirInfo != UFE.Dir && Status.IsVFSMapped)
251 UFE.Name = InterndFileName;
257 UFE.Name = InterndFileName;
258 UFE.Size = Status.getSize();
259 UFE.ModTime = llvm::sys::toTimeT(Status.getLastModificationTime());
261 UFE.UID = NextFileUID++;
262 UFE.UniqueID = Status.getUniqueID();
263 UFE.IsNamedPipe = Status.getType() == llvm::sys::fs::file_type::fifo_file;
264 UFE.File = std::move(F);
268 if (
auto PathName = UFE.File->getName())
269 fillRealPathName(&UFE, *PathName);
270 }
else if (!openFile) {
272 fillRealPathName(&UFE, InterndFileName);
279 time_t ModificationTime) {
283 auto &NamedFileEnt = *SeenFileEntries.insert({
Filename,
nullptr}).first;
284 if (NamedFileEnt.second)
285 return NamedFileEnt.second;
288 ++NumFileCacheMisses;
289 addAncestorsAsVirtualDirs(Filename);
298 "The directory of a virtual file should already be in the cache.");
301 llvm::vfs::Status Status;
302 const char *InterndFileName = NamedFileEnt.first().data();
303 if (getStatValue(InterndFileName, Status,
true,
nullptr) == 0) {
304 UFE = &UniqueRealFiles[Status.getUniqueID()];
305 Status = llvm::vfs::Status(
306 Status.getName(), Status.getUniqueID(),
307 llvm::sys::toTimePoint(ModificationTime),
308 Status.getUser(), Status.getGroup(), Size,
309 Status.getType(), Status.getPermissions());
311 NamedFileEnt.second = UFE;
323 UFE->UniqueID = Status.getUniqueID();
324 UFE->IsNamedPipe = Status.getType() == llvm::sys::fs::file_type::fifo_file;
325 fillRealPathName(UFE, Status.
getName());
327 VirtualFileEntries.push_back(llvm::make_unique<FileEntry>());
328 UFE = VirtualFileEntries.back().get();
329 NamedFileEnt.second = UFE;
332 UFE->Name = InterndFileName;
334 UFE->ModTime = ModificationTime;
336 UFE->UID = NextFileUID++;
343 StringRef pathRef(path.data(), path.size());
346 || llvm::sys::path::is_absolute(pathRef))
350 llvm::sys::path::append(NewPath, pathRef);
358 if (!llvm::sys::path::is_absolute(StringRef(Path.data(), Path.size()))) {
359 FS->makeAbsolute(Path);
366 void FileManager::fillRealPathName(
FileEntry *UFE, llvm::StringRef FileName) {
373 llvm::sys::path::remove_dots(AbsPath,
true);
374 UFE->RealPathName = AbsPath.str();
377 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
379 bool ShouldCloseOpenFile) {
380 uint64_t FileSize = Entry->
getSize();
390 Entry->File->getBuffer(Filename, FileSize,
394 if (ShouldCloseOpenFile)
402 return FS->getBufferForFile(Filename, FileSize,
407 return FS->getBufferForFile(FilePath, FileSize,
411 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
414 return FS->getBufferForFile(Filename, -1,
true, isVolatile);
418 return FS->getBufferForFile(FilePath.c_str(), -1,
true, isVolatile);
426 bool FileManager::getStatValue(StringRef Path, llvm::vfs::Status &Status,
428 std::unique_ptr<llvm::vfs::File> *F) {
433 StatCache.get(), *FS));
439 StatCache.get(), *FS));
443 llvm::vfs::Status &
Result) {
447 llvm::ErrorOr<llvm::vfs::Status> S = FS->status(FilePath.c_str());
455 assert(Entry &&
"Cannot invalidate a NULL FileEntry");
457 SeenFileEntries.erase(Entry->
getName());
471 UIDToFiles.resize(NextFileUID);
474 for (llvm::StringMap<FileEntry*, llvm::BumpPtrAllocator>::const_iterator
475 FE = SeenFileEntries.begin(), FEEnd = SeenFileEntries.end();
478 UIDToFiles[FE->getValue()->getUID()] = FE->getValue();
481 for (
const auto &VFE : VirtualFileEntries)
482 UIDToFiles[VFE->getUID()] = VFE.get();
486 off_t Size, time_t ModificationTime) {
488 File->ModTime = ModificationTime;
493 llvm::DenseMap<const DirectoryEntry *, llvm::StringRef>::iterator Known
494 = CanonicalDirNames.find(Dir);
495 if (Known != CanonicalDirNames.end())
496 return Known->second;
498 StringRef CanonicalName(Dir->
getName());
501 if (!FS->getRealPath(Dir->
getName(), CanonicalNameBuf))
502 CanonicalName = StringRef(CanonicalNameBuf).copy(CanonicalNameStorage);
504 CanonicalDirNames.insert({Dir, CanonicalName});
505 return CanonicalName;
509 llvm::errs() <<
"\n*** File Manager Stats:\n";
510 llvm::errs() << UniqueRealFiles.size() <<
" real files found, " 511 << UniqueRealDirs.size() <<
" real dirs found.\n";
512 llvm::errs() << VirtualFileEntries.size() <<
" virtual files found, " 513 << VirtualDirectoryEntries.size() <<
" virtual dirs found.\n";
514 llvm::errs() << NumDirLookups <<
" dir lookups, " 515 << NumDirCacheMisses <<
" dir cache misses.\n";
516 llvm::errs() << NumFileLookups <<
" file lookups, " 517 << NumFileCacheMisses <<
" file cache misses.\n";
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...
const llvm::sys::fs::UniqueID & getUniqueID() const
FileManager(const FileSystemOptions &FileSystemOpts, IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS=nullptr)
Construct a file manager, optionally with a custom VFS.
const FileEntry * getFile(StringRef Filename, bool OpenFile=false, bool CacheFailure=true)
Lookup, cache, and verify the specified file (real or virtual).
const DirectoryEntry * getDirectory(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...
static const DirectoryEntry * getDirectoryFromFile(FileManager &FileMgr, StringRef Filename, bool CacheFailure)
Retrieve the directory that the given file name resides in.
std::string WorkingDir
If set, paths are resolved as if the working directory was set to the value of WorkingDir.
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). ...
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.
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.
bool getNoncachedStatValue(StringRef Path, llvm::vfs::Status &Result)
Get the 'stat' information for the given Path.
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.
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...
static void modifyFileEntry(FileEntry *File, off_t Size, time_t ModificationTime)
Modifies the size and modification time of a previously created FileEntry.
void invalidateCache(const FileEntry *Entry)
Remove the real file Entry from the cache.
StringRef getName() const