SerializedDiagnosticPrinter.cpp revision 14afab36c73c32a831838ba80f36136a80d9e6db
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/DiagnosticOptions.h" 16#include "clang/Basic/SourceManager.h" 17#include "clang/Basic/FileManager.h" 18#include "clang/Basic/Diagnostic.h" 19#include "clang/Basic/Version.h" 20#include "clang/Lex/Lexer.h" 21#include "clang/Frontend/SerializedDiagnosticPrinter.h" 22#include "clang/Frontend/DiagnosticRenderer.h" 23 24using namespace clang; 25using namespace clang::serialized_diags; 26 27namespace { 28 29class AbbreviationMap { 30 llvm::DenseMap<unsigned, unsigned> Abbrevs; 31public: 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 47typedef llvm::SmallVector<uint64_t, 64> RecordData; 48typedef llvm::SmallVectorImpl<uint64_t> RecordDataImpl; 49 50class SDiagsWriter; 51 52class SDiagsRenderer : public DiagnosticNoteRenderer { 53 SDiagsWriter &Writer; 54public: 55 SDiagsRenderer(SDiagsWriter &Writer, const LangOptions &LangOpts, 56 DiagnosticOptions *DiagOpts) 57 : DiagnosticNoteRenderer(LangOpts, DiagOpts), Writer(Writer) {} 58 59 virtual ~SDiagsRenderer() {} 60 61protected: 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 90class SDiagsWriter : public DiagnosticConsumer { 91 friend class SDiagsRenderer; 92 93 struct SharedState; 94 95 explicit SDiagsWriter(llvm::IntrusiveRefCntPtr<SharedState> State) 96 : LangOpts(0), OriginalInstance(false), State(State) { } 97 98public: 99 SDiagsWriter(llvm::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 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 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 : llvm::RefCountedBase<SharedState> { 194 SharedState(llvm::raw_ostream *os, DiagnosticOptions *diags) 195 : DiagOpts(diags), Stream(Buffer), OS(os), EmittedAnyDiagBlocks(false) { } 196 197 /// \brief Diagnostic options. 198 llvm::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<llvm::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, llvm::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 llvm::IntrusiveRefCntPtr<SharedState> State; 238}; 239} // end anonymous namespace 240 241namespace clang { 242namespace serialized_diags { 243DiagnosticConsumer *create(llvm::raw_ostream *OS, 244 DiagnosticOptions *diags) { 245 return new SDiagsWriter(OS, diags); 246} 247} // end namespace serialized_diags 248} // end namespace clang 249 250//===----------------------------------------------------------------------===// 251// Serialization methods. 252//===----------------------------------------------------------------------===// 253 254/// \brief Emits a block ID in the BLOCKINFO block. 255static void EmitBlockID(unsigned ID, const char *Name, 256 llvm::BitstreamWriter &Stream, 257 RecordDataImpl &Record) { 258 Record.clear(); 259 Record.push_back(ID); 260 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record); 261 262 // Emit the block name if present. 263 if (Name == 0 || Name[0] == 0) 264 return; 265 266 Record.clear(); 267 268 while (*Name) 269 Record.push_back(*Name++); 270 271 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record); 272} 273 274/// \brief Emits a record ID in the BLOCKINFO block. 275static void EmitRecordID(unsigned ID, const char *Name, 276 llvm::BitstreamWriter &Stream, 277 RecordDataImpl &Record){ 278 Record.clear(); 279 Record.push_back(ID); 280 281 while (*Name) 282 Record.push_back(*Name++); 283 284 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record); 285} 286 287void SDiagsWriter::AddLocToRecord(SourceLocation Loc, 288 const SourceManager *SM, 289 PresumedLoc PLoc, 290 RecordDataImpl &Record, 291 unsigned TokSize) { 292 if (PLoc.isInvalid()) { 293 // Emit a "sentinel" location. 294 Record.push_back((unsigned)0); // File. 295 Record.push_back((unsigned)0); // Line. 296 Record.push_back((unsigned)0); // Column. 297 Record.push_back((unsigned)0); // Offset. 298 return; 299 } 300 301 Record.push_back(getEmitFile(PLoc.getFilename())); 302 Record.push_back(PLoc.getLine()); 303 Record.push_back(PLoc.getColumn()+TokSize); 304 Record.push_back(SM->getFileOffset(Loc)); 305} 306 307void SDiagsWriter::AddCharSourceRangeToRecord(CharSourceRange Range, 308 RecordDataImpl &Record, 309 const SourceManager &SM) { 310 AddLocToRecord(Range.getBegin(), Record, &SM); 311 unsigned TokSize = 0; 312 if (Range.isTokenRange()) 313 TokSize = Lexer::MeasureTokenLength(Range.getEnd(), 314 SM, *LangOpts); 315 316 AddLocToRecord(Range.getEnd(), Record, &SM, TokSize); 317} 318 319unsigned SDiagsWriter::getEmitFile(const char *FileName){ 320 if (!FileName) 321 return 0; 322 323 unsigned &entry = State->Files[FileName]; 324 if (entry) 325 return entry; 326 327 // Lazily generate the record for the file. 328 entry = State->Files.size(); 329 RecordData Record; 330 Record.push_back(RECORD_FILENAME); 331 Record.push_back(entry); 332 Record.push_back(0); // For legacy. 333 Record.push_back(0); // For legacy. 334 StringRef Name(FileName); 335 Record.push_back(Name.size()); 336 State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_FILENAME), Record, 337 Name); 338 339 return entry; 340} 341 342void SDiagsWriter::EmitCharSourceRange(CharSourceRange R, 343 const SourceManager &SM) { 344 State->Record.clear(); 345 State->Record.push_back(RECORD_SOURCE_RANGE); 346 AddCharSourceRangeToRecord(R, State->Record, SM); 347 State->Stream.EmitRecordWithAbbrev(State->Abbrevs.get(RECORD_SOURCE_RANGE), 348 State->Record); 349} 350 351/// \brief Emits the preamble of the diagnostics file. 352void SDiagsWriter::EmitPreamble() { 353 // Emit the file header. 354 State->Stream.Emit((unsigned)'D', 8); 355 State->Stream.Emit((unsigned)'I', 8); 356 State->Stream.Emit((unsigned)'A', 8); 357 State->Stream.Emit((unsigned)'G', 8); 358 359 EmitBlockInfoBlock(); 360 EmitMetaBlock(); 361} 362 363static void AddSourceLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) { 364 using namespace llvm; 365 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // File ID. 366 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Line. 367 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Column. 368 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Offset; 369} 370 371static void AddRangeLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) { 372 AddSourceLocationAbbrev(Abbrev); 373 AddSourceLocationAbbrev(Abbrev); 374} 375 376void SDiagsWriter::EmitBlockInfoBlock() { 377 State->Stream.EnterBlockInfoBlock(3); 378 379 using namespace llvm; 380 llvm::BitstreamWriter &Stream = State->Stream; 381 RecordData &Record = State->Record; 382 AbbreviationMap &Abbrevs = State->Abbrevs; 383 384 // ==---------------------------------------------------------------------==// 385 // The subsequent records and Abbrevs are for the "Meta" block. 386 // ==---------------------------------------------------------------------==// 387 388 EmitBlockID(BLOCK_META, "Meta", Stream, Record); 389 EmitRecordID(RECORD_VERSION, "Version", Stream, Record); 390 BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); 391 Abbrev->Add(BitCodeAbbrevOp(RECORD_VERSION)); 392 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); 393 Abbrevs.set(RECORD_VERSION, Stream.EmitBlockInfoAbbrev(BLOCK_META, Abbrev)); 394 395 // ==---------------------------------------------------------------------==// 396 // The subsequent records and Abbrevs are for the "Diagnostic" block. 397 // ==---------------------------------------------------------------------==// 398 399 EmitBlockID(BLOCK_DIAG, "Diag", Stream, Record); 400 EmitRecordID(RECORD_DIAG, "DiagInfo", Stream, Record); 401 EmitRecordID(RECORD_SOURCE_RANGE, "SrcRange", Stream, Record); 402 EmitRecordID(RECORD_CATEGORY, "CatName", Stream, Record); 403 EmitRecordID(RECORD_DIAG_FLAG, "DiagFlag", Stream, Record); 404 EmitRecordID(RECORD_FILENAME, "FileName", Stream, Record); 405 EmitRecordID(RECORD_FIXIT, "FixIt", Stream, Record); 406 407 // Emit abbreviation for RECORD_DIAG. 408 Abbrev = new BitCodeAbbrev(); 409 Abbrev->Add(BitCodeAbbrevOp(RECORD_DIAG)); 410 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Diag level. 411 AddSourceLocationAbbrev(Abbrev); 412 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Category. 413 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped Diag ID. 414 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size. 415 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Diagnostc text. 416 Abbrevs.set(RECORD_DIAG, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev)); 417 418 // Emit abbrevation for RECORD_CATEGORY. 419 Abbrev = new BitCodeAbbrev(); 420 Abbrev->Add(BitCodeAbbrevOp(RECORD_CATEGORY)); 421 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Category ID. 422 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8)); // Text size. 423 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Category text. 424 Abbrevs.set(RECORD_CATEGORY, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev)); 425 426 // Emit abbrevation for RECORD_SOURCE_RANGE. 427 Abbrev = new BitCodeAbbrev(); 428 Abbrev->Add(BitCodeAbbrevOp(RECORD_SOURCE_RANGE)); 429 AddRangeLocationAbbrev(Abbrev); 430 Abbrevs.set(RECORD_SOURCE_RANGE, 431 Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev)); 432 433 // Emit the abbreviation for RECORD_DIAG_FLAG. 434 Abbrev = new BitCodeAbbrev(); 435 Abbrev->Add(BitCodeAbbrevOp(RECORD_DIAG_FLAG)); 436 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped Diag ID. 437 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size. 438 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Flag name text. 439 Abbrevs.set(RECORD_DIAG_FLAG, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, 440 Abbrev)); 441 442 // Emit the abbreviation for RECORD_FILENAME. 443 Abbrev = new BitCodeAbbrev(); 444 Abbrev->Add(BitCodeAbbrevOp(RECORD_FILENAME)); 445 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped file ID. 446 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Size. 447 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Modifcation time. 448 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size. 449 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name text. 450 Abbrevs.set(RECORD_FILENAME, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, 451 Abbrev)); 452 453 // Emit the abbreviation for RECORD_FIXIT. 454 Abbrev = new BitCodeAbbrev(); 455 Abbrev->Add(BitCodeAbbrevOp(RECORD_FIXIT)); 456 AddRangeLocationAbbrev(Abbrev); 457 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size. 458 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // FixIt text. 459 Abbrevs.set(RECORD_FIXIT, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, 460 Abbrev)); 461 462 Stream.ExitBlock(); 463} 464 465void SDiagsWriter::EmitMetaBlock() { 466 llvm::BitstreamWriter &Stream = State->Stream; 467 RecordData &Record = State->Record; 468 AbbreviationMap &Abbrevs = State->Abbrevs; 469 470 Stream.EnterSubblock(BLOCK_META, 3); 471 Record.clear(); 472 Record.push_back(RECORD_VERSION); 473 Record.push_back(Version); 474 Stream.EmitRecordWithAbbrev(Abbrevs.get(RECORD_VERSION), Record); 475 Stream.ExitBlock(); 476} 477 478unsigned SDiagsWriter::getEmitCategory(unsigned int category) { 479 if (State->Categories.count(category)) 480 return category; 481 482 State->Categories.insert(category); 483 484 // We use a local version of 'Record' so that we can be generating 485 // another record when we lazily generate one for the category entry. 486 RecordData Record; 487 Record.push_back(RECORD_CATEGORY); 488 Record.push_back(category); 489 StringRef catName = DiagnosticIDs::getCategoryNameFromID(category); 490 Record.push_back(catName.size()); 491 State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_CATEGORY), Record, 492 catName); 493 494 return category; 495} 496 497unsigned SDiagsWriter::getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel, 498 unsigned DiagID) { 499 if (DiagLevel == DiagnosticsEngine::Note) 500 return 0; // No flag for notes. 501 502 StringRef FlagName = DiagnosticIDs::getWarningOptionForDiag(DiagID); 503 if (FlagName.empty()) 504 return 0; 505 506 // Here we assume that FlagName points to static data whose pointer 507 // value is fixed. This allows us to unique by diagnostic groups. 508 const void *data = FlagName.data(); 509 std::pair<unsigned, StringRef> &entry = State->DiagFlags[data]; 510 if (entry.first == 0) { 511 entry.first = State->DiagFlags.size(); 512 entry.second = FlagName; 513 514 // Lazily emit the string in a separate record. 515 RecordData Record; 516 Record.push_back(RECORD_DIAG_FLAG); 517 Record.push_back(entry.first); 518 Record.push_back(FlagName.size()); 519 State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_DIAG_FLAG), 520 Record, FlagName); 521 } 522 523 return entry.first; 524} 525 526void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, 527 const Diagnostic &Info) { 528 // Enter the block for a non-note diagnostic immediately, rather than waiting 529 // for beginDiagnostic, in case associated notes are emitted before we get 530 // there. 531 if (DiagLevel != DiagnosticsEngine::Note) { 532 if (State->EmittedAnyDiagBlocks) 533 ExitDiagBlock(); 534 535 EnterDiagBlock(); 536 State->EmittedAnyDiagBlocks = true; 537 } 538 539 // Compute the diagnostic text. 540 State->diagBuf.clear(); 541 Info.FormatDiagnostic(State->diagBuf); 542 543 if (Info.getLocation().isInvalid()) { 544 // Special-case diagnostics with no location. We may not have entered a 545 // source file in this case, so we can't use the normal DiagnosticsRenderer 546 // machinery. 547 EmitDiagnosticMessage(SourceLocation(), PresumedLoc(), DiagLevel, 548 State->diagBuf, 0, &Info); 549 return; 550 } 551 552 assert(Info.hasSourceManager() && LangOpts && 553 "Unexpected diagnostic with valid location outside of a source file"); 554 SDiagsRenderer Renderer(*this, *LangOpts, &*State->DiagOpts); 555 Renderer.emitDiagnostic(Info.getLocation(), DiagLevel, 556 State->diagBuf.str(), 557 Info.getRanges(), 558 llvm::makeArrayRef(Info.getFixItHints(), 559 Info.getNumFixItHints()), 560 &Info.getSourceManager(), 561 &Info); 562} 563 564void SDiagsWriter::EmitDiagnosticMessage(SourceLocation Loc, 565 PresumedLoc PLoc, 566 DiagnosticsEngine::Level Level, 567 StringRef Message, 568 const SourceManager *SM, 569 DiagOrStoredDiag D) { 570 llvm::BitstreamWriter &Stream = State->Stream; 571 RecordData &Record = State->Record; 572 AbbreviationMap &Abbrevs = State->Abbrevs; 573 574 // Emit the RECORD_DIAG record. 575 Record.clear(); 576 Record.push_back(RECORD_DIAG); 577 Record.push_back(Level); 578 AddLocToRecord(Loc, SM, PLoc, Record); 579 580 if (const Diagnostic *Info = D.dyn_cast<const Diagnostic*>()) { 581 // Emit the category string lazily and get the category ID. 582 unsigned DiagID = DiagnosticIDs::getCategoryNumberForDiag(Info->getID()); 583 Record.push_back(getEmitCategory(DiagID)); 584 // Emit the diagnostic flag string lazily and get the mapped ID. 585 Record.push_back(getEmitDiagnosticFlag(Level, Info->getID())); 586 } else { 587 Record.push_back(getEmitCategory()); 588 Record.push_back(getEmitDiagnosticFlag(Level)); 589 } 590 591 Record.push_back(Message.size()); 592 Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG), Record, Message); 593} 594 595void 596SDiagsRenderer::emitDiagnosticMessage(SourceLocation Loc, 597 PresumedLoc PLoc, 598 DiagnosticsEngine::Level Level, 599 StringRef Message, 600 ArrayRef<clang::CharSourceRange> Ranges, 601 const SourceManager *SM, 602 DiagOrStoredDiag D) { 603 Writer.EmitDiagnosticMessage(Loc, PLoc, Level, Message, SM, D); 604} 605 606void SDiagsWriter::EnterDiagBlock() { 607 State->Stream.EnterSubblock(BLOCK_DIAG, 4); 608} 609 610void SDiagsWriter::ExitDiagBlock() { 611 State->Stream.ExitBlock(); 612} 613 614void SDiagsRenderer::beginDiagnostic(DiagOrStoredDiag D, 615 DiagnosticsEngine::Level Level) { 616 if (Level == DiagnosticsEngine::Note) 617 Writer.EnterDiagBlock(); 618} 619 620void SDiagsRenderer::endDiagnostic(DiagOrStoredDiag D, 621 DiagnosticsEngine::Level Level) { 622 // Only end note diagnostics here, because we can't be sure when we've seen 623 // the last note associated with a non-note diagnostic. 624 if (Level == DiagnosticsEngine::Note) 625 Writer.ExitDiagBlock(); 626} 627 628void SDiagsWriter::EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges, 629 ArrayRef<FixItHint> Hints, 630 const SourceManager &SM) { 631 llvm::BitstreamWriter &Stream = State->Stream; 632 RecordData &Record = State->Record; 633 AbbreviationMap &Abbrevs = State->Abbrevs; 634 635 // Emit Source Ranges. 636 for (ArrayRef<CharSourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); 637 I != E; ++I) 638 if (I->isValid()) 639 EmitCharSourceRange(*I, SM); 640 641 // Emit FixIts. 642 for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end(); 643 I != E; ++I) { 644 const FixItHint &Fix = *I; 645 if (Fix.isNull()) 646 continue; 647 Record.clear(); 648 Record.push_back(RECORD_FIXIT); 649 AddCharSourceRangeToRecord(Fix.RemoveRange, Record, SM); 650 Record.push_back(Fix.CodeToInsert.size()); 651 Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_FIXIT), Record, 652 Fix.CodeToInsert); 653 } 654} 655 656void SDiagsRenderer::emitCodeContext(SourceLocation Loc, 657 DiagnosticsEngine::Level Level, 658 SmallVectorImpl<CharSourceRange> &Ranges, 659 ArrayRef<FixItHint> Hints, 660 const SourceManager &SM) { 661 Writer.EmitCodeContext(Ranges, Hints, SM); 662} 663 664void SDiagsRenderer::emitNote(SourceLocation Loc, StringRef Message, 665 const SourceManager *SM) { 666 Writer.EnterDiagBlock(); 667 PresumedLoc PLoc = SM ? SM->getPresumedLoc(Loc) : PresumedLoc(); 668 Writer.EmitDiagnosticMessage(Loc, PLoc, DiagnosticsEngine::Note, 669 Message, SM, DiagOrStoredDiag()); 670 Writer.ExitDiagBlock(); 671} 672 673void SDiagsWriter::finish() { 674 // The original instance is responsible for writing the file. 675 if (!OriginalInstance) 676 return; 677 678 // Finish off any diagnostic we were in the process of emitting. 679 if (State->EmittedAnyDiagBlocks) 680 ExitDiagBlock(); 681 682 // Write the generated bitstream to "Out". 683 State->OS->write((char *)&State->Buffer.front(), State->Buffer.size()); 684 State->OS->flush(); 685 686 State->OS.reset(0); 687} 688