r219647 - Frontend: Extract SerializedDiagnosticReader out of CXLoadedDiagnostic (NFC)
Justin Bogner
mail at justinbogner.com
Mon Oct 13 17:40:56 PDT 2014
Author: bogner
Date: Mon Oct 13 19:40:55 2014
New Revision: 219647
URL: http://llvm.org/viewvc/llvm-project?rev=219647&view=rev
Log:
Frontend: Extract SerializedDiagnosticReader out of CXLoadedDiagnostic (NFC)
We currently read serialized diagnostics directly in the C API, which
makes it difficult to reuse this logic elsewhere. This extracts the
core of the serialized diagnostic parsing logic into a base class that
can be subclassed using a visitor pattern.
Added:
cfe/trunk/include/clang/Frontend/SerializedDiagnosticReader.h
cfe/trunk/include/clang/Frontend/SerializedDiagnostics.h
- copied, changed from r219642, cfe/trunk/include/clang/Frontend/SerializedDiagnosticPrinter.h
cfe/trunk/lib/Frontend/SerializedDiagnosticReader.cpp
Modified:
cfe/trunk/include/clang/Frontend/SerializedDiagnosticPrinter.h
cfe/trunk/lib/Frontend/CMakeLists.txt
cfe/trunk/lib/Frontend/SerializedDiagnosticPrinter.cpp
cfe/trunk/tools/libclang/CXLoadedDiagnostic.cpp
Modified: cfe/trunk/include/clang/Frontend/SerializedDiagnosticPrinter.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/SerializedDiagnosticPrinter.h?rev=219647&r1=219646&r2=219647&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/SerializedDiagnosticPrinter.h (original)
+++ cfe/trunk/include/clang/Frontend/SerializedDiagnosticPrinter.h Mon Oct 13 19:40:55 2014
@@ -11,6 +11,7 @@
#define LLVM_CLANG_FRONTEND_SERIALIZEDDIAGNOSTICPRINTER_H
#include "clang/Basic/LLVM.h"
+#include "clang/Frontend/SerializedDiagnostics.h"
#include "llvm/Bitcode/BitstreamWriter.h"
namespace llvm {
@@ -23,41 +24,6 @@ class DiagnosticsEngine;
class DiagnosticOptions;
namespace serialized_diags {
-
-enum BlockIDs {
- /// \brief A top-level block which represents any meta data associated
- /// with the diagostics, including versioning of the format.
- BLOCK_META = llvm::bitc::FIRST_APPLICATION_BLOCKID,
-
- /// \brief The this block acts as a container for all the information
- /// for a specific diagnostic.
- BLOCK_DIAG
-};
-
-enum RecordIDs {
- RECORD_VERSION = 1,
- RECORD_DIAG,
- RECORD_SOURCE_RANGE,
- RECORD_DIAG_FLAG,
- RECORD_CATEGORY,
- RECORD_FILENAME,
- RECORD_FIXIT,
- RECORD_FIRST = RECORD_VERSION,
- RECORD_LAST = RECORD_FIXIT
-};
-
-/// A stable version of DiagnosticIDs::Level.
-///
-/// Do not change the order of values in this enum, and please increment the
-/// serialized diagnostics version number when you add to it.
-enum Level {
- Ignored = 0,
- Note,
- Warning,
- Error,
- Fatal,
- Remark
-};
/// \brief Returns a DiagnosticConsumer that serializes diagnostics to
/// a bitcode file.
Added: cfe/trunk/include/clang/Frontend/SerializedDiagnosticReader.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/SerializedDiagnosticReader.h?rev=219647&view=auto
==============================================================================
--- cfe/trunk/include/clang/Frontend/SerializedDiagnosticReader.h (added)
+++ cfe/trunk/include/clang/Frontend/SerializedDiagnosticReader.h Mon Oct 13 19:40:55 2014
@@ -0,0 +1,131 @@
+//===--- 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
Copied: cfe/trunk/include/clang/Frontend/SerializedDiagnostics.h (from r219642, cfe/trunk/include/clang/Frontend/SerializedDiagnosticPrinter.h)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/SerializedDiagnostics.h?p2=cfe/trunk/include/clang/Frontend/SerializedDiagnostics.h&p1=cfe/trunk/include/clang/Frontend/SerializedDiagnosticPrinter.h&r1=219642&r2=219647&rev=219647&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/SerializedDiagnosticPrinter.h (original)
+++ cfe/trunk/include/clang/Frontend/SerializedDiagnostics.h Mon Oct 13 19:40:55 2014
@@ -1,4 +1,4 @@
-//===--- SerializedDiagnosticPrinter.h - Serializer for diagnostics -------===//
+//===--- SerializedDiagnostics.h - Common data for serialized diagnostics -===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,23 +7,14 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_FRONTEND_SERIALIZEDDIAGNOSTICPRINTER_H
-#define LLVM_CLANG_FRONTEND_SERIALIZEDDIAGNOSTICPRINTER_H
+#ifndef LLVM_CLANG_FRONTEND_SERIALIZE_DIAGNOSTICS_H_
+#define LLVM_CLANG_FRONTEND_SERIALIZE_DIAGNOSTICS_H_
-#include "clang/Basic/LLVM.h"
-#include "llvm/Bitcode/BitstreamWriter.h"
-
-namespace llvm {
-class raw_ostream;
-}
+#include "llvm/BitCode/BitCodes.h"
namespace clang {
-class DiagnosticConsumer;
-class DiagnosticsEngine;
-class DiagnosticOptions;
-
namespace serialized_diags {
-
+
enum BlockIDs {
/// \brief A top-level block which represents any meta data associated
/// with the diagostics, including versioning of the format.
@@ -46,7 +37,7 @@ enum RecordIDs {
RECORD_LAST = RECORD_FIXIT
};
-/// A stable version of DiagnosticIDs::Level.
+/// \brief A stable version of DiagnosticIDs::Level.
///
/// Do not change the order of values in this enum, and please increment the
/// serialized diagnostics version number when you add to it.
@@ -59,16 +50,8 @@ enum Level {
Remark
};
-/// \brief Returns a DiagnosticConsumer that serializes diagnostics to
-/// a bitcode file.
-///
-/// The created DiagnosticConsumer is designed for quick and lightweight
-/// transfer of of diagnostics to the enclosing build system (e.g., an IDE).
-/// This allows wrapper tools for Clang to get diagnostics from Clang
-/// (via libclang) without needing to parse Clang's command line output.
-///
-std::unique_ptr<DiagnosticConsumer> create(std::unique_ptr<raw_ostream> OS,
- DiagnosticOptions *diags);
+/// \brief The serialized diagnostics version number.
+enum { VersionNumber = 2 };
} // end serialized_diags namespace
} // end clang namespace
Modified: cfe/trunk/lib/Frontend/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CMakeLists.txt?rev=219647&r1=219646&r2=219647&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CMakeLists.txt (original)
+++ cfe/trunk/lib/Frontend/CMakeLists.txt Mon Oct 13 19:40:55 2014
@@ -31,6 +31,7 @@ add_clang_library(clangFrontend
MultiplexConsumer.cpp
PrintPreprocessedOutput.cpp
SerializedDiagnosticPrinter.cpp
+ SerializedDiagnosticReader.cpp
TextDiagnostic.cpp
TextDiagnosticBuffer.cpp
TextDiagnosticPrinter.cpp
Modified: cfe/trunk/lib/Frontend/SerializedDiagnosticPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/SerializedDiagnosticPrinter.cpp?rev=219647&r1=219646&r2=219647&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/SerializedDiagnosticPrinter.cpp (original)
+++ cfe/trunk/lib/Frontend/SerializedDiagnosticPrinter.cpp Mon Oct 13 19:40:55 2014
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/SerializedDiagnosticPrinter.h"
+#include "clang/Frontend/SerializedDiagnostics.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
@@ -172,9 +173,6 @@ private:
void AddCharSourceRangeToRecord(CharSourceRange R, RecordDataImpl &Record,
const SourceManager &SM);
- /// \brief The version of the diagnostics file.
- enum { Version = 2 };
-
/// \brief Language options, which can differ from one clone of this client
/// to another.
const LangOptions *LangOpts;
@@ -466,7 +464,7 @@ void SDiagsWriter::EmitMetaBlock() {
Stream.EnterSubblock(BLOCK_META, 3);
Record.clear();
Record.push_back(RECORD_VERSION);
- Record.push_back(Version);
+ Record.push_back(VersionNumber);
Stream.EmitRecordWithAbbrev(Abbrevs.get(RECORD_VERSION), Record);
Stream.ExitBlock();
}
Added: cfe/trunk/lib/Frontend/SerializedDiagnosticReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/SerializedDiagnosticReader.cpp?rev=219647&view=auto
==============================================================================
--- cfe/trunk/lib/Frontend/SerializedDiagnosticReader.cpp (added)
+++ cfe/trunk/lib/Frontend/SerializedDiagnosticReader.cpp Mon Oct 13 19:40:55 2014
@@ -0,0 +1,296 @@
+//===--- 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;
+}
Modified: cfe/trunk/tools/libclang/CXLoadedDiagnostic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CXLoadedDiagnostic.cpp?rev=219647&r1=219646&r2=219647&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CXLoadedDiagnostic.cpp (original)
+++ cfe/trunk/tools/libclang/CXLoadedDiagnostic.cpp Mon Oct 13 19:40:55 2014
@@ -16,7 +16,8 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LLVM.h"
-#include "clang/Frontend/SerializedDiagnosticPrinter.h"
+#include "clang/Frontend/SerializedDiagnostics.h"
+#include "clang/Frontend/SerializedDiagnosticReader.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
@@ -183,475 +184,207 @@ void CXLoadedDiagnostic::decodeLocation(
// 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 {
+class DiagLoader : serialized_diags::SerializedDiagnosticReader {
enum CXLoadDiag_Error *error;
CXString *errorString;
-
- void reportBad(enum CXLoadDiag_Error code, llvm::StringRef err) {
+ std::unique_ptr<CXLoadedDiagnosticSetImpl> TopDiags;
+ SmallVector<std::unique_ptr<CXLoadedDiagnostic>, 8> CurrentDiags;
+
+ std::error_code reportBad(enum CXLoadDiag_Error code, llvm::StringRef err) {
if (error)
*error = code;
if (errorString)
*errorString = cxstring::createDup(err);
+ return serialized_diags::SDError::HandlerFailed;
}
- void reportInvalidFile(llvm::StringRef err) {
+ std::error_code reportInvalidFile(llvm::StringRef err) {
return reportBad(CXLoadDiag_InvalidFile, err);
}
- 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)
- : error(e), errorString(es) {
- if (error)
- *error = CXLoadDiag_None;
- if (errorString)
- *errorString = cxstring::createEmpty();
- }
+ std::error_code readRange(const serialized_diags::Location &SDStart,
+ const serialized_diags::Location &SDEnd,
+ CXSourceRange &SR);
- CXDiagnosticSet load(const char *file);
-};
-}
+ std::error_code readLocation(const serialized_diags::Location &SDLoc,
+ CXLoadedDiagnostic::Location &LoadedLoc);
-CXDiagnosticSet DiagLoader::load(const char *file) {
- // Open the diagnostics file.
- std::string ErrStr;
- FileSystemOptions FO;
- FileManager FileMgr(FO);
+protected:
+ std::error_code visitStartOfDiagnostic() override;
+ std::error_code visitEndOfDiagnostic() override;
- std::unique_ptr<llvm::MemoryBuffer> Buffer = FileMgr.getBufferForFile(file);
- if (!Buffer) {
- reportBad(CXLoadDiag_CannotLoad, ErrStr);
- return nullptr;
- }
+ std::error_code visitCategoryRecord(unsigned ID, StringRef Name) override;
- 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 visitDiagFlagRecord(unsigned ID, StringRef Name) override;
- std::unique_ptr<CXLoadedDiagnosticSetImpl> Diags(
- new CXLoadedDiagnosticSetImpl());
+ std::error_code visitDiagnosticRecord(
+ unsigned Severity, const serialized_diags::Location &Location,
+ unsigned Category, unsigned Flag, StringRef Message) override;
- 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;
- }
- }
-}
+ std::error_code visitFilenameRecord(unsigned ID, unsigned Size,
+ unsigned Timestamp,
+ StringRef Name) override;
-StreamResult DiagLoader::readToNextRecordOrBlock(llvm::BitstreamCursor &Stream,
- llvm::StringRef errorContext,
- unsigned &blockOrRecordID,
- bool atTopLevel) {
-
- blockOrRecordID = 0;
+ std::error_code visitFixitRecord(const serialized_diags::Location &Start,
+ const serialized_diags::Location &End,
+ StringRef CodeToInsert) override;
- while (!Stream.AtEndOfStream()) {
- unsigned Code = Stream.ReadCode();
+ std::error_code
+ visitSourceRangeRecord(const serialized_diags::Location &Start,
+ const serialized_diags::Location &End) override;
- // 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;
- }
+public:
+ DiagLoader(enum CXLoadDiag_Error *e, CXString *es)
+ : SerializedDiagnosticReader(), error(e), errorString(es) {
+ if (error)
+ *error = CXLoadDiag_None;
+ if (errorString)
+ *errorString = cxstring::createEmpty();
}
-
- if (atTopLevel)
- return Read_EndOfStream;
-
- reportInvalidFile(Twine("Premature end of diagnostics file within ").str() +
- errorContext.str());
- return Read_Failure;
+
+ CXDiagnosticSet load(const char *file);
+};
}
-LoadResult DiagLoader::readMetaBlock(llvm::BitstreamCursor &Stream) {
- if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_META)) {
- reportInvalidFile("Malformed metadata block");
- return Failure;
- }
+CXDiagnosticSet DiagLoader::load(const char *file) {
+ TopDiags = llvm::make_unique<CXLoadedDiagnosticSetImpl>();
- 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 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;
}
- }
-}
-
-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;
+ return 0;
}
- 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;
+ return (CXDiagnosticSet)TopDiags.release();
}
-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;
-}
-
-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;
+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");
}
-
- 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;
+ LoadedLoc.line = SDLoc.Line;
+ LoadedLoc.column = SDLoc.Col;
+ LoadedLoc.offset = SDLoc.Offset;
+ return std::error_code();
}
-LoadResult DiagLoader::readRange(CXLoadedDiagnosticSetImpl &TopDiags,
- RecordData &Record,
- unsigned int RecStartIdx,
- CXSourceRange &SR) {
+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>();
-
- if (readLocation(TopDiags, Record, RecStartIdx, *Start))
- return Failure;
- if (readLocation(TopDiags, Record, RecStartIdx, *End))
- return Failure;
+ 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;
CXSourceLocation startLoc = makeLocation(Start);
CXSourceLocation endLoc = makeLocation(End);
SR = clang_getRange(startLoc, endLoc);
- return Success;
+ 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;
- }
- }
- }
+std::error_code DiagLoader::visitStartOfDiagnostic() {
+ CurrentDiags.push_back(llvm::make_unique<CXLoadedDiagnostic>());
+ return std::error_code();
+}
+
+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();
+}
+
+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();
+}
+
+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();
+}
+
+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();
+}
+
+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();
+}
+
+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();
+}
+
+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();
}
extern "C" {
More information about the cfe-commits
mailing list