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