blob: 974ec535edc1e982c4a63cfed3801152da89ab3f [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"
Ted Kremenek15322172011-11-10 08:43:12 +000019#include "clang/Lex/Lexer.h"
Ted Kremenek78002122011-10-29 00:12:39 +000020#include "clang/Frontend/SerializedDiagnosticPrinter.h"
21
22using namespace clang;
Ted Kremenekfdd0ced2011-11-05 00:09:57 +000023using namespace clang::serialized_diags;
Ted Kremenek78002122011-10-29 00:12:39 +000024
25namespace {
Ted Kremenek78002122011-10-29 00:12:39 +000026
27class AbbreviationMap {
28 llvm::DenseMap<unsigned, unsigned> Abbrevs;
29public:
30 AbbreviationMap() {}
31
32 void set(unsigned recordID, unsigned abbrevID) {
33 assert(Abbrevs.find(recordID) == Abbrevs.end()
34 && "Abbreviation already set.");
35 Abbrevs[recordID] = abbrevID;
36 }
37
38 unsigned get(unsigned recordID) {
39 assert(Abbrevs.find(recordID) != Abbrevs.end() &&
40 "Abbreviation not set.");
41 return Abbrevs[recordID];
42 }
43};
44
45typedef llvm::SmallVector<uint64_t, 64> RecordData;
46typedef llvm::SmallVectorImpl<uint64_t> RecordDataImpl;
47
48class SDiagsWriter : public DiagnosticConsumer {
49public:
50 SDiagsWriter(DiagnosticsEngine &diags, llvm::raw_ostream *os)
Ted Kremenek15322172011-11-10 08:43:12 +000051 : LangOpts(0), Stream(Buffer), OS(os), Diags(diags),
52 inNonNoteDiagnostic(false)
Ted Kremenek78002122011-10-29 00:12:39 +000053 {
54 EmitPreamble();
55 };
56
57 ~SDiagsWriter() {}
58
59 void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
60 const Diagnostic &Info);
61
62 void EndSourceFile();
63
Ted Kremenek15322172011-11-10 08:43:12 +000064 void BeginSourceFile(const LangOptions &LO,
65 const Preprocessor *PP) {
66 LangOpts = &LO;
67 }
68
Ted Kremenek78002122011-10-29 00:12:39 +000069 DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const {
70 // It makes no sense to clone this.
71 return 0;
72 }
73
74private:
75 /// \brief Emit the preamble for the serialized diagnostics.
76 void EmitPreamble();
77
78 /// \brief Emit the BLOCKINFO block.
79 void EmitBlockInfoBlock();
Ted Kremenek0d34e6e2011-11-05 00:10:11 +000080
Ted Kremenek0b69aa82011-11-08 20:27:29 +000081 /// \brief Emit the META data block.
82 void EmitMetaBlock();
83
Ted Kremenek2a20b4f2011-11-05 00:10:01 +000084 /// \brief Emit a record for a CharSourceRange.
85 void EmitCharSourceRange(CharSourceRange R);
86
Ted Kremenek3baf63d2011-11-05 00:10:07 +000087 /// \brief Emit the string information for the category for a diagnostic.
88 unsigned getEmitCategory(unsigned DiagID);
89
90 /// \brief Emit the string information for diagnostic flags.
91 unsigned getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
92 const Diagnostic &Info);
Ted Kremenek0dbadc42011-11-05 00:10:04 +000093
Ted Kremenek0d34e6e2011-11-05 00:10:11 +000094 /// \brief Emit (lazily) the file string and retrieved the file identifier.
95 unsigned getEmitFile(SourceLocation Loc);
96
97 /// \brief Add SourceLocation information the specified record.
Ted Kremenek15322172011-11-10 08:43:12 +000098 void AddLocToRecord(SourceLocation Loc, RecordDataImpl &Record,
99 unsigned TokSize = 0);
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000100
Ted Kremenek96dcade2011-11-05 03:34:23 +0000101 /// \brief Add CharSourceRange information the specified record.
102 void AddCharSourceRangeToRecord(CharSourceRange R, RecordDataImpl &Record);
103
Ted Kremenek78002122011-10-29 00:12:39 +0000104 /// \brief The version of the diagnostics file.
105 enum { Version = 1 };
106
Ted Kremenek15322172011-11-10 08:43:12 +0000107 const LangOptions *LangOpts;
108
Ted Kremenek78002122011-10-29 00:12:39 +0000109 /// \brief The byte buffer for the serialized content.
110 std::vector<unsigned char> Buffer;
111
112 /// \brief The BitStreamWriter for the serialized diagnostics.
113 llvm::BitstreamWriter Stream;
114
115 /// \brief The name of the diagnostics file.
116 llvm::OwningPtr<llvm::raw_ostream> OS;
117
118 /// \brief The DiagnosticsEngine tied to all diagnostic locations.
119 DiagnosticsEngine &Diags;
120
121 /// \brief The set of constructed record abbreviations.
122 AbbreviationMap Abbrevs;
123
124 /// \brief A utility buffer for constructing record content.
125 RecordData Record;
126
127 /// \brief A text buffer for rendering diagnostic text.
128 llvm::SmallString<256> diagBuf;
129
130 /// \brief The collection of diagnostic categories used.
131 llvm::DenseSet<unsigned> Categories;
132
133 /// \brief The collection of files used.
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000134 llvm::DenseMap<const FileEntry *, unsigned> Files;
Ted Kremenek45d92752011-11-05 00:09:50 +0000135
136 typedef llvm::DenseMap<const void *, std::pair<unsigned, llvm::StringRef> >
137 DiagFlagsTy;
138
139 /// \brief Map for uniquing strings.
140 DiagFlagsTy DiagFlags;
Ted Kremenek78002122011-10-29 00:12:39 +0000141
Ted Kremenek59b61612011-11-05 00:09:47 +0000142 /// \brief Flag indicating whether or not we are in the process of
143 /// emitting a non-note diagnostic.
144 bool inNonNoteDiagnostic;
Ted Kremenek78002122011-10-29 00:12:39 +0000145};
146} // end anonymous namespace
147
148namespace clang {
149namespace serialized_diags {
150DiagnosticConsumer *create(llvm::raw_ostream *OS, DiagnosticsEngine &Diags) {
151 return new SDiagsWriter(Diags, OS);
152}
153} // end namespace serialized_diags
154} // end namespace clang
155
156//===----------------------------------------------------------------------===//
157// Serialization methods.
158//===----------------------------------------------------------------------===//
159
160/// \brief Emits a block ID in the BLOCKINFO block.
161static void EmitBlockID(unsigned ID, const char *Name,
162 llvm::BitstreamWriter &Stream,
163 RecordDataImpl &Record) {
164 Record.clear();
165 Record.push_back(ID);
166 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
167
168 // Emit the block name if present.
169 if (Name == 0 || Name[0] == 0)
170 return;
171
172 Record.clear();
173
174 while (*Name)
175 Record.push_back(*Name++);
176
177 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record);
178}
179
180/// \brief Emits a record ID in the BLOCKINFO block.
181static void EmitRecordID(unsigned ID, const char *Name,
182 llvm::BitstreamWriter &Stream,
183 RecordDataImpl &Record){
184 Record.clear();
185 Record.push_back(ID);
186
187 while (*Name)
188 Record.push_back(*Name++);
189
190 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
191}
192
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000193void SDiagsWriter::AddLocToRecord(SourceLocation Loc,
Ted Kremenek15322172011-11-10 08:43:12 +0000194 RecordDataImpl &Record,
195 unsigned TokSize) {
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000196 if (Loc.isInvalid()) {
197 // Emit a "sentinel" location.
Ted Kremenek15322172011-11-10 08:43:12 +0000198 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.
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000202 return;
203 }
204
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000205 SourceManager &SM = Diags.getSourceManager();
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000206 Loc = SM.getSpellingLoc(Loc);
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000207 Record.push_back(getEmitFile(Loc));
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000208 Record.push_back(SM.getSpellingLineNumber(Loc));
Ted Kremenek15322172011-11-10 08:43:12 +0000209 Record.push_back(SM.getSpellingColumnNumber(Loc)+TokSize);
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000210
211 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
212 FileID FID = LocInfo.first;
213 unsigned FileOffset = LocInfo.second;
214 Record.push_back(FileOffset);
215}
216
Ted Kremenek96dcade2011-11-05 03:34:23 +0000217void SDiagsWriter::AddCharSourceRangeToRecord(CharSourceRange Range,
218 RecordDataImpl &Record) {
219 AddLocToRecord(Range.getBegin(), Record);
Ted Kremenek15322172011-11-10 08:43:12 +0000220 unsigned TokSize = 0;
221 if (Range.isTokenRange())
222 TokSize = Lexer::MeasureTokenLength(Range.getEnd(),
223 Diags.getSourceManager(),
224 *LangOpts);
225
226 AddLocToRecord(Range.getEnd(), Record, TokSize);
Ted Kremenek96dcade2011-11-05 03:34:23 +0000227}
228
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000229unsigned SDiagsWriter::getEmitFile(SourceLocation Loc) {
230 SourceManager &SM = Diags.getSourceManager();
231 assert(Loc.isValid());
232 const std::pair<FileID, unsigned> &LocInfo = SM.getDecomposedLoc(Loc);
233 const FileEntry *FE = SM.getFileEntryForID(LocInfo.first);
234 if (!FE)
235 return 0;
236
237 unsigned &entry = Files[FE];
238 if (entry)
239 return entry;
240
241 // Lazily generate the record for the file.
242 entry = Files.size();
243 RecordData Record;
244 Record.push_back(RECORD_FILENAME);
245 Record.push_back(entry);
246 Record.push_back(FE->getSize());
247 Record.push_back(FE->getModificationTime());
248 StringRef Name = FE->getName();
249 Record.push_back(Name.size());
250 Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_FILENAME), Record, Name);
251
252 return entry;
253}
254
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000255void SDiagsWriter::EmitCharSourceRange(CharSourceRange R) {
256 Record.clear();
257 Record.push_back(RECORD_SOURCE_RANGE);
Ted Kremenek96dcade2011-11-05 03:34:23 +0000258 AddCharSourceRangeToRecord(R, Record);
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000259 Stream.EmitRecordWithAbbrev(Abbrevs.get(RECORD_SOURCE_RANGE), Record);
260}
261
Ted Kremenek78002122011-10-29 00:12:39 +0000262/// \brief Emits the preamble of the diagnostics file.
263void SDiagsWriter::EmitPreamble() {
Ted Kremenek78002122011-10-29 00:12:39 +0000264 // Emit the file header.
265 Stream.Emit((unsigned)'D', 8);
Ted Kremenek0b69aa82011-11-08 20:27:29 +0000266 Stream.Emit((unsigned)'I', 8);
267 Stream.Emit((unsigned)'A', 8);
268 Stream.Emit((unsigned)'G', 8);
Ted Kremenek069f9c22011-11-05 00:09:53 +0000269
Ted Kremenek78002122011-10-29 00:12:39 +0000270 EmitBlockInfoBlock();
Ted Kremenek0b69aa82011-11-08 20:27:29 +0000271 EmitMetaBlock();
Ted Kremenek78002122011-10-29 00:12:39 +0000272}
273
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000274static void AddSourceLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) {
275 using namespace llvm;
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000276 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // File ID.
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000277 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Line.
278 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Column.
279 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Offset;
280}
Ted Kremenek96dcade2011-11-05 03:34:23 +0000281
282static void AddRangeLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) {
283 AddSourceLocationAbbrev(Abbrev);
284 AddSourceLocationAbbrev(Abbrev);
285}
286
Ted Kremenek78002122011-10-29 00:12:39 +0000287void SDiagsWriter::EmitBlockInfoBlock() {
288 Stream.EnterBlockInfoBlock(3);
Ted Kremenek0b69aa82011-11-08 20:27:29 +0000289
290 using namespace llvm;
291
292 // ==---------------------------------------------------------------------==//
293 // The subsequent records and Abbrevs are for the "Meta" block.
294 // ==---------------------------------------------------------------------==//
295
296 EmitBlockID(BLOCK_META, "Meta", Stream, Record);
297 EmitRecordID(RECORD_VERSION, "Version", Stream, Record);
298 BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
299 Abbrev->Add(BitCodeAbbrevOp(RECORD_VERSION));
300 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
301 Abbrevs.set(RECORD_VERSION, Stream.EmitBlockInfoAbbrev(BLOCK_META, Abbrev));
302
Ted Kremenek78002122011-10-29 00:12:39 +0000303 // ==---------------------------------------------------------------------==//
304 // The subsequent records and Abbrevs are for the "Diagnostic" block.
305 // ==---------------------------------------------------------------------==//
306
Ted Kremenek45d92752011-11-05 00:09:50 +0000307 EmitBlockID(BLOCK_DIAG, "Diag", Stream, Record);
308 EmitRecordID(RECORD_DIAG, "DiagInfo", Stream, Record);
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000309 EmitRecordID(RECORD_SOURCE_RANGE, "SrcRange", Stream, Record);
Ted Kremenek0dbadc42011-11-05 00:10:04 +0000310 EmitRecordID(RECORD_CATEGORY, "CatName", Stream, Record);
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000311 EmitRecordID(RECORD_DIAG_FLAG, "DiagFlag", Stream, Record);
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000312 EmitRecordID(RECORD_FILENAME, "FileName", Stream, Record);
Ted Kremenek96dcade2011-11-05 03:34:23 +0000313 EmitRecordID(RECORD_FIXIT, "FixIt", Stream, Record);
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000314
Ted Kremenek78002122011-10-29 00:12:39 +0000315 // Emit abbreviation for RECORD_DIAG.
Ted Kremenek0b69aa82011-11-08 20:27:29 +0000316 Abbrev = new BitCodeAbbrev();
Ted Kremenek78002122011-10-29 00:12:39 +0000317 Abbrev->Add(BitCodeAbbrevOp(RECORD_DIAG));
Ted Kremenek45d92752011-11-05 00:09:50 +0000318 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Diag level.
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000319 AddSourceLocationAbbrev(Abbrev);
Ted Kremenek45d92752011-11-05 00:09:50 +0000320 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Category.
321 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped Diag ID.
Ted Kremenek78002122011-10-29 00:12:39 +0000322 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
323 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Diagnostc text.
324 Abbrevs.set(RECORD_DIAG, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000325
Ted Kremenek0dbadc42011-11-05 00:10:04 +0000326 // Emit abbrevation for RECORD_CATEGORY.
327 Abbrev = new BitCodeAbbrev();
328 Abbrev->Add(BitCodeAbbrevOp(RECORD_CATEGORY));
329 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Category ID.
330 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8)); // Text size.
331 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Category text.
332 Abbrevs.set(RECORD_CATEGORY, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
333
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000334 // Emit abbrevation for RECORD_SOURCE_RANGE.
335 Abbrev = new BitCodeAbbrev();
336 Abbrev->Add(BitCodeAbbrevOp(RECORD_SOURCE_RANGE));
Ted Kremenek96dcade2011-11-05 03:34:23 +0000337 AddRangeLocationAbbrev(Abbrev);
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000338 Abbrevs.set(RECORD_SOURCE_RANGE,
339 Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000340
341 // Emit the abbreviation for RECORD_DIAG_FLAG.
342 Abbrev = new BitCodeAbbrev();
343 Abbrev->Add(BitCodeAbbrevOp(RECORD_DIAG_FLAG));
344 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped Diag ID.
345 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
346 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Flag name text.
347 Abbrevs.set(RECORD_DIAG_FLAG, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
348 Abbrev));
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000349
350 // Emit the abbreviation for RECORD_FILENAME.
Ted Kremenek78002122011-10-29 00:12:39 +0000351 Abbrev = new BitCodeAbbrev();
Ted Kremenek28eac522011-11-05 00:09:43 +0000352 Abbrev->Add(BitCodeAbbrevOp(RECORD_FILENAME));
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000353 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped file ID.
354 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Size.
355 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Modifcation time.
Ted Kremenek78002122011-10-29 00:12:39 +0000356 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
357 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name text.
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000358 Abbrevs.set(RECORD_FILENAME, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
Ted Kremenek78002122011-10-29 00:12:39 +0000359 Abbrev));
Ted Kremenek96dcade2011-11-05 03:34:23 +0000360
361 // Emit the abbreviation for RECORD_FIXIT.
362 Abbrev = new BitCodeAbbrev();
363 Abbrev->Add(BitCodeAbbrevOp(RECORD_FIXIT));
364 AddRangeLocationAbbrev(Abbrev);
365 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
366 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // FixIt text.
367 Abbrevs.set(RECORD_FIXIT, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
368 Abbrev));
Ted Kremenek78002122011-10-29 00:12:39 +0000369
370 Stream.ExitBlock();
371}
372
Ted Kremenek0b69aa82011-11-08 20:27:29 +0000373void SDiagsWriter::EmitMetaBlock() {
374 Stream.EnterSubblock(BLOCK_META, 3);
375 Record.clear();
376 Record.push_back(RECORD_VERSION);
377 Record.push_back(Version);
378 Stream.EmitRecordWithAbbrev(Abbrevs.get(RECORD_VERSION), Record);
379 Stream.ExitBlock();
380}
381
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000382unsigned SDiagsWriter::getEmitCategory(unsigned int DiagID) {
383 unsigned category = DiagnosticIDs::getCategoryNumberForDiag(DiagID);
Ted Kremenek0dbadc42011-11-05 00:10:04 +0000384
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000385 if (Categories.count(category))
386 return category;
387
388 Categories.insert(category);
Ted Kremenek0dbadc42011-11-05 00:10:04 +0000389
390 // We use a local version of 'Record' so that we can be generating
391 // another record when we lazily generate one for the category entry.
392 RecordData Record;
393 Record.push_back(RECORD_CATEGORY);
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000394 Record.push_back(category);
395 StringRef catName = DiagnosticIDs::getCategoryNameFromID(category);
Ted Kremenek0dbadc42011-11-05 00:10:04 +0000396 Record.push_back(catName.size());
397 Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_CATEGORY), Record, catName);
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000398
399 return category;
400}
401
402unsigned SDiagsWriter::getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
403 const Diagnostic &Info) {
404 if (DiagLevel == DiagnosticsEngine::Note)
405 return 0; // No flag for notes.
406
407 StringRef FlagName = DiagnosticIDs::getWarningOptionForDiag(Info.getID());
408 if (FlagName.empty())
409 return 0;
410
411 // Here we assume that FlagName points to static data whose pointer
412 // value is fixed. This allows us to unique by diagnostic groups.
413 const void *data = FlagName.data();
414 std::pair<unsigned, StringRef> &entry = DiagFlags[data];
415 if (entry.first == 0) {
416 entry.first = DiagFlags.size();
417 entry.second = FlagName;
418
419 // Lazily emit the string in a separate record.
420 RecordData Record;
421 Record.push_back(RECORD_DIAG_FLAG);
422 Record.push_back(entry.first);
423 Record.push_back(FlagName.size());
424 Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG_FLAG),
425 Record, FlagName);
426 }
427
428 return entry.first;
Ted Kremenek0dbadc42011-11-05 00:10:04 +0000429}
430
Ted Kremenek78002122011-10-29 00:12:39 +0000431void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
432 const Diagnostic &Info) {
433
Ted Kremenek59b61612011-11-05 00:09:47 +0000434 if (DiagLevel != DiagnosticsEngine::Note) {
435 if (inNonNoteDiagnostic) {
436 // We have encountered a non-note diagnostic. Finish up the previous
437 // diagnostic block before starting a new one.
438 Stream.ExitBlock();
439 }
440 inNonNoteDiagnostic = true;
441 }
442
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000443 Stream.EnterSubblock(BLOCK_DIAG, 4);
Ted Kremenek78002122011-10-29 00:12:39 +0000444
445 // Emit the RECORD_DIAG record.
446 Record.clear();
447 Record.push_back(RECORD_DIAG);
448 Record.push_back(DiagLevel);
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000449 AddLocToRecord(Info.getLocation(), Record);
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000450 // Emit the category string lazily and get the category ID.
451 Record.push_back(getEmitCategory(Info.getID()));
452 // Emit the diagnostic flag string lazily and get the mapped ID.
453 Record.push_back(getEmitDiagnosticFlag(DiagLevel, Info));
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000454 // Emit the diagnostic text.
Ted Kremenek78002122011-10-29 00:12:39 +0000455 diagBuf.clear();
456 Info.FormatDiagnostic(diagBuf); // Compute the diagnostic text.
457 Record.push_back(diagBuf.str().size());
458 Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG), Record, diagBuf.str());
Ted Kremenek96dcade2011-11-05 03:34:23 +0000459
460 // Emit Source Ranges.
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000461 ArrayRef<CharSourceRange> Ranges = Info.getRanges();
462 for (ArrayRef<CharSourceRange>::iterator it=Ranges.begin(), ei=Ranges.end();
463 it != ei; ++it) {
464 EmitCharSourceRange(*it);
465 }
466
Ted Kremenek96dcade2011-11-05 03:34:23 +0000467 // Emit FixIts.
468 for (unsigned i = 0, n = Info.getNumFixItHints(); i != n; ++i) {
469 const FixItHint &fix = Info.getFixItHint(i);
470 if (fix.isNull())
471 continue;
472 Record.clear();
473 Record.push_back(RECORD_FIXIT);
474 AddCharSourceRangeToRecord(fix.RemoveRange, Record);
475 Record.push_back(fix.CodeToInsert.size());
476 Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_FIXIT), Record,
477 fix.CodeToInsert);
478 }
Ted Kremenek59b61612011-11-05 00:09:47 +0000479
480 if (DiagLevel == DiagnosticsEngine::Note) {
481 // Notes currently cannot have child diagnostics. Complete the
482 // diagnostic now.
483 Stream.ExitBlock();
484 }
Ted Kremenek78002122011-10-29 00:12:39 +0000485}
486
Ted Kremenek78002122011-10-29 00:12:39 +0000487void SDiagsWriter::EndSourceFile() {
Ted Kremenek59b61612011-11-05 00:09:47 +0000488 if (inNonNoteDiagnostic) {
489 // Finish off any diagnostics we were in the process of emitting.
490 Stream.ExitBlock();
491 inNonNoteDiagnostic = false;
492 }
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000493
Ted Kremenek78002122011-10-29 00:12:39 +0000494 // Write the generated bitstream to "Out".
495 OS->write((char *)&Buffer.front(), Buffer.size());
496 OS->flush();
497
498 OS.reset(0);
499}
500