blob: 4bf813e1603da0e3711f4db012daeb02b3138583 [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"
Ted Kremenek2a764102011-12-17 05:26:11 +000021#include "clang/Frontend/DiagnosticRenderer.h"
Ted Kremenek78002122011-10-29 00:12:39 +000022
23using namespace clang;
Ted Kremenekfdd0ced2011-11-05 00:09:57 +000024using namespace clang::serialized_diags;
Ted Kremenek78002122011-10-29 00:12:39 +000025
26namespace {
Ted Kremenek78002122011-10-29 00:12:39 +000027
28class AbbreviationMap {
29 llvm::DenseMap<unsigned, unsigned> Abbrevs;
30public:
31 AbbreviationMap() {}
32
33 void set(unsigned recordID, unsigned abbrevID) {
34 assert(Abbrevs.find(recordID) == Abbrevs.end()
35 && "Abbreviation already set.");
36 Abbrevs[recordID] = abbrevID;
37 }
38
39 unsigned get(unsigned recordID) {
40 assert(Abbrevs.find(recordID) != Abbrevs.end() &&
41 "Abbreviation not set.");
42 return Abbrevs[recordID];
43 }
44};
45
46typedef llvm::SmallVector<uint64_t, 64> RecordData;
47typedef llvm::SmallVectorImpl<uint64_t> RecordDataImpl;
Ted Kremenek2a764102011-12-17 05:26:11 +000048
49class SDiagsWriter;
50
51class SDiagsRenderer : public DiagnosticRenderer {
52 SDiagsWriter &Writer;
53 RecordData &Record;
54public:
55 SDiagsRenderer(SDiagsWriter &Writer, RecordData &Record,
56 const SourceManager &SM,
57 const LangOptions &LangOpts,
58 const DiagnosticOptions &DiagOpts)
59 : DiagnosticRenderer(SM, LangOpts, DiagOpts),
60 Writer(Writer), Record(Record){}
61
62 virtual ~SDiagsRenderer() {}
63
64protected:
65 virtual void emitDiagnosticMessage(SourceLocation Loc,
66 PresumedLoc PLoc,
67 DiagnosticsEngine::Level Level,
68 StringRef Message,
69 ArrayRef<CharSourceRange> Ranges,
70 const Diagnostic *Info);
71
72 virtual void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
73 DiagnosticsEngine::Level Level,
74 ArrayRef<CharSourceRange> Ranges) {}
75
76 virtual void emitBasicNote(StringRef Message);
77
78 void emitNote(SourceLocation Loc, StringRef Message);
79
80 virtual void emitIncludeLocation(SourceLocation Loc,
81 PresumedLoc PLoc);
82
83 virtual void emitCodeContext(SourceLocation Loc,
84 DiagnosticsEngine::Level Level,
85 SmallVectorImpl<CharSourceRange>& Ranges,
86 ArrayRef<FixItHint> Hints);
87
88 virtual void beginDiagnostic(const Diagnostic *Info,
89 DiagnosticsEngine::Level Level);
90 virtual void endDiagnostic(const Diagnostic *Info,
91 DiagnosticsEngine::Level Level);
92};
Ted Kremenek78002122011-10-29 00:12:39 +000093
94class SDiagsWriter : public DiagnosticConsumer {
Ted Kremenek2a764102011-12-17 05:26:11 +000095 friend class SDiagsRenderer;
Ted Kremenek78002122011-10-29 00:12:39 +000096public:
Ted Kremenek2a764102011-12-17 05:26:11 +000097 explicit SDiagsWriter(llvm::raw_ostream *os, const DiagnosticOptions &diags)
98 : LangOpts(0), DiagOpts(diags),
99 Stream(Buffer), OS(os), inNonNoteDiagnostic(false)
Ted Kremenek78002122011-10-29 00:12:39 +0000100 {
101 EmitPreamble();
Devang Patel02ae32a2011-11-15 01:30:40 +0000102 }
Ted Kremenek78002122011-10-29 00:12:39 +0000103
104 ~SDiagsWriter() {}
105
106 void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
107 const Diagnostic &Info);
108
Ted Kremenek15322172011-11-10 08:43:12 +0000109 void BeginSourceFile(const LangOptions &LO,
110 const Preprocessor *PP) {
111 LangOpts = &LO;
112 }
Argyrios Kyrtzidis29f27872011-12-07 05:52:12 +0000113
114 virtual void finish();
115
Ted Kremenek78002122011-10-29 00:12:39 +0000116 DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const {
117 // It makes no sense to clone this.
118 return 0;
119 }
120
121private:
122 /// \brief Emit the preamble for the serialized diagnostics.
123 void EmitPreamble();
124
125 /// \brief Emit the BLOCKINFO block.
126 void EmitBlockInfoBlock();
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000127
Ted Kremenek0b69aa82011-11-08 20:27:29 +0000128 /// \brief Emit the META data block.
129 void EmitMetaBlock();
130
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000131 /// \brief Emit a record for a CharSourceRange.
Ted Kremenek2a764102011-12-17 05:26:11 +0000132 void EmitCharSourceRange(CharSourceRange R, const SourceManager &SM);
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000133
Ted Kremenek2a764102011-12-17 05:26:11 +0000134 /// \brief Emit the string information for the category.
135 unsigned getEmitCategory(unsigned category = 0);
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000136
137 /// \brief Emit the string information for diagnostic flags.
138 unsigned getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
Ted Kremenek2a764102011-12-17 05:26:11 +0000139 unsigned DiagID = 0);
Ted Kremenek0dbadc42011-11-05 00:10:04 +0000140
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000141 /// \brief Emit (lazily) the file string and retrieved the file identifier.
Ted Kremenek2a764102011-12-17 05:26:11 +0000142 unsigned getEmitFile(const char *Filename);
143
144 /// \brief Add SourceLocation information the specified record.
145 void AddLocToRecord(SourceLocation Loc, const SourceManager &SM,
146 PresumedLoc PLoc, RecordDataImpl &Record,
147 unsigned TokSize = 0);
148
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000149 /// \brief Add SourceLocation information the specified record.
Ted Kremenek15322172011-11-10 08:43:12 +0000150 void AddLocToRecord(SourceLocation Loc, RecordDataImpl &Record,
Ted Kremenek2a764102011-12-17 05:26:11 +0000151 const SourceManager &SM,
152 unsigned TokSize = 0) {
153 AddLocToRecord(Loc, SM, SM.getPresumedLoc(Loc), Record, TokSize);
154 }
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000155
Ted Kremenek96dcade2011-11-05 03:34:23 +0000156 /// \brief Add CharSourceRange information the specified record.
Argyrios Kyrtzidis29f27872011-12-07 05:52:12 +0000157 void AddCharSourceRangeToRecord(CharSourceRange R, RecordDataImpl &Record,
Ted Kremenek2a764102011-12-17 05:26:11 +0000158 const SourceManager &SM);
Ted Kremenek96dcade2011-11-05 03:34:23 +0000159
Ted Kremenek78002122011-10-29 00:12:39 +0000160 /// \brief The version of the diagnostics file.
161 enum { Version = 1 };
162
Ted Kremenek15322172011-11-10 08:43:12 +0000163 const LangOptions *LangOpts;
Ted Kremenek2a764102011-12-17 05:26:11 +0000164 const DiagnosticOptions &DiagOpts;
Ted Kremenek15322172011-11-10 08:43:12 +0000165
Ted Kremenek78002122011-10-29 00:12:39 +0000166 /// \brief The byte buffer for the serialized content.
167 std::vector<unsigned char> Buffer;
168
169 /// \brief The BitStreamWriter for the serialized diagnostics.
170 llvm::BitstreamWriter Stream;
171
172 /// \brief The name of the diagnostics file.
173 llvm::OwningPtr<llvm::raw_ostream> OS;
174
Ted Kremenek78002122011-10-29 00:12:39 +0000175 /// \brief The set of constructed record abbreviations.
176 AbbreviationMap Abbrevs;
177
178 /// \brief A utility buffer for constructing record content.
179 RecordData Record;
180
181 /// \brief A text buffer for rendering diagnostic text.
182 llvm::SmallString<256> diagBuf;
183
184 /// \brief The collection of diagnostic categories used.
185 llvm::DenseSet<unsigned> Categories;
186
187 /// \brief The collection of files used.
Ted Kremenek2a764102011-12-17 05:26:11 +0000188 llvm::DenseMap<const char *, unsigned> Files;
Ted Kremenek45d92752011-11-05 00:09:50 +0000189
190 typedef llvm::DenseMap<const void *, std::pair<unsigned, llvm::StringRef> >
191 DiagFlagsTy;
192
193 /// \brief Map for uniquing strings.
194 DiagFlagsTy DiagFlags;
Ted Kremenek78002122011-10-29 00:12:39 +0000195
Ted Kremenek59b61612011-11-05 00:09:47 +0000196 /// \brief Flag indicating whether or not we are in the process of
197 /// emitting a non-note diagnostic.
198 bool inNonNoteDiagnostic;
Ted Kremenek78002122011-10-29 00:12:39 +0000199};
200} // end anonymous namespace
201
202namespace clang {
203namespace serialized_diags {
Ted Kremenek2a764102011-12-17 05:26:11 +0000204DiagnosticConsumer *create(llvm::raw_ostream *OS,
205 const DiagnosticOptions &diags) {
206 return new SDiagsWriter(OS, diags);
Ted Kremenek78002122011-10-29 00:12:39 +0000207}
208} // end namespace serialized_diags
209} // end namespace clang
210
211//===----------------------------------------------------------------------===//
212// Serialization methods.
213//===----------------------------------------------------------------------===//
214
215/// \brief Emits a block ID in the BLOCKINFO block.
216static void EmitBlockID(unsigned ID, const char *Name,
217 llvm::BitstreamWriter &Stream,
218 RecordDataImpl &Record) {
219 Record.clear();
220 Record.push_back(ID);
221 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
222
223 // Emit the block name if present.
224 if (Name == 0 || Name[0] == 0)
225 return;
226
227 Record.clear();
228
229 while (*Name)
230 Record.push_back(*Name++);
231
232 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record);
233}
234
235/// \brief Emits a record ID in the BLOCKINFO block.
236static void EmitRecordID(unsigned ID, const char *Name,
237 llvm::BitstreamWriter &Stream,
238 RecordDataImpl &Record){
239 Record.clear();
240 Record.push_back(ID);
241
242 while (*Name)
243 Record.push_back(*Name++);
244
245 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
246}
247
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000248void SDiagsWriter::AddLocToRecord(SourceLocation Loc,
Ted Kremenek2a764102011-12-17 05:26:11 +0000249 const SourceManager &SM,
250 PresumedLoc PLoc,
Ted Kremenek15322172011-11-10 08:43:12 +0000251 RecordDataImpl &Record,
252 unsigned TokSize) {
Ted Kremenek2a764102011-12-17 05:26:11 +0000253 if (PLoc.isInvalid()) {
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000254 // Emit a "sentinel" location.
Ted Kremenek15322172011-11-10 08:43:12 +0000255 Record.push_back((unsigned)0); // File.
256 Record.push_back((unsigned)0); // Line.
257 Record.push_back((unsigned)0); // Column.
258 Record.push_back((unsigned)0); // Offset.
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000259 return;
260 }
261
Ted Kremenek2a764102011-12-17 05:26:11 +0000262 Record.push_back(getEmitFile(PLoc.getFilename()));
263 Record.push_back(PLoc.getLine());
264 Record.push_back(PLoc.getColumn()+TokSize);
Benjamin Kramer6eb29d22011-11-10 11:29:20 +0000265 Record.push_back(SM.getFileOffset(Loc));
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000266}
267
Ted Kremenek96dcade2011-11-05 03:34:23 +0000268void SDiagsWriter::AddCharSourceRangeToRecord(CharSourceRange Range,
Argyrios Kyrtzidis29f27872011-12-07 05:52:12 +0000269 RecordDataImpl &Record,
Ted Kremenek2a764102011-12-17 05:26:11 +0000270 const SourceManager &SM) {
Argyrios Kyrtzidis29f27872011-12-07 05:52:12 +0000271 AddLocToRecord(Range.getBegin(), Record, SM);
Ted Kremenek15322172011-11-10 08:43:12 +0000272 unsigned TokSize = 0;
273 if (Range.isTokenRange())
274 TokSize = Lexer::MeasureTokenLength(Range.getEnd(),
Argyrios Kyrtzidis29f27872011-12-07 05:52:12 +0000275 SM, *LangOpts);
Ted Kremenek15322172011-11-10 08:43:12 +0000276
Argyrios Kyrtzidis29f27872011-12-07 05:52:12 +0000277 AddLocToRecord(Range.getEnd(), Record, SM, TokSize);
Ted Kremenek96dcade2011-11-05 03:34:23 +0000278}
279
Ted Kremenek2a764102011-12-17 05:26:11 +0000280unsigned SDiagsWriter::getEmitFile(const char *FileName){
281 if (!FileName)
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000282 return 0;
283
Ted Kremenek2a764102011-12-17 05:26:11 +0000284 unsigned &entry = Files[FileName];
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000285 if (entry)
286 return entry;
287
288 // Lazily generate the record for the file.
289 entry = Files.size();
290 RecordData Record;
291 Record.push_back(RECORD_FILENAME);
292 Record.push_back(entry);
Ted Kremenek2a764102011-12-17 05:26:11 +0000293 Record.push_back(0); // For legacy.
294 Record.push_back(0); // For legacy.
295 StringRef Name(FileName);
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000296 Record.push_back(Name.size());
297 Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_FILENAME), Record, Name);
298
299 return entry;
300}
301
Argyrios Kyrtzidis29f27872011-12-07 05:52:12 +0000302void SDiagsWriter::EmitCharSourceRange(CharSourceRange R,
Ted Kremenek2a764102011-12-17 05:26:11 +0000303 const SourceManager &SM) {
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000304 Record.clear();
305 Record.push_back(RECORD_SOURCE_RANGE);
Argyrios Kyrtzidis29f27872011-12-07 05:52:12 +0000306 AddCharSourceRangeToRecord(R, Record, SM);
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000307 Stream.EmitRecordWithAbbrev(Abbrevs.get(RECORD_SOURCE_RANGE), Record);
308}
309
Ted Kremenek78002122011-10-29 00:12:39 +0000310/// \brief Emits the preamble of the diagnostics file.
311void SDiagsWriter::EmitPreamble() {
Ted Kremenek78002122011-10-29 00:12:39 +0000312 // Emit the file header.
313 Stream.Emit((unsigned)'D', 8);
Ted Kremenek0b69aa82011-11-08 20:27:29 +0000314 Stream.Emit((unsigned)'I', 8);
315 Stream.Emit((unsigned)'A', 8);
316 Stream.Emit((unsigned)'G', 8);
Ted Kremenek069f9c22011-11-05 00:09:53 +0000317
Ted Kremenek78002122011-10-29 00:12:39 +0000318 EmitBlockInfoBlock();
Ted Kremenek0b69aa82011-11-08 20:27:29 +0000319 EmitMetaBlock();
Ted Kremenek78002122011-10-29 00:12:39 +0000320}
321
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000322static void AddSourceLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) {
323 using namespace llvm;
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000324 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // File ID.
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000325 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Line.
326 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Column.
327 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Offset;
328}
Ted Kremenek96dcade2011-11-05 03:34:23 +0000329
330static void AddRangeLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) {
331 AddSourceLocationAbbrev(Abbrev);
332 AddSourceLocationAbbrev(Abbrev);
333}
334
Ted Kremenek78002122011-10-29 00:12:39 +0000335void SDiagsWriter::EmitBlockInfoBlock() {
336 Stream.EnterBlockInfoBlock(3);
Ted Kremenek0b69aa82011-11-08 20:27:29 +0000337
338 using namespace llvm;
339
340 // ==---------------------------------------------------------------------==//
341 // The subsequent records and Abbrevs are for the "Meta" block.
342 // ==---------------------------------------------------------------------==//
343
344 EmitBlockID(BLOCK_META, "Meta", Stream, Record);
345 EmitRecordID(RECORD_VERSION, "Version", Stream, Record);
346 BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
347 Abbrev->Add(BitCodeAbbrevOp(RECORD_VERSION));
348 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
349 Abbrevs.set(RECORD_VERSION, Stream.EmitBlockInfoAbbrev(BLOCK_META, Abbrev));
350
Ted Kremenek78002122011-10-29 00:12:39 +0000351 // ==---------------------------------------------------------------------==//
352 // The subsequent records and Abbrevs are for the "Diagnostic" block.
353 // ==---------------------------------------------------------------------==//
354
Ted Kremenek45d92752011-11-05 00:09:50 +0000355 EmitBlockID(BLOCK_DIAG, "Diag", Stream, Record);
356 EmitRecordID(RECORD_DIAG, "DiagInfo", Stream, Record);
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000357 EmitRecordID(RECORD_SOURCE_RANGE, "SrcRange", Stream, Record);
Ted Kremenek0dbadc42011-11-05 00:10:04 +0000358 EmitRecordID(RECORD_CATEGORY, "CatName", Stream, Record);
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000359 EmitRecordID(RECORD_DIAG_FLAG, "DiagFlag", Stream, Record);
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000360 EmitRecordID(RECORD_FILENAME, "FileName", Stream, Record);
Ted Kremenek96dcade2011-11-05 03:34:23 +0000361 EmitRecordID(RECORD_FIXIT, "FixIt", Stream, Record);
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000362
Ted Kremenek78002122011-10-29 00:12:39 +0000363 // Emit abbreviation for RECORD_DIAG.
Ted Kremenek0b69aa82011-11-08 20:27:29 +0000364 Abbrev = new BitCodeAbbrev();
Ted Kremenek78002122011-10-29 00:12:39 +0000365 Abbrev->Add(BitCodeAbbrevOp(RECORD_DIAG));
Ted Kremenek45d92752011-11-05 00:09:50 +0000366 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Diag level.
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000367 AddSourceLocationAbbrev(Abbrev);
Ted Kremenek45d92752011-11-05 00:09:50 +0000368 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Category.
369 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped Diag ID.
Ted Kremenek78002122011-10-29 00:12:39 +0000370 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
371 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Diagnostc text.
372 Abbrevs.set(RECORD_DIAG, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000373
Ted Kremenek0dbadc42011-11-05 00:10:04 +0000374 // Emit abbrevation for RECORD_CATEGORY.
375 Abbrev = new BitCodeAbbrev();
376 Abbrev->Add(BitCodeAbbrevOp(RECORD_CATEGORY));
377 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Category ID.
378 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8)); // Text size.
379 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Category text.
380 Abbrevs.set(RECORD_CATEGORY, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
381
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000382 // Emit abbrevation for RECORD_SOURCE_RANGE.
383 Abbrev = new BitCodeAbbrev();
384 Abbrev->Add(BitCodeAbbrevOp(RECORD_SOURCE_RANGE));
Ted Kremenek96dcade2011-11-05 03:34:23 +0000385 AddRangeLocationAbbrev(Abbrev);
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000386 Abbrevs.set(RECORD_SOURCE_RANGE,
387 Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000388
389 // Emit the abbreviation for RECORD_DIAG_FLAG.
390 Abbrev = new BitCodeAbbrev();
391 Abbrev->Add(BitCodeAbbrevOp(RECORD_DIAG_FLAG));
392 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped Diag ID.
393 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
394 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Flag name text.
395 Abbrevs.set(RECORD_DIAG_FLAG, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
396 Abbrev));
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000397
398 // Emit the abbreviation for RECORD_FILENAME.
Ted Kremenek78002122011-10-29 00:12:39 +0000399 Abbrev = new BitCodeAbbrev();
Ted Kremenek28eac522011-11-05 00:09:43 +0000400 Abbrev->Add(BitCodeAbbrevOp(RECORD_FILENAME));
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000401 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped file ID.
402 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Size.
403 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Modifcation time.
Ted Kremenek78002122011-10-29 00:12:39 +0000404 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
405 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name text.
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000406 Abbrevs.set(RECORD_FILENAME, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
Ted Kremenek78002122011-10-29 00:12:39 +0000407 Abbrev));
Ted Kremenek96dcade2011-11-05 03:34:23 +0000408
409 // Emit the abbreviation for RECORD_FIXIT.
410 Abbrev = new BitCodeAbbrev();
411 Abbrev->Add(BitCodeAbbrevOp(RECORD_FIXIT));
412 AddRangeLocationAbbrev(Abbrev);
413 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
414 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // FixIt text.
415 Abbrevs.set(RECORD_FIXIT, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
416 Abbrev));
Ted Kremenek78002122011-10-29 00:12:39 +0000417
418 Stream.ExitBlock();
419}
420
Ted Kremenek0b69aa82011-11-08 20:27:29 +0000421void SDiagsWriter::EmitMetaBlock() {
422 Stream.EnterSubblock(BLOCK_META, 3);
423 Record.clear();
424 Record.push_back(RECORD_VERSION);
425 Record.push_back(Version);
426 Stream.EmitRecordWithAbbrev(Abbrevs.get(RECORD_VERSION), Record);
427 Stream.ExitBlock();
428}
429
Ted Kremenek2a764102011-12-17 05:26:11 +0000430unsigned SDiagsWriter::getEmitCategory(unsigned int category) {
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000431 if (Categories.count(category))
432 return category;
433
434 Categories.insert(category);
Ted Kremenek0dbadc42011-11-05 00:10:04 +0000435
436 // We use a local version of 'Record' so that we can be generating
437 // another record when we lazily generate one for the category entry.
438 RecordData Record;
439 Record.push_back(RECORD_CATEGORY);
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000440 Record.push_back(category);
441 StringRef catName = DiagnosticIDs::getCategoryNameFromID(category);
Ted Kremenek0dbadc42011-11-05 00:10:04 +0000442 Record.push_back(catName.size());
443 Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_CATEGORY), Record, catName);
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000444
445 return category;
446}
447
448unsigned SDiagsWriter::getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
Ted Kremenek2a764102011-12-17 05:26:11 +0000449 unsigned DiagID) {
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000450 if (DiagLevel == DiagnosticsEngine::Note)
451 return 0; // No flag for notes.
452
Ted Kremenek2a764102011-12-17 05:26:11 +0000453 StringRef FlagName = DiagnosticIDs::getWarningOptionForDiag(DiagID);
Ted Kremenek3baf63d2011-11-05 00:10:07 +0000454 if (FlagName.empty())
455 return 0;
456
457 // Here we assume that FlagName points to static data whose pointer
458 // value is fixed. This allows us to unique by diagnostic groups.
459 const void *data = FlagName.data();
460 std::pair<unsigned, StringRef> &entry = DiagFlags[data];
461 if (entry.first == 0) {
462 entry.first = DiagFlags.size();
463 entry.second = FlagName;
464
465 // Lazily emit the string in a separate record.
466 RecordData Record;
467 Record.push_back(RECORD_DIAG_FLAG);
468 Record.push_back(entry.first);
469 Record.push_back(FlagName.size());
470 Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG_FLAG),
471 Record, FlagName);
472 }
473
474 return entry.first;
Ted Kremenek0dbadc42011-11-05 00:10:04 +0000475}
476
Ted Kremenek78002122011-10-29 00:12:39 +0000477void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
478 const Diagnostic &Info) {
Ted Kremenek59b61612011-11-05 00:09:47 +0000479 if (DiagLevel != DiagnosticsEngine::Note) {
480 if (inNonNoteDiagnostic) {
481 // We have encountered a non-note diagnostic. Finish up the previous
482 // diagnostic block before starting a new one.
483 Stream.ExitBlock();
484 }
485 inNonNoteDiagnostic = true;
486 }
Ted Kremenek96dcade2011-11-05 03:34:23 +0000487
Ted Kremenek2a764102011-12-17 05:26:11 +0000488 // Compute the diagnostic text.
489 diagBuf.clear();
490 Info.FormatDiagnostic(diagBuf);
491
492 SourceManager &SM = Info.getSourceManager();
493 SDiagsRenderer Renderer(*this, Record, SM, *LangOpts, DiagOpts);
494 Renderer.emitDiagnostic(Info.getLocation(), DiagLevel,
495 diagBuf.str(),
496 Info.getRanges(),
497 llvm::makeArrayRef(Info.getFixItHints(),
498 Info.getNumFixItHints()),
499 &Info);
500}
501
502void
503SDiagsRenderer::emitDiagnosticMessage(SourceLocation Loc,
504 PresumedLoc PLoc,
505 DiagnosticsEngine::Level Level,
506 StringRef Message,
507 ArrayRef<clang::CharSourceRange> Ranges,
508 const Diagnostic *Info) {
509 // Emit the RECORD_DIAG record.
510 Writer.Record.clear();
511 Writer.Record.push_back(RECORD_DIAG);
512 Writer.Record.push_back(Level);
513 Writer.AddLocToRecord(Loc, SM, PLoc, Record);
514
515 if (Info) {
516 // Emit the category string lazily and get the category ID.
517 unsigned DiagID = DiagnosticIDs::getCategoryNumberForDiag(Info->getID());
518 Writer.Record.push_back(Writer.getEmitCategory(DiagID));
519 // Emit the diagnostic flag string lazily and get the mapped ID.
520 Writer.Record.push_back(Writer.getEmitDiagnosticFlag(Level, Info->getID()));
521 }
522 else {
523 Writer.Record.push_back(Writer.getEmitCategory());
524 Writer.Record.push_back(Writer.getEmitDiagnosticFlag(Level));
525 }
526
527 Writer.Record.push_back(Message.size());
528 Writer.Stream.EmitRecordWithBlob(Writer.Abbrevs.get(RECORD_DIAG),
529 Writer.Record, Message);
530}
531
532void SDiagsRenderer::beginDiagnostic(const Diagnostic *Info,
533 DiagnosticsEngine::Level Level) {
534 Writer.Stream.EnterSubblock(BLOCK_DIAG, 4);
535}
536
537void SDiagsRenderer::endDiagnostic(const Diagnostic *Info,
538 DiagnosticsEngine::Level Level) {
539 if (Info && Level != DiagnosticsEngine::Note)
540 return;
541 Writer.Stream.ExitBlock();
542}
543
544void SDiagsRenderer::emitCodeContext(SourceLocation Loc,
545 DiagnosticsEngine::Level Level,
546 SmallVectorImpl<CharSourceRange> &Ranges,
547 ArrayRef<FixItHint> Hints) {
Ted Kremenek96dcade2011-11-05 03:34:23 +0000548 // Emit Source Ranges.
Ted Kremenek2a20b4f2011-11-05 00:10:01 +0000549 for (ArrayRef<CharSourceRange>::iterator it=Ranges.begin(), ei=Ranges.end();
550 it != ei; ++it) {
Argyrios Kyrtzidis29f27872011-12-07 05:52:12 +0000551 if (it->isValid())
Ted Kremenek2a764102011-12-17 05:26:11 +0000552 Writer.EmitCharSourceRange(*it, SM);
Ted Kremenek96dcade2011-11-05 03:34:23 +0000553 }
Ted Kremenek59b61612011-11-05 00:09:47 +0000554
Ted Kremenek2a764102011-12-17 05:26:11 +0000555 // Emit FixIts.
556 for (ArrayRef<FixItHint>::iterator it = Hints.begin(), et = Hints.end();
557 it != et; ++it) {
558 const FixItHint &fix = *it;
559 if (fix.isNull())
560 continue;
561 Writer.Record.clear();
562 Writer.Record.push_back(RECORD_FIXIT);
563 Writer.AddCharSourceRangeToRecord(fix.RemoveRange, Record, SM);
564 Writer.Record.push_back(fix.CodeToInsert.size());
565 Writer.Stream.EmitRecordWithBlob(Writer.Abbrevs.get(RECORD_FIXIT), Record,
566 fix.CodeToInsert);
Ted Kremenek59b61612011-11-05 00:09:47 +0000567 }
Ted Kremenek78002122011-10-29 00:12:39 +0000568}
569
Ted Kremenek2a764102011-12-17 05:26:11 +0000570void SDiagsRenderer::emitNote(SourceLocation Loc, StringRef Message) {
571 Writer.Stream.EnterSubblock(BLOCK_DIAG, 4);
572 RecordData Record;
573 Record.push_back(RECORD_DIAG);
574 Record.push_back(DiagnosticsEngine::Note);
575 Writer.AddLocToRecord(Loc, Record, SM);
576 Record.push_back(Writer.getEmitCategory());
577 Record.push_back(Writer.getEmitDiagnosticFlag(DiagnosticsEngine::Note));
578 Record.push_back(Message.size());
579 Writer.Stream.EmitRecordWithBlob(Writer.Abbrevs.get(RECORD_DIAG),
580 Record, Message);
581 Writer.Stream.ExitBlock();
582}
583
584void SDiagsRenderer::emitIncludeLocation(SourceLocation Loc,
585 PresumedLoc PLoc) {
586 // Generate a note indicating the include location.
587 llvm::SmallString<200> MessageStorage;
588 llvm::raw_svector_ostream Message(MessageStorage);
589 Message << "in file included from " << PLoc.getFilename() << ':'
590 << PLoc.getLine() << ":";
591 emitNote(Loc, Message.str());
592}
593
594void SDiagsRenderer::emitBasicNote(StringRef Message) {
595 emitNote(SourceLocation(), Message);
596}
597
Argyrios Kyrtzidis29f27872011-12-07 05:52:12 +0000598void SDiagsWriter::finish() {
Ted Kremenek59b61612011-11-05 00:09:47 +0000599 if (inNonNoteDiagnostic) {
600 // Finish off any diagnostics we were in the process of emitting.
601 Stream.ExitBlock();
602 inNonNoteDiagnostic = false;
603 }
Ted Kremenek0d34e6e2011-11-05 00:10:11 +0000604
Ted Kremenek78002122011-10-29 00:12:39 +0000605 // Write the generated bitstream to "Out".
606 OS->write((char *)&Buffer.front(), Buffer.size());
607 OS->flush();
608
609 OS.reset(0);
610}
611