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/StringRef.h" 21 #include "llvm/Bitstream/BitCodes.h" 22 #include "llvm/Support/FileSystem.h" 23 #include "llvm/Support/raw_ostream.h" 24 #include <utility> 25 26 using namespace clang; 27 using namespace clang::serialized_diags; 28 29 namespace { 30 31 class AbbreviationMap { 32 llvm::DenseMap<unsigned, unsigned> Abbrevs; 33 public: 34 AbbreviationMap() {} 35 36 void set(unsigned recordID, unsigned abbrevID) { 37 assert(!Abbrevs.contains(recordID) && "Abbreviation already set."); 38 Abbrevs[recordID] = abbrevID; 39 } 40 41 unsigned get(unsigned recordID) { 42 assert(Abbrevs.contains(recordID) && "Abbreviation not set."); 43 return Abbrevs[recordID]; 44 } 45 }; 46 47 typedef SmallVector<uint64_t, 64> RecordData; 48 typedef SmallVectorImpl<uint64_t> RecordDataImpl; 49 typedef ArrayRef<uint64_t> RecordDataRef; 50 51 class SDiagsWriter; 52 53 class SDiagsRenderer : public DiagnosticNoteRenderer { 54 SDiagsWriter &Writer; 55 public: 56 SDiagsRenderer(SDiagsWriter &Writer, const LangOptions &LangOpts, 57 DiagnosticOptions &DiagOpts) 58 : DiagnosticNoteRenderer(LangOpts, DiagOpts), Writer(Writer) {} 59 60 ~SDiagsRenderer() override {} 61 62 protected: 63 void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc, 64 DiagnosticsEngine::Level Level, StringRef Message, 65 ArrayRef<CharSourceRange> Ranges, 66 DiagOrStoredDiag D) override; 67 68 void emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc, 69 DiagnosticsEngine::Level Level, 70 ArrayRef<CharSourceRange> Ranges) override {} 71 72 void emitNote(FullSourceLoc Loc, StringRef Message) override; 73 74 void emitCodeContext(FullSourceLoc Loc, DiagnosticsEngine::Level Level, 75 SmallVectorImpl<CharSourceRange> &Ranges, 76 ArrayRef<FixItHint> Hints) override; 77 78 void beginDiagnostic(DiagOrStoredDiag D, 79 DiagnosticsEngine::Level Level) override; 80 void endDiagnostic(DiagOrStoredDiag D, 81 DiagnosticsEngine::Level Level) override; 82 }; 83 84 typedef llvm::DenseMap<unsigned, unsigned> AbbrevLookup; 85 86 class SDiagsMerger : SerializedDiagnosticReader { 87 SDiagsWriter &Writer; 88 AbbrevLookup FileLookup; 89 AbbrevLookup CategoryLookup; 90 AbbrevLookup DiagFlagLookup; 91 92 public: 93 SDiagsMerger(SDiagsWriter &Writer) : Writer(Writer) {} 94 95 std::error_code mergeRecordsFromFile(const char *File) { 96 return readDiagnostics(File); 97 } 98 99 protected: 100 std::error_code visitStartOfDiagnostic() override; 101 std::error_code visitEndOfDiagnostic() override; 102 std::error_code visitCategoryRecord(unsigned ID, StringRef Name) override; 103 std::error_code visitDiagFlagRecord(unsigned ID, StringRef Name) override; 104 std::error_code visitDiagnosticRecord( 105 unsigned Severity, const serialized_diags::Location &Location, 106 unsigned Category, unsigned Flag, StringRef Message) override; 107 std::error_code visitFilenameRecord(unsigned ID, unsigned Size, 108 unsigned Timestamp, 109 StringRef Name) override; 110 std::error_code visitFixitRecord(const serialized_diags::Location &Start, 111 const serialized_diags::Location &End, 112 StringRef CodeToInsert) override; 113 std::error_code 114 visitSourceRangeRecord(const serialized_diags::Location &Start, 115 const serialized_diags::Location &End) override; 116 117 private: 118 std::error_code adjustSourceLocFilename(RecordData &Record, 119 unsigned int offset); 120 121 void adjustAbbrevID(RecordData &Record, AbbrevLookup &Lookup, 122 unsigned NewAbbrev); 123 124 void writeRecordWithAbbrev(unsigned ID, RecordData &Record); 125 126 void writeRecordWithBlob(unsigned ID, RecordData &Record, StringRef Blob); 127 }; 128 129 class SDiagsWriter : public DiagnosticConsumer { 130 friend class SDiagsRenderer; 131 friend class SDiagsMerger; 132 133 struct SharedState; 134 135 explicit SDiagsWriter(std::shared_ptr<SharedState> State) 136 : LangOpts(nullptr), OriginalInstance(false), MergeChildRecords(false), 137 State(std::move(State)) {} 138 139 public: 140 SDiagsWriter(StringRef File, DiagnosticOptions &Diags, bool MergeChildRecords) 141 : LangOpts(nullptr), OriginalInstance(true), 142 MergeChildRecords(MergeChildRecords), 143 State(std::make_shared<SharedState>(File, Diags)) { 144 if (MergeChildRecords) 145 RemoveOldDiagnostics(); 146 EmitPreamble(); 147 } 148 149 ~SDiagsWriter() override {} 150 151 void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, 152 const Diagnostic &Info) override; 153 154 void BeginSourceFile(const LangOptions &LO, const Preprocessor *PP) override { 155 LangOpts = &LO; 156 } 157 158 void finish() override; 159 160 private: 161 /// Build a DiagnosticsEngine to emit diagnostics about the diagnostics 162 DiagnosticsEngine *getMetaDiags(); 163 164 /// Remove old copies of the serialized diagnostics. This is necessary 165 /// so that we can detect when subprocesses write diagnostics that we should 166 /// merge into our own. 167 void RemoveOldDiagnostics(); 168 169 /// Emit the preamble for the serialized diagnostics. 170 void EmitPreamble(); 171 172 /// Emit the BLOCKINFO block. 173 void EmitBlockInfoBlock(); 174 175 /// Emit the META data block. 176 void EmitMetaBlock(); 177 178 /// Start a DIAG block. 179 void EnterDiagBlock(); 180 181 /// End a DIAG block. 182 void ExitDiagBlock(); 183 184 /// Emit a DIAG record. 185 void EmitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc, 186 DiagnosticsEngine::Level Level, StringRef Message, 187 DiagOrStoredDiag D); 188 189 /// Emit FIXIT and SOURCE_RANGE records for a diagnostic. 190 void EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges, 191 ArrayRef<FixItHint> Hints, 192 const SourceManager &SM); 193 194 /// Emit a record for a CharSourceRange. 195 void EmitCharSourceRange(CharSourceRange R, const SourceManager &SM); 196 197 /// Emit the string information for the category. 198 unsigned getEmitCategory(unsigned category = 0); 199 200 /// Emit the string information for diagnostic flags. 201 unsigned getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel, 202 const Diagnostic *Diag = nullptr); 203 204 unsigned getEmitDiagnosticFlag(StringRef DiagName); 205 206 /// Emit (lazily) the file string and retrieved the file identifier. 207 unsigned getEmitFile(const char *Filename); 208 209 /// Add SourceLocation information the specified record. 210 void AddLocToRecord(FullSourceLoc Loc, PresumedLoc PLoc, 211 RecordDataImpl &Record, unsigned TokSize = 0); 212 213 /// Add SourceLocation information the specified record. 214 void AddLocToRecord(FullSourceLoc Loc, RecordDataImpl &Record, 215 unsigned TokSize = 0) { 216 AddLocToRecord(Loc, Loc.hasManager() ? Loc.getPresumedLoc() : PresumedLoc(), 217 Record, TokSize); 218 } 219 220 /// Add CharSourceRange information the specified record. 221 void AddCharSourceRangeToRecord(CharSourceRange R, RecordDataImpl &Record, 222 const SourceManager &SM); 223 224 /// Language options, which can differ from one clone of this client 225 /// to another. 226 const LangOptions *LangOpts; 227 228 /// Whether this is the original instance (rather than one of its 229 /// clones), responsible for writing the file at the end. 230 bool OriginalInstance; 231 232 /// Whether this instance should aggregate diagnostics that are 233 /// generated from child processes. 234 bool MergeChildRecords; 235 236 /// Whether we've started finishing and tearing down this instance. 237 bool IsFinishing = false; 238 239 /// State that is shared among the various clones of this diagnostic 240 /// consumer. 241 struct SharedState { 242 SharedState(StringRef File, DiagnosticOptions &DiagOpts) 243 : DiagOpts(DiagOpts), Stream(Buffer), OutputFile(File.str()), 244 EmittedAnyDiagBlocks(false) {} 245 246 /// Diagnostic options. 247 DiagnosticOptions DiagOpts; 248 249 /// The byte buffer for the serialized content. 250 SmallString<1024> Buffer; 251 252 /// The BitStreamWriter for the serialized diagnostics. 253 llvm::BitstreamWriter Stream; 254 255 /// The name of the diagnostics file. 256 std::string OutputFile; 257 258 /// The set of constructed record abbreviations. 259 AbbreviationMap Abbrevs; 260 261 /// A utility buffer for constructing record content. 262 RecordData Record; 263 264 /// A text buffer for rendering diagnostic text. 265 SmallString<256> diagBuf; 266 267 /// The collection of diagnostic categories used. 268 llvm::DenseSet<unsigned> Categories; 269 270 /// The collection of files used. 271 llvm::DenseMap<const char *, unsigned> Files; 272 273 typedef llvm::DenseMap<const void *, std::pair<unsigned, StringRef> > 274 DiagFlagsTy; 275 276 /// Map for uniquing strings. 277 DiagFlagsTy DiagFlags; 278 279 /// Whether we have already started emission of any DIAG blocks. Once 280 /// this becomes \c true, we never close a DIAG block until we know that we're 281 /// starting another one or we're done. 282 bool EmittedAnyDiagBlocks; 283 284 /// Engine for emitting diagnostics about the diagnostics. 285 std::unique_ptr<DiagnosticsEngine> MetaDiagnostics; 286 }; 287 288 /// State shared among the various clones of this diagnostic consumer. 289 std::shared_ptr<SharedState> State; 290 }; 291 } // end anonymous namespace 292 293 namespace clang { 294 namespace serialized_diags { 295 std::unique_ptr<DiagnosticConsumer> create(StringRef OutputFile, 296 DiagnosticOptions &DiagOpts, 297 bool MergeChildRecords) { 298 return std::make_unique<SDiagsWriter>(OutputFile, DiagOpts, 299 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 const Diagnostic *Diag) { 539 if (!Diag || DiagLevel == DiagnosticsEngine::Note) 540 return 0; // No flag for notes. 541 542 StringRef FlagName = 543 Diag->getDiags()->getDiagnosticIDs()->getWarningOptionForDiag( 544 Diag->getID()); 545 return getEmitDiagnosticFlag(FlagName); 546 } 547 548 unsigned SDiagsWriter::getEmitDiagnosticFlag(StringRef FlagName) { 549 if (FlagName.empty()) 550 return 0; 551 552 // Here we assume that FlagName points to static data whose pointer 553 // value is fixed. This allows us to unique by diagnostic groups. 554 const void *data = FlagName.data(); 555 std::pair<unsigned, StringRef> &entry = State->DiagFlags[data]; 556 if (entry.first == 0) { 557 entry.first = State->DiagFlags.size(); 558 entry.second = FlagName; 559 560 // Lazily emit the string in a separate record. 561 RecordData::value_type Record[] = {RECORD_DIAG_FLAG, entry.first, 562 FlagName.size()}; 563 State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_DIAG_FLAG), 564 Record, FlagName); 565 } 566 567 return entry.first; 568 } 569 570 void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, 571 const Diagnostic &Info) { 572 assert(!IsFinishing && 573 "Received a diagnostic after we've already started teardown."); 574 if (IsFinishing) { 575 SmallString<256> diagnostic; 576 Info.FormatDiagnostic(diagnostic); 577 getMetaDiags()->Report( 578 diag::warn_fe_serialized_diag_failure_during_finalization) 579 << diagnostic; 580 return; 581 } 582 583 // Enter the block for a non-note diagnostic immediately, rather than waiting 584 // for beginDiagnostic, in case associated notes are emitted before we get 585 // there. 586 if (DiagLevel != DiagnosticsEngine::Note) { 587 if (State->EmittedAnyDiagBlocks) 588 ExitDiagBlock(); 589 590 EnterDiagBlock(); 591 State->EmittedAnyDiagBlocks = true; 592 } 593 594 // Compute the diagnostic text. 595 State->diagBuf.clear(); 596 Info.FormatDiagnostic(State->diagBuf); 597 598 if (Info.getLocation().isInvalid()) { 599 // Special-case diagnostics with no location. We may not have entered a 600 // source file in this case, so we can't use the normal DiagnosticsRenderer 601 // machinery. 602 603 // Make sure we bracket all notes as "sub-diagnostics". This matches 604 // the behavior in SDiagsRenderer::emitDiagnostic(). 605 if (DiagLevel == DiagnosticsEngine::Note) 606 EnterDiagBlock(); 607 608 EmitDiagnosticMessage(FullSourceLoc(), PresumedLoc(), DiagLevel, 609 State->diagBuf, &Info); 610 611 if (DiagLevel == DiagnosticsEngine::Note) 612 ExitDiagBlock(); 613 614 return; 615 } 616 617 assert(Info.hasSourceManager() && LangOpts && 618 "Unexpected diagnostic with valid location outside of a source file"); 619 SDiagsRenderer Renderer(*this, *LangOpts, State->DiagOpts); 620 Renderer.emitDiagnostic( 621 FullSourceLoc(Info.getLocation(), Info.getSourceManager()), DiagLevel, 622 State->diagBuf, Info.getRanges(), Info.getFixItHints(), &Info); 623 } 624 625 static serialized_diags::Level getStableLevel(DiagnosticsEngine::Level Level) { 626 switch (Level) { 627 #define CASE(X) case DiagnosticsEngine::X: return serialized_diags::X; 628 CASE(Ignored) 629 CASE(Note) 630 CASE(Remark) 631 CASE(Warning) 632 CASE(Error) 633 CASE(Fatal) 634 #undef CASE 635 } 636 637 llvm_unreachable("invalid diagnostic level"); 638 } 639 640 void SDiagsWriter::EmitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc, 641 DiagnosticsEngine::Level Level, 642 StringRef Message, 643 DiagOrStoredDiag D) { 644 llvm::BitstreamWriter &Stream = State->Stream; 645 RecordData &Record = State->Record; 646 AbbreviationMap &Abbrevs = State->Abbrevs; 647 648 // Emit the RECORD_DIAG record. 649 Record.clear(); 650 Record.push_back(RECORD_DIAG); 651 Record.push_back(getStableLevel(Level)); 652 AddLocToRecord(Loc, PLoc, Record); 653 654 if (const Diagnostic *Info = dyn_cast_if_present<const Diagnostic *>(D)) { 655 // Emit the category string lazily and get the category ID. 656 unsigned DiagID = DiagnosticIDs::getCategoryNumberForDiag(Info->getID()); 657 Record.push_back(getEmitCategory(DiagID)); 658 // Emit the diagnostic flag string lazily and get the mapped ID. 659 Record.push_back(getEmitDiagnosticFlag(Level, Info)); 660 } else { 661 Record.push_back(getEmitCategory()); 662 Record.push_back(getEmitDiagnosticFlag(Level)); 663 } 664 665 Record.push_back(Message.size()); 666 Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG), Record, Message); 667 } 668 669 void SDiagsRenderer::emitDiagnosticMessage( 670 FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, 671 StringRef Message, ArrayRef<clang::CharSourceRange> Ranges, 672 DiagOrStoredDiag D) { 673 Writer.EmitDiagnosticMessage(Loc, PLoc, Level, Message, D); 674 } 675 676 void SDiagsWriter::EnterDiagBlock() { 677 State->Stream.EnterSubblock(BLOCK_DIAG, 4); 678 } 679 680 void SDiagsWriter::ExitDiagBlock() { 681 State->Stream.ExitBlock(); 682 } 683 684 void SDiagsRenderer::beginDiagnostic(DiagOrStoredDiag D, 685 DiagnosticsEngine::Level Level) { 686 if (Level == DiagnosticsEngine::Note) 687 Writer.EnterDiagBlock(); 688 } 689 690 void SDiagsRenderer::endDiagnostic(DiagOrStoredDiag D, 691 DiagnosticsEngine::Level Level) { 692 // Only end note diagnostics here, because we can't be sure when we've seen 693 // the last note associated with a non-note diagnostic. 694 if (Level == DiagnosticsEngine::Note) 695 Writer.ExitDiagBlock(); 696 } 697 698 void SDiagsWriter::EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges, 699 ArrayRef<FixItHint> Hints, 700 const SourceManager &SM) { 701 llvm::BitstreamWriter &Stream = State->Stream; 702 RecordData &Record = State->Record; 703 AbbreviationMap &Abbrevs = State->Abbrevs; 704 705 // Emit Source Ranges. 706 for (ArrayRef<CharSourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); 707 I != E; ++I) 708 if (I->isValid()) 709 EmitCharSourceRange(*I, SM); 710 711 // Emit FixIts. 712 for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end(); 713 I != E; ++I) { 714 const FixItHint &Fix = *I; 715 if (Fix.isNull()) 716 continue; 717 Record.clear(); 718 Record.push_back(RECORD_FIXIT); 719 AddCharSourceRangeToRecord(Fix.RemoveRange, Record, SM); 720 Record.push_back(Fix.CodeToInsert.size()); 721 Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_FIXIT), Record, 722 Fix.CodeToInsert); 723 } 724 } 725 726 void SDiagsRenderer::emitCodeContext(FullSourceLoc Loc, 727 DiagnosticsEngine::Level Level, 728 SmallVectorImpl<CharSourceRange> &Ranges, 729 ArrayRef<FixItHint> Hints) { 730 Writer.EmitCodeContext(Ranges, Hints, Loc.getManager()); 731 } 732 733 void SDiagsRenderer::emitNote(FullSourceLoc Loc, StringRef Message) { 734 Writer.EnterDiagBlock(); 735 PresumedLoc PLoc = Loc.hasManager() ? Loc.getPresumedLoc() : PresumedLoc(); 736 Writer.EmitDiagnosticMessage(Loc, PLoc, DiagnosticsEngine::Note, Message, 737 DiagOrStoredDiag()); 738 Writer.ExitDiagBlock(); 739 } 740 741 DiagnosticsEngine *SDiagsWriter::getMetaDiags() { 742 // FIXME: It's slightly absurd to create a new diagnostics engine here, but 743 // the other options that are available today are worse: 744 // 745 // 1. Teach DiagnosticsConsumers to emit diagnostics to the engine they are a 746 // part of. The DiagnosticsEngine would need to know not to send 747 // diagnostics back to the consumer that failed. This would require us to 748 // rework ChainedDiagnosticsConsumer and teach the engine about multiple 749 // consumers, which is difficult today because most APIs interface with 750 // consumers rather than the engine itself. 751 // 752 // 2. Pass a DiagnosticsEngine to SDiagsWriter on creation - this would need 753 // to be distinct from the engine the writer was being added to and would 754 // normally not be used. 755 if (!State->MetaDiagnostics) { 756 IntrusiveRefCntPtr<DiagnosticIDs> IDs(new DiagnosticIDs()); 757 auto Client = new TextDiagnosticPrinter(llvm::errs(), State->DiagOpts); 758 State->MetaDiagnostics = 759 std::make_unique<DiagnosticsEngine>(IDs, State->DiagOpts, Client); 760 } 761 return State->MetaDiagnostics.get(); 762 } 763 764 void SDiagsWriter::RemoveOldDiagnostics() { 765 if (!llvm::sys::fs::remove(State->OutputFile)) 766 return; 767 768 getMetaDiags()->Report(diag::warn_fe_serialized_diag_merge_failure); 769 // Disable merging child records, as whatever is in this file may be 770 // misleading. 771 MergeChildRecords = false; 772 } 773 774 void SDiagsWriter::finish() { 775 assert(!IsFinishing); 776 IsFinishing = true; 777 778 // The original instance is responsible for writing the file. 779 if (!OriginalInstance) 780 return; 781 782 // Finish off any diagnostic we were in the process of emitting. 783 if (State->EmittedAnyDiagBlocks) 784 ExitDiagBlock(); 785 786 if (MergeChildRecords) { 787 if (!State->EmittedAnyDiagBlocks) 788 // We have no diagnostics of our own, so we can just leave the child 789 // process' output alone 790 return; 791 792 if (llvm::sys::fs::exists(State->OutputFile)) 793 if (SDiagsMerger(*this).mergeRecordsFromFile(State->OutputFile.c_str())) 794 getMetaDiags()->Report(diag::warn_fe_serialized_diag_merge_failure); 795 } 796 797 std::error_code EC; 798 auto OS = std::make_unique<llvm::raw_fd_ostream>(State->OutputFile.c_str(), 799 EC, llvm::sys::fs::OF_None); 800 if (EC) { 801 getMetaDiags()->Report(diag::warn_fe_serialized_diag_failure) 802 << State->OutputFile << EC.message(); 803 OS->clear_error(); 804 return; 805 } 806 807 // Write the generated bitstream to "Out". 808 OS->write((char *)&State->Buffer.front(), State->Buffer.size()); 809 OS->flush(); 810 811 assert(!OS->has_error()); 812 if (OS->has_error()) { 813 getMetaDiags()->Report(diag::warn_fe_serialized_diag_failure) 814 << State->OutputFile << OS->error().message(); 815 OS->clear_error(); 816 } 817 } 818 819 std::error_code SDiagsMerger::visitStartOfDiagnostic() { 820 Writer.EnterDiagBlock(); 821 return std::error_code(); 822 } 823 824 std::error_code SDiagsMerger::visitEndOfDiagnostic() { 825 Writer.ExitDiagBlock(); 826 return std::error_code(); 827 } 828 829 std::error_code 830 SDiagsMerger::visitSourceRangeRecord(const serialized_diags::Location &Start, 831 const serialized_diags::Location &End) { 832 RecordData::value_type Record[] = { 833 RECORD_SOURCE_RANGE, FileLookup[Start.FileID], Start.Line, Start.Col, 834 Start.Offset, FileLookup[End.FileID], End.Line, End.Col, End.Offset}; 835 Writer.State->Stream.EmitRecordWithAbbrev( 836 Writer.State->Abbrevs.get(RECORD_SOURCE_RANGE), Record); 837 return std::error_code(); 838 } 839 840 std::error_code SDiagsMerger::visitDiagnosticRecord( 841 unsigned Severity, const serialized_diags::Location &Location, 842 unsigned Category, unsigned Flag, StringRef Message) { 843 RecordData::value_type Record[] = { 844 RECORD_DIAG, Severity, FileLookup[Location.FileID], Location.Line, 845 Location.Col, Location.Offset, CategoryLookup[Category], 846 Flag ? DiagFlagLookup[Flag] : 0, Message.size()}; 847 848 Writer.State->Stream.EmitRecordWithBlob( 849 Writer.State->Abbrevs.get(RECORD_DIAG), Record, Message); 850 return std::error_code(); 851 } 852 853 std::error_code 854 SDiagsMerger::visitFixitRecord(const serialized_diags::Location &Start, 855 const serialized_diags::Location &End, 856 StringRef Text) { 857 RecordData::value_type Record[] = {RECORD_FIXIT, FileLookup[Start.FileID], 858 Start.Line, Start.Col, Start.Offset, 859 FileLookup[End.FileID], End.Line, End.Col, 860 End.Offset, Text.size()}; 861 862 Writer.State->Stream.EmitRecordWithBlob( 863 Writer.State->Abbrevs.get(RECORD_FIXIT), Record, Text); 864 return std::error_code(); 865 } 866 867 std::error_code SDiagsMerger::visitFilenameRecord(unsigned ID, unsigned Size, 868 unsigned Timestamp, 869 StringRef Name) { 870 FileLookup[ID] = Writer.getEmitFile(Name.str().c_str()); 871 return std::error_code(); 872 } 873 874 std::error_code SDiagsMerger::visitCategoryRecord(unsigned ID, StringRef Name) { 875 CategoryLookup[ID] = Writer.getEmitCategory(ID); 876 return std::error_code(); 877 } 878 879 std::error_code SDiagsMerger::visitDiagFlagRecord(unsigned ID, StringRef Name) { 880 DiagFlagLookup[ID] = Writer.getEmitDiagnosticFlag(Name); 881 return std::error_code(); 882 } 883