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