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