blob: 04184f7f4b04900e8faa8f973285979ae3a2d1c9 [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:
Argyrios Kyrtzidis29f27872011-12-07 05:52:12 +000050 explicit SDiagsWriter(llvm::raw_ostream *os)
51 : LangOpts(0), Stream(Buffer), OS(os), inNonNoteDiagnostic(false)
Ted Kremenek78002122011-10-29 00:12:39 +000052 {
53 EmitPreamble();
Devang Patel02ae32a2011-11-15 01:30:40 +000054 }
Ted Kremenek78002122011-10-29 00:12:39 +000055
56 ~SDiagsWriter() {}
57
58 void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
59 const Diagnostic &Info);
60
Ted Kremenek15322172011-11-10 08:43:12 +000061 void BeginSourceFile(const LangOptions &LO,
62 const Preprocessor *PP) {
63 LangOpts = &LO;
64 }
Argyrios Kyrtzidis29f27872011-12-07 05:52:12 +000065
66 virtual void finish();
67
Ted Kremenek78002122011-10-29 00:12:39 +000068 DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const {
69 // It makes no sense to clone this.
70 return 0;
71 }
72
73private:
74 /// \brief Emit the preamble for the serialized diagnostics.
75 void EmitPreamble();
76
77 /// \brief Emit the BLOCKINFO block.
78 void EmitBlockInfoBlock();
Ted Kremenek0d34e6e2011-11-05 00:10:11 +000079
Ted Kremenek0b69aa82011-11-08 20:27:29 +000080 /// \brief Emit the META data block.
81 void EmitMetaBlock();
82
Ted Kremenek2a20b4f2011-11-05 00:10:01 +000083 /// \brief Emit a record for a CharSourceRange.
Argyrios Kyrtzidis29f27872011-12-07 05:52:12 +000084 void EmitCharSourceRange(CharSourceRange R, SourceManager &SM);
Ted Kremenek2a20b4f2011-11-05 00:10:01 +000085
Ted Kremenek3baf63d2011-11-05 00:10:07 +000086 /// \brief Emit the string information for the category for a diagnostic.
87 unsigned getEmitCategory(unsigned DiagID);
88
89 /// \brief Emit the string information for diagnostic flags.
90 unsigned getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
91 const Diagnostic &Info);
Ted Kremenek0dbadc42011-11-05 00:10:04 +000092
Ted Kremenek0d34e6e2011-11-05 00:10:11 +000093 /// \brief Emit (lazily) the file string and retrieved the file identifier.
Argyrios Kyrtzidis29f27872011-12-07 05:52:12 +000094 unsigned getEmitFile(SourceLocation Loc, SourceManager &SM);
Ted Kremenek0d34e6e2011-11-05 00:10:11 +000095
96 /// \brief Add SourceLocation information the specified record.
Ted Kremenek15322172011-11-10 08:43:12 +000097 void AddLocToRecord(SourceLocation Loc, RecordDataImpl &Record,
Argyrios Kyrtzidis29f27872011-12-07 05:52:12 +000098 SourceManager &SM,
Ted Kremenek15322172011-11-10 08:43:12 +000099 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.
Argyrios Kyrtzidis29f27872011-12-07 05:52:12 +0000102 void AddCharSourceRangeToRecord(CharSourceRange R, RecordDataImpl &Record,
103 SourceManager &SM);
Ted Kremenek96dcade2011-11-05 03:34:23 +0000104
Ted Kremenek78002122011-10-29 00:12:39 +0000105 /// \brief The version of the diagnostics file.
106 enum { Version = 1 };
107
Ted Kremenek15322172011-11-10 08:43:12 +0000108 const LangOptions *LangOpts;
109
Ted Kremenek78002122011-10-29 00:12:39 +0000110 /// \brief The byte buffer for the serialized content.
111 std::vector<unsigned char> Buffer;
112
113 /// \brief The BitStreamWriter for the serialized diagnostics.
114 llvm::BitstreamWriter Stream;
115
116 /// \brief The name of the diagnostics file.
117 llvm::OwningPtr<llvm::raw_ostream> OS;
118
Ted Kremenek78002122011-10-29 00:12:39 +0000119 /// \brief The set of constructed record abbreviations.
120 AbbreviationMap Abbrevs;
121
122 /// \brief A utility buffer for constructing record content.
123 RecordData Record;
124
125 /// \brief A text buffer for rendering diagnostic text.
126 llvm::SmallString<256> diagBuf;
127
128 /// \brief The collection of diagnostic categories used.
129 llvm::DenseSet<unsigned> Categories;
130
131 /// \brief The collection of files used.
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000132 llvm::DenseMap<const FileEntry *, unsigned> Files;
Ted Kremenek45d92752011-11-05 00:09:50 +0000133
134 typedef llvm::DenseMap<const void *, std::pair<unsigned, llvm::StringRef> >
135 DiagFlagsTy;
136
137 /// \brief Map for uniquing strings.
138 DiagFlagsTy DiagFlags;
Ted Kremenek78002122011-10-29 00:12:39 +0000139
Ted Kremenek59b61612011-11-05 00:09:47 +0000140 /// \brief Flag indicating whether or not we are in the process of
141 /// emitting a non-note diagnostic.
142 bool inNonNoteDiagnostic;
Ted Kremenek78002122011-10-29 00:12:39 +0000143};
144} // end anonymous namespace
145
146namespace clang {
147namespace serialized_diags {
Argyrios Kyrtzidis29f27872011-12-07 05:52:12 +0000148DiagnosticConsumer *create(llvm::raw_ostream *OS) {
149 return new SDiagsWriter(OS);
Ted Kremenek78002122011-10-29 00:12:39 +0000150}
151} // end namespace serialized_diags
152} // end namespace clang
153
154//===----------------------------------------------------------------------===//
155// Serialization methods.
156//===----------------------------------------------------------------------===//
157
158/// \brief Emits a block ID in the BLOCKINFO block.
159static void EmitBlockID(unsigned ID, const char *Name,
160 llvm::BitstreamWriter &Stream,
161 RecordDataImpl &Record) {
162 Record.clear();
163 Record.push_back(ID);
164 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
165
166 // Emit the block name if present.
167 if (Name == 0 || Name[0] == 0)
168 return;
169
170 Record.clear();
171
172 while (*Name)
173 Record.push_back(*Name++);
174
175 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record);
176}
177
178/// \brief Emits a record ID in the BLOCKINFO block.
179static void EmitRecordID(unsigned ID, const char *Name,
180 llvm::BitstreamWriter &Stream,
181 RecordDataImpl &Record){
182 Record.clear();
183 Record.push_back(ID);
184
185 while (*Name)
186 Record.push_back(*Name++);
187
188 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
189}
190
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000191void SDiagsWriter::AddLocToRecord(SourceLocation Loc,
Ted Kremenek15322172011-11-10 08:43:12 +0000192 RecordDataImpl &Record,
Argyrios Kyrtzidis29f27872011-12-07 05:52:12 +0000193 SourceManager &SM,
Ted Kremenek15322172011-11-10 08:43:12 +0000194 unsigned TokSize) {
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000195 if (Loc.isInvalid()) {
196 // Emit a "sentinel" location.
Ted Kremenek15322172011-11-10 08:43:12 +0000197 Record.push_back((unsigned)0); // File.
198 Record.push_back((unsigned)0); // Line.
199 Record.push_back((unsigned)0); // Column.
200 Record.push_back((unsigned)0); // Offset.
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000201 return;
202 }
203
204 Loc = SM.getSpellingLoc(Loc);
Argyrios Kyrtzidis29f27872011-12-07 05:52:12 +0000205 Record.push_back(getEmitFile(Loc, SM));
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000206 Record.push_back(SM.getSpellingLineNumber(Loc));
Ted Kremenek15322172011-11-10 08:43:12 +0000207 Record.push_back(SM.getSpellingColumnNumber(Loc)+TokSize);
Benjamin Kramer6eb29d22011-11-10 11:29:20 +0000208 Record.push_back(SM.getFileOffset(Loc));
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000209}
210
Ted Kremenek96dcade2011-11-05 03:34:23 +0000211void SDiagsWriter::AddCharSourceRangeToRecord(CharSourceRange Range,
Argyrios Kyrtzidis29f27872011-12-07 05:52:12 +0000212 RecordDataImpl &Record,
213 SourceManager &SM) {
214 AddLocToRecord(Range.getBegin(), Record, SM);
Ted Kremenek15322172011-11-10 08:43:12 +0000215 unsigned TokSize = 0;
216 if (Range.isTokenRange())
217 TokSize = Lexer::MeasureTokenLength(Range.getEnd(),
Argyrios Kyrtzidis29f27872011-12-07 05:52:12 +0000218 SM, *LangOpts);
Ted Kremenek15322172011-11-10 08:43:12 +0000219
Argyrios Kyrtzidis29f27872011-12-07 05:52:12 +0000220 AddLocToRecord(Range.getEnd(), Record, SM, TokSize);
Ted Kremenek96dcade2011-11-05 03:34:23 +0000221}
222
Argyrios Kyrtzidis29f27872011-12-07 05:52:12 +0000223unsigned SDiagsWriter::getEmitFile(SourceLocation Loc, SourceManager &SM) {
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000224 assert(Loc.isValid());
225 const std::pair<FileID, unsigned> &LocInfo = SM.getDecomposedLoc(Loc);
226 const FileEntry *FE = SM.getFileEntryForID(LocInfo.first);
227 if (!FE)
228 return 0;
229
230 unsigned &entry = Files[FE];
231 if (entry)
232 return entry;
233
234 // Lazily generate the record for the file.
235 entry = Files.size();
236 RecordData Record;
237 Record.push_back(RECORD_FILENAME);
238 Record.push_back(entry);
239 Record.push_back(FE->getSize());
240 Record.push_back(FE->getModificationTime());
241 StringRef Name = FE->getName();
242 Record.push_back(Name.size());
243 Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_FILENAME), Record, Name);
244
245 return entry;
246}
247
Argyrios Kyrtzidis29f27872011-12-07 05:52:12 +0000248void SDiagsWriter::EmitCharSourceRange(CharSourceRange R,
249 SourceManager &SM) {
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000250 Record.clear();
251 Record.push_back(RECORD_SOURCE_RANGE);
Argyrios Kyrtzidis29f27872011-12-07 05:52:12 +0000252 AddCharSourceRangeToRecord(R, Record, SM);
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000253 Stream.EmitRecordWithAbbrev(Abbrevs.get(RECORD_SOURCE_RANGE), Record);
254}
255
Ted Kremenek78002122011-10-29 00:12:39 +0000256/// \brief Emits the preamble of the diagnostics file.
257void SDiagsWriter::EmitPreamble() {
Ted Kremenek78002122011-10-29 00:12:39 +0000258 // Emit the file header.
259 Stream.Emit((unsigned)'D', 8);
Ted Kremenek0b69aa82011-11-08 20:27:29 +0000260 Stream.Emit((unsigned)'I', 8);
261 Stream.Emit((unsigned)'A', 8);
262 Stream.Emit((unsigned)'G', 8);
Ted Kremenek069f9c22011-11-05 00:09:53 +0000263
Ted Kremenek78002122011-10-29 00:12:39 +0000264 EmitBlockInfoBlock();
Ted Kremenek0b69aa82011-11-08 20:27:29 +0000265 EmitMetaBlock();
Ted Kremenek78002122011-10-29 00:12:39 +0000266}
267
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000268static void AddSourceLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) {
269 using namespace llvm;
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000270 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // File ID.
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000271 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Line.
272 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Column.
273 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Offset;
274}
Ted Kremenek96dcade2011-11-05 03:34:23 +0000275
276static void AddRangeLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) {
277 AddSourceLocationAbbrev(Abbrev);
278 AddSourceLocationAbbrev(Abbrev);
279}
280
Ted Kremenek78002122011-10-29 00:12:39 +0000281void SDiagsWriter::EmitBlockInfoBlock() {
282 Stream.EnterBlockInfoBlock(3);
Ted Kremenek0b69aa82011-11-08 20:27:29 +0000283
284 using namespace llvm;
285
286 // ==---------------------------------------------------------------------==//
287 // The subsequent records and Abbrevs are for the "Meta" block.
288 // ==---------------------------------------------------------------------==//
289
290 EmitBlockID(BLOCK_META, "Meta", Stream, Record);
291 EmitRecordID(RECORD_VERSION, "Version", Stream, Record);
292 BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
293 Abbrev->Add(BitCodeAbbrevOp(RECORD_VERSION));
294 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
295 Abbrevs.set(RECORD_VERSION, Stream.EmitBlockInfoAbbrev(BLOCK_META, Abbrev));
296
Ted Kremenek78002122011-10-29 00:12:39 +0000297 // ==---------------------------------------------------------------------==//
298 // The subsequent records and Abbrevs are for the "Diagnostic" block.
299 // ==---------------------------------------------------------------------==//
300
Ted Kremenek45d92752011-11-05 00:09:50 +0000301 EmitBlockID(BLOCK_DIAG, "Diag", Stream, Record);
302 EmitRecordID(RECORD_DIAG, "DiagInfo", Stream, Record);
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000303 EmitRecordID(RECORD_SOURCE_RANGE, "SrcRange", Stream, Record);
Ted Kremenek0dbadc42011-11-05 00:10:04 +0000304 EmitRecordID(RECORD_CATEGORY, "CatName", Stream, Record);
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000305 EmitRecordID(RECORD_DIAG_FLAG, "DiagFlag", Stream, Record);
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000306 EmitRecordID(RECORD_FILENAME, "FileName", Stream, Record);
Ted Kremenek96dcade2011-11-05 03:34:23 +0000307 EmitRecordID(RECORD_FIXIT, "FixIt", Stream, Record);
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000308
Ted Kremenek78002122011-10-29 00:12:39 +0000309 // Emit abbreviation for RECORD_DIAG.
Ted Kremenek0b69aa82011-11-08 20:27:29 +0000310 Abbrev = new BitCodeAbbrev();
Ted Kremenek78002122011-10-29 00:12:39 +0000311 Abbrev->Add(BitCodeAbbrevOp(RECORD_DIAG));
Ted Kremenek45d92752011-11-05 00:09:50 +0000312 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Diag level.
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000313 AddSourceLocationAbbrev(Abbrev);
Ted Kremenek45d92752011-11-05 00:09:50 +0000314 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Category.
315 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped Diag ID.
Ted Kremenek78002122011-10-29 00:12:39 +0000316 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
317 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Diagnostc text.
318 Abbrevs.set(RECORD_DIAG, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000319
Ted Kremenek0dbadc42011-11-05 00:10:04 +0000320 // Emit abbrevation for RECORD_CATEGORY.
321 Abbrev = new BitCodeAbbrev();
322 Abbrev->Add(BitCodeAbbrevOp(RECORD_CATEGORY));
323 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Category ID.
324 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8)); // Text size.
325 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Category text.
326 Abbrevs.set(RECORD_CATEGORY, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
327
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000328 // Emit abbrevation for RECORD_SOURCE_RANGE.
329 Abbrev = new BitCodeAbbrev();
330 Abbrev->Add(BitCodeAbbrevOp(RECORD_SOURCE_RANGE));
Ted Kremenek96dcade2011-11-05 03:34:23 +0000331 AddRangeLocationAbbrev(Abbrev);
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000332 Abbrevs.set(RECORD_SOURCE_RANGE,
333 Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000334
335 // Emit the abbreviation for RECORD_DIAG_FLAG.
336 Abbrev = new BitCodeAbbrev();
337 Abbrev->Add(BitCodeAbbrevOp(RECORD_DIAG_FLAG));
338 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped Diag ID.
339 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
340 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Flag name text.
341 Abbrevs.set(RECORD_DIAG_FLAG, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
342 Abbrev));
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000343
344 // Emit the abbreviation for RECORD_FILENAME.
Ted Kremenek78002122011-10-29 00:12:39 +0000345 Abbrev = new BitCodeAbbrev();
Ted Kremenek28eac522011-11-05 00:09:43 +0000346 Abbrev->Add(BitCodeAbbrevOp(RECORD_FILENAME));
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000347 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped file ID.
348 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Size.
349 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Modifcation time.
Ted Kremenek78002122011-10-29 00:12:39 +0000350 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
351 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name text.
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000352 Abbrevs.set(RECORD_FILENAME, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
Ted Kremenek78002122011-10-29 00:12:39 +0000353 Abbrev));
Ted Kremenek96dcade2011-11-05 03:34:23 +0000354
355 // Emit the abbreviation for RECORD_FIXIT.
356 Abbrev = new BitCodeAbbrev();
357 Abbrev->Add(BitCodeAbbrevOp(RECORD_FIXIT));
358 AddRangeLocationAbbrev(Abbrev);
359 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
360 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // FixIt text.
361 Abbrevs.set(RECORD_FIXIT, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
362 Abbrev));
Ted Kremenek78002122011-10-29 00:12:39 +0000363
364 Stream.ExitBlock();
365}
366
Ted Kremenek0b69aa82011-11-08 20:27:29 +0000367void SDiagsWriter::EmitMetaBlock() {
368 Stream.EnterSubblock(BLOCK_META, 3);
369 Record.clear();
370 Record.push_back(RECORD_VERSION);
371 Record.push_back(Version);
372 Stream.EmitRecordWithAbbrev(Abbrevs.get(RECORD_VERSION), Record);
373 Stream.ExitBlock();
374}
375
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000376unsigned SDiagsWriter::getEmitCategory(unsigned int DiagID) {
377 unsigned category = DiagnosticIDs::getCategoryNumberForDiag(DiagID);
Ted Kremenek0dbadc42011-11-05 00:10:04 +0000378
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000379 if (Categories.count(category))
380 return category;
381
382 Categories.insert(category);
Ted Kremenek0dbadc42011-11-05 00:10:04 +0000383
384 // We use a local version of 'Record' so that we can be generating
385 // another record when we lazily generate one for the category entry.
386 RecordData Record;
387 Record.push_back(RECORD_CATEGORY);
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000388 Record.push_back(category);
389 StringRef catName = DiagnosticIDs::getCategoryNameFromID(category);
Ted Kremenek0dbadc42011-11-05 00:10:04 +0000390 Record.push_back(catName.size());
391 Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_CATEGORY), Record, catName);
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000392
393 return category;
394}
395
396unsigned SDiagsWriter::getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
397 const Diagnostic &Info) {
398 if (DiagLevel == DiagnosticsEngine::Note)
399 return 0; // No flag for notes.
400
401 StringRef FlagName = DiagnosticIDs::getWarningOptionForDiag(Info.getID());
402 if (FlagName.empty())
403 return 0;
404
405 // Here we assume that FlagName points to static data whose pointer
406 // value is fixed. This allows us to unique by diagnostic groups.
407 const void *data = FlagName.data();
408 std::pair<unsigned, StringRef> &entry = DiagFlags[data];
409 if (entry.first == 0) {
410 entry.first = DiagFlags.size();
411 entry.second = FlagName;
412
413 // Lazily emit the string in a separate record.
414 RecordData Record;
415 Record.push_back(RECORD_DIAG_FLAG);
416 Record.push_back(entry.first);
417 Record.push_back(FlagName.size());
418 Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG_FLAG),
419 Record, FlagName);
420 }
421
422 return entry.first;
Ted Kremenek0dbadc42011-11-05 00:10:04 +0000423}
424
Ted Kremenek78002122011-10-29 00:12:39 +0000425void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
426 const Diagnostic &Info) {
Argyrios Kyrtzidis29f27872011-12-07 05:52:12 +0000427 SourceManager &SM = Info.getSourceManager();
Ted Kremenek78002122011-10-29 00:12:39 +0000428
Ted Kremenek59b61612011-11-05 00:09:47 +0000429 if (DiagLevel != DiagnosticsEngine::Note) {
430 if (inNonNoteDiagnostic) {
431 // We have encountered a non-note diagnostic. Finish up the previous
432 // diagnostic block before starting a new one.
433 Stream.ExitBlock();
434 }
435 inNonNoteDiagnostic = true;
436 }
437
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000438 Stream.EnterSubblock(BLOCK_DIAG, 4);
Ted Kremenek78002122011-10-29 00:12:39 +0000439
440 // Emit the RECORD_DIAG record.
441 Record.clear();
442 Record.push_back(RECORD_DIAG);
443 Record.push_back(DiagLevel);
Argyrios Kyrtzidis29f27872011-12-07 05:52:12 +0000444 AddLocToRecord(Info.getLocation(), Record, SM);
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000445 // Emit the category string lazily and get the category ID.
446 Record.push_back(getEmitCategory(Info.getID()));
447 // Emit the diagnostic flag string lazily and get the mapped ID.
448 Record.push_back(getEmitDiagnosticFlag(DiagLevel, Info));
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000449 // Emit the diagnostic text.
Ted Kremenek78002122011-10-29 00:12:39 +0000450 diagBuf.clear();
451 Info.FormatDiagnostic(diagBuf); // Compute the diagnostic text.
452 Record.push_back(diagBuf.str().size());
453 Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG), Record, diagBuf.str());
Ted Kremenek96dcade2011-11-05 03:34:23 +0000454
455 // Emit Source Ranges.
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000456 ArrayRef<CharSourceRange> Ranges = Info.getRanges();
457 for (ArrayRef<CharSourceRange>::iterator it=Ranges.begin(), ei=Ranges.end();
458 it != ei; ++it) {
Argyrios Kyrtzidis29f27872011-12-07 05:52:12 +0000459 if (it->isValid())
460 EmitCharSourceRange(*it, SM);
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000461 }
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);
Argyrios Kyrtzidis29f27872011-12-07 05:52:12 +0000470 AddCharSourceRangeToRecord(fix.RemoveRange, Record, SM);
Ted Kremenek96dcade2011-11-05 03:34:23 +0000471 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
Argyrios Kyrtzidis29f27872011-12-07 05:52:12 +0000483void SDiagsWriter::finish() {
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