]> granicus.if.org Git - clang/commitdiff
Introduce a new BufferResult class to act as the return type of
authorDouglas Gregor <dgregor@apple.com>
Mon, 15 Mar 2010 22:54:52 +0000 (22:54 +0000)
committerDouglas Gregor <dgregor@apple.com>
Mon, 15 Mar 2010 22:54:52 +0000 (22:54 +0000)
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

14 files changed:
include/clang/AST/ASTContext.h
include/clang/Basic/DiagnosticCommonKinds.td
include/clang/Basic/SourceManager.h
lib/AST/ASTContext.cpp
lib/Basic/SourceManager.cpp
lib/Frontend/RewriteObjC.cpp
lib/Frontend/TextDiagnosticPrinter.cpp
lib/Lex/Lexer.cpp
lib/Lex/PPLexerChange.cpp
lib/Lex/TokenLexer.cpp
lib/Rewrite/HTMLRewrite.cpp
lib/Rewrite/Rewriter.cpp
lib/Sema/SemaChecking.cpp
tools/CIndex/CIndex.cpp

index 71ddc8794bb6f7dc33952476a92bc35d3c95dc07..ffd0dec6b9a5b2392029cd997eabb2e15e80a37c 100644 (file)
@@ -40,6 +40,7 @@ namespace clang {
   class ASTRecordLayout;
   class BlockExpr;
   class CharUnits;
+  class Diagnostic;
   class Expr;
   class ExternalASTSource;
   class IdentifierTable;
@@ -356,7 +357,7 @@ public:
   TranslationUnitDecl *getTranslationUnitDecl() const { return TUDecl; }
 
 
-  const char *getCommentForDecl(const Decl *D);
+  const char *getCommentForDecl(const Decl *D, Diagnostic &Diags);
 
   // Builtin Types.
   CanQualType VoidTy;
index 66f84dbbbabecf62a6a0613715048810e18a7559..d79f7ad42faa0e27472abb13ce26e621cd3a70c9 100644 (file)
@@ -63,4 +63,7 @@ def err_target_unknown_cpu : Error<"unknown target CPU '%0'">;
 def err_target_unknown_abi : Error<"unknown target ABI '%0'">;
 def err_target_invalid_feature : Error<"invalid target feature '%0'">;
 
+// Anywhere we open a file
+def err_cannot_open_file : Error<"cannot open file '%0': %1">, DefaultFatal;
+
 }
index 015d82a63cc059ffe47be3972636231ad8cd02eb..05480419abfe941a117b8772c968c82cff611db6 100644 (file)
 #include "clang/Basic/SourceLocation.h"
 #include "llvm/Support/Allocator.h"
 #include "llvm/System/DataTypes.h"
