+++ /dev/null
-//===--- SerializedDiagnosticReader.h - Reads diagnostics -------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_FRONTEND_SERIALIZED_DIAGNOSTIC_READER_H_
-#define LLVM_CLANG_FRONTEND_SERIALIZED_DIAGNOSTIC_READER_H_
-
-#include "clang/Basic/LLVM.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/Bitcode/BitstreamReader.h"
-#include "llvm/Support/ErrorOr.h"
-
-namespace clang {
-namespace serialized_diags {
-
-enum class SDError {
- CouldNotLoad = 1,
- InvalidSignature,
- InvalidDiagnostics,
- MalformedTopLevelBlock,
- MalformedSubBlock,
- MalformedBlockInfoBlock,
- MalformedMetadataBlock,
- MalformedDiagnosticBlock,
- MalformedDiagnosticRecord,
- MissingVersion,
- VersionMismatch,
- UnsupportedConstruct,
- /// A generic error for subclass handlers that don't want or need to define
- /// their own error_category.
- HandlerFailed
-};
-
-const std::error_category &SDErrorCategory();
-
-inline std::error_code make_error_code(SDError E) {
- return std::error_code(static_cast<int>(E), SDErrorCategory());
-}
-
-/// \brief A location that is represented in the serialized diagnostics.
-struct Location {
- unsigned FileID;
- unsigned Line;
- unsigned Col;
- unsigned Offset;
- Location(unsigned FileID, unsigned Line, unsigned Col, unsigned Offset)
- : FileID(FileID), Line(Line), Col(Col), Offset(Offset) {}
-};
-
-/// \brief A base class that handles reading serialized diagnostics from a file.
-///
-/// Subclasses should override the visit* methods with their logic for handling
-/// the various constructs that are found in serialized diagnostics.
-class SerializedDiagnosticReader {
-public:
- SerializedDiagnosticReader() {}
- virtual ~SerializedDiagnosticReader() {}
-
- /// \brief Read the diagnostics in \c File
- std::error_code readDiagnostics(StringRef File);
-
-private:
- enum class Cursor;
-
- /// \brief Read to the next record or block to process.
- llvm::ErrorOr<Cursor> skipUntilRecordOrBlock(llvm::BitstreamCursor &Stream,
- unsigned &BlockOrRecordId);
-
- /// \brief Read a metadata block from \c Stream.
- std::error_code readMetaBlock(llvm::BitstreamCursor &Stream);
-
- /// \brief Read a diagnostic block from \c Stream.
- std::error_code readDiagnosticBlock(llvm::BitstreamCursor &Stream);
-
-protected:
- /// \brief Visit the start of a diagnostic block.
- virtual std::error_code visitStartOfDiagnostic() {
- return std::error_code();
- };
- /// \brief Visit the end of a diagnostic block.
- virtual std::error_code visitEndOfDiagnostic() { return std::error_code(); };
- /// \brief Visit a category. This associates the category \c ID to a \c Name.
- virtual std::error_code visitCategoryRecord(unsigned ID, StringRef Name) {
- return std::error_code();
- };
- /// \brief Visit a flag. This associates the flag's \c ID to a \c Name.
- virtual std::error_code visitDiagFlagRecord(unsigned ID, StringRef Name) {
- return std::error_code();
- };
- /// \brief Visit a diagnostic.
- virtual std::error_code
- visitDiagnosticRecord(unsigned Severity, const Location &Location,
- unsigned Category, unsigned Flag, StringRef Message) {
- return std::error_code();
- };
- /// \brief Visit a filename. This associates the file's \c ID to a \c Name.
- virtual std::error_code visitFilenameRecord(unsigned ID, unsigned Size,
- unsigned Timestamp,
- StringRef Name) {
- return std::error_code();
- };
- /// \brief Visit a fixit hint.
- virtual std::error_code
- visitFixitRecord(const Location &Start, const Location &End, StringRef Text) {
- return std::error_code();
- };
- /// \brief Visit a source range.
- virtual std::error_code visitSourceRangeRecord(const Location &Start,
- const Location &End) {
- return std::error_code();
- };
- /// \brief Visit the version of the set of diagnostics.
- virtual std::error_code visitVersionRecord(unsigned Version) {
- return std::error_code();
- };
-};
-
-} // end serialized_diags namespace
-} // end clang namespace
-
-namespace std {
-template <>
-struct is_error_code_enum<clang::serialized_diags::SDError> : std::true_type {};
-}
-
-#endif
+++ /dev/null
-//===--- SerializedDiagnosticReader.cpp - Reads diagnostics ---------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Frontend/SerializedDiagnosticReader.h"
-#include "clang/Frontend/SerializedDiagnostics.h"
-#include "clang/Basic/FileManager.h"
-#include "llvm/Support/ManagedStatic.h"
-#include "llvm/Support/MemoryBuffer.h"
-
-using namespace clang;
-using namespace clang::serialized_diags;
-
-std::error_code SerializedDiagnosticReader::readDiagnostics(StringRef File) {
- // Open the diagnostics file.
- FileSystemOptions FO;
- FileManager FileMgr(FO);
-
- std::unique_ptr<llvm::MemoryBuffer> Buffer = FileMgr.getBufferForFile(File);
- if (!Buffer)
- return SDError::CouldNotLoad;
-
- llvm::BitstreamReader StreamFile;
- StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
- (const unsigned char *)Buffer->getBufferEnd());
-
- llvm::BitstreamCursor Stream;
- Stream.init(StreamFile);
-
- // Sniff for the signature.
- if (Stream.Read(8) != 'D' ||
- Stream.Read(8) != 'I' ||
- Stream.Read(8) != 'A' ||
- Stream.Read(8) != 'G')
- return SDError::InvalidSignature;
-
- // Read the top level blocks.
- while (!Stream.AtEndOfStream()) {
- if (Stream.ReadCode() != llvm::bitc::ENTER_SUBBLOCK)
- return SDError::InvalidDiagnostics;
-
- std::error_code EC;
- switch (Stream.ReadSubBlockID()) {
- case llvm::bitc::BLOCKINFO_BLOCK_ID:
- if (Stream.ReadBlockInfoBlock())
- return SDError::MalformedBlockInfoBlock;
- continue;
- case BLOCK_META:
- if ((EC = readMetaBlock(Stream)))
- return EC;
- continue;
- case BLOCK_DIAG:
- if ((EC = readDiagnosticBlock(Stream)))
- return EC;
- continue;
- default:
- if (!Stream.SkipBlock())
- return SDError::MalformedTopLevelBlock;
- continue;
- }
- }
- return std::error_code();
-}
-
-enum class SerializedDiagnosticReader::Cursor {
- Record = 1,
- BlockEnd,
- BlockBegin
-};
-
-llvm::ErrorOr<SerializedDiagnosticReader::Cursor>
-SerializedDiagnosticReader::skipUntilRecordOrBlock(
- llvm::BitstreamCursor &Stream, unsigned &BlockOrRecordID) {
- BlockOrRecordID = 0;
-
- while (!Stream.AtEndOfStream()) {
- unsigned Code = Stream.ReadCode();
-
- switch ((llvm::bitc::FixedAbbrevIDs)Code) {
- case llvm::bitc::ENTER_SUBBLOCK:
- BlockOrRecordID = Stream.ReadSubBlockID();
- return Cursor::BlockBegin;
-
- case llvm::bitc::END_BLOCK:
- if (Stream.ReadBlockEnd())
- return SDError::InvalidDiagnostics;
- return Cursor::BlockEnd;
-
- case llvm::bitc::DEFINE_ABBREV:
- Stream.ReadAbbrevRecord();
- continue;
-
- case llvm::bitc::UNABBREV_RECORD:
- return SDError::UnsupportedConstruct;
-
- default:
- // We found a record.
- BlockOrRecordID = Code;
- return Cursor::Record;
- }
- }
-
- return SDError::InvalidDiagnostics;
-}
-
-std::error_code
-SerializedDiagnosticReader::readMetaBlock(llvm::BitstreamCursor &Stream) {
- if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_META))
- return SDError::MalformedMetadataBlock;
-
- bool VersionChecked = false;
-
- while (true) {
- unsigned BlockOrCode = 0;
- llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode);
- if (!Res)
- Res.getError();
-
- switch (Res.get()) {
- case Cursor::Record:
- break;
- case Cursor::BlockBegin:
- if (Stream.SkipBlock())
- return SDError::MalformedMetadataBlock;
- case Cursor::BlockEnd:
- if (!VersionChecked)
- return SDError::MissingVersion;
- return std::error_code();
- }
-
- SmallVector<uint64_t, 1> Record;
- unsigned RecordID = Stream.readRecord(BlockOrCode, Record);
-
- if (RecordID == RECORD_VERSION) {
- if (Record.size() < 1)
- return SDError::MissingVersion;
- if (Record[0] > VersionNumber)
- return SDError::VersionMismatch;
- VersionChecked = true;
- }
- }
-}
-
-std::error_code
-SerializedDiagnosticReader::readDiagnosticBlock(llvm::BitstreamCursor &Stream) {
- if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_DIAG))
- return SDError::MalformedDiagnosticBlock;
-
- std::error_code EC;
- if ((EC = visitStartOfDiagnostic()))
- return EC;
-
- SmallVector<uint64_t, 16> Record;
- while (true) {
- unsigned BlockOrCode = 0;
- llvm::ErrorOr<Cursor> Res = skipUntilRecordOrBlock(Stream, BlockOrCode);
- if (!Res)
- Res.getError();
-
- switch (Res.get()) {
- case Cursor::BlockBegin:
- // The only blocks we care about are subdiagnostics.
- if (BlockOrCode == serialized_diags::BLOCK_DIAG) {
- if ((EC = readDiagnosticBlock(Stream)))
- return EC;
- } else if (!Stream.SkipBlock())
- return SDError::MalformedSubBlock;
- continue;
- case Cursor::BlockEnd:
- if ((EC = visitEndOfDiagnostic()))
- return EC;
- return std::error_code();
- case Cursor::Record:
- break;
- }
-
- // Read the record.
- Record.clear();
- StringRef Blob;
- unsigned RecID = Stream.readRecord(BlockOrCode, Record, &Blob);
-
- if (RecID < serialized_diags::RECORD_FIRST ||
- RecID > serialized_diags::RECORD_LAST)
- continue;
-
- switch ((RecordIDs)RecID) {
- case RECORD_CATEGORY:
- // A category has ID and name size.
- if (Record.size() != 2)
- return SDError::MalformedDiagnosticRecord;
- if ((EC = visitCategoryRecord(Record[0], Blob)))
- return EC;
- continue;
- case RECORD_DIAG:
- // A diagnostic has severity, location (4), category, flag, and message
- // size.
- if (Record.size() != 8)
- return SDError::MalformedDiagnosticRecord;
- if ((EC = visitDiagnosticRecord(
- Record[0], Location(Record[1], Record[2], Record[3], Record[4]),
- Record[5], Record[6], Blob)))
- return EC;
- continue;
- case RECORD_DIAG_FLAG:
- // A diagnostic flag has ID and name size.
- if (Record.size() != 2)
- return SDError::MalformedDiagnosticRecord;
- if ((EC = visitDiagFlagRecord(Record[0], Blob)))
- return EC;
- continue;
- case RECORD_FILENAME:
- // A filename has ID, size, timestamp, and name size. The size and
- // timestamp are legacy fields that are always zero these days.
- if (Record.size() != 4)
- return SDError::MalformedDiagnosticRecord;
- if ((EC = visitFilenameRecord(Record[0], Record[1], Record[2], Blob)))
- return EC;
- continue;
- case RECORD_FIXIT:
- // A fixit has two locations (4 each) and message size.
- if (Record.size() != 9)
- return SDError::MalformedDiagnosticRecord;
- if ((EC = visitFixitRecord(
- Location(Record[0], Record[1], Record[2], Record[3]),
- Location(Record[4], Record[5], Record[6], Record[7]), Blob)))
- return EC;
- continue;
- case RECORD_SOURCE_RANGE:
- // A source range is two locations (4 each).
- if (Record.size() != 8)
- return SDError::MalformedDiagnosticRecord;
- if ((EC = visitSourceRangeRecord(
- Location(Record[0], Record[1], Record[2], Record[3]),
- Location(Record[4], Record[5], Record[6], Record[7]))))
- return EC;
- continue;
- case RECORD_VERSION:
- // A version is just a number.
- if (Record.size() != 1)
- return SDError::MalformedDiagnosticRecord;
- if ((EC = visitVersionRecord(Record[0])))
- return EC;
- continue;
- }
- }
-}
-
-namespace {
-class SDErrorCategoryType final : public std::error_category {
- const char *name() const LLVM_NOEXCEPT override {
- return "clang.serialized_diags";
- }
- std::string message(int IE) const override {
- SDError E = static_cast<SDError>(IE);
- switch (E) {
- case SDError::CouldNotLoad:
- return "Failed to open diagnostics file";
- case SDError::InvalidSignature:
- return "Invalid diagnostics signature";
- case SDError::InvalidDiagnostics:
- return "Parse error reading diagnostics";
- case SDError::MalformedTopLevelBlock:
- return "Malformed block at top-level of diagnostics";
- case SDError::MalformedSubBlock:
- return "Malformed sub-block in a diagnostic";
- case SDError::MalformedBlockInfoBlock:
- return "Malformed BlockInfo block";
- case SDError::MalformedMetadataBlock:
- return "Malformed Metadata block";
- case SDError::MalformedDiagnosticBlock:
- return "Malformed Diagnostic block";
- case SDError::MalformedDiagnosticRecord:
- return "Malformed Diagnostic record";
- case SDError::MissingVersion:
- return "No version provided in diagnostics";
- case SDError::VersionMismatch:
- return "Unsupported diagnostics version";
- case SDError::UnsupportedConstruct:
- return "Bitcode constructs that are not supported in diagnostics appear";
- case SDError::HandlerFailed:
- return "Generic error occurred while handling a record";
- }
- llvm_unreachable("Unknown error type!");
- }
-};
-}
-
-static llvm::ManagedStatic<SDErrorCategoryType> ErrorCategory;
-const std::error_category &clang::serialized_diags::SDErrorCategory() {
- return *ErrorCategory;
-}
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LLVM.h"
-#include "clang/Frontend/SerializedDiagnostics.h"
-#include "clang/Frontend/SerializedDiagnosticReader.h"
+#include "clang/Frontend/SerializedDiagnosticPrinter.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
// Deserialize diagnostics.
//===----------------------------------------------------------------------===//
+enum { MaxSupportedVersion = 2 };
+typedef SmallVector<uint64_t, 64> RecordData;
+enum LoadResult { Failure = 1, Success = 0 };
+enum StreamResult { Read_EndOfStream,
+ Read_BlockBegin,
+ Read_Failure,
+ Read_Record,
+ Read_BlockEnd };
+
namespace {
-class DiagLoader : serialized_diags::SerializedDiagnosticReader {
+class DiagLoader {
enum CXLoadDiag_Error *error;
CXString *errorString;
- std::unique_ptr<CXLoadedDiagnosticSetImpl> TopDiags;
- SmallVector<std::unique_ptr<CXLoadedDiagnostic>, 8> CurrentDiags;
-
- std::error_code reportBad(enum CXLoadDiag_Error code, llvm::StringRef err) {
+
+ void reportBad(enum CXLoadDiag_Error code, llvm::StringRef err) {
if (error)
*error = code;
if (errorString)
*errorString = cxstring::createDup(err);
- return serialized_diags::SDError::HandlerFailed;
}
- std::error_code reportInvalidFile(llvm::StringRef err) {
+ void reportInvalidFile(llvm::StringRef err) {
return reportBad(CXLoadDiag_InvalidFile, err);
}
- std::error_code readRange(const serialized_diags::Location &SDStart,
- const serialized_diags::Location &SDEnd,
- CXSourceRange &SR);
-
- std::error_code readLocation(const serialized_diags::Location &SDLoc,
- CXLoadedDiagnostic::Location &LoadedLoc);
-
-protected:
- std::error_code visitStartOfDiagnostic() override;
- std::error_code visitEndOfDiagnostic() override;
-
- std::error_code visitCategoryRecord(unsigned ID, StringRef Name) override;
-
- std::error_code visitDiagFlagRecord(unsigned ID, StringRef Name) override;
-
- std::error_code visitDiagnosticRecord(
- unsigned Severity, const serialized_diags::Location &Location,
- unsigned Category, unsigned Flag, StringRef Message) override;
-
- std::error_code visitFilenameRecord(unsigned ID, unsigned Size,
- unsigned Timestamp,
- StringRef Name) override;
-
- std::error_code visitFixitRecord(const serialized_diags::Location &Start,
- const serialized_diags::Location &End,
- StringRef CodeToInsert) override;
-
- std::error_code
- visitSourceRangeRecord(const serialized_diags::Location &Start,
- const serialized_diags::Location &End) override;
-
+ LoadResult readMetaBlock(llvm::BitstreamCursor &Stream);
+
+ LoadResult readDiagnosticBlock(llvm::BitstreamCursor &Stream,
+ CXDiagnosticSetImpl &Diags,
+ CXLoadedDiagnosticSetImpl &TopDiags);
+
+ StreamResult readToNextRecordOrBlock(llvm::BitstreamCursor &Stream,
+ llvm::StringRef errorContext,
+ unsigned &BlockOrRecordID,
+ bool atTopLevel = false);
+
+
+ LoadResult readString(CXLoadedDiagnosticSetImpl &TopDiags,
+ Strings &strings, llvm::StringRef errorContext,
+ RecordData &Record,
+ StringRef Blob,
+ bool allowEmptyString = false);
+
+ LoadResult readString(CXLoadedDiagnosticSetImpl &TopDiags,
+ const char *&RetStr,
+ llvm::StringRef errorContext,
+ RecordData &Record,
+ StringRef Blob,
+ bool allowEmptyString = false);
+
+ LoadResult readRange(CXLoadedDiagnosticSetImpl &TopDiags,
+ RecordData &Record, unsigned RecStartIdx,
+ CXSourceRange &SR);
+
+ LoadResult readLocation(CXLoadedDiagnosticSetImpl &TopDiags,
+ RecordData &Record, unsigned &offset,
+ CXLoadedDiagnostic::Location &Loc);
+
public:
DiagLoader(enum CXLoadDiag_Error *e, CXString *es)
- : SerializedDiagnosticReader(), error(e), errorString(es) {
- if (error)
- *error = CXLoadDiag_None;
- if (errorString)
- *errorString = cxstring::createEmpty();
- }
+ : error(e), errorString(es) {
+ if (error)
+ *error = CXLoadDiag_None;
+ if (errorString)
+ *errorString = cxstring::createEmpty();
+ }
CXDiagnosticSet load(const char *file);
};
}
CXDiagnosticSet DiagLoader::load(const char *file) {
- TopDiags = llvm::make_unique<CXLoadedDiagnosticSetImpl>();
-
- std::error_code EC = readDiagnostics(file);
- if (EC) {
- switch (EC.value()) {
- case static_cast<int>(serialized_diags::SDError::HandlerFailed):
- // We've already reported the problem.
- break;
- case static_cast<int>(serialized_diags::SDError::CouldNotLoad):
- reportBad(CXLoadDiag_CannotLoad, EC.message());
- break;
- default:
- reportInvalidFile(EC.message());
- break;
- }
- return 0;
+ // Open the diagnostics file.
+ std::string ErrStr;
+ FileSystemOptions FO;
+ FileManager FileMgr(FO);
+
+ std::unique_ptr<llvm::MemoryBuffer> Buffer = FileMgr.getBufferForFile(file);
+ if (!Buffer) {
+ reportBad(CXLoadDiag_CannotLoad, ErrStr);
+ return nullptr;
}
- return (CXDiagnosticSet)TopDiags.release();
-}
+ llvm::BitstreamReader StreamFile;
+ StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
+ (const unsigned char *)Buffer->getBufferEnd());
+
+ llvm::BitstreamCursor Stream;
+ Stream.init(StreamFile);
+
+ // Sniff for the signature.
+ if (Stream.Read(8) != 'D' ||
+ Stream.Read(8) != 'I' ||
+ Stream.Read(8) != 'A' ||
+ Stream.Read(8) != 'G') {
+ reportBad(CXLoadDiag_InvalidFile,
+ "Bad header in diagnostics file");
+ return nullptr;
+ }
-std::error_code
-DiagLoader::readLocation(const serialized_diags::Location &SDLoc,
- CXLoadedDiagnostic::Location &LoadedLoc) {
- unsigned FileID = SDLoc.FileID;
- if (FileID == 0)
- LoadedLoc.file = nullptr;
- else {
- LoadedLoc.file = const_cast<FileEntry *>(TopDiags->Files[FileID]);
- if (!LoadedLoc.file)
- return reportInvalidFile("Corrupted file entry in source location");
+ std::unique_ptr<CXLoadedDiagnosticSetImpl> Diags(
+ new CXLoadedDiagnosticSetImpl());
+
+ while (true) {
+ unsigned BlockID = 0;
+ StreamResult Res = readToNextRecordOrBlock(Stream, "Top-level",
+ BlockID, true);
+ switch (Res) {
+ case Read_EndOfStream:
+ return (CXDiagnosticSet)Diags.release();
+ case Read_Failure:
+ return nullptr;
+ case Read_Record:
+ llvm_unreachable("Top-level does not have records");
+ case Read_BlockEnd:
+ continue;
+ case Read_BlockBegin:
+ break;
+ }
+
+ switch (BlockID) {
+ case serialized_diags::BLOCK_META:
+ if (readMetaBlock(Stream))
+ return nullptr;
+ break;
+ case serialized_diags::BLOCK_DIAG:
+ if (readDiagnosticBlock(Stream, *Diags.get(), *Diags.get()))
+ return nullptr;
+ break;
+ default:
+ if (!Stream.SkipBlock()) {
+ reportInvalidFile("Malformed block at top-level of diagnostics file");
+ return nullptr;
+ }
+ break;
+ }
}
- LoadedLoc.line = SDLoc.Line;
- LoadedLoc.column = SDLoc.Col;
- LoadedLoc.offset = SDLoc.Offset;
- return std::error_code();
}
-std::error_code
-DiagLoader::readRange(const serialized_diags::Location &SDStart,
- const serialized_diags::Location &SDEnd,
- CXSourceRange &SR) {
- CXLoadedDiagnostic::Location *Start, *End;
- Start = TopDiags->Alloc.Allocate<CXLoadedDiagnostic::Location>();
- End = TopDiags->Alloc.Allocate<CXLoadedDiagnostic::Location>();
-
- std::error_code EC;
- if ((EC = readLocation(SDStart, *Start)))
- return EC;
- if ((EC = readLocation(SDEnd, *End)))
- return EC;
+StreamResult DiagLoader::readToNextRecordOrBlock(llvm::BitstreamCursor &Stream,
+ llvm::StringRef errorContext,
+ unsigned &blockOrRecordID,
+ bool atTopLevel) {
- CXSourceLocation startLoc = makeLocation(Start);
- CXSourceLocation endLoc = makeLocation(End);
- SR = clang_getRange(startLoc, endLoc);
- return std::error_code();
+ blockOrRecordID = 0;
+
+ while (!Stream.AtEndOfStream()) {
+ unsigned Code = Stream.ReadCode();
+
+ // Handle the top-level specially.
+ if (atTopLevel) {
+ if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+ unsigned BlockID = Stream.ReadSubBlockID();
+ if (BlockID == llvm::bitc::BLOCKINFO_BLOCK_ID) {
+ if (Stream.ReadBlockInfoBlock()) {
+ reportInvalidFile("Malformed BlockInfoBlock in diagnostics file");
+ return Read_Failure;
+ }
+ continue;
+ }
+ blockOrRecordID = BlockID;
+ return Read_BlockBegin;
+ }
+ reportInvalidFile("Only blocks can appear at the top of a "
+ "diagnostic file");
+ return Read_Failure;
+ }
+
+ switch ((llvm::bitc::FixedAbbrevIDs)Code) {
+ case llvm::bitc::ENTER_SUBBLOCK:
+ blockOrRecordID = Stream.ReadSubBlockID();
+ return Read_BlockBegin;
+
+ case llvm::bitc::END_BLOCK:
+ if (Stream.ReadBlockEnd()) {
+ reportInvalidFile("Cannot read end of block");
+ return Read_Failure;
+ }
+ return Read_BlockEnd;
+
+ case llvm::bitc::DEFINE_ABBREV:
+ Stream.ReadAbbrevRecord();
+ continue;
+
+ case llvm::bitc::UNABBREV_RECORD:
+ reportInvalidFile("Diagnostics file should have no unabbreviated "
+ "records");
+ return Read_Failure;
+
+ default:
+ // We found a record.
+ blockOrRecordID = Code;
+ return Read_Record;
+ }
+ }
+
+ if (atTopLevel)
+ return Read_EndOfStream;
+
+ reportInvalidFile(Twine("Premature end of diagnostics file within ").str() +
+ errorContext.str());
+ return Read_Failure;
}
-std::error_code DiagLoader::visitStartOfDiagnostic() {
- CurrentDiags.push_back(llvm::make_unique<CXLoadedDiagnostic>());
- return std::error_code();
-}
+LoadResult DiagLoader::readMetaBlock(llvm::BitstreamCursor &Stream) {
+ if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_META)) {
+ reportInvalidFile("Malformed metadata block");
+ return Failure;
+ }
-std::error_code DiagLoader::visitEndOfDiagnostic() {
- auto D = CurrentDiags.pop_back_val();
- if (CurrentDiags.empty())
- TopDiags->appendDiagnostic(std::move(D));
- else
- CurrentDiags.back()->getChildDiagnostics().appendDiagnostic(std::move(D));
- return std::error_code();
+ bool versionChecked = false;
+
+ while (true) {
+ unsigned blockOrCode = 0;
+ StreamResult Res = readToNextRecordOrBlock(Stream, "Metadata Block",
+ blockOrCode);
+
+ switch(Res) {
+ case Read_EndOfStream:
+ llvm_unreachable("EndOfStream handled by readToNextRecordOrBlock");
+ case Read_Failure:
+ return Failure;
+ case Read_Record:
+ break;
+ case Read_BlockBegin:
+ if (Stream.SkipBlock()) {
+ reportInvalidFile("Malformed metadata block");
+ return Failure;
+ }
+ case Read_BlockEnd:
+ if (!versionChecked) {
+ reportInvalidFile("Diagnostics file does not contain version"
+ " information");
+ return Failure;
+ }
+ return Success;
+ }
+
+ RecordData Record;
+ unsigned recordID = Stream.readRecord(blockOrCode, Record);
+
+ if (recordID == serialized_diags::RECORD_VERSION) {
+ if (Record.size() < 1) {
+ reportInvalidFile("malformed VERSION identifier in diagnostics file");
+ return Failure;
+ }
+ if (Record[0] > MaxSupportedVersion) {
+ reportInvalidFile("diagnostics file is a newer version than the one "
+ "supported");
+ return Failure;
+ }
+ versionChecked = true;
+ }
+ }
}
-std::error_code DiagLoader::visitCategoryRecord(unsigned ID, StringRef Name) {
- // FIXME: Why do we care about long strings?
- if (Name.size() > 65536)
- return reportInvalidFile("Out-of-bounds string in category");
- TopDiags->Categories[ID] = TopDiags->copyString(Name);
- return std::error_code();
-}
+LoadResult DiagLoader::readString(CXLoadedDiagnosticSetImpl &TopDiags,
+ const char *&RetStr,
+ llvm::StringRef errorContext,
+ RecordData &Record,
+ StringRef Blob,
+ bool allowEmptyString) {
+
+ // Basic buffer overflow check.
+ if (Blob.size() > 65536) {
+ reportInvalidFile(std::string("Out-of-bounds string in ") +
+ std::string(errorContext));
+ return Failure;
+ }
-std::error_code DiagLoader::visitDiagFlagRecord(unsigned ID, StringRef Name) {
- // FIXME: Why do we care about long strings?
- if (Name.size() > 65536)
- return reportInvalidFile("Out-of-bounds string in warning flag");
- TopDiags->WarningFlags[ID] = TopDiags->copyString(Name);
- return std::error_code();
+ if (allowEmptyString && Record.size() >= 1 && Blob.size() == 0) {
+ RetStr = "";
+ return Success;
+ }
+
+ if (Record.size() < 1 || Blob.size() == 0) {
+ reportInvalidFile(std::string("Corrupted ") + std::string(errorContext)
+ + std::string(" entry"));
+ return Failure;
+ }
+
+ RetStr = TopDiags.copyString(Blob);
+ return Success;
}
-std::error_code DiagLoader::visitFilenameRecord(unsigned ID, unsigned Size,
- unsigned Timestamp,
- StringRef Name) {
- // FIXME: Why do we care about long strings?
- if (Name.size() > 65536)
- return reportInvalidFile("Out-of-bounds string in filename");
- TopDiags->FileNames[ID] = TopDiags->copyString(Name);
- TopDiags->Files[ID] =
- TopDiags->FakeFiles.getVirtualFile(Name, Size, Timestamp);
- return std::error_code();
+LoadResult DiagLoader::readString(CXLoadedDiagnosticSetImpl &TopDiags,
+ Strings &strings,
+ llvm::StringRef errorContext,
+ RecordData &Record,
+ StringRef Blob,
+ bool allowEmptyString) {
+ const char *RetStr;
+ if (readString(TopDiags, RetStr, errorContext, Record, Blob,
+ allowEmptyString))
+ return Failure;
+ strings[Record[0]] = RetStr;
+ return Success;
}
-std::error_code
-DiagLoader::visitSourceRangeRecord(const serialized_diags::Location &Start,
- const serialized_diags::Location &End) {
- CXSourceRange SR;
- if (std::error_code EC = readRange(Start, End, SR))
- return EC;
- CurrentDiags.back()->Ranges.push_back(SR);
- return std::error_code();
+LoadResult DiagLoader::readLocation(CXLoadedDiagnosticSetImpl &TopDiags,
+ RecordData &Record, unsigned &offset,
+ CXLoadedDiagnostic::Location &Loc) {
+ if (Record.size() < offset + 4) {
+ reportInvalidFile("Corrupted source location");
+ return Failure;
+ }
+ auto Fields = makeArrayRef(Record).slice(offset);
+ offset += 4;
+
+ unsigned fileID = Fields[0];
+ if (fileID == 0) {
+ // Sentinel value.
+ Loc.file = nullptr;
+ Loc.line = 0;
+ Loc.column = 0;
+ Loc.offset = 0;
+ return Success;
+ }
+
+ const FileEntry *FE = TopDiags.Files[fileID];
+ if (!FE) {
+ reportInvalidFile("Corrupted file entry in source location");
+ return Failure;
+ }
+ Loc.file = const_cast<FileEntry *>(FE);
+ Loc.line = Fields[1];
+ Loc.column = Fields[2];
+ Loc.offset = Fields[3];
+ return Success;
}
-std::error_code
-DiagLoader::visitFixitRecord(const serialized_diags::Location &Start,
- const serialized_diags::Location &End,
- StringRef CodeToInsert) {
- CXSourceRange SR;
- if (std::error_code EC = readRange(Start, End, SR))
- return EC;
- // FIXME: Why do we care about long strings?
- if (CodeToInsert.size() > 65536)
- return reportInvalidFile("Out-of-bounds string in FIXIT");
- CurrentDiags.back()->FixIts.push_back(
- std::make_pair(SR, TopDiags->copyString(CodeToInsert)));
- return std::error_code();
+LoadResult DiagLoader::readRange(CXLoadedDiagnosticSetImpl &TopDiags,
+ RecordData &Record,
+ unsigned int RecStartIdx,
+ CXSourceRange &SR) {
+ CXLoadedDiagnostic::Location *Start, *End;
+ Start = TopDiags.Alloc.Allocate<CXLoadedDiagnostic::Location>();
+ End = TopDiags.Alloc.Allocate<CXLoadedDiagnostic::Location>();
+
+ if (readLocation(TopDiags, Record, RecStartIdx, *Start))
+ return Failure;
+ if (readLocation(TopDiags, Record, RecStartIdx, *End))
+ return Failure;
+
+ CXSourceLocation startLoc = makeLocation(Start);
+ CXSourceLocation endLoc = makeLocation(End);
+ SR = clang_getRange(startLoc, endLoc);
+ return Success;
}
-std::error_code DiagLoader::visitDiagnosticRecord(
- unsigned Severity, const serialized_diags::Location &Location,
- unsigned Category, unsigned Flag, StringRef Message) {
- CXLoadedDiagnostic &D = *CurrentDiags.back();
- D.severity = Severity;
- if (std::error_code EC = readLocation(Location, D.DiagLoc))
- return EC;
- D.category = Category;
- D.DiagOption = Flag ? TopDiags->WarningFlags[Flag] : "";
- D.CategoryText = Category ? TopDiags->Categories[Category] : "";
- D.Spelling = TopDiags->copyString(Message);
- return std::error_code();
+LoadResult DiagLoader::readDiagnosticBlock(llvm::BitstreamCursor &Stream,
+ CXDiagnosticSetImpl &Diags,
+ CXLoadedDiagnosticSetImpl &TopDiags){
+
+ if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_DIAG)) {
+ reportInvalidFile("malformed diagnostic block");
+ return Failure;
+ }
+
+ std::unique_ptr<CXLoadedDiagnostic> D(new CXLoadedDiagnostic());
+ RecordData Record;
+
+ while (true) {
+ unsigned blockOrCode = 0;
+ StreamResult Res = readToNextRecordOrBlock(Stream, "Diagnostic Block",
+ blockOrCode);
+ switch (Res) {
+ case Read_EndOfStream:
+ llvm_unreachable("EndOfStream handled in readToNextRecordOrBlock");
+ case Read_Failure:
+ return Failure;
+ case Read_BlockBegin: {
+ // The only blocks we care about are subdiagnostics.
+ if (blockOrCode != serialized_diags::BLOCK_DIAG) {
+ if (!Stream.SkipBlock()) {
+ reportInvalidFile("Invalid subblock in Diagnostics block");
+ return Failure;
+ }
+ } else if (readDiagnosticBlock(Stream, D->getChildDiagnostics(),
+ TopDiags)) {
+ return Failure;
+ }
+
+ continue;
+ }
+ case Read_BlockEnd:
+ Diags.appendDiagnostic(std::move(D));
+ return Success;
+ case Read_Record:
+ break;
+ }
+
+ // Read the record.
+ Record.clear();
+ StringRef Blob;
+ unsigned recID = Stream.readRecord(blockOrCode, Record, &Blob);
+
+ if (recID < serialized_diags::RECORD_FIRST ||
+ recID > serialized_diags::RECORD_LAST)
+ continue;
+
+ switch ((serialized_diags::RecordIDs)recID) {
+ case serialized_diags::RECORD_VERSION:
+ continue;
+ case serialized_diags::RECORD_CATEGORY:
+ if (readString(TopDiags, TopDiags.Categories, "category", Record,
+ Blob, /* allowEmptyString */ true))
+ return Failure;
+ continue;
+
+ case serialized_diags::RECORD_DIAG_FLAG:
+ if (readString(TopDiags, TopDiags.WarningFlags, "warning flag", Record,
+ Blob))
+ return Failure;
+ continue;
+
+ case serialized_diags::RECORD_FILENAME: {
+ if (readString(TopDiags, TopDiags.FileNames, "filename", Record,
+ Blob))
+ return Failure;
+
+ if (Record.size() < 3) {
+ reportInvalidFile("Invalid file entry");
+ return Failure;
+ }
+
+ const FileEntry *FE =
+ TopDiags.FakeFiles.getVirtualFile(TopDiags.FileNames[Record[0]],
+ /* size */ Record[1],
+ /* time */ Record[2]);
+
+ TopDiags.Files[Record[0]] = FE;
+ continue;
+ }
+
+ case serialized_diags::RECORD_SOURCE_RANGE: {
+ CXSourceRange SR;
+ if (readRange(TopDiags, Record, 0, SR))
+ return Failure;
+ D->Ranges.push_back(SR);
+ continue;
+ }
+
+ case serialized_diags::RECORD_FIXIT: {
+ CXSourceRange SR;
+ if (readRange(TopDiags, Record, 0, SR))
+ return Failure;
+ const char *RetStr;
+ if (readString(TopDiags, RetStr, "FIXIT", Record, Blob,
+ /* allowEmptyString */ true))
+ return Failure;
+ D->FixIts.push_back(std::make_pair(SR, RetStr));
+ continue;
+ }
+
+ case serialized_diags::RECORD_DIAG: {
+ D->severity = Record[0];
+ unsigned offset = 1;
+ if (readLocation(TopDiags, Record, offset, D->DiagLoc))
+ return Failure;
+ D->category = Record[offset++];
+ unsigned diagFlag = Record[offset++];
+ D->DiagOption = diagFlag ? TopDiags.WarningFlags[diagFlag] : "";
+ D->CategoryText = D->category ? TopDiags.Categories[D->category] : "";
+ D->Spelling = TopDiags.copyString(Blob);
+ continue;
+ }
+ }
+ }
}
extern "C" {