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