clang  3.8.0
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"
15 #include "clang/Basic/Version.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 
29 using namespace clang;
30 using namespace clang::serialized_diags;
31 
32 namespace {
33 
34 class AbbreviationMap {
35  llvm::DenseMap<unsigned, unsigned> Abbrevs;
36 public:
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 
52 typedef SmallVector<uint64_t, 64> RecordData;
53 typedef SmallVectorImpl<uint64_t> RecordDataImpl;
54 typedef ArrayRef<uint64_t> RecordDataRef;
55 
56 class SDiagsWriter;
57 
58 class SDiagsRenderer : public DiagnosticNoteRenderer {
59  SDiagsWriter &Writer;
60 public:
61  SDiagsRenderer(SDiagsWriter &Writer, const LangOptions &LangOpts,
62  DiagnosticOptions *DiagOpts)
63  : DiagnosticNoteRenderer(LangOpts, DiagOpts), Writer(Writer) {}
64 
65  ~SDiagsRenderer() override {}
66 
67 protected:
68  void emitDiagnosticMessage(SourceLocation Loc,
69  PresumedLoc PLoc,
71  StringRef Message,
73  const SourceManager *SM,
74  DiagOrStoredDiag D) override;
75 
76  void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
79  const SourceManager &SM) override {}
80 
81  void emitNote(SourceLocation Loc, StringRef Message,
82  const SourceManager *SM) override;
83 
84  void emitCodeContext(SourceLocation Loc,
87  ArrayRef<FixItHint> Hints,
88  const SourceManager &SM) override;
89 
90  void beginDiagnostic(DiagOrStoredDiag D,
92  void endDiagnostic(DiagOrStoredDiag D,
94 };
95 
96 typedef llvm::DenseMap<unsigned, unsigned> AbbrevLookup;
97 
98 class SDiagsMerger : SerializedDiagnosticReader {
99  SDiagsWriter &Writer;
100  AbbrevLookup FileLookup;
101  AbbrevLookup CategoryLookup;
102  AbbrevLookup DiagFlagLookup;
103 
104 public:
105  SDiagsMerger(SDiagsWriter &Writer)
106  : SerializedDiagnosticReader(), Writer(Writer) {}
107 
108  std::error_code mergeRecordsFromFile(const char *File) {
109  return readDiagnostics(File);
110  }
111 
112 protected:
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(
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,
125  StringRef CodeToInsert) override;
126  std::error_code
127  visitSourceRangeRecord(const serialized_diags::Location &Start,
128  const serialized_diags::Location &End) override;
129 
130 private:
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 
142 class 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 
152 public:
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 
173 private:
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,
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.
263 
264  /// \brief The byte buffer for the serialized content.
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.
305 };
306 } // end anonymous namespace
307 
308 namespace clang {
309 namespace serialized_diags {
310 std::unique_ptr<DiagnosticConsumer>
311 create(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.
323 static 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.
343 static 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 
355 void 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 
375 void 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 
387 unsigned 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 
406 void 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.
416 void 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 
427 static 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 
435 static void AddRangeLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) {
436  AddSourceLocationAbbrev(Abbrev);
437  AddSourceLocationAbbrev(Abbrev);
438 }
439 
440 void 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 
529 void 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 
539 unsigned 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 
553 unsigned 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 
562 unsigned 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 
584 void 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 
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 
646 void SDiagsWriter::EmitDiagnosticMessage(SourceLocation Loc,
647  PresumedLoc PLoc,
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 
677 void
678 SDiagsRenderer::emitDiagnosticMessage(SourceLocation Loc,
679  PresumedLoc PLoc,
681  StringRef Message,
683  const SourceManager *SM,
684  DiagOrStoredDiag D) {
685  Writer.EmitDiagnosticMessage(Loc, PLoc, Level, Message, SM, D);
686 }
687 
688 void SDiagsWriter::EnterDiagBlock() {
689  State->Stream.EnterSubblock(BLOCK_DIAG, 4);
690 }
691 
692 void SDiagsWriter::ExitDiagBlock() {
693  State->Stream.ExitBlock();
694 }
695 
696 void SDiagsRenderer::beginDiagnostic(DiagOrStoredDiag D,
697  DiagnosticsEngine::Level Level) {
698  if (Level == DiagnosticsEngine::Note)
699  Writer.EnterDiagBlock();
700 }
701 
702 void 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 
710 void 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 
738 void SDiagsRenderer::emitCodeContext(SourceLocation Loc,
741  ArrayRef<FixItHint> Hints,
742  const SourceManager &SM) {
743  Writer.EmitCodeContext(Ranges, Hints, SM);
744 }
745 
746 void 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 
755 DiagnosticsEngine *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) {
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 
779 void 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 
789 void 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 
823 std::error_code SDiagsMerger::visitStartOfDiagnostic() {
824  Writer.EnterDiagBlock();
825  return std::error_code();
826 }
827 
828 std::error_code SDiagsMerger::visitEndOfDiagnostic() {
829  Writer.ExitDiagBlock();
830  return std::error_code();
831 }
832 
833 std::error_code
834 SDiagsMerger::visitSourceRangeRecord(const serialized_diags::Location &Start,
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 
844 std::error_code SDiagsMerger::visitDiagnosticRecord(
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 
857 std::error_code
858 SDiagsMerger::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 
871 std::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 
878 std::error_code SDiagsMerger::visitCategoryRecord(unsigned ID, StringRef Name) {
879  CategoryLookup[ID] = Writer.getEmitCategory(ID);
880  return std::error_code();
881 }
882 
883 std::error_code SDiagsMerger::visitDiagFlagRecord(unsigned ID, StringRef Name) {
884  DiagFlagLookup[ID] = Writer.getEmitDiagnosticFlag(Name);
885  return std::error_code();
886 }
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)
SourceLocation getBegin() const
unsigned getColumn() const
Return the presumed column number of this location.
Defines the clang::FileManager interface and associated types.
bool isInvalid() const
Return true if this object is invalid or uninitialized.
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:64
std::unique_ptr< llvm::MemoryBuffer > Buffer
unsigned getID() const
Definition: Diagnostic.h:1146
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:62
Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...
Definition: Diagnostic.h:1307
class LLVM_ALIGNAS(8) DependentTemplateSpecializationType const IdentifierInfo * Name
Represents a template specialization type whose template cannot be resolved, e.g. ...
Definition: Type.h:4381
LineState State
int Category
Definition: Format.cpp:1726
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:1147
SmallVector< CharSourceRange, 8 > Ranges
Definition: Format.cpp:1715
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:135
static void EmitRecordID(unsigned ID, const char *Name, llvm::BitstreamWriter &Stream, RecordDataImpl &Record)
Emits a record ID in the BLOCKINFO block.
unsigned getLine() const
Return the presumed line number of this location.
detail::InMemoryDirectory::const_iterator I
bool isInvalid() const
#define CASE(X)
StringRef Filename
Definition: Format.cpp:1723
const SmallVectorImpl< AnnotatedLine * >::const_iterator End
ID
Defines the set of possible language-specific address spaces.
Definition: AddressSpaces.h:27
SourceManager & SM
Represents a character-granular source range.
SourceLocation getEnd() const
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:406
Defines version macros and version-related utility functions for Clang.
static void EmitBlockID(unsigned ID, const char *Name, llvm::BitstreamWriter &Stream, RecordDataImpl &Record)
Emits a block ID in the BLOCKINFO block.
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.
CharSourceRange RemoveRange
Code that should be replaced to correct the error.
Definition: Diagnostic.h:56
#define false
Definition: stdbool.h:33
llvm::PointerUnion< const Diagnostic *, const StoredDiagnostic * > DiagOrStoredDiag
bool isTokenRange() const
Return true if the end of this range specifies the start of the last token.
const char * getFilename() const
Return the presumed filename of this location.
Encodes a location in the source.
Subclass of DiagnosticRender that turns all subdiagostics into explicit notes.
Options for controlling the compiler diagnostics engine.
A base class that handles reading serialized diagnostics from a file.
bool hasSourceManager() const
Definition: Diagnostic.h:1148
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.
detail::InMemoryDirectory::const_iterator E
ArrayRef< CharSourceRange > getRanges() const
Return an array reference for this diagnostic's ranges.
Definition: Diagnostic.h:1224
Defines the Diagnostic-related interfaces.
SourceManager & getSourceManager() const
Definition: Diagnostic.h:1149
static void AddRangeLocationAbbrev(llvm::BitCodeAbbrev *Abbrev)
bool isNull() const
Definition: Diagnostic.h:72
Level
The level of the diagnostic, after it has been through mapping.
Definition: Diagnostic.h:141
A little helper class (which is basically a smart pointer that forwards info from DiagnosticsEngine) ...
Definition: Diagnostic.h:1137
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:52
StringRef Text
Definition: Format.cpp:1724
unsigned getFileOffset(SourceLocation SpellingLoc) const
Returns the offset from the start of the file that the specified SourceLocation represents.
#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:630
This class handles loading and caching of source files into memory.
ArrayRef< FixItHint > getFixItHints() const
Definition: Diagnostic.h:1237
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:96
PresumedLoc getPresumedLoc(SourceLocation Loc, bool UseLineDirectives=true) const
Returns the "presumed" location of a SourceLocation specifies.