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