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