+#include "llvm/ADT/PointerUnion.h"
 #include "llvm/ADT/DenseMap.h"
 #include <vector>
 #include <cassert>
 
 namespace llvm {
 class MemoryBuffer;
+class StringRef;
 }
 
 namespace clang {
 
+class Diagnostic;
 class SourceManager;
 class FileManager;
 class FileEntry;
 class LineTableInfo;
-
+  
+/// \brief Class used as a return value by operations that return an
+/// \c llvm::MemoryBuffer.
+///
+/// Since not all source-manager routines that return buffers are guaranteed
+/// to succeed, 
+class BufferResult {
+  struct FailureData;
+  llvm::PointerUnion<const llvm::MemoryBuffer *, FailureData *> Data;
+  
+  // Cannot copy buffer result structures
+  BufferResult &operator=(const BufferResult &Other);
+  
+public:
+  BufferResult(const BufferResult &Other);
+  BufferResult(const llvm::MemoryBuffer *Buffer) : Data(Buffer) { }
+  BufferResult(const char *FileName, llvm::StringRef ErrorStr,
+               const llvm::MemoryBuffer *Buffer = 0);
+  ~BufferResult();
+  
+  // \brief Determine whether there was any failure when finding this buffer.
+  bool isInvalid() const;
+  
+  /// \brief Retrieve the memory buffer that this result refers to. If an
+  /// error occurs, emits a diagnostic via the given diagnostics object and
+  /// may return NULL.
+  const llvm::MemoryBuffer *getBuffer(Diagnostic &Diags) const;
+  
+  /// \brief Retrieve the memory buffer that this result refers to. If an error
+  /// occurs, provides the file name and a non-empty error string to indicate 
+  /// what failed, and may return NULL.
+  const llvm::MemoryBuffer *getBuffer(llvm::StringRef &FileName, 
+                                      std::string &Error) const;
+  
+  // FIXME: TEMPORARY! Allows a buffer result to be interpreted as a buffer,
+  // which is very unsafe (but is used throughout Clang). Note that this will
+  // spit a diagnostic to standard error before returning the buffer.
+  operator const llvm::MemoryBuffer *() const;
+  
+  // FIXME: TEMPORARY! Allows a buffer result to be interpreted like a smart
+  // pointer to a buffer, which is very unsafe. Note that this will emit a
+  // diagnostic to standard error before returning the buffer.
+  const llvm::MemoryBuffer * operator->() const { return *this; }
+};
+  
 /// SrcMgr - Public enums and private classes that are part of the
 /// SourceManager implementation.
 ///
@@ -68,10 +115,8 @@ namespace SrcMgr {
     /// if SourceLineCache is non-null.
     unsigned NumLines;
 
-    /// getBuffer - Returns the memory buffer for the associated content.  If
-    /// there is an error opening this buffer the first time, this manufactures
-    /// a temporary buffer and returns a non-empty error string.
-    const llvm::MemoryBuffer *getBuffer(std::string *ErrorStr = 0) const;
+    /// getBuffer - Returns the memory buffer for the associated content. 
+    BufferResult getBuffer() const;
 
     /// getSize - Returns the size of the content encapsulated by this
     ///  ContentCache. This can be the size of the source file or the size of an
@@ -407,7 +452,7 @@ public:
                                         unsigned Offset = 0);
 
   /// \brief Retrieve the memory buffer associated with the given file.
-  const llvm::MemoryBuffer *getMemoryBufferForFile(const FileEntry *File);
+  BufferResult getMemoryBufferForFile(const FileEntry *File);
 
   /// \brief Override the contents of the given source file by providing an
   /// already-allocated buffer.
@@ -428,8 +473,8 @@ public:
   /// getBuffer - Return the buffer for the specified FileID. If there is an
   /// error opening this buffer the first time, this manufactures a temporary
   /// buffer and returns a non-empty error string.
-  const llvm::MemoryBuffer *getBuffer(FileID FID, std::string *Error = 0) const{
-    return getSLocEntry(FID).getFile().getContentCache()->getBuffer(Error);
+  BufferResult getBuffer(FileID FID) const{
+    return getSLocEntry(FID).getFile().getContentCache()->getBuffer();
   }
 
   /// getFileEntryForID - Returns the FileEntry record for the provided FileID.
@@ -439,8 +484,21 @@ public:
 
   /// getBufferData - Return a pointer to the start and end of the source buffer
   /// data for the specified FileID.
-  std::pair<const char*, const char*> getBufferData(FileID FID) const;
+  ///
+  /// If an error occurs while reading in the file, provides the file name 
+  /// and a non-empty error string and returns a pair of NULL pointers.
+  std::pair<const char*, const char*> getBufferData(FileID FID,
+                                                    llvm::StringRef &FileName,
+                                                    std::string &Error) const;
 
+  /// getBufferData - Return a pointer to the start and end of the source buffer
+  /// data for the specified FileID.
+  /// 
+  /// If an error occurs while reading in the file, emits a diagnostic to the
+  /// given \c Diagnostic object and returns a pair of NULL pointers.
+  std::pair<const char*, const char*> getBufferData(FileID FID, 
+                                                    Diagnostic &Diags) const;
+  
 
   //===--------------------------------------------------------------------===//
   // SourceLocation manipulation methods.
index c64f97a97f1c8f76222706203ef937041246ea01..6d90884ba9417d7adafcb993ec84a39764e4b0d6 100644 (file)
@@ -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;
     }
index 156b809b51f2b6e1ef8839ac50620ff82ab03b95..dcbd4f166bfa8f6bc4f0f9337387c29e4c1a2df6 100644 (file)
 
 #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.
index 3181a55088bb891c2787692a99ecbaf1dfcb082d..cd3d4ee0b96c46b8a564c8dc9bb85bd624392782 100644 (file)
@@ -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();
 
index 60c1f4b9b8a4cfc598d0145397dd03cf12d51cfa..2b243fad248298d7628bbe89401119f9e521ccb0 100644 (file)
@@ -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);
index 3207062ccadd623ba1a87b7589bfae3ce3b3cdcd..149041559abf45412a6fefa20d2dbc7ef572480b 100644 (file)
@@ -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]))
index 0b26ccbecbab7812f47ff3f9130f03634dcd56af..4fba7b7bee13ad93eb9b8765df9a25816af08ab2 100644 (file)
@@ -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);
index efd1efed29397012c01a96969d22167bfc451dc7..7ccaa89fe3e8e5cd7cccc505203d71ad8b89a754 100644 (file)
@@ -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.
index 342b0e6ef5e5bc5516f28ec16dfe6c50f0b606f6..cf1c779b3ea0c2d192aa7bcd4fe287fcb4f088c7 100644 (file)
@@ -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
index 9744496ac4fe0b99f13ec6d19cd673bb064ac783..84c0979d6dd52f05759783846b79dd894fd0aa50 100644 (file)
@@ -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;
index 544d66b503e81114aed13c3d2e4a9239d78482ea..7e66d7e910d57450817e655f19bb000a8c55f425 100644 (file)
@@ -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
index b52a32ed9b5183c84c555d19a3123170665e0a9e..c570ee4935d955c2e8caee82811bd4ee6dda6b0c 100644 (file)
@@ -2043,7 +2043,10 @@ CXString clang_getTokenSpelling(CXTranslationUnit TU, CXToken CXTok) {
   std::pair<FileID, unsigned> LocInfo
     = CXXUnit->getSourceManager().getDecomposedLoc(Loc);
   std::pair<const char *,const char *> Buffer
-    = CXXUnit->getSourceManager().getBufferData(LocInfo.first);
+    = CXXUnit->getSourceManager().getBufferData(LocInfo.first,
+                                  CXXUnit->getPreprocessor().getDiagnostics());
+  if (!Buffer.first)
+    return createCXString("");
 
   return createCXString(llvm::StringRef(Buffer.first+LocInfo.second,
                                         CXTok.int_data[2]));
@@ -2096,7 +2099,11 @@ void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range,
 
   // Create a lexer
   std::pair<const char *,const char *> Buffer
-    = SourceMgr.getBufferData(BeginLocInfo.first);
+    = SourceMgr.getBufferData(BeginLocInfo.first, 
+                              CXXUnit->getPreprocessor().getDiagnostics());
+  if (!Buffer.first)
+    return;
+  
   Lexer Lex(SourceMgr.getLocForStartOfFile(BeginLocInfo.first),
             CXXUnit->getASTContext().getLangOptions(),
             Buffer.first, Buffer.first + BeginLocInfo.second, Buffer.second);
@@ -2125,12 +2132,16 @@ void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range,
       CXTok.int_data[0] = CXToken_Literal;
       CXTok.ptr_data = (void *)Tok.getLiteralData();
     } else if (Tok.is(tok::identifier)) {
-      // Lookup the identifier to determine whether we have a
+      // Lookup the identifier to determine whether we have a keyword.
       std::pair<FileID, unsigned> LocInfo
         = SourceMgr.getDecomposedLoc(Tok.getLocation());
-      const char *StartPos
-        = CXXUnit->getSourceManager().getBufferData(LocInfo.first).first +
-          LocInfo.second;
+      std::pair<const char *, const char *> Buf
+        = CXXUnit->getSourceManager().getBufferData(LocInfo.first,
+                                  CXXUnit->getPreprocessor().getDiagnostics());
+      if (!Buf.first)
+        return;
+      
+      const char *StartPos= Buf.first + LocInfo.second;
       IdentifierInfo *II
         = CXXUnit->getPreprocessor().LookUpIdentifierInfo(Tok, StartPos);
       CXTok.int_data[0] = II->getTokenID() == tok::identifier?