1 //===--- SerializedDiagnosticPrinter.cpp - Serializer for diagnostics -----===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "clang/Frontend/SerializedDiagnosticPrinter.h"
10 #include "clang/Basic/Diagnostic.h"
11 #include "clang/Basic/DiagnosticOptions.h"
12 #include "clang/Basic/SourceManager.h"
13 #include "clang/Frontend/DiagnosticRenderer.h"
14 #include "clang/Frontend/FrontendDiagnostic.h"
15 #include "clang/Frontend/SerializedDiagnosticReader.h"
16 #include "clang/Frontend/SerializedDiagnostics.h"
17 #include "clang/Frontend/TextDiagnosticPrinter.h"
18 #include "clang/Lex/Lexer.h"
19 #include "llvm/ADT/DenseSet.h"
20 #include "llvm/ADT/STLExtras.h"
21 #include "llvm/ADT/SmallString.h"
22 #include "llvm/ADT/StringRef.h"
23 #include "llvm/Support/raw_ostream.h"
24 #include <utility>
25 
26 using namespace clang;
27 using namespace clang::serialized_diags;
28 
29 namespace {
30 
31 class AbbreviationMap {
32   llvm::DenseMap<unsigned, unsigned> Abbrevs;
33 public:
34   AbbreviationMap() {}
35 
36   void set(unsigned recordID, unsigned abbrevID) {
37     assert(Abbrevs.find(recordID) == Abbrevs.end()
38            && "Abbreviation already set.");
39     Abbrevs[recordID] = abbrevID;
40   }
41 
42   unsigned get(unsigned recordID) {
43     assert(Abbrevs.find(recordID) != Abbrevs.end() &&
44            "Abbreviation not set.");
45     return Abbrevs[recordID];
46   }
47 };
48 
49 typedef SmallVector<uint64_t, 64> RecordData;
50 typedef SmallVectorImpl<uint64_t> RecordDataImpl;
51 typedef ArrayRef<uint64_t> RecordDataRef;
52 
53 class SDiagsWriter;
54 
55 class SDiagsRenderer : public DiagnosticNoteRenderer {
56   SDiagsWriter &Writer;
57 public:
58   SDiagsRenderer(SDiagsWriter &Writer, const LangOptions &LangOpts,
59                  DiagnosticOptions *DiagOpts)
60     : DiagnosticNoteRenderer(LangOpts, DiagOpts), Writer(Writer) {}
61 
62   ~SDiagsRenderer() override {}
63 
64 protected:
65   void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
66                              DiagnosticsEngine::Level Level, StringRef Message,
67                              ArrayRef<CharSourceRange> Ranges,
68                              DiagOrStoredDiag D) override;
69 
70   void emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
71                          DiagnosticsEngine::Level Level,
72                          ArrayRef<CharSourceRange> Ranges) override {}
73 
74   void emitNote(FullSourceLoc Loc, StringRef Message) override;
75 
76   void emitCodeContext(FullSourceLoc Loc, DiagnosticsEngine::Level Level,
77                        SmallVectorImpl<CharSourceRange> &Ranges,
78                        ArrayRef<FixItHint> Hints) override;
79 
80   void beginDiagnostic(DiagOrStoredDiag D,
81                        DiagnosticsEngine::Level Level) override;
82   void endDiagnostic(DiagOrStoredDiag D,
83                      DiagnosticsEngine::Level Level) override;
84 };
85 
86 typedef llvm::DenseMap<unsigned, unsigned> AbbrevLookup;
87 
88 class SDiagsMerger : SerializedDiagnosticReader {
89   SDiagsWriter &Writer;
90   AbbrevLookup FileLookup;
91   AbbrevLookup CategoryLookup;
92   AbbrevLookup DiagFlagLookup;
93 
94 public:
95   SDiagsMerger(SDiagsWriter &Writer)
96       : SerializedDiagnosticReader(), Writer(Writer) {}
97 
98   std::error_code mergeRecordsFromFile(const char *File) {
99     return readDiagnostics(File);
100   }
101 
102 protected:
103   std::error_code visitStartOfDiagnostic() override;
104   std::error_code visitEndOfDiagnostic() override;
105   std::error_code visitCategoryRecord(unsigned ID, StringRef Name) override;
106   std::error_code visitDiagFlagRecord(unsigned ID, StringRef Name) override;
107   std::error_code visitDiagnosticRecord(
108       unsigned Severity, const serialized_diags::Location &Location,
109       unsigned Category, unsigned Flag, StringRef Message) override;
110   std::error_code visitFilenameRecord(unsigned ID, unsigned Size,
111                                       unsigned Timestamp,
112                                       StringRef Name) override;
113   std::error_code visitFixitRecord(const serialized_diags::Location &Start,
114                                    const serialized_diags::Location &End,
115                                    StringRef CodeToInsert) override;
116   std::error_code
117   visitSourceRangeRecord(const serialized_diags::Location &Start,
118                          const serialized_diags::Location &End) override;
119 
120 private:
121   std::error_code adjustSourceLocFilename(RecordData &Record,
122                                           unsigned int offset);
123 
124   void adjustAbbrevID(RecordData &Record, AbbrevLookup &Lookup,
125                       unsigned NewAbbrev);
126 
127   void writeRecordWithAbbrev(unsigned ID, RecordData &Record);
128 
129   void writeRecordWithBlob(unsigned ID, RecordData &Record, StringRef Blob);
130 };
131 
132 class SDiagsWriter : public DiagnosticConsumer {
133   friend class SDiagsRenderer;
134   friend class SDiagsMerger;
135 
136   struct SharedState;
137 
138   explicit SDiagsWriter(std::shared_ptr<SharedState> State)
139       : LangOpts(nullptr), OriginalInstance(false), MergeChildRecords(false),
140         State(std::move(State)) {}
141 
142 public:
143   SDiagsWriter(StringRef File, DiagnosticOptions *Diags, bool MergeChildRecords)
144       : LangOpts(nullptr), OriginalInstance(true),
145         MergeChildRecords(MergeChildRecords),
146         State(std::make_shared<SharedState>(File, Diags)) {
147     if (MergeChildRecords)
148       RemoveOldDiagnostics();
149     EmitPreamble();
150   }
151 
152   ~SDiagsWriter() override {}
153 
154   void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
155                         const Diagnostic &Info) override;
156 
157   void BeginSourceFile(const LangOptions &LO, const Preprocessor *PP) override {
158     LangOpts = &LO;
159   }
160 
161   void finish() override;
162 
163 private:
164   /// Build a DiagnosticsEngine to emit diagnostics about the diagnostics
165   DiagnosticsEngine *getMetaDiags();
166 
167   /// Remove old copies of the serialized diagnostics. This is necessary
168   /// so that we can detect when subprocesses write diagnostics that we should
169   /// merge into our own.
170   void RemoveOldDiagnostics();
171 
172   /// Emit the preamble for the serialized diagnostics.
173   void EmitPreamble();
174 
175   /// Emit the BLOCKINFO block.
176   void EmitBlockInfoBlock();
177 
178   /// Emit the META data block.
179   void EmitMetaBlock();
180 
181   /// Start a DIAG block.
182   void EnterDiagBlock();
183 
184   /// End a DIAG block.
185   void ExitDiagBlock();
186 
187   /// Emit a DIAG record.
188   void EmitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
189                              DiagnosticsEngine::Level Level, StringRef Message,
190                              DiagOrStoredDiag D);
191 
192   /// Emit FIXIT and SOURCE_RANGE records for a diagnostic.
193   void EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges,
194                        ArrayRef<FixItHint> Hints,
195                        const SourceManager &SM);
196 
197   /// Emit a record for a CharSourceRange.
198   void EmitCharSourceRange(CharSourceRange R, const SourceManager &SM);
199 
200   /// Emit the string information for the category.
201   unsigned getEmitCategory(unsigned category = 0);
202 
203   /// Emit the string information for diagnostic flags.
204   unsigned getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
205                                  unsigned DiagID = 0);
206 
207   unsigned getEmitDiagnosticFlag(StringRef DiagName);
208 
209   /// Emit (lazily) the file string and retrieved the file identifier.
210   unsigned getEmitFile(const char *Filename);
211 
212   /// Add SourceLocation information the specified record.
213   void AddLocToRecord(FullSourceLoc Loc, PresumedLoc PLoc,
214                       RecordDataImpl &Record, unsigned TokSize = 0);
215 
216   /// Add SourceLocation information the specified record.
217   void AddLocToRecord(FullSourceLoc Loc, RecordDataImpl &Record,
218                       unsigned TokSize = 0) {
219     AddLocToRecord(Loc, Loc.hasManager() ? Loc.getPresumedLoc() : PresumedLoc(),
220                    Record, TokSize);
221   }
222 
223   /// Add CharSourceRange information the specified record.
224   void AddCharSourceRangeToRecord(CharSourceRange R, RecordDataImpl &Record,
225                                   const SourceManager &SM);
226 
227   /// Language options, which can differ from one clone of this client
228   /// to another.
229   const LangOptions *LangOpts;
230 
231   /// Whether this is the original instance (rather than one of its
232   /// clones), responsible for writing the file at the end.
233   bool OriginalInstance;
234 
235   /// Whether this instance should aggregate diagnostics that are
236   /// generated from child processes.
237   bool MergeChildRecords;
238 
239   /// State that is shared among the various clones of this diagnostic
240   /// consumer.
241   struct SharedState {
242     SharedState(StringRef File, DiagnosticOptions *Diags)
243         : DiagOpts(Diags), Stream(Buffer), OutputFile(File.str()),
244           EmittedAnyDiagBlocks(false) {}
245 
246     /// Diagnostic options.
247     IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
248 
249     /// The byte buffer for the serialized content.
250     SmallString<1024> Buffer;
251 
252     /// The BitStreamWriter for the serialized diagnostics.
253     llvm::BitstreamWriter Stream;
254 
255     /// The name of the diagnostics file.
256     std::string OutputFile;
257 
258     /// The set of constructed record abbreviations.
259     AbbreviationMap Abbrevs;
260 
261     /// A utility buffer for constructing record content.
262     RecordData Record;
263 
264     /// A text buffer for rendering diagnostic text.
265     SmallString<256> diagBuf;
266 
267     /// The collection of diagnostic categories used.
268     llvm::DenseSet<unsigned> Categories;
269 
270     /// The collection of files used.
271     llvm::DenseMap<const char *, unsigned> Files;
272 
273     typedef llvm::DenseMap<const void *, std::pair<unsigned, StringRef> >
274     DiagFlagsTy;
275 
276     /// Map for uniquing strings.
277     DiagFlagsTy DiagFlags;
278 
279     /// Whether we have already started emission of any DIAG blocks. Once
280     /// this becomes \c true, we never close a DIAG block until we know that we're
281     /// starting another one or we're done.
282     bool EmittedAnyDiagBlocks;
283 
284     /// Engine for emitting diagnostics about the diagnostics.
285     std::unique_ptr<DiagnosticsEngine> MetaDiagnostics;
286   };
287 
288   /// State shared among the various clones of this diagnostic consumer.
289   std::shared_ptr<SharedState> State;
290 };
291 } // end anonymous namespace
292 
293 namespace clang {
294 namespace serialized_diags {
295 std::unique_ptr<DiagnosticConsumer>
296 create(StringRef OutputFile, DiagnosticOptions *Diags, bool MergeChildRecords) {
297   return llvm::make_unique<SDiagsWriter>(OutputFile, Diags, MergeChildRecords);
298 }
299 
300 } // end namespace serialized_diags
301 } // end namespace clang
302 
303 //===----------------------------------------------------------------------===//
304 // Serialization methods.
305 //===----------------------------------------------------------------------===//
306 
307 /// Emits a block ID in the BLOCKINFO block.
308 static void EmitBlockID(unsigned ID, const char *Name,
309                         llvm::BitstreamWriter &Stream,
310                         RecordDataImpl &Record) {
311   Record.clear();
312   Record.push_back(ID);
313   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
314 
315   // Emit the block name if present.
316   if (!Name || Name[0] == 0)
317     return;
318 
319   Record.clear();
320 
321   while (*Name)
322     Record.push_back(*Name++);
323 
324   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record);
325 }
326 
327 /// Emits a record ID in the BLOCKINFO block.
328 static void EmitRecordID(unsigned ID, const char *Name,
329                          llvm::BitstreamWriter &Stream,
330                          RecordDataImpl &Record){
331   Record.clear();
332   Record.push_back(ID);
333 
334   while (*Name)
335     Record.push_back(*Name++);
336 
337   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
338 }
339 
340 void SDiagsWriter::AddLocToRecord(FullSourceLoc Loc, PresumedLoc PLoc,
341                                   RecordDataImpl &Record, unsigned TokSize) {
342   if (PLoc.isInvalid()) {
343     // Emit a "sentinel" location.
344     Record.push_back((unsigned)0); // File.
345     Record.push_back((unsigned)0); // Line.
346     Record.push_back((unsigned)0); // Column.
347     Record.push_back((unsigned)0); // Offset.
348     return;
349   }
350 
351   Record.push_back(getEmitFile(PLoc.getFilename()));
352   Record.push_back(PLoc.getLine());
353   Record.push_back(PLoc.getColumn()+TokSize);
354   Record.push_back(Loc.getFileOffset());
355 }
356 
357 void SDiagsWriter::AddCharSourceRangeToRecord(CharSourceRange Range,
358                                               RecordDataImpl &Record,
359                                               const SourceManager &SM) {
360   AddLocToRecord(FullSourceLoc(Range.getBegin(), SM), Record);
361   unsigned TokSize = 0;
362   if (Range.isTokenRange())
363     TokSize = Lexer::MeasureTokenLength(Range.getEnd(),
364                                         SM, *LangOpts);
365 
366   AddLocToRecord(FullSourceLoc(Range.getEnd(), SM), Record, TokSize);
367 }
368 
369 unsigned SDiagsWriter::getEmitFile(const char *FileName){
370   if (!FileName)
371     return 0;
372 
373   unsigned &entry = State->Files[FileName];
374   if (entry)
375     return entry;
376 
377   // Lazily generate the record for the file.
378   entry = State->Files.size();
379   StringRef Name(FileName);
380   RecordData::value_type Record[] = {RECORD_FILENAME, entry, 0 /* For legacy */,
381                                      0 /* For legacy */, Name.size()};
382   State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_FILENAME), Record,
383                                    Name);
384 
385   return entry;
386 }
387 
388 void SDiagsWriter::EmitCharSourceRange(CharSourceRange R,
389                                        const SourceManager &SM) {
390   State->Record.clear();
391   State->Record.push_back(RECORD_SOURCE_RANGE);
392   AddCharSourceRangeToRecord(R, State->Record, SM);
393   State->Stream.EmitRecordWithAbbrev(State->Abbrevs.get(RECORD_SOURCE_RANGE),
394                                      State->Record);
395 }
396 
397 /// Emits the preamble of the diagnostics file.
398 void SDiagsWriter::EmitPreamble() {
399   // Emit the file header.
400   State->Stream.Emit((unsigned)'D', 8);
401   State->Stream.Emit((unsigned)'I', 8);
402   State->Stream.Emit((unsigned)'A', 8);
403   State->Stream.Emit((unsigned)'G', 8);
404 
405   EmitBlockInfoBlock();
406   EmitMetaBlock();
407 }
408 
409 static void AddSourceLocationAbbrev(llvm::BitCodeAbbrev &Abbrev) {
410   using namespace llvm;
411   Abbrev.Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // File ID.
412   Abbrev.Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Line.
413   Abbrev.Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Column.
414   Abbrev.Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Offset;
415 }
416 
417 static void AddRangeLocationAbbrev(llvm::BitCodeAbbrev &Abbrev) {
418   AddSourceLocationAbbrev(Abbrev);
419   AddSourceLocationAbbrev(Abbrev);
420 }
421 
422 void SDiagsWriter::EmitBlockInfoBlock() {
423   State->Stream.EnterBlockInfoBlock();
424 
425   using namespace llvm;
426   llvm::BitstreamWriter &Stream = State->Stream;
427   RecordData &Record = State->Record;
428   AbbreviationMap &Abbrevs = State->Abbrevs;
429 
430   // ==---------------------------------------------------------------------==//
431   // The subsequent records and Abbrevs are for the "Meta" block.
432   // ==---------------------------------------------------------------------==//
433 
434   EmitBlockID(BLOCK_META, "Meta", Stream, Record);
435   EmitRecordID(RECORD_VERSION, "Version", Stream, Record);
436   auto Abbrev = std::make_shared<BitCodeAbbrev>();
437   Abbrev->Add(BitCodeAbbrevOp(RECORD_VERSION));
438   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
439   Abbrevs.set(RECORD_VERSION, Stream.EmitBlockInfoAbbrev(BLOCK_META, Abbrev));
440 
441   // ==---------------------------------------------------------------------==//
442   // The subsequent records and Abbrevs are for the "Diagnostic" block.
443   // ==---------------------------------------------------------------------==//
444 
445   EmitBlockID(BLOCK_DIAG, "Diag", Stream, Record);
446   EmitRecordID(RECORD_DIAG, "DiagInfo", Stream, Record);
447   EmitRecordID(RECORD_SOURCE_RANGE, "SrcRange", Stream, Record);
448   EmitRecordID(RECORD_CATEGORY, "CatName", Stream, Record);
449   EmitRecordID(RECORD_DIAG_FLAG, "DiagFlag", Stream, Record);
450   EmitRecordID(RECORD_FILENAME, "FileName", Stream, Record);
451   EmitRecordID(RECORD_FIXIT, "FixIt", Stream, Record);
452 
453   // Emit abbreviation for RECORD_DIAG.
454   Abbrev = std::make_shared<BitCodeAbbrev>();
455   Abbrev->Add(BitCodeAbbrevOp(RECORD_DIAG));
456   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3));  // Diag level.
457   AddSourceLocationAbbrev(*Abbrev);
458   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Category.
459   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped Diag ID.
460   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // Text size.
461   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Diagnostc text.
462   Abbrevs.set(RECORD_DIAG, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
463 
464   // Emit abbreviation for RECORD_CATEGORY.
465   Abbrev = std::make_shared<BitCodeAbbrev>();
466   Abbrev->Add(BitCodeAbbrevOp(RECORD_CATEGORY));
467   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Category ID.
468   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8));  // Text size.
469   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));      // Category text.
470   Abbrevs.set(RECORD_CATEGORY, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
471 
472   // Emit abbreviation for RECORD_SOURCE_RANGE.
473   Abbrev = std::make_shared<BitCodeAbbrev>();
474   Abbrev->Add(BitCodeAbbrevOp(RECORD_SOURCE_RANGE));
475   AddRangeLocationAbbrev(*Abbrev);
476   Abbrevs.set(RECORD_SOURCE_RANGE,
477               Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
478 
479   // Emit the abbreviation for RECORD_DIAG_FLAG.
480   Abbrev = std::make_shared<BitCodeAbbrev>();
481   Abbrev->Add(BitCodeAbbrevOp(RECORD_DIAG_FLAG));
482   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped Diag ID.
483   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
484   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Flag name text.
485   Abbrevs.set(RECORD_DIAG_FLAG, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
486                                                            Abbrev));
487 
488   // Emit the abbreviation for RECORD_FILENAME.
489   Abbrev = std::make_shared<BitCodeAbbrev>();
490   Abbrev->Add(BitCodeAbbrevOp(RECORD_FILENAME));
491   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped file ID.
492   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Size.
493   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Modification time.
494   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
495   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name text.
496   Abbrevs.set(RECORD_FILENAME, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
497                                                           Abbrev));
498 
499   // Emit the abbreviation for RECORD_FIXIT.
500   Abbrev = std::make_shared<BitCodeAbbrev>();
501   Abbrev->Add(BitCodeAbbrevOp(RECORD_FIXIT));
502   AddRangeLocationAbbrev(*Abbrev);
503   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
504   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));      // FixIt text.
505   Abbrevs.set(RECORD_FIXIT, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
506                                                        Abbrev));
507 
508   Stream.ExitBlock();
509 }
510 
511 void SDiagsWriter::EmitMetaBlock() {
512   llvm::BitstreamWriter &Stream = State->Stream;
513   AbbreviationMap &Abbrevs = State->Abbrevs;
514 
515   Stream.EnterSubblock(BLOCK_META, 3);
516   RecordData::value_type Record[] = {RECORD_VERSION, VersionNumber};
517   Stream.EmitRecordWithAbbrev(Abbrevs.get(RECORD_VERSION), Record);
518   Stream.ExitBlock();
519 }
520 
521 unsigned SDiagsWriter::getEmitCategory(unsigned int category) {
522   if (!State->Categories.insert(category).second)
523     return category;
524 
525   // We use a local version of 'Record' so that we can be generating
526   // another record when we lazily generate one for the category entry.
527   StringRef catName = DiagnosticIDs::getCategoryNameFromID(category);
528   RecordData::value_type Record[] = {RECORD_CATEGORY, category, catName.size()};
529   State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_CATEGORY), Record,
530                                    catName);
531 
532   return category;
533 }
534 
535 unsigned SDiagsWriter::getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
536                                              unsigned DiagID) {
537   if (DiagLevel == DiagnosticsEngine::Note)
538     return 0; // No flag for notes.
539 
540   StringRef FlagName = DiagnosticIDs::getWarningOptionForDiag(DiagID);
541   return getEmitDiagnosticFlag(FlagName);
542 }
543 
544 unsigned SDiagsWriter::getEmitDiagnosticFlag(StringRef FlagName) {
545   if (FlagName.empty())
546     return 0;
547 
548   // Here we assume that FlagName points to static data whose pointer
549   // value is fixed.  This allows us to unique by diagnostic groups.
550   const void *data = FlagName.data();
551   std::pair<unsigned, StringRef> &entry = State->DiagFlags[data];
552   if (entry.first == 0) {
553     entry.first = State->DiagFlags.size();
554     entry.second = FlagName;
555 
556     // Lazily emit the string in a separate record.
557     RecordData::value_type Record[] = {RECORD_DIAG_FLAG, entry.first,
558                                        FlagName.size()};
559     State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_DIAG_FLAG),
560                                      Record, FlagName);
561   }
562 
563   return entry.first;
564 }
565 
566 void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
567                                     const Diagnostic &Info) {
568   // Enter the block for a non-note diagnostic immediately, rather than waiting
569   // for beginDiagnostic, in case associated notes are emitted before we get
570   // there.
571   if (DiagLevel != DiagnosticsEngine::Note) {
572     if (State->EmittedAnyDiagBlocks)
573       ExitDiagBlock();
574 
575     EnterDiagBlock();
576     State->EmittedAnyDiagBlocks = true;
577   }
578 
579   // Compute the diagnostic text.
580   State->diagBuf.clear();
581   Info.FormatDiagnostic(State->diagBuf);
582 
583   if (Info.getLocation().isInvalid()) {
584     // Special-case diagnostics with no location. We may not have entered a
585     // source file in this case, so we can't use the normal DiagnosticsRenderer
586     // machinery.
587 
588     // Make sure we bracket all notes as "sub-diagnostics".  This matches
589     // the behavior in SDiagsRenderer::emitDiagnostic().
590     if (DiagLevel == DiagnosticsEngine::Note)
591       EnterDiagBlock();
592 
593     EmitDiagnosticMessage(FullSourceLoc(), PresumedLoc(), DiagLevel,
594                           State->diagBuf, &Info);
595 
596     if (DiagLevel == DiagnosticsEngine::Note)
597       ExitDiagBlock();
598 
599     return;
600   }
601 
602   assert(Info.hasSourceManager() && LangOpts &&
603          "Unexpected diagnostic with valid location outside of a source file");
604   SDiagsRenderer Renderer(*this, *LangOpts, &*State->DiagOpts);
605   Renderer.emitDiagnostic(
606       FullSourceLoc(Info.getLocation(), Info.getSourceManager()), DiagLevel,
607       State->diagBuf, Info.getRanges(), Info.getFixItHints(), &Info);
608 }
609 
610 static serialized_diags::Level getStableLevel(DiagnosticsEngine::Level Level) {
611   switch (Level) {
612 #define CASE(X) case DiagnosticsEngine::X: return serialized_diags::X;
613   CASE(Ignored)
614   CASE(Note)
615   CASE(Remark)
616   CASE(Warning)
617   CASE(Error)
618   CASE(Fatal)
619 #undef CASE
620   }
621 
622   llvm_unreachable("invalid diagnostic level");
623 }
624 
625 void SDiagsWriter::EmitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
626                                          DiagnosticsEngine::Level Level,
627                                          StringRef Message,
628                                          DiagOrStoredDiag D) {
629   llvm::BitstreamWriter &Stream = State->Stream;
630   RecordData &Record = State->Record;
631   AbbreviationMap &Abbrevs = State->Abbrevs;
632 
633   // Emit the RECORD_DIAG record.
634   Record.clear();
635   Record.push_back(RECORD_DIAG);
636   Record.push_back(getStableLevel(Level));
637   AddLocToRecord(Loc, PLoc, Record);
638 
639   if (const Diagnostic *Info = D.dyn_cast<const Diagnostic*>()) {
640     // Emit the category string lazily and get the category ID.
641     unsigned DiagID = DiagnosticIDs::getCategoryNumberForDiag(Info->getID());
642     Record.push_back(getEmitCategory(DiagID));
643     // Emit the diagnostic flag string lazily and get the mapped ID.
644     Record.push_back(getEmitDiagnosticFlag(Level, Info->getID()));
645   } else {
646     Record.push_back(getEmitCategory());
647     Record.push_back(getEmitDiagnosticFlag(Level));
648   }
649 
650   Record.push_back(Message.size());
651   Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG), Record, Message);
652 }
653 
654 void SDiagsRenderer::emitDiagnosticMessage(
655     FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level,
656     StringRef Message, ArrayRef<clang::CharSourceRange> Ranges,
657     DiagOrStoredDiag D) {
658   Writer.EmitDiagnosticMessage(Loc, PLoc, Level, Message, D);
659 }
660 
661 void SDiagsWriter::EnterDiagBlock() {
662   State->Stream.EnterSubblock(BLOCK_DIAG, 4);
663 }
664 
665 void SDiagsWriter::ExitDiagBlock() {
666   State->Stream.ExitBlock();
667 }
668 
669 void SDiagsRenderer::beginDiagnostic(DiagOrStoredDiag D,
670                                      DiagnosticsEngine::Level Level) {
671   if (Level == DiagnosticsEngine::Note)
672     Writer.EnterDiagBlock();
673 }
674 
675 void SDiagsRenderer::endDiagnostic(DiagOrStoredDiag D,
676                                    DiagnosticsEngine::Level Level) {
677   // Only end note diagnostics here, because we can't be sure when we've seen
678   // the last note associated with a non-note diagnostic.
679   if (Level == DiagnosticsEngine::Note)
680     Writer.ExitDiagBlock();
681 }
682 
683 void SDiagsWriter::EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges,
684                                    ArrayRef<FixItHint> Hints,
685                                    const SourceManager &SM) {
686   llvm::BitstreamWriter &Stream = State->Stream;
687   RecordData &Record = State->Record;
688   AbbreviationMap &Abbrevs = State->Abbrevs;
689 
690   // Emit Source Ranges.
691   for (ArrayRef<CharSourceRange>::iterator I = Ranges.begin(), E = Ranges.end();
692        I != E; ++I)
693     if (I->isValid())
694       EmitCharSourceRange(*I, SM);
695 
696   // Emit FixIts.
697   for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end();
698        I != E; ++I) {
699     const FixItHint &Fix = *I;
700     if (Fix.isNull())
701       continue;
702     Record.clear();
703     Record.push_back(RECORD_FIXIT);
704     AddCharSourceRangeToRecord(Fix.RemoveRange, Record, SM);
705     Record.push_back(Fix.CodeToInsert.size());
706     Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_FIXIT), Record,
707                               Fix.CodeToInsert);
708   }
709 }
710 
711 void SDiagsRenderer::emitCodeContext(FullSourceLoc Loc,
712                                      DiagnosticsEngine::Level Level,
713                                      SmallVectorImpl<CharSourceRange> &Ranges,
714                                      ArrayRef<FixItHint> Hints) {
715   Writer.EmitCodeContext(Ranges, Hints, Loc.getManager());
716 }
717 
718 void SDiagsRenderer::emitNote(FullSourceLoc Loc, StringRef Message) {
719   Writer.EnterDiagBlock();
720   PresumedLoc PLoc = Loc.hasManager() ? Loc.getPresumedLoc() : PresumedLoc();
721   Writer.EmitDiagnosticMessage(Loc, PLoc, DiagnosticsEngine::Note, Message,
722                                DiagOrStoredDiag());
723   Writer.ExitDiagBlock();
724 }
725 
726 DiagnosticsEngine *SDiagsWriter::getMetaDiags() {
727   // FIXME: It's slightly absurd to create a new diagnostics engine here, but
728   // the other options that are available today are worse:
729   //
730   // 1. Teach DiagnosticsConsumers to emit diagnostics to the engine they are a
731   //    part of. The DiagnosticsEngine would need to know not to send
732   //    diagnostics back to the consumer that failed. This would require us to
733   //    rework ChainedDiagnosticsConsumer and teach the engine about multiple
734   //    consumers, which is difficult today because most APIs interface with
735   //    consumers rather than the engine itself.
736   //
737   // 2. Pass a DiagnosticsEngine to SDiagsWriter on creation - this would need
738   //    to be distinct from the engine the writer was being added to and would
739   //    normally not be used.
740   if (!State->MetaDiagnostics) {
741     IntrusiveRefCntPtr<DiagnosticIDs> IDs(new DiagnosticIDs());
742     auto Client =
743         new TextDiagnosticPrinter(llvm::errs(), State->DiagOpts.get());
744     State->MetaDiagnostics = llvm::make_unique<DiagnosticsEngine>(
745         IDs, State->DiagOpts.get(), Client);
746   }
747   return State->MetaDiagnostics.get();
748 }
749 
750 void SDiagsWriter::RemoveOldDiagnostics() {
751   if (!llvm::sys::fs::remove(State->OutputFile))
752     return;
753 
754   getMetaDiags()->Report(diag::warn_fe_serialized_diag_merge_failure);
755   // Disable merging child records, as whatever is in this file may be
756   // misleading.
757   MergeChildRecords = false;
758 }
759 
760 void SDiagsWriter::finish() {
761   // The original instance is responsible for writing the file.
762   if (!OriginalInstance)
763     return;
764 
765   // Finish off any diagnostic we were in the process of emitting.
766   if (State->EmittedAnyDiagBlocks)
767     ExitDiagBlock();
768 
769   if (MergeChildRecords) {
770     if (!State->EmittedAnyDiagBlocks)
771       // We have no diagnostics of our own, so we can just leave the child
772       // process' output alone
773       return;
774 
775     if (llvm::sys::fs::exists(State->OutputFile))
776       if (SDiagsMerger(*this).mergeRecordsFromFile(State->OutputFile.c_str()))
777         getMetaDiags()->Report(diag::warn_fe_serialized_diag_merge_failure);
778   }
779 
780   std::error_code EC;
781   auto OS = llvm::make_unique<llvm::raw_fd_ostream>(State->OutputFile.c_str(),
782                                                     EC, llvm::sys::fs::F_None);
783   if (EC) {
784     getMetaDiags()->Report(diag::warn_fe_serialized_diag_failure)
785         << State->OutputFile << EC.message();
786     return;
787   }
788 
789   // Write the generated bitstream to "Out".
790   OS->write((char *)&State->Buffer.front(), State->Buffer.size());
791   OS->flush();
792 }
793 
794 std::error_code SDiagsMerger::visitStartOfDiagnostic() {
795   Writer.EnterDiagBlock();
796   return std::error_code();
797 }
798 
799 std::error_code SDiagsMerger::visitEndOfDiagnostic() {
800   Writer.ExitDiagBlock();
801   return std::error_code();
802 }
803 
804 std::error_code
805 SDiagsMerger::visitSourceRangeRecord(const serialized_diags::Location &Start,
806                                      const serialized_diags::Location &End) {
807   RecordData::value_type Record[] = {
808       RECORD_SOURCE_RANGE, FileLookup[Start.FileID], Start.Line, Start.Col,
809       Start.Offset, FileLookup[End.FileID], End.Line, End.Col, End.Offset};
810   Writer.State->Stream.EmitRecordWithAbbrev(
811       Writer.State->Abbrevs.get(RECORD_SOURCE_RANGE), Record);
812   return std::error_code();
813 }
814 
815 std::error_code SDiagsMerger::visitDiagnosticRecord(
816     unsigned Severity, const serialized_diags::Location &Location,
817     unsigned Category, unsigned Flag, StringRef Message) {
818   RecordData::value_type Record[] = {
819       RECORD_DIAG, Severity, FileLookup[Location.FileID], Location.Line,
820       Location.Col, Location.Offset, CategoryLookup[Category],
821       Flag ? DiagFlagLookup[Flag] : 0, Message.size()};
822 
823   Writer.State->Stream.EmitRecordWithBlob(
824       Writer.State->Abbrevs.get(RECORD_DIAG), Record, Message);
825   return std::error_code();
826 }
827 
828 std::error_code
829 SDiagsMerger::visitFixitRecord(const serialized_diags::Location &Start,
830                                const serialized_diags::Location &End,
831                                StringRef Text) {
832   RecordData::value_type Record[] = {RECORD_FIXIT, FileLookup[Start.FileID],
833                                      Start.Line, Start.Col, Start.Offset,
834                                      FileLookup[End.FileID], End.Line, End.Col,
835                                      End.Offset, Text.size()};
836 
837   Writer.State->Stream.EmitRecordWithBlob(
838       Writer.State->Abbrevs.get(RECORD_FIXIT), Record, Text);
839   return std::error_code();
840 }
841 
842 std::error_code SDiagsMerger::visitFilenameRecord(unsigned ID, unsigned Size,
843                                                   unsigned Timestamp,
844                                                   StringRef Name) {
845   FileLookup[ID] = Writer.getEmitFile(Name.str().c_str());
846   return std::error_code();
847 }
848 
849 std::error_code SDiagsMerger::visitCategoryRecord(unsigned ID, StringRef Name) {
850   CategoryLookup[ID] = Writer.getEmitCategory(ID);
851   return std::error_code();
852 }
853 
854 std::error_code SDiagsMerger::visitDiagFlagRecord(unsigned ID, StringRef Name) {
855   DiagFlagLookup[ID] = Writer.getEmitDiagnosticFlag(Name);
856   return std::error_code();
857 }
858