clang API Documentation

SerializedDiagnosticPrinter.cpp
Go to the documentation of this file.
00001 //===--- SerializedDiagnosticPrinter.cpp - Serializer for diagnostics -----===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 
00010 #include <vector>
00011 #include "llvm/Support/raw_ostream.h"
00012 #include "llvm/ADT/StringRef.h"
00013 #include "llvm/ADT/SmallString.h"
00014 #include "llvm/ADT/DenseSet.h"
00015 #include "clang/Basic/SourceManager.h"
00016 #include "clang/Basic/FileManager.h"
00017 #include "clang/Basic/Diagnostic.h"
00018 #include "clang/Basic/Version.h"
00019 #include "clang/Lex/Lexer.h"
00020 #include "clang/Frontend/SerializedDiagnosticPrinter.h"
00021 #include "clang/Frontend/DiagnosticRenderer.h"
00022 
00023 using namespace clang;
00024 using namespace clang::serialized_diags;
00025 
00026 namespace {
00027   
00028 class AbbreviationMap {
00029   llvm::DenseMap<unsigned, unsigned> Abbrevs;
00030 public:
00031   AbbreviationMap() {}
00032   
00033   void set(unsigned recordID, unsigned abbrevID) {
00034     assert(Abbrevs.find(recordID) == Abbrevs.end() 
00035            && "Abbreviation already set.");
00036     Abbrevs[recordID] = abbrevID;
00037   }
00038   
00039   unsigned get(unsigned recordID) {
00040     assert(Abbrevs.find(recordID) != Abbrevs.end() &&
00041            "Abbreviation not set.");
00042     return Abbrevs[recordID];
00043   }
00044 };
00045  
00046 typedef llvm::SmallVector<uint64_t, 64> RecordData;
00047 typedef llvm::SmallVectorImpl<uint64_t> RecordDataImpl;
00048 
00049 class SDiagsWriter;
00050   
00051 class SDiagsRenderer : public DiagnosticNoteRenderer {
00052   SDiagsWriter &Writer;
00053   RecordData &Record;
00054 public:
00055   SDiagsRenderer(SDiagsWriter &Writer, RecordData &Record,
00056                  const LangOptions &LangOpts,
00057                  const DiagnosticOptions &DiagOpts)
00058     : DiagnosticNoteRenderer(LangOpts, DiagOpts),
00059       Writer(Writer), Record(Record){}
00060 
00061   virtual ~SDiagsRenderer() {}
00062   
00063 protected:
00064   virtual void emitDiagnosticMessage(SourceLocation Loc,
00065                                      PresumedLoc PLoc,
00066                                      DiagnosticsEngine::Level Level,
00067                                      StringRef Message,
00068                                      ArrayRef<CharSourceRange> Ranges,
00069                                      const SourceManager *SM,
00070                                      DiagOrStoredDiag D);
00071   
00072   virtual void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
00073                                  DiagnosticsEngine::Level Level,
00074                                  ArrayRef<CharSourceRange> Ranges,
00075                                  const SourceManager &SM) {}
00076   
00077   void emitNote(SourceLocation Loc, StringRef Message, const SourceManager *SM);
00078   
00079   virtual void emitCodeContext(SourceLocation Loc,
00080                                DiagnosticsEngine::Level Level,
00081                                SmallVectorImpl<CharSourceRange>& Ranges,
00082                                ArrayRef<FixItHint> Hints,
00083                                const SourceManager &SM);
00084   
00085   virtual void beginDiagnostic(DiagOrStoredDiag D,
00086                                DiagnosticsEngine::Level Level);
00087   virtual void endDiagnostic(DiagOrStoredDiag D,
00088                              DiagnosticsEngine::Level Level);
00089 };
00090   
00091 class SDiagsWriter : public DiagnosticConsumer {
00092   friend class SDiagsRenderer;
00093 public:  
00094   explicit SDiagsWriter(llvm::raw_ostream *os, const DiagnosticOptions &diags) 
00095     : LangOpts(0), DiagOpts(diags),
00096       Stream(Buffer), OS(os), inNonNoteDiagnostic(false)
00097   { 
00098     EmitPreamble();
00099   }
00100   
00101   ~SDiagsWriter() {}
00102   
00103   void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
00104                         const Diagnostic &Info);
00105   
00106   void BeginSourceFile(const LangOptions &LO,
00107                        const Preprocessor *PP) {
00108     LangOpts = &LO;
00109   }
00110 
00111   virtual void finish();
00112 
00113   DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const {
00114     // It makes no sense to clone this.
00115     return 0;
00116   }
00117 
00118 private:
00119   /// \brief Emit the preamble for the serialized diagnostics.
00120   void EmitPreamble();
00121   
00122   /// \brief Emit the BLOCKINFO block.
00123   void EmitBlockInfoBlock();
00124 
00125   /// \brief Emit the META data block.
00126   void EmitMetaBlock();
00127   
00128   /// \brief Emit a record for a CharSourceRange.
00129   void EmitCharSourceRange(CharSourceRange R, const SourceManager &SM);
00130   
00131   /// \brief Emit the string information for the category.
00132   unsigned getEmitCategory(unsigned category = 0);
00133   
00134   /// \brief Emit the string information for diagnostic flags.
00135   unsigned getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
00136                                  unsigned DiagID = 0);
00137   
00138   /// \brief Emit (lazily) the file string and retrieved the file identifier.
00139   unsigned getEmitFile(const char *Filename);
00140 
00141   /// \brief Add SourceLocation information the specified record.  
00142   void AddLocToRecord(SourceLocation Loc, const SourceManager *SM,
00143                       PresumedLoc PLoc, RecordDataImpl &Record,
00144                       unsigned TokSize = 0);
00145 
00146   /// \brief Add SourceLocation information the specified record.
00147   void AddLocToRecord(SourceLocation Loc, RecordDataImpl &Record,
00148                       const SourceManager *SM,
00149                       unsigned TokSize = 0) {
00150     AddLocToRecord(Loc, SM, SM ? SM->getPresumedLoc(Loc) : PresumedLoc(),
00151                    Record, TokSize);
00152   }
00153 
00154   /// \brief Add CharSourceRange information the specified record.
00155   void AddCharSourceRangeToRecord(CharSourceRange R, RecordDataImpl &Record,
00156                                   const SourceManager &SM);
00157 
00158   /// \brief The version of the diagnostics file.
00159   enum { Version = 1 };
00160 
00161   const LangOptions *LangOpts;
00162   const DiagnosticOptions &DiagOpts;
00163   
00164   /// \brief The byte buffer for the serialized content.
00165   SmallString<1024> Buffer;
00166 
00167   /// \brief The BitStreamWriter for the serialized diagnostics.
00168   llvm::BitstreamWriter Stream;
00169 
00170   /// \brief The name of the diagnostics file.
00171   OwningPtr<llvm::raw_ostream> OS;
00172   
00173   /// \brief The set of constructed record abbreviations.
00174   AbbreviationMap Abbrevs;
00175 
00176   /// \brief A utility buffer for constructing record content.
00177   RecordData Record;
00178 
00179   /// \brief A text buffer for rendering diagnostic text.
00180   SmallString<256> diagBuf;
00181   
00182   /// \brief The collection of diagnostic categories used.
00183   llvm::DenseSet<unsigned> Categories;
00184   
00185   /// \brief The collection of files used.
00186   llvm::DenseMap<const char *, unsigned> Files;
00187 
00188   typedef llvm::DenseMap<const void *, std::pair<unsigned, llvm::StringRef> > 
00189           DiagFlagsTy;
00190 
00191   /// \brief Map for uniquing strings.
00192   DiagFlagsTy DiagFlags;
00193   
00194   /// \brief Flag indicating whether or not we are in the process of
00195   /// emitting a non-note diagnostic.
00196   bool inNonNoteDiagnostic;
00197 };
00198 } // end anonymous namespace
00199 
00200 namespace clang {
00201 namespace serialized_diags {
00202 DiagnosticConsumer *create(llvm::raw_ostream *OS,
00203                            const DiagnosticOptions &diags) {
00204   return new SDiagsWriter(OS, diags);
00205 }
00206 } // end namespace serialized_diags
00207 } // end namespace clang
00208 
00209 //===----------------------------------------------------------------------===//
00210 // Serialization methods.
00211 //===----------------------------------------------------------------------===//
00212 
00213 /// \brief Emits a block ID in the BLOCKINFO block.
00214 static void EmitBlockID(unsigned ID, const char *Name,
00215                         llvm::BitstreamWriter &Stream,
00216                         RecordDataImpl &Record) {
00217   Record.clear();
00218   Record.push_back(ID);
00219   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
00220   
00221   // Emit the block name if present.
00222   if (Name == 0 || Name[0] == 0)
00223     return;
00224 
00225   Record.clear();
00226 
00227   while (*Name)
00228     Record.push_back(*Name++);
00229 
00230   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record);
00231 }
00232 
00233 /// \brief Emits a record ID in the BLOCKINFO block.
00234 static void EmitRecordID(unsigned ID, const char *Name,
00235                          llvm::BitstreamWriter &Stream,
00236                          RecordDataImpl &Record){
00237   Record.clear();
00238   Record.push_back(ID);
00239 
00240   while (*Name)
00241     Record.push_back(*Name++);
00242 
00243   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
00244 }
00245 
00246 void SDiagsWriter::AddLocToRecord(SourceLocation Loc,
00247                                   const SourceManager *SM,
00248                                   PresumedLoc PLoc,
00249                                   RecordDataImpl &Record,
00250                                   unsigned TokSize) {
00251   if (PLoc.isInvalid()) {
00252     // Emit a "sentinel" location.
00253     Record.push_back((unsigned)0); // File.
00254     Record.push_back((unsigned)0); // Line.
00255     Record.push_back((unsigned)0); // Column.
00256     Record.push_back((unsigned)0); // Offset.
00257     return;
00258   }
00259 
00260   Record.push_back(getEmitFile(PLoc.getFilename()));
00261   Record.push_back(PLoc.getLine());
00262   Record.push_back(PLoc.getColumn()+TokSize);
00263   Record.push_back(SM->getFileOffset(Loc));
00264 }
00265 
00266 void SDiagsWriter::AddCharSourceRangeToRecord(CharSourceRange Range,
00267                                               RecordDataImpl &Record,
00268                                               const SourceManager &SM) {
00269   AddLocToRecord(Range.getBegin(), Record, &SM);
00270   unsigned TokSize = 0;
00271   if (Range.isTokenRange())
00272     TokSize = Lexer::MeasureTokenLength(Range.getEnd(),
00273                                         SM, *LangOpts);
00274   
00275   AddLocToRecord(Range.getEnd(), Record, &SM, TokSize);
00276 }
00277 
00278 unsigned SDiagsWriter::getEmitFile(const char *FileName){
00279   if (!FileName)
00280     return 0;
00281   
00282   unsigned &entry = Files[FileName];
00283   if (entry)
00284     return entry;
00285   
00286   // Lazily generate the record for the file.
00287   entry = Files.size();
00288   RecordData Record;
00289   Record.push_back(RECORD_FILENAME);
00290   Record.push_back(entry);
00291   Record.push_back(0); // For legacy.
00292   Record.push_back(0); // For legacy.
00293   StringRef Name(FileName);
00294   Record.push_back(Name.size());
00295   Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_FILENAME), Record, Name);
00296 
00297   return entry;
00298 }
00299 
00300 void SDiagsWriter::EmitCharSourceRange(CharSourceRange R,
00301                                        const SourceManager &SM) {
00302   Record.clear();
00303   Record.push_back(RECORD_SOURCE_RANGE);
00304   AddCharSourceRangeToRecord(R, Record, SM);
00305   Stream.EmitRecordWithAbbrev(Abbrevs.get(RECORD_SOURCE_RANGE), Record);
00306 }
00307 
00308 /// \brief Emits the preamble of the diagnostics file.
00309 void SDiagsWriter::EmitPreamble() {
00310   // Emit the file header.
00311   Stream.Emit((unsigned)'D', 8);
00312   Stream.Emit((unsigned)'I', 8);
00313   Stream.Emit((unsigned)'A', 8);
00314   Stream.Emit((unsigned)'G', 8);
00315 
00316   EmitBlockInfoBlock();
00317   EmitMetaBlock();
00318 }
00319 
00320 static void AddSourceLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) {
00321   using namespace llvm;
00322   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // File ID.
00323   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Line.
00324   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Column.
00325   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Offset;
00326 }
00327 
00328 static void AddRangeLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) {
00329   AddSourceLocationAbbrev(Abbrev);
00330   AddSourceLocationAbbrev(Abbrev);  
00331 }
00332 
00333 void SDiagsWriter::EmitBlockInfoBlock() {
00334   Stream.EnterBlockInfoBlock(3);
00335 
00336   using namespace llvm;
00337 
00338   // ==---------------------------------------------------------------------==//
00339   // The subsequent records and Abbrevs are for the "Meta" block.
00340   // ==---------------------------------------------------------------------==//
00341 
00342   EmitBlockID(BLOCK_META, "Meta", Stream, Record);
00343   EmitRecordID(RECORD_VERSION, "Version", Stream, Record);
00344   BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
00345   Abbrev->Add(BitCodeAbbrevOp(RECORD_VERSION));
00346   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
00347   Abbrevs.set(RECORD_VERSION, Stream.EmitBlockInfoAbbrev(BLOCK_META, Abbrev));
00348 
00349   // ==---------------------------------------------------------------------==//
00350   // The subsequent records and Abbrevs are for the "Diagnostic" block.
00351   // ==---------------------------------------------------------------------==//
00352 
00353   EmitBlockID(BLOCK_DIAG, "Diag", Stream, Record);
00354   EmitRecordID(RECORD_DIAG, "DiagInfo", Stream, Record);
00355   EmitRecordID(RECORD_SOURCE_RANGE, "SrcRange", Stream, Record);
00356   EmitRecordID(RECORD_CATEGORY, "CatName", Stream, Record);
00357   EmitRecordID(RECORD_DIAG_FLAG, "DiagFlag", Stream, Record);
00358   EmitRecordID(RECORD_FILENAME, "FileName", Stream, Record);
00359   EmitRecordID(RECORD_FIXIT, "FixIt", Stream, Record);
00360 
00361   // Emit abbreviation for RECORD_DIAG.
00362   Abbrev = new BitCodeAbbrev();
00363   Abbrev->Add(BitCodeAbbrevOp(RECORD_DIAG));
00364   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3));  // Diag level.
00365   AddSourceLocationAbbrev(Abbrev);
00366   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Category.  
00367   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped Diag ID.
00368   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
00369   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Diagnostc text.
00370   Abbrevs.set(RECORD_DIAG, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
00371   
00372   // Emit abbrevation for RECORD_CATEGORY.
00373   Abbrev = new BitCodeAbbrev();
00374   Abbrev->Add(BitCodeAbbrevOp(RECORD_CATEGORY));
00375   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Category ID.
00376   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8));  // Text size.
00377   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));      // Category text.
00378   Abbrevs.set(RECORD_CATEGORY, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
00379 
00380   // Emit abbrevation for RECORD_SOURCE_RANGE.
00381   Abbrev = new BitCodeAbbrev();
00382   Abbrev->Add(BitCodeAbbrevOp(RECORD_SOURCE_RANGE));
00383   AddRangeLocationAbbrev(Abbrev);
00384   Abbrevs.set(RECORD_SOURCE_RANGE,
00385               Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
00386   
00387   // Emit the abbreviation for RECORD_DIAG_FLAG.
00388   Abbrev = new BitCodeAbbrev();
00389   Abbrev->Add(BitCodeAbbrevOp(RECORD_DIAG_FLAG));
00390   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped Diag ID.
00391   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
00392   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Flag name text.
00393   Abbrevs.set(RECORD_DIAG_FLAG, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
00394                                                            Abbrev));
00395   
00396   // Emit the abbreviation for RECORD_FILENAME.
00397   Abbrev = new BitCodeAbbrev();
00398   Abbrev->Add(BitCodeAbbrevOp(RECORD_FILENAME));
00399   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped file ID.
00400   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Size.
00401   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Modifcation time.  
00402   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
00403   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name text.
00404   Abbrevs.set(RECORD_FILENAME, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
00405                                                           Abbrev));
00406   
00407   // Emit the abbreviation for RECORD_FIXIT.
00408   Abbrev = new BitCodeAbbrev();
00409   Abbrev->Add(BitCodeAbbrevOp(RECORD_FIXIT));
00410   AddRangeLocationAbbrev(Abbrev);
00411   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
00412   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));      // FixIt text.
00413   Abbrevs.set(RECORD_FIXIT, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
00414                                                        Abbrev));
00415 
00416   Stream.ExitBlock();
00417 }
00418 
00419 void SDiagsWriter::EmitMetaBlock() {
00420   Stream.EnterSubblock(BLOCK_META, 3);
00421   Record.clear();
00422   Record.push_back(RECORD_VERSION);
00423   Record.push_back(Version);
00424   Stream.EmitRecordWithAbbrev(Abbrevs.get(RECORD_VERSION), Record);  
00425   Stream.ExitBlock();
00426 }
00427 
00428 unsigned SDiagsWriter::getEmitCategory(unsigned int category) {
00429   if (Categories.count(category))
00430     return category;
00431   
00432   Categories.insert(category);
00433   
00434   // We use a local version of 'Record' so that we can be generating
00435   // another record when we lazily generate one for the category entry.
00436   RecordData Record;
00437   Record.push_back(RECORD_CATEGORY);
00438   Record.push_back(category);
00439   StringRef catName = DiagnosticIDs::getCategoryNameFromID(category);
00440   Record.push_back(catName.size());
00441   Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_CATEGORY), Record, catName);
00442   
00443   return category;
00444 }
00445 
00446 unsigned SDiagsWriter::getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
00447                                              unsigned DiagID) {
00448   if (DiagLevel == DiagnosticsEngine::Note)
00449     return 0; // No flag for notes.
00450   
00451   StringRef FlagName = DiagnosticIDs::getWarningOptionForDiag(DiagID);
00452   if (FlagName.empty())
00453     return 0;
00454 
00455   // Here we assume that FlagName points to static data whose pointer
00456   // value is fixed.  This allows us to unique by diagnostic groups.
00457   const void *data = FlagName.data();
00458   std::pair<unsigned, StringRef> &entry = DiagFlags[data];
00459   if (entry.first == 0) {
00460     entry.first = DiagFlags.size();
00461     entry.second = FlagName;
00462     
00463     // Lazily emit the string in a separate record.
00464     RecordData Record;
00465     Record.push_back(RECORD_DIAG_FLAG);
00466     Record.push_back(entry.first);
00467     Record.push_back(FlagName.size());
00468     Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG_FLAG),
00469                               Record, FlagName);    
00470   }
00471 
00472   return entry.first;
00473 }
00474 
00475 void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
00476                                     const Diagnostic &Info) {
00477   if (DiagLevel != DiagnosticsEngine::Note) {
00478     if (inNonNoteDiagnostic) {
00479       // We have encountered a non-note diagnostic.  Finish up the previous
00480       // diagnostic block before starting a new one.
00481       Stream.ExitBlock();
00482     }
00483     inNonNoteDiagnostic = true;
00484   }
00485 
00486   // Compute the diagnostic text.
00487   diagBuf.clear();   
00488   Info.FormatDiagnostic(diagBuf);
00489 
00490   const SourceManager *
00491     SM = Info.hasSourceManager() ? &Info.getSourceManager() : 0;
00492   SDiagsRenderer Renderer(*this, Record, *LangOpts, DiagOpts);
00493   Renderer.emitDiagnostic(Info.getLocation(), DiagLevel,
00494                           diagBuf.str(),
00495                           Info.getRanges(),
00496                           llvm::makeArrayRef(Info.getFixItHints(),
00497                                              Info.getNumFixItHints()),
00498                           SM,
00499                           &Info);
00500 }
00501 
00502 void
00503 SDiagsRenderer::emitDiagnosticMessage(SourceLocation Loc,
00504                                       PresumedLoc PLoc,
00505                                       DiagnosticsEngine::Level Level,
00506                                       StringRef Message,
00507                                       ArrayRef<clang::CharSourceRange> Ranges,
00508                                       const SourceManager *SM,
00509                                       DiagOrStoredDiag D) {
00510   // Emit the RECORD_DIAG record.
00511   Writer.Record.clear();
00512   Writer.Record.push_back(RECORD_DIAG);
00513   Writer.Record.push_back(Level);
00514   Writer.AddLocToRecord(Loc, SM, PLoc, Record);
00515 
00516   if (const Diagnostic *Info = D.dyn_cast<const Diagnostic*>()) {
00517     // Emit the category string lazily and get the category ID.
00518     unsigned DiagID = DiagnosticIDs::getCategoryNumberForDiag(Info->getID());
00519     Writer.Record.push_back(Writer.getEmitCategory(DiagID));
00520     // Emit the diagnostic flag string lazily and get the mapped ID.
00521     Writer.Record.push_back(Writer.getEmitDiagnosticFlag(Level, Info->getID()));
00522   }
00523   else {
00524     Writer.Record.push_back(Writer.getEmitCategory());
00525     Writer.Record.push_back(Writer.getEmitDiagnosticFlag(Level));
00526   }
00527 
00528   Writer.Record.push_back(Message.size());
00529   Writer.Stream.EmitRecordWithBlob(Writer.Abbrevs.get(RECORD_DIAG),
00530                                    Writer.Record, Message);
00531 }
00532 
00533 void SDiagsRenderer::beginDiagnostic(DiagOrStoredDiag D,
00534                                      DiagnosticsEngine::Level Level) {
00535   Writer.Stream.EnterSubblock(BLOCK_DIAG, 4);  
00536 }
00537 
00538 void SDiagsRenderer::endDiagnostic(DiagOrStoredDiag D,
00539                                    DiagnosticsEngine::Level Level) {
00540   if (D && Level != DiagnosticsEngine::Note)
00541     return;
00542   Writer.Stream.ExitBlock();
00543 }
00544 
00545 void SDiagsRenderer::emitCodeContext(SourceLocation Loc,
00546                                      DiagnosticsEngine::Level Level,
00547                                      SmallVectorImpl<CharSourceRange> &Ranges,
00548                                      ArrayRef<FixItHint> Hints,
00549                                      const SourceManager &SM) {  
00550   // Emit Source Ranges.
00551   for (ArrayRef<CharSourceRange>::iterator it=Ranges.begin(), ei=Ranges.end();
00552        it != ei; ++it) {
00553     if (it->isValid())
00554       Writer.EmitCharSourceRange(*it, SM);
00555   }
00556   
00557   // Emit FixIts.
00558   for (ArrayRef<FixItHint>::iterator it = Hints.begin(), et = Hints.end();
00559        it != et; ++it) {
00560     const FixItHint &fix = *it;
00561     if (fix.isNull())
00562       continue;
00563     Writer.Record.clear();
00564     Writer.Record.push_back(RECORD_FIXIT);
00565     Writer.AddCharSourceRangeToRecord(fix.RemoveRange, Record, SM);
00566     Writer.Record.push_back(fix.CodeToInsert.size());
00567     Writer.Stream.EmitRecordWithBlob(Writer.Abbrevs.get(RECORD_FIXIT), Record,
00568                                      fix.CodeToInsert);    
00569   }
00570 }
00571 
00572 void SDiagsRenderer::emitNote(SourceLocation Loc, StringRef Message,
00573                               const SourceManager *SM) {
00574   Writer.Stream.EnterSubblock(BLOCK_DIAG, 4);
00575   RecordData Record;
00576   Record.push_back(RECORD_DIAG);
00577   Record.push_back(DiagnosticsEngine::Note);
00578   Writer.AddLocToRecord(Loc, Record, SM);
00579   Record.push_back(Writer.getEmitCategory());
00580   Record.push_back(Writer.getEmitDiagnosticFlag(DiagnosticsEngine::Note));
00581   Record.push_back(Message.size());
00582   Writer.Stream.EmitRecordWithBlob(Writer.Abbrevs.get(RECORD_DIAG),
00583                                    Record, Message);
00584   Writer.Stream.ExitBlock();
00585 }
00586 
00587 void SDiagsWriter::finish() {
00588   if (inNonNoteDiagnostic) {
00589     // Finish off any diagnostics we were in the process of emitting.
00590     Stream.ExitBlock();
00591     inNonNoteDiagnostic = false;
00592   }
00593 
00594   // Write the generated bitstream to "Out".
00595   OS->write((char *)&Buffer.front(), Buffer.size());
00596   OS->flush();
00597   
00598   OS.reset(0);
00599 }
00600