diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/Basic/FileManager.cpp')
-rw-r--r-- | contrib/llvm-project/clang/lib/Basic/FileManager.cpp | 181 |
1 files changed, 115 insertions, 66 deletions
diff --git a/contrib/llvm-project/clang/lib/Basic/FileManager.cpp b/contrib/llvm-project/clang/lib/Basic/FileManager.cpp index e92e9d5911c0..6e9d5d7fb422 100644 --- a/contrib/llvm-project/clang/lib/Basic/FileManager.cpp +++ b/contrib/llvm-project/clang/lib/Basic/FileManager.cpp @@ -69,21 +69,22 @@ void FileManager::clearStatCache() { StatCache.reset(); } /// Retrieve the directory that the given file name resides in. /// Filename can point to either a real file or a virtual file. -static llvm::ErrorOr<const DirectoryEntry *> +static llvm::Expected<DirectoryEntryRef> getDirectoryFromFile(FileManager &FileMgr, StringRef Filename, bool CacheFailure) { if (Filename.empty()) - return std::errc::no_such_file_or_directory; + return llvm::errorCodeToError( + make_error_code(std::errc::no_such_file_or_directory)); if (llvm::sys::path::is_separator(Filename[Filename.size() - 1])) - return std::errc::is_a_directory; + return llvm::errorCodeToError(make_error_code(std::errc::is_a_directory)); StringRef DirName = llvm::sys::path::parent_path(Filename); // Use the current directory if file has no path component. if (DirName.empty()) DirName = "."; - return FileMgr.getDirectory(DirName, CacheFailure); + return FileMgr.getDirectoryRef(DirName, CacheFailure); } /// Add all ancestors of the given path (pointing to either a file or @@ -141,7 +142,7 @@ FileManager::getDirectoryRef(StringRef DirName, bool CacheFailure) { SeenDirEntries.insert({DirName, std::errc::no_such_file_or_directory}); if (!SeenDirInsertResult.second) { if (SeenDirInsertResult.first->second) - return DirectoryEntryRef(&*SeenDirInsertResult.first); + return DirectoryEntryRef(*SeenDirInsertResult.first); return llvm::errorCodeToError(SeenDirInsertResult.first->second.getError()); } @@ -180,7 +181,7 @@ FileManager::getDirectoryRef(StringRef DirName, bool CacheFailure) { UDE.Name = InterndDirName; } - return DirectoryEntryRef(&NamedDirEnt); + return DirectoryEntryRef(NamedDirEnt); } llvm::ErrorOr<const DirectoryEntry *> @@ -212,11 +213,11 @@ FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) { SeenFileInsertResult.first->second.getError()); // Construct and return and FileEntryRef, unless it's a redirect to another // filename. - SeenFileEntryOrRedirect Value = *SeenFileInsertResult.first->second; - FileEntry *FE; - if (LLVM_LIKELY(FE = Value.dyn_cast<FileEntry *>())) - return FileEntryRef(SeenFileInsertResult.first->first(), *FE); - return getFileRef(*Value.get<const StringRef *>(), openFile, CacheFailure); + FileEntryRef::MapValue Value = *SeenFileInsertResult.first->second; + if (LLVM_LIKELY(Value.V.is<FileEntry *>())) + return FileEntryRef(*SeenFileInsertResult.first); + return FileEntryRef(*reinterpret_cast<const FileEntryRef::MapEntry *>( + Value.V.get<const void *>())); } // We've not seen this before. Fill it in. @@ -235,14 +236,15 @@ FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) { // without a 'sys' subdir will get a cached failure result. auto DirInfoOrErr = getDirectoryFromFile(*this, Filename, CacheFailure); if (!DirInfoOrErr) { // Directory doesn't exist, file can't exist. + std::error_code Err = errorToErrorCode(DirInfoOrErr.takeError()); if (CacheFailure) - NamedFileEnt->second = DirInfoOrErr.getError(); + NamedFileEnt->second = Err; else SeenFileEntries.erase(Filename); - return llvm::errorCodeToError(DirInfoOrErr.getError()); + return llvm::errorCodeToError(Err); } - const DirectoryEntry *DirInfo = *DirInfoOrErr; + DirectoryEntryRef DirInfo = *DirInfoOrErr; // FIXME: Use the directory info to prune this, before doing the stat syscall. // FIXME: This will reduce the # syscalls. @@ -268,26 +270,30 @@ FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) { // This occurs when one dir is symlinked to another, for example. FileEntry &UFE = UniqueRealFiles[Status.getUniqueID()]; - NamedFileEnt->second = &UFE; - - // If the name returned by getStatValue is different than Filename, re-intern - // the name. - if (Status.getName() != Filename) { - auto &NewNamedFileEnt = - *SeenFileEntries.insert({Status.getName(), &UFE}).first; - assert((*NewNamedFileEnt.second).get<FileEntry *>() == &UFE && + if (Status.getName() == Filename) { + // The name matches. Set the FileEntry. + NamedFileEnt->second = FileEntryRef::MapValue(UFE, DirInfo); + } else { + // Name mismatch. We need a redirect. First grab the actual entry we want + // to return. + auto &Redirection = + *SeenFileEntries + .insert({Status.getName(), FileEntryRef::MapValue(UFE, DirInfo)}) + .first; + assert(Redirection.second->V.is<FileEntry *>() && + "filename redirected to a non-canonical filename?"); + assert(Redirection.second->V.get<FileEntry *>() == &UFE && "filename from getStatValue() refers to wrong file"); - InterndFileName = NewNamedFileEnt.first().data(); - // In addition to re-interning the name, construct a redirecting seen file - // entry, that will point to the name the filesystem actually wants to use. - StringRef *Redirect = new (CanonicalNameStorage) StringRef(InterndFileName); - auto SeenFileInsertResultIt = SeenFileEntries.find(Filename); - assert(SeenFileInsertResultIt != SeenFileEntries.end() && - "unexpected SeenFileEntries cache miss"); - SeenFileInsertResultIt->second = Redirect; - NamedFileEnt = &*SeenFileInsertResultIt; + + // Cache the redirection in the previously-inserted entry, still available + // in the tentative return value. + NamedFileEnt->second = FileEntryRef::MapValue(Redirection); + + // Fix the tentative return value. + NamedFileEnt = &Redirection; } + FileEntryRef ReturnedRef(*NamedFileEnt); if (UFE.isValid()) { // Already have an entry with this inode, return it. // FIXME: this hack ensures that if we look up a file by a virtual path in @@ -296,26 +302,26 @@ FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) { // module's structure when its headers/module map are mapped in the VFS. // We should remove this as soon as we can properly support a file having // multiple names. - if (DirInfo != UFE.Dir && Status.IsVFSMapped) - UFE.Dir = DirInfo; + if (&DirInfo.getDirEntry() != UFE.Dir && Status.IsVFSMapped) + UFE.Dir = &DirInfo.getDirEntry(); - // Always update the name to use the last name by which a file was accessed. - // FIXME: Neither this nor always using the first name is correct; we want - // to switch towards a design where we return a FileName object that + // Always update LastRef to the last name by which a file was accessed. + // FIXME: Neither this nor always using the first reference is correct; we + // want to switch towards a design where we return a FileName object that // encapsulates both the name by which the file was accessed and the // corresponding FileEntry. - // FIXME: The Name should be removed from FileEntry once all clients - // adopt FileEntryRef. - UFE.Name = InterndFileName; + // FIXME: LastRef should be removed from FileEntry once all clients adopt + // FileEntryRef. + UFE.LastRef = ReturnedRef; - return FileEntryRef(InterndFileName, UFE); + return ReturnedRef; } // Otherwise, we don't have this file yet, add it. - UFE.Name = InterndFileName; + UFE.LastRef = ReturnedRef; UFE.Size = Status.getSize(); UFE.ModTime = llvm::sys::toTimeT(Status.getLastModificationTime()); - UFE.Dir = DirInfo; + UFE.Dir = &DirInfo.getDirEntry(); UFE.UID = NextFileUID++; UFE.UniqueID = Status.getUniqueID(); UFE.IsNamedPipe = Status.getType() == llvm::sys::fs::file_type::fifo_file; @@ -329,24 +335,46 @@ FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) { // We should still fill the path even if we aren't opening the file. fillRealPathName(&UFE, InterndFileName); } - return FileEntryRef(InterndFileName, UFE); + return ReturnedRef; +} + +llvm::Expected<FileEntryRef> FileManager::getSTDIN() { + // Only read stdin once. + if (STDIN) + return *STDIN; + + std::unique_ptr<llvm::MemoryBuffer> Content; + if (auto ContentOrError = llvm::MemoryBuffer::getSTDIN()) + Content = std::move(*ContentOrError); + else + return llvm::errorCodeToError(ContentOrError.getError()); + + STDIN = getVirtualFileRef(Content->getBufferIdentifier(), + Content->getBufferSize(), 0); + FileEntry &FE = const_cast<FileEntry &>(STDIN->getFileEntry()); + FE.Content = std::move(Content); + FE.IsNamedPipe = true; + return *STDIN; } -const FileEntry * -FileManager::getVirtualFile(StringRef Filename, off_t Size, - time_t ModificationTime) { +const FileEntry *FileManager::getVirtualFile(StringRef Filename, off_t Size, + time_t ModificationTime) { + return &getVirtualFileRef(Filename, Size, ModificationTime).getFileEntry(); +} + +FileEntryRef FileManager::getVirtualFileRef(StringRef Filename, off_t Size, + time_t ModificationTime) { ++NumFileLookups; // See if there is already an entry in the map for an existing file. auto &NamedFileEnt = *SeenFileEntries.insert( {Filename, std::errc::no_such_file_or_directory}).first; if (NamedFileEnt.second) { - SeenFileEntryOrRedirect Value = *NamedFileEnt.second; - FileEntry *FE; - if (LLVM_LIKELY(FE = Value.dyn_cast<FileEntry *>())) - return FE; - return getVirtualFile(*Value.get<const StringRef *>(), Size, - ModificationTime); + FileEntryRef::MapValue Value = *NamedFileEnt.second; + if (LLVM_LIKELY(Value.V.is<FileEntry *>())) + return FileEntryRef(NamedFileEnt); + return FileEntryRef(*reinterpret_cast<const FileEntryRef::MapEntry *>( + Value.V.get<const void *>())); } // We've not seen this before, or the file is cached as non-existent. @@ -357,7 +385,8 @@ FileManager::getVirtualFile(StringRef Filename, off_t Size, // Now that all ancestors of Filename are in the cache, the // following call is guaranteed to find the DirectoryEntry from the // cache. - auto DirInfo = getDirectoryFromFile(*this, Filename, /*CacheFailure=*/true); + auto DirInfo = expectedToOptional( + getDirectoryFromFile(*this, Filename, /*CacheFailure=*/true)); assert(DirInfo && "The directory of a virtual file should already be in the cache."); @@ -372,7 +401,7 @@ FileManager::getVirtualFile(StringRef Filename, off_t Size, Status.getUser(), Status.getGroup(), Size, Status.getType(), Status.getPermissions()); - NamedFileEnt.second = UFE; + NamedFileEnt.second = FileEntryRef::MapValue(*UFE, *DirInfo); // If we had already opened this file, close it now so we don't // leak the descriptor. We're not going to use the file @@ -381,8 +410,11 @@ FileManager::getVirtualFile(StringRef Filename, off_t Size, UFE->closeFile(); // If we already have an entry with this inode, return it. + // + // FIXME: Surely this should add a reference by the new name, and return + // it instead... if (UFE->isValid()) - return UFE; + return FileEntryRef(NamedFileEnt); UFE->UniqueID = Status.getUniqueID(); UFE->IsNamedPipe = Status.getType() == llvm::sys::fs::file_type::fifo_file; @@ -390,17 +422,17 @@ FileManager::getVirtualFile(StringRef Filename, off_t Size, } else { VirtualFileEntries.push_back(std::make_unique<FileEntry>()); UFE = VirtualFileEntries.back().get(); - NamedFileEnt.second = UFE; + NamedFileEnt.second = FileEntryRef::MapValue(*UFE, *DirInfo); } - UFE->Name = InterndFileName; + UFE->LastRef = FileEntryRef(NamedFileEnt); UFE->Size = Size; UFE->ModTime = ModificationTime; - UFE->Dir = *DirInfo; + UFE->Dir = &DirInfo->getDirEntry(); UFE->UID = NextFileUID++; UFE->IsValid = true; UFE->File.reset(); - return UFE; + return FileEntryRef(NamedFileEnt); } llvm::Optional<FileEntryRef> FileManager::getBypassFile(FileEntryRef VF) { @@ -409,17 +441,30 @@ llvm::Optional<FileEntryRef> FileManager::getBypassFile(FileEntryRef VF) { if (getStatValue(VF.getName(), Status, /*isFile=*/true, /*F=*/nullptr)) return None; - // Fill it in from the stat. + if (!SeenBypassFileEntries) + SeenBypassFileEntries = std::make_unique< + llvm::StringMap<llvm::ErrorOr<FileEntryRef::MapValue>>>(); + + // If we've already bypassed just use the existing one. + auto Insertion = SeenBypassFileEntries->insert( + {VF.getName(), std::errc::no_such_file_or_directory}); + if (!Insertion.second) + return FileEntryRef(*Insertion.first); + + // Fill in the new entry from the stat. BypassFileEntries.push_back(std::make_unique<FileEntry>()); const FileEntry &VFE = VF.getFileEntry(); FileEntry &BFE = *BypassFileEntries.back(); - BFE.Name = VFE.getName(); + Insertion.first->second = FileEntryRef::MapValue(BFE, VF.getDir()); + BFE.LastRef = FileEntryRef(*Insertion.first); BFE.Size = Status.getSize(); BFE.Dir = VFE.Dir; BFE.ModTime = llvm::sys::toTimeT(Status.getLastModificationTime()); BFE.UID = NextFileUID++; BFE.IsValid = true; - return FileEntryRef(VF.getName(), BFE); + + // Save the entry in the bypass table and return. + return FileEntryRef(*Insertion.first); } bool FileManager::FixupRelativePath(SmallVectorImpl<char> &path) const { @@ -460,10 +505,14 @@ void FileManager::fillRealPathName(FileEntry *UFE, llvm::StringRef FileName) { llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileManager::getBufferForFile(const FileEntry *Entry, bool isVolatile, bool RequiresNullTerminator) { + // If the content is living on the file entry, return a reference to it. + if (Entry->Content) + return llvm::MemoryBuffer::getMemBuffer(Entry->Content->getMemBufferRef()); + uint64_t FileSize = Entry->getSize(); // If there's a high enough chance that the file have changed since we // got its size, force a stat before opening it. - if (isVolatile) + if (isVolatile || Entry->isNamedPipe()) FileSize = -1; StringRef Filename = Entry->getName(); @@ -534,13 +583,13 @@ void FileManager::GetUniqueIDMapping( UIDToFiles.resize(NextFileUID); // Map file entries - for (llvm::StringMap<llvm::ErrorOr<SeenFileEntryOrRedirect>, + for (llvm::StringMap<llvm::ErrorOr<FileEntryRef::MapValue>, llvm::BumpPtrAllocator>::const_iterator FE = SeenFileEntries.begin(), FEEnd = SeenFileEntries.end(); FE != FEEnd; ++FE) - if (llvm::ErrorOr<SeenFileEntryOrRedirect> Entry = FE->getValue()) { - if (const auto *FE = (*Entry).dyn_cast<FileEntry *>()) + if (llvm::ErrorOr<FileEntryRef::MapValue> Entry = FE->getValue()) { + if (const auto *FE = Entry->V.dyn_cast<FileEntry *>()) UIDToFiles[FE->getUID()] = FE; } |