Home | History | Annotate | Download | only in Frontend
      1 //===--- SerializedDiagnosticPrinter.cpp - Serializer for diagnostics -----===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include <vector>
     11 #include "llvm/Support/raw_ostream.h"
     12 #include "llvm/ADT/StringRef.h"
     13 #include "llvm/ADT/SmallString.h"
     14 #include "llvm/ADT/DenseSet.h"
     15 #include "clang/Basic/SourceManager.h"
     16 #include "clang/Basic/FileManager.h"
     17 #include "clang/Basic/Diagnostic.h"
     18 #include "clang/Basic/Version.h"
     19 #include "clang/Lex/Lexer.h"
     20 #include "clang/Frontend/SerializedDiagnosticPrinter.h"
     21 #include "clang/Frontend/DiagnosticRenderer.h"
     22 
     23 using namespace clang;
     24 using namespace clang::serialized_diags;
     25 
     26 namespace {
     27 
     28 class AbbreviationMap {
     29   llvm::DenseMap<unsigned, unsigned> Abbrevs;
     30 public:
     31   AbbreviationMap() {}
     32 
     33   void set(unsigned recordID, unsigned abbrevID) {
     34     assert(Abbrevs.find(recordID) == Abbrevs.end()
     35            && "Abbreviation already set.");
     36     Abbrevs[recordID] = abbrevID;
     37   }
     38 
     39   unsigned get(unsigned recordID) {
     40     assert(Abbrevs.find(recordID) != Abbrevs.end() &&
     41            "Abbreviation not set.");
     42     return Abbrevs[recordID];
     43   }
     44 };
     45 
     46 typedef llvm::SmallVector<uint64_t, 64> RecordData;
     47 typedef llvm::SmallVectorImpl<uint64_t> RecordDataImpl;
     48 
     49 class SDiagsWriter;
     50 
     51 class SDiagsRenderer : public DiagnosticNoteRenderer {
     52   SDiagsWriter &Writer;
     53   RecordData &Record;
     54 public:
     55   SDiagsRenderer(SDiagsWriter &Writer, RecordData &Record,
     56                  const SourceManager &SM,
     57                  const LangOptions &LangOpts,
     58                  const DiagnosticOptions &DiagOpts)
     59     : DiagnosticNoteRenderer(SM, LangOpts, DiagOpts),
     60       Writer(Writer), Record(Record){}
     61 
     62   virtual ~SDiagsRenderer() {}
     63 
     64 protected:
     65   virtual void emitDiagnosticMessage(SourceLocation Loc,
     66                                      PresumedLoc PLoc,
     67                                      DiagnosticsEngine::Level Level,
     68                                      StringRef Message,
     69                                      ArrayRef<CharSourceRange> Ranges,
     70                                      DiagOrStoredDiag D);
     71 
     72   virtual void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
     73                                  DiagnosticsEngine::Level Level,
     74                                  ArrayRef<CharSourceRange> Ranges) {}
     75 
     76   void emitNote(SourceLocation Loc, StringRef Message);
     77 
     78   virtual void emitCodeContext(SourceLocation Loc,
     79                                DiagnosticsEngine::Level Level,
     80                                SmallVectorImpl<CharSourceRange>& Ranges,
     81                                ArrayRef<FixItHint> Hints);
     82 
     83   virtual void beginDiagnostic(DiagOrStoredDiag D,
     84                                DiagnosticsEngine::Level Level);
     85   virtual void endDiagnostic(DiagOrStoredDiag D,
     86                              DiagnosticsEngine::Level Level);
     87 };
     88 
     89 class SDiagsWriter : public DiagnosticConsumer {
     90   friend class SDiagsRenderer;
     91 public:
     92   explicit SDiagsWriter(llvm::raw_ostream *os, const DiagnosticOptions &diags)
     93     : LangOpts(0), DiagOpts(diags),
     94       Stream(Buffer), OS(os), inNonNoteDiagnostic(false)
     95   {
     96     EmitPreamble();
     97   }
     98 
     99   ~SDiagsWriter() {}
    100 
    101   void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
    102                         const Diagnostic &Info);
    103 
    104   void BeginSourceFile(const LangOptions &LO,
    105                        const Preprocessor *PP) {
    106     LangOpts = &LO;
    107   }
    108 
    109   virtual void finish();
    110 
    111   DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const {
    112     // It makes no sense to clone this.
    113     return 0;
    114   }
    115 
    116 private:
    117   /// \brief Emit the preamble for the serialized diagnostics.
    118   void EmitPreamble();
    119 
    120   /// \brief Emit the BLOCKINFO block.
    121   void EmitBlockInfoBlock();
    122 
    123   /// \brief Emit the META data block.
    124   void EmitMetaBlock();
    125 
    126   /// \brief Emit a record for a CharSourceRange.
    127   void EmitCharSourceRange(CharSourceRange R, const SourceManager &SM);
    128 
    129   /// \brief Emit the string information for the category.
    130   unsigned getEmitCategory(unsigned category = 0);
    131 
    132   /// \brief Emit the string information for diagnostic flags.
    133   unsigned getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
    134                                  unsigned DiagID = 0);
    135 
    136   /// \brief Emit (lazily) the file string and retrieved the file identifier.
    137   unsigned getEmitFile(const char *Filename);
    138 
    139   /// \brief Add SourceLocation information the specified record.
    140   void AddLocToRecord(SourceLocation Loc, const SourceManager &SM,
    141                       PresumedLoc PLoc, RecordDataImpl &Record,
    142                       unsigned TokSize = 0);
    143 
    144   /// \brief Add SourceLocation information the specified record.
    145   void AddLocToRecord(SourceLocation Loc, RecordDataImpl &Record,
    146                       const SourceManager &SM,
    147                       unsigned TokSize = 0) {
    148     AddLocToRecord(Loc, SM, SM.getPresumedLoc(Loc), Record, TokSize);
    149   }
    150 
    151   /// \brief Add CharSourceRange information the specified record.
    152   void AddCharSourceRangeToRecord(CharSourceRange R, RecordDataImpl &Record,
    153                                   const SourceManager &SM);
    154 
    155   /// \brief The version of the diagnostics file.
    156   enum { Version = 1 };
    157 
    158   const LangOptions *LangOpts;
    159   const DiagnosticOptions &DiagOpts;
    160 
    161   /// \brief The byte buffer for the serialized content.
    162   SmallString<1024> Buffer;
    163 
    164   /// \brief The BitStreamWriter for the serialized diagnostics.
    165   llvm::BitstreamWriter Stream;
    166 
    167   /// \brief The name of the diagnostics file.
    168   OwningPtr<llvm::raw_ostream> OS;
    169 
    170   /// \brief The set of constructed record abbreviations.
    171   AbbreviationMap Abbrevs;
    172 
    173   /// \brief A utility buffer for constructing record content.
    174   RecordData Record;
    175 
    176   /// \brief A text buffer for rendering diagnostic text.
    177   SmallString<256> diagBuf;
    178 
    179   /// \brief The collection of diagnostic categories used.
    180   llvm::DenseSet<unsigned> Categories;
    181 
    182   /// \brief The collection of files used.
    183   llvm::DenseMap<const char *, unsigned> Files;
    184 
    185   typedef llvm::DenseMap<const void *, std::pair<unsigned, llvm::StringRef> >
    186           DiagFlagsTy;
    187 
    188   /// \brief Map for uniquing strings.
    189   DiagFlagsTy DiagFlags;
    190 
    191   /// \brief Flag indicating whether or not we are in the process of
    192   /// emitting a non-note diagnostic.
    193   bool inNonNoteDiagnostic;
    194 };
    195 } // end anonymous namespace
    196 
    197 namespace clang {
    198 namespace serialized_diags {
    199 DiagnosticConsumer *create(llvm::raw_ostream *OS,
    200                            const DiagnosticOptions &diags) {
    201   return new SDiagsWriter(OS, diags);
    202 }
    203 } // end namespace serialized_diags
    204 } // end namespace clang
    205 
    206 //===----------------------------------------------------------------------===//
    207 // Serialization methods.
    208 //===----------------------------------------------------------------------===//
    209 
    210 /// \brief Emits a block ID in the BLOCKINFO block.
    211 static void EmitBlockID(unsigned ID, const char *Name,
    212                         llvm::BitstreamWriter &Stream,
    213                         RecordDataImpl &Record) {
    214   Record.clear();
    215   Record.push_back(ID);
    216   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
    217 
    218   // Emit the block name if present.
    219   if (Name == 0 || Name[0] == 0)
    220     return;
    221 
    222   Record.clear();
    223 
    224   while (*Name)
    225     Record.push_back(*Name++);
    226 
    227   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record);
    228 }
    229 
    230 /// \brief Emits a record ID in the BLOCKINFO block.
    231 static void EmitRecordID(unsigned ID, const char *Name,
    232                          llvm::BitstreamWriter &Stream,
    233                          RecordDataImpl &Record){
    234   Record.clear();
    235   Record.push_back(ID);
    236 
    237   while (*Name)
    238     Record.push_back(*Name++);
    239 
    240   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
    241 }
    242 
    243 void SDiagsWriter::AddLocToRecord(SourceLocation Loc,
    244                                   const SourceManager &SM,
    245                                   PresumedLoc PLoc,
    246                                   RecordDataImpl &Record,
    247                                   unsigned TokSize) {
    248   if (PLoc.isInvalid()) {
    249     // Emit a "sentinel" location.
    250     Record.push_back((unsigned)0); // File.
    251     Record.push_back((unsigned)0); // Line.
    252     Record.push_back((unsigned)0); // Column.
    253     Record.push_back((unsigned)0); // Offset.
    254     return;
    255   }
    256 
    257   Record.push_back(getEmitFile(PLoc.getFilename()));
    258   Record.push_back(PLoc.getLine());
    259   Record.push_back(PLoc.getColumn()+TokSize);
    260   Record.push_back(SM.getFileOffset(Loc));
    261 }
    262 
    263 void SDiagsWriter::AddCharSourceRangeToRecord(CharSourceRange Range,
    264                                               RecordDataImpl &Record,
    265                                               const SourceManager &SM) {
    266   AddLocToRecord(Range.getBegin(), Record, SM);
    267   unsigned TokSize = 0;
    268   if (Range.isTokenRange())
    269     TokSize = Lexer::MeasureTokenLength(Range.getEnd(),
    270                                         SM, *LangOpts);
    271 
    272   AddLocToRecord(Range.getEnd(), Record, SM, TokSize);
    273 }
    274 
    275 unsigned SDiagsWriter::getEmitFile(const char *FileName){
    276   if (!FileName)
    277     return 0;
    278 
    279   unsigned &entry = Files[FileName];
    280   if (entry)
    281     return entry;
    282 
    283   // Lazily generate the record for the file.
    284   entry = Files.size();
    285   RecordData Record;
    286   Record.push_back(RECORD_FILENAME);
    287   Record.push_back(entry);
    288   Record.push_back(0); // For legacy.
    289   Record.push_back(0); // For legacy.
    290   StringRef Name(FileName);
    291   Record.push_back(Name.size());
    292   Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_FILENAME), Record, Name);
    293 
    294   return entry;
    295 }
    296 
    297 void SDiagsWriter::EmitCharSourceRange(CharSourceRange R,
    298                                        const SourceManager &SM) {
    299   Record.clear();
    300   Record.push_back(RECORD_SOURCE_RANGE);
    301   AddCharSourceRangeToRecord(R, Record, SM);
    302   Stream.EmitRecordWithAbbrev(Abbrevs.get(RECORD_SOURCE_RANGE), Record);
    303 }
    304 
    305 /// \brief Emits the preamble of the diagnostics file.
    306 void SDiagsWriter::EmitPreamble() {
    307   // Emit the file header.
    308   Stream.Emit((unsigned)'D', 8);
    309   Stream.Emit((unsigned)'I', 8);
    310   Stream.Emit((unsigned)'A', 8);
    311   Stream.Emit((unsigned)'G', 8);
    312 
    313   EmitBlockInfoBlock();
    314   EmitMetaBlock();
    315 }
    316 
    317 static void AddSourceLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) {
    318   using namespace llvm;
    319   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // File ID.
    320   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Line.
    321   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Column.
    322   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Offset;
    323 }
    324 
    325 static void AddRangeLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) {
    326   AddSourceLocationAbbrev(Abbrev);
    327   AddSourceLocationAbbrev(Abbrev);
    328 }
    329 
    330 void SDiagsWriter::EmitBlockInfoBlock() {
    331   Stream.EnterBlockInfoBlock(3);
    332 
    333   using namespace llvm;
    334 
    335   // ==---------------------------------------------------------------------==//
    336   // The subsequent records and Abbrevs are for the "Meta" block.
    337   // ==---------------------------------------------------------------------==//
    338 
    339   EmitBlockID(BLOCK_META, "Meta", Stream, Record);
    340   EmitRecordID(RECORD_VERSION, "Version", Stream, Record);
    341   BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
    342   Abbrev->Add(BitCodeAbbrevOp(RECORD_VERSION));
    343   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
    344   Abbrevs.set(RECORD_VERSION, Stream.EmitBlockInfoAbbrev(BLOCK_META, Abbrev));
    345 
    346   // ==---------------------------------------------------------------------==//
    347   // The subsequent records and Abbrevs are for the "Diagnostic" block.
    348   // ==---------------------------------------------------------------------==//
    349 
    350   EmitBlockID(BLOCK_DIAG, "Diag", Stream, Record);
    351   EmitRecordID(RECORD_DIAG, "DiagInfo", Stream, Record);
    352   EmitRecordID(RECORD_SOURCE_RANGE, "SrcRange", Stream, Record);
    353   EmitRecordID(RECORD_CATEGORY, "CatName", Stream, Record);
    354   EmitRecordID(RECORD_DIAG_FLAG, "DiagFlag", Stream, Record);
    355   EmitRecordID(RECORD_FILENAME, "FileName", Stream, Record);
    356   EmitRecordID(RECORD_FIXIT, "FixIt", Stream, Record);
    357 
    358   // Emit abbreviation for RECORD_DIAG.
    359   Abbrev = new BitCodeAbbrev();
    360   Abbrev->Add(BitCodeAbbrevOp(RECORD_DIAG));
    361   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3));  // Diag level.
    362   AddSourceLocationAbbrev(Abbrev);
    363   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Category.
    364   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped Diag ID.
    365   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
    366   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Diagnostc text.
    367   Abbrevs.set(RECORD_DIAG, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
    368 
    369   // Emit abbrevation for RECORD_CATEGORY.
    370   Abbrev = new BitCodeAbbrev();
    371   Abbrev->Add(BitCodeAbbrevOp(RECORD_CATEGORY));
    372   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Category ID.
    373   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8));  // Text size.
    374   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));      // Category text.
    375   Abbrevs.set(RECORD_CATEGORY, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
    376 
    377   // Emit abbrevation for RECORD_SOURCE_RANGE.
    378   Abbrev = new BitCodeAbbrev();
    379   Abbrev->Add(BitCodeAbbrevOp(RECORD_SOURCE_RANGE));
    380   AddRangeLocationAbbrev(Abbrev);
    381   Abbrevs.set(RECORD_SOURCE_RANGE,
    382               Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
    383 
    384   // Emit the abbreviation for RECORD_DIAG_FLAG.
    385   Abbrev = new BitCodeAbbrev();
    386   Abbrev->Add(BitCodeAbbrevOp(RECORD_DIAG_FLAG));
    387   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped Diag ID.
    388   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
    389   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Flag name text.
    390   Abbrevs.set(RECORD_DIAG_FLAG, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
    391                                                            Abbrev));
    392 
    393   // Emit the abbreviation for RECORD_FILENAME.
    394   Abbrev = new BitCodeAbbrev();
    395   Abbrev->Add(BitCodeAbbrevOp(RECORD_FILENAME));
    396   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped file ID.
    397   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Size.
    398   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Modifcation time.
    399   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
    400   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name text.
    401   Abbrevs.set(RECORD_FILENAME, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
    402                                                           Abbrev));
    403 
    404   // Emit the abbreviation for RECORD_FIXIT.
    405   Abbrev = new BitCodeAbbrev();
    406   Abbrev->Add(BitCodeAbbrevOp(RECORD_FIXIT));
    407   AddRangeLocationAbbrev(Abbrev);
    408   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
    409   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));      // FixIt text.
    410   Abbrevs.set(RECORD_FIXIT, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
    411                                                        Abbrev));
    412 
    413   Stream.ExitBlock();
    414 }
    415 
    416 void SDiagsWriter::EmitMetaBlock() {
    417   Stream.EnterSubblock(BLOCK_META, 3);
    418   Record.clear();
    419   Record.push_back(RECORD_VERSION);
    420   Record.push_back(Version);
    421   Stream.EmitRecordWithAbbrev(Abbrevs.get(RECORD_VERSION), Record);
    422   Stream.ExitBlock();
    423 }
    424 
    425 unsigned SDiagsWriter::getEmitCategory(unsigned int category) {
    426   if (Categories.count(category))
    427     return category;
    428 
    429   Categories.insert(category);
    430 
    431   // We use a local version of 'Record' so that we can be generating
    432   // another record when we lazily generate one for the category entry.
    433   RecordData Record;
    434   Record.push_back(RECORD_CATEGORY);
    435   Record.push_back(category);
    436   StringRef catName = DiagnosticIDs::getCategoryNameFromID(category);
    437   Record.push_back(catName.size());
    438   Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_CATEGORY), Record, catName);
    439 
    440   return category;
    441 }
    442 
    443 unsigned SDiagsWriter::getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
    444                                              unsigned DiagID) {
    445   if (DiagLevel == DiagnosticsEngine::Note)
    446     return 0; // No flag for notes.
    447 
    448   StringRef FlagName = DiagnosticIDs::getWarningOptionForDiag(DiagID);
    449   if (FlagName.empty())
    450     return 0;
    451 
    452   // Here we assume that FlagName points to static data whose pointer
    453   // value is fixed.  This allows us to unique by diagnostic groups.
    454   const void *data = FlagName.data();
    455   std::pair<unsigned, StringRef> &entry = DiagFlags[data];
    456   if (entry.first == 0) {
    457     entry.first = DiagFlags.size();
    458     entry.second = FlagName;
    459 
    460     // Lazily emit the string in a separate record.
    461     RecordData Record;
    462     Record.push_back(RECORD_DIAG_FLAG);
    463     Record.push_back(entry.first);
    464     Record.push_back(FlagName.size());
    465     Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG_FLAG),
    466                               Record, FlagName);
    467   }
    468 
    469   return entry.first;
    470 }
    471 
    472 void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
    473                                     const Diagnostic &Info) {
    474   if (DiagLevel != DiagnosticsEngine::Note) {
    475     if (inNonNoteDiagnostic) {
    476       // We have encountered a non-note diagnostic.  Finish up the previous
    477       // diagnostic block before starting a new one.
    478       Stream.ExitBlock();
    479     }
    480     inNonNoteDiagnostic = true;
    481   }
    482 
    483   // Compute the diagnostic text.
    484   diagBuf.clear();
    485   Info.FormatDiagnostic(diagBuf);
    486 
    487   SourceManager &SM = Info.getSourceManager();
    488   SDiagsRenderer Renderer(*this, Record, SM, *LangOpts, DiagOpts);
    489   Renderer.emitDiagnostic(Info.getLocation(), DiagLevel,
    490                           diagBuf.str(),
    491                           Info.getRanges(),
    492                           llvm::makeArrayRef(Info.getFixItHints(),
    493                                              Info.getNumFixItHints()),
    494                           &Info);
    495 }
    496 
    497 void
    498 SDiagsRenderer::emitDiagnosticMessage(SourceLocation Loc,
    499                                       PresumedLoc PLoc,
    500                                       DiagnosticsEngine::Level Level,
    501                                       StringRef Message,
    502                                       ArrayRef<clang::CharSourceRange> Ranges,
    503                                       DiagOrStoredDiag D) {
    504   // Emit the RECORD_DIAG record.
    505   Writer.Record.clear();
    506   Writer.Record.push_back(RECORD_DIAG);
    507   Writer.Record.push_back(Level);
    508   Writer.AddLocToRecord(Loc, SM, PLoc, Record);
    509 
    510   if (const Diagnostic *Info = D.dyn_cast<const Diagnostic*>()) {
    511     // Emit the category string lazily and get the category ID.
    512     unsigned DiagID = DiagnosticIDs::getCategoryNumberForDiag(Info->getID());
    513     Writer.Record.push_back(Writer.getEmitCategory(DiagID));
    514     // Emit the diagnostic flag string lazily and get the mapped ID.
    515     Writer.Record.push_back(Writer.getEmitDiagnosticFlag(Level, Info->getID()));
    516   }
    517   else {
    518     Writer.Record.push_back(Writer.getEmitCategory());
    519     Writer.Record.push_back(Writer.getEmitDiagnosticFlag(Level));
    520   }
    521 
    522   Writer.Record.push_back(Message.size());
    523   Writer.Stream.EmitRecordWithBlob(Writer.Abbrevs.get(RECORD_DIAG),
    524                                    Writer.Record, Message);
    525 }
    526 
    527 void SDiagsRenderer::beginDiagnostic(DiagOrStoredDiag D,
    528                                      DiagnosticsEngine::Level Level) {
    529   Writer.Stream.EnterSubblock(BLOCK_DIAG, 4);
    530 }
    531 
    532 void SDiagsRenderer::endDiagnostic(DiagOrStoredDiag D,
    533                                    DiagnosticsEngine::Level Level) {
    534   if (D && Level != DiagnosticsEngine::Note)
    535     return;
    536   Writer.Stream.ExitBlock();
    537 }
    538 
    539 void SDiagsRenderer::emitCodeContext(SourceLocation Loc,
    540                                      DiagnosticsEngine::Level Level,
    541                                      SmallVectorImpl<CharSourceRange> &Ranges,
    542                                      ArrayRef<FixItHint> Hints) {
    543   // Emit Source Ranges.
    544   for (ArrayRef<CharSourceRange>::iterator it=Ranges.begin(), ei=Ranges.end();
    545        it != ei; ++it) {
    546     if (it->isValid())
    547       Writer.EmitCharSourceRange(*it, SM);
    548   }
    549 
    550   // Emit FixIts.
    551   for (ArrayRef<FixItHint>::iterator it = Hints.begin(), et = Hints.end();
    552        it != et; ++it) {
    553     const FixItHint &fix = *it;
    554     if (fix.isNull())
    555       continue;
    556     Writer.Record.clear();
    557     Writer.Record.push_back(RECORD_FIXIT);
    558     Writer.AddCharSourceRangeToRecord(fix.RemoveRange, Record, SM);
    559     Writer.Record.push_back(fix.CodeToInsert.size());
    560     Writer.Stream.EmitRecordWithBlob(Writer.Abbrevs.get(RECORD_FIXIT), Record,
    561                                      fix.CodeToInsert);
    562   }
    563 }
    564 
    565 void SDiagsRenderer::emitNote(SourceLocation Loc, StringRef Message) {
    566   Writer.Stream.EnterSubblock(BLOCK_DIAG, 4);
    567   RecordData Record;
    568   Record.push_back(RECORD_DIAG);
    569   Record.push_back(DiagnosticsEngine::Note);
    570   Writer.AddLocToRecord(Loc, Record, SM);
    571   Record.push_back(Writer.getEmitCategory());
    572   Record.push_back(Writer.getEmitDiagnosticFlag(DiagnosticsEngine::Note));
    573   Record.push_back(Message.size());
    574   Writer.Stream.EmitRecordWithBlob(Writer.Abbrevs.get(RECORD_DIAG),
    575                                    Record, Message);
    576   Writer.Stream.ExitBlock();
    577 }
    578 
    579 void SDiagsWriter::finish() {
    580   if (inNonNoteDiagnostic) {
    581     // Finish off any diagnostics we were in the process of emitting.
    582     Stream.ExitBlock();
    583     inNonNoteDiagnostic = false;
    584   }
    585 
    586   // Write the generated bitstream to "Out".
    587   OS->write((char *)&Buffer.front(), Buffer.size());
    588   OS->flush();
    589 
    590   OS.reset(0);
    591 }
    592 
    593