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