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