blob: 5984567e2ce6ac7c03b7f9f539380528c1da29e4 [file] [log] [blame]
Ted Kremenek78002122011-10-29 00:12:39 +00001//===--- 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>
Ted Kremenek78002122011-10-29 00:12:39 +000011#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/Frontend/SerializedDiagnosticPrinter.h"
20
21using namespace clang;
Ted Kremenekfdd0ced2011-11-05 00:09:57 +000022using namespace clang::serialized_diags;
Ted Kremenek78002122011-10-29 00:12:39 +000023
24namespace {
Ted Kremenek78002122011-10-29 00:12:39 +000025
26class AbbreviationMap {
27 llvm::DenseMap<unsigned, unsigned> Abbrevs;
28public:
29 AbbreviationMap() {}
30
31 void set(unsigned recordID, unsigned abbrevID) {
32 assert(Abbrevs.find(recordID) == Abbrevs.end()
33 && "Abbreviation already set.");
34 Abbrevs[recordID] = abbrevID;
35 }
36
37 unsigned get(unsigned recordID) {
38 assert(Abbrevs.find(recordID) != Abbrevs.end() &&
39 "Abbreviation not set.");
40 return Abbrevs[recordID];
41 }
42};
43
44typedef llvm::SmallVector<uint64_t, 64> RecordData;
45typedef llvm::SmallVectorImpl<uint64_t> RecordDataImpl;
46
47class SDiagsWriter : public DiagnosticConsumer {
48public:
49 SDiagsWriter(DiagnosticsEngine &diags, llvm::raw_ostream *os)
Ted Kremenek59b61612011-11-05 00:09:47 +000050 : Stream(Buffer), OS(os), Diags(diags), inNonNoteDiagnostic(false)
Ted Kremenek78002122011-10-29 00:12:39 +000051 {
52 EmitPreamble();
53 };
54
55 ~SDiagsWriter() {}
56
57 void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
58 const Diagnostic &Info);
59
60 void EndSourceFile();
61
62 DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const {
63 // It makes no sense to clone this.
64 return 0;
65 }
66
67private:
68 /// \brief Emit the preamble for the serialized diagnostics.
69 void EmitPreamble();
70
71 /// \brief Emit the BLOCKINFO block.
72 void EmitBlockInfoBlock();
Ted Kremenek0d34e6e2011-11-05 00:10:11 +000073
Ted Kremenek0b69aa82011-11-08 20:27:29 +000074 /// \brief Emit the META data block.
75 void EmitMetaBlock();
76
Ted Kremenek2a20b4f2011-11-05 00:10:01 +000077 /// \brief Emit a record for a CharSourceRange.
78 void EmitCharSourceRange(CharSourceRange R);
79
Ted Kremenek3baf63d2011-11-05 00:10:07 +000080 /// \brief Emit the string information for the category for a diagnostic.
81 unsigned getEmitCategory(unsigned DiagID);
82
83 /// \brief Emit the string information for diagnostic flags.
84 unsigned getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
85 const Diagnostic &Info);
Ted Kremenek0dbadc42011-11-05 00:10:04 +000086
Ted Kremenek0d34e6e2011-11-05 00:10:11 +000087 /// \brief Emit (lazily) the file string and retrieved the file identifier.
88 unsigned getEmitFile(SourceLocation Loc);
89
90 /// \brief Add SourceLocation information the specified record.
91 void AddLocToRecord(SourceLocation Loc, RecordDataImpl &Record);
92
Ted Kremenek96dcade2011-11-05 03:34:23 +000093 /// \brief Add CharSourceRange information the specified record.
94 void AddCharSourceRangeToRecord(CharSourceRange R, RecordDataImpl &Record);
95
Ted Kremenek78002122011-10-29 00:12:39 +000096 /// \brief The version of the diagnostics file.
97 enum { Version = 1 };
98
99 /// \brief The byte buffer for the serialized content.
100 std::vector<unsigned char> Buffer;
101
102 /// \brief The BitStreamWriter for the serialized diagnostics.
103 llvm::BitstreamWriter Stream;
104
105 /// \brief The name of the diagnostics file.
106 llvm::OwningPtr<llvm::raw_ostream> OS;
107
108 /// \brief The DiagnosticsEngine tied to all diagnostic locations.
109 DiagnosticsEngine &Diags;
110
111 /// \brief The set of constructed record abbreviations.
112 AbbreviationMap Abbrevs;
113
114 /// \brief A utility buffer for constructing record content.
115 RecordData Record;
116
117 /// \brief A text buffer for rendering diagnostic text.
118 llvm::SmallString<256> diagBuf;
119
120 /// \brief The collection of diagnostic categories used.
121 llvm::DenseSet<unsigned> Categories;
122
123 /// \brief The collection of files used.
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000124 llvm::DenseMap<const FileEntry *, unsigned> Files;
Ted Kremenek45d92752011-11-05 00:09:50 +0000125
126 typedef llvm::DenseMap<const void *, std::pair<unsigned, llvm::StringRef> >
127 DiagFlagsTy;
128
129 /// \brief Map for uniquing strings.
130 DiagFlagsTy DiagFlags;
Ted Kremenek78002122011-10-29 00:12:39 +0000131
Ted Kremenek59b61612011-11-05 00:09:47 +0000132 /// \brief Flag indicating whether or not we are in the process of
133 /// emitting a non-note diagnostic.
134 bool inNonNoteDiagnostic;
Ted Kremenek78002122011-10-29 00:12:39 +0000135};
136} // end anonymous namespace
137
138namespace clang {
139namespace serialized_diags {
140DiagnosticConsumer *create(llvm::raw_ostream *OS, DiagnosticsEngine &Diags) {
141 return new SDiagsWriter(Diags, OS);
142}
143} // end namespace serialized_diags
144} // end namespace clang
145
146//===----------------------------------------------------------------------===//
147// Serialization methods.
148//===----------------------------------------------------------------------===//
149
150/// \brief Emits a block ID in the BLOCKINFO block.
151static void EmitBlockID(unsigned ID, const char *Name,
152 llvm::BitstreamWriter &Stream,
153 RecordDataImpl &Record) {
154 Record.clear();
155 Record.push_back(ID);
156 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
157
158 // Emit the block name if present.
159 if (Name == 0 || Name[0] == 0)
160 return;
161
162 Record.clear();
163
164 while (*Name)
165 Record.push_back(*Name++);
166
167 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record);
168}
169
170/// \brief Emits a record ID in the BLOCKINFO block.
171static void EmitRecordID(unsigned ID, const char *Name,
172 llvm::BitstreamWriter &Stream,
173 RecordDataImpl &Record){
174 Record.clear();
175 Record.push_back(ID);
176
177 while (*Name)
178 Record.push_back(*Name++);
179
180 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
181}
182
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000183void SDiagsWriter::AddLocToRecord(SourceLocation Loc,
184 RecordDataImpl &Record) {
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000185 if (Loc.isInvalid()) {
186 // Emit a "sentinel" location.
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000187 Record.push_back((unsigned) 0); // File.
188 Record.push_back(~(unsigned)0); // Line.
189 Record.push_back(~(unsigned)0); // Column.
190 Record.push_back(~(unsigned)0); // Offset.
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000191 return;
192 }
193
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000194 SourceManager &SM = Diags.getSourceManager();
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000195 Loc = SM.getSpellingLoc(Loc);
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000196 Record.push_back(getEmitFile(Loc));
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000197 Record.push_back(SM.getSpellingLineNumber(Loc));
198 Record.push_back(SM.getSpellingColumnNumber(Loc));
199
200 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
201 FileID FID = LocInfo.first;
202 unsigned FileOffset = LocInfo.second;
203 Record.push_back(FileOffset);
204}
205
Ted Kremenek96dcade2011-11-05 03:34:23 +0000206void SDiagsWriter::AddCharSourceRangeToRecord(CharSourceRange Range,
207 RecordDataImpl &Record) {
208 AddLocToRecord(Range.getBegin(), Record);
209 AddLocToRecord(Range.getEnd(), Record);
210}
211
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000212unsigned SDiagsWriter::getEmitFile(SourceLocation Loc) {
213 SourceManager &SM = Diags.getSourceManager();
214 assert(Loc.isValid());
215 const std::pair<FileID, unsigned> &LocInfo = SM.getDecomposedLoc(Loc);
216 const FileEntry *FE = SM.getFileEntryForID(LocInfo.first);
217 if (!FE)
218 return 0;
219
220 unsigned &entry = Files[FE];
221 if (entry)
222 return entry;
223
224 // Lazily generate the record for the file.
225 entry = Files.size();
226 RecordData Record;
227 Record.push_back(RECORD_FILENAME);
228 Record.push_back(entry);
229 Record.push_back(FE->getSize());
230 Record.push_back(FE->getModificationTime());
231 StringRef Name = FE->getName();
232 Record.push_back(Name.size());
233 Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_FILENAME), Record, Name);
234
235 return entry;
236}
237
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000238void SDiagsWriter::EmitCharSourceRange(CharSourceRange R) {
239 Record.clear();
240 Record.push_back(RECORD_SOURCE_RANGE);
Ted Kremenek96dcade2011-11-05 03:34:23 +0000241 AddCharSourceRangeToRecord(R, Record);
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000242 Stream.EmitRecordWithAbbrev(Abbrevs.get(RECORD_SOURCE_RANGE), Record);
243}
244
Ted Kremenek78002122011-10-29 00:12:39 +0000245/// \brief Emits the preamble of the diagnostics file.
246void SDiagsWriter::EmitPreamble() {
Ted Kremenek78002122011-10-29 00:12:39 +0000247 // Emit the file header.
248 Stream.Emit((unsigned)'D', 8);
Ted Kremenek0b69aa82011-11-08 20:27:29 +0000249 Stream.Emit((unsigned)'I', 8);
250 Stream.Emit((unsigned)'A', 8);
251 Stream.Emit((unsigned)'G', 8);
Ted Kremenek069f9c22011-11-05 00:09:53 +0000252
Ted Kremenek78002122011-10-29 00:12:39 +0000253 EmitBlockInfoBlock();
Ted Kremenek0b69aa82011-11-08 20:27:29 +0000254 EmitMetaBlock();
Ted Kremenek78002122011-10-29 00:12:39 +0000255}
256
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000257static void AddSourceLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) {
258 using namespace llvm;
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000259 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // File ID.
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000260 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Line.
261 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Column.
262 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Offset;
263}
Ted Kremenek96dcade2011-11-05 03:34:23 +0000264
265static void AddRangeLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) {
266 AddSourceLocationAbbrev(Abbrev);
267 AddSourceLocationAbbrev(Abbrev);
268}
269
Ted Kremenek78002122011-10-29 00:12:39 +0000270void SDiagsWriter::EmitBlockInfoBlock() {
271 Stream.EnterBlockInfoBlock(3);
Ted Kremenek0b69aa82011-11-08 20:27:29 +0000272
273 using namespace llvm;
274
275 // ==---------------------------------------------------------------------==//
276 // The subsequent records and Abbrevs are for the "Meta" block.
277 // ==---------------------------------------------------------------------==//
278
279 EmitBlockID(BLOCK_META, "Meta", Stream, Record);
280 EmitRecordID(RECORD_VERSION, "Version", Stream, Record);
281 BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
282 Abbrev->Add(BitCodeAbbrevOp(RECORD_VERSION));
283 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
284 Abbrevs.set(RECORD_VERSION, Stream.EmitBlockInfoAbbrev(BLOCK_META, Abbrev));
285
Ted Kremenek78002122011-10-29 00:12:39 +0000286 // ==---------------------------------------------------------------------==//
287 // The subsequent records and Abbrevs are for the "Diagnostic" block.
288 // ==---------------------------------------------------------------------==//
289
Ted Kremenek45d92752011-11-05 00:09:50 +0000290 EmitBlockID(BLOCK_DIAG, "Diag", Stream, Record);
291 EmitRecordID(RECORD_DIAG, "DiagInfo", Stream, Record);
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000292 EmitRecordID(RECORD_SOURCE_RANGE, "SrcRange", Stream, Record);
Ted Kremenek0dbadc42011-11-05 00:10:04 +0000293 EmitRecordID(RECORD_CATEGORY, "CatName", Stream, Record);
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000294 EmitRecordID(RECORD_DIAG_FLAG, "DiagFlag", Stream, Record);
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000295 EmitRecordID(RECORD_FILENAME, "FileName", Stream, Record);
Ted Kremenek96dcade2011-11-05 03:34:23 +0000296 EmitRecordID(RECORD_FIXIT, "FixIt", Stream, Record);
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000297
Ted Kremenek78002122011-10-29 00:12:39 +0000298 // Emit abbreviation for RECORD_DIAG.
Ted Kremenek0b69aa82011-11-08 20:27:29 +0000299 Abbrev = new BitCodeAbbrev();
Ted Kremenek78002122011-10-29 00:12:39 +0000300 Abbrev->Add(BitCodeAbbrevOp(RECORD_DIAG));
Ted Kremenek45d92752011-11-05 00:09:50 +0000301 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Diag level.
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000302 AddSourceLocationAbbrev(Abbrev);
Ted Kremenek45d92752011-11-05 00:09:50 +0000303 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Category.
304 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped Diag ID.
Ted Kremenek78002122011-10-29 00:12:39 +0000305 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
306 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Diagnostc text.
307 Abbrevs.set(RECORD_DIAG, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000308
Ted Kremenek0dbadc42011-11-05 00:10:04 +0000309 // Emit abbrevation for RECORD_CATEGORY.
310 Abbrev = new BitCodeAbbrev();
311 Abbrev->Add(BitCodeAbbrevOp(RECORD_CATEGORY));
312 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Category ID.
313 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8)); // Text size.
314 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Category text.
315 Abbrevs.set(RECORD_CATEGORY, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
316
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000317 // Emit abbrevation for RECORD_SOURCE_RANGE.
318 Abbrev = new BitCodeAbbrev();
319 Abbrev->Add(BitCodeAbbrevOp(RECORD_SOURCE_RANGE));
Ted Kremenek96dcade2011-11-05 03:34:23 +0000320 AddRangeLocationAbbrev(Abbrev);
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000321 Abbrevs.set(RECORD_SOURCE_RANGE,
322 Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000323
324 // Emit the abbreviation for RECORD_DIAG_FLAG.
325 Abbrev = new BitCodeAbbrev();
326 Abbrev->Add(BitCodeAbbrevOp(RECORD_DIAG_FLAG));
327 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped Diag ID.
328 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
329 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Flag name text.
330 Abbrevs.set(RECORD_DIAG_FLAG, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
331 Abbrev));
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000332
333 // Emit the abbreviation for RECORD_FILENAME.
Ted Kremenek78002122011-10-29 00:12:39 +0000334 Abbrev = new BitCodeAbbrev();
Ted Kremenek28eac522011-11-05 00:09:43 +0000335 Abbrev->Add(BitCodeAbbrevOp(RECORD_FILENAME));
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000336 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped file ID.
337 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Size.
338 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Modifcation time.
Ted Kremenek78002122011-10-29 00:12:39 +0000339 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
340 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name text.
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000341 Abbrevs.set(RECORD_FILENAME, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
Ted Kremenek78002122011-10-29 00:12:39 +0000342 Abbrev));
Ted Kremenek96dcade2011-11-05 03:34:23 +0000343
344 // Emit the abbreviation for RECORD_FIXIT.
345 Abbrev = new BitCodeAbbrev();
346 Abbrev->Add(BitCodeAbbrevOp(RECORD_FIXIT));
347 AddRangeLocationAbbrev(Abbrev);
348 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
349 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // FixIt text.
350 Abbrevs.set(RECORD_FIXIT, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
351 Abbrev));
Ted Kremenek78002122011-10-29 00:12:39 +0000352
353 Stream.ExitBlock();
354}
355
Ted Kremenek0b69aa82011-11-08 20:27:29 +0000356void SDiagsWriter::EmitMetaBlock() {
357 Stream.EnterSubblock(BLOCK_META, 3);
358 Record.clear();
359 Record.push_back(RECORD_VERSION);
360 Record.push_back(Version);
361 Stream.EmitRecordWithAbbrev(Abbrevs.get(RECORD_VERSION), Record);
362 Stream.ExitBlock();
363}
364
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000365unsigned SDiagsWriter::getEmitCategory(unsigned int DiagID) {
366 unsigned category = DiagnosticIDs::getCategoryNumberForDiag(DiagID);
Ted Kremenek0dbadc42011-11-05 00:10:04 +0000367
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000368 if (Categories.count(category))
369 return category;
370
371 Categories.insert(category);
Ted Kremenek0dbadc42011-11-05 00:10:04 +0000372
373 // We use a local version of 'Record' so that we can be generating
374 // another record when we lazily generate one for the category entry.
375 RecordData Record;
376 Record.push_back(RECORD_CATEGORY);
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000377 Record.push_back(category);
378 StringRef catName = DiagnosticIDs::getCategoryNameFromID(category);
Ted Kremenek0dbadc42011-11-05 00:10:04 +0000379 Record.push_back(catName.size());
380 Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_CATEGORY), Record, catName);
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000381
382 return category;
383}
384
385unsigned SDiagsWriter::getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
386 const Diagnostic &Info) {
387 if (DiagLevel == DiagnosticsEngine::Note)
388 return 0; // No flag for notes.
389
390 StringRef FlagName = DiagnosticIDs::getWarningOptionForDiag(Info.getID());
391 if (FlagName.empty())
392 return 0;
393
394 // Here we assume that FlagName points to static data whose pointer
395 // value is fixed. This allows us to unique by diagnostic groups.
396 const void *data = FlagName.data();
397 std::pair<unsigned, StringRef> &entry = DiagFlags[data];
398 if (entry.first == 0) {
399 entry.first = DiagFlags.size();
400 entry.second = FlagName;
401
402 // Lazily emit the string in a separate record.
403 RecordData Record;
404 Record.push_back(RECORD_DIAG_FLAG);
405 Record.push_back(entry.first);
406 Record.push_back(FlagName.size());
407 Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG_FLAG),
408 Record, FlagName);
409 }
410
411 return entry.first;
Ted Kremenek0dbadc42011-11-05 00:10:04 +0000412}
413
Ted Kremenek78002122011-10-29 00:12:39 +0000414void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
415 const Diagnostic &Info) {
416
Ted Kremenek59b61612011-11-05 00:09:47 +0000417 if (DiagLevel != DiagnosticsEngine::Note) {
418 if (inNonNoteDiagnostic) {
419 // We have encountered a non-note diagnostic. Finish up the previous
420 // diagnostic block before starting a new one.
421 Stream.ExitBlock();
422 }
423 inNonNoteDiagnostic = true;
424 }
425
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000426 Stream.EnterSubblock(BLOCK_DIAG, 4);
Ted Kremenek78002122011-10-29 00:12:39 +0000427
428 // Emit the RECORD_DIAG record.
429 Record.clear();
430 Record.push_back(RECORD_DIAG);
431 Record.push_back(DiagLevel);
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000432 AddLocToRecord(Info.getLocation(), Record);
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000433 // Emit the category string lazily and get the category ID.
434 Record.push_back(getEmitCategory(Info.getID()));
435 // Emit the diagnostic flag string lazily and get the mapped ID.
436 Record.push_back(getEmitDiagnosticFlag(DiagLevel, Info));
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000437 // Emit the diagnostic text.
Ted Kremenek78002122011-10-29 00:12:39 +0000438 diagBuf.clear();
439 Info.FormatDiagnostic(diagBuf); // Compute the diagnostic text.
440 Record.push_back(diagBuf.str().size());
441 Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG), Record, diagBuf.str());
Ted Kremenek96dcade2011-11-05 03:34:23 +0000442
443 // Emit Source Ranges.
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000444 ArrayRef<CharSourceRange> Ranges = Info.getRanges();
445 for (ArrayRef<CharSourceRange>::iterator it=Ranges.begin(), ei=Ranges.end();
446 it != ei; ++it) {
447 EmitCharSourceRange(*it);
448 }
449
Ted Kremenek96dcade2011-11-05 03:34:23 +0000450 // Emit FixIts.
451 for (unsigned i = 0, n = Info.getNumFixItHints(); i != n; ++i) {
452 const FixItHint &fix = Info.getFixItHint(i);
453 if (fix.isNull())
454 continue;
455 Record.clear();
456 Record.push_back(RECORD_FIXIT);
457 AddCharSourceRangeToRecord(fix.RemoveRange, Record);
458 Record.push_back(fix.CodeToInsert.size());
459 Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_FIXIT), Record,
460 fix.CodeToInsert);
461 }
Ted Kremenek59b61612011-11-05 00:09:47 +0000462
463 if (DiagLevel == DiagnosticsEngine::Note) {
464 // Notes currently cannot have child diagnostics. Complete the
465 // diagnostic now.
466 Stream.ExitBlock();
467 }
Ted Kremenek78002122011-10-29 00:12:39 +0000468}
469
Ted Kremenek78002122011-10-29 00:12:39 +0000470void SDiagsWriter::EndSourceFile() {
Ted Kremenek59b61612011-11-05 00:09:47 +0000471 if (inNonNoteDiagnostic) {
472 // Finish off any diagnostics we were in the process of emitting.
473 Stream.ExitBlock();
474 inNonNoteDiagnostic = false;
475 }
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000476
Ted Kremenek78002122011-10-29 00:12:39 +0000477 // Write the generated bitstream to "Out".
478 OS->write((char *)&Buffer.front(), Buffer.size());
479 OS->flush();
480
481 OS.reset(0);
482}
483