SerializedDiagnosticPrinter.cpp revision 249423
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
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 SmallVector<uint64_t, 64> RecordData;
48typedef 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(IntrusiveRefCntPtr<SharedState> State)
96    : LangOpts(0), OriginalInstance(false), State(State) { }
97
98public:
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
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 : 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
241namespace clang {
242namespace serialized_diags {
243DiagnosticConsumer *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.
254static 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.
274static 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
286void 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
306void 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
318unsigned 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
341void 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.
351void 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
362static 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
370static void AddRangeLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) {
371  AddSourceLocationAbbrev(Abbrev);
372  AddSourceLocationAbbrev(Abbrev);
373}
374
375void 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
464void 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
477unsigned 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
496unsigned 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
525void 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
573void 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
604void
605SDiagsRenderer::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
615void SDiagsWriter::EnterDiagBlock() {
616  State->Stream.EnterSubblock(BLOCK_DIAG, 4);
617}
618
619void SDiagsWriter::ExitDiagBlock() {
620  State->Stream.ExitBlock();
621}
622
623void SDiagsRenderer::beginDiagnostic(DiagOrStoredDiag D,
624                                     DiagnosticsEngine::Level Level) {
625  if (Level == DiagnosticsEngine::Note)
626    Writer.EnterDiagBlock();
627}
628
629void 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
637void 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
665void 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
673void 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
682void 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