SerializedDiagnosticPrinter.cpp 21 KB

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