Home | History | Annotate | Download | only in Frontend
      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 "clang/Frontend/SerializedDiagnosticPrinter.h"
     11 #include "clang/Basic/Diagnostic.h"
     12 #include "clang/Basic/DiagnosticOptions.h"
     13 #include "clang/Basic/FileManager.h"
     14 #include "clang/Basic/SourceManager.h"
     15 #include "clang/Basic/Version.h"
     16 #include "clang/Frontend/DiagnosticRenderer.h"
     17 #include "clang/Lex/Lexer.h"
     18 #include "llvm/ADT/DenseSet.h"
     19 #include "llvm/ADT/SmallString.h"
     20 #include "llvm/ADT/StringRef.h"
     21 #include "llvm/Support/raw_ostream.h"
     22 #include <vector>
     23 
     24 using namespace clang;
     25 using namespace clang::serialized_diags;
     26 
     27 namespace {
     28 
     29 class AbbreviationMap {
     30   llvm::DenseMap<unsigned, unsigned> Abbrevs;
     31 public:
     32   AbbreviationMap() {}
     33 
     34   void set(unsigned recordID, unsigned abbrevID) {
     35     assert(Abbrevs.find(recordID) == Abbrevs.end()
     36            && "Abbreviation already set.");
     37     Abbrevs[recordID] = abbrevID;
     38   }
     39 
     40   unsigned get(unsigned recordID) {
     41     assert(Abbrevs.find(recordID) != Abbrevs.end() &&
     42            "Abbreviation not set.");
     43     return Abbrevs[recordID];
     44   }
     45 };
     46 
     47 typedef SmallVector<uint64_t, 64> RecordData;
     48 typedef SmallVectorImpl<uint64_t> RecordDataImpl;
     49 
     50 class SDiagsWriter;
     51 
     52 class SDiagsRenderer : public DiagnosticNoteRenderer {
     53   SDiagsWriter &Writer;
     54 public:
     55   SDiagsRenderer(SDiagsWriter &Writer, const LangOptions &LangOpts,
     56                  DiagnosticOptions *DiagOpts)
     57     : DiagnosticNoteRenderer(LangOpts, DiagOpts), Writer(Writer) {}
     58 
     59   virtual ~SDiagsRenderer() {}
     60 
     61 protected:
     62   virtual void emitDiagnosticMessage(SourceLocation Loc,
     63                                      PresumedLoc PLoc,
     64                                      DiagnosticsEngine::Level Level,
     65                                      StringRef Message,
     66                                      ArrayRef<CharSourceRange> Ranges,
     67                                      const SourceManager *SM,
     68                                      DiagOrStoredDiag D);
     69 
     70   virtual void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
     71                                  DiagnosticsEngine::Level Level,
     72                                  ArrayRef<CharSourceRange> Ranges,
     73                                  const SourceManager &SM) {}
     74 
     75   virtual void emitNote(SourceLocation Loc, StringRef Message,
     76                         const SourceManager *SM);
     77 
     78   virtual void emitCodeContext(SourceLocation Loc,
     79                                DiagnosticsEngine::Level Level,
     80                                SmallVectorImpl<CharSourceRange>& Ranges,
     81                                ArrayRef<FixItHint> Hints,
     82                                const SourceManager &SM);
     83 
     84   virtual void beginDiagnostic(DiagOrStoredDiag D,
     85                                DiagnosticsEngine::Level Level);
     86   virtual void endDiagnostic(DiagOrStoredDiag D,
     87                              DiagnosticsEngine::Level Level);
     88 };
     89 
     90 class SDiagsWriter : public DiagnosticConsumer {
     91   friend class SDiagsRenderer;
     92 
     93   struct SharedState;
     94 
     95   explicit SDiagsWriter(IntrusiveRefCntPtr<SharedState> State)
     96     : LangOpts(0), OriginalInstance(false), State(State) { }
     97 
     98 public:
     99   SDiagsWriter(raw_ostream *os, DiagnosticOptions *diags)
    100     : LangOpts(0), OriginalInstance(true), State(new SharedState(os, diags))
    101   {
    102     EmitPreamble();
    103   }
    104 
    105   ~SDiagsWriter() {}
    106 
    107   void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
    108                         const Diagnostic &Info);
    109 
    110   void BeginSourceFile(const LangOptions &LO,
    111                        const Preprocessor *PP) {
    112     LangOpts = &LO;
    113   }
    114 
    115   virtual void finish();
    116 
    117   DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const {
    118     return new SDiagsWriter(State);
    119   }
    120 
    121 private:
    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 Start a DIAG block.
    132   void EnterDiagBlock();
    133 
    134   /// \brief End a DIAG block.
    135   void ExitDiagBlock();
    136 
    137   /// \brief Emit a DIAG record.
    138   void EmitDiagnosticMessage(SourceLocation Loc,
    139                              PresumedLoc PLoc,
    140                              DiagnosticsEngine::Level Level,
    141                              StringRef Message,
    142                              const SourceManager *SM,
    143                              DiagOrStoredDiag D);
    144 
    145   /// \brief Emit FIXIT and SOURCE_RANGE records for a diagnostic.
    146   void EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges,
    147                        ArrayRef<FixItHint> Hints,
    148                        const SourceManager &SM);
    149 
    150   /// \brief Emit a record for a CharSourceRange.
    151   void EmitCharSourceRange(CharSourceRange R, const SourceManager &SM);
    152 
    153   /// \brief Emit the string information for the category.
    154   unsigned getEmitCategory(unsigned category = 0);
    155 
    156   /// \brief Emit the string information for diagnostic flags.
    157   unsigned getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
    158                                  unsigned DiagID = 0);
    159 
    160   /// \brief Emit (lazily) the file string and retrieved the file identifier.
    161   unsigned getEmitFile(const char *Filename);
    162 
    163   /// \brief Add SourceLocation information the specified record.
    164   void AddLocToRecord(SourceLocation Loc, const SourceManager *SM,
    165                       PresumedLoc PLoc, RecordDataImpl &Record,
    166                       unsigned TokSize = 0);
    167 
    168   /// \brief Add SourceLocation information the specified record.
    169   void AddLocToRecord(SourceLocation Loc, RecordDataImpl &Record,
    170                       const SourceManager *SM,
    171                       unsigned TokSize = 0) {
    172     AddLocToRecord(Loc, SM, SM ? SM->getPresumedLoc(Loc) : PresumedLoc(),
    173                    Record, TokSize);
    174   }
    175 
    176   /// \brief Add CharSourceRange information the specified record.
    177   void AddCharSourceRangeToRecord(CharSourceRange R, RecordDataImpl &Record,
    178                                   const SourceManager &SM);
    179 
    180   /// \brief The version of the diagnostics file.
    181   enum { Version = 1 };
    182 
    183   /// \brief Language options, which can differ from one clone of this client
    184   /// to another.
    185   const LangOptions *LangOpts;
    186 
    187   /// \brief Whether this is the original instance (rather than one of its
    188   /// clones), responsible for writing the file at the end.
    189   bool OriginalInstance;
    190 
    191   /// \brief State that is shared among the various clones of this diagnostic
    192   /// consumer.
    193   struct SharedState : RefCountedBase<SharedState> {
    194     SharedState(raw_ostream *os, DiagnosticOptions *diags)
    195       : DiagOpts(diags), Stream(Buffer), OS(os), EmittedAnyDiagBlocks(false) { }
    196 
    197     /// \brief Diagnostic options.
    198     IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
    199 
    200     /// \brief The byte buffer for the serialized content.
    201     SmallString<1024> Buffer;
    202 
    203     /// \brief The BitStreamWriter for the serialized diagnostics.
    204     llvm::BitstreamWriter Stream;
    205 
    206     /// \brief The name of the diagnostics file.
    207     OwningPtr<raw_ostream> OS;
    208 
    209     /// \brief The set of constructed record abbreviations.
    210     AbbreviationMap Abbrevs;
    211 
    212     /// \brief A utility buffer for constructing record content.
    213     RecordData Record;
    214 
    215     /// \brief A text buffer for rendering diagnostic text.
    216     SmallString<256> diagBuf;
    217 
    218     /// \brief The collection of diagnostic categories used.
    219     llvm::DenseSet<unsigned> Categories;
    220 
    221     /// \brief The collection of files used.
    222     llvm::DenseMap<const char *, unsigned> Files;
    223 
    224     typedef llvm::DenseMap<const void *, std::pair<unsigned, StringRef> >
    225     DiagFlagsTy;
    226 
    227     /// \brief Map for uniquing strings.
    228     DiagFlagsTy DiagFlags;
    229 
    230     /// \brief Whether we have already started emission of any DIAG blocks. Once
    231     /// this becomes \c true, we never close a DIAG block until we know that we're
    232     /// starting another one or we're done.
    233     bool EmittedAnyDiagBlocks;
    234   };
    235 
    236   /// \brief State shared among the various clones of this diagnostic consumer.
    237   IntrusiveRefCntPtr<SharedState> State;
    238 };
    239 } // end anonymous namespace
    240 
    241 namespace clang {
    242 namespace serialized_diags {
    243 DiagnosticConsumer *create(raw_ostream *OS, DiagnosticOptions *diags) {
    244   return new SDiagsWriter(OS, diags);
    245 }
    246 } // end namespace serialized_diags
    247 } // end namespace clang
    248 
    249 //===----------------------------------------------------------------------===//
    250 // Serialization methods.
    251 //===----------------------------------------------------------------------===//
    252 
    253 /// \brief Emits a block ID in the BLOCKINFO block.
    254 static void EmitBlockID(unsigned ID, const char *Name,
    255                         llvm::BitstreamWriter &Stream,
    256                         RecordDataImpl &Record) {
    257   Record.clear();
    258   Record.push_back(ID);
    259   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
    260 
    261   // Emit the block name if present.
    262   if (Name == 0 || Name[0] == 0)
    263     return;
    264 
    265   Record.clear();
    266 
    267   while (*Name)
    268     Record.push_back(*Name++);
    269 
    270   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record);
    271 }
    272 
    273 /// \brief Emits a record ID in the BLOCKINFO block.
    274 static void EmitRecordID(unsigned ID, const char *Name,
    275                          llvm::BitstreamWriter &Stream,
    276                          RecordDataImpl &Record){
    277   Record.clear();
    278   Record.push_back(ID);
    279 
    280   while (*Name)
    281     Record.push_back(*Name++);
    282 
    283   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
    284 }
    285 
    286 void SDiagsWriter::AddLocToRecord(SourceLocation Loc,
    287                                   const SourceManager *SM,
    288                                   PresumedLoc PLoc,
    289                                   RecordDataImpl &Record,
    290                                   unsigned TokSize) {
    291   if (PLoc.isInvalid()) {
    292     // Emit a "sentinel" location.
    293     Record.push_back((unsigned)0); // File.
    294     Record.push_back((unsigned)0); // Line.
    295     Record.push_back((unsigned)0); // Column.
    296     Record.push_back((unsigned)0); // Offset.
    297     return;
    298   }
    299 
    300   Record.push_back(getEmitFile(PLoc.getFilename()));
    301   Record.push_back(PLoc.getLine());
    302   Record.push_back(PLoc.getColumn()+TokSize);
    303   Record.push_back(SM->getFileOffset(Loc));
    304 }
    305 
    306 void SDiagsWriter::AddCharSourceRangeToRecord(CharSourceRange Range,
    307                                               RecordDataImpl &Record,
    308                                               const SourceManager &SM) {
    309   AddLocToRecord(Range.getBegin(), Record, &SM);
    310   unsigned TokSize = 0;
    311   if (Range.isTokenRange())
    312     TokSize = Lexer::MeasureTokenLength(Range.getEnd(),
    313                                         SM, *LangOpts);
    314 
    315   AddLocToRecord(Range.getEnd(), Record, &SM, TokSize);
    316 }
    317 
    318 unsigned SDiagsWriter::getEmitFile(const char *FileName){
    319   if (!FileName)
    320     return 0;
    321 
    322   unsigned &entry = State->Files[FileName];
    323   if (entry)
    324     return entry;
    325 
    326   // Lazily generate the record for the file.
    327   entry = State->Files.size();
    328   RecordData Record;
    329   Record.push_back(RECORD_FILENAME);
    330   Record.push_back(entry);
    331   Record.push_back(0); // For legacy.
    332   Record.push_back(0); // For legacy.
    333   StringRef Name(FileName);
    334   Record.push_back(Name.size());
    335   State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_FILENAME), Record,
    336                                    Name);
    337 
    338   return entry;
    339 }
    340 
    341 void SDiagsWriter::EmitCharSourceRange(CharSourceRange R,
    342                                        const SourceManager &SM) {
    343   State->Record.clear();
    344   State->Record.push_back(RECORD_SOURCE_RANGE);
    345   AddCharSourceRangeToRecord(R, State->Record, SM);
    346   State->Stream.EmitRecordWithAbbrev(State->Abbrevs.get(RECORD_SOURCE_RANGE),
    347                                      State->Record);
    348 }
    349 
    350 /// \brief Emits the preamble of the diagnostics file.
    351 void SDiagsWriter::EmitPreamble() {
    352   // Emit the file header.
    353   State->Stream.Emit((unsigned)'D', 8);
    354   State->Stream.Emit((unsigned)'I', 8);
    355   State->Stream.Emit((unsigned)'A', 8);
    356   State->Stream.Emit((unsigned)'G', 8);
    357 
    358   EmitBlockInfoBlock();
    359   EmitMetaBlock();
    360 }
    361 
    362 static void AddSourceLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) {
    363   using namespace llvm;
    364   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // File ID.
    365   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Line.
    366   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Column.
    367   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Offset;
    368 }
    369 
    370 static void AddRangeLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) {
    371   AddSourceLocationAbbrev(Abbrev);
    372   AddSourceLocationAbbrev(Abbrev);
    373 }
    374 
    375 void SDiagsWriter::EmitBlockInfoBlock() {
    376   State->Stream.EnterBlockInfoBlock(3);
    377 
    378   using namespace llvm;
    379   llvm::BitstreamWriter &Stream = State->Stream;
    380   RecordData &Record = State->Record;
    381   AbbreviationMap &Abbrevs = State->Abbrevs;
    382 
    383   // ==---------------------------------------------------------------------==//
    384   // The subsequent records and Abbrevs are for the "Meta" block.
    385   // ==---------------------------------------------------------------------==//
    386 
    387   EmitBlockID(BLOCK_META, "Meta", Stream, Record);
    388   EmitRecordID(RECORD_VERSION, "Version", Stream, Record);
    389   BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
    390   Abbrev->Add(BitCodeAbbrevOp(RECORD_VERSION));
    391   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
    392   Abbrevs.set(RECORD_VERSION, Stream.EmitBlockInfoAbbrev(BLOCK_META, Abbrev));
    393 
    394   // ==---------------------------------------------------------------------==//
    395   // The subsequent records and Abbrevs are for the "Diagnostic" block.
    396   // ==---------------------------------------------------------------------==//
    397 
    398   EmitBlockID(BLOCK_DIAG, "Diag", Stream, Record);
    399   EmitRecordID(RECORD_DIAG, "DiagInfo", Stream, Record);
    400   EmitRecordID(RECORD_SOURCE_RANGE, "SrcRange", Stream, Record);
    401   EmitRecordID(RECORD_CATEGORY, "CatName", Stream, Record);
    402   EmitRecordID(RECORD_DIAG_FLAG, "DiagFlag", Stream, Record);
    403   EmitRecordID(RECORD_FILENAME, "FileName", Stream, Record);
    404   EmitRecordID(RECORD_FIXIT, "FixIt", Stream, Record);
    405 
    406   // Emit abbreviation for RECORD_DIAG.
    407   Abbrev = new BitCodeAbbrev();
    408   Abbrev->Add(BitCodeAbbrevOp(RECORD_DIAG));
    409   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3));  // Diag level.
    410   AddSourceLocationAbbrev(Abbrev);
    411   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Category.
    412   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped Diag ID.
    413   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
    414   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Diagnostc text.
    415   Abbrevs.set(RECORD_DIAG, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
    416 
    417   // Emit abbrevation for RECORD_CATEGORY.
    418   Abbrev = new BitCodeAbbrev();
    419   Abbrev->Add(BitCodeAbbrevOp(RECORD_CATEGORY));
    420   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Category ID.
    421   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8));  // Text size.
    422   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));      // Category text.
    423   Abbrevs.set(RECORD_CATEGORY, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
    424 
    425   // Emit abbrevation for RECORD_SOURCE_RANGE.
    426   Abbrev = new BitCodeAbbrev();
    427   Abbrev->Add(BitCodeAbbrevOp(RECORD_SOURCE_RANGE));
    428   AddRangeLocationAbbrev(Abbrev);
    429   Abbrevs.set(RECORD_SOURCE_RANGE,
    430               Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
    431 
    432   // Emit the abbreviation for RECORD_DIAG_FLAG.
    433   Abbrev = new BitCodeAbbrev();
    434   Abbrev->Add(BitCodeAbbrevOp(RECORD_DIAG_FLAG));
    435   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped Diag ID.
    436   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
    437   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Flag name text.
    438   Abbrevs.set(RECORD_DIAG_FLAG, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
    439                                                            Abbrev));
    440 
    441   // Emit the abbreviation for RECORD_FILENAME.
    442   Abbrev = new BitCodeAbbrev();
    443   Abbrev->Add(BitCodeAbbrevOp(RECORD_FILENAME));
    444   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped file ID.
    445   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Size.
    446   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Modifcation time.
    447   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
    448   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name text.
    449   Abbrevs.set(RECORD_FILENAME, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
    450                                                           Abbrev));
    451 
    452   // Emit the abbreviation for RECORD_FIXIT.
    453   Abbrev = new BitCodeAbbrev();
    454   Abbrev->Add(BitCodeAbbrevOp(RECORD_FIXIT));
    455   AddRangeLocationAbbrev(Abbrev);
    456   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
    457   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));      // FixIt text.
    458   Abbrevs.set(RECORD_FIXIT, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
    459                                                        Abbrev));
    460 
    461   Stream.ExitBlock();
    462 }
    463 
    464 void SDiagsWriter::EmitMetaBlock() {
    465   llvm::BitstreamWriter &Stream = State->Stream;
    466   RecordData &Record = State->Record;
    467   AbbreviationMap &Abbrevs = State->Abbrevs;
    468 
    469   Stream.EnterSubblock(BLOCK_META, 3);
    470   Record.clear();
    471   Record.push_back(RECORD_VERSION);
    472   Record.push_back(Version);
    473   Stream.EmitRecordWithAbbrev(Abbrevs.get(RECORD_VERSION), Record);
    474   Stream.ExitBlock();
    475 }
    476 
    477 unsigned SDiagsWriter::getEmitCategory(unsigned int category) {
    478   if (State->Categories.count(category))
    479     return category;
    480 
    481   State->Categories.insert(category);
    482 
    483   // We use a local version of 'Record' so that we can be generating
    484   // another record when we lazily generate one for the category entry.
    485   RecordData Record;
    486   Record.push_back(RECORD_CATEGORY);
    487   Record.push_back(category);
    488   StringRef catName = DiagnosticIDs::getCategoryNameFromID(category);
    489   Record.push_back(catName.size());
    490   State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_CATEGORY), Record,
    491                                    catName);
    492 
    493   return category;
    494 }
    495 
    496 unsigned SDiagsWriter::getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
    497                                              unsigned DiagID) {
    498   if (DiagLevel == DiagnosticsEngine::Note)
    499     return 0; // No flag for notes.
    500 
    501   StringRef FlagName = DiagnosticIDs::getWarningOptionForDiag(DiagID);
    502   if (FlagName.empty())
    503     return 0;
    504 
    505   // Here we assume that FlagName points to static data whose pointer
    506   // value is fixed.  This allows us to unique by diagnostic groups.
    507   const void *data = FlagName.data();
    508   std::pair<unsigned, StringRef> &entry = State->DiagFlags[data];
    509   if (entry.first == 0) {
    510     entry.first = State->DiagFlags.size();
    511     entry.second = FlagName;
    512 
    513     // Lazily emit the string in a separate record.
    514     RecordData Record;
    515     Record.push_back(RECORD_DIAG_FLAG);
    516     Record.push_back(entry.first);
    517     Record.push_back(FlagName.size());
    518     State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_DIAG_FLAG),
    519                                      Record, FlagName);
    520   }
    521 
    522   return entry.first;
    523 }
    524 
    525 void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
    526                                     const Diagnostic &Info) {
    527   // Enter the block for a non-note diagnostic immediately, rather than waiting
    528   // for beginDiagnostic, in case associated notes are emitted before we get
    529   // there.
    530   if (DiagLevel != DiagnosticsEngine::Note) {
    531     if (State->EmittedAnyDiagBlocks)
    532       ExitDiagBlock();
    533 
    534     EnterDiagBlock();
    535     State->EmittedAnyDiagBlocks = true;
    536   }
    537 
    538   // Compute the diagnostic text.
    539   State->diagBuf.clear();
    540   Info.FormatDiagnostic(State->diagBuf);
    541 
    542   if (Info.getLocation().isInvalid()) {
    543     // Special-case diagnostics with no location. We may not have entered a
    544     // source file in this case, so we can't use the normal DiagnosticsRenderer
    545     // machinery.
    546 
    547     // Make sure we bracket all notes as "sub-diagnostics".  This matches
    548     // the behavior in SDiagsRenderer::emitDiagnostic().
    549     if (DiagLevel == DiagnosticsEngine::Note)
    550       EnterDiagBlock();
    551 
    552     EmitDiagnosticMessage(SourceLocation(), PresumedLoc(), DiagLevel,
    553                           State->diagBuf, 0, &Info);
    554 
    555     if (DiagLevel == DiagnosticsEngine::Note)
    556       ExitDiagBlock();
    557 
    558     return;
    559   }
    560 
    561   assert(Info.hasSourceManager() && LangOpts &&
    562          "Unexpected diagnostic with valid location outside of a source file");
    563   SDiagsRenderer Renderer(*this, *LangOpts, &*State->DiagOpts);
    564   Renderer.emitDiagnostic(Info.getLocation(), DiagLevel,
    565                           State->diagBuf.str(),
    566                           Info.getRanges(),
    567                           llvm::makeArrayRef(Info.getFixItHints(),
    568                                              Info.getNumFixItHints()),
    569                           &Info.getSourceManager(),
    570                           &Info);
    571 }
    572 
    573 void SDiagsWriter::EmitDiagnosticMessage(SourceLocation Loc,
    574                                          PresumedLoc PLoc,
    575                                          DiagnosticsEngine::Level Level,
    576                                          StringRef Message,
    577                                          const SourceManager *SM,
    578                                          DiagOrStoredDiag D) {
    579   llvm::BitstreamWriter &Stream = State->Stream;
    580   RecordData &Record = State->Record;
    581   AbbreviationMap &Abbrevs = State->Abbrevs;
    582 
    583   // Emit the RECORD_DIAG record.
    584   Record.clear();
    585   Record.push_back(RECORD_DIAG);
    586   Record.push_back(Level);
    587   AddLocToRecord(Loc, SM, PLoc, Record);
    588 
    589   if (const Diagnostic *Info = D.dyn_cast<const Diagnostic*>()) {
    590     // Emit the category string lazily and get the category ID.
    591     unsigned DiagID = DiagnosticIDs::getCategoryNumberForDiag(Info->getID());
    592     Record.push_back(getEmitCategory(DiagID));
    593     // Emit the diagnostic flag string lazily and get the mapped ID.
    594     Record.push_back(getEmitDiagnosticFlag(Level, Info->getID()));
    595   } else {
    596     Record.push_back(getEmitCategory());
    597     Record.push_back(getEmitDiagnosticFlag(Level));
    598   }
    599 
    600   Record.push_back(Message.size());
    601   Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG), Record, Message);
    602 }
    603 
    604 void
    605 SDiagsRenderer::emitDiagnosticMessage(SourceLocation Loc,
    606                                       PresumedLoc PLoc,
    607                                       DiagnosticsEngine::Level Level,
    608                                       StringRef Message,
    609                                       ArrayRef<clang::CharSourceRange> Ranges,
    610                                       const SourceManager *SM,
    611                                       DiagOrStoredDiag D) {
    612   Writer.EmitDiagnosticMessage(Loc, PLoc, Level, Message, SM, D);
    613 }
    614 
    615 void SDiagsWriter::EnterDiagBlock() {
    616   State->Stream.EnterSubblock(BLOCK_DIAG, 4);
    617 }
    618 
    619 void SDiagsWriter::ExitDiagBlock() {
    620   State->Stream.ExitBlock();
    621 }
    622 
    623 void SDiagsRenderer::beginDiagnostic(DiagOrStoredDiag D,
    624                                      DiagnosticsEngine::Level Level) {
    625   if (Level == DiagnosticsEngine::Note)
    626     Writer.EnterDiagBlock();
    627 }
    628 
    629 void SDiagsRenderer::endDiagnostic(DiagOrStoredDiag D,
    630                                    DiagnosticsEngine::Level Level) {
    631   // Only end note diagnostics here, because we can't be sure when we've seen
    632   // the last note associated with a non-note diagnostic.
    633   if (Level == DiagnosticsEngine::Note)
    634     Writer.ExitDiagBlock();
    635 }
    636 
    637 void SDiagsWriter::EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges,
    638                                    ArrayRef<FixItHint> Hints,
    639                                    const SourceManager &SM) {
    640   llvm::BitstreamWriter &Stream = State->Stream;
    641   RecordData &Record = State->Record;
    642   AbbreviationMap &Abbrevs = State->Abbrevs;
    643 
    644   // Emit Source Ranges.
    645   for (ArrayRef<CharSourceRange>::iterator I = Ranges.begin(), E = Ranges.end();
    646        I != E; ++I)
    647     if (I->isValid())
    648       EmitCharSourceRange(*I, SM);
    649 
    650   // Emit FixIts.
    651   for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end();
    652        I != E; ++I) {
    653     const FixItHint &Fix = *I;
    654     if (Fix.isNull())
    655       continue;
    656     Record.clear();
    657     Record.push_back(RECORD_FIXIT);
    658     AddCharSourceRangeToRecord(Fix.RemoveRange, Record, SM);
    659     Record.push_back(Fix.CodeToInsert.size());
    660     Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_FIXIT), Record,
    661                               Fix.CodeToInsert);
    662   }
    663 }
    664 
    665 void SDiagsRenderer::emitCodeContext(SourceLocation Loc,
    666                                      DiagnosticsEngine::Level Level,
    667                                      SmallVectorImpl<CharSourceRange> &Ranges,
    668                                      ArrayRef<FixItHint> Hints,
    669                                      const SourceManager &SM) {
    670   Writer.EmitCodeContext(Ranges, Hints, SM);
    671 }
    672 
    673 void SDiagsRenderer::emitNote(SourceLocation Loc, StringRef Message,
    674                               const SourceManager *SM) {
    675   Writer.EnterDiagBlock();
    676   PresumedLoc PLoc = SM ? SM->getPresumedLoc(Loc) : PresumedLoc();
    677   Writer.EmitDiagnosticMessage(Loc, PLoc, DiagnosticsEngine::Note,
    678                                Message, SM, DiagOrStoredDiag());
    679   Writer.ExitDiagBlock();
    680 }
    681 
    682 void SDiagsWriter::finish() {
    683   // The original instance is responsible for writing the file.
    684   if (!OriginalInstance)
    685     return;
    686 
    687   // Finish off any diagnostic we were in the process of emitting.
    688   if (State->EmittedAnyDiagBlocks)
    689     ExitDiagBlock();
    690 
    691   // Write the generated bitstream to "Out".
    692   State->OS->write((char *)&State->Buffer.front(), State->Buffer.size());
    693   State->OS->flush();
    694 
    695   State->OS.reset(0);
    696 }
    697