Index: clang-tools-extra/clang-tidy/bugprone/SuspiciousSemicolonCheck.cpp =================================================================== --- clang-tools-extra/clang-tidy/bugprone/SuspiciousSemicolonCheck.cpp +++ clang-tools-extra/clang-tidy/bugprone/SuspiciousSemicolonCheck.cpp @@ -53,10 +53,10 @@ SourceLocation LocEnd = Semicolon->getEndLoc(); FileID FID = SM.getFileID(LocEnd); - const llvm::MemoryBuffer *Buffer = SM.getBuffer(FID, LocEnd); + llvm::MemoryBufferRef Buffer = SM.getBufferOrFake(FID, LocEnd); Lexer Lexer(SM.getLocForStartOfFile(FID), Ctxt.getLangOpts(), - Buffer->getBufferStart(), SM.getCharacterData(LocEnd) + 1, - Buffer->getBufferEnd()); + Buffer.getBufferStart(), SM.getCharacterData(LocEnd) + 1, + Buffer.getBufferEnd()); if (Lexer.LexFromRawLexer(Token)) return; Index: clang-tools-extra/clang-tidy/misc/StaticAssertCheck.cpp =================================================================== --- clang-tools-extra/clang-tidy/misc/StaticAssertCheck.cpp +++ clang-tools-extra/clang-tidy/misc/StaticAssertCheck.cpp @@ -145,7 +145,8 @@ const LangOptions &Opts = ASTCtx->getLangOpts(); const SourceManager &SM = ASTCtx->getSourceManager(); - const llvm::MemoryBuffer *Buffer = SM.getBuffer(SM.getFileID(AssertLoc)); + llvm::Optional Buffer = + SM.getBuffer(SM.getFileID(AssertLoc)); if (!Buffer) return SourceLocation(); Index: clang-tools-extra/clang-tidy/readability/MagicNumbersCheck.cpp =================================================================== --- clang-tools-extra/clang-tidy/readability/MagicNumbersCheck.cpp +++ clang-tools-extra/clang-tidy/readability/MagicNumbersCheck.cpp @@ -159,10 +159,7 @@ if (FileOffset.first.isInvalid()) return false; - const StringRef BufferIdentifier = - SourceManager->getBuffer(FileOffset.first)->getBufferIdentifier(); - - return BufferIdentifier.empty(); + return SourceManager->getBufferIdentifierOrEmpty(FileOffset.first).empty(); } } // namespace readability Index: clang-tools-extra/clangd/ClangdUnit.cpp =================================================================== --- clang-tools-extra/clangd/ClangdUnit.cpp +++ clang-tools-extra/clangd/ClangdUnit.cpp @@ -257,7 +257,7 @@ SrcMgr::CharacteristicKind Kind, FileID PrevFID) override { // It'd be nice if there was a better way to identify built-in headers... if (Reason == FileChangeReason::ExitFile && - SM.getBuffer(PrevFID)->getBufferIdentifier() == "") + SM.getBufferOrFake(PrevFID)->getBufferIdentifier() == "") replay(); } Index: clang-tools-extra/clangd/Format.cpp =================================================================== --- clang-tools-extra/clangd/Format.cpp +++ clang-tools-extra/clangd/Format.cpp @@ -25,7 +25,8 @@ SourceManagerForFile FileSM("dummy.cpp", Code); auto &SM = FileSM.get(); FileID FID = SM.getMainFileID(); - Lexer Lex(FID, SM.getBuffer(FID), SM, format::getFormattingLangOpts(Style)); + Lexer Lex(FID, SM.getBufferOrFake(FID), SM, + format::getFormattingLangOpts(Style)); Token Tok; std::vector Brackets; while (!Lex.LexFromRawLexer(Tok)) { Index: clang-tools-extra/clangd/SourceCode.cpp =================================================================== --- clang-tools-extra/clangd/SourceCode.cpp +++ clang-tools-extra/clangd/SourceCode.cpp @@ -452,9 +452,9 @@ llvm::StringRef toSourceCode(const SourceManager &SM, SourceRange R) { assert(isValidFileRange(SM, R)); - bool Invalid = false; - auto *Buf = SM.getBuffer(SM.getFileID(R.getBegin()), &Invalid); - assert(!Invalid); + llvm::Optional Buf = + SM.getBuffer(SM.getFileID(R.getBegin())); + assert(Buf); size_t BeginOffset = SM.getFileOffset(R.getBegin()); size_t EndOffset = SM.getFileOffset(R.getEnd()); @@ -463,7 +463,7 @@ llvm::Expected sourceLocationInMainFile(const SourceManager &SM, Position P) { - llvm::StringRef Code = SM.getBuffer(SM.getMainFileID())->getBuffer(); + llvm::StringRef Code = SM.getBufferOrFake(SM.getMainFileID())->getBuffer(); auto Offset = positionToOffset(Code, P, /*AllowColumnBeyondLineLength=*/false); if (!Offset) @@ -613,7 +613,8 @@ SourceManagerForFile FileSM("dummy.cpp", NullTerminatedCode); auto &SM = FileSM.get(); auto FID = SM.getMainFileID(); - Lexer Lex(FID, SM.getBuffer(FID), SM, format::getFormattingLangOpts(Style)); + Lexer Lex(FID, SM.getBufferOrFake(FID), SM, + format::getFormattingLangOpts(Style)); Token Tok; while (!Lex.LexFromRawLexer(Tok)) Index: clang-tools-extra/modularize/PreprocessorTracker.cpp =================================================================== --- clang-tools-extra/modularize/PreprocessorTracker.cpp +++ clang-tools-extra/modularize/PreprocessorTracker.cpp @@ -312,8 +312,8 @@ // Retrieve source line from file image given a location. static std::string getSourceLine(clang::Preprocessor &PP, clang::SourceLocation Loc) { - const llvm::MemoryBuffer *MemBuffer = - PP.getSourceManager().getBuffer(PP.getSourceManager().getFileID(Loc)); + llvm::MemoryBufferRef MemBuffer = PP.getSourceManager().getBufferOrFake( + PP.getSourceManager().getFileID(Loc)); const char *Buffer = MemBuffer->getBufferStart(); const char *BufferEnd = MemBuffer->getBufferEnd(); const char *BeginPtr = PP.getSourceManager().getCharacterData(Loc); @@ -338,7 +338,8 @@ // Retrieve source line from file image given a file ID and line number. static std::string getSourceLine(clang::Preprocessor &PP, clang::FileID FileID, int Line) { - const llvm::MemoryBuffer *MemBuffer = PP.getSourceManager().getBuffer(FileID); + llvm::MemoryBufferRef MemBuffer = + PP.getSourceManager().getBufferOrFake(FileID); const char *Buffer = MemBuffer->getBufferStart(); const char *BufferEnd = MemBuffer->getBufferEnd(); const char *BeginPtr = Buffer; Index: clang/include/clang/Basic/SourceManager.h =================================================================== --- clang/include/clang/Basic/SourceManager.h +++ clang/include/clang/Basic/SourceManager.h @@ -93,9 +93,6 @@ /// This object owns the MemoryBuffer object. class alignas(8) ContentCache { enum CCFlags { - /// Whether the buffer is invalid. - InvalidFlag = 0x01, - /// Whether the buffer should not be freed on destruction. DoNotFreeFlag = 0x02 }; @@ -149,21 +146,21 @@ /// after serialization and deserialization. unsigned IsTransient : 1; + /// Cache whether the content is known to be invalid. + mutable unsigned IsBufferInvalid : 1; + ContentCache(const FileEntry *Ent = nullptr) : ContentCache(Ent, Ent) {} ContentCache(const FileEntry *Ent, const FileEntry *contentEnt) : Buffer(nullptr, false), OrigEntry(Ent), ContentsEntry(contentEnt), - BufferOverridden(false), IsFileVolatile(false), IsTransient(false) {} + BufferOverridden(false), IsFileVolatile(false), IsTransient(false), + IsBufferInvalid(false) {} /// The copy ctor does not allow copies where source object has either /// a non-NULL Buffer or SourceLineCache. Ownership of allocated memory /// is not transferred, so this is a logical error. ContentCache(const ContentCache &RHS) - : Buffer(nullptr, false), BufferOverridden(false), - IsFileVolatile(false), IsTransient(false) { - OrigEntry = RHS.OrigEntry; - ContentsEntry = RHS.ContentsEntry; - + : ContentCache(RHS.OrigEntry, RHS.ContentsEntry) { assert(RHS.Buffer.getPointer() == nullptr && RHS.SourceLineCache == nullptr && "Passed ContentCache object cannot own a buffer."); @@ -184,10 +181,26 @@ /// will be emitted at. /// /// \param Invalid If non-NULL, will be set \c true if an error occurred. - const llvm::MemoryBuffer *getBuffer(DiagnosticsEngine &Diag, - FileManager &FM, - SourceLocation Loc = SourceLocation(), - bool *Invalid = nullptr) const; + llvm::Optional + getBuffer(DiagnosticsEngine &Diag, FileManager &FM, + SourceLocation Loc = SourceLocation()) const; + + llvm::Optional + getBufferIdentifier(DiagnosticsEngine &Diag, FileManager &FM, + SourceLocation Loc = SourceLocation()) const { + if (auto Buffer = getBuffer(Diag, FM, Loc)) + return Buffer->getBufferIdentifier(); + return None; + } + + /// Get the buffer size, giving 0 if the buffer is invalid. + llvm::Optional + getBufferSize(DiagnosticsEngine &Diag, FileManager &FM, + SourceLocation Loc = SourceLocation()) const { + if (auto Buffer = getBuffer(Diag, FM, Loc)) + return Buffer->getBufferSize(); + return None; + } /// Returns the size of the content encapsulated by this /// ContentCache. @@ -218,9 +231,7 @@ void replaceBuffer(const llvm::MemoryBuffer *B, bool DoNotFree = false); /// Determine whether the buffer itself is invalid. - bool isBufferInvalid() const { - return Buffer.getInt() & InvalidFlag; - } + bool isBufferInvalid() const { return IsBufferInvalid; } /// Determine whether the buffer should be freed. bool shouldFreeBuffer() const { @@ -283,6 +294,11 @@ return X; } + static FileInfo getForRecovery() { + FileInfo X = get(SourceLocation(), nullptr, SrcMgr::C_User, ""); + return X; + } + SourceLocation getIncludeLoc() const { return SourceLocation::getFromRawEncoding(IncludeLoc); } @@ -858,19 +874,16 @@ Name, IncludeLoc, FileCharacter, LoadedID, LoadedOffset); } - enum UnownedTag { Unowned }; - /// Create a new FileID that represents the specified memory buffer. /// - /// This does not take ownership of the MemoryBuffer. The memory buffer must - /// outlive the SourceManager. - FileID createFileID(UnownedTag, const llvm::MemoryBuffer *Buffer, + /// This does not take ownership of the MemoryBufferRef. The memory buffer + /// must outlive the SourceManager. + FileID createFileID(llvm::MemoryBufferRef Buffer, SrcMgr::CharacteristicKind FileCharacter = SrcMgr::C_User, int LoadedID = 0, unsigned LoadedOffset = 0, SourceLocation IncludeLoc = SourceLocation()) { - return createFileID(createMemBufferContentCache(Buffer, /*DoNotFree*/ true), - Buffer->getBufferIdentifier(), IncludeLoc, - FileCharacter, LoadedID, LoadedOffset); + return createFileID(llvm::MemoryBuffer::getMemBuffer(Buffer), FileCharacter, + LoadedID, LoadedOffset, IncludeLoc); } /// Get the FileID for \p SourceFile if it exists. Otherwise, create a @@ -911,8 +924,8 @@ /// /// \param Invalid If non-NULL, will be set \c true if an error /// occurs while retrieving the memory buffer. - const llvm::MemoryBuffer *getMemoryBufferForFile(const FileEntry *File, - bool *Invalid = nullptr); + llvm::Optional + getMemoryBufferForFile(const FileEntry *File); /// Override the contents of the given source file by providing an /// already-allocated buffer. @@ -976,34 +989,37 @@ /// /// 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, SourceLocation Loc, - bool *Invalid = nullptr) const { + llvm::Optional + getBuffer(FileID FID, SourceLocation Loc = SourceLocation()) const { bool MyInvalid = false; const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &MyInvalid); - if (MyInvalid || !Entry.isFile()) { - if (Invalid) - *Invalid = true; - - return getFakeBufferForRecovery(); - } + if (MyInvalid || !Entry.isFile()) + return None; return Entry.getFile().getContentCache()->getBuffer(Diag, getFileManager(), - Loc, Invalid); + Loc); } - const llvm::MemoryBuffer *getBuffer(FileID FID, - bool *Invalid = nullptr) const { - bool MyInvalid = false; - const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &MyInvalid); - if (MyInvalid || !Entry.isFile()) { - if (Invalid) - *Invalid = true; + llvm::MemoryBufferRef + getBufferOrFake(FileID FID, SourceLocation Loc = SourceLocation()) const { + if (auto Buffer = getBuffer(FID, Loc)) + return *Buffer; + return llvm::MemoryBufferRef("<<>>", ""); + } - return getFakeBufferForRecovery(); - } + llvm::Optional + getBufferIdentifier(FileID FID, SourceLocation Loc = SourceLocation()) const { + if (auto Buffer = getBuffer(FID, Loc)) + return Buffer->getBufferIdentifier(); + return None; + } - return Entry.getFile().getContentCache()->getBuffer( - Diag, getFileManager(), SourceLocation(), Invalid); + llvm::StringRef + getBufferIdentifierOrEmpty(FileID FID, + SourceLocation Loc = SourceLocation()) const { + if (auto Identifier = getBufferIdentifier(FID, Loc)) + return *Identifier; + return ""; } /// Returns the FileEntry record for the provided FileID. @@ -1041,12 +1057,29 @@ return Content->OrigEntry; } + /// Return a StringRef to the source buffer data for the + /// specified FileID, or None if it's invalid. + /// + /// \param FID The file ID whose contents will be returned. + llvm::Optional getBufferDataOrNone(FileID FID) const; + /// Return a StringRef to the source buffer data for the /// specified FileID. /// /// \param FID The file ID whose contents will be returned. /// \param Invalid If non-NULL, will be set true if an error occurred. - StringRef getBufferData(FileID FID, bool *Invalid = nullptr) const; + StringRef getBufferData(FileID FID, bool *Invalid) const { + auto Data = getBufferDataOrNone(FID); + if (Invalid) + *Invalid = !Data; + return Data ? *Data : ""; + } + + StringRef getBufferData(FileID FID) const { + if (auto Data = getBufferDataOrNone(FID)) + return *Data; + return ""; + } /// Get the number of FileIDs (files and macros) that were created /// during preprocessing of \p FID, including it. @@ -1761,7 +1794,6 @@ friend class ASTReader; friend class ASTWriter; - llvm::MemoryBuffer *getFakeBufferForRecovery() const; const SrcMgr::ContentCache *getFakeContentCacheForRecovery() const; const SrcMgr::SLocEntry &loadSLocEntry(unsigned Index, bool *Invalid) const; Index: clang/include/clang/Frontend/FrontendAction.h =================================================================== --- clang/include/clang/Frontend/FrontendAction.h +++ clang/include/clang/Frontend/FrontendAction.h @@ -145,7 +145,7 @@ assert(!CurrentInput.isEmpty() && "No current file!"); return CurrentInput.isFile() ? CurrentInput.getFile() - : CurrentInput.getBuffer()->getBufferIdentifier(); + : CurrentInput.getBuffer().getBufferIdentifier(); } InputKind getCurrentFileKind() const { Index: clang/include/clang/Frontend/FrontendOptions.h =================================================================== --- clang/include/clang/Frontend/FrontendOptions.h +++ clang/include/clang/Frontend/FrontendOptions.h @@ -15,18 +15,13 @@ #include "clang/Sema/CodeCompleteOptions.h" #include "clang/Serialization/ModuleFileExtension.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/MemoryBuffer.h" #include #include #include #include #include -namespace llvm { - -class MemoryBuffer; - -} // namespace llvm - namespace clang { namespace frontend { @@ -188,7 +183,7 @@ /// The input, if it comes from a buffer rather than a file. This object /// does not own the buffer, and the caller is responsible for ensuring /// that it outlives any users. - const llvm::MemoryBuffer *Buffer = nullptr; + llvm::Optional Buffer; /// The kind of input, e.g., C source, AST file, LLVM IR. InputKind Kind; @@ -200,16 +195,16 @@ FrontendInputFile() = default; FrontendInputFile(StringRef File, InputKind Kind, bool IsSystem = false) : File(File.str()), Kind(Kind), IsSystem(IsSystem) {} - FrontendInputFile(const llvm::MemoryBuffer *Buffer, InputKind Kind, + FrontendInputFile(llvm::MemoryBufferRef Buffer, InputKind Kind, bool IsSystem = false) : Buffer(Buffer), Kind(Kind), IsSystem(IsSystem) {} InputKind getKind() const { return Kind; } bool isSystem() const { return IsSystem; } - bool isEmpty() const { return File.empty() && Buffer == nullptr; } - bool isFile() const { return !isBuffer(); } - bool isBuffer() const { return Buffer != nullptr; } + bool isEmpty() const { return File.empty() && !Buffer; } + bool isFile() const { return !Buffer; } + bool isBuffer() const { return !isFile(); } bool isPreprocessed() const { return Kind.isPreprocessed(); } StringRef getFile() const { @@ -217,9 +212,9 @@ return File; } - const llvm::MemoryBuffer *getBuffer() const { - assert(isBuffer()); - return Buffer; + llvm::MemoryBufferRef getBuffer() const { + assert(Buffer); + return *Buffer; } }; Index: clang/include/clang/Frontend/PrecompiledPreamble.h =================================================================== --- clang/include/clang/Frontend/PrecompiledPreamble.h +++ clang/include/clang/Frontend/PrecompiledPreamble.h @@ -216,7 +216,7 @@ static PreambleFileHash createForFile(off_t Size, time_t ModTime); static PreambleFileHash - createForMemoryBuffer(const llvm::MemoryBuffer *Buffer); + createForMemoryBuffer(llvm::Optional Buffer); friend bool operator==(const PreambleFileHash &LHS, const PreambleFileHash &RHS) { Index: clang/include/clang/Lex/Lexer.h =================================================================== --- clang/include/clang/Lex/Lexer.h +++ clang/include/clang/Lex/Lexer.h @@ -28,6 +28,7 @@ namespace llvm { class MemoryBuffer; +class MemoryBufferRef; } // namespace llvm @@ -138,7 +139,7 @@ /// with the specified preprocessor managing the lexing process. This lexer /// assumes that the associated file buffer and Preprocessor objects will /// outlive it, so it doesn't take ownership of either of them. - Lexer(FileID FID, const llvm::MemoryBuffer *InputFile, Preprocessor &PP); + Lexer(FileID FID, const llvm::MemoryBufferRef &InputFile, Preprocessor &PP); /// Lexer constructor - Create a new raw lexer object. This object is only /// suitable for calls to 'LexFromRawLexer'. This lexer assumes that the @@ -149,7 +150,7 @@ /// Lexer constructor - Create a new raw lexer object. This object is only /// suitable for calls to 'LexFromRawLexer'. This lexer assumes that the /// text range will outlive it, so it doesn't take ownership of it. - Lexer(FileID FID, const llvm::MemoryBuffer *FromFile, + Lexer(FileID FID, const llvm::MemoryBufferRef &FromFile, const SourceManager &SM, const LangOptions &LangOpts); Lexer(const Lexer &) = delete; Index: clang/lib/ARCMigrate/Transforms.cpp =================================================================== --- clang/lib/ARCMigrate/Transforms.cpp +++ clang/lib/ARCMigrate/Transforms.cpp @@ -140,10 +140,10 @@ std::pair locInfo = SM.getDecomposedLoc(loc); // Try to load the file buffer. - bool invalidTemp = false; - StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); - if (invalidTemp) + llvm::Optional maybeFile = SM.getBufferData(locInfo.first); + if (!maybeFile) return SourceLocation(); + StringRef file = *maybeFile; const char *tokenBegin = file.data() + locInfo.second; @@ -388,10 +388,10 @@ std::pair locInfo = SM.getDecomposedLoc(atLoc); // Try to load the file buffer. - bool invalidTemp = false; - StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); - if (invalidTemp) + llvm::Optional maybeFile = SM.getBufferData(locInfo.first); + if (!maybeFile) return false; + StringRef file = *maybeFile; const char *tokenBegin = file.data() + locInfo.second; @@ -469,10 +469,10 @@ std::pair locInfo = SM.getDecomposedLoc(atLoc); // Try to load the file buffer. - bool invalidTemp = false; - StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); - if (invalidTemp) + llvm::Optional maybeFile = SM.getBufferData(locInfo.first); + if (!maybeFile) return false; + StringRef file = *maybeFile; const char *tokenBegin = file.data() + locInfo.second; Index: clang/lib/AST/ASTImporter.cpp =================================================================== --- clang/lib/AST/ASTImporter.cpp +++ clang/lib/AST/ASTImporter.cpp @@ -8512,11 +8512,9 @@ if (ToID.isInvalid() || IsBuiltin) { // FIXME: We want to re-use the existing MemoryBuffer! - bool Invalid = true; - const llvm::MemoryBuffer *FromBuf = - Cache->getBuffer(FromContext.getDiagnostics(), - FromSM.getFileManager(), SourceLocation{}, &Invalid); - if (!FromBuf || Invalid) + llvm::Optional FromBuf = Cache->getBuffer( + FromContext.getDiagnostics(), FromSM.getFileManager()); + if (!FromBuf) // FIXME: Use a new error kind? return llvm::make_error(ImportError::Unknown); Index: clang/lib/Basic/Diagnostic.cpp =================================================================== --- clang/lib/Basic/Diagnostic.cpp +++ clang/lib/Basic/Diagnostic.cpp @@ -258,7 +258,7 @@ PrintedOuterHeading = true; llvm::errs() << "File " << &File << " : " << SrcMgr.getBuffer(ID)->getBufferIdentifier(); + << ">: " << SrcMgr.getBufferOrFake(ID).getBufferIdentifier(); if (F.second.Parent) { std::pair Decomp = SrcMgr.getDecomposedIncludedLoc(ID); Index: clang/lib/Basic/SourceLocation.cpp =================================================================== --- clang/lib/Basic/SourceLocation.cpp +++ clang/lib/Basic/SourceLocation.cpp @@ -245,7 +245,13 @@ StringRef FullSourceLoc::getBufferData(bool *Invalid) const { assert(isValid()); - return SrcMgr->getBuffer(SrcMgr->getFileID(*this), Invalid)->getBuffer(); + auto Buffer = SrcMgr->getBuffer(SrcMgr->getFileID(*this)); + if (Invalid) + *Invalid = !Buffer; + + if (Buffer) + return Buffer->getBuffer(); + return ""; } std::pair FullSourceLoc::getDecomposedLoc() const { Index: clang/lib/Basic/SourceManager.cpp =================================================================== --- clang/lib/Basic/SourceManager.cpp +++ clang/lib/Basic/SourceManager.cpp @@ -83,6 +83,8 @@ } void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B, bool DoNotFree) { + IsBufferInvalid = false; + if (B && B == Buffer.getPointer()) { assert(0 && "Replacing with the same buffer"); Buffer.setInt(DoNotFree? DoNotFreeFlag : 0); @@ -95,18 +97,17 @@ Buffer.setInt((B && DoNotFree) ? DoNotFreeFlag : 0); } -const llvm::MemoryBuffer *ContentCache::getBuffer(DiagnosticsEngine &Diag, - FileManager &FM, - SourceLocation Loc, - bool *Invalid) const { +llvm::Optional +ContentCache::getBuffer(DiagnosticsEngine &Diag, FileManager &FM, + SourceLocation Loc) const { // Lazily create the Buffer for ContentCaches that wrap files. If we already // computed it, just return what we have. - if (Buffer.getPointer() || !ContentsEntry) { - if (Invalid) - *Invalid = isBufferInvalid(); - - return Buffer.getPointer(); - } + if (isBufferInvalid()) + return None; + if (auto *B = Buffer.getPointer()) + return B->getMemBufferRef(); + if (!ContentsEntry) + return None; // Check that the file's size fits in an 'unsigned' (with room for a // past-the-end value). This is deeply regrettable, but various parts of @@ -115,13 +116,6 @@ // miserably on large source files. if ((uint64_t)ContentsEntry->getSize() >= std::numeric_limits::max()) { - // We can't make a memory buffer of the required size, so just make a small - // one. We should never hit a situation where we've already parsed to a - // later offset of the file, so it shouldn't matter that the buffer is - // smaller than the file. - Buffer.setPointer( - llvm::MemoryBuffer::getMemBuffer("", ContentsEntry->getName()) - .release()); if (Diag.isDiagnosticInFlight()) Diag.SetDelayedDiagnostic(diag::err_file_too_large, ContentsEntry->getName()); @@ -129,9 +123,8 @@ Diag.Report(Loc, diag::err_file_too_large) << ContentsEntry->getName(); - Buffer.setInt(Buffer.getInt() | InvalidFlag); - if (Invalid) *Invalid = true; - return Buffer.getPointer(); + IsBufferInvalid = true; + return None; } auto BufferOrError = FM.getBufferForFile(ContentsEntry, IsFileVolatile); @@ -141,20 +134,7 @@ // exists. Most likely, we were using a stat cache with an invalid entry but // the file could also have been removed during processing. Since we can't // really deal with this situation, just create an empty buffer. - // - // FIXME: This is definitely not ideal, but our immediate clients can't - // currently handle returning a null entry here. Ideally we should detect - // that we are in an inconsistent situation and error out as quickly as - // possible. if (!BufferOrError) { - StringRef FillStr("<<>>\n"); - auto BackupBuffer = llvm::WritableMemoryBuffer::getNewUninitMemBuffer( - ContentsEntry->getSize(), ""); - char *Ptr = BackupBuffer->getBufferStart(); - for (unsigned i = 0, e = ContentsEntry->getSize(); i != e; ++i) - Ptr[i] = FillStr[i % FillStr.size()]; - Buffer.setPointer(BackupBuffer.release()); - if (Diag.isDiagnosticInFlight()) Diag.SetDelayedDiagnostic(diag::err_cannot_open_file, ContentsEntry->getName(), @@ -163,10 +143,8 @@ Diag.Report(Loc, diag::err_cannot_open_file) << ContentsEntry->getName() << BufferOrError.getError().message(); - Buffer.setInt(Buffer.getInt() | InvalidFlag); - - if (Invalid) *Invalid = true; - return Buffer.getPointer(); + IsBufferInvalid = true; + return None; } Buffer.setPointer(BufferOrError->release()); @@ -181,9 +159,8 @@ Diag.Report(Loc, diag::err_file_modified) << ContentsEntry->getName(); - Buffer.setInt(Buffer.getInt() | InvalidFlag); - if (Invalid) *Invalid = true; - return Buffer.getPointer(); + IsBufferInvalid = true; + return None; } // If the buffer is valid, check to see if it has a UTF Byte Order Mark @@ -208,13 +185,11 @@ if (InvalidBOM) { Diag.Report(Loc, diag::err_unsupported_bom) << InvalidBOM << ContentsEntry->getName(); - Buffer.setInt(Buffer.getInt() | InvalidFlag); + IsBufferInvalid = true; + return None; } - if (Invalid) - *Invalid = isBufferInvalid(); - - return Buffer.getPointer(); + return Buffer.getPointer()->getMemBufferRef(); } unsigned LineTableInfo::getLineTableFilenameID(StringRef Name) { @@ -487,25 +462,12 @@ return std::make_pair(-ID - 1, CurrentLoadedOffset); } -/// As part of recovering from missing or changed content, produce a -/// fake, non-empty buffer. -llvm::MemoryBuffer *SourceManager::getFakeBufferForRecovery() const { - if (!FakeBufferForRecovery) - FakeBufferForRecovery = - llvm::MemoryBuffer::getMemBuffer("<<>"); - - return FakeBufferForRecovery.get(); -} - /// As part of recovering from missing or changed content, produce a /// fake content cache. const SrcMgr::ContentCache * SourceManager::getFakeContentCacheForRecovery() const { - if (!FakeContentCacheForRecovery) { + if (!FakeContentCacheForRecovery) FakeContentCacheForRecovery = std::make_unique(); - FakeContentCacheForRecovery->replaceBuffer(getFakeBufferForRecovery(), - /*DoNotFree=*/true); - } return FakeContentCacheForRecovery.get(); } @@ -639,11 +601,11 @@ return SourceLocation::getMacroLoc(NextLocalOffset - (TokLength + 1)); } -const llvm::MemoryBuffer * -SourceManager::getMemoryBufferForFile(const FileEntry *File, bool *Invalid) { +llvm::Optional +SourceManager::getMemoryBufferForFile(const FileEntry *File) { const SrcMgr::ContentCache *IR = getOrCreateContentCache(File); assert(IR && "getOrCreateContentCache() cannot return NULL"); - return IR->getBuffer(Diag, getFileManager(), SourceLocation(), Invalid); + return IR->getBuffer(Diag, getFileManager()); } void SourceManager::overrideFileContents(const FileEntry *SourceFile, @@ -689,24 +651,16 @@ const_cast(CC)->IsTransient = true; } -StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const { +llvm::Optional SourceManager::getBufferDataOrNone(FileID FID) const { bool MyInvalid = false; const SLocEntry &SLoc = getSLocEntry(FID, &MyInvalid); - if (!SLoc.isFile() || MyInvalid) { - if (Invalid) - *Invalid = true; - return "<<<<>>>>"; - } - - const llvm::MemoryBuffer *Buf = SLoc.getFile().getContentCache()->getBuffer( - Diag, getFileManager(), SourceLocation(), &MyInvalid); - if (Invalid) - *Invalid = MyInvalid; + if (!SLoc.isFile() || MyInvalid) + return None; - if (MyInvalid) - return "<<<<>>>>"; - - return Buf->getBuffer(); + if (llvm::Optional Buf = + SLoc.getFile().getContentCache()->getBuffer(Diag, getFileManager())) + return Buf->getBuffer(); + return None; } //===----------------------------------------------------------------------===// @@ -1128,24 +1082,22 @@ return "<<<>>>"; } - const llvm::MemoryBuffer *Buffer = - Entry.getFile().getContentCache()->getBuffer( - Diag, getFileManager(), SourceLocation(), &CharDataInvalid); + llvm::Optional Buffer = + Entry.getFile().getContentCache()->getBuffer(Diag, getFileManager()); if (Invalid) - *Invalid = CharDataInvalid; - return Buffer->getBufferStart() + (CharDataInvalid? 0 : LocInfo.second); + *Invalid = !Buffer; + return Buffer ? Buffer->getBufferStart() + LocInfo.second : nullptr; } /// getColumnNumber - Return the column # for the specified file position. /// this is significantly cheaper to compute than the line number. unsigned SourceManager::getColumnNumber(FileID FID, unsigned FilePos, bool *Invalid) const { - bool MyInvalid = false; - const llvm::MemoryBuffer *MemBuf = getBuffer(FID, &MyInvalid); + llvm::Optional MemBuf = getBuffer(FID); if (Invalid) - *Invalid = MyInvalid; + *Invalid = !MemBuf; - if (MyInvalid) + if (!MemBuf) return 1; // It is okay to request a position just past the end of the buffer. @@ -1226,9 +1178,9 @@ llvm::BumpPtrAllocator &Alloc, const SourceManager &SM, bool &Invalid) { // Note that calling 'getBuffer()' may lazily page in the file. - const MemoryBuffer *Buffer = - FI->getBuffer(Diag, SM.getFileManager(), SourceLocation(), &Invalid); - if (Invalid) + llvm::Optional Buffer = + FI->getBuffer(Diag, SM.getFileManager()); + if (!Buffer) return; // Find the file offsets of all of the *physical* source lines. This does @@ -1425,7 +1377,9 @@ bool *Invalid) const { if (isInvalid(Loc, Invalid)) return ""; - return getBuffer(getFileID(Loc), Invalid)->getBufferIdentifier(); + if (auto Buffer = getBuffer(getFileID(Loc))) + return Buffer->getBufferIdentifier(); + return ""; } /// getPresumedLoc - This method returns the "presumed" location of a @@ -1457,8 +1411,8 @@ StringRef Filename; if (C->OrigEntry) Filename = C->OrigEntry->getName(); - else - Filename = C->getBuffer(Diag, getFileManager())->getBufferIdentifier(); + else if (auto Name = C->getBufferIdentifier(Diag, getFileManager())) + Filename = *Name; unsigned LineNo = getLineNumber(LocInfo.first, LocInfo.second, &Invalid); if (Invalid) @@ -1658,13 +1612,16 @@ } if (Line > Content->NumLines) { - unsigned Size = Content->getBuffer(Diag, getFileManager())->getBufferSize(); - if (Size > 0) - --Size; + unsigned Size = 0; + if (llvm::Optional RawSize = + Content->getBufferSize(Diag, getFileManager())) + if (*RawSize > 0) + Size = *RawSize - 1; return FileLoc.getLocWithOffset(Size); } - const llvm::MemoryBuffer *Buffer = Content->getBuffer(Diag, getFileManager()); + llvm::Optional Buffer = + Content->getBuffer(Diag, getFileManager()); unsigned FilePos = Content->SourceLineCache[Line - 1]; const char *Buf = Buffer->getBufferStart() + FilePos; unsigned BufLength = Buffer->getBufferSize() - FilePos; @@ -1949,11 +1906,10 @@ // If we arrived here, the location is either in a built-ins buffer or // associated with global inline asm. PR5662 and PR22576 are examples. - - StringRef LB = getBuffer(LOffs.first)->getBufferIdentifier(); - StringRef RB = getBuffer(ROffs.first)->getBufferIdentifier(); - bool LIsBuiltins = LB == ""; - bool RIsBuiltins = RB == ""; + llvm::Optional LB = getBufferIdentifier(LOffs.first); + llvm::Optional RB = getBufferIdentifier(ROffs.first); + bool LIsBuiltins = LB == StringRef(""); + bool RIsBuiltins = RB == StringRef(""); // Sort built-in before non-built-in. if (LIsBuiltins || RIsBuiltins) { if (LIsBuiltins != RIsBuiltins) @@ -1962,8 +1918,8 @@ // lower IDs come first. return LOffs.first < ROffs.first; } - bool LIsAsm = LB == ""; - bool RIsAsm = RB == ""; + bool LIsAsm = LB == StringRef(""); + bool RIsAsm = RB == StringRef(""); // Sort assembler after built-ins, but before the rest. if (LIsAsm || RIsAsm) { if (LIsAsm != RIsAsm) @@ -1971,8 +1927,8 @@ assert(LOffs.first == ROffs.first); return false; } - bool LIsScratch = LB == ""; - bool RIsScratch = RB == ""; + bool LIsScratch = LB == StringRef(""); + bool RIsScratch = RB == StringRef(""); // Sort scratch after inline asm, but before the rest. if (LIsScratch || RIsScratch) { if (LIsScratch != RIsScratch) Index: clang/lib/CodeGen/CGDebugInfo.cpp =================================================================== --- clang/lib/CodeGen/CGDebugInfo.cpp +++ clang/lib/CodeGen/CGDebugInfo.cpp @@ -372,9 +372,8 @@ return None; SourceManager &SM = CGM.getContext().getSourceManager(); - bool Invalid; - const llvm::MemoryBuffer *MemBuffer = SM.getBuffer(FID, &Invalid); - if (Invalid) + llvm::Optional MemBuffer = SM.getBuffer(FID); + if (!MemBuffer) return None; llvm::MD5 Hash; @@ -392,13 +391,7 @@ if (!CGM.getCodeGenOpts().EmbedSource) return None; - bool SourceInvalid = false; - StringRef Source = SM.getBufferData(FID, &SourceInvalid); - - if (SourceInvalid) - return None; - - return Source; + return SM.getBufferData(FID); } llvm::DIFile *CGDebugInfo::getOrCreateFile(SourceLocation Loc) { Index: clang/lib/CodeGen/CodeGenAction.cpp =================================================================== --- clang/lib/CodeGen/CodeGenAction.cpp +++ clang/lib/CodeGen/CodeGenAction.cpp @@ -1025,11 +1025,10 @@ if (BA != Backend_EmitNothing && !OS) return; - bool Invalid; SourceManager &SM = CI.getSourceManager(); FileID FID = SM.getMainFileID(); - const llvm::MemoryBuffer *MainFile = SM.getBuffer(FID, &Invalid); - if (Invalid) + llvm::Optional MainFile = SM.getBuffer(FID); + if (!MainFile) return; TheModule = loadModule(*MainFile); @@ -1044,8 +1043,7 @@ TheModule->setTargetTriple(TargetOpts.Triple); } - EmbedBitcode(TheModule.get(), CI.getCodeGenOpts(), - MainFile->getMemBufferRef()); + EmbedBitcode(TheModule.get(), CI.getCodeGenOpts(), *MainFile); LLVMContext &Ctx = TheModule->getContext(); Ctx.setInlineAsmDiagnosticHandler(BitcodeInlineAsmDiagHandler, Index: clang/lib/Format/FormatTokenLexer.cpp =================================================================== --- clang/lib/Format/FormatTokenLexer.cpp +++ clang/lib/Format/FormatTokenLexer.cpp @@ -31,7 +31,7 @@ Keywords(IdentTable), Encoding(Encoding), FirstInLineIndex(0), FormattingDisabled(false), MacroBlockBeginRegex(Style.MacroBlockBegin), MacroBlockEndRegex(Style.MacroBlockEnd) { - Lex.reset(new Lexer(ID, SourceMgr.getBuffer(ID), SourceMgr, + Lex.reset(new Lexer(ID, SourceMgr.getBufferOrFake(ID), SourceMgr, getFormattingLangOpts(Style))); Lex->SetKeepWhitespaceMode(true); @@ -541,7 +541,7 @@ unsigned FirstInLineOffset; std::tie(ID, FirstInLineOffset) = SourceMgr.getDecomposedLoc( Tokens[FirstInLineIndex]->getStartOfNonWhitespace()); - StringRef Buffer = SourceMgr.getBuffer(ID)->getBuffer(); + StringRef Buffer = SourceMgr.getBufferOrFake(ID).getBuffer(); // Calculate the offset of the start of the current line. auto LineOffset = Buffer.rfind('\n', FirstInLineOffset); if (LineOffset == StringRef::npos) { Index: clang/lib/Frontend/ASTUnit.cpp =================================================================== --- clang/lib/Frontend/ASTUnit.cpp +++ clang/lib/Frontend/ASTUnit.cpp @@ -1466,7 +1466,7 @@ if (Input.isFile()) return Input.getFile(); else - return Input.getBuffer()->getBufferIdentifier(); + return Input.getBuffer().getBufferIdentifier(); } if (SourceMgr) { Index: clang/lib/Frontend/CompilerInstance.cpp =================================================================== --- clang/lib/Frontend/CompilerInstance.cpp +++ clang/lib/Frontend/CompilerInstance.cpp @@ -820,8 +820,7 @@ : Input.isSystem() ? SrcMgr::C_System : SrcMgr::C_User; if (Input.isBuffer()) { - SourceMgr.setMainFileID(SourceMgr.createFileID(SourceManager::Unowned, - Input.getBuffer(), Kind)); + SourceMgr.setMainFileID(SourceMgr.createFileID(Input.getBuffer(), Kind)); assert(SourceMgr.getMainFileID().isValid() && "Couldn't establish MainFileID!"); return true; Index: clang/lib/Frontend/FrontendAction.cpp =================================================================== --- clang/lib/Frontend/FrontendAction.cpp +++ clang/lib/Frontend/FrontendAction.cpp @@ -234,13 +234,13 @@ auto &SourceMgr = CI.getSourceManager(); auto MainFileID = SourceMgr.getMainFileID(); - bool Invalid = false; - const auto *MainFileBuf = SourceMgr.getBuffer(MainFileID, &Invalid); - if (Invalid) + llvm::Optional MainFileBuf = + SourceMgr.getBuffer(MainFileID); + if (!MainFileBuf) return SourceLocation(); std::unique_ptr RawLexer( - new Lexer(MainFileID, MainFileBuf, SourceMgr, CI.getLangOpts())); + new Lexer(MainFileID, *MainFileBuf, SourceMgr, CI.getLangOpts())); // If the first line has the syntax of // @@ -438,7 +438,7 @@ PresumedModuleMapFile)) return true; - if (SrcMgr.getBuffer(ModuleMapID)->getBufferSize() == Offset) + if (SrcMgr.getBufferOrFake(ModuleMapID).getBufferSize() == Offset) Offset = 0; return false; @@ -611,7 +611,7 @@ if (auto *File = OldSM.getFileEntryForID(ID)) Input = FrontendInputFile(File->getName(), Kind); else - Input = FrontendInputFile(OldSM.getBuffer(ID), Kind); + Input = FrontendInputFile(OldSM.getBufferOrFake(ID), Kind); } setCurrentInput(Input, std::move(AST)); } Index: clang/lib/Frontend/FrontendActions.cpp =================================================================== --- clang/lib/Frontend/FrontendActions.cpp +++ clang/lib/Frontend/FrontendActions.cpp @@ -259,7 +259,7 @@ if (FIF.getKind().getFormat() != InputKind::Source || !FIF.isFile()) { CI.getDiagnostics().Report(diag::err_module_header_file_not_found) << (FIF.isFile() ? FIF.getFile() - : FIF.getBuffer()->getBufferIdentifier()); + : FIF.getBuffer().getBufferIdentifier()); return true; } @@ -273,7 +273,8 @@ // Set that buffer up as our "real" input. Inputs.clear(); - Inputs.push_back(FrontendInputFile(Buffer.get(), Kind, /*IsSystem*/false)); + Inputs.push_back( + FrontendInputFile(Buffer->getMemBufferRef(), Kind, /*IsSystem*/ false)); return GenerateModuleAction::PrepareToExecuteAction(CI); } @@ -727,8 +728,8 @@ SourceManager &SM = PP.getSourceManager(); // Start lexing the specified input file. - const llvm::MemoryBuffer *FromFile = SM.getBuffer(SM.getMainFileID()); - Lexer RawLex(SM.getMainFileID(), FromFile, SM, PP.getLangOpts()); + Lexer RawLex(SM.getMainFileID(), SM.getBufferOrFake(SM.getMainFileID()), SM, + PP.getLangOpts()); RawLex.SetKeepWhitespaceMode(true); Token RawTok; @@ -782,11 +783,9 @@ // concern, so if we scan for too long, we'll just assume the file should // be opened in binary mode. bool BinaryMode = true; - bool InvalidFile = false; const SourceManager& SM = CI.getSourceManager(); - const llvm::MemoryBuffer *Buffer = SM.getBuffer(SM.getMainFileID(), - &InvalidFile); - if (!InvalidFile) { + if (llvm::Optional Buffer = + SM.getBuffer(SM.getMainFileID())) { const char *cur = Buffer->getBufferStart(); const char *end = Buffer->getBufferEnd(); const char *next = (cur != end) ? cur + 1 : end; @@ -914,12 +913,12 @@ void PrintDependencyDirectivesSourceMinimizerAction::ExecuteAction() { CompilerInstance &CI = getCompilerInstance(); SourceManager &SM = CI.getPreprocessor().getSourceManager(); - const llvm::MemoryBuffer *FromFile = SM.getBuffer(SM.getMainFileID()); + llvm::MemoryBufferRef FromFile = SM.getBufferOrFake(SM.getMainFileID()); llvm::SmallString<1024> Output; llvm::SmallVector Toks; if (minimizeSourceToDependencyDirectives( - FromFile->getBuffer(), Output, Toks, &CI.getDiagnostics(), + FromFile.getBuffer(), Output, Toks, &CI.getDiagnostics(), SM.getLocForStartOfFile(SM.getMainFileID()))) { assert(CI.getDiagnostics().hasErrorOccurred() && "no errors reported for failure"); Index: clang/lib/Frontend/PrecompiledPreamble.cpp =================================================================== --- clang/lib/Frontend/PrecompiledPreamble.cpp +++ clang/lib/Frontend/PrecompiledPreamble.cpp @@ -379,7 +379,8 @@ PrecompiledPreamble::PreambleFileHash::createForFile(File->getSize(), ModTime); } else { - const llvm::MemoryBuffer *Buffer = SourceMgr.getMemoryBufferForFile(File); + llvm::Optional Buffer = + SourceMgr.getMemoryBufferForFile(File); FilesInPreamble[File->getName()] = PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(Buffer); } @@ -460,7 +461,9 @@ llvm::StringMap OverridenFileBuffers; for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) { const PrecompiledPreamble::PreambleFileHash PreambleHash = - PreambleFileHash::createForMemoryBuffer(RB.second); + PreambleFileHash::createForMemoryBuffer( + RB.second ? RB.second->getMemBufferRef() + : llvm::Optional(None)); llvm::vfs::Status Status; if (moveOnNoError(VFS->status(RB.first), Status)) OverriddenFiles[Status.getUniqueID()] = PreambleHash; @@ -688,13 +691,13 @@ PrecompiledPreamble::PreambleFileHash PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer( - const llvm::MemoryBuffer *Buffer) { + llvm::Optional Buffer) { PreambleFileHash Result; - Result.Size = Buffer->getBufferSize(); + Result.Size = Buffer ? Buffer->getBufferSize() : 0; Result.ModTime = 0; llvm::MD5 MD5Ctx; - MD5Ctx.update(Buffer->getBuffer().data()); + MD5Ctx.update(Buffer ? Buffer->getBuffer().data() : nullptr); MD5Ctx.final(Result.MD5); return Result; Index: clang/lib/Frontend/Rewrite/HTMLPrint.cpp =================================================================== --- clang/lib/Frontend/Rewrite/HTMLPrint.cpp +++ clang/lib/Frontend/Rewrite/HTMLPrint.cpp @@ -70,7 +70,7 @@ if (Entry) Name = Entry->getName(); else - Name = R.getSourceMgr().getBuffer(FID)->getBufferIdentifier(); + Name = R.getSourceMgr().getBufferOrFake(FID).getBufferIdentifier(); html::AddLineNumbers(R, FID); html::AddHeaderFooterInternalBuiltinCSS(R, FID, Name); Index: clang/lib/Frontend/Rewrite/InclusionRewriter.cpp =================================================================== --- clang/lib/Frontend/Rewrite/InclusionRewriter.cpp +++ clang/lib/Frontend/Rewrite/InclusionRewriter.cpp @@ -40,7 +40,7 @@ SourceManager &SM; ///< Used to read and manage source files. raw_ostream &OS; ///< The destination stream for rewritten contents. StringRef MainEOL; ///< The line ending marker to use. - const llvm::MemoryBuffer *PredefinesBuffer; ///< The preprocessor predefines. + Optional PredefinesBuffer; ///< The preprocessor predefines. bool ShowLineMarkers; ///< Show #line markers. bool UseLineDirectives; ///< Use of line directives or line markers. /// Tracks where inclusions that change the file are found. @@ -57,7 +57,7 @@ bool UseLineDirectives); void Process(FileID FileId, SrcMgr::CharacteristicKind FileType, const DirectoryLookup *DirLookup); - void setPredefinesBuffer(const llvm::MemoryBuffer *Buf) { + void setPredefinesBuffer(Optional Buf) { PredefinesBuffer = Buf; } void detectMainFileEOL(); @@ -82,12 +82,11 @@ SrcMgr::CharacteristicKind FileType, StringRef Extra = StringRef()); void WriteImplicitModuleImport(const Module *Mod); - void OutputContentUpTo(const MemoryBuffer &FromFile, - unsigned &WriteFrom, unsigned WriteTo, - StringRef EOL, int &lines, + void OutputContentUpTo(MemoryBufferRef FromFile, unsigned &WriteFrom, + unsigned WriteTo, StringRef EOL, int &lines, bool EnsureNewline); void CommentOutDirective(Lexer &DirectivesLex, const Token &StartToken, - const MemoryBuffer &FromFile, StringRef EOL, + MemoryBufferRef FromFile, StringRef EOL, unsigned &NextToWrite, int &Lines); bool HandleHasInclude(FileID FileId, Lexer &RawLex, const DirectoryLookup *Lookup, Token &Tok, @@ -105,8 +104,7 @@ bool ShowLineMarkers, bool UseLineDirectives) : PP(PP), SM(PP.getSourceManager()), OS(OS), MainEOL("\n"), - PredefinesBuffer(nullptr), ShowLineMarkers(ShowLineMarkers), - UseLineDirectives(UseLineDirectives), + ShowLineMarkers(ShowLineMarkers), UseLineDirectives(UseLineDirectives), LastInclusionLocation(SourceLocation()) {} /// Write appropriate line information as either #line directives or GNU line @@ -235,7 +233,7 @@ /// Detect the likely line ending style of \p FromFile by examining the first /// newline found within it. -static StringRef DetectEOL(const MemoryBuffer &FromFile) { +static StringRef DetectEOL(MemoryBufferRef FromFile) { // Detect what line endings the file uses, so that added content does not mix // the style. We need to check for "\r\n" first because "\n\r" will match // "\r\n\r\n". @@ -250,23 +248,21 @@ } void InclusionRewriter::detectMainFileEOL() { - bool Invalid; - const MemoryBuffer &FromFile = *SM.getBuffer(SM.getMainFileID(), &Invalid); - assert(!Invalid); - if (Invalid) + Optional FromFile = SM.getBuffer(SM.getMainFileID()); + if (!FromFile) return; // Should never happen, but whatever. - MainEOL = DetectEOL(FromFile); + MainEOL = DetectEOL(*FromFile); } /// Writes out bytes from \p FromFile, starting at \p NextToWrite and ending at /// \p WriteTo - 1. -void InclusionRewriter::OutputContentUpTo(const MemoryBuffer &FromFile, +void InclusionRewriter::OutputContentUpTo(MemoryBufferRef FromFile, unsigned &WriteFrom, unsigned WriteTo, StringRef LocalEOL, int &Line, bool EnsureNewline) { if (WriteTo <= WriteFrom) return; - if (&FromFile == PredefinesBuffer) { + if (FromFile == PredefinesBuffer) { // Ignore the #defines of the predefines buffer. WriteFrom = WriteTo; return; @@ -313,7 +309,7 @@ /// through the \p FromFile buffer. void InclusionRewriter::CommentOutDirective(Lexer &DirectiveLex, const Token &StartToken, - const MemoryBuffer &FromFile, + MemoryBufferRef FromFile, StringRef LocalEOL, unsigned &NextToWrite, int &Line) { OutputContentUpTo(FromFile, NextToWrite, @@ -323,7 +319,7 @@ do { DirectiveLex.LexFromRawLexer(DirectiveToken); } while (!DirectiveToken.is(tok::eod) && DirectiveToken.isNot(tok::eof)); - if (&FromFile == PredefinesBuffer) { + if (FromFile == PredefinesBuffer) { // OutputContentUpTo() would not output anything anyway. return; } @@ -425,11 +421,11 @@ void InclusionRewriter::Process(FileID FileId, SrcMgr::CharacteristicKind FileType, const DirectoryLookup *DirLookup) { - bool Invalid; - const MemoryBuffer &FromFile = *SM.getBuffer(FileId, &Invalid); - assert(!Invalid && "Attempting to process invalid inclusion"); + Optional MaybeFromFile = SM.getBuffer(FileId); + assert(MaybeFromFile && "Attempting to process invalid inclusion"); + auto FromFile = *MaybeFromFile; StringRef FileName = FromFile.getBufferIdentifier(); - Lexer RawLex(FileId, &FromFile, PP.getSourceManager(), PP.getLangOpts()); + Lexer RawLex(FileId, FromFile, PP.getSourceManager(), PP.getLangOpts()); RawLex.SetCommentRetentionState(false); StringRef LocalEOL = DetectEOL(FromFile); Index: clang/lib/Frontend/Rewrite/RewriteMacros.cpp =================================================================== --- clang/lib/Frontend/Rewrite/RewriteMacros.cpp +++ clang/lib/Frontend/Rewrite/RewriteMacros.cpp @@ -64,7 +64,7 @@ // Create a lexer to lex all the tokens of the main file in raw mode. Even // though it is in raw mode, it will not return comments. - const llvm::MemoryBuffer *FromFile = SM.getBuffer(SM.getMainFileID()); + llvm::MemoryBufferRef FromFile = SM.getBufferOrFake(SM.getMainFileID()); Lexer RawLex(SM.getMainFileID(), FromFile, SM, PP.getLangOpts()); // Switch on comment lexing because we really do want them. Index: clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp =================================================================== --- clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp +++ clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp @@ -701,9 +701,9 @@ // Get the ID and start/end of the main file. MainFileID = SM->getMainFileID(); - const llvm::MemoryBuffer *MainBuf = SM->getBuffer(MainFileID); - MainFileStart = MainBuf->getBufferStart(); - MainFileEnd = MainBuf->getBufferEnd(); + llvm::MemoryBufferRef MainBuf = SM->getBufferOrFake(MainFileID); + MainFileStart = MainBuf.getBufferStart(); + MainFileEnd = MainBuf.getBufferEnd(); Rewrite.setSourceMgr(Context->getSourceManager(), Context->getLangOpts()); } Index: clang/lib/Frontend/Rewrite/RewriteObjC.cpp =================================================================== --- clang/lib/Frontend/Rewrite/RewriteObjC.cpp +++ clang/lib/Frontend/Rewrite/RewriteObjC.cpp @@ -630,9 +630,9 @@ // Get the ID and start/end of the main file. MainFileID = SM->getMainFileID(); - const llvm::MemoryBuffer *MainBuf = SM->getBuffer(MainFileID); - MainFileStart = MainBuf->getBufferStart(); - MainFileEnd = MainBuf->getBufferEnd(); + llvm::MemoryBufferRef MainBuf = SM->getBufferOrFake(MainFileID); + MainFileStart = MainBuf.getBufferStart(); + MainFileEnd = MainBuf.getBufferEnd(); Rewrite.setSourceMgr(Context->getSourceManager(), Context->getLangOpts()); } Index: clang/lib/Frontend/VerifyDiagnosticConsumer.cpp =================================================================== --- clang/lib/Frontend/VerifyDiagnosticConsumer.cpp +++ clang/lib/Frontend/VerifyDiagnosticConsumer.cpp @@ -809,7 +809,7 @@ return false; // Create a lexer to lex all the tokens of the main file in raw mode. - const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID); + llvm::MemoryBufferRef FromFile = SM.getBufferOrFake(FID); Lexer RawLex(FID, FromFile, SM, LangOpts); // Return comments as tokens, this is how we find expected diagnostics. Index: clang/lib/Lex/Lexer.cpp =================================================================== --- clang/lib/Lex/Lexer.cpp +++ clang/lib/Lex/Lexer.cpp @@ -130,12 +130,13 @@ /// with the specified preprocessor managing the lexing process. This lexer /// assumes that the associated file buffer and Preprocessor objects will /// outlive it, so it doesn't take ownership of either of them. -Lexer::Lexer(FileID FID, const llvm::MemoryBuffer *InputFile, Preprocessor &PP) +Lexer::Lexer(FileID FID, const llvm::MemoryBufferRef &InputFile, + Preprocessor &PP) : PreprocessorLexer(&PP, FID), FileLoc(PP.getSourceManager().getLocForStartOfFile(FID)), LangOpts(PP.getLangOpts()) { - InitLexer(InputFile->getBufferStart(), InputFile->getBufferStart(), - InputFile->getBufferEnd()); + InitLexer(InputFile.getBufferStart(), InputFile.getBufferStart(), + InputFile.getBufferEnd()); resetExtendedTokenMode(); } @@ -155,10 +156,10 @@ /// Lexer constructor - Create a new raw lexer object. This object is only /// suitable for calls to 'LexFromRawLexer'. This lexer assumes that the text /// range will outlive it, so it doesn't take ownership of it. -Lexer::Lexer(FileID FID, const llvm::MemoryBuffer *FromFile, +Lexer::Lexer(FileID FID, const llvm::MemoryBufferRef &FromFile, const SourceManager &SM, const LangOptions &langOpts) - : Lexer(SM.getLocForStartOfFile(FID), langOpts, FromFile->getBufferStart(), - FromFile->getBufferStart(), FromFile->getBufferEnd()) {} + : Lexer(SM.getLocForStartOfFile(FID), langOpts, FromFile.getBufferStart(), + FromFile.getBufferStart(), FromFile.getBufferEnd()) {} void Lexer::resetExtendedTokenMode() { assert(PP && "Cannot reset token mode without a preprocessor"); @@ -191,7 +192,7 @@ // Create the lexer as if we were going to lex the file normally. FileID SpellingFID = SM.getFileID(SpellingLoc); - const llvm::MemoryBuffer *InputFile = SM.getBuffer(SpellingFID); + llvm::MemoryBufferRef InputFile = SM.getBufferOrFake(SpellingFID); Lexer *L = new Lexer(SpellingFID, InputFile, PP); // Now that the lexer is created, change the start/end locations so that we Index: clang/lib/Lex/ModuleMap.cpp =================================================================== --- clang/lib/Lex/ModuleMap.cpp +++ clang/lib/Lex/ModuleMap.cpp @@ -2979,7 +2979,7 @@ } assert(Target && "Missing target information"); - const llvm::MemoryBuffer *Buffer = SourceMgr.getBuffer(ID); + llvm::Optional Buffer = SourceMgr.getBuffer(ID); if (!Buffer) return ParsedModuleMap[File] = true; assert((!Offset || *Offset <= Buffer->getBufferSize()) && Index: clang/lib/Lex/PPLexerChange.cpp =================================================================== --- clang/lib/Lex/PPLexerChange.cpp +++ clang/lib/Lex/PPLexerChange.cpp @@ -75,10 +75,9 @@ MaxIncludeStackDepth = IncludeMacroStack.size(); // Get the MemoryBuffer for this FID, if it fails, we fail. - bool Invalid = false; - const llvm::MemoryBuffer *InputFile = - getSourceManager().getBuffer(FID, Loc, &Invalid); - if (Invalid) { + llvm::Optional InputFile = + getSourceManager().getBuffer(FID, Loc); + if (!InputFile) { SourceLocation FileStart = SourceMgr.getLocForStartOfFile(FID); Diag(Loc, diag::err_pp_error_opening_file) << std::string(SourceMgr.getBufferName(FileStart)) << ""; @@ -92,7 +91,7 @@ CodeCompletionFileLoc.getLocWithOffset(CodeCompletionOffset); } - EnterSourceFileWithLexer(new Lexer(FID, InputFile, *this), CurDir); + EnterSourceFileWithLexer(new Lexer(FID, *InputFile, *this), CurDir); return false; } Index: clang/lib/Lex/Preprocessor.cpp =================================================================== --- clang/lib/Lex/Preprocessor.cpp +++ clang/lib/Lex/Preprocessor.cpp @@ -388,9 +388,9 @@ using llvm::MemoryBuffer; // Load the actual file's contents. - bool Invalid = false; - const MemoryBuffer *Buffer = SourceMgr.getMemoryBufferForFile(File, &Invalid); - if (Invalid) + llvm::Optional Buffer = + SourceMgr.getMemoryBufferForFile(File); + if (!Buffer) return true; // Find the byte position of the truncation point. Index: clang/lib/Rewrite/HTMLRewrite.cpp =================================================================== --- clang/lib/Rewrite/HTMLRewrite.cpp +++ clang/lib/Rewrite/HTMLRewrite.cpp @@ -107,9 +107,9 @@ void html::EscapeText(Rewriter &R, FileID FID, bool EscapeSpaces, bool ReplaceTabs) { - const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FID); - const char* C = Buf->getBufferStart(); - const char* FileEnd = Buf->getBufferEnd(); + llvm::MemoryBufferRef Buf = R.getSourceMgr().getBufferOrFake(FID); + const char *C = Buf.getBufferStart(); + const char *FileEnd = Buf.getBufferEnd(); assert (C <= FileEnd); @@ -226,9 +226,9 @@ void html::AddLineNumbers(Rewriter& R, FileID FID) { - const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FID); - const char* FileBeg = Buf->getBufferStart(); - const char* FileEnd = Buf->getBufferEnd(); + llvm::MemoryBufferRef Buf = R.getSourceMgr().getBufferOrFake(FID); + const char *FileBeg = Buf.getBufferStart(); + const char *FileEnd = Buf.getBufferEnd(); const char* C = FileBeg; RewriteBuffer &RB = R.getEditBuffer(FID); @@ -274,9 +274,9 @@ void html::AddHeaderFooterInternalBuiltinCSS(Rewriter &R, FileID FID, StringRef title) { - const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FID); - const char* FileStart = Buf->getBufferStart(); - const char* FileEnd = Buf->getBufferEnd(); + llvm::MemoryBufferRef Buf = R.getSourceMgr().getBufferOrFake(FID); + const char *FileStart = Buf.getBufferStart(); + const char *FileEnd = Buf.getBufferEnd(); SourceLocation StartLoc = R.getSourceMgr().getLocForStartOfFile(FID); SourceLocation EndLoc = StartLoc.getLocWithOffset(FileEnd-FileStart); @@ -445,7 +445,7 @@ RewriteBuffer &RB = R.getEditBuffer(FID); const SourceManager &SM = PP.getSourceManager(); - const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID); + llvm::MemoryBufferRef FromFile = SM.getBufferOrFake(FID); Lexer L(FID, FromFile, SM, PP.getLangOpts()); const char *BufferStart = L.getBuffer().data(); @@ -536,7 +536,7 @@ const SourceManager &SM = PP.getSourceManager(); std::vector TokenStream; - const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID); + llvm::MemoryBufferRef FromFile = SM.getBufferOrFake(FID); Lexer L(FID, FromFile, SM, PP.getLangOpts()); // Lex all the tokens in raw mode, to avoid entering #includes or expanding Index: clang/lib/Rewrite/TokenRewriter.cpp =================================================================== --- clang/lib/Rewrite/TokenRewriter.cpp +++ clang/lib/Rewrite/TokenRewriter.cpp @@ -28,7 +28,7 @@ ScratchBuf.reset(new ScratchBuffer(SM)); // Create a lexer to lex all the tokens of the main file in raw mode. - const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID); + llvm::MemoryBufferRef FromFile = SM.getBufferOrFake(FID); Lexer RawLex(FID, FromFile, SM, LangOpts); // Return all comments and whitespace as tokens. Index: clang/lib/Serialization/ASTWriter.cpp =================================================================== --- clang/lib/Serialization/ASTWriter.cpp +++ clang/lib/Serialization/ASTWriter.cpp @@ -2315,9 +2315,9 @@ // We add one to the size so that we capture the trailing NULL // that is required by llvm::MemoryBuffer::getMemBuffer (on // the reader side). - const llvm::MemoryBuffer *Buffer = + llvm::Optional Buffer = Content->getBuffer(PP.getDiagnostics(), PP.getFileManager()); - StringRef Name = Buffer->getBufferIdentifier(); + StringRef Name = Buffer ? Buffer->getBufferIdentifier() : ""; Stream.EmitRecordWithBlob(SLocBufferAbbrv, Record, StringRef(Name.data(), Name.size() + 1)); EmitBlob = true; @@ -2329,8 +2329,10 @@ if (EmitBlob) { // Include the implicit terminating null character in the on-disk buffer // if we're writing it uncompressed. - const llvm::MemoryBuffer *Buffer = + llvm::Optional Buffer = Content->getBuffer(PP.getDiagnostics(), PP.getFileManager()); + if (!Buffer) + Buffer = llvm::MemoryBufferRef("<<>>", ""); StringRef Blob(Buffer->getBufferStart(), Buffer->getBufferSize() + 1); emitBlob(Stream, Blob, SLocBufferBlobCompressedAbbrv, SLocBufferBlobAbbrv); Index: clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp @@ -1137,10 +1137,9 @@ SE = Mgr.getSourceManager().getSLocEntry(SLInfo.first); } - bool Invalid = false; - const llvm::MemoryBuffer *BF = - Mgr.getSourceManager().getBuffer(SLInfo.first, SL, &Invalid); - if (Invalid) + llvm::Optional BF = + Mgr.getSourceManager().getBuffer(SLInfo.first, SL); + if (!BF) return; Lexer TheLexer(SL, LangOptions(), BF->getBufferStart(), Index: clang/lib/StaticAnalyzer/Core/BugReporter.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/BugReporter.cpp +++ clang/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -1511,9 +1511,8 @@ if (FID != SM.getFileID(ExpansionRange.getEnd())) return None; - bool Invalid; - const llvm::MemoryBuffer *Buffer = SM.getBuffer(FID, &Invalid); - if (Invalid) + llvm::Optional Buffer = SM.getBuffer(FID); + if (!Buffer) return None; unsigned BeginOffset = SM.getFileOffset(ExpansionRange.getBegin()); Index: clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp +++ clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp @@ -749,8 +749,8 @@ if (LPosInfo.first != BugFileID) return; - const llvm::MemoryBuffer *Buf = SM.getBuffer(LPosInfo.first); - const char* FileStart = Buf->getBufferStart(); + llvm::MemoryBufferRef Buf = SM.getBufferOrFake(LPosInfo.first); + const char *FileStart = Buf.getBufferStart(); // Compute the column number. Rewind from the current position to the start // of the line. @@ -760,7 +760,7 @@ // Compute LineEnd. const char *LineEnd = TokInstantiationPtr; - const char* FileEnd = Buf->getBufferEnd(); + const char *FileEnd = Buf.getBufferEnd(); while (*LineEnd != '\n' && LineEnd != FileEnd) ++LineEnd; Index: clang/lib/StaticAnalyzer/Core/IssueHash.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/IssueHash.cpp +++ clang/lib/StaticAnalyzer/Core/IssueHash.cpp @@ -120,7 +120,8 @@ return ""; } -static StringRef GetNthLineOfFile(const llvm::MemoryBuffer *Buffer, int Line) { +static StringRef GetNthLineOfFile(llvm::Optional Buffer, + int Line) { if (!Buffer) return ""; @@ -135,7 +136,7 @@ const LangOptions &LangOpts) { static StringRef Whitespaces = " \t\n"; - StringRef Str = GetNthLineOfFile(SM.getBuffer(L.getFileID(), L), + StringRef Str = GetNthLineOfFile(SM.getBufferOrFake(L.getFileID(), L), L.getExpansionLineNumber()); StringRef::size_type col = Str.find_first_not_of(Whitespaces); if (col == StringRef::npos) @@ -144,7 +145,7 @@ col++; SourceLocation StartOfLine = SM.translateLineCol(SM.getFileID(L), L.getExpansionLineNumber(), col); - const llvm::MemoryBuffer *Buffer = + llvm::Optional Buffer = SM.getBuffer(SM.getFileID(StartOfLine), StartOfLine); if (!Buffer) return {}; Index: clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp +++ clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp @@ -1011,11 +1011,11 @@ // First, we create a Lexer to lex *at the expansion location* the tokens // referring to the macro's name and its arguments. std::pair LocInfo = SM.getDecomposedLoc(ExpanLoc); - const llvm::MemoryBuffer *MB = SM.getBuffer(LocInfo.first); - const char *MacroNameTokenPos = MB->getBufferStart() + LocInfo.second; + llvm::MemoryBufferRef MB = SM.getBufferOrFake(LocInfo.first); + const char *MacroNameTokenPos = MB.getBufferStart() + LocInfo.second; Lexer RawLexer(SM.getLocForStartOfFile(LocInfo.first), LangOpts, - MB->getBufferStart(), MacroNameTokenPos, MB->getBufferEnd()); + MB.getBufferStart(), MacroNameTokenPos, MB.getBufferEnd()); // Acquire the macro's name. Token TheTok; Index: clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp =================================================================== --- clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -569,7 +569,7 @@ static bool isBisonFile(ASTContext &C) { const SourceManager &SM = C.getSourceManager(); FileID FID = SM.getMainFileID(); - StringRef Buffer = SM.getBuffer(FID)->getBuffer(); + StringRef Buffer = SM.getBufferOrFake(FID).getBuffer(); if (Buffer.startswith("/* A Bison parser, made by")) return true; return false; Index: clang/lib/Tooling/Inclusions/HeaderIncludes.cpp =================================================================== --- clang/lib/Tooling/Inclusions/HeaderIncludes.cpp +++ clang/lib/Tooling/Inclusions/HeaderIncludes.cpp @@ -41,7 +41,7 @@ GetOffsetAfterSequence) { SourceManagerForFile VirtualSM(FileName, Code); SourceManager &SM = VirtualSM.get(); - Lexer Lex(SM.getMainFileID(), SM.getBuffer(SM.getMainFileID()), SM, + Lexer Lex(SM.getMainFileID(), SM.getBufferOrFake(SM.getMainFileID()), SM, createLangOpts()); Token Tok; // Get the first token. Index: clang/lib/Tooling/Syntax/Tokens.cpp =================================================================== --- clang/lib/Tooling/Syntax/Tokens.cpp +++ clang/lib/Tooling/Syntax/Tokens.cpp @@ -262,7 +262,7 @@ Tokens.push_back(syntax::Token(T)); }; - Lexer L(FID, SM.getBuffer(FID), SM, LO); + Lexer L(FID, SM.getBufferOrFake(FID), SM, LO); clang::Token T; while (!L.LexFromRawLexer(T)) Index: clang/tools/clang-diff/ClangDiff.cpp =================================================================== --- clang/tools/clang-diff/ClangDiff.cpp +++ clang/tools/clang-diff/ClangDiff.cpp @@ -284,7 +284,7 @@ unsigned Begin, End; std::tie(Begin, End) = Tree.getSourceRangeOffsets(Node); const SourceManager &SrcMgr = Tree.getASTContext().getSourceManager(); - auto Code = SrcMgr.getBuffer(SrcMgr.getMainFileID())->getBuffer(); + auto Code = SrcMgr.getBufferOrFake(SrcMgr.getMainFileID()).getBuffer(); for (; Offset < Begin; ++Offset) printHtml(OS, Code[Offset]); OS << "= Buffer->getBufferStart() && - LocData < Buffer->getBufferEnd()); + assert(LocData >= Buffer.getBufferStart() && + LocData < Buffer.getBufferEnd()); const char *LineBegin = LocData - LocColumn; - assert(LineBegin >= Buffer->getBufferStart()); + assert(LineBegin >= Buffer.getBufferStart()); const char *LineEnd = nullptr; for (LineEnd = LineBegin; *LineEnd != '\n' && *LineEnd != '\r' && - LineEnd < Buffer->getBufferEnd(); + LineEnd < Buffer.getBufferEnd(); ++LineEnd) ; Index: clang/tools/libclang/CIndex.cpp =================================================================== --- clang/tools/libclang/CIndex.cpp +++ clang/tools/libclang/CIndex.cpp @@ -4252,9 +4252,8 @@ const SourceManager &SM = cxtu::getASTUnit(TU)->getSourceManager(); FileID fid = SM.translateFile(static_cast(file)); - bool Invalid = true; - const llvm::MemoryBuffer *buf = SM.getBuffer(fid, &Invalid); - if (Invalid) { + llvm::Optional buf = SM.getBuffer(fid); + if (!buf) { if (size) *size = 0; return nullptr; Index: llvm/include/llvm/Support/LineIterator.h =================================================================== --- llvm/include/llvm/Support/LineIterator.h +++ llvm/include/llvm/Support/LineIterator.h @@ -9,6 +9,7 @@ #ifndef LLVM_SUPPORT_LINEITERATOR_H #define LLVM_SUPPORT_LINEITERATOR_H +#include "llvm/ADT/Optional.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/DataTypes.h" #include @@ -16,6 +17,7 @@ namespace llvm { class MemoryBuffer; +class MemoryBufferRef; /// A forward iterator which reads text lines from a buffer. /// @@ -30,16 +32,22 @@ /// Note that this iterator requires the buffer to be nul terminated. class line_iterator : public std::iterator { - const MemoryBuffer *Buffer; + Optional Buffer; char CommentMarker; bool SkipBlanks; unsigned LineNumber; StringRef CurrentLine; + explicit line_iterator(StringRef Buffer, bool SkipBlanks, char CommentMarker); + public: /// Default construct an "end" iterator. - line_iterator() : Buffer(nullptr) {} + line_iterator() = default; + + /// Construct a new iterator around an unowned memory buffer. + explicit line_iterator(const MemoryBufferRef &Buffer, bool SkipBlanks = true, + char CommentMarker = '\0'); /// Construct a new iterator around some memory buffer. explicit line_iterator(const MemoryBuffer &Buffer, bool SkipBlanks = true, @@ -70,8 +78,14 @@ const StringRef *operator->() const { return &CurrentLine; } friend bool operator==(const line_iterator &LHS, const line_iterator &RHS) { - return LHS.Buffer == RHS.Buffer && - LHS.CurrentLine.begin() == RHS.CurrentLine.begin(); + if (LHS.Buffer && RHS.Buffer) { + // Use pointer identity to compare Buffer. + if (LHS.Buffer->begin() != RHS.Buffer->begin()) + return false; + } else if (LHS.Buffer || RHS.Buffer) { + return false; + } + return LHS.CurrentLine.begin() == RHS.CurrentLine.begin(); } friend bool operator!=(const line_iterator &LHS, const line_iterator &RHS) { Index: llvm/include/llvm/Support/MemoryBuffer.h =================================================================== --- llvm/include/llvm/Support/MemoryBuffer.h +++ llvm/include/llvm/Support/MemoryBuffer.h @@ -276,6 +276,15 @@ const char *getBufferStart() const { return Buffer.begin(); } const char *getBufferEnd() const { return Buffer.end(); } size_t getBufferSize() const { return Buffer.size(); } + + /// Check if two memory buffer refs have the same pointer identity. + friend bool operator==(const MemoryBufferRef &LHS, + const MemoryBufferRef &RHS) { + return LHS.Buffer.begin() == RHS.Buffer.begin() && + LHS.Buffer.end() == RHS.Buffer.end() && + LHS.Identifier.begin() == RHS.Identifier.begin() && + LHS.Identifier.end() == RHS.Identifier.end(); + } }; // Create wrappers for C Binding types (see CBindingWrapping.h). Index: llvm/lib/Support/LineIterator.cpp =================================================================== --- llvm/lib/Support/LineIterator.cpp +++ llvm/lib/Support/LineIterator.cpp @@ -31,27 +31,37 @@ return false; } +line_iterator::line_iterator(const MemoryBufferRef &Buffer, bool SkipBlanks, + char CommentMarker) + : line_iterator(StringRef(Buffer.getBufferStart(), Buffer.getBufferSize()), + SkipBlanks, CommentMarker) {} + line_iterator::line_iterator(const MemoryBuffer &Buffer, bool SkipBlanks, char CommentMarker) - : Buffer(Buffer.getBufferSize() ? &Buffer : nullptr), + : line_iterator(StringRef(Buffer.getBufferStart(), Buffer.getBufferSize()), + SkipBlanks, CommentMarker) {} + +line_iterator::line_iterator(StringRef Buffer, bool SkipBlanks, + char CommentMarker) + : Buffer(Buffer.empty() ? Optional(None) : Buffer), CommentMarker(CommentMarker), SkipBlanks(SkipBlanks), LineNumber(1), - CurrentLine(Buffer.getBufferSize() ? Buffer.getBufferStart() : nullptr, - 0) { + CurrentLine(Buffer.empty() ? nullptr : Buffer.begin(), 0) { // Ensure that if we are constructed on a non-empty memory buffer that it is // a null terminated buffer. - if (Buffer.getBufferSize()) { - assert(Buffer.getBufferEnd()[0] == '\0'); - // Make sure we don't skip a leading newline if we're keeping blanks - if (SkipBlanks || !isAtLineEnd(Buffer.getBufferStart())) - advance(); - } + if (Buffer.empty()) + return; + + assert(Buffer.end()[0] == '\0'); + // Make sure we don't skip a leading newline if we're keeping blanks + if (SkipBlanks || !isAtLineEnd(Buffer.begin())) + advance(); } void line_iterator::advance() { assert(Buffer && "Cannot advance past the end!"); const char *Pos = CurrentLine.end(); - assert(Pos == Buffer->getBufferStart() || isAtLineEnd(Pos) || *Pos == '\0'); + assert(Pos == Buffer->begin() || isAtLineEnd(Pos) || *Pos == '\0'); if (skipIfAtLineEnd(Pos)) ++LineNumber; @@ -78,7 +88,7 @@ if (*Pos == '\0') { // We've hit the end of the buffer, reset ourselves to the end state. - Buffer = nullptr; + Buffer = None; CurrentLine = StringRef(); return; }