23 #include "llvm/ADT/SmallString.h"
24 #include "llvm/Config/llvm-config.h"
25 #include "llvm/ADT/STLExtras.h"
26 #include "llvm/Support/FileSystem.h"
27 #include "llvm/Support/MemoryBuffer.h"
28 #include "llvm/Support/Path.h"
29 #include "llvm/Support/raw_ostream.h"
33 #include <system_error>
35 using namespace clang;
39 #define NON_EXISTENT_DIR reinterpret_cast<DirectoryEntry*>((intptr_t)-1)
43 #define NON_EXISTENT_FILE reinterpret_cast<FileEntry*>((intptr_t)-1)
51 : FS(FS), FileSystemOpts(FSO),
52 SeenDirEntries(64), SeenFileEntries(64), NextFileUID(0) {
53 NumDirLookups = NumFileLookups = 0;
54 NumDirCacheMisses = NumFileCacheMisses = 0;
66 assert(statCache &&
"No stat cache provided?");
67 if (AtBeginning || !StatCache.get()) {
68 statCache->setNextStatCache(std::move(StatCache));
69 StatCache = std::move(statCache);
84 if (StatCache.get() == statCache) {
86 StatCache = StatCache->takeNextStatCache();
95 assert(PrevCache &&
"Stat cache not found for removal");
108 if (Filename.empty())
111 if (llvm::sys::path::is_separator(Filename[Filename.size() - 1]))
114 StringRef DirName = llvm::sys::path::parent_path(Filename);
124 void FileManager::addAncestorsAsVirtualDirs(StringRef Path) {
125 StringRef DirName = llvm::sys::path::parent_path(Path);
130 *SeenDirEntries.insert(std::make_pair(DirName,
nullptr)).first;
140 auto UDE = llvm::make_unique<DirectoryEntry>();
141 UDE->Name = NamedDirEnt.first().data();
142 NamedDirEnt.second = UDE.get();
143 VirtualDirectoryEntries.push_back(std::move(UDE));
146 addAncestorsAsVirtualDirs(DirName);
154 if (DirName.size() > 1 &&
155 DirName != llvm::sys::path::root_path(DirName) &&
156 llvm::sys::path::is_separator(DirName.back()))
157 DirName = DirName.substr(0, DirName.size()-1);
161 std::string DirNameStr;
162 if (DirName.size() > 1 && DirName.back() ==
':' &&
163 DirName.equals_lower(llvm::sys::path::root_name(DirName))) {
164 DirNameStr = DirName.str() +
'.';
165 DirName = DirNameStr;
171 *SeenDirEntries.insert(std::make_pair(DirName,
nullptr)).first;
175 if (NamedDirEnt.second)
177 : NamedDirEnt.second;
186 const char *InterndDirName = NamedDirEnt.first().data();
190 if (getStatValue(InterndDirName, Data,
false,
nullptr )) {
193 SeenDirEntries.erase(DirName);
203 NamedDirEnt.second = &UDE;
207 UDE.Name = InterndDirName;
219 *SeenFileEntries.insert(std::make_pair(Filename,
nullptr)).first;
222 if (NamedFileEnt.second)
224 : NamedFileEnt.second;
226 ++NumFileCacheMisses;
233 const char *InterndFileName = NamedFileEnt.first().data();
242 if (DirInfo ==
nullptr) {
244 SeenFileEntries.erase(Filename);
253 std::unique_ptr<vfs::File> F;
255 if (getStatValue(InterndFileName, Data,
true, openFile ? &F :
nullptr)) {
258 SeenFileEntries.erase(Filename);
263 assert((openFile || !F) &&
"undesired open file");
269 NamedFileEnt.second = &UFE;
273 if (Data.
Name != Filename) {
275 *SeenFileEntries.insert(std::make_pair(Data.
Name,
nullptr)).first;
276 if (!NamedFileEnt.second)
277 NamedFileEnt.second = &UFE;
279 assert(NamedFileEnt.second == &UFE &&
280 "filename from getStatValue() refers to wrong file");
281 InterndFileName = NamedFileEnt.first().data();
300 UFE.Name = InterndFileName;
306 UFE.Name = InterndFileName;
307 UFE.Size = Data.
Size;
310 UFE.UID = NextFileUID++;
313 UFE.InPCH = Data.
InPCH;
314 UFE.File = std::move(F);
321 time_t ModificationTime) {
326 *SeenFileEntries.insert(std::make_pair(Filename,
nullptr)).first;
330 return NamedFileEnt.second;
332 ++NumFileCacheMisses;
337 addAncestorsAsVirtualDirs(Filename);
346 "The directory of a virtual file should already be in the cache.");
350 const char *InterndFileName = NamedFileEnt.first().data();
351 if (getStatValue(InterndFileName, Data,
true,
nullptr) == 0) {
353 Data.
ModTime = ModificationTime;
354 UFE = &UniqueRealFiles[Data.
UniqueID];
356 NamedFileEnt.second = UFE;
370 UFE->InPCH = Data.
InPCH;
374 VirtualFileEntries.push_back(llvm::make_unique<FileEntry>());
375 UFE = VirtualFileEntries.back().get();
376 NamedFileEnt.second = UFE;
379 UFE->Name = InterndFileName;
381 UFE->ModTime = ModificationTime;
383 UFE->UID = NextFileUID++;
389 StringRef pathRef(path.data(), path.size());
392 || llvm::sys::path::is_absolute(pathRef))
396 llvm::sys::path::append(NewPath, pathRef);
404 if (!llvm::sys::path::is_absolute(StringRef(Path.data(), Path.size()))) {
405 llvm::sys::fs::make_absolute(Path);
412 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
414 bool ShouldCloseOpenFile) {
415 uint64_t FileSize = Entry->
getSize();
425 Entry->File->getBuffer(Filename, FileSize,
429 if (ShouldCloseOpenFile)
437 return FS->getBufferForFile(Filename, FileSize,
442 return FS->getBufferForFile(
FilePath, FileSize,
446 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
449 return FS->getBufferForFile(Filename);
453 return FS->getBufferForFile(FilePath.c_str());
461 bool FileManager::getStatValue(
const char *Path,
FileData &Data,
bool isFile,
462 std::unique_ptr<vfs::File> *F) {
472 StatCache.get(), *FS);
480 llvm::ErrorOr<vfs::Status>
S = FS->status(FilePath.c_str());
488 assert(Entry &&
"Cannot invalidate a NULL FileEntry");
490 SeenFileEntries.erase(Entry->
getName());
502 UIDToFiles.resize(NextFileUID);
505 for (llvm::StringMap<FileEntry*, llvm::BumpPtrAllocator>::const_iterator
506 FE = SeenFileEntries.begin(), FEEnd = SeenFileEntries.end();
509 UIDToFiles[FE->getValue()->getUID()] = FE->getValue();
512 for (
const auto &VFE : VirtualFileEntries)
514 UIDToFiles[VFE->getUID()] = VFE.get();
518 off_t Size, time_t ModificationTime) {
520 File->ModTime = ModificationTime;
526 = CanonicalDirNames.find(Dir);
527 if (Known != CanonicalDirNames.end())
528 return Known->second;
530 StringRef CanonicalName(Dir->
getName());
533 char CanonicalNameBuf[PATH_MAX];
534 if (realpath(Dir->
getName(), CanonicalNameBuf))
535 CanonicalName = StringRef(CanonicalNameBuf).copy(CanonicalNameStorage);
538 llvm::sys::fs::make_absolute(CanonicalNameBuf);
539 llvm::sys::path::native(CanonicalNameBuf);
546 llvm::sys::path::remove_dots(CanonicalNameBuf,
true);
547 CanonicalName = StringRef(CanonicalNameBuf).copy(CanonicalNameStorage);
550 CanonicalDirNames.insert(std::make_pair(Dir, CanonicalName));
551 return CanonicalName;
555 llvm::errs() <<
"\n*** File Manager Stats:\n";
556 llvm::errs() << UniqueRealFiles.size() <<
" real files found, "
557 << UniqueRealDirs.size() <<
" real dirs found.\n";
558 llvm::errs() << VirtualFileEntries.size() <<
" virtual files found, "
559 << VirtualDirectoryEntries.size() <<
" virtual dirs found.\n";
560 llvm::errs() << NumDirLookups <<
" dir lookups, "
561 << NumDirCacheMisses <<
" dir cache misses.\n";
562 llvm::errs() << NumFileLookups <<
" file lookups, "
563 << 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.
virtual ~PCHContainerReader()=0
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.
virtual ~PCHContainerWriter()=0
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...