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