diff options
author | Douglas Gregor <dgregor@apple.com> | 2010-03-15 22:54:52 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2010-03-15 22:54:52 +0000 |
commit | aea67dbd653a2dd6dd5cc2159279e81e855b2482 (patch) | |
tree | bd96a24447cf5a504d84556ed129f6366f2fae2d /lib/Basic/SourceManager.cpp | |
parent | 37cafb077ad5b170acae77e566638603011ef4c0 (diff) |
Introduce a new BufferResult class to act as the return type of
SourceManager's getBuffer() (and similar) operations. This abstract
can be used to force callers to cope with errors in getBuffer(), such
as missing files and changed files. Fix a bunch of callers to use the
new interface.
Add some very basic checks for file consistency (file size,
modification time) into ContentCache::getBuffer(), although these
checks don't help much until we've updated the main callers (e.g.,
SourceManager::getSpelling()).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@98585 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Basic/SourceManager.cpp')
-rw-r--r-- | lib/Basic/SourceManager.cpp | 115 |
1 files changed, 104 insertions, 11 deletions
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp index 156b809b51..dcbd4f166b 100644 --- a/lib/Basic/SourceManager.cpp +++ b/lib/Basic/SourceManager.cpp @@ -13,12 +13,15 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/SourceManagerInternals.h" +#include "clang/Basic/Diagnostic.h" #include "clang/Basic/FileManager.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Path.h" #include <algorithm> +#include <string> + using namespace clang; using namespace SrcMgr; using llvm::MemoryBuffer; @@ -27,6 +30,75 @@ using llvm::MemoryBuffer; // SourceManager Helper Classes //===----------------------------------------------------------------------===// +struct BufferResult::FailureData { + const llvm::MemoryBuffer *Buffer; + const char *FileName; + std::string ErrorStr; +}; + +BufferResult::BufferResult(const BufferResult &Other) { + if (const llvm::MemoryBuffer *Buffer + = Other.Data.dyn_cast<const llvm::MemoryBuffer *>()) { + Data = Buffer; + return; + } + + Data = new FailureData(*Other.Data.get<FailureData *>()); +} + +BufferResult::BufferResult(const char *FileName, llvm::StringRef ErrorStr, + const llvm::MemoryBuffer *Buffer) { + FailureData *FD = new FailureData; + FD->FileName = FileName; + FD->ErrorStr = ErrorStr; + FD->Buffer = Buffer; + Data = FD; +} + +BufferResult::~BufferResult() { + if (FailureData *FD = Data.dyn_cast<FailureData *>()) + delete FD; +} + +bool BufferResult::isInvalid() const { + return Data.is<FailureData *>(); +} + +const llvm::MemoryBuffer *BufferResult::getBuffer(Diagnostic &Diags) const { + llvm::StringRef FileName; + std::string ErrorMsg; + const llvm::MemoryBuffer *Result = getBuffer(FileName, ErrorMsg); + if (!ErrorMsg.empty()) { + Diags.Report(diag::err_cannot_open_file) + << FileName << ErrorMsg; + } + return Result; +} + +const llvm::MemoryBuffer *BufferResult::getBuffer(llvm::StringRef &FileName, + std::string &Error) const { + if (const llvm::MemoryBuffer *Buffer + = Data.dyn_cast<const llvm::MemoryBuffer *>()) + return Buffer; + + FailureData *Fail = Data.get<FailureData *>(); + FileName = Fail->FileName; + Error = Fail->ErrorStr; + return Fail->Buffer; +} + +BufferResult::operator const llvm::MemoryBuffer *() const { + llvm::StringRef FileName; + std::string ErrorMsg; + const llvm::MemoryBuffer *Result = getBuffer(FileName, ErrorMsg); + if (!ErrorMsg.empty()) { + fprintf(stderr, "error: cannot open file '%s': %s\n", + FileName.str().c_str(), ErrorMsg.c_str()); + } + + return Result; +} + ContentCache::~ContentCache() { delete Buffer; } @@ -54,10 +126,13 @@ void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B) { Buffer = B; } -const llvm::MemoryBuffer *ContentCache::getBuffer(std::string *ErrorStr) const { +BufferResult ContentCache::getBuffer() const { // Lazily create the Buffer for ContentCaches that wrap files. if (!Buffer && Entry) { - Buffer = MemoryBuffer::getFile(Entry->getName(), ErrorStr,Entry->getSize()); + std::string ErrorStr; + struct stat FileInfo; + Buffer = MemoryBuffer::getFile(Entry->getName(), &ErrorStr, + Entry->getSize(), &FileInfo); // If we were unable to open the file, then we are in an inconsistent // situation where the content cache referenced a file which no longer @@ -75,8 +150,21 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(std::string *ErrorStr) const { char *Ptr = const_cast<char*>(Buffer->getBufferStart()); for (unsigned i = 0, e = Entry->getSize(); i != e; ++i) Ptr[i] = FillStr[i % FillStr.size()]; + return BufferResult(Entry->getName(), ErrorStr, Buffer); + } else { + // Check that the file's size and modification time is the same as + // in the file entry (which may have come from a stat cache). + // FIXME: Make these strings localizable. + if (FileInfo.st_size != Entry->getSize()) { + ErrorStr = "file has changed size since it was originally read"; + return BufferResult(Entry->getName(), ErrorStr, Buffer); + } else if (FileInfo.st_mtime != Entry->getModificationTime()) { + ErrorStr = "file has been modified since it was originally read"; + return BufferResult(Entry->getName(), ErrorStr, Buffer); + } } } + return Buffer; } @@ -426,12 +514,9 @@ SourceLocation SourceManager::createInstantiationLoc(SourceLocation SpellingLoc, return SourceLocation::getMacroLoc(NextOffset-(TokLength+1)); } -const llvm::MemoryBuffer * -SourceManager::getMemoryBufferForFile(const FileEntry *File) { +BufferResult SourceManager::getMemoryBufferForFile(const FileEntry *File) { const SrcMgr::ContentCache *IR = getOrCreateContentCache(File); - if (IR == 0) - return 0; - + assert(IR && "getOrCreateContentCache() cannot return NULL"); return IR->getBuffer(); } @@ -445,14 +530,22 @@ bool SourceManager::overrideFileContents(const FileEntry *SourceFile, return false; } -/// getBufferData - Return a pointer to the start and end of the source buffer -/// data for the specified FileID. std::pair<const char*, const char*> -SourceManager::getBufferData(FileID FID) const { - const llvm::MemoryBuffer *Buf = getBuffer(FID); +SourceManager::getBufferData(FileID FID, llvm::StringRef &FileName, + std::string &Error) const { + const llvm::MemoryBuffer *Buf = getBuffer(FID).getBuffer(FileName, Error); + if (!Error.empty()) + return std::make_pair((const char *)0, (const char *)0); return std::make_pair(Buf->getBufferStart(), Buf->getBufferEnd()); } +std::pair<const char*, const char*> +SourceManager::getBufferData(FileID FID, Diagnostic &Diags) const { + const llvm::MemoryBuffer *Buf = getBuffer(FID).getBuffer(Diags); + if (!Buf) + return std::make_pair((const char *)0, (const char *)0); + return std::make_pair(Buf->getBufferStart(), Buf->getBufferEnd()); +} //===----------------------------------------------------------------------===// // SourceLocation manipulation methods. |