22 #include "llvm/ADT/SmallString.h"
23 #include "llvm/Config/llvm-config.h"
24 #include "llvm/ADT/STLExtras.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"
32 #include <system_error>
34 using namespace clang;
38 #define NON_EXISTENT_DIR reinterpret_cast<DirectoryEntry*>((intptr_t)-1)
42 #define NON_EXISTENT_FILE reinterpret_cast<FileEntry*>((intptr_t)-1)
50 : FS(FS), FileSystemOpts(FSO),
51 SeenDirEntries(64), SeenFileEntries(64), NextFileUID(0) {
52 NumDirLookups = NumFileLookups = 0;
53 NumDirCacheMisses = NumFileCacheMisses = 0;
65 assert(statCache &&
"No stat cache provided?");
66 if (AtBeginning || !StatCache.get()) {
67 statCache->setNextStatCache(std::move(StatCache));
68 StatCache = std::move(statCache);
83 if (StatCache.get() == statCache) {
85 StatCache = StatCache->takeNextStatCache();
94 assert(PrevCache &&
"Stat cache not found for removal");
107 if (Filename.empty())
110 if (llvm::sys::path::is_separator(Filename[Filename.size() - 1]))
113 StringRef DirName = llvm::sys::path::parent_path(Filename);
123 void FileManager::addAncestorsAsVirtualDirs(StringRef Path) {
124 StringRef DirName = llvm::sys::path::parent_path(Path);
129 *SeenDirEntries.insert(std::make_pair(DirName,
nullptr)).first;
139 auto UDE = llvm::make_unique<DirectoryEntry>();
140 UDE->Name = NamedDirEnt.first().data();
141 NamedDirEnt.second = UDE.get();
142 VirtualDirectoryEntries.push_back(std::move(UDE));
145 addAncestorsAsVirtualDirs(DirName);
153 if (DirName.size() > 1 &&
154 DirName != llvm::sys::path::root_path(DirName) &&
155 llvm::sys::path::is_separator(DirName.back()))
156 DirName = DirName.substr(0, DirName.size()-1);
160 std::string DirNameStr;
161 if (DirName.size() > 1 && DirName.back() ==
':' &&
162 DirName.equals_lower(llvm::sys::path::root_name(DirName))) {
163 DirNameStr = DirName.str() +
'.';
164 DirName = DirNameStr;
170 *SeenDirEntries.insert(std::make_pair(DirName,
nullptr)).first;
174 if (NamedDirEnt.second)
176 : NamedDirEnt.second;
185 const char *InterndDirName = NamedDirEnt.first().data();
189 if (getStatValue(InterndDirName, Data,
false,
nullptr )) {
192 SeenDirEntries.erase(DirName);
202 NamedDirEnt.second = &UDE;
206 UDE.Name = InterndDirName;
218 *SeenFileEntries.insert(std::make_pair(Filename,
nullptr)).first;
221 if (NamedFileEnt.second)
223 : NamedFileEnt.second;
225 ++NumFileCacheMisses;
232 const char *InterndFileName = NamedFileEnt.first().data();
241 if (DirInfo ==
nullptr) {
243 SeenFileEntries.erase(Filename);
252 std::unique_ptr<vfs::File> F;
254 if (getStatValue(InterndFileName, Data,
true, openFile ? &F :
nullptr)) {
257 SeenFileEntries.erase(Filename);
262 assert((openFile || !F) &&
"undesired open file");
268 NamedFileEnt.second = &UFE;
272 if (Data.
Name != Filename) {
274 *SeenFileEntries.insert(std::make_pair(Data.
Name,
nullptr)).first;
275 if (!NamedFileEnt.second)
276 NamedFileEnt.second = &UFE;
278 assert(NamedFileEnt.second == &UFE &&
279 "filename from getStatValue() refers to wrong file");
280 InterndFileName = NamedFileEnt.first().data();
299 UFE.Name = InterndFileName;
305 UFE.Name = InterndFileName;
306 UFE.Size = Data.
Size;
309 UFE.UID = NextFileUID++;
312 UFE.InPCH = Data.
InPCH;
313 UFE.File = std::move(F);
316 if (
auto RealPathName = UFE.File->getName())
317 UFE.RealPathName = *RealPathName;
323 time_t ModificationTime) {
328 *SeenFileEntries.insert(std::make_pair(Filename,
nullptr)).first;
332 return NamedFileEnt.second;
334 ++NumFileCacheMisses;
339 addAncestorsAsVirtualDirs(Filename);
348 "The directory of a virtual file should already be in the cache.");
352 const char *InterndFileName = NamedFileEnt.first().data();
353 if (getStatValue(InterndFileName, Data,
true,
nullptr) == 0) {
355 Data.
ModTime = ModificationTime;
356 UFE = &UniqueRealFiles[Data.
UniqueID];
358 NamedFileEnt.second = UFE;
372 UFE->InPCH = Data.
InPCH;
376 VirtualFileEntries.push_back(llvm::make_unique<FileEntry>());
377 UFE = VirtualFileEntries.back().get();
378 NamedFileEnt.second = UFE;
381 UFE->Name = InterndFileName;
383 UFE->ModTime = ModificationTime;
385 UFE->UID = NextFileUID++;
391 StringRef pathRef(path.data(), path.size());
394 || llvm::sys::path::is_absolute(pathRef))
398 llvm::sys::path::append(NewPath, pathRef);
406 if (!llvm::sys::path::is_absolute(StringRef(Path.data(), Path.size()))) {
407 llvm::sys::fs::make_absolute(Path);
414 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
416 bool ShouldCloseOpenFile) {
417 uint64_t FileSize = Entry->
getSize();
427 Entry->File->getBuffer(Filename, FileSize,
431 if (ShouldCloseOpenFile)
439 return FS->getBufferForFile(Filename, FileSize,
444 return FS->getBufferForFile(
FilePath, FileSize,
448 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
451 return FS->getBufferForFile(Filename);
455 return FS->getBufferForFile(FilePath.c_str());
463 bool FileManager::getStatValue(
const char *Path,
FileData &Data,
bool isFile,
464 std::unique_ptr<vfs::File> *F) {
474 StatCache.get(), *FS);
482 llvm::ErrorOr<vfs::Status>
S = FS->status(FilePath.c_str());
490 assert(Entry &&
"Cannot invalidate a NULL FileEntry");
492 SeenFileEntries.erase(Entry->
getName());
504 UIDToFiles.resize(NextFileUID);
507 for (llvm::StringMap<FileEntry*, llvm::BumpPtrAllocator>::const_iterator
508 FE = SeenFileEntries.begin(), FEEnd = SeenFileEntries.end();
511 UIDToFiles[FE->getValue()->getUID()] = FE->getValue();
514 for (
const auto &VFE : VirtualFileEntries)
516 UIDToFiles[VFE->getUID()] = VFE.get();
520 off_t Size, time_t ModificationTime) {
522 File->ModTime = ModificationTime;
528 = CanonicalDirNames.find(Dir);
529 if (Known != CanonicalDirNames.end())
530 return Known->second;
532 StringRef CanonicalName(Dir->
getName());
535 char CanonicalNameBuf[PATH_MAX];
536 if (realpath(Dir->
getName(), CanonicalNameBuf))
537 CanonicalName = StringRef(CanonicalNameBuf).copy(CanonicalNameStorage);
540 llvm::sys::fs::make_absolute(CanonicalNameBuf);
541 llvm::sys::path::native(CanonicalNameBuf);
548 llvm::sys::path::remove_dots(CanonicalNameBuf,
true);
549 CanonicalName = StringRef(CanonicalNameBuf).copy(CanonicalNameStorage);
552 CanonicalDirNames.insert(std::make_pair(Dir, CanonicalName));
553 return CanonicalName;
557 llvm::errs() <<
"\n*** File Manager Stats:\n";
558 llvm::errs() << UniqueRealFiles.size() <<
" real files found, "
559 << UniqueRealDirs.size() <<
" real dirs found.\n";
560 llvm::errs() << VirtualFileEntries.size() <<
" virtual files found, "
561 << VirtualDirectoryEntries.size() <<
" virtual dirs found.\n";
562 llvm::errs() << NumDirLookups <<
" dir lookups, "
563 << NumDirCacheMisses <<
" dir cache misses.\n";
564 llvm::errs() << NumFileLookups <<
" file lookups, "
565 << 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.
IntrusiveRefCntPtr< FileSystem > getRealFileSystem()
Gets an vfs::FileSystem for the 'real' file system, as seen by the operating system.
Defines the FileSystemStatCache interface.
FileManager(const FileSystemOptions &FileSystemOpts, IntrusiveRefCntPtr< vfs::FileSystem > FS=nullptr)
static bool get(const char *Path, FileData &Data, bool isFile, std::unique_ptr< vfs::File > *F, FileSystemStatCache *Cache, vfs::FileSystem &FS)
Get the 'stat' information for the specified path, using the cache to accelerate it if possible...
#define NON_EXISTENT_DIR
NON_EXISTENT_DIR - A special value distinct from null that is used to represent a dir name that doesn...
#define NON_EXISTENT_FILE
NON_EXISTENT_FILE - A special value distinct from null that is used to represent a filename that does...
bool makeAbsolutePath(SmallVectorImpl< char > &Path) const
Makes Path absolute taking into account FileSystemOptions and the working directory option...
Abstract interface for introducing a FileManager cache for 'stat' system calls, which is used by prec...
std::unique_ptr< FileSystemStatCache > takeNextStatCache()
Retrieve the next stat call cache in the chain, transferring ownership of this cache (and...
The result of a status operation.
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).
static const DirectoryEntry * getDirectoryFromFile(FileManager &FileMgr, StringRef Filename, bool CacheFailure)
Retrieve the directory that the given file name resides in.
const llvm::sys::fs::UniqueID & getUniqueID() const
void setNextStatCache(std::unique_ptr< FileSystemStatCache > Cache)
Sets the next stat call cache in the chain of stat caches.
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.
void addStatCache(std::unique_ptr< FileSystemStatCache > statCache, bool AtBeginning=false)
Installs the provided FileSystemStatCache object within the FileManager.
const char * getName() const
llvm::sys::fs::UniqueID UniqueID
const TemplateArgument * iterator
Cached information about one file (either on disk or in the virtual file system). ...
void clearStatCaches()
Removes all FileSystemStatCache objects from the manager.
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...
const char * getName() const
StringRef getCanonicalName(const DirectoryEntry *Dir)
Retrieve the canonical name for a given directory.
void removeStatCache(FileSystemStatCache *statCache)
Removes the specified 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.
Cached information about one directory (either on disk or in the virtual file system).
Keeps track of options that affect how file operations are performed.
bool getNoncachedStatValue(StringRef Path, vfs::Status &Result)
Get the 'stat' information for the given Path.
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.
bool FixupRelativePath(SmallVectorImpl< char > &path) const
If path is not absolute and FileSystemOptions set the working directory, the path is modified to be r...
FileSystemStatCache * getNextStatCache()
Retrieve the next stat call cache in the chain.
void GetUniqueIDMapping(SmallVectorImpl< const FileEntry * > &UIDToFiles) const
Produce an array mapping from the unique IDs assigned to each file to the corresponding FileEntry poi...