blob: c773f81ce3bf5e52bedcad0cc4dcb0810d4ede64 [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();
Devang Patel02ae32a2011-11-15 01:30:40 +000055 }
Ted Kremenek78002122011-10-29 00:12:39 +000056
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);
Benjamin Kramer6eb29d22011-11-10 11:29:20 +0000210 Record.push_back(SM.getFileOffset(Loc));
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000211}
212
Ted Kremenek96dcade2011-11-05 03:34:23 +0000213void SDiagsWriter::AddCharSourceRangeToRecord(CharSourceRange Range,
214 RecordDataImpl &Record) {
215 AddLocToRecord(Range.getBegin(), Record);
Ted Kremenek15322172011-11-10 08:43:12 +0000216 unsigned TokSize = 0;
217 if (Range.isTokenRange())
218 TokSize = Lexer::MeasureTokenLength(Range.getEnd(),
219 Diags.getSourceManager(),
220 *LangOpts);
221
222 AddLocToRecord(Range.getEnd(), Record, TokSize);
Ted Kremenek96dcade2011-11-05 03:34:23 +0000223}
224
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000225unsigned SDiagsWriter::getEmitFile(SourceLocation Loc) {
226 SourceManager &SM = Diags.getSourceManager();
227 assert(Loc.isValid());
228 const std::pair<FileID, unsigned> &LocInfo = SM.getDecomposedLoc(Loc);
229 const FileEntry *FE = SM.getFileEntryForID(LocInfo.first);
230 if (!FE)
231 return 0;
232
233 unsigned &entry = Files[FE];
234 if (entry)
235 return entry;
236
237 // Lazily generate the record for the file.
238 entry = Files.size();
239 RecordData Record;
240 Record.push_back(RECORD_FILENAME);
241 Record.push_back(entry);
242 Record.push_back(FE->getSize());
243 Record.push_back(FE->getModificationTime());
244 StringRef Name = FE->getName();
245 Record.push_back(Name.size());
246 Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_FILENAME), Record, Name);
247
248 return entry;
249}
250
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000251void SDiagsWriter::EmitCharSourceRange(CharSourceRange R) {
252 Record.clear();
253 Record.push_back(RECORD_SOURCE_RANGE);
Ted Kremenek96dcade2011-11-05 03:34:23 +0000254 AddCharSourceRangeToRecord(R, Record);
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000255 Stream.EmitRecordWithAbbrev(Abbrevs.get(RECORD_SOURCE_RANGE), Record);
256}
257
Ted Kremenek78002122011-10-29 00:12:39 +0000258/// \brief Emits the preamble of the diagnostics file.
259void SDiagsWriter::EmitPreamble() {
Ted Kremenek78002122011-10-29 00:12:39 +0000260 // Emit the file header.
261 Stream.Emit((unsigned)'D', 8);
Ted Kremenek0b69aa82011-11-08 20:27:29 +0000262 Stream.Emit((unsigned)'I', 8);
263 Stream.Emit((unsigned)'A', 8);
264 Stream.Emit((unsigned)'G', 8);
Ted Kremenek069f9c22011-11-05 00:09:53 +0000265
Ted Kremenek78002122011-10-29 00:12:39 +0000266 EmitBlockInfoBlock();
Ted Kremenek0b69aa82011-11-08 20:27:29 +0000267 EmitMetaBlock();
Ted Kremenek78002122011-10-29 00:12:39 +0000268}
269
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000270static void AddSourceLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) {
271 using namespace llvm;
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000272 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // File ID.
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000273 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Line.
274 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Column.
275 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Offset;
276}
Ted Kremenek96dcade2011-11-05 03:34:23 +0000277
278static void AddRangeLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) {
279 AddSourceLocationAbbrev(Abbrev);
280 AddSourceLocationAbbrev(Abbrev);
281}
282
Ted Kremenek78002122011-10-29 00:12:39 +0000283void SDiagsWriter::EmitBlockInfoBlock() {
284 Stream.EnterBlockInfoBlock(3);
Ted Kremenek0b69aa82011-11-08 20:27:29 +0000285
286 using namespace llvm;
287
288 // ==---------------------------------------------------------------------==//
289 // The subsequent records and Abbrevs are for the "Meta" block.
290 // ==---------------------------------------------------------------------==//
291
292 EmitBlockID(BLOCK_META, "Meta", Stream, Record);
293 EmitRecordID(RECORD_VERSION, "Version", Stream, Record);
294 BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
295 Abbrev->Add(BitCodeAbbrevOp(RECORD_VERSION));
296 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
297 Abbrevs.set(RECORD_VERSION, Stream.EmitBlockInfoAbbrev(BLOCK_META, Abbrev));
298
Ted Kremenek78002122011-10-29 00:12:39 +0000299 // ==---------------------------------------------------------------------==//
300 // The subsequent records and Abbrevs are for the "Diagnostic" block.
301 // ==---------------------------------------------------------------------==//
302
Ted Kremenek45d92752011-11-05 00:09:50 +0000303 EmitBlockID(BLOCK_DIAG, "Diag", Stream, Record);
304 EmitRecordID(RECORD_DIAG, "DiagInfo", Stream, Record);
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000305 EmitRecordID(RECORD_SOURCE_RANGE, "SrcRange", Stream, Record);
Ted Kremenek0dbadc42011-11-05 00:10:04 +0000306 EmitRecordID(RECORD_CATEGORY, "CatName", Stream, Record);
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000307 EmitRecordID(RECORD_DIAG_FLAG, "DiagFlag", Stream, Record);
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000308 EmitRecordID(RECORD_FILENAME, "FileName", Stream, Record);
Ted Kremenek96dcade2011-11-05 03:34:23 +0000309 EmitRecordID(RECORD_FIXIT, "FixIt", Stream, Record);
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000310
Ted Kremenek78002122011-10-29 00:12:39 +0000311 // Emit abbreviation for RECORD_DIAG.
Ted Kremenek0b69aa82011-11-08 20:27:29 +0000312 Abbrev = new BitCodeAbbrev();
Ted Kremenek78002122011-10-29 00:12:39 +0000313 Abbrev->Add(BitCodeAbbrevOp(RECORD_DIAG));
Ted Kremenek45d92752011-11-05 00:09:50 +0000314 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Diag level.
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000315 AddSourceLocationAbbrev(Abbrev);
Ted Kremenek45d92752011-11-05 00:09:50 +0000316 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Category.
317 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped Diag ID.
Ted Kremenek78002122011-10-29 00:12:39 +0000318 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
319 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Diagnostc text.
320 Abbrevs.set(RECORD_DIAG, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000321
Ted Kremenek0dbadc42011-11-05 00:10:04 +0000322 // Emit abbrevation for RECORD_CATEGORY.
323 Abbrev = new BitCodeAbbrev();
324 Abbrev->Add(BitCodeAbbrevOp(RECORD_CATEGORY));
325 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Category ID.
326 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8)); // Text size.
327 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Category text.
328 Abbrevs.set(RECORD_CATEGORY, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
329
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000330 // Emit abbrevation for RECORD_SOURCE_RANGE.
331 Abbrev = new BitCodeAbbrev();
332 Abbrev->Add(BitCodeAbbrevOp(RECORD_SOURCE_RANGE));
Ted Kremenek96dcade2011-11-05 03:34:23 +0000333 AddRangeLocationAbbrev(Abbrev);
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000334 Abbrevs.set(RECORD_SOURCE_RANGE,
335 Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000336
337 // Emit the abbreviation for RECORD_DIAG_FLAG.
338 Abbrev = new BitCodeAbbrev();
339 Abbrev->Add(BitCodeAbbrevOp(RECORD_DIAG_FLAG));
340 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped Diag ID.
341 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
342 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Flag name text.
343 Abbrevs.set(RECORD_DIAG_FLAG, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
344 Abbrev));
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000345
346 // Emit the abbreviation for RECORD_FILENAME.
Ted Kremenek78002122011-10-29 00:12:39 +0000347 Abbrev = new BitCodeAbbrev();
Ted Kremenek28eac522011-11-05 00:09:43 +0000348 Abbrev->Add(BitCodeAbbrevOp(RECORD_FILENAME));
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000349 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped file ID.
350 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Size.
351 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Modifcation time.
Ted Kremenek78002122011-10-29 00:12:39 +0000352 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
353 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name text.
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000354 Abbrevs.set(RECORD_FILENAME, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
Ted Kremenek78002122011-10-29 00:12:39 +0000355 Abbrev));
Ted Kremenek96dcade2011-11-05 03:34:23 +0000356
357 // Emit the abbreviation for RECORD_FIXIT.
358 Abbrev = new BitCodeAbbrev();
359 Abbrev->Add(BitCodeAbbrevOp(RECORD_FIXIT));
360 AddRangeLocationAbbrev(Abbrev);
361 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
362 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // FixIt text.
363 Abbrevs.set(RECORD_FIXIT, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
364 Abbrev));
Ted Kremenek78002122011-10-29 00:12:39 +0000365
366 Stream.ExitBlock();
367}
368
Ted Kremenek0b69aa82011-11-08 20:27:29 +0000369void SDiagsWriter::EmitMetaBlock() {
370 Stream.EnterSubblock(BLOCK_META, 3);
371 Record.clear();
372 Record.push_back(RECORD_VERSION);
373 Record.push_back(Version);
374 Stream.EmitRecordWithAbbrev(Abbrevs.get(RECORD_VERSION), Record);
375 Stream.ExitBlock();
376}
377
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000378unsigned SDiagsWriter::getEmitCategory(unsigned int DiagID) {
379 unsigned category = DiagnosticIDs::getCategoryNumberForDiag(DiagID);
Ted Kremenek0dbadc42011-11-05 00:10:04 +0000380
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000381 if (Categories.count(category))
382 return category;
383
384 Categories.insert(category);
Ted Kremenek0dbadc42011-11-05 00:10:04 +0000385
386 // We use a local version of 'Record' so that we can be generating
387 // another record when we lazily generate one for the category entry.
388 RecordData Record;
389 Record.push_back(RECORD_CATEGORY);
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000390 Record.push_back(category);
391 StringRef catName = DiagnosticIDs::getCategoryNameFromID(category);
Ted Kremenek0dbadc42011-11-05 00:10:04 +0000392 Record.push_back(catName.size());
393 Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_CATEGORY), Record, catName);
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000394
395 return category;
396}
397
398unsigned SDiagsWriter::getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
399 const Diagnostic &Info) {
400 if (DiagLevel == DiagnosticsEngine::Note)
401 return 0; // No flag for notes.
402
403 StringRef FlagName = DiagnosticIDs::getWarningOptionForDiag(Info.getID());
404 if (FlagName.empty())
405 return 0;
406
407 // Here we assume that FlagName points to static data whose pointer
408 // value is fixed. This allows us to unique by diagnostic groups.
409 const void *data = FlagName.data();
410 std::pair<unsigned, StringRef> &entry = DiagFlags[data];
411 if (entry.first == 0) {
412 entry.first = DiagFlags.size();
413 entry.second = FlagName;
414
415 // Lazily emit the string in a separate record.
416 RecordData Record;
417 Record.push_back(RECORD_DIAG_FLAG);
418 Record.push_back(entry.first);
419 Record.push_back(FlagName.size());
420 Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG_FLAG),
421 Record, FlagName);
422 }
423
424 return entry.first;
Ted Kremenek0dbadc42011-11-05 00:10:04 +0000425}
426
Ted Kremenek78002122011-10-29 00:12:39 +0000427void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
428 const Diagnostic &Info) {
429
Ted Kremenek59b61612011-11-05 00:09:47 +0000430 if (DiagLevel != DiagnosticsEngine::Note) {
431 if (inNonNoteDiagnostic) {
432 // We have encountered a non-note diagnostic. Finish up the previous
433 // diagnostic block before starting a new one.
434 Stream.ExitBlock();
435 }
436 inNonNoteDiagnostic = true;
437 }
438
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000439 Stream.EnterSubblock(BLOCK_DIAG, 4);
Ted Kremenek78002122011-10-29 00:12:39 +0000440
441 // Emit the RECORD_DIAG record.
442 Record.clear();
443 Record.push_back(RECORD_DIAG);
444 Record.push_back(DiagLevel);
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000445 AddLocToRecord(Info.getLocation(), Record);
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000446 // Emit the category string lazily and get the category ID.
447 Record.push_back(getEmitCategory(Info.getID()));
448 // Emit the diagnostic flag string lazily and get the mapped ID.
449 Record.push_back(getEmitDiagnosticFlag(DiagLevel, Info));
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000450 // Emit the diagnostic text.
Ted Kremenek78002122011-10-29 00:12:39 +0000451 diagBuf.clear();
452 Info.FormatDiagnostic(diagBuf); // Compute the diagnostic text.
453 Record.push_back(diagBuf.str().size());
454 Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG), Record, diagBuf.str());
Ted Kremenek96dcade2011-11-05 03:34:23 +0000455
456 // Emit Source Ranges.
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000457 ArrayRef<CharSourceRange> Ranges = Info.getRanges();
458 for (ArrayRef<CharSourceRange>::iterator it=Ranges.begin(), ei=Ranges.end();
459 it != ei; ++it) {
460 EmitCharSourceRange(*it);
461 }
462
Ted Kremenek96dcade2011-11-05 03:34:23 +0000463 // Emit FixIts.
464 for (unsigned i = 0, n = Info.getNumFixItHints(); i != n; ++i) {
465 const FixItHint &fix = Info.getFixItHint(i);
466 if (fix.isNull())
467 continue;
468 Record.clear();
469 Record.push_back(RECORD_FIXIT);
470 AddCharSourceRangeToRecord(fix.RemoveRange, Record);
471 Record.push_back(fix.CodeToInsert.size());
472 Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_FIXIT), Record,
473 fix.CodeToInsert);
474 }
Ted Kremenek59b61612011-11-05 00:09:47 +0000475
476 if (DiagLevel == DiagnosticsEngine::Note) {
477 // Notes currently cannot have child diagnostics. Complete the
478 // diagnostic now.
479 Stream.ExitBlock();
480 }
Ted Kremenek78002122011-10-29 00:12:39 +0000481}
482
Ted Kremenek78002122011-10-29 00:12:39 +0000483void SDiagsWriter::EndSourceFile() {
Ted Kremenek59b61612011-11-05 00:09:47 +0000484 if (inNonNoteDiagnostic) {
485 // Finish off any diagnostics we were in the process of emitting.
486 Stream.ExitBlock();
487 inNonNoteDiagnostic = false;
488 }
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000489
Ted Kremenek78002122011-10-29 00:12:39 +0000490 // Write the generated bitstream to "Out".
491 OS->write((char *)&Buffer.front(), Buffer.size());
492 OS->flush();
493
494 OS.reset(0);
495}
496