SerializedDiagnosticPrinter.cpp revision 14afab36c73c32a831838ba80f36136a80d9e6db
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/DiagnosticOptions.h"
16#include "clang/Basic/SourceManager.h"
17#include "clang/Basic/FileManager.h"
18#include "clang/Basic/Diagnostic.h"
19#include "clang/Basic/Version.h"
20#include "clang/Lex/Lexer.h"
21#include "clang/Frontend/SerializedDiagnosticPrinter.h"
22#include "clang/Frontend/DiagnosticRenderer.h"
23
24using namespace clang;
25using namespace clang::serialized_diags;
26
27namespace {
28
29class AbbreviationMap {
30  llvm::DenseMap<unsigned, unsigned> Abbrevs;
31public:
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
47typedef llvm::SmallVector<uint64_t, 64> RecordData;
48typedef llvm::SmallVectorImpl<uint64_t> RecordDataImpl;
49
50class SDiagsWriter;
51
52class SDiagsRenderer : public DiagnosticNoteRenderer {
53  SDiagsWriter &Writer;
54public:
55  SDiagsRenderer(SDiagsWriter &Writer, const LangOptions &LangOpts,
56                 DiagnosticOptions *DiagOpts)
57    : DiagnosticNoteRenderer(LangOpts, DiagOpts), Writer(Writer) {}
58
59  virtual ~SDiagsRenderer() {}
60
61protected:
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
90class SDiagsWriter : public DiagnosticConsumer {
91  friend class SDiagsRenderer;
92
93  struct SharedState;
94
95  explicit SDiagsWriter(llvm::IntrusiveRefCntPtr<SharedState> State)
96    : LangOpts(0), OriginalInstance(false), State(State) { }
97
98public:
99  SDiagsWriter(llvm::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
121private:
122  /// \brief Emit the preamble for the serialized diagnostics.
123  void EmitPreamble();
124
125  /// \brief Emit the BLOCKINFO block.
126  void EmitBlockInfoBlock();
127
128  /// \brief Emit the META data block.
129  void EmitMetaBlock();
130
131  /// \brief 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 : llvm::RefCountedBase<SharedState> {
194    SharedState(llvm::raw_ostream *os, DiagnosticOptions *diags)
195      : DiagOpts(diags), Stream(Buffer), OS(os), EmittedAnyDiagBlocks(false) { }
196
197    /// \brief Diagnostic options.
198    llvm::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<llvm::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, llvm::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  llvm::IntrusiveRefCntPtr<SharedState> State;
238};
239} // end anonymous namespace
240
241namespace clang {
242namespace serialized_diags {
243DiagnosticConsumer *create(llvm::raw_ostream *OS,
244                           DiagnosticOptions *diags) {
245  return new SDiagsWriter(OS, diags);
246}
247} // end namespace serialized_diags
248} // end namespace clang
249
250//===----------------------------------------------------------------------===//
251// Serialization methods.
252//===----------------------------------------------------------------------===//
253
254/// \brief Emits a block ID in the BLOCKINFO block.
255static void EmitBlockID(unsigned ID, const char *Name,
256                        llvm::BitstreamWriter &Stream,
257                        RecordDataImpl &Record) {
258  Record.clear();
259  Record.push_back(ID);
260  Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
261
262  // Emit the block name if present.
263  if (Name == 0 || Name[0] == 0)
264    return;
265
266  Record.clear();
267
268  while (*Name)
269    Record.push_back(*Name++);
270
271  Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record);
272}
273
274/// \brief Emits a record ID in the BLOCKINFO block.
275static void EmitRecordID(unsigned ID, const char *Name,
276                         llvm::BitstreamWriter &Stream,
277                         RecordDataImpl &Record){
278  Record.clear();
279  Record.push_back(ID);
280
281  while (*Name)
282    Record.push_back(*Name++);
283
284  Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
285}
286
287void SDiagsWriter::AddLocToRecord(SourceLocation Loc,
288                                  const SourceManager *SM,
289                                  PresumedLoc PLoc,
290                                  RecordDataImpl &Record,
291                                  unsigned TokSize) {
292  if (PLoc.isInvalid()) {
293    // Emit a "sentinel" location.
294    Record.push_back((unsigned)0); // File.
295    Record.push_back((unsigned)0); // Line.
296    Record.push_back((unsigned)0); // Column.
297    Record.push_back((unsigned)0); // Offset.
298    return;
299  }
300
301  Record.push_back(getEmitFile(PLoc.getFilename()));
302  Record.push_back(PLoc.getLine());
303  Record.push_back(PLoc.getColumn()+TokSize);
304  Record.push_back(SM->getFileOffset(Loc));
305}
306
307void SDiagsWriter::AddCharSourceRangeToRecord(CharSourceRange Range,
308                                              RecordDataImpl &Record,
309                                              const SourceManager &SM) {
310  AddLocToRecord(Range.getBegin(), Record, &SM);
311  unsigned TokSize = 0;
312  if (Range.isTokenRange())
313    TokSize = Lexer::MeasureTokenLength(Range.getEnd(),
314                                        SM, *LangOpts);
315
316  AddLocToRecord(Range.getEnd(), Record, &SM, TokSize);
317}
318
319unsigned SDiagsWriter::getEmitFile(const char *FileName){
320  if (!FileName)
321    return 0;
322
323  unsigned &entry = State->Files[FileName];
324  if (entry)
325    return entry;
326
327  // Lazily generate the record for the file.
328  entry = State->Files.size();
329  RecordData Record;
330  Record.push_back(RECORD_FILENAME);
331  Record.push_back(entry);
332  Record.push_back(0); // For legacy.
333  Record.push_back(0); // For legacy.
334  StringRef Name(FileName);
335  Record.push_back(Name.size());
336  State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_FILENAME), Record,
337                                   Name);
338
339  return entry;
340}
341
342void SDiagsWriter::EmitCharSourceRange(CharSourceRange R,
343                                       const SourceManager &SM) {
344  State->Record.clear();
345  State->Record.push_back(RECORD_SOURCE_RANGE);
346  AddCharSourceRangeToRecord(R, State->Record, SM);
347  State->Stream.EmitRecordWithAbbrev(State->Abbrevs.get(RECORD_SOURCE_RANGE),
348                                     State->Record);
349}
350
351/// \brief Emits the preamble of the diagnostics file.
352void SDiagsWriter::EmitPreamble() {
353  // Emit the file header.
354  State->Stream.Emit((unsigned)'D', 8);
355  State->Stream.Emit((unsigned)'I', 8);
356  State->Stream.Emit((unsigned)'A', 8);
357  State->Stream.Emit((unsigned)'G', 8);
358
359  EmitBlockInfoBlock();
360  EmitMetaBlock();
361}
362
363static void AddSourceLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) {
364  using namespace llvm;
365  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // File ID.
366  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Line.
367  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Column.
368  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Offset;
369}
370
371static void AddRangeLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) {
372  AddSourceLocationAbbrev(Abbrev);
373  AddSourceLocationAbbrev(Abbrev);
374}
375
376void SDiagsWriter::EmitBlockInfoBlock() {
377  State->Stream.EnterBlockInfoBlock(3);
378
379  using namespace llvm;
380  llvm::BitstreamWriter &Stream = State->Stream;
381  RecordData &Record = State->Record;
382  AbbreviationMap &Abbrevs = State->Abbrevs;
383
384  // ==---------------------------------------------------------------------==//
385  // The subsequent records and Abbrevs are for the "Meta" block.
386  // ==---------------------------------------------------------------------==//
387
388  EmitBlockID(BLOCK_META, "Meta", Stream, Record);
389  EmitRecordID(RECORD_VERSION, "Version", Stream, Record);
390  BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
391  Abbrev->Add(BitCodeAbbrevOp(RECORD_VERSION));
392  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
393  Abbrevs.set(RECORD_VERSION, Stream.EmitBlockInfoAbbrev(BLOCK_META, Abbrev));
394
395  // ==---------------------------------------------------------------------==//
396  // The subsequent records and Abbrevs are for the "Diagnostic" block.
397  // ==---------------------------------------------------------------------==//
398
399  EmitBlockID(BLOCK_DIAG, "Diag", Stream, Record);
400  EmitRecordID(RECORD_DIAG, "DiagInfo", Stream, Record);
401  EmitRecordID(RECORD_SOURCE_RANGE, "SrcRange", Stream, Record);
402  EmitRecordID(RECORD_CATEGORY, "CatName", Stream, Record);
403  EmitRecordID(RECORD_DIAG_FLAG, "DiagFlag", Stream, Record);
404  EmitRecordID(RECORD_FILENAME, "FileName", Stream, Record);
405  EmitRecordID(RECORD_FIXIT, "FixIt", Stream, Record);
406
407  // Emit abbreviation for RECORD_DIAG.
408  Abbrev = new BitCodeAbbrev();
409  Abbrev->Add(BitCodeAbbrevOp(RECORD_DIAG));
410  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3));  // Diag level.
411  AddSourceLocationAbbrev(Abbrev);
412  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Category.
413  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped Diag ID.
414  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
415  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Diagnostc text.
416  Abbrevs.set(RECORD_DIAG, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
417
418  // Emit abbrevation for RECORD_CATEGORY.
419  Abbrev = new BitCodeAbbrev();
420  Abbrev->Add(BitCodeAbbrevOp(RECORD_CATEGORY));
421  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Category ID.
422  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8));  // Text size.
423  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));      // Category text.
424  Abbrevs.set(RECORD_CATEGORY, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
425
426  // Emit abbrevation for RECORD_SOURCE_RANGE.
427  Abbrev = new BitCodeAbbrev();
428  Abbrev->Add(BitCodeAbbrevOp(RECORD_SOURCE_RANGE));
429  AddRangeLocationAbbrev(Abbrev);
430  Abbrevs.set(RECORD_SOURCE_RANGE,
431              Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
432
433  // Emit the abbreviation for RECORD_DIAG_FLAG.
434  Abbrev = new BitCodeAbbrev();
435  Abbrev->Add(BitCodeAbbrevOp(RECORD_DIAG_FLAG));
436  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped Diag ID.
437  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
438  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Flag name text.
439  Abbrevs.set(RECORD_DIAG_FLAG, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
440                                                           Abbrev));
441
442  // Emit the abbreviation for RECORD_FILENAME.
443  Abbrev = new BitCodeAbbrev();
444  Abbrev->Add(BitCodeAbbrevOp(RECORD_FILENAME));
445  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped file ID.
446  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Size.
447  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Modifcation time.
448  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
449  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name text.
450  Abbrevs.set(RECORD_FILENAME, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
451                                                          Abbrev));
452
453  // Emit the abbreviation for RECORD_FIXIT.
454  Abbrev = new BitCodeAbbrev();
455  Abbrev->Add(BitCodeAbbrevOp(RECORD_FIXIT));
456  AddRangeLocationAbbrev(Abbrev);
457  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
458  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));      // FixIt text.
459  Abbrevs.set(RECORD_FIXIT, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
460                                                       Abbrev));
461
462  Stream.ExitBlock();
463}
464
465void SDiagsWriter::EmitMetaBlock() {
466  llvm::BitstreamWriter &Stream = State->Stream;
467  RecordData &Record = State->Record;
468  AbbreviationMap &Abbrevs = State->Abbrevs;
469
470  Stream.EnterSubblock(BLOCK_META, 3);
471  Record.clear();
472  Record.push_back(RECORD_VERSION);
473  Record.push_back(Version);
474  Stream.EmitRecordWithAbbrev(Abbrevs.get(RECORD_VERSION), Record);
475  Stream.ExitBlock();
476}
477
478unsigned SDiagsWriter::getEmitCategory(unsigned int category) {
479  if (State->Categories.count(category))
480    return category;
481
482  State->Categories.insert(category);
483
484  // We use a local version of 'Record' so that we can be generating
485  // another record when we lazily generate one for the category entry.
486  RecordData Record;
487  Record.push_back(RECORD_CATEGORY);
488  Record.push_back(category);
489  StringRef catName = DiagnosticIDs::getCategoryNameFromID(category);
490  Record.push_back(catName.size());
491  State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_CATEGORY), Record,
492                                   catName);
493
494  return category;
495}
496
497unsigned SDiagsWriter::getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
498                                             unsigned DiagID) {
499  if (DiagLevel == DiagnosticsEngine::Note)
500    return 0; // No flag for notes.
501
502  StringRef FlagName = DiagnosticIDs::getWarningOptionForDiag(DiagID);
503  if (FlagName.empty())
504    return 0;
505
506  // Here we assume that FlagName points to static data whose pointer
507  // value is fixed.  This allows us to unique by diagnostic groups.
508  const void *data = FlagName.data();
509  std::pair<unsigned, StringRef> &entry = State->DiagFlags[data];
510  if (entry.first == 0) {
511    entry.first = State->DiagFlags.size();
512    entry.second = FlagName;
513
514    // Lazily emit the string in a separate record.
515    RecordData Record;
516    Record.push_back(RECORD_DIAG_FLAG);
517    Record.push_back(entry.first);
518    Record.push_back(FlagName.size());
519    State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_DIAG_FLAG),
520                                     Record, FlagName);
521  }
522
523  return entry.first;
524}
525
526void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
527                                    const Diagnostic &Info) {
528  // Enter the block for a non-note diagnostic immediately, rather than waiting
529  // for beginDiagnostic, in case associated notes are emitted before we get
530  // there.
531  if (DiagLevel != DiagnosticsEngine::Note) {
532    if (State->EmittedAnyDiagBlocks)
533      ExitDiagBlock();
534
535    EnterDiagBlock();
536    State->EmittedAnyDiagBlocks = true;
537  }
538
539  // Compute the diagnostic text.
540  State->diagBuf.clear();
541  Info.FormatDiagnostic(State->diagBuf);
542
543  if (Info.getLocation().isInvalid()) {
544    // Special-case diagnostics with no location. We may not have entered a
545    // source file in this case, so we can't use the normal DiagnosticsRenderer
546    // machinery.
547    EmitDiagnosticMessage(SourceLocation(), PresumedLoc(), DiagLevel,
548                          State->diagBuf, 0, &Info);
549    return;
550  }
551
552  assert(Info.hasSourceManager() && LangOpts &&
553         "Unexpected diagnostic with valid location outside of a source file");
554  SDiagsRenderer Renderer(*this, *LangOpts, &*State->DiagOpts);
555  Renderer.emitDiagnostic(Info.getLocation(), DiagLevel,
556                          State->diagBuf.str(),
557                          Info.getRanges(),
558                          llvm::makeArrayRef(Info.getFixItHints(),
559                                             Info.getNumFixItHints()),
560                          &Info.getSourceManager(),
561                          &Info);
562}
563
564void SDiagsWriter::EmitDiagnosticMessage(SourceLocation Loc,
565                                         PresumedLoc PLoc,
566                                         DiagnosticsEngine::Level Level,
567                                         StringRef Message,
568                                         const SourceManager *SM,
569                                         DiagOrStoredDiag D) {
570  llvm::BitstreamWriter &Stream = State->Stream;
571  RecordData &Record = State->Record;
572  AbbreviationMap &Abbrevs = State->Abbrevs;
573
574  // Emit the RECORD_DIAG record.
575  Record.clear();
576  Record.push_back(RECORD_DIAG);
577  Record.push_back(Level);
578  AddLocToRecord(Loc, SM, PLoc, Record);
579
580  if (const Diagnostic *Info = D.dyn_cast<const Diagnostic*>()) {
581    // Emit the category string lazily and get the category ID.
582    unsigned DiagID = DiagnosticIDs::getCategoryNumberForDiag(Info->getID());
583    Record.push_back(getEmitCategory(DiagID));
584    // Emit the diagnostic flag string lazily and get the mapped ID.
585    Record.push_back(getEmitDiagnosticFlag(Level, Info->getID()));
586  } else {
587    Record.push_back(getEmitCategory());
588    Record.push_back(getEmitDiagnosticFlag(Level));
589  }
590
591  Record.push_back(Message.size());
592  Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG), Record, Message);
593}
594
595void
596SDiagsRenderer::emitDiagnosticMessage(SourceLocation Loc,
597                                      PresumedLoc PLoc,
598                                      DiagnosticsEngine::Level Level,
599                                      StringRef Message,
600                                      ArrayRef<clang::CharSourceRange> Ranges,
601                                      const SourceManager *SM,
602                                      DiagOrStoredDiag D) {
603  Writer.EmitDiagnosticMessage(Loc, PLoc, Level, Message, SM, D);
604}
605
606void SDiagsWriter::EnterDiagBlock() {
607  State->Stream.EnterSubblock(BLOCK_DIAG, 4);
608}
609
610void SDiagsWriter::ExitDiagBlock() {
611  State->Stream.ExitBlock();
612}
613
614void SDiagsRenderer::beginDiagnostic(DiagOrStoredDiag D,
615                                     DiagnosticsEngine::Level Level) {
616  if (Level == DiagnosticsEngine::Note)
617    Writer.EnterDiagBlock();
618}
619
620void SDiagsRenderer::endDiagnostic(DiagOrStoredDiag D,
621                                   DiagnosticsEngine::Level Level) {
622  // Only end note diagnostics here, because we can't be sure when we've seen
623  // the last note associated with a non-note diagnostic.
624  if (Level == DiagnosticsEngine::Note)
625    Writer.ExitDiagBlock();
626}
627
628void SDiagsWriter::EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges,
629                                   ArrayRef<FixItHint> Hints,
630                                   const SourceManager &SM) {
631  llvm::BitstreamWriter &Stream = State->Stream;
632  RecordData &Record = State->Record;
633  AbbreviationMap &Abbrevs = State->Abbrevs;
634
635  // Emit Source Ranges.
636  for (ArrayRef<CharSourceRange>::iterator I = Ranges.begin(), E = Ranges.end();
637       I != E; ++I)
638    if (I->isValid())
639      EmitCharSourceRange(*I, SM);
640
641  // Emit FixIts.
642  for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end();
643       I != E; ++I) {
644    const FixItHint &Fix = *I;
645    if (Fix.isNull())
646      continue;
647    Record.clear();
648    Record.push_back(RECORD_FIXIT);
649    AddCharSourceRangeToRecord(Fix.RemoveRange, Record, SM);
650    Record.push_back(Fix.CodeToInsert.size());
651    Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_FIXIT), Record,
652                              Fix.CodeToInsert);
653  }
654}
655
656void SDiagsRenderer::emitCodeContext(SourceLocation Loc,
657                                     DiagnosticsEngine::Level Level,
658                                     SmallVectorImpl<CharSourceRange> &Ranges,
659                                     ArrayRef<FixItHint> Hints,
660                                     const SourceManager &SM) {
661  Writer.EmitCodeContext(Ranges, Hints, SM);
662}
663
664void SDiagsRenderer::emitNote(SourceLocation Loc, StringRef Message,
665                              const SourceManager *SM) {
666  Writer.EnterDiagBlock();
667  PresumedLoc PLoc = SM ? SM->getPresumedLoc(Loc) : PresumedLoc();
668  Writer.EmitDiagnosticMessage(Loc, PLoc, DiagnosticsEngine::Note,
669                               Message, SM, DiagOrStoredDiag());
670  Writer.ExitDiagBlock();
671}
672
673void SDiagsWriter::finish() {
674  // The original instance is responsible for writing the file.
675  if (!OriginalInstance)
676    return;
677
678  // Finish off any diagnostic we were in the process of emitting.
679  if (State->EmittedAnyDiagBlocks)
680    ExitDiagBlock();
681
682  // Write the generated bitstream to "Out".
683  State->OS->write((char *)&State->Buffer.front(), State->Buffer.size());
684  State->OS->flush();
685
686  State->OS.reset(0);
687}
688