FileManager: Use llvm::Expected in new getFileRef API

`FileManager::getFileRef` is a modern API which we expect to convert to
over time.  We should modernize the error handling as well, using
`llvm::Expected` instead of `llvm::ErrorOr`, to help clients that care
about errors to ensure nothing is missed.

However, not all clients care.  I've also added another path for those
that don't:

- `FileEntryRef` is now copy- and move-assignable (using a pointer
  instead of a reference).
- `FileManager::getOptionalFileRef` returns an `llvm::Optional` instead
  of `llvm::Expected`.
- Added an `llvm::expectedToOptional` utility in case this is useful
  elsewhere.

https://reviews.llvm.org/D66705

llvm-svn: 369943
This commit is contained in:
Duncan P. N. Exon Smith 2019-08-26 18:29:51 +00:00
parent 36d1588f01
commit 9ef6c49baf
6 changed files with 50 additions and 28 deletions

View File

@ -110,26 +110,27 @@ public:
/// accessed by the FileManager's client.
class FileEntryRef {
public:
FileEntryRef() = delete;
FileEntryRef(StringRef Name, const FileEntry &Entry)
: Name(Name), Entry(Entry) {}
: Name(Name), Entry(&Entry) {}
const StringRef getName() const { return Name; }
const FileEntry &getFileEntry() const { return Entry; }
const FileEntry &getFileEntry() const { return *Entry; }
off_t getSize() const { return Entry.getSize(); }
off_t getSize() const { return Entry->getSize(); }
unsigned getUID() const { return Entry.getUID(); }
unsigned getUID() const { return Entry->getUID(); }
const llvm::sys::fs::UniqueID &getUniqueID() const {
return Entry.getUniqueID();
return Entry->getUniqueID();
}
time_t getModificationTime() const { return Entry.getModificationTime(); }
time_t getModificationTime() const { return Entry->getModificationTime(); }
private:
StringRef Name;
const FileEntry &Entry;
const FileEntry *Entry;
};
/// Implements support for file system lookup, file system caching,
@ -284,10 +285,18 @@ public:
///
/// \param CacheFailure If true and the file does not exist, we'll cache
/// the failure to find this file.
llvm::ErrorOr<FileEntryRef> getFileRef(StringRef Filename,
llvm::Expected<FileEntryRef> getFileRef(StringRef Filename,
bool OpenFile = false,
bool CacheFailure = true);
/// Get a FileEntryRef if it exists, without doing anything on error.
llvm::Optional<FileEntryRef> getOptionalFileRef(StringRef Filename,
bool OpenFile = false,
bool CacheFailure = true) {
return llvm::expectedToOptional(
getFileRef(Filename, OpenFile, CacheFailure));
}
/// Returns the current file system options
FileSystemOptions &getFileSystemOpts() { return FileSystemOpts; }
const FileSystemOptions &getFileSystemOpts() const { return FileSystemOpts; }

View File

@ -187,10 +187,10 @@ FileManager::getFile(StringRef Filename, bool openFile, bool CacheFailure) {
auto Result = getFileRef(Filename, openFile, CacheFailure);
if (Result)
return &Result->getFileEntry();
return Result.getError();
return llvm::errorToErrorCode(Result.takeError());
}
llvm::ErrorOr<FileEntryRef>
llvm::Expected<FileEntryRef>
FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) {
++NumFileLookups;
@ -199,7 +199,8 @@ FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) {
SeenFileEntries.insert({Filename, std::errc::no_such_file_or_directory});
if (!SeenFileInsertResult.second) {
if (!SeenFileInsertResult.first->second)
return SeenFileInsertResult.first->second.getError();
return llvm::errorCodeToError(
SeenFileInsertResult.first->second.getError());
// Construct and return and FileEntryRef, unless it's a redirect to another
// filename.
SeenFileEntryOrRedirect Value = *SeenFileInsertResult.first->second;
@ -230,7 +231,7 @@ FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) {
else
SeenFileEntries.erase(Filename);
return DirInfoOrErr.getError();
return llvm::errorCodeToError(DirInfoOrErr.getError());
}
const DirectoryEntry *DirInfo = *DirInfoOrErr;
@ -249,7 +250,7 @@ FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) {
else
SeenFileEntries.erase(Filename);
return statError;
return llvm::errorCodeToError(statError);
}
assert((openFile || !F) && "undesired open file");

View File

