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