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/Lex/Lexer.h" 18 #include "llvm/ADT/DenseSet.h" 19 #include "llvm/ADT/SmallString.h" 20 #include "llvm/ADT/StringRef.h" 21 #include "llvm/Support/raw_ostream.h" 22 #include <vector> 23 24 using namespace clang; 25 using namespace clang::serialized_diags; 26 27 namespace { 28 29 class AbbreviationMap { 30 llvm::DenseMap<unsigned, unsigned> Abbrevs; 31 public: 32 AbbreviationMap() {} 33 34 void set(unsigned recordID, unsigned abbrevID) { 35 assert(Abbrevs.find(recordID) == Abbrevs.end() 36 && "Abbreviation already set."); 37 Abbrevs[recordID] = abbrevID; 38 } 39 40 unsigned get(unsigned recordID) { 41 assert(Abbrevs.find(recordID) != Abbrevs.end() && 42 "Abbreviation not set."); 43 return Abbrevs[recordID]; 44 } 45 }; 46 47 typedef SmallVector<uint64_t, 64> RecordData; 48 typedef SmallVectorImpl<uint64_t> RecordDataImpl; 49 50 class SDiagsWriter; 51 52 class SDiagsRenderer : public DiagnosticNoteRenderer { 53 SDiagsWriter &Writer; 54 public: 55 SDiagsRenderer(SDiagsWriter &Writer, const LangOptions &LangOpts, 56 DiagnosticOptions *DiagOpts) 57 : DiagnosticNoteRenderer(LangOpts, DiagOpts), Writer(Writer) {} 58 59 virtual ~SDiagsRenderer() {} 60 61 protected: 62 void emitDiagnosticMessage(SourceLocation Loc, 63 PresumedLoc PLoc, 64 DiagnosticsEngine::Level Level, 65 StringRef Message, 66 ArrayRef<CharSourceRange> Ranges, 67 const SourceManager *SM, 68 DiagOrStoredDiag D) override; 69 70 void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc, 71 DiagnosticsEngine::Level Level, 72 ArrayRef<CharSourceRange> Ranges, 73 const SourceManager &SM) override {} 74 75 void emitNote(SourceLocation Loc, StringRef Message, 76 const SourceManager *SM) override; 77 78 void emitCodeContext(SourceLocation Loc, 79 DiagnosticsEngine::Level Level, 80 SmallVectorImpl<CharSourceRange>& Ranges, 81 ArrayRef<FixItHint> Hints, 82 const SourceManager &SM) override; 83 84 void beginDiagnostic(DiagOrStoredDiag D, 85 DiagnosticsEngine::Level Level) override; 86 void endDiagnostic(DiagOrStoredDiag D, 87 DiagnosticsEngine::Level Level) override; 88 }; 89 90 class SDiagsWriter : public DiagnosticConsumer { 91 friend class SDiagsRenderer; 92 93 struct SharedState; 94 95 explicit SDiagsWriter(IntrusiveRefCntPtr<SharedState> State) 96 : LangOpts(nullptr), OriginalInstance(false), State(State) {} 97 98 public: 99 SDiagsWriter(raw_ostream *os, DiagnosticOptions *diags) 100 : LangOpts(nullptr), OriginalInstance(true), 101 State(new SharedState(os, diags)) 102 { 103 EmitPreamble(); 104 } 105 106 ~SDiagsWriter() {} 107 108 void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, 109 const Diagnostic &Info) override; 110 111 void BeginSourceFile(const LangOptions &LO, const Preprocessor *PP) override { 112 LangOpts = &LO; 113 } 114 115 void finish() override; 116 117 private: 118 /// \brief Emit the preamble for the serialized diagnostics. 119 void EmitPreamble(); 120 121 /// \brief Emit the BLOCKINFO block. 122 void EmitBlockInfoBlock(); 123 124 /// \brief Emit the META data block. 125 void EmitMetaBlock(); 126 127 /// \brief Start a DIAG block. 128 void EnterDiagBlock(); 129 130 /// \brief End a DIAG block. 131 void ExitDiagBlock(); 132 133 /// \brief Emit a DIAG record. 134 void EmitDiagnosticMessage(SourceLocation Loc, 135 PresumedLoc PLoc, 136 DiagnosticsEngine::Level Level, 137 StringRef Message, 138 const SourceManager *SM, 139 DiagOrStoredDiag D); 140 141 /// \brief Emit FIXIT and SOURCE_RANGE records for a diagnostic. 142 void EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges, 143 ArrayRef<FixItHint> Hints, 144 const SourceManager &SM); 145 146 /// \brief Emit a record for a CharSourceRange. 147 void EmitCharSourceRange(CharSourceRange R, const SourceManager &SM); 148 149 /// \brief Emit the string information for the category. 150 unsigned getEmitCategory(unsigned category = 0); 151 152 /// \brief Emit the string information for diagnostic flags. 153 unsigned getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel, 154 unsigned DiagID = 0); 155 156 /// \brief Emit (lazily) the file string and retrieved the file identifier. 157 unsigned getEmitFile(const char *Filename); 158 159 /// \brief Add SourceLocation information the specified record. 160 void AddLocToRecord(SourceLocation Loc, const SourceManager *SM, 161 PresumedLoc PLoc, RecordDataImpl &Record, 162 unsigned TokSize = 0); 163 164 /// \brief Add SourceLocation information the specified record. 165 void AddLocToRecord(SourceLocation Loc, RecordDataImpl &Record, 166 const SourceManager *SM, 167 unsigned TokSize = 0) { 168 AddLocToRecord(Loc, SM, SM ? SM->getPresumedLoc(Loc) : PresumedLoc(), 169 Record, TokSize); 170 } 171 172 /// \brief Add CharSourceRange information the specified record. 173 void AddCharSourceRangeToRecord(CharSourceRange R, RecordDataImpl &Record, 174 const SourceManager &SM); 175 176 /// \brief The version of the diagnostics file. 177 enum { Version = 2 }; 178 179 /// \brief Language options, which can differ from one clone of this client 180 /// to another. 181 const LangOptions *LangOpts; 182 183 /// \brief Whether this is the original instance (rather than one of its 184 /// clones), responsible for writing the file at the end. 185 bool OriginalInstance; 186 187 /// \brief State that is shared among the various clones of this diagnostic 188 /// consumer. 189 struct SharedState : RefCountedBase<SharedState> { 190 SharedState(raw_ostream *os, DiagnosticOptions *diags) 191 : DiagOpts(diags), Stream(Buffer), OS(os), EmittedAnyDiagBlocks(false) { } 192 193 /// \brief Diagnostic options. 194 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts; 195 196 /// \brief The byte buffer for the serialized content. 197 SmallString<1024> Buffer; 198 199 /// \brief The BitStreamWriter for the serialized diagnostics. 200 llvm::BitstreamWriter Stream; 201 202 /// \brief The name of the diagnostics file. 203 std::unique_ptr<raw_ostream> OS; 204 205 /// \brief The set of constructed record abbreviations. 206 AbbreviationMap Abbrevs; 207 208 /// \brief A utility buffer for constructing record content. 209 RecordData Record; 210 211 /// \brief A text buffer for rendering diagnostic text. 212 SmallString<256> diagBuf; 213 214 /// \brief The collection of diagnostic categories used. 215 llvm::DenseSet<unsigned> Categories; 216 217 /// \brief The collection of files used. 218 llvm::DenseMap<const char *, unsigned> Files; 219 220 typedef llvm::DenseMap<const void *, std::pair<unsigned, StringRef> > 221 DiagFlagsTy; 222 223 /// \brief Map for uniquing strings. 224 DiagFlagsTy DiagFlags; 225 226 /// \brief Whether we have already started emission of any DIAG blocks. Once 227 /// this becomes \c true, we never close a DIAG block until we know that we're 228 /// starting another one or we're done. 229 bool EmittedAnyDiagBlocks; 230 }; 231 232 /// \brief State shared among the various clones of this diagnostic consumer. 233 IntrusiveRefCntPtr<SharedState> State; 234 }; 235 } // end anonymous namespace 236 237 namespace clang { 238 namespace serialized_diags { 239 DiagnosticConsumer *create(raw_ostream *OS, DiagnosticOptions *diags) { 240 return new SDiagsWriter(OS, diags); 241 } 242 } // end namespace serialized_diags 243 } // end namespace clang 244 245 //===----------------------------------------------------------------------===// 246 // Serialization methods. 247 //===----------------------------------------------------------------------===// 248 249 /// \brief Emits a block ID in the BLOCKINFO block. 250 static void EmitBlockID(unsigned ID, const char *Name, 251 llvm::BitstreamWriter &Stream, 252 RecordDataImpl &Record) { 253 Record.clear(); 254 Record.push_back(ID); 255 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record); 256 257 // Emit the block name if present. 258 if (!Name || Name[0] == 0) 259 return; 260 261 Record.clear(); 262 263 while (*Name) 264 Record.push_back(*Name++); 265 266 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record); 267 } 268 269 /// \brief Emits a record ID in the BLOCKINFO block. 270 static void EmitRecordID(unsigned ID, const char *Name, 271 llvm::BitstreamWriter &Stream, 272 RecordDataImpl &Record){ 273 Record.clear(); 274 Record.push_back(ID); 275 276 while (*Name) 277 Record.push_back(*Name++); 278 279 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record); 280 } 281 282 void SDiagsWriter::AddLocToRecord(SourceLocation Loc, 283 const SourceManager *SM, 284 PresumedLoc PLoc, 285 RecordDataImpl &Record, 286 unsigned TokSize) { 287 if (PLoc.isInvalid()) { 288 // Emit a "sentinel" location. 289 Record.push_back((unsigned)0); // File. 290 Record.push_back((unsigned)0); // Line. 291 Record.push_back((unsigned)0); // Column. 292 Record.push_back((unsigned)0); // Offset. 293 return; 294 } 295 296 Record.push_back(getEmitFile(PLoc.getFilename())); 297 Record.push_back(PLoc.getLine()); 298 Record.push_back(PLoc.getColumn()+TokSize); 299 Record.push_back(SM->getFileOffset(Loc)); 300 } 301 302 void SDiagsWriter::AddCharSourceRangeToRecord(CharSourceRange Range, 303 RecordDataImpl &Record, 304 const SourceManager &SM) { 305 AddLocToRecord(Range.getBegin(), Record, &SM); 306 unsigned TokSize = 0; 307 if (Range.isTokenRange()) 308 TokSize = Lexer::MeasureTokenLength(Range.getEnd(), 309 SM, *LangOpts); 310 311 AddLocToRecord(Range.getEnd(), Record, &SM, TokSize); 312 } 313 314 unsigned SDiagsWriter::getEmitFile(const char *FileName){ 315 if (!FileName) 316 return 0; 317 318 unsigned &entry = State->Files[FileName]; 319 if (entry) 320 return entry; 321 322 // Lazily generate the record for the file. 323 entry = State->Files.size(); 324 RecordData Record; 325 Record.push_back(RECORD_FILENAME); 326 Record.push_back(entry); 327 Record.push_back(0); // For legacy. 328 Record.push_back(0); // For legacy. 329 StringRef Name(FileName); 330 Record.push_back(Name.size()); 331 State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_FILENAME), Record, 332 Name); 333 334 return entry; 335 } 336 337 void SDiagsWriter::EmitCharSourceRange(CharSourceRange R, 338 const SourceManager &SM) { 339 State->Record.clear(); 340 State->Record.push_back(RECORD_SOURCE_RANGE); 341 AddCharSourceRangeToRecord(R, State->Record, SM); 342 State->Stream.EmitRecordWithAbbrev(State->Abbrevs.get(RECORD_SOURCE_RANGE), 343 State->Record); 344 } 345 346 /// \brief Emits the preamble of the diagnostics file. 347 void SDiagsWriter::EmitPreamble() { 348 // Emit the file header. 349 State->Stream.Emit((unsigned)'D', 8); 350 State->Stream.Emit((unsigned)'I', 8); 351 State->Stream.Emit((unsigned)'A', 8); 352 State->Stream.Emit((unsigned)'G', 8); 353 354 EmitBlockInfoBlock(); 355 EmitMetaBlock(); 356 } 357 358 static void AddSourceLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) { 359 using namespace llvm; 360 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // File ID. 361 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Line. 362 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Column. 363 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Offset; 364 } 365 366 static void AddRangeLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) { 367 AddSourceLocationAbbrev(Abbrev); 368 AddSourceLocationAbbrev(Abbrev); 369 } 370 371 void SDiagsWriter::EmitBlockInfoBlock() { 372 State->Stream.EnterBlockInfoBlock(3); 373 374 using namespace llvm; 375 llvm::BitstreamWriter &Stream = State->Stream; 376 RecordData &Record = State->Record; 377 AbbreviationMap &Abbrevs = State->Abbrevs; 378 379 // ==---------------------------------------------------------------------==// 380 // The subsequent records and Abbrevs are for the "Meta" block. 381 // ==---------------------------------------------------------------------==// 382 383 EmitBlockID(BLOCK_META, "Meta", Stream, Record); 384 EmitRecordID(RECORD_VERSION, "Version", Stream, Record); 385 BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); 386 Abbrev->Add(BitCodeAbbrevOp(RECORD_VERSION)); 387 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); 388 Abbrevs.set(RECORD_VERSION, Stream.EmitBlockInfoAbbrev(BLOCK_META, Abbrev)); 389 390 // ==---------------------------------------------------------------------==// 391 // The subsequent records and Abbrevs are for the "Diagnostic" block. 392 // ==---------------------------------------------------------------------==// 393 394 EmitBlockID(BLOCK_DIAG, "Diag", Stream, Record); 395 EmitRecordID(RECORD_DIAG, "DiagInfo", Stream, Record); 396 EmitRecordID(RECORD_SOURCE_RANGE, "SrcRange", Stream, Record); 397 EmitRecordID(RECORD_CATEGORY, "CatName", Stream, Record); 398 EmitRecordID(RECORD_DIAG_FLAG, "DiagFlag", Stream, Record); 399 EmitRecordID(RECORD_FILENAME, "FileName", Stream, Record); 400 EmitRecordID(RECORD_FIXIT, "FixIt", Stream, Record); 401 402 // Emit abbreviation for RECORD_DIAG. 403 Abbrev = new BitCodeAbbrev(); 404 Abbrev->Add(BitCodeAbbrevOp(RECORD_DIAG)); 405 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Diag level. 406 AddSourceLocationAbbrev(Abbrev); 407 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Category. 408 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped Diag ID. 409 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size. 410 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Diagnostc text. 411 Abbrevs.set(RECORD_DIAG, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev)); 412 413 // Emit abbrevation for RECORD_CATEGORY. 414 Abbrev = new BitCodeAbbrev(); 415 Abbrev->Add(BitCodeAbbrevOp(RECORD_CATEGORY)); 416 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Category ID. 417 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8)); // Text size. 418 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Category text. 419 Abbrevs.set(RECORD_CATEGORY, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev)); 420 421 // Emit abbrevation for RECORD_SOURCE_RANGE. 422 Abbrev = new BitCodeAbbrev(); 423 Abbrev->Add(BitCodeAbbrevOp(RECORD_SOURCE_RANGE)); 424 AddRangeLocationAbbrev(Abbrev); 425 Abbrevs.set(RECORD_SOURCE_RANGE, 426 Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev)); 427 428 // Emit the abbreviation for RECORD_DIAG_FLAG. 429 Abbrev = new BitCodeAbbrev(); 430 Abbrev->Add(BitCodeAbbrevOp(RECORD_DIAG_FLAG)); 431 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped Diag ID. 432 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size. 433 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Flag name text. 434 Abbrevs.set(RECORD_DIAG_FLAG, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, 435 Abbrev)); 436 437 // Emit the abbreviation for RECORD_FILENAME. 438 Abbrev = new BitCodeAbbrev(); 439 Abbrev->Add(BitCodeAbbrevOp(RECORD_FILENAME)); 440 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped file ID. 441 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Size. 442 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Modifcation time. 443 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size. 444 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name text. 445 Abbrevs.set(RECORD_FILENAME, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, 446 Abbrev)); 447 448 // Emit the abbreviation for RECORD_FIXIT. 449 Abbrev = new BitCodeAbbrev(); 450 Abbrev->Add(BitCodeAbbrevOp(RECORD_FIXIT)); 451 AddRangeLocationAbbrev(Abbrev); 452 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size. 453 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // FixIt text. 454 Abbrevs.set(RECORD_FIXIT, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, 455 Abbrev)); 456 457 Stream.ExitBlock(); 458 } 459 460 void SDiagsWriter::EmitMetaBlock() { 461 llvm::BitstreamWriter &Stream = State->Stream; 462 RecordData &Record = State->Record; 463 AbbreviationMap &Abbrevs = State->Abbrevs; 464 465 Stream.EnterSubblock(BLOCK_META, 3); 466 Record.clear(); 467 Record.push_back(RECORD_VERSION); 468 Record.push_back(Version); 469 Stream.EmitRecordWithAbbrev(Abbrevs.get(RECORD_VERSION), Record); 470 Stream.ExitBlock(); 471 } 472 473 unsigned SDiagsWriter::getEmitCategory(unsigned int category) { 474 if (State->Categories.count(category)) 475 return category; 476 477 State->Categories.insert(category); 478 479 // We use a local version of 'Record' so that we can be generating 480 // another record when we lazily generate one for the category entry. 481 RecordData Record; 482 Record.push_back(RECORD_CATEGORY); 483 Record.push_back(category); 484 StringRef catName = DiagnosticIDs::getCategoryNameFromID(category); 485 Record.push_back(catName.size()); 486 State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_CATEGORY), Record, 487 catName); 488 489 return category; 490 } 491 492 unsigned SDiagsWriter::getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel, 493 unsigned DiagID) { 494 if (DiagLevel == DiagnosticsEngine::Note) 495 return 0; // No flag for notes. 496 497 StringRef FlagName = DiagnosticIDs::getWarningOptionForDiag(DiagID); 498 if (FlagName.empty()) 499 return 0; 500 501 // Here we assume that FlagName points to static data whose pointer 502 // value is fixed. This allows us to unique by diagnostic groups. 503 const void *data = FlagName.data(); 504 std::pair<unsigned, StringRef> &entry = State->DiagFlags[data]; 505 if (entry.first == 0) { 506 entry.first = State->DiagFlags.size(); 507 entry.second = FlagName; 508 509 // Lazily emit the string in a separate record. 510 RecordData Record; 511 Record.push_back(RECORD_DIAG_FLAG); 512 Record.push_back(entry.first); 513 Record.push_back(FlagName.size()); 514 State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_DIAG_FLAG), 515 Record, FlagName); 516 } 517 518 return entry.first; 519 } 520 521 void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, 522 const Diagnostic &Info) { 523 // Enter the block for a non-note diagnostic immediately, rather than waiting 524 // for beginDiagnostic, in case associated notes are emitted before we get 525 // there. 526 if (DiagLevel != DiagnosticsEngine::Note) { 527 if (State->EmittedAnyDiagBlocks) 528 ExitDiagBlock(); 529 530 EnterDiagBlock(); 531 State->EmittedAnyDiagBlocks = true; 532 } 533 534 // Compute the diagnostic text. 535 State->diagBuf.clear(); 536 Info.FormatDiagnostic(State->diagBuf); 537 538 if (Info.getLocation().isInvalid()) { 539 // Special-case diagnostics with no location. We may not have entered a 540 // source file in this case, so we can't use the normal DiagnosticsRenderer 541 // machinery. 542 543 // Make sure we bracket all notes as "sub-diagnostics". This matches 544 // the behavior in SDiagsRenderer::emitDiagnostic(). 545 if (DiagLevel == DiagnosticsEngine::Note) 546 EnterDiagBlock(); 547 548 EmitDiagnosticMessage(SourceLocation(), PresumedLoc(), DiagLevel, 549 State->diagBuf, nullptr, &Info); 550 551 if (DiagLevel == DiagnosticsEngine::Note) 552 ExitDiagBlock(); 553 554 return; 555 } 556 557 assert(Info.hasSourceManager() && LangOpts && 558 "Unexpected diagnostic with valid location outside of a source file"); 559 SDiagsRenderer Renderer(*this, *LangOpts, &*State->DiagOpts); 560 Renderer.emitDiagnostic(Info.getLocation(), DiagLevel, 561 State->diagBuf.str(), 562 Info.getRanges(), 563 Info.getFixItHints(), 564 &Info.getSourceManager(), 565 &Info); 566 } 567 568 static serialized_diags::Level getStableLevel(DiagnosticsEngine::Level Level) { 569 switch (Level) { 570 #define CASE(X) case DiagnosticsEngine::X: return serialized_diags::X; 571 CASE(Ignored) 572 CASE(Note) 573 CASE(Remark) 574 CASE(Warning) 575 CASE(Error) 576 CASE(Fatal) 577 #undef CASE 578 } 579 580 llvm_unreachable("invalid diagnostic level"); 581 } 582 583 void SDiagsWriter::EmitDiagnosticMessage(SourceLocation Loc, 584 PresumedLoc PLoc, 585 DiagnosticsEngine::Level Level, 586 StringRef Message, 587 const SourceManager *SM, 588 DiagOrStoredDiag D) { 589 llvm::BitstreamWriter &Stream = State->Stream; 590 RecordData &Record = State->Record; 591 AbbreviationMap &Abbrevs = State->Abbrevs; 592 593 // Emit the RECORD_DIAG record. 594 Record.clear(); 595 Record.push_back(RECORD_DIAG); 596 Record.push_back(getStableLevel(Level)); 597 AddLocToRecord(Loc, SM, PLoc, Record); 598 599 if (const Diagnostic *Info = D.dyn_cast<const Diagnostic*>()) { 600 // Emit the category string lazily and get the category ID. 601 unsigned DiagID = DiagnosticIDs::getCategoryNumberForDiag(Info->getID()); 602 Record.push_back(getEmitCategory(DiagID)); 603 // Emit the diagnostic flag string lazily and get the mapped ID. 604 Record.push_back(getEmitDiagnosticFlag(Level, Info->getID())); 605 } else { 606 Record.push_back(getEmitCategory()); 607 Record.push_back(getEmitDiagnosticFlag(Level)); 608 } 609 610 Record.push_back(Message.size()); 611 Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG), Record, Message); 612 } 613 614 void 615 SDiagsRenderer::emitDiagnosticMessage(SourceLocation Loc, 616 PresumedLoc PLoc, 617 DiagnosticsEngine::Level Level, 618 StringRef Message, 619 ArrayRef<clang::CharSourceRange> Ranges, 620 const SourceManager *SM, 621 DiagOrStoredDiag D) { 622 Writer.EmitDiagnosticMessage(Loc, PLoc, Level, Message, SM, D); 623 } 624 625 void SDiagsWriter::EnterDiagBlock() { 626 State->Stream.EnterSubblock(BLOCK_DIAG, 4); 627 } 628 629 void SDiagsWriter::ExitDiagBlock() { 630 State->Stream.ExitBlock(); 631 } 632 633 void SDiagsRenderer::beginDiagnostic(DiagOrStoredDiag D, 634 DiagnosticsEngine::Level Level) { 635 if (Level == DiagnosticsEngine::Note) 636 Writer.EnterDiagBlock(); 637 } 638 639 void SDiagsRenderer::endDiagnostic(DiagOrStoredDiag D, 640 DiagnosticsEngine::Level Level) { 641 // Only end note diagnostics here, because we can't be sure when we've seen 642 // the last note associated with a non-note diagnostic. 643 if (Level == DiagnosticsEngine::Note) 644 Writer.ExitDiagBlock(); 645 } 646 647 void SDiagsWriter::EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges, 648 ArrayRef<FixItHint> Hints, 649 const SourceManager &SM) { 650 llvm::BitstreamWriter &Stream = State->Stream; 651 RecordData &Record = State->Record; 652 AbbreviationMap &Abbrevs = State->Abbrevs; 653 654 // Emit Source Ranges. 655 for (ArrayRef<CharSourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); 656 I != E; ++I) 657 if (I->isValid()) 658 EmitCharSourceRange(*I, SM); 659 660 // Emit FixIts. 661 for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end(); 662 I != E; ++I) { 663 const FixItHint &Fix = *I; 664 if (Fix.isNull()) 665 continue; 666 Record.clear(); 667 Record.push_back(RECORD_FIXIT); 668 AddCharSourceRangeToRecord(Fix.RemoveRange, Record, SM); 669 Record.push_back(Fix.CodeToInsert.size()); 670 Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_FIXIT), Record, 671 Fix.CodeToInsert); 672 } 673 } 674 675 void SDiagsRenderer::emitCodeContext(SourceLocation Loc, 676 DiagnosticsEngine::Level Level, 677 SmallVectorImpl<CharSourceRange> &Ranges, 678 ArrayRef<FixItHint> Hints, 679 const SourceManager &SM) { 680 Writer.EmitCodeContext(Ranges, Hints, SM); 681 } 682 683 void SDiagsRenderer::emitNote(SourceLocation Loc, StringRef Message, 684 const SourceManager *SM) { 685 Writer.EnterDiagBlock(); 686 PresumedLoc PLoc = SM ? SM->getPresumedLoc(Loc) : PresumedLoc(); 687 Writer.EmitDiagnosticMessage(Loc, PLoc, DiagnosticsEngine::Note, 688 Message, SM, DiagOrStoredDiag()); 689 Writer.ExitDiagBlock(); 690 } 691 692 void SDiagsWriter::finish() { 693 // The original instance is responsible for writing the file. 694 if (!OriginalInstance) 695 return; 696 697 // Finish off any diagnostic we were in the process of emitting. 698 if (State->EmittedAnyDiagBlocks) 699 ExitDiagBlock(); 700 701 // Write the generated bitstream to "Out". 702 State->OS->write((char *)&State->Buffer.front(), State->Buffer.size()); 703 State->OS->flush(); 704 705 State->OS.reset(nullptr); 706 } 707