]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/llvm/tools/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp
MFC r234353:
[FreeBSD/stable/9.git] / contrib / llvm / tools / clang / lib / Frontend / SerializedDiagnosticPrinter.cpp
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