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