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