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 <vector> 11 #include "llvm/Support/raw_ostream.h" 12 #include "llvm/ADT/StringRef.h" 13 #include "llvm/ADT/SmallString.h" 14 #include "llvm/ADT/DenseSet.h" 15 #include "clang/Basic/SourceManager.h" 16 #include "clang/Basic/FileManager.h" 17 #include "clang/Basic/Diagnostic.h" 18 #include "clang/Basic/Version.h" 19 #include "clang/Lex/Lexer.h" 20 #include "clang/Frontend/SerializedDiagnosticPrinter.h" 21 #include "clang/Frontend/DiagnosticRenderer.h" 22 23 using namespace clang; 24 using namespace clang::serialized_diags; 25 26 namespace { 27 28 class AbbreviationMap { 29 llvm::DenseMap<unsigned, unsigned> Abbrevs; 30 public: 31 AbbreviationMap() {} 32 33 void set(unsigned recordID, unsigned abbrevID) { 34 assert(Abbrevs.find(recordID) == Abbrevs.end() 35 && "Abbreviation already set."); 36 Abbrevs[recordID] = abbrevID; 37 } 38 39 unsigned get(unsigned recordID) { 40 assert(Abbrevs.find(recordID) != Abbrevs.end() && 41 "Abbreviation not set."); 42 return Abbrevs[recordID]; 43 } 44 }; 45 46 typedef llvm::SmallVector<uint64_t, 64> RecordData; 47 typedef llvm::SmallVectorImpl<uint64_t> RecordDataImpl; 48 49 class SDiagsWriter; 50 51 class SDiagsRenderer : public DiagnosticNoteRenderer { 52 SDiagsWriter &Writer; 53 RecordData &Record; 54 public: 55 SDiagsRenderer(SDiagsWriter &Writer, RecordData &Record, 56 const SourceManager &SM, 57 const LangOptions &LangOpts, 58 const DiagnosticOptions &DiagOpts) 59 : DiagnosticNoteRenderer(SM, LangOpts, DiagOpts), 60 Writer(Writer), Record(Record){} 61 62 virtual ~SDiagsRenderer() {} 63 64 protected: 65 virtual void emitDiagnosticMessage(SourceLocation Loc, 66 PresumedLoc PLoc, 67 DiagnosticsEngine::Level Level, 68 StringRef Message, 69 ArrayRef<CharSourceRange> Ranges, 70 DiagOrStoredDiag D); 71 72 virtual void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc, 73 DiagnosticsEngine::Level Level, 74 ArrayRef<CharSourceRange> Ranges) {} 75 76 void emitNote(SourceLocation Loc, StringRef Message); 77 78 virtual void emitCodeContext(SourceLocation Loc, 79 DiagnosticsEngine::Level Level, 80 SmallVectorImpl<CharSourceRange>& Ranges, 81 ArrayRef<FixItHint> Hints); 82 83 virtual void beginDiagnostic(DiagOrStoredDiag D, 84 DiagnosticsEngine::Level Level); 85 virtual void endDiagnostic(DiagOrStoredDiag D, 86 DiagnosticsEngine::Level Level); 87 }; 88 89 class SDiagsWriter : public DiagnosticConsumer { 90 friend class SDiagsRenderer; 91 public: 92 explicit SDiagsWriter(llvm::raw_ostream *os, const DiagnosticOptions &diags) 93 : LangOpts(0), DiagOpts(diags), 94 Stream(Buffer), OS(os), inNonNoteDiagnostic(false) 95 { 96 EmitPreamble(); 97 } 98 99 ~SDiagsWriter() {} 100 101 void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, 102 const Diagnostic &Info); 103 104 void BeginSourceFile(const LangOptions &LO, 105 const Preprocessor *PP) { 106 LangOpts = &LO; 107 } 108 109 virtual void finish(); 110 111 DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const { 112 // It makes no sense to clone this. 113 return 0; 114 } 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 Emit a record for a CharSourceRange. 127 void EmitCharSourceRange(CharSourceRange R, const SourceManager &SM); 128 129 /// \brief Emit the string information for the category. 130 unsigned getEmitCategory(unsigned category = 0); 131 132 /// \brief Emit the string information for diagnostic flags. 133 unsigned getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel, 134 unsigned DiagID = 0); 135 136 /// \brief Emit (lazily) the file string and retrieved the file identifier. 137 unsigned getEmitFile(const char *Filename); 138 139 /// \brief Add SourceLocation information the specified record. 140 void AddLocToRecord(SourceLocation Loc, const SourceManager &SM, 141 PresumedLoc PLoc, RecordDataImpl &Record, 142 unsigned TokSize = 0); 143 144 /// \brief Add SourceLocation information the specified record. 145 void AddLocToRecord(SourceLocation Loc, RecordDataImpl &Record, 146 const SourceManager &SM, 147 unsigned TokSize = 0) { 148 AddLocToRecord(Loc, SM, SM.getPresumedLoc(Loc), Record, TokSize); 149 } 150 151 /// \brief Add CharSourceRange information the specified record. 152 void AddCharSourceRangeToRecord(CharSourceRange R, RecordDataImpl &Record, 153 const SourceManager &SM); 154 155 /// \brief The version of the diagnostics file. 156 enum { Version = 1 }; 157 158 const LangOptions *LangOpts; 159 const DiagnosticOptions &DiagOpts; 160 161 /// \brief The byte buffer for the serialized content. 162 SmallString<1024> Buffer; 163 164 /// \brief The BitStreamWriter for the serialized diagnostics. 165 llvm::BitstreamWriter Stream; 166 167 /// \brief The name of the diagnostics file. 168 OwningPtr<llvm::raw_ostream> OS; 169 170 /// \brief The set of constructed record abbreviations. 171 AbbreviationMap Abbrevs; 172 173 /// \brief A utility buffer for constructing record content. 174 RecordData Record; 175 176 /// \brief A text buffer for rendering diagnostic text. 177 SmallString<256> diagBuf; 178 179 /// \brief The collection of diagnostic categories used. 180 llvm::DenseSet<unsigned> Categories; 181 182 /// \brief The collection of files used. 183 llvm::DenseMap<const char *, unsigned> Files; 184 185 typedef llvm::DenseMap<const void *, std::pair<unsigned, llvm::StringRef> > 186 DiagFlagsTy; 187 188 /// \brief Map for uniquing strings. 189 DiagFlagsTy DiagFlags; 190 191 /// \brief Flag indicating whether or not we are in the process of 192 /// emitting a non-note diagnostic. 193 bool inNonNoteDiagnostic; 194 }; 195 } // end anonymous namespace 196 197 namespace clang { 198 namespace serialized_diags { 199 DiagnosticConsumer *create(llvm::raw_ostream *OS, 200 const DiagnosticOptions &diags) { 201 return new SDiagsWriter(OS, diags); 202 } 203 } // end namespace serialized_diags 204 } // end namespace clang 205 206 //===----------------------------------------------------------------------===// 207 // Serialization methods. 208 //===----------------------------------------------------------------------===// 209 210 /// \brief Emits a block ID in the BLOCKINFO block. 211 static void EmitBlockID(unsigned ID, const char *Name, 212 llvm::BitstreamWriter &Stream, 213 RecordDataImpl &Record) { 214 Record.clear(); 215 Record.push_back(ID); 216 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record); 217 218 // Emit the block name if present. 219 if (Name == 0 || Name[0] == 0) 220 return; 221 222 Record.clear(); 223 224 while (*Name) 225 Record.push_back(*Name++); 226 227 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record); 228 } 229 230 /// \brief Emits a record ID in the BLOCKINFO block. 231 static void EmitRecordID(unsigned ID, const char *Name, 232 llvm::BitstreamWriter &Stream, 233 RecordDataImpl &Record){ 234 Record.clear(); 235 Record.push_back(ID); 236 237 while (*Name) 238 Record.push_back(*Name++); 239 240 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record); 241 } 242 243 void SDiagsWriter::AddLocToRecord(SourceLocation Loc, 244 const SourceManager &SM, 245 PresumedLoc PLoc, 246 RecordDataImpl &Record, 247 unsigned TokSize) { 248 if (PLoc.isInvalid()) { 249 // Emit a "sentinel" location. 250 Record.push_back((unsigned)0); // File. 251 Record.push_back((unsigned)0); // Line. 252 Record.push_back((unsigned)0); // Column. 253 Record.push_back((unsigned)0); // Offset. 254 return; 255 } 256 257 Record.push_back(getEmitFile(PLoc.getFilename())); 258 Record.push_back(PLoc.getLine()); 259 Record.push_back(PLoc.getColumn()+TokSize); 260 Record.push_back(SM.getFileOffset(Loc)); 261 } 262 263 void SDiagsWriter::AddCharSourceRangeToRecord(CharSourceRange Range, 264 RecordDataImpl &Record, 265 const SourceManager &SM) { 266 AddLocToRecord(Range.getBegin(), Record, SM); 267 unsigned TokSize = 0; 268 if (Range.isTokenRange()) 269 TokSize = Lexer::MeasureTokenLength(Range.getEnd(), 270 SM, *LangOpts); 271 272 AddLocToRecord(Range.getEnd(), Record, SM, TokSize); 273 } 274 275 unsigned SDiagsWriter::getEmitFile(const char *FileName){ 276 if (!FileName) 277 return 0; 278 279 unsigned &entry = Files[FileName]; 280 if (entry) 281 return entry; 282 283 // Lazily generate the record for the file. 284 entry = Files.size(); 285 RecordData Record; 286 Record.push_back(RECORD_FILENAME); 287 Record.push_back(entry); 288 Record.push_back(0); // For legacy. 289 Record.push_back(0); // For legacy. 290 StringRef Name(FileName); 291 Record.push_back(Name.size()); 292 Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_FILENAME), Record, Name); 293 294 return entry; 295 } 296 297 void SDiagsWriter::EmitCharSourceRange(CharSourceRange R, 298 const SourceManager &SM) { 299 Record.clear(); 300 Record.push_back(RECORD_SOURCE_RANGE); 301 AddCharSourceRangeToRecord(R, Record, SM); 302 Stream.EmitRecordWithAbbrev(Abbrevs.get(RECORD_SOURCE_RANGE), Record); 303 } 304 305 /// \brief Emits the preamble of the diagnostics file. 306 void SDiagsWriter::EmitPreamble() { 307 // Emit the file header. 308 Stream.Emit((unsigned)'D', 8); 309 Stream.Emit((unsigned)'I', 8); 310 Stream.Emit((unsigned)'A', 8); 311 Stream.Emit((unsigned)'G', 8); 312 313 EmitBlockInfoBlock(); 314 EmitMetaBlock(); 315 } 316 317 static void AddSourceLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) { 318 using namespace llvm; 319 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // File ID. 320 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Line. 321 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Column. 322 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Offset; 323 } 324 325 static void AddRangeLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) { 326 AddSourceLocationAbbrev(Abbrev); 327 AddSourceLocationAbbrev(Abbrev); 328 } 329 330 void SDiagsWriter::EmitBlockInfoBlock() { 331 Stream.EnterBlockInfoBlock(3); 332 333 using namespace llvm; 334 335 // ==---------------------------------------------------------------------==// 336 // The subsequent records and Abbrevs are for the "Meta" block. 337 // ==---------------------------------------------------------------------==// 338 339 EmitBlockID(BLOCK_META, "Meta", Stream, Record); 340 EmitRecordID(RECORD_VERSION, "Version", Stream, Record); 341 BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); 342 Abbrev->Add(BitCodeAbbrevOp(RECORD_VERSION)); 343 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); 344 Abbrevs.set(RECORD_VERSION, Stream.EmitBlockInfoAbbrev(BLOCK_META, Abbrev)); 345 346 // ==---------------------------------------------------------------------==// 347 // The subsequent records and Abbrevs are for the "Diagnostic" block. 348 // ==---------------------------------------------------------------------==// 349 350 EmitBlockID(BLOCK_DIAG, "Diag", Stream, Record); 351 EmitRecordID(RECORD_DIAG, "DiagInfo", Stream, Record); 352 EmitRecordID(RECORD_SOURCE_RANGE, "SrcRange", Stream, Record); 353 EmitRecordID(RECORD_CATEGORY, "CatName", Stream, Record); 354 EmitRecordID(RECORD_DIAG_FLAG, "DiagFlag", Stream, Record); 355 EmitRecordID(RECORD_FILENAME, "FileName", Stream, Record); 356 EmitRecordID(RECORD_FIXIT, "FixIt", Stream, Record); 357 358 // Emit abbreviation for RECORD_DIAG. 359 Abbrev = new BitCodeAbbrev(); 360 Abbrev->Add(BitCodeAbbrevOp(RECORD_DIAG)); 361 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Diag level. 362 AddSourceLocationAbbrev(Abbrev); 363 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Category. 364 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped Diag ID. 365 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size. 366 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Diagnostc text. 367 Abbrevs.set(RECORD_DIAG, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev)); 368 369 // Emit abbrevation for RECORD_CATEGORY. 370 Abbrev = new BitCodeAbbrev(); 371 Abbrev->Add(BitCodeAbbrevOp(RECORD_CATEGORY)); 372 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Category ID. 373 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8)); // Text size. 374 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Category text. 375 Abbrevs.set(RECORD_CATEGORY, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev)); 376 377 // Emit abbrevation for RECORD_SOURCE_RANGE. 378 Abbrev = new BitCodeAbbrev(); 379 Abbrev->Add(BitCodeAbbrevOp(RECORD_SOURCE_RANGE)); 380 AddRangeLocationAbbrev(Abbrev); 381 Abbrevs.set(RECORD_SOURCE_RANGE, 382 Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev)); 383 384 // Emit the abbreviation for RECORD_DIAG_FLAG. 385 Abbrev = new BitCodeAbbrev(); 386 Abbrev->Add(BitCodeAbbrevOp(RECORD_DIAG_FLAG)); 387 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped Diag ID. 388 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size. 389 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Flag name text. 390 Abbrevs.set(RECORD_DIAG_FLAG, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, 391 Abbrev)); 392 393 // Emit the abbreviation for RECORD_FILENAME. 394 Abbrev = new BitCodeAbbrev(); 395 Abbrev->Add(BitCodeAbbrevOp(RECORD_FILENAME)); 396 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped file ID. 397 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Size. 398 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Modifcation time. 399 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size. 400 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name text. 401 Abbrevs.set(RECORD_FILENAME, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, 402 Abbrev)); 403 404 // Emit the abbreviation for RECORD_FIXIT. 405 Abbrev = new BitCodeAbbrev(); 406 Abbrev->Add(BitCodeAbbrevOp(RECORD_FIXIT)); 407 AddRangeLocationAbbrev(Abbrev); 408 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size. 409 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // FixIt text. 410 Abbrevs.set(RECORD_FIXIT, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, 411 Abbrev)); 412 413 Stream.ExitBlock(); 414 } 415 416 void SDiagsWriter::EmitMetaBlock() { 417 Stream.EnterSubblock(BLOCK_META, 3); 418 Record.clear(); 419 Record.push_back(RECORD_VERSION); 420 Record.push_back(Version); 421 Stream.EmitRecordWithAbbrev(Abbrevs.get(RECORD_VERSION), Record); 422 Stream.ExitBlock(); 423 } 424 425 unsigned SDiagsWriter::getEmitCategory(unsigned int category) { 426 if (Categories.count(category)) 427 return category; 428 429 Categories.insert(category); 430 431 // We use a local version of 'Record' so that we can be generating 432 // another record when we lazily generate one for the category entry. 433 RecordData Record; 434 Record.push_back(RECORD_CATEGORY); 435 Record.push_back(category); 436 StringRef catName = DiagnosticIDs::getCategoryNameFromID(category); 437 Record.push_back(catName.size()); 438 Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_CATEGORY), Record, catName); 439 440 return category; 441 } 442 443 unsigned SDiagsWriter::getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel, 444 unsigned DiagID) { 445 if (DiagLevel == DiagnosticsEngine::Note) 446 return 0; // No flag for notes. 447 448 StringRef FlagName = DiagnosticIDs::getWarningOptionForDiag(DiagID); 449 if (FlagName.empty()) 450 return 0; 451 452 // Here we assume that FlagName points to static data whose pointer 453 // value is fixed. This allows us to unique by diagnostic groups. 454 const void *data = FlagName.data(); 455 std::pair<unsigned, StringRef> &entry = DiagFlags[data]; 456 if (entry.first == 0) { 457 entry.first = DiagFlags.size(); 458 entry.second = FlagName; 459 460 // Lazily emit the string in a separate record. 461 RecordData Record; 462 Record.push_back(RECORD_DIAG_FLAG); 463 Record.push_back(entry.first); 464 Record.push_back(FlagName.size()); 465 Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG_FLAG), 466 Record, FlagName); 467 } 468 469 return entry.first; 470 } 471 472 void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, 473 const Diagnostic &Info) { 474 if (DiagLevel != DiagnosticsEngine::Note) { 475 if (inNonNoteDiagnostic) { 476 // We have encountered a non-note diagnostic. Finish up the previous 477 // diagnostic block before starting a new one. 478 Stream.ExitBlock(); 479 } 480 inNonNoteDiagnostic = true; 481 } 482 483 // Compute the diagnostic text. 484 diagBuf.clear(); 485 Info.FormatDiagnostic(diagBuf); 486 487 SourceManager &SM = Info.getSourceManager(); 488 SDiagsRenderer Renderer(*this, Record, SM, *LangOpts, DiagOpts); 489 Renderer.emitDiagnostic(Info.getLocation(), DiagLevel, 490 diagBuf.str(), 491 Info.getRanges(), 492 llvm::makeArrayRef(Info.getFixItHints(), 493 Info.getNumFixItHints()), 494 &Info); 495 } 496 497 void 498 SDiagsRenderer::emitDiagnosticMessage(SourceLocation Loc, 499 PresumedLoc PLoc, 500 DiagnosticsEngine::Level Level, 501 StringRef Message, 502 ArrayRef<clang::CharSourceRange> Ranges, 503 DiagOrStoredDiag D) { 504 // Emit the RECORD_DIAG record. 505 Writer.Record.clear(); 506 Writer.Record.push_back(RECORD_DIAG); 507 Writer.Record.push_back(Level); 508 Writer.AddLocToRecord(Loc, SM, PLoc, Record); 509 510 if (const Diagnostic *Info = D.dyn_cast<const Diagnostic*>()) { 511 // Emit the category string lazily and get the category ID. 512 unsigned DiagID = DiagnosticIDs::getCategoryNumberForDiag(Info->getID()); 513 Writer.Record.push_back(Writer.getEmitCategory(DiagID)); 514 // Emit the diagnostic flag string lazily and get the mapped ID. 515 Writer.Record.push_back(Writer.getEmitDiagnosticFlag(Level, Info->getID())); 516 } 517 else { 518 Writer.Record.push_back(Writer.getEmitCategory()); 519 Writer.Record.push_back(Writer.getEmitDiagnosticFlag(Level)); 520 } 521 522 Writer.Record.push_back(Message.size()); 523 Writer.Stream.EmitRecordWithBlob(Writer.Abbrevs.get(RECORD_DIAG), 524 Writer.Record, Message); 525 } 526 527 void SDiagsRenderer::beginDiagnostic(DiagOrStoredDiag D, 528 DiagnosticsEngine::Level Level) { 529 Writer.Stream.EnterSubblock(BLOCK_DIAG, 4); 530 } 531 532 void SDiagsRenderer::endDiagnostic(DiagOrStoredDiag D, 533 DiagnosticsEngine::Level Level) { 534 if (D && Level != DiagnosticsEngine::Note) 535 return; 536 Writer.Stream.ExitBlock(); 537 } 538 539 void SDiagsRenderer::emitCodeContext(SourceLocation Loc, 540 DiagnosticsEngine::Level Level, 541 SmallVectorImpl<CharSourceRange> &Ranges, 542 ArrayRef<FixItHint> Hints) { 543 // Emit Source Ranges. 544 for (ArrayRef<CharSourceRange>::iterator it=Ranges.begin(), ei=Ranges.end(); 545 it != ei; ++it) { 546 if (it->isValid()) 547 Writer.EmitCharSourceRange(*it, SM); 548 } 549 550 // Emit FixIts. 551 for (ArrayRef<FixItHint>::iterator it = Hints.begin(), et = Hints.end(); 552 it != et; ++it) { 553 const FixItHint &fix = *it; 554 if (fix.isNull()) 555 continue; 556 Writer.Record.clear(); 557 Writer.Record.push_back(RECORD_FIXIT); 558 Writer.AddCharSourceRangeToRecord(fix.RemoveRange, Record, SM); 559 Writer.Record.push_back(fix.CodeToInsert.size()); 560 Writer.Stream.EmitRecordWithBlob(Writer.Abbrevs.get(RECORD_FIXIT), Record, 561 fix.CodeToInsert); 562 } 563 } 564 565 void SDiagsRenderer::emitNote(SourceLocation Loc, StringRef Message) { 566 Writer.Stream.EnterSubblock(BLOCK_DIAG, 4); 567 RecordData Record; 568 Record.push_back(RECORD_DIAG); 569 Record.push_back(DiagnosticsEngine::Note); 570 Writer.AddLocToRecord(Loc, Record, SM); 571 Record.push_back(Writer.getEmitCategory()); 572 Record.push_back(Writer.getEmitDiagnosticFlag(DiagnosticsEngine::Note)); 573 Record.push_back(Message.size()); 574 Writer.Stream.EmitRecordWithBlob(Writer.Abbrevs.get(RECORD_DIAG), 575 Record, Message); 576 Writer.Stream.ExitBlock(); 577 } 578 579 void SDiagsWriter::finish() { 580 if (inNonNoteDiagnostic) { 581 // Finish off any diagnostics we were in the process of emitting. 582 Stream.ExitBlock(); 583 inNonNoteDiagnostic = false; 584 } 585 586 // Write the generated bitstream to "Out". 587 OS->write((char *)&Buffer.front(), Buffer.size()); 588 OS->flush(); 589 590 OS.reset(0); 591 } 592 593