summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/ASTContext.cpp24
-rw-r--r--clang/lib/Basic/SourceManager.cpp115
-rw-r--r--clang/lib/Frontend/RewriteObjC.cpp17
-rw-r--r--clang/lib/Frontend/TextDiagnosticPrinter.cpp10
-rw-r--r--clang/lib/Lex/Lexer.cpp9
-rw-r--r--clang/lib/Lex/PPLexerChange.cpp6
-rw-r--r--clang/lib/Lex/TokenLexer.cpp5
-rw-r--r--clang/lib/Rewrite/HTMLRewrite.cpp12
-rw-r--r--clang/lib/Rewrite/Rewriter.cpp12
-rw-r--r--clang/lib/Sema/SemaChecking.cpp5
10 files changed, 182 insertions, 33 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index c64f97a97f1..6d90884ba94 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -423,10 +423,14 @@ namespace {
/// (which requires a < after the Doxygen-comment delimiter). Otherwise,
/// we only return true when we find a non-member comment.
static bool
-isDoxygenComment(SourceManager &SourceMgr, SourceRange Comment,
- bool Member = false) {
+isDoxygenComment(SourceManager &SourceMgr, Diagnostic &Diags,
+ SourceRange Comment, bool Member = false) {
const char *BufferStart
- = SourceMgr.getBufferData(SourceMgr.getFileID(Comment.getBegin())).first;
+ = SourceMgr.getBufferData(SourceMgr.getFileID(Comment.getBegin()),
+ Diags).first;
+ if (!BufferStart)
+ return false;
+
const char *Start = BufferStart + SourceMgr.getFileOffset(Comment.getBegin());
const char* End = BufferStart + SourceMgr.getFileOffset(Comment.getEnd());
@@ -444,7 +448,7 @@ isDoxygenComment(SourceManager &SourceMgr, SourceRange Comment,
/// \brief Retrieve the comment associated with the given declaration, if
/// it has one.
-const char *ASTContext::getCommentForDecl(const Decl *D) {
+const char *ASTContext::getCommentForDecl(const Decl *D, Diagnostic &Diags) {
if (!D)
return 0;
@@ -489,12 +493,14 @@ const char *ASTContext::getCommentForDecl(const Decl *D) {
std::pair<FileID, unsigned> DeclStartDecomp
= SourceMgr.getDecomposedLoc(DeclStartLoc);
const char *FileBufferStart
- = SourceMgr.getBufferData(DeclStartDecomp.first).first;
-
+ = SourceMgr.getBufferData(DeclStartDecomp.first, Diags).first;
+ if (!FileBufferStart)
+ return 0;
+
// First check whether we have a comment for a member.
if (LastComment != Comments.end() &&
!isa<TagDecl>(D) && !isa<NamespaceDecl>(D) &&
- isDoxygenComment(SourceMgr, *LastComment, true)) {
+ isDoxygenComment(SourceMgr, Diags, *LastComment, true)) {
std::pair<FileID, unsigned> LastCommentEndDecomp
= SourceMgr.getDecomposedLoc(LastComment->getEnd());
if (DeclStartDecomp.first == LastCommentEndDecomp.first &&
@@ -526,7 +532,7 @@ const char *ASTContext::getCommentForDecl(const Decl *D) {
return 0;
// Check that we actually have a Doxygen comment.
- if (!isDoxygenComment(SourceMgr, *LastComment))
+ if (!isDoxygenComment(SourceMgr, Diags, *LastComment))
return 0;
// Compute the starting line for the declaration and for the end of the
@@ -561,7 +567,7 @@ const char *ASTContext::getCommentForDecl(const Decl *D) {
}
// If this comment is not a Doxygen comment, we're done.
- if (!isDoxygenComment(SourceMgr, *FirstComment)) {
+ if (!isDoxygenComment(SourceMgr, Diags, *FirstComment)) {
++FirstComment;
break;
}
diff --git a/clang/lib/Basic/SourceManager.cpp b/clang/lib/Basic/SourceManager.cpp
index 156b809b51f..dcbd4f166bf 100644
--- a/clang/lib/Basic/SourceManager.cpp
+++ b/clang/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.
diff --git a/clang/lib/Frontend/RewriteObjC.cpp b/clang/lib/Frontend/RewriteObjC.cpp
index 3181a55088b..cd3d4ee0b96 100644
--- a/clang/lib/Frontend/RewriteObjC.cpp
+++ b/clang/lib/Frontend/RewriteObjC.cpp
@@ -706,7 +706,11 @@ void RewriteObjC::HandleTopLevelSingleDecl(Decl *D) {
void RewriteObjC::RewriteInclude() {
SourceLocation LocStart = SM->getLocForStartOfFile(MainFileID);
- std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
+ std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID,
+ Diags);
+ if (!MainBuf.first)
+ return;
+
const char *MainBufStart = MainBuf.first;
const char *MainBufEnd = MainBuf.second;
size_t ImportLen = strlen("import");
@@ -731,7 +735,11 @@ void RewriteObjC::RewriteInclude() {
}
void RewriteObjC::RewriteTabs() {
- std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
+ std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID,
+ Diags);
+ if (!MainBuf.first)
+ return;
+
const char *MainBufStart = MainBuf.first;
const char *MainBufEnd = MainBuf.second;
@@ -973,7 +981,10 @@ void RewriteObjC::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) {
}
void RewriteObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
- std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID);
+ std::pair<const char*, const char*> MainBuf = SM->getBufferData(MainFileID,
+ Diags);
+ if (!MainBuf.first)
+ return;
SourceLocation LocStart = PDecl->getLocStart();
diff --git a/clang/lib/Frontend/TextDiagnosticPrinter.cpp b/clang/lib/Frontend/TextDiagnosticPrinter.cpp
index 60c1f4b9b8a..2b243fad248 100644
--- a/clang/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/clang/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -330,9 +330,15 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
unsigned FileOffset = LocInfo.second;
// Get information about the buffer it points into.
- std::pair<const char*, const char*> BufferInfo = SM.getBufferData(FID);
+ llvm::StringRef ErrorFileName;
+ std::string ErrorStr;
+ std::pair<const char*, const char*> BufferInfo = SM.getBufferData(FID,
+ ErrorFileName,
+ ErrorStr);
const char *BufStart = BufferInfo.first;
-
+ if (!BufStart)
+ return;
+
unsigned ColNo = SM.getColumnNumber(FID, FileOffset);
unsigned CaretEndColNo
= ColNo + Lexer::MeasureTokenLength(Loc, SM, *LangOpts);
diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index 3207062ccad..149041559ab 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -229,7 +229,14 @@ unsigned Lexer::MeasureTokenLength(SourceLocation Loc,
// the token this macro expanded to.
Loc = SM.getInstantiationLoc(Loc);
std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
- std::pair<const char *,const char *> Buffer = SM.getBufferData(LocInfo.first);
+ llvm::StringRef FileName;
+ std::string ErrorStr;
+ std::pair<const char *,const char *> Buffer = SM.getBufferData(LocInfo.first,
+ FileName,
+ ErrorStr);
+ if (!Buffer.first)
+ return 0;
+
const char *StrData = Buffer.first+LocInfo.second;
if (isWhitespace(StrData[0]))
diff --git a/clang/lib/Lex/PPLexerChange.cpp b/clang/lib/Lex/PPLexerChange.cpp
index 0b26ccbecba..4fba7b7bee1 100644
--- a/clang/lib/Lex/PPLexerChange.cpp
+++ b/clang/lib/Lex/PPLexerChange.cpp
@@ -80,9 +80,9 @@ bool Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir,
}
// Get the MemoryBuffer for this FID, if it fails, we fail.
- const llvm::MemoryBuffer *InputFile =
- getSourceManager().getBuffer(FID, &ErrorStr);
- if (!ErrorStr.empty())
+ const llvm::MemoryBuffer *InputFile
+ = getSourceManager().getBuffer(FID).getBuffer(getDiagnostics());
+ if (!InputFile)
return true;
EnterSourceFileWithLexer(new Lexer(FID, InputFile, *this), CurDir);
diff --git a/clang/lib/Lex/TokenLexer.cpp b/clang/lib/Lex/TokenLexer.cpp
index efd1efed293..7ccaa89fe3e 100644
--- a/clang/lib/Lex/TokenLexer.cpp
+++ b/clang/lib/Lex/TokenLexer.cpp
@@ -439,7 +439,10 @@ bool TokenLexer::PasteTokens(Token &Tok) {
SourceManager &SourceMgr = PP.getSourceManager();
FileID LocFileID = SourceMgr.getFileID(ResultTokLoc);
- const char *ScratchBufStart = SourceMgr.getBufferData(LocFileID).first;
+ const char *ScratchBufStart
+ = SourceMgr.getBufferData(LocFileID, PP.getDiagnostics()).first;
+ if (!ScratchBufStart)
+ return false;
// Make a lexer to lex this string from. Lex just this one token.
// Make a lexer object so that we lex and expand the paste result.
diff --git a/clang/lib/Rewrite/HTMLRewrite.cpp b/clang/lib/Rewrite/HTMLRewrite.cpp
index 342b0e6ef5e..cf1c779b3ea 100644
--- a/clang/lib/Rewrite/HTMLRewrite.cpp
+++ b/clang/lib/Rewrite/HTMLRewrite.cpp
@@ -43,8 +43,18 @@ void html::HighlightRange(Rewriter &R, SourceLocation B, SourceLocation E,
// Include the whole end token in the range.
EOffset += Lexer::MeasureTokenLength(E, R.getSourceMgr(), R.getLangOpts());
+ llvm::StringRef FileName;
+ std::string ErrorStr;
+ const char *BufferStart = SM.getBufferData(FID, FileName, ErrorStr).first;
+ if (!BufferStart) {
+ // FIXME: Add a diagnostic object somewhere?
+ fprintf(stderr, "error: cannot open file '%s': %s\n",
+ FileName.str().c_str(), ErrorStr.c_str());
+ return;
+ }
+
HighlightRange(R.getEditBuffer(FID), BOffset, EOffset,
- SM.getBufferData(FID).first, StartTag, EndTag);
+ BufferStart, StartTag, EndTag);
}
/// HighlightRange - This is the same as the above method, but takes
diff --git a/clang/lib/Rewrite/Rewriter.cpp b/clang/lib/Rewrite/Rewriter.cpp
index 9744496ac4f..84c0979d6dd 100644
--- a/clang/lib/Rewrite/Rewriter.cpp
+++ b/clang/lib/Rewrite/Rewriter.cpp
@@ -165,7 +165,17 @@ RewriteBuffer &Rewriter::getEditBuffer(FileID FID) {
return I->second;
I = RewriteBuffers.insert(I, std::make_pair(FID, RewriteBuffer()));
- std::pair<const char*, const char*> MB = SourceMgr->getBufferData(FID);
+ llvm::StringRef FileName;
+ std::string ErrorStr;
+
+ std::pair<const char*, const char*> MB
+ = SourceMgr->getBufferData(FID, FileName, ErrorStr);
+ if (!MB.first) {
+ // FIXME: Add a diagnostic object somewhere?
+ fprintf(stderr, "error: cannot open file '%s': %s\n",
+ FileName.str().c_str(), ErrorStr.c_str());
+ }
+
I->second.Initialize(MB.first, MB.second);
return I->second;
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 544d66b503e..7e66d7e910d 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -60,7 +60,10 @@ SourceLocation Sema::getLocationOfStringLiteralByte(const StringLiteral *SL,
std::pair<FileID, unsigned> LocInfo =
SourceMgr.getDecomposedLoc(StrTokSpellingLoc);
std::pair<const char *,const char *> Buffer =
- SourceMgr.getBufferData(LocInfo.first);
+ SourceMgr.getBufferData(LocInfo.first, Diags);
+ if (!Buffer.first)
+ return StrTokSpellingLoc;
+
const char *StrData = Buffer.first+LocInfo.second;
// Create a langops struct and enable trigraphs. This is sufficient for
OpenPOWER on IntegriCloud