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