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