clang  9.0.0svn
SerializedDiagnosticPrinter.cpp
Go to the documentation of this file.
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 
10 #include "clang/Basic/Diagnostic.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,
68  DiagOrStoredDiag D) override;
69 
70  void emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
72  ArrayRef<CharSourceRange> Ranges) override {}
73 
74  void emitNote(FullSourceLoc Loc, StringRef Message) override;
75 
76  void emitCodeContext(FullSourceLoc Loc, DiagnosticsEngine::Level Level,
78  ArrayRef<FixItHint> Hints) override;
79 
80  void beginDiagnostic(DiagOrStoredDiag D,
82  void endDiagnostic(DiagOrStoredDiag D,
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(
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,
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.
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 
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,
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(
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,
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) {
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,
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(
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 }
static unsigned getCategoryNumberForDiag(unsigned DiagID)
Return the category number that a specified DiagID belongs to, or 0 if no category.
static serialized_diags::Level getStableLevel(DiagnosticsEngine::Level Level)
DominatorTree GraphTraits specialization so the DominatorTree can be iterable by generic graph iterat...
Definition: Dominators.h:29
Defines the SourceManager interface.
Level
A stable version of DiagnosticIDs::Level.
llvm::PointerUnion< const Diagnostic *, const StoredDiagnostic * > DiagOrStoredDiag
std::string CodeToInsert
The actual code to insert at the insertion location, as a string.
Definition: Diagnostic.h:77
static StringRef getCategoryNameFromID(unsigned CategoryID)
Given a category ID, return the name of the category.
static void AddSourceLocationAbbrev(llvm::BitCodeAbbrev &Abbrev)
Severity
Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs to either Ignore (nothing)...
Definition: DiagnosticIDs.h:79
Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...
Definition: Diagnostic.h:1489
bool hasSourceManager() const
Definition: Diagnostic.h:1329
unsigned getID() const
Definition: Diagnostic.h:1327
SourceLocation getBegin() const
LineState State
Definition: Format.h:2222
int Category
Definition: Format.cpp:1710
bool isNull() const
Definition: Diagnostic.h:85
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:49
const SourceLocation & getLocation() const
Definition: Diagnostic.h:1328
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:148
Defines the Diagnostic-related interfaces.
PresumedLoc getPresumedLoc(bool UseLineDirectives=true) const
static void EmitRecordID(unsigned ID, const char *Name, llvm::BitstreamWriter &Stream, RecordDataImpl &Record)
Emits a record ID in the BLOCKINFO block.
return Out str()
#define CASE(X)
StringRef Filename
Definition: Format.cpp:1707
bool hasManager() const
SourceLocation End
Represents a character-granular source range.
bool isInvalid() const
Return true if this object is invalid or uninitialized.
static unsigned MeasureTokenLength(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
MeasureTokenLength - Relex the token at the specified location and return its length in bytes in the ...
Definition: Lexer.cpp:435
unsigned getLine() const
Return the presumed line number of this location.
static void EmitBlockID(unsigned ID, const char *Name, llvm::BitstreamWriter &Stream, RecordDataImpl &Record)
Emits a block ID in the BLOCKINFO block.
const SourceManager & getManager() const
static StringRef getWarningOptionForDiag(unsigned DiagID)
Return the lowest-level warning option that enables the specified diagnostic.
Represents an unpacked "presumed" location which can be presented to the user.
const SourceManager & SM
Definition: Format.cpp:1568
const char * getFilename() const
Return the presumed filename of this location.
CharSourceRange RemoveRange
Code that should be replaced to correct the error.
Definition: Diagnostic.h:69
#define false
Definition: stdbool.h:17
unsigned getColumn() const
Return the presumed column number of this location.
Subclass of DiagnosticRender that turns all subdiagostics into explicit notes.
Options for controlling the compiler diagnostics engine.
unsigned getFileOffset() const
SourceManager & getSourceManager() const
Definition: Diagnostic.h:1330
bool isTokenRange() const
Return true if the end of this range specifies the start of the last token.
Dataflow Directional Tag Classes.
A base class that handles reading serialized diagnostics from a file.
A location that is represented in the serialized diagnostics.
std::unique_ptr< DiagnosticConsumer > create(StringRef OutputFile, DiagnosticOptions *Diags, bool MergeChildRecords=false)
Returns a DiagnosticConsumer that serializes diagnostics to a bitcode file.
Used for handling and querying diagnostic IDs.
static void AddRangeLocationAbbrev(llvm::BitCodeAbbrev &Abbrev)
SourceLocation getEnd() const
ArrayRef< CharSourceRange > getRanges() const
Return an array reference for this diagnostic&#39;s ranges.
Definition: Diagnostic.h:1405
ArrayRef< FixItHint > getFixItHints() const
Definition: Diagnostic.h:1418
Level
The level of the diagnostic, after it has been through mapping.
Definition: Diagnostic.h:151
A little helper class (which is basically a smart pointer that forwards info from DiagnosticsEngine) ...
Definition: Diagnostic.h:1317
A SourceLocation and its associated SourceManager.
The this block acts as a container for all the information for a specific diagnostic.
Annotates a diagnostic with some code that should be inserted, removed, or replaced to fix the proble...
Definition: Diagnostic.h:65
StringRef Text
Definition: Format.cpp:1708
#define true
Definition: stdbool.h:16
A top-level block which represents any meta data associated with the diagostics, including versioning...
void FormatDiagnostic(SmallVectorImpl< char > &OutStr) const
Format this diagnostic into a string, substituting the formal arguments into the %0 slots...
Definition: Diagnostic.cpp:763
This class handles loading and caching of source files into memory.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:123