SerializedDiagnosticPrinter.cpp revision 239462
1139749Simp//===--- SerializedDiagnosticPrinter.cpp - Serializer for diagnostics -----===//
2119815Smarcel//
3119815Smarcel//                     The LLVM Compiler Infrastructure
4119815Smarcel//
5119815Smarcel// This file is distributed under the University of Illinois Open Source
6119815Smarcel// License. See LICENSE.TXT for details.
7119815Smarcel//
8119815Smarcel//===----------------------------------------------------------------------===//
9119815Smarcel
10119815Smarcel#include <vector>
11119815Smarcel#include "llvm/Support/raw_ostream.h"
12119815Smarcel#include "llvm/ADT/StringRef.h"
13119815Smarcel#include "llvm/ADT/SmallString.h"
14119815Smarcel#include "llvm/ADT/DenseSet.h"
15119815Smarcel#include "clang/Basic/SourceManager.h"
16119815Smarcel#include "clang/Basic/FileManager.h"
17119815Smarcel#include "clang/Basic/Diagnostic.h"
18119815Smarcel#include "clang/Basic/Version.h"
19119815Smarcel#include "clang/Lex/Lexer.h"
20119815Smarcel#include "clang/Frontend/SerializedDiagnosticPrinter.h"
21119815Smarcel#include "clang/Frontend/DiagnosticRenderer.h"
22119815Smarcel
23119815Smarcelusing namespace clang;
24119815Smarcelusing namespace clang::serialized_diags;
25119815Smarcel
26119815Smarcelnamespace {
27119815Smarcel
28119815Smarcelclass AbbreviationMap {
29119815Smarcel  llvm::DenseMap<unsigned, unsigned> Abbrevs;
30119815Smarcelpublic:
31119815Smarcel  AbbreviationMap() {}
32119815Smarcel
33119815Smarcel  void set(unsigned recordID, unsigned abbrevID) {
34119815Smarcel    assert(Abbrevs.find(recordID) == Abbrevs.end()
35119815Smarcel           && "Abbreviation already set.");
36119815Smarcel    Abbrevs[recordID] = abbrevID;
37119815Smarcel  }
38119815Smarcel
39119815Smarcel  unsigned get(unsigned recordID) {
40137956Smarcel    assert(Abbrevs.find(recordID) != Abbrevs.end() &&
41137956Smarcel           "Abbreviation not set.");
42119815Smarcel    return Abbrevs[recordID];
43119815Smarcel  }
44119815Smarcel};
45119815Smarcel
46160717Smarceltypedef llvm::SmallVector<uint64_t, 64> RecordData;
47160717Smarceltypedef llvm::SmallVectorImpl<uint64_t> RecordDataImpl;
48160717Smarcel
49160717Smarcelclass SDiagsWriter;
50160717Smarcel
51160717Smarcelclass SDiagsRenderer : public DiagnosticNoteRenderer {
52160717Smarcel  SDiagsWriter &Writer;
53119815Smarcel  RecordData &Record;
54119815Smarcelpublic:
55119815Smarcel  SDiagsRenderer(SDiagsWriter &Writer, RecordData &Record,
56119815Smarcel                 const LangOptions &LangOpts,
57119815Smarcel                 const DiagnosticOptions &DiagOpts)
58119815Smarcel    : DiagnosticNoteRenderer(LangOpts, DiagOpts),
59119815Smarcel      Writer(Writer), Record(Record){}
60119815Smarcel
61119815Smarcel  virtual ~SDiagsRenderer() {}
62119815Smarcel
63119815Smarcelprotected:
64119815Smarcel  virtual void emitDiagnosticMessage(SourceLocation Loc,
65119815Smarcel                                     PresumedLoc PLoc,
66119815Smarcel                                     DiagnosticsEngine::Level Level,
67119815Smarcel                                     StringRef Message,
68119815Smarcel                                     ArrayRef<CharSourceRange> Ranges,
69119815Smarcel                                     const SourceManager *SM,
70119815Smarcel                                     DiagOrStoredDiag D);
71119815Smarcel
72119815Smarcel  virtual void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
73119815Smarcel                                 DiagnosticsEngine::Level Level,
74119815Smarcel                                 ArrayRef<CharSourceRange> Ranges,
75119815Smarcel                                 const SourceManager &SM) {}
76119815Smarcel
77119815Smarcel  void emitNote(SourceLocation Loc, StringRef Message, const SourceManager *SM);
78158504Smarcel
79119815Smarcel  virtual void emitCodeContext(SourceLocation Loc,
80119815Smarcel                               DiagnosticsEngine::Level Level,
81157451Smarcel                               SmallVectorImpl<CharSourceRange>& Ranges,
82158504Smarcel                               ArrayRef<FixItHint> Hints,
83119815Smarcel                               const SourceManager &SM);
84119815Smarcel
85119815Smarcel  virtual void beginDiagnostic(DiagOrStoredDiag D,
86119815Smarcel                               DiagnosticsEngine::Level Level);
87119815Smarcel  virtual void endDiagnostic(DiagOrStoredDiag D,
88119815Smarcel                             DiagnosticsEngine::Level Level);
89119815Smarcel};
90158504Smarcel
91119815Smarcelclass SDiagsWriter : public DiagnosticConsumer {
92119815Smarcel  friend class SDiagsRenderer;
93119815Smarcelpublic:
94119815Smarcel  explicit SDiagsWriter(llvm::raw_ostream *os, const DiagnosticOptions &diags)
95119815Smarcel    : LangOpts(0), DiagOpts(diags),
96119815Smarcel      Stream(Buffer), OS(os), inNonNoteDiagnostic(false)
97119815Smarcel  {
98119815Smarcel    EmitPreamble();
99119815Smarcel  }
100119815Smarcel
101119815Smarcel  ~SDiagsWriter() {}
102119815Smarcel
103119815Smarcel  void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
104119815Smarcel                        const Diagnostic &Info);
105119815Smarcel
106119815Smarcel  void BeginSourceFile(const LangOptions &LO,
107119815Smarcel                       const Preprocessor *PP) {
108119815Smarcel    LangOpts = &LO;
109119815Smarcel  }
110119815Smarcel
111119815Smarcel  virtual void finish();
112119815Smarcel
113119815Smarcel  DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const {
114119815Smarcel    // It makes no sense to clone this.
115119815Smarcel    return 0;
116119815Smarcel  }
117119815Smarcel
118119815Smarcelprivate:
119119815Smarcel  /// \brief Emit the preamble for the serialized diagnostics.
120119815Smarcel  void EmitPreamble();
121119815Smarcel
122119815Smarcel  /// \brief Emit the BLOCKINFO block.
123119815Smarcel  void EmitBlockInfoBlock();
124119815Smarcel
125119815Smarcel  /// \brief Emit the META data block.
126119815Smarcel  void EmitMetaBlock();
127119815Smarcel
128119815Smarcel  /// \brief Emit a record for a CharSourceRange.
129158504Smarcel  void EmitCharSourceRange(CharSourceRange R, const SourceManager &SM);
130119815Smarcel
131158504Smarcel  /// \brief Emit the string information for the category.
132158504Smarcel  unsigned getEmitCategory(unsigned category = 0);
133158504Smarcel
134160717Smarcel  /// \brief Emit the string information for diagnostic flags.
135158504Smarcel  unsigned getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
136158504Smarcel                                 unsigned DiagID = 0);
137158504Smarcel
138119815Smarcel  /// \brief Emit (lazily) the file string and retrieved the file identifier.
139119815Smarcel  unsigned getEmitFile(const char *Filename);
140119815Smarcel
141119815Smarcel  /// \brief Add SourceLocation information the specified record.
142119815Smarcel  void AddLocToRecord(SourceLocation Loc, const SourceManager *SM,
143119815Smarcel                      PresumedLoc PLoc, RecordDataImpl &Record,
144119815Smarcel                      unsigned TokSize = 0);
145119815Smarcel
146119815Smarcel  /// \brief Add SourceLocation information the specified record.
147119815Smarcel  void AddLocToRecord(SourceLocation Loc, RecordDataImpl &Record,
148119815Smarcel                      const SourceManager *SM,
149119815Smarcel                      unsigned TokSize = 0) {
150160717Smarcel    AddLocToRecord(Loc, SM, SM ? SM->getPresumedLoc(Loc) : PresumedLoc(),
151158504Smarcel                   Record, TokSize);
152119815Smarcel  }
153119815Smarcel
154119815Smarcel  /// \brief Add CharSourceRange information the specified record.
155119815Smarcel  void AddCharSourceRangeToRecord(CharSourceRange R, RecordDataImpl &Record,
156119815Smarcel                                  const SourceManager &SM);
157119815Smarcel
158119815Smarcel  /// \brief The version of the diagnostics file.
159119815Smarcel  enum { Version = 1 };
160141032Smarcel
161119815Smarcel  const LangOptions *LangOpts;
162119815Smarcel  const DiagnosticOptions &DiagOpts;
163119815Smarcel
164119815Smarcel  /// \brief The byte buffer for the serialized content.
165119815Smarcel  SmallString<1024> Buffer;
166120452Smarcel
167120452Smarcel  /// \brief The BitStreamWriter for the serialized diagnostics.
168141032Smarcel  llvm::BitstreamWriter Stream;
169120452Smarcel
170120452Smarcel  /// \brief The name of the diagnostics file.
171141032Smarcel  OwningPtr<llvm::raw_ostream> OS;
172120452Smarcel
173120452Smarcel  /// \brief The set of constructed record abbreviations.
174119815Smarcel  AbbreviationMap Abbrevs;
175158504Smarcel
176119815Smarcel  /// \brief A utility buffer for constructing record content.
177160717Smarcel  RecordData Record;
178119815Smarcel
179119815Smarcel  /// \brief A text buffer for rendering diagnostic text.
180119815Smarcel  SmallString<256> diagBuf;
181119815Smarcel
182119815Smarcel  /// \brief The collection of diagnostic categories used.
183119815Smarcel  llvm::DenseSet<unsigned> Categories;
184119815Smarcel
185119815Smarcel  /// \brief The collection of files used.
186119815Smarcel  llvm::DenseMap<const char *, unsigned> Files;
187119815Smarcel
188119815Smarcel  typedef llvm::DenseMap<const void *, std::pair<unsigned, llvm::StringRef> >
189119815Smarcel          DiagFlagsTy;
190119815Smarcel
191119815Smarcel  /// \brief Map for uniquing strings.
192119815Smarcel  DiagFlagsTy DiagFlags;
193119815Smarcel
194119815Smarcel  /// \brief Flag indicating whether or not we are in the process of
195166100Smarius  /// emitting a non-note diagnostic.
196157380Smarcel  bool inNonNoteDiagnostic;
197119815Smarcel};
198168281Smarcel} // end anonymous namespace
199119815Smarcel
200119815Smarcelnamespace clang {
201119815Smarcelnamespace serialized_diags {
202119815SmarcelDiagnosticConsumer *create(llvm::raw_ostream *OS,
203166100Smarius                           const DiagnosticOptions &diags) {
204119815Smarcel  return new SDiagsWriter(OS, diags);
205119815Smarcel}
206119815Smarcel} // end namespace serialized_diags
207119815Smarcel} // end namespace clang
208119815Smarcel
209119815Smarcel//===----------------------------------------------------------------------===//
210119815Smarcel// Serialization methods.
211119815Smarcel//===----------------------------------------------------------------------===//
212119815Smarcel
213119815Smarcel/// \brief Emits a block ID in the BLOCKINFO block.
214119815Smarcelstatic void EmitBlockID(unsigned ID, const char *Name,
215119815Smarcel                        llvm::BitstreamWriter &Stream,
216119815Smarcel                        RecordDataImpl &Record) {
217119815Smarcel  Record.clear();
218119815Smarcel  Record.push_back(ID);
219119815Smarcel  Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
220119815Smarcel
221119815Smarcel  // Emit the block name if present.
222119815Smarcel  if (Name == 0 || Name[0] == 0)
223119815Smarcel    return;
224119815Smarcel
225119815Smarcel  Record.clear();
226119815Smarcel
227119815Smarcel  while (*Name)
228119815Smarcel    Record.push_back(*Name++);
229119815Smarcel
230119815Smarcel  Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record);
231145603Smarcel}
232119815Smarcel
233119815Smarcel/// \brief Emits a record ID in the BLOCKINFO block.
234119815Smarcelstatic void EmitRecordID(unsigned ID, const char *Name,
235119815Smarcel                         llvm::BitstreamWriter &Stream,
236119815Smarcel                         RecordDataImpl &Record){
237119815Smarcel  Record.clear();
238166100Smarius  Record.push_back(ID);
239119815Smarcel
240119815Smarcel  while (*Name)
241166100Smarius    Record.push_back(*Name++);
242119815Smarcel
243119815Smarcel  Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
244119815Smarcel}
245157380Smarcel
246119815Smarcelvoid SDiagsWriter::AddLocToRecord(SourceLocation Loc,
247157380Smarcel                                  const SourceManager *SM,
248119815Smarcel                                  PresumedLoc PLoc,
249157380Smarcel                                  RecordDataImpl &Record,
250157380Smarcel                                  unsigned TokSize) {
251157380Smarcel  if (PLoc.isInvalid()) {
252157380Smarcel    // Emit a "sentinel" location.
253157380Smarcel    Record.push_back((unsigned)0); // File.
254157380Smarcel    Record.push_back((unsigned)0); // Line.
255157380Smarcel    Record.push_back((unsigned)0); // Column.
256157380Smarcel    Record.push_back((unsigned)0); // Offset.
257157380Smarcel    return;
258157380Smarcel  }
259157380Smarcel
260157380Smarcel  Record.push_back(getEmitFile(PLoc.getFilename()));
261157380Smarcel  Record.push_back(PLoc.getLine());
262119815Smarcel  Record.push_back(PLoc.getColumn()+TokSize);
263119815Smarcel  Record.push_back(SM->getFileOffset(Loc));
264119815Smarcel}
265119815Smarcel
266119815Smarcelvoid SDiagsWriter::AddCharSourceRangeToRecord(CharSourceRange Range,
267119815Smarcel                                              RecordDataImpl &Record,
268119815Smarcel                                              const SourceManager &SM) {
269119815Smarcel  AddLocToRecord(Range.getBegin(), Record, &SM);
270128911Smarcel  unsigned TokSize = 0;
271119815Smarcel  if (Range.isTokenRange())
272119815Smarcel    TokSize = Lexer::MeasureTokenLength(Range.getEnd(),
273119815Smarcel                                        SM, *LangOpts);
274119815Smarcel
275119815Smarcel  AddLocToRecord(Range.getEnd(), Record, &SM, TokSize);
276119815Smarcel}
277119815Smarcel
278119815Smarcelunsigned SDiagsWriter::getEmitFile(const char *FileName){
279119815Smarcel  if (!FileName)
280119815Smarcel    return 0;
281119815Smarcel
282119815Smarcel  unsigned &entry = Files[FileName];
283119815Smarcel  if (entry)
284262649Simp    return entry;
285262649Simp
286119815Smarcel  // Lazily generate the record for the file.
287119815Smarcel  entry = Files.size();
288119815Smarcel  RecordData Record;
289119815Smarcel  Record.push_back(RECORD_FILENAME);
290119815Smarcel  Record.push_back(entry);
291119815Smarcel  Record.push_back(0); // For legacy.
292119815Smarcel  Record.push_back(0); // For legacy.
293119815Smarcel  StringRef Name(FileName);
294119815Smarcel  Record.push_back(Name.size());
295119815Smarcel  Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_FILENAME), Record, Name);
296119815Smarcel
297119815Smarcel  return entry;
298119815Smarcel}
299262649Simp
300262649Simpvoid SDiagsWriter::EmitCharSourceRange(CharSourceRange R,
301119815Smarcel                                       const SourceManager &SM) {
302119815Smarcel  Record.clear();
303119815Smarcel  Record.push_back(RECORD_SOURCE_RANGE);
304119815Smarcel  AddCharSourceRangeToRecord(R, Record, SM);
305168281Smarcel  Stream.EmitRecordWithAbbrev(Abbrevs.get(RECORD_SOURCE_RANGE), Record);
306119815Smarcel}
307119815Smarcel
308168281Smarcel/// \brief Emits the preamble of the diagnostics file.
309119815Smarcelvoid SDiagsWriter::EmitPreamble() {
310119815Smarcel  // Emit the file header.
311119815Smarcel  Stream.Emit((unsigned)'D', 8);
312119815Smarcel  Stream.Emit((unsigned)'I', 8);
313119815Smarcel  Stream.Emit((unsigned)'A', 8);
314119815Smarcel  Stream.Emit((unsigned)'G', 8);
315119815Smarcel
316119815Smarcel  EmitBlockInfoBlock();
317119815Smarcel  EmitMetaBlock();
318119815Smarcel}
319119815Smarcel
320119815Smarcelstatic void AddSourceLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) {
321119815Smarcel  using namespace llvm;
322119815Smarcel  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // File ID.
323119815Smarcel  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Line.
324119815Smarcel  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Column.
325119815Smarcel  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Offset;
326119815Smarcel}
327119815Smarcel
328119815Smarcelstatic void AddRangeLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) {
329119815Smarcel  AddSourceLocationAbbrev(Abbrev);
330119815Smarcel  AddSourceLocationAbbrev(Abbrev);
331119815Smarcel}
332119815Smarcel
333119815Smarcelvoid SDiagsWriter::EmitBlockInfoBlock() {
334119815Smarcel  Stream.EnterBlockInfoBlock(3);
335119815Smarcel
336119815Smarcel  using namespace llvm;
337155971Smarcel
338119815Smarcel  // ==---------------------------------------------------------------------==//
339119815Smarcel  // The subsequent records and Abbrevs are for the "Meta" block.
340119815Smarcel  // ==---------------------------------------------------------------------==//
341119815Smarcel
342119815Smarcel  EmitBlockID(BLOCK_META, "Meta", Stream, Record);
343141032Smarcel  EmitRecordID(RECORD_VERSION, "Version", Stream, Record);
344119815Smarcel  BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
345119815Smarcel  Abbrev->Add(BitCodeAbbrevOp(RECORD_VERSION));
346119815Smarcel  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
347119815Smarcel  Abbrevs.set(RECORD_VERSION, Stream.EmitBlockInfoAbbrev(BLOCK_META, Abbrev));
348119815Smarcel
349141032Smarcel  // ==---------------------------------------------------------------------==//
350141032Smarcel  // The subsequent records and Abbrevs are for the "Diagnostic" block.
351119815Smarcel  // ==---------------------------------------------------------------------==//
352119815Smarcel
353119815Smarcel  EmitBlockID(BLOCK_DIAG, "Diag", Stream, Record);
354119815Smarcel  EmitRecordID(RECORD_DIAG, "DiagInfo", Stream, Record);
355119815Smarcel  EmitRecordID(RECORD_SOURCE_RANGE, "SrcRange", Stream, Record);
356119815Smarcel  EmitRecordID(RECORD_CATEGORY, "CatName", Stream, Record);
357119815Smarcel  EmitRecordID(RECORD_DIAG_FLAG, "DiagFlag", Stream, Record);
358119815Smarcel  EmitRecordID(RECORD_FILENAME, "FileName", Stream, Record);
359119815Smarcel  EmitRecordID(RECORD_FIXIT, "FixIt", Stream, Record);
360119815Smarcel
361119815Smarcel  // Emit abbreviation for RECORD_DIAG.
362119815Smarcel  Abbrev = new BitCodeAbbrev();
363119815Smarcel  Abbrev->Add(BitCodeAbbrevOp(RECORD_DIAG));
364119815Smarcel  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3));  // Diag level.
365119815Smarcel  AddSourceLocationAbbrev(Abbrev);
366119815Smarcel  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Category.
367119815Smarcel  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped Diag ID.
368119815Smarcel  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
369119815Smarcel  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Diagnostc text.
370119815Smarcel  Abbrevs.set(RECORD_DIAG, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
371119815Smarcel
372119815Smarcel  // Emit abbrevation for RECORD_CATEGORY.
373119815Smarcel  Abbrev = new BitCodeAbbrev();
374119815Smarcel  Abbrev->Add(BitCodeAbbrevOp(RECORD_CATEGORY));
375119815Smarcel  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Category ID.
376119815Smarcel  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8));  // Text size.
377157300Smarcel  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));      // Category text.
378120143Smarcel  Abbrevs.set(RECORD_CATEGORY, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
379157300Smarcel
380131043Sphk  // Emit abbrevation for RECORD_SOURCE_RANGE.
381131043Sphk  Abbrev = new BitCodeAbbrev();
382141032Smarcel  Abbrev->Add(BitCodeAbbrevOp(RECORD_SOURCE_RANGE));
383155973Smarcel  AddRangeLocationAbbrev(Abbrev);
384119815Smarcel  Abbrevs.set(RECORD_SOURCE_RANGE,
385119815Smarcel              Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
386119815Smarcel
387119815Smarcel  // Emit the abbreviation for RECORD_DIAG_FLAG.
388119815Smarcel  Abbrev = new BitCodeAbbrev();
389119815Smarcel  Abbrev->Add(BitCodeAbbrevOp(RECORD_DIAG_FLAG));
390119815Smarcel  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped Diag ID.
391119815Smarcel  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
392119815Smarcel  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Flag name text.
393160716Smarcel  Abbrevs.set(RECORD_DIAG_FLAG, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
394119815Smarcel                                                           Abbrev));
395119815Smarcel
396120143Smarcel  // Emit the abbreviation for RECORD_FILENAME.
397157300Smarcel  Abbrev = new BitCodeAbbrev();
398119815Smarcel  Abbrev->Add(BitCodeAbbrevOp(RECORD_FILENAME));
399119815Smarcel  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped file ID.
400119815Smarcel  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Size.
401119815Smarcel  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Modifcation time.
402119815Smarcel  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
403119815Smarcel  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name text.
404119815Smarcel  Abbrevs.set(RECORD_FILENAME, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
405119815Smarcel                                                          Abbrev));
406119815Smarcel
407160716Smarcel  // Emit the abbreviation for RECORD_FIXIT.
408160716Smarcel  Abbrev = new BitCodeAbbrev();
409160716Smarcel  Abbrev->Add(BitCodeAbbrevOp(RECORD_FIXIT));
410160716Smarcel  AddRangeLocationAbbrev(Abbrev);
411160716Smarcel  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
412160716Smarcel  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));      // FixIt text.
413119815Smarcel  Abbrevs.set(RECORD_FIXIT, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
414120143Smarcel                                                       Abbrev));
415120143Smarcel
416119815Smarcel  Stream.ExitBlock();
417157300Smarcel}
418120143Smarcel
419119815Smarcelvoid SDiagsWriter::EmitMetaBlock() {
420119815Smarcel  Stream.EnterSubblock(BLOCK_META, 3);
421119815Smarcel  Record.clear();
422119815Smarcel  Record.push_back(RECORD_VERSION);
423119815Smarcel  Record.push_back(Version);
424128911Smarcel  Stream.EmitRecordWithAbbrev(Abbrevs.get(RECORD_VERSION), Record);
425119815Smarcel  Stream.ExitBlock();
426119815Smarcel}
427119815Smarcel
428141032Smarcelunsigned SDiagsWriter::getEmitCategory(unsigned int category) {
429119815Smarcel  if (Categories.count(category))
430119815Smarcel    return category;
431119815Smarcel
432141032Smarcel  Categories.insert(category);
433157300Smarcel
434141032Smarcel  // We use a local version of 'Record' so that we can be generating
435141032Smarcel  // another record when we lazily generate one for the category entry.
436141032Smarcel  RecordData Record;
437141032Smarcel  Record.push_back(RECORD_CATEGORY);
438141032Smarcel  Record.push_back(category);
439141032Smarcel  StringRef catName = DiagnosticIDs::getCategoryNameFromID(category);
440141032Smarcel  Record.push_back(catName.size());
441141032Smarcel  Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_CATEGORY), Record, catName);
442141032Smarcel
443141032Smarcel  return category;
444141032Smarcel}
445141032Smarcel
446141032Smarcelunsigned SDiagsWriter::getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
447141032Smarcel                                             unsigned DiagID) {
448141032Smarcel  if (DiagLevel == DiagnosticsEngine::Note)
449141032Smarcel    return 0; // No flag for notes.
450119815Smarcel
451141032Smarcel  StringRef FlagName = DiagnosticIDs::getWarningOptionForDiag(DiagID);
452141032Smarcel  if (FlagName.empty())
453155971Smarcel    return 0;
454141032Smarcel
455141032Smarcel  // Here we assume that FlagName points to static data whose pointer
456119815Smarcel  // value is fixed.  This allows us to unique by diagnostic groups.
457141032Smarcel  const void *data = FlagName.data();
458141032Smarcel  std::pair<unsigned, StringRef> &entry = DiagFlags[data];
459155971Smarcel  if (entry.first == 0) {
460155971Smarcel    entry.first = DiagFlags.size();
461141032Smarcel    entry.second = FlagName;
462119815Smarcel
463141032Smarcel    // Lazily emit the string in a separate record.
464141032Smarcel    RecordData Record;
465141032Smarcel    Record.push_back(RECORD_DIAG_FLAG);
466141032Smarcel    Record.push_back(entry.first);
467141032Smarcel    Record.push_back(FlagName.size());
468141032Smarcel    Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG_FLAG),
469155971Smarcel                              Record, FlagName);
470141032Smarcel  }
471141032Smarcel
472141032Smarcel  return entry.first;
473141032Smarcel}
474155973Smarcel
475155971Smarcelvoid SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
476141032Smarcel                                    const Diagnostic &Info) {
477141032Smarcel  if (DiagLevel != DiagnosticsEngine::Note) {
478141032Smarcel    if (inNonNoteDiagnostic) {
479141032Smarcel      // We have encountered a non-note diagnostic.  Finish up the previous
480155971Smarcel      // diagnostic block before starting a new one.
481141032Smarcel      Stream.ExitBlock();
482119815Smarcel    }
483141032Smarcel    inNonNoteDiagnostic = true;
484141032Smarcel  }
485141032Smarcel
486141032Smarcel  // Compute the diagnostic text.
487141032Smarcel  diagBuf.clear();
488141032Smarcel  Info.FormatDiagnostic(diagBuf);
489157300Smarcel
490141032Smarcel  const SourceManager *
491119815Smarcel    SM = Info.hasSourceManager() ? &Info.getSourceManager() : 0;
492119815Smarcel  SDiagsRenderer Renderer(*this, Record, *LangOpts, DiagOpts);
493119815Smarcel  Renderer.emitDiagnostic(Info.getLocation(), DiagLevel,
494119815Smarcel                          diagBuf.str(),
495119815Smarcel                          Info.getRanges(),
496119815Smarcel                          llvm::makeArrayRef(Info.getFixItHints(),
497119815Smarcel                                             Info.getNumFixItHints()),
498119815Smarcel                          SM,
499119815Smarcel                          &Info);
500119815Smarcel}
501157300Smarcel
502119815Smarcelvoid
503119815SmarcelSDiagsRenderer::emitDiagnosticMessage(SourceLocation Loc,
504157300Smarcel                                      PresumedLoc PLoc,
505119815Smarcel                                      DiagnosticsEngine::Level Level,
506119815Smarcel                                      StringRef Message,
507119815Smarcel                                      ArrayRef<clang::CharSourceRange> Ranges,
508119815Smarcel                                      const SourceManager *SM,
509119815Smarcel                                      DiagOrStoredDiag D) {
510119815Smarcel  // Emit the RECORD_DIAG record.
511119815Smarcel  Writer.Record.clear();
512119815Smarcel  Writer.Record.push_back(RECORD_DIAG);
513120452Smarcel  Writer.Record.push_back(Level);
514119815Smarcel  Writer.AddLocToRecord(Loc, SM, PLoc, Record);
515119815Smarcel
516119815Smarcel  if (const Diagnostic *Info = D.dyn_cast<const Diagnostic*>()) {
517119815Smarcel    // Emit the category string lazily and get the category ID.
518119815Smarcel    unsigned DiagID = DiagnosticIDs::getCategoryNumberForDiag(Info->getID());
519248965Sian    Writer.Record.push_back(Writer.getEmitCategory(DiagID));
520248965Sian    // Emit the diagnostic flag string lazily and get the mapped ID.
521248965Sian    Writer.Record.push_back(Writer.getEmitDiagnosticFlag(Level, Info->getID()));
522120452Smarcel  }
523119815Smarcel  else {
524120452Smarcel    Writer.Record.push_back(Writer.getEmitCategory());
525119815Smarcel    Writer.Record.push_back(Writer.getEmitDiagnosticFlag(Level));
526119815Smarcel  }
527119815Smarcel
528119815Smarcel  Writer.Record.push_back(Message.size());
529119815Smarcel  Writer.Stream.EmitRecordWithBlob(Writer.Abbrevs.get(RECORD_DIAG),
530119815Smarcel                                   Writer.Record, Message);
531119815Smarcel}
532119815Smarcel
533119815Smarcelvoid SDiagsRenderer::beginDiagnostic(DiagOrStoredDiag D,
534119815Smarcel                                     DiagnosticsEngine::Level Level) {
535119815Smarcel  Writer.Stream.EnterSubblock(BLOCK_DIAG, 4);
536119815Smarcel}
537157300Smarcel
538119815Smarcelvoid SDiagsRenderer::endDiagnostic(DiagOrStoredDiag D,
539120146Smarcel                                   DiagnosticsEngine::Level Level) {
540120146Smarcel  if (D && Level != DiagnosticsEngine::Note)
541120146Smarcel    return;
542120146Smarcel  Writer.Stream.ExitBlock();
543120146Smarcel}
544141032Smarcel
545141032Smarcelvoid SDiagsRenderer::emitCodeContext(SourceLocation Loc,
546119815Smarcel                                     DiagnosticsEngine::Level Level,
547119815Smarcel                                     SmallVectorImpl<CharSourceRange> &Ranges,
548119815Smarcel                                     ArrayRef<FixItHint> Hints,
549119815Smarcel                                     const SourceManager &SM) {
550119815Smarcel  // Emit Source Ranges.
551141032Smarcel  for (ArrayRef<CharSourceRange>::iterator it=Ranges.begin(), ei=Ranges.end();
552141032Smarcel       it != ei; ++it) {
553119815Smarcel    if (it->isValid())
554141032Smarcel      Writer.EmitCharSourceRange(*it, SM);
555119815Smarcel  }
556120146Smarcel
557120146Smarcel  // Emit FixIts.
558119815Smarcel  for (ArrayRef<FixItHint>::iterator it = Hints.begin(), et = Hints.end();
559119815Smarcel       it != et; ++it) {
560120146Smarcel    const FixItHint &fix = *it;
561120146Smarcel    if (fix.isNull())
562141032Smarcel      continue;
563141032Smarcel    Writer.Record.clear();
564120146Smarcel    Writer.Record.push_back(RECORD_FIXIT);
565141032Smarcel    Writer.AddCharSourceRangeToRecord(fix.RemoveRange, Record, SM);
566120146Smarcel    Writer.Record.push_back(fix.CodeToInsert.size());
567120146Smarcel    Writer.Stream.EmitRecordWithBlob(Writer.Abbrevs.get(RECORD_FIXIT), Record,
568120146Smarcel                                     fix.CodeToInsert);
569120146Smarcel  }
570120146Smarcel}
571157300Smarcel
572119815Smarcelvoid SDiagsRenderer::emitNote(SourceLocation Loc, StringRef Message,
573119815Smarcel                              const SourceManager *SM) {
574119815Smarcel  Writer.Stream.EnterSubblock(BLOCK_DIAG, 4);
575119815Smarcel  RecordData Record;
576119815Smarcel  Record.push_back(RECORD_DIAG);
577119815Smarcel  Record.push_back(DiagnosticsEngine::Note);
578119815Smarcel  Writer.AddLocToRecord(Loc, Record, SM);
579119815Smarcel  Record.push_back(Writer.getEmitCategory());
580119815Smarcel  Record.push_back(Writer.getEmitDiagnosticFlag(DiagnosticsEngine::Note));
581119815Smarcel  Record.push_back(Message.size());
582119815Smarcel  Writer.Stream.EmitRecordWithBlob(Writer.Abbrevs.get(RECORD_DIAG),
583119815Smarcel                                   Record, Message);
584119815Smarcel  Writer.Stream.ExitBlock();
585119815Smarcel}
586131043Sphk
587131043Sphkvoid SDiagsWriter::finish() {
588131043Sphk  if (inNonNoteDiagnostic) {
589119815Smarcel    // Finish off any diagnostics we were in the process of emitting.
590131043Sphk    Stream.ExitBlock();
591131043Sphk    inNonNoteDiagnostic = false;
592131043Sphk  }
593119815Smarcel
594119815Smarcel  // Write the generated bitstream to "Out".
595119815Smarcel  OS->write((char *)&Buffer.front(), Buffer.size());
596157300Smarcel  OS->flush();
597131043Sphk
598119815Smarcel  OS.reset(0);
599119815Smarcel}
600119815Smarcel
601131043Sphk