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 LangOptions &LangOpts,
57                  const DiagnosticOptions &DiagOpts)
58     : DiagnosticNoteRenderer(LangOpts, DiagOpts),
59       Writer(Writer), Record(Record){}
60 
61   virtual ~SDiagsRenderer() {}
62 
63 protected:
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 
91 class SDiagsWriter : public DiagnosticConsumer {
92   friend class SDiagsRenderer;
93 public:
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 
118 private:
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 
200 namespace clang {
201 namespace serialized_diags {
202 DiagnosticConsumer *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.
214 static 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.
234 static 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 
246 void 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 
266 void 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 
278 unsigned 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 
300 void 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.
309 void 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 
320 static 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 
328 static void AddRangeLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) {
329   AddSourceLocationAbbrev(Abbrev);
330   AddSourceLocationAbbrev(Abbrev);
331 }
332 
333 void 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 
419 void 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 
428 unsigned 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 
446 unsigned 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 
475 void 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 
502 void
503 SDiagsRenderer::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 
533 void SDiagsRenderer::beginDiagnostic(DiagOrStoredDiag D,
534                                      DiagnosticsEngine::Level Level) {
535   Writer.Stream.EnterSubblock(BLOCK_DIAG, 4);
536 }
537 
538 void SDiagsRenderer::endDiagnostic(DiagOrStoredDiag D,
539                                    DiagnosticsEngine::Level Level) {
540   if (D && Level != DiagnosticsEngine::Note)
541     return;
542   Writer.Stream.ExitBlock();
543 }
544 
545 void 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 
572 void 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 
587 void 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