diff options
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. |