aboutsummaryrefslogtreecommitdiff
path: root/lib/Basic/SourceManager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Basic/SourceManager.cpp')
-rw-r--r--lib/Basic/SourceManager.cpp115
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.