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