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