Clang Project

clang_source_code/lib/Frontend/SerializedDiagnosticPrinter.cpp
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
26using namespace clang;
27using namespace clang::serialized_diags;
28
29namespace {
30
31class AbbreviationMap {
32  llvm::DenseMap<unsignedunsignedAbbrevs;
33public:
34  AbbreviationMap() {}
35
36  void set(unsigned recordIDunsigned abbrevID) {
37     (0) . __assert_fail ("Abbrevs.find(recordID) == Abbrevs.end() && \"Abbreviation already set.\"", "/home/seafit/code_projects/clang_source/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp", 38, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Abbrevs.find(recordID) == Abbrevs.end()
38 (0) . __assert_fail ("Abbrevs.find(recordID) == Abbrevs.end() && \"Abbreviation already set.\"", "/home/seafit/code_projects/clang_source/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp", 38, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">           && "Abbreviation already set.");
39    Abbrevs[recordID] = abbrevID;
40  }
41
42  unsigned get(unsigned recordID) {
43     (0) . __assert_fail ("Abbrevs.find(recordID) != Abbrevs.end() && \"Abbreviation not set.\"", "/home/seafit/code_projects/clang_source/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp", 44, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Abbrevs.find(recordID) != Abbrevs.end() &&
44 (0) . __assert_fail ("Abbrevs.find(recordID) != Abbrevs.end() && \"Abbreviation not set.\"", "/home/seafit/code_projects/clang_source/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp", 44, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">           "Abbreviation not set.");
45    return Abbrevs[recordID];
46  }
47};
48
49typedef SmallVector<uint64_t64RecordData;
50typedef SmallVectorImpl<uint64_tRecordDataImpl;
51typedef ArrayRef<uint64_tRecordDataRef;
52
53class SDiagsWriter;
54
55class SDiagsRenderer : public DiagnosticNoteRenderer {
56  SDiagsWriter &Writer;
57public:
58  SDiagsRenderer(SDiagsWriter &Writerconst LangOptions &LangOpts,
59                 DiagnosticOptions *DiagOpts)
60    : DiagnosticNoteRenderer(LangOptsDiagOpts), Writer(Writer) {}
61
62  ~SDiagsRenderer() override {}
63
64protected:
65  void emitDiagnosticMessage(FullSourceLoc LocPresumedLoc PLoc,
66                             DiagnosticsEngine::Level LevelStringRef Message,
67                             ArrayRef<CharSourceRangeRanges,
68                             DiagOrStoredDiag D) override;
69
70  void emitDiagnosticLoc(FullSourceLoc LocPresumedLoc PLoc,
71                         DiagnosticsEngine::Level Level,
72                         ArrayRef<CharSourceRangeRanges) override {}
73
74  void emitNote(FullSourceLoc LocStringRef Message) override;
75
76  void emitCodeContext(FullSourceLoc LocDiagnosticsEngine::Level Level,
77                       SmallVectorImpl<CharSourceRange> &Ranges,
78                       ArrayRef<FixItHintHints) override;
79
80  void beginDiagnostic(DiagOrStoredDiag D,
81                       DiagnosticsEngine::Level Level) override;
82  void endDiagnostic(DiagOrStoredDiag D,
83                     DiagnosticsEngine::Level Level) override;
84};
85
86typedef llvm::DenseMap<unsignedunsignedAbbrevLookup;
87
88class SDiagsMerger : SerializedDiagnosticReader {
89  SDiagsWriter &Writer;
90  AbbrevLookup FileLookup;
91  AbbrevLookup CategoryLookup;
92  AbbrevLookup DiagFlagLookup;
93
94public:
95  SDiagsMerger(SDiagsWriter &Writer)
96      : SerializedDiagnosticReader(), Writer(Writer) {}
97
98  std::error_code mergeRecordsFromFile(const char *File) {
99    return readDiagnostics(File);
100  }
101
102protected:
103  std::error_code visitStartOfDiagnostic() override;
104  std::error_code visitEndOfDiagnostic() override;
105  std::error_code visitCategoryRecord(unsigned IDStringRef Name) override;
106  std::error_code visitDiagFlagRecord(unsigned IDStringRef Name) override;
107  std::error_code visitDiagnosticRecord(
108      unsigned Severityconst serialized_diags::Location &Location,
109      unsigned Categoryunsigned FlagStringRef Message) override;
110  std::error_code visitFilenameRecord(unsigned IDunsigned 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
120private:
121  std::error_code adjustSourceLocFilename(RecordData &Record,
122                                          unsigned int offset);
123
124  void adjustAbbrevID(RecordData &RecordAbbrevLookup &Lookup,
125                      unsigned NewAbbrev);
126
127  void writeRecordWithAbbrev(unsigned IDRecordData &Record);
128
129  void writeRecordWithBlob(unsigned IDRecordData &RecordStringRef Blob);
130};
131
132class SDiagsWriter : public DiagnosticConsumer {
133  friend class SDiagsRenderer;
134  friend class SDiagsMerger;
135
136  struct SharedState;
137
138  explicit SDiagsWriter(std::shared_ptr<SharedStateState)
139      : LangOpts(nullptr), OriginalInstance(false), MergeChildRecords(false),
140        State(std::move(State)) {}
141
142public:
143  SDiagsWriter(StringRef FileDiagnosticOptions *Diagsbool 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 &LOconst Preprocessor *PP) override {
158    LangOpts = &LO;
159  }
160
161  void finish() override;
162
163private:
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 LocPresumedLoc PLoc,
189                             DiagnosticsEngine::Level LevelStringRef Message,
190                             DiagOrStoredDiag D);
191
192  /// Emit FIXIT and SOURCE_RANGE records for a diagnostic.
193  void EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges,
194                       ArrayRef<FixItHintHints,
195                       const SourceManager &SM);
196
197  /// Emit a record for a CharSourceRange.
198  void EmitCharSourceRange(CharSourceRange Rconst 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 LocPresumedLoc PLoc,
214                      RecordDataImpl &Recordunsigned TokSize = 0);
215
216  /// Add SourceLocation information the specified record.
217  void AddLocToRecord(FullSourceLoc LocRecordDataImpl &Record,
218                      unsigned TokSize = 0) {
219    AddLocToRecord(LocLoc.hasManager() ? Loc.getPresumedLoc() : PresumedLoc(),
220                   RecordTokSize);
221  }
222
223  /// Add CharSourceRange information the specified record.
224  void AddCharSourceRangeToRecord(CharSourceRange RRecordDataImpl &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 FileDiagnosticOptions *Diags)
243        : DiagOpts(Diags), Stream(Buffer), OutputFile(File.str()),
244          EmittedAnyDiagBlocks(false) {}
245
246    /// Diagnostic options.
247    IntrusiveRefCntPtr<DiagnosticOptionsDiagOpts;
248
249    /// The byte buffer for the serialized content.
250    SmallString<1024Buffer;
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<256diagBuf;
266
267    /// The collection of diagnostic categories used.
268    llvm::DenseSet<unsignedCategories;
269
270    /// The collection of files used.
271    llvm::DenseMap<const char *, unsignedFiles;
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<DiagnosticsEngineMetaDiagnostics;
286  };
287
288  /// State shared among the various clones of this diagnostic consumer.
289  std::shared_ptr<SharedStateState;
290};
291// end anonymous namespace
292
293namespace clang {
294namespace serialized_diags {
295std::unique_ptr<DiagnosticConsumer>
296create(StringRef OutputFileDiagnosticOptions *Diagsbool 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.
308static void EmitBlockID(unsigned IDconst 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.
328static void EmitRecordID(unsigned IDconst 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
340void SDiagsWriter::AddLocToRecord(FullSourceLoc LocPresumedLoc PLoc,
341                                  RecordDataImpl &Recordunsigned 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
357void 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), RecordTokSize);
367}
368
369unsigned 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
388void SDiagsWriter::EmitCharSourceRange(CharSourceRange R,
389                                       const SourceManager &SM) {
390  State->Record.clear();
391  State->Record.push_back(RECORD_SOURCE_RANGE);
392  AddCharSourceRangeToRecord(RState->RecordSM);
393  State->Stream.EmitRecordWithAbbrev(State->Abbrevs.get(RECORD_SOURCE_RANGE),
394                                     State->Record);
395}
396
397/// Emits the preamble of the diagnostics file.
398void 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
409static 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
417static void AddRangeLocationAbbrev(llvm::BitCodeAbbrev &Abbrev) {
418  AddSourceLocationAbbrev(Abbrev);
419  AddSourceLocationAbbrev(Abbrev);
420}
421
422void 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
511void 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
521unsigned 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
535unsigned 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
544unsigned 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<unsignedStringRef> &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
566void 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   (0) . __assert_fail ("Info.hasSourceManager() && LangOpts && \"Unexpected diagnostic with valid location outside of a source file\"", "/home/seafit/code_projects/clang_source/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp", 603, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Info.hasSourceManager() && LangOpts &&
603 (0) . __assert_fail ("Info.hasSourceManager() && LangOpts && \"Unexpected diagnostic with valid location outside of a source file\"", "/home/seafit/code_projects/clang_source/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp", 603, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">         "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
610static 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
625void SDiagsWriter::EmitDiagnosticMessage(FullSourceLoc LocPresumedLoc 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(LocPLocRecord);
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
654void SDiagsRenderer::emitDiagnosticMessage(
655    FullSourceLoc LocPresumedLoc PLocDiagnosticsEngine::Level Level,
656    StringRef MessageArrayRef<clang::CharSourceRangeRanges,
657    DiagOrStoredDiag D) {
658  Writer.EmitDiagnosticMessage(Loc, PLoc, Level, Message, D);
659}
660
661void SDiagsWriter::EnterDiagBlock() {
662  State->Stream.EnterSubblock(BLOCK_DIAG4);
663}
664
665void SDiagsWriter::ExitDiagBlock() {
666  State->Stream.ExitBlock();
667}
668
669void SDiagsRenderer::beginDiagnostic(DiagOrStoredDiag D,
670                                     DiagnosticsEngine::Level Level) {
671  if (Level == DiagnosticsEngine::Note)
672    Writer.EnterDiagBlock();
673}
674
675void 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
683void SDiagsWriter::EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges,
684                                   ArrayRef<FixItHintHints,
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
711void SDiagsRenderer::emitCodeContext(FullSourceLoc Loc,
712                                     DiagnosticsEngine::Level Level,
713                                     SmallVectorImpl<CharSourceRange> &Ranges,
714                                     ArrayRef<FixItHintHints) {
715  Writer.EmitCodeContext(Ranges, Hints, Loc.getManager());
716}
717
718void SDiagsRenderer::emitNote(FullSourceLoc LocStringRef 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
726DiagnosticsEngine *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<DiagnosticIDsIDs(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
750void 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
760void 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
794std::error_code SDiagsMerger::visitStartOfDiagnostic() {
795  Writer.EnterDiagBlock();
796  return std::error_code();
797}
798
799std::error_code SDiagsMerger::visitEndOfDiagnostic() {
800  Writer.ExitDiagBlock();
801  return std::error_code();
802}
803
804std::error_code
805SDiagsMerger::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
815std::error_code SDiagsMerger::visitDiagnosticRecord(
816    unsigned Severityconst serialized_diags::Location &Location,
817    unsigned Categoryunsigned FlagStringRef 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
828std::error_code
829SDiagsMerger::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
842std::error_code SDiagsMerger::visitFilenameRecord(unsigned IDunsigned Size,
843                                                  unsigned Timestamp,
844                                                  StringRef Name) {
845  FileLookup[ID] = Writer.getEmitFile(Name.str().c_str());
846  return std::error_code();
847}
848
849std::error_code SDiagsMerger::visitCategoryRecord(unsigned IDStringRef Name) {
850  CategoryLookup[ID] = Writer.getEmitCategory(ID);
851  return std::error_code();
852}
853
854std::error_code SDiagsMerger::visitDiagFlagRecord(unsigned IDStringRef Name) {
855  DiagFlagLookup[ID] = Writer.getEmitDiagnosticFlag(Name);
856  return std::error_code();
857}
858