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