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