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