@ -833,6 +833,8 @@ bool CompilerInstance::InitializeSourceManager(
if (InputFile != "-") {
auto FileOrErr = FileMgr.getFileRef(InputFile, /*OpenFile=*/true);
if (!FileOrErr) {
// FIXME: include the error in the diagnostic.
consumeError(FileOrErr.takeError());
Diags.Report(diag::err_fe_error_reading) << InputFile;
return false;
}

View File

@ -204,9 +204,7 @@ Optional<FileEntryRef> HeaderMap::LookupFile(StringRef Filename,
if (Dest.empty())
return None;
if (auto File = FM.getFileRef(Dest))
return *File;
return None;
return FM.getOptionalFileRef(Dest);
}
StringRef HeaderMapImpl::lookupFilename(StringRef Filename,

View File

@ -314,7 +314,7 @@ Optional<FileEntryRef> HeaderSearch::getFileAndSuggestModule(
if (!File) {
// For rare, surprising errors (e.g. "out of file handles"), diag the EC
// message.
std::error_code EC = File.getError();
std::error_code EC = llvm::errorToErrorCode(File.takeError());
if (EC != llvm::errc::no_such_file_or_directory &&
EC != llvm::errc::invalid_argument &&
EC != llvm::errc::is_a_directory && EC != llvm::errc::not_a_directory) {
@ -401,7 +401,7 @@ Optional<FileEntryRef> DirectoryLookup::LookupFile(
FixupSearchPath();
return *Result;
}
} else if (auto Res = HS.getFileMgr().getFileRef(Dest)) {
} else if (auto Res = HS.getFileMgr().getOptionalFileRef(Dest)) {
FixupSearchPath();
return *Res;
}
@ -553,9 +553,8 @@ Optional<FileEntryRef> DirectoryLookup::DoFrameworkLookup(
FrameworkName.append(Filename.begin()+SlashPos+1, Filename.end());
llvm::ErrorOr<FileEntryRef> File =
FileMgr.getFileRef(FrameworkName, /*OpenFile=*/!SuggestedModule);
auto File =
FileMgr.getOptionalFileRef(FrameworkName, /*OpenFile=*/!SuggestedModule);
if (!File) {
// Check "/System/Library/Frameworks/Cocoa.framework/PrivateHeaders/file.h"
const char *Private = "Private";
@ -565,7 +564,8 @@ Optional<FileEntryRef> DirectoryLookup::DoFrameworkLookup(
SearchPath->insert(SearchPath->begin()+OrigSize, Private,
Private+strlen(Private));
File = FileMgr.getFileRef(FrameworkName, /*OpenFile=*/!SuggestedModule);
File = FileMgr.getOptionalFileRef(FrameworkName,
/*OpenFile=*/!SuggestedModule);
}
// If we found the header and are allowed to suggest a module, do so now.
@ -1076,9 +1076,7 @@ Optional<FileEntryRef> HeaderSearch::LookupSubframeworkHeader(
}
HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end());
llvm::ErrorOr<FileEntryRef> File =
FileMgr.getFileRef(HeadersFilename, /*OpenFile=*/true);
auto File = FileMgr.getOptionalFileRef(HeadersFilename, /*OpenFile=*/true);
if (!File) {
// Check ".../Frameworks/HIToolbox.framework/PrivateHeaders/HIToolbox.h"
HeadersFilename = FrameworkName;
@ -1090,7 +1088,7 @@ Optional<FileEntryRef> HeaderSearch::LookupSubframeworkHeader(
}
HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end());
File = FileMgr.getFileRef(HeadersFilename, /*OpenFile=*/true);
File = FileMgr.getOptionalFileRef(HeadersFilename, /*OpenFile=*/true);
if (!File)
return None;

View File

@ -982,6 +982,20 @@ inline void consumeError(Error Err) {
handleAllErrors(std::move(Err), [](const ErrorInfoBase &) {});
}
/// Convert an Expected to an Optional without doing anything. This method
/// should be used only where an error can be considered a reasonable and
/// expected return value.
///
/// Uses of this method are potentially indicative of problems: perhaps the
/// error should be propagated further, or the error-producer should just
/// return an Optional in the first place.
template <typename T> Optional<T> expectedToOptional(Expected<T> &&E) {
if (E)
return std::move(*E);
consumeError(E.takeError());
return None;
}
/// Helper for converting an Error to a bool.
///
/// This method returns true if Err is in an error state, or false if it is