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