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 | 802b77601e50161f0b0d2451a722e11f3b49cdfb (patch) | |
| tree | fa9b72b5282af43966aff1b27012e481accbf26b /clang/lib | |
| parent | 45c1505bf60a17a02846a823fac6d8544a27501c (diff) | |
| download | bcm5719-llvm-802b77601e50161f0b0d2451a722e11f3b49cdfb.tar.gz bcm5719-llvm-802b77601e50161f0b0d2451a722e11f3b49cdfb.zip | |
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()).
llvm-svn: 98585
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/AST/ASTContext.cpp | 24 | ||||
| -rw-r--r-- | clang/lib/Basic/SourceManager.cpp | 115 | ||||
| -rw-r--r-- | clang/lib/Frontend/RewriteObjC.cpp | 17 | ||||
| -rw-r--r-- | clang/lib/Frontend/TextDiagnosticPrinter.cpp | 10 | ||||
| -rw-r--r-- | clang/lib/Lex/Lexer.cpp | 9 | ||||
| -rw-r--r-- | clang/lib/Lex/PPLexerChange.cpp | 6 | ||||
| -rw-r--r-- | clang/lib/Lex/TokenLexer.cpp | 5 | ||||
| -rw-r--r-- | clang/lib/Rewrite/HTMLRewrite.cpp | 12 | ||||
| -rw-r--r-- | clang/lib/Rewrite/Rewriter.cpp | 12 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 5 |
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 |

