forked from OSchip/llvm-project
Basic: Add native support for stdin to SourceManager and FileManager
Add support for stdin to SourceManager and FileManager. Adds FileManager::getSTDIN, which adds a FileEntryRef for `<stdin>` and reads the MemoryBuffer, which is stored as `FileEntry::Content`. Eventually the other buffers in `ContentCache` will sink to here as well -- we probably usually want to load/save a MemoryBuffer eagerly -- but it's happening early for stdin to get rid of CompilerInstance::InitializeSourceManager's final call to `SourceManager::overrideFileContents`. clang/test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.export/p1.cpp relies on building a module from stdin; supporting that requires setting ContentCache::BufferOverridden. Differential Revision: https://reviews.llvm.org/D93148
This commit is contained in:
parent
245218bb35
commit
3ee43adfb2
|
@ -25,6 +25,9 @@
|
|||
#include "llvm/Support/FileSystem/UniqueID.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MemoryBuffer;
|
||||
|
||||
namespace vfs {
|
||||
|
||||
class File;
|
||||
|
@ -67,6 +70,7 @@ public:
|
|||
inline unsigned getUID() const;
|
||||
inline const llvm::sys::fs::UniqueID &getUniqueID() const;
|
||||
inline time_t getModificationTime() const;
|
||||
inline bool isNamedPipe() const;
|
||||
inline void closeFile() const;
|
||||
|
||||
/// Check if the underlying FileEntry is the same, intentially ignoring
|
||||
|
@ -339,6 +343,9 @@ class FileEntry {
|
|||
/// The open file, if it is owned by the \p FileEntry.
|
||||
mutable std::unique_ptr<llvm::vfs::File> File;
|
||||
|
||||
/// The file content, if it is owned by the \p FileEntry.
|
||||
std::unique_ptr<llvm::MemoryBuffer> Content;
|
||||
|
||||
// First access name for this FileEntry.
|
||||
//
|
||||
// This is Optional only to allow delayed construction (FileEntryRef has no
|
||||
|
@ -390,6 +397,8 @@ time_t FileEntryRef::getModificationTime() const {
|
|||
return getFileEntry().getModificationTime();
|
||||
}
|
||||
|
||||
bool FileEntryRef::isNamedPipe() const { return getFileEntry().isNamedPipe(); }
|
||||
|
||||
void FileEntryRef::closeFile() const { getFileEntry().closeFile(); }
|
||||
|
||||
} // end namespace clang
|
||||
|
|
|
@ -99,6 +99,9 @@ class FileManager : public RefCountedBase<FileManager> {
|
|||
std::unique_ptr<llvm::StringMap<llvm::ErrorOr<FileEntryRef::MapValue>>>
|
||||
SeenBypassFileEntries;
|
||||
|
||||
/// The file entry for stdin, if it has been accessed through the FileManager.
|
||||
Optional<FileEntryRef> STDIN;
|
||||
|
||||
/// The canonical names of files and directories .
|
||||
llvm::DenseMap<const void *, llvm::StringRef> CanonicalNames;
|
||||
|
||||
|
@ -217,6 +220,14 @@ public:
|
|||
bool OpenFile = false,
|
||||
bool CacheFailure = true);
|
||||
|
||||
/// Get the FileEntryRef for stdin, returning an error if stdin cannot be
|
||||
/// read.
|
||||
///
|
||||
/// This reads and caches stdin before returning. Subsequent calls return the
|
||||
/// same file entry, and a reference to the cached input is returned by calls
|
||||
/// to getBufferForFile.
|
||||
llvm::Expected<FileEntryRef> getSTDIN();
|
||||
|
||||
/// Get a FileEntryRef if it exists, without doing anything on error.
|
||||
llvm::Optional<FileEntryRef> getOptionalFileRef(StringRef Filename,
|
||||
bool OpenFile = false,
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Basic/FileEntry.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/VirtualFileSystem.h"
|
||||
|
||||
using namespace clang;
|
||||
|
|
|
@ -338,6 +338,25 @@ FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) {
|
|||
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) {
|
||||
return &getVirtualFileRef(Filename, Size, ModificationTime).getFileEntry();
|
||||
|
@ -486,6 +505,10 @@ 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.
|
||||
|
|
|
@ -414,6 +414,7 @@ ContentCache &SourceManager::getOrCreateContentCache(const FileEntry *FileEnt,
|
|||
|
||||
Entry->IsFileVolatile = UserFilesAreVolatile && !isSystemFile;
|
||||
Entry->IsTransient = FilesAreTransient;
|
||||
Entry->BufferOverridden |= FileEnt->isNamedPipe();
|
||||
|
||||
return *Entry;
|
||||
}
|
||||
|
|
|
@ -848,33 +848,22 @@ bool CompilerInstance::InitializeSourceManager(const FrontendInputFile &Input,
|
|||
StringRef InputFile = Input.getFile();
|
||||
|
||||
// Figure out where to get and map in the main file.
|
||||
if (InputFile != "-") {
|
||||
auto FileOrErr = FileMgr.getFileRef(InputFile, /*OpenFile=*/true);
|
||||
if (!FileOrErr) {
|
||||
// FIXME: include the error in the diagnostic.
|
||||
consumeError(FileOrErr.takeError());
|
||||
auto FileOrErr = InputFile == "-"
|
||||
? FileMgr.getSTDIN()
|
||||
: FileMgr.getFileRef(InputFile, /*OpenFile=*/true);
|
||||
if (!FileOrErr) {
|
||||
// FIXME: include the error in the diagnostic even when it's not stdin.
|
||||
auto EC = llvm::errorToErrorCode(FileOrErr.takeError());
|
||||
if (InputFile != "-")
|
||||
Diags.Report(diag::err_fe_error_reading) << InputFile;
|
||||
return false;
|
||||
}
|
||||
|
||||
SourceMgr.setMainFileID(
|
||||
SourceMgr.createFileID(*FileOrErr, SourceLocation(), Kind));
|
||||
} else {
|
||||
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> SBOrErr =
|
||||
llvm::MemoryBuffer::getSTDIN();
|
||||
if (std::error_code EC = SBOrErr.getError()) {
|
||||
else
|
||||
Diags.Report(diag::err_fe_error_reading_stdin) << EC.message();
|
||||
return false;
|
||||
}
|
||||
std::unique_ptr<llvm::MemoryBuffer> SB = std::move(SBOrErr.get());
|
||||
|
||||
FileEntryRef File = FileMgr.getVirtualFileRef(SB->getBufferIdentifier(),
|
||||
SB->getBufferSize(), 0);
|
||||
SourceMgr.setMainFileID(
|
||||
SourceMgr.createFileID(File, SourceLocation(), Kind));
|
||||
SourceMgr.overrideFileContents(File, std::move(SB));
|
||||
return false;
|
||||
}
|
||||
|
||||
SourceMgr.setMainFileID(
|
||||
SourceMgr.createFileID(*FileOrErr, SourceLocation(), Kind));
|
||||
|
||||
assert(SourceMgr.getMainFileID().isValid() &&
|
||||
"Couldn't establish MainFileID!");
|
||||
return true;
|
||||
|
|
Loading…
Reference in New Issue