xref: /aosp_15_r20/external/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp (revision 67e74705e28f6214e480b399dd47ea732279e315)
1*67e74705SXin Li //===--- SerializedDiagnosticPrinter.cpp - Serializer for diagnostics -----===//
2*67e74705SXin Li //
3*67e74705SXin Li //                     The LLVM Compiler Infrastructure
4*67e74705SXin Li //
5*67e74705SXin Li // This file is distributed under the University of Illinois Open Source
6*67e74705SXin Li // License. See LICENSE.TXT for details.
7*67e74705SXin Li //
8*67e74705SXin Li //===----------------------------------------------------------------------===//
9*67e74705SXin Li 
10*67e74705SXin Li #include "clang/Frontend/SerializedDiagnosticPrinter.h"
11*67e74705SXin Li #include "clang/Basic/Diagnostic.h"
12*67e74705SXin Li #include "clang/Basic/DiagnosticOptions.h"
13*67e74705SXin Li #include "clang/Basic/FileManager.h"
14*67e74705SXin Li #include "clang/Basic/SourceManager.h"
15*67e74705SXin Li #include "clang/Basic/Version.h"
16*67e74705SXin Li #include "clang/Frontend/DiagnosticRenderer.h"
17*67e74705SXin Li #include "clang/Frontend/FrontendDiagnostic.h"
18*67e74705SXin Li #include "clang/Frontend/SerializedDiagnosticReader.h"
19*67e74705SXin Li #include "clang/Frontend/SerializedDiagnostics.h"
20*67e74705SXin Li #include "clang/Frontend/TextDiagnosticPrinter.h"
21*67e74705SXin Li #include "clang/Lex/Lexer.h"
22*67e74705SXin Li #include "llvm/ADT/DenseSet.h"
23*67e74705SXin Li #include "llvm/ADT/STLExtras.h"
24*67e74705SXin Li #include "llvm/ADT/SmallString.h"
25*67e74705SXin Li #include "llvm/ADT/StringRef.h"
26*67e74705SXin Li #include "llvm/Support/raw_ostream.h"
27*67e74705SXin Li #include <utility>
28*67e74705SXin Li #include <vector>
29*67e74705SXin Li 
30*67e74705SXin Li using namespace clang;
31*67e74705SXin Li using namespace clang::serialized_diags;
32*67e74705SXin Li 
33*67e74705SXin Li namespace {
34*67e74705SXin Li 
35*67e74705SXin Li class AbbreviationMap {
36*67e74705SXin Li   llvm::DenseMap<unsigned, unsigned> Abbrevs;
37*67e74705SXin Li public:
AbbreviationMap()38*67e74705SXin Li   AbbreviationMap() {}
39*67e74705SXin Li 
set(unsigned recordID,unsigned abbrevID)40*67e74705SXin Li   void set(unsigned recordID, unsigned abbrevID) {
41*67e74705SXin Li     assert(Abbrevs.find(recordID) == Abbrevs.end()
42*67e74705SXin Li            && "Abbreviation already set.");
43*67e74705SXin Li     Abbrevs[recordID] = abbrevID;
44*67e74705SXin Li   }
45*67e74705SXin Li 
get(unsigned recordID)46*67e74705SXin Li   unsigned get(unsigned recordID) {
47*67e74705SXin Li     assert(Abbrevs.find(recordID) != Abbrevs.end() &&
48*67e74705SXin Li            "Abbreviation not set.");
49*67e74705SXin Li     return Abbrevs[recordID];
50*67e74705SXin Li   }
51*67e74705SXin Li };
52*67e74705SXin Li 
53*67e74705SXin Li typedef SmallVector<uint64_t, 64> RecordData;
54*67e74705SXin Li typedef SmallVectorImpl<uint64_t> RecordDataImpl;
55*67e74705SXin Li typedef ArrayRef<uint64_t> RecordDataRef;
56*67e74705SXin Li 
57*67e74705SXin Li class SDiagsWriter;
58*67e74705SXin Li 
59*67e74705SXin Li class SDiagsRenderer : public DiagnosticNoteRenderer {
60*67e74705SXin Li   SDiagsWriter &Writer;
61*67e74705SXin Li public:
SDiagsRenderer(SDiagsWriter & Writer,const LangOptions & LangOpts,DiagnosticOptions * DiagOpts)62*67e74705SXin Li   SDiagsRenderer(SDiagsWriter &Writer, const LangOptions &LangOpts,
63*67e74705SXin Li                  DiagnosticOptions *DiagOpts)
64*67e74705SXin Li     : DiagnosticNoteRenderer(LangOpts, DiagOpts), Writer(Writer) {}
65*67e74705SXin Li 
~SDiagsRenderer()66*67e74705SXin Li   ~SDiagsRenderer() override {}
67*67e74705SXin Li 
68*67e74705SXin Li protected:
69*67e74705SXin Li   void emitDiagnosticMessage(SourceLocation Loc,
70*67e74705SXin Li                              PresumedLoc PLoc,
71*67e74705SXin Li                              DiagnosticsEngine::Level Level,
72*67e74705SXin Li                              StringRef Message,
73*67e74705SXin Li                              ArrayRef<CharSourceRange> Ranges,
74*67e74705SXin Li                              const SourceManager *SM,
75*67e74705SXin Li                              DiagOrStoredDiag D) override;
76*67e74705SXin Li 
emitDiagnosticLoc(SourceLocation Loc,PresumedLoc PLoc,DiagnosticsEngine::Level Level,ArrayRef<CharSourceRange> Ranges,const SourceManager & SM)77*67e74705SXin Li   void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
78*67e74705SXin Li                          DiagnosticsEngine::Level Level,
79*67e74705SXin Li                          ArrayRef<CharSourceRange> Ranges,
80*67e74705SXin Li                          const SourceManager &SM) override {}
81*67e74705SXin Li 
82*67e74705SXin Li   void emitNote(SourceLocation Loc, StringRef Message,
83*67e74705SXin Li                 const SourceManager *SM) override;
84*67e74705SXin Li 
85*67e74705SXin Li   void emitCodeContext(SourceLocation Loc,
86*67e74705SXin Li                        DiagnosticsEngine::Level Level,
87*67e74705SXin Li                        SmallVectorImpl<CharSourceRange>& Ranges,
88*67e74705SXin Li                        ArrayRef<FixItHint> Hints,
89*67e74705SXin Li                        const SourceManager &SM) override;
90*67e74705SXin Li 
91*67e74705SXin Li   void beginDiagnostic(DiagOrStoredDiag D,
92*67e74705SXin Li                        DiagnosticsEngine::Level Level) override;
93*67e74705SXin Li   void endDiagnostic(DiagOrStoredDiag D,
94*67e74705SXin Li                      DiagnosticsEngine::Level Level) override;
95*67e74705SXin Li };
96*67e74705SXin Li 
97*67e74705SXin Li typedef llvm::DenseMap<unsigned, unsigned> AbbrevLookup;
98*67e74705SXin Li 
99*67e74705SXin Li class SDiagsMerger : SerializedDiagnosticReader {
100*67e74705SXin Li   SDiagsWriter &Writer;
101*67e74705SXin Li   AbbrevLookup FileLookup;
102*67e74705SXin Li   AbbrevLookup CategoryLookup;
103*67e74705SXin Li   AbbrevLookup DiagFlagLookup;
104*67e74705SXin Li 
105*67e74705SXin Li public:
SDiagsMerger(SDiagsWriter & Writer)106*67e74705SXin Li   SDiagsMerger(SDiagsWriter &Writer)
107*67e74705SXin Li       : SerializedDiagnosticReader(), Writer(Writer) {}
108*67e74705SXin Li 
mergeRecordsFromFile(const char * File)109*67e74705SXin Li   std::error_code mergeRecordsFromFile(const char *File) {
110*67e74705SXin Li     return readDiagnostics(File);
111*67e74705SXin Li   }
112*67e74705SXin Li 
113*67e74705SXin Li protected:
114*67e74705SXin Li   std::error_code visitStartOfDiagnostic() override;
115*67e74705SXin Li   std::error_code visitEndOfDiagnostic() override;
116*67e74705SXin Li   std::error_code visitCategoryRecord(unsigned ID, StringRef Name) override;
117*67e74705SXin Li   std::error_code visitDiagFlagRecord(unsigned ID, StringRef Name) override;
118*67e74705SXin Li   std::error_code visitDiagnosticRecord(
119*67e74705SXin Li       unsigned Severity, const serialized_diags::Location &Location,
120*67e74705SXin Li       unsigned Category, unsigned Flag, StringRef Message) override;
121*67e74705SXin Li   std::error_code visitFilenameRecord(unsigned ID, unsigned Size,
122*67e74705SXin Li                                       unsigned Timestamp,
123*67e74705SXin Li                                       StringRef Name) override;
124*67e74705SXin Li   std::error_code visitFixitRecord(const serialized_diags::Location &Start,
125*67e74705SXin Li                                    const serialized_diags::Location &End,
126*67e74705SXin Li                                    StringRef CodeToInsert) override;
127*67e74705SXin Li   std::error_code
128*67e74705SXin Li   visitSourceRangeRecord(const serialized_diags::Location &Start,
129*67e74705SXin Li                          const serialized_diags::Location &End) override;
130*67e74705SXin Li 
131*67e74705SXin Li private:
132*67e74705SXin Li   std::error_code adjustSourceLocFilename(RecordData &Record,
133*67e74705SXin Li                                           unsigned int offset);
134*67e74705SXin Li 
135*67e74705SXin Li   void adjustAbbrevID(RecordData &Record, AbbrevLookup &Lookup,
136*67e74705SXin Li                       unsigned NewAbbrev);
137*67e74705SXin Li 
138*67e74705SXin Li   void writeRecordWithAbbrev(unsigned ID, RecordData &Record);
139*67e74705SXin Li 
140*67e74705SXin Li   void writeRecordWithBlob(unsigned ID, RecordData &Record, StringRef Blob);
141*67e74705SXin Li };
142*67e74705SXin Li 
143*67e74705SXin Li class SDiagsWriter : public DiagnosticConsumer {
144*67e74705SXin Li   friend class SDiagsRenderer;
145*67e74705SXin Li   friend class SDiagsMerger;
146*67e74705SXin Li 
147*67e74705SXin Li   struct SharedState;
148*67e74705SXin Li 
SDiagsWriter(IntrusiveRefCntPtr<SharedState> State)149*67e74705SXin Li   explicit SDiagsWriter(IntrusiveRefCntPtr<SharedState> State)
150*67e74705SXin Li       : LangOpts(nullptr), OriginalInstance(false), MergeChildRecords(false),
151*67e74705SXin Li         State(std::move(State)) {}
152*67e74705SXin Li 
153*67e74705SXin Li public:
SDiagsWriter(StringRef File,DiagnosticOptions * Diags,bool MergeChildRecords)154*67e74705SXin Li   SDiagsWriter(StringRef File, DiagnosticOptions *Diags, bool MergeChildRecords)
155*67e74705SXin Li       : LangOpts(nullptr), OriginalInstance(true),
156*67e74705SXin Li         MergeChildRecords(MergeChildRecords),
157*67e74705SXin Li         State(new SharedState(File, Diags)) {
158*67e74705SXin Li     if (MergeChildRecords)
159*67e74705SXin Li       RemoveOldDiagnostics();
160*67e74705SXin Li     EmitPreamble();
161*67e74705SXin Li   }
162*67e74705SXin Li 
~SDiagsWriter()163*67e74705SXin Li   ~SDiagsWriter() override {}
164*67e74705SXin Li 
165*67e74705SXin Li   void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
166*67e74705SXin Li                         const Diagnostic &Info) override;
167*67e74705SXin Li 
BeginSourceFile(const LangOptions & LO,const Preprocessor * PP)168*67e74705SXin Li   void BeginSourceFile(const LangOptions &LO, const Preprocessor *PP) override {
169*67e74705SXin Li     LangOpts = &LO;
170*67e74705SXin Li   }
171*67e74705SXin Li 
172*67e74705SXin Li   void finish() override;
173*67e74705SXin Li 
174*67e74705SXin Li private:
175*67e74705SXin Li   /// \brief Build a DiagnosticsEngine to emit diagnostics about the diagnostics
176*67e74705SXin Li   DiagnosticsEngine *getMetaDiags();
177*67e74705SXin Li 
178*67e74705SXin Li   /// \brief Remove old copies of the serialized diagnostics. This is necessary
179*67e74705SXin Li   /// so that we can detect when subprocesses write diagnostics that we should
180*67e74705SXin Li   /// merge into our own.
181*67e74705SXin Li   void RemoveOldDiagnostics();
182*67e74705SXin Li 
183*67e74705SXin Li   /// \brief Emit the preamble for the serialized diagnostics.
184*67e74705SXin Li   void EmitPreamble();
185*67e74705SXin Li 
186*67e74705SXin Li   /// \brief Emit the BLOCKINFO block.
187*67e74705SXin Li   void EmitBlockInfoBlock();
188*67e74705SXin Li 
189*67e74705SXin Li   /// \brief Emit the META data block.
190*67e74705SXin Li   void EmitMetaBlock();
191*67e74705SXin Li 
192*67e74705SXin Li   /// \brief Start a DIAG block.
193*67e74705SXin Li   void EnterDiagBlock();
194*67e74705SXin Li 
195*67e74705SXin Li   /// \brief End a DIAG block.
196*67e74705SXin Li   void ExitDiagBlock();
197*67e74705SXin Li 
198*67e74705SXin Li   /// \brief Emit a DIAG record.
199*67e74705SXin Li   void EmitDiagnosticMessage(SourceLocation Loc,
200*67e74705SXin Li                              PresumedLoc PLoc,
201*67e74705SXin Li                              DiagnosticsEngine::Level Level,
202*67e74705SXin Li                              StringRef Message,
203*67e74705SXin Li                              const SourceManager *SM,
204*67e74705SXin Li                              DiagOrStoredDiag D);
205*67e74705SXin Li 
206*67e74705SXin Li   /// \brief Emit FIXIT and SOURCE_RANGE records for a diagnostic.
207*67e74705SXin Li   void EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges,
208*67e74705SXin Li                        ArrayRef<FixItHint> Hints,
209*67e74705SXin Li                        const SourceManager &SM);
210*67e74705SXin Li 
211*67e74705SXin Li   /// \brief Emit a record for a CharSourceRange.
212*67e74705SXin Li   void EmitCharSourceRange(CharSourceRange R, const SourceManager &SM);
213*67e74705SXin Li 
214*67e74705SXin Li   /// \brief Emit the string information for the category.
215*67e74705SXin Li   unsigned getEmitCategory(unsigned category = 0);
216*67e74705SXin Li 
217*67e74705SXin Li   /// \brief Emit the string information for diagnostic flags.
218*67e74705SXin Li   unsigned getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
219*67e74705SXin Li                                  unsigned DiagID = 0);
220*67e74705SXin Li 
221*67e74705SXin Li   unsigned getEmitDiagnosticFlag(StringRef DiagName);
222*67e74705SXin Li 
223*67e74705SXin Li   /// \brief Emit (lazily) the file string and retrieved the file identifier.
224*67e74705SXin Li   unsigned getEmitFile(const char *Filename);
225*67e74705SXin Li 
226*67e74705SXin Li   /// \brief Add SourceLocation information the specified record.
227*67e74705SXin Li   void AddLocToRecord(SourceLocation Loc, const SourceManager *SM,
228*67e74705SXin Li                       PresumedLoc PLoc, RecordDataImpl &Record,
229*67e74705SXin Li                       unsigned TokSize = 0);
230*67e74705SXin Li 
231*67e74705SXin Li   /// \brief Add SourceLocation information the specified record.
AddLocToRecord(SourceLocation Loc,RecordDataImpl & Record,const SourceManager * SM,unsigned TokSize=0)232*67e74705SXin Li   void AddLocToRecord(SourceLocation Loc, RecordDataImpl &Record,
233*67e74705SXin Li                       const SourceManager *SM,
234*67e74705SXin Li                       unsigned TokSize = 0) {
235*67e74705SXin Li     AddLocToRecord(Loc, SM, SM ? SM->getPresumedLoc(Loc) : PresumedLoc(),
236*67e74705SXin Li                    Record, TokSize);
237*67e74705SXin Li   }
238*67e74705SXin Li 
239*67e74705SXin Li   /// \brief Add CharSourceRange information the specified record.
240*67e74705SXin Li   void AddCharSourceRangeToRecord(CharSourceRange R, RecordDataImpl &Record,
241*67e74705SXin Li                                   const SourceManager &SM);
242*67e74705SXin Li 
243*67e74705SXin Li   /// \brief Language options, which can differ from one clone of this client
244*67e74705SXin Li   /// to another.
245*67e74705SXin Li   const LangOptions *LangOpts;
246*67e74705SXin Li 
247*67e74705SXin Li   /// \brief Whether this is the original instance (rather than one of its
248*67e74705SXin Li   /// clones), responsible for writing the file at the end.
249*67e74705SXin Li   bool OriginalInstance;
250*67e74705SXin Li 
251*67e74705SXin Li   /// \brief Whether this instance should aggregate diagnostics that are
252*67e74705SXin Li   /// generated from child processes.
253*67e74705SXin Li   bool MergeChildRecords;
254*67e74705SXin Li 
255*67e74705SXin Li   /// \brief State that is shared among the various clones of this diagnostic
256*67e74705SXin Li   /// consumer.
257*67e74705SXin Li   struct SharedState : RefCountedBase<SharedState> {
SharedState__anonc54855760111::SDiagsWriter::SharedState258*67e74705SXin Li     SharedState(StringRef File, DiagnosticOptions *Diags)
259*67e74705SXin Li         : DiagOpts(Diags), Stream(Buffer), OutputFile(File.str()),
260*67e74705SXin Li           EmittedAnyDiagBlocks(false) {}
261*67e74705SXin Li 
262*67e74705SXin Li     /// \brief Diagnostic options.
263*67e74705SXin Li     IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
264*67e74705SXin Li 
265*67e74705SXin Li     /// \brief The byte buffer for the serialized content.
266*67e74705SXin Li     SmallString<1024> Buffer;
267*67e74705SXin Li 
268*67e74705SXin Li     /// \brief The BitStreamWriter for the serialized diagnostics.
269*67e74705SXin Li     llvm::BitstreamWriter Stream;
270*67e74705SXin Li 
271*67e74705SXin Li     /// \brief The name of the diagnostics file.
272*67e74705SXin Li     std::string OutputFile;
273*67e74705SXin Li 
274*67e74705SXin Li     /// \brief The set of constructed record abbreviations.
275*67e74705SXin Li     AbbreviationMap Abbrevs;
276*67e74705SXin Li 
277*67e74705SXin Li     /// \brief A utility buffer for constructing record content.
278*67e74705SXin Li     RecordData Record;
279*67e74705SXin Li 
280*67e74705SXin Li     /// \brief A text buffer for rendering diagnostic text.
281*67e74705SXin Li     SmallString<256> diagBuf;
282*67e74705SXin Li 
283*67e74705SXin Li     /// \brief The collection of diagnostic categories used.
284*67e74705SXin Li     llvm::DenseSet<unsigned> Categories;
285*67e74705SXin Li 
286*67e74705SXin Li     /// \brief The collection of files used.
287*67e74705SXin Li     llvm::DenseMap<const char *, unsigned> Files;
288*67e74705SXin Li 
289*67e74705SXin Li     typedef llvm::DenseMap<const void *, std::pair<unsigned, StringRef> >
290*67e74705SXin Li     DiagFlagsTy;
291*67e74705SXin Li 
292*67e74705SXin Li     /// \brief Map for uniquing strings.
293*67e74705SXin Li     DiagFlagsTy DiagFlags;
294*67e74705SXin Li 
295*67e74705SXin Li     /// \brief Whether we have already started emission of any DIAG blocks. Once
296*67e74705SXin Li     /// this becomes \c true, we never close a DIAG block until we know that we're
297*67e74705SXin Li     /// starting another one or we're done.
298*67e74705SXin Li     bool EmittedAnyDiagBlocks;
299*67e74705SXin Li 
300*67e74705SXin Li     /// \brief Engine for emitting diagnostics about the diagnostics.
301*67e74705SXin Li     std::unique_ptr<DiagnosticsEngine> MetaDiagnostics;
302*67e74705SXin Li   };
303*67e74705SXin Li 
304*67e74705SXin Li   /// \brief State shared among the various clones of this diagnostic consumer.
305*67e74705SXin Li   IntrusiveRefCntPtr<SharedState> State;
306*67e74705SXin Li };
307*67e74705SXin Li } // end anonymous namespace
308*67e74705SXin Li 
309*67e74705SXin Li namespace clang {
310*67e74705SXin Li namespace serialized_diags {
311*67e74705SXin Li std::unique_ptr<DiagnosticConsumer>
create(StringRef OutputFile,DiagnosticOptions * Diags,bool MergeChildRecords)312*67e74705SXin Li create(StringRef OutputFile, DiagnosticOptions *Diags, bool MergeChildRecords) {
313*67e74705SXin Li   return llvm::make_unique<SDiagsWriter>(OutputFile, Diags, MergeChildRecords);
314*67e74705SXin Li }
315*67e74705SXin Li 
316*67e74705SXin Li } // end namespace serialized_diags
317*67e74705SXin Li } // end namespace clang
318*67e74705SXin Li 
319*67e74705SXin Li //===----------------------------------------------------------------------===//
320*67e74705SXin Li // Serialization methods.
321*67e74705SXin Li //===----------------------------------------------------------------------===//
322*67e74705SXin Li 
323*67e74705SXin Li /// \brief Emits a block ID in the BLOCKINFO block.
EmitBlockID(unsigned ID,const char * Name,llvm::BitstreamWriter & Stream,RecordDataImpl & Record)324*67e74705SXin Li static void EmitBlockID(unsigned ID, const char *Name,
325*67e74705SXin Li                         llvm::BitstreamWriter &Stream,
326*67e74705SXin Li                         RecordDataImpl &Record) {
327*67e74705SXin Li   Record.clear();
328*67e74705SXin Li   Record.push_back(ID);
329*67e74705SXin Li   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
330*67e74705SXin Li 
331*67e74705SXin Li   // Emit the block name if present.
332*67e74705SXin Li   if (!Name || Name[0] == 0)
333*67e74705SXin Li     return;
334*67e74705SXin Li 
335*67e74705SXin Li   Record.clear();
336*67e74705SXin Li 
337*67e74705SXin Li   while (*Name)
338*67e74705SXin Li     Record.push_back(*Name++);
339*67e74705SXin Li 
340*67e74705SXin Li   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record);
341*67e74705SXin Li }
342*67e74705SXin Li 
343*67e74705SXin Li /// \brief Emits a record ID in the BLOCKINFO block.
EmitRecordID(unsigned ID,const char * Name,llvm::BitstreamWriter & Stream,RecordDataImpl & Record)344*67e74705SXin Li static void EmitRecordID(unsigned ID, const char *Name,
345*67e74705SXin Li                          llvm::BitstreamWriter &Stream,
346*67e74705SXin Li                          RecordDataImpl &Record){
347*67e74705SXin Li   Record.clear();
348*67e74705SXin Li   Record.push_back(ID);
349*67e74705SXin Li 
350*67e74705SXin Li   while (*Name)
351*67e74705SXin Li     Record.push_back(*Name++);
352*67e74705SXin Li 
353*67e74705SXin Li   Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
354*67e74705SXin Li }
355*67e74705SXin Li 
AddLocToRecord(SourceLocation Loc,const SourceManager * SM,PresumedLoc PLoc,RecordDataImpl & Record,unsigned TokSize)356*67e74705SXin Li void SDiagsWriter::AddLocToRecord(SourceLocation Loc,
357*67e74705SXin Li                                   const SourceManager *SM,
358*67e74705SXin Li                                   PresumedLoc PLoc,
359*67e74705SXin Li                                   RecordDataImpl &Record,
360*67e74705SXin Li                                   unsigned TokSize) {
361*67e74705SXin Li   if (PLoc.isInvalid()) {
362*67e74705SXin Li     // Emit a "sentinel" location.
363*67e74705SXin Li     Record.push_back((unsigned)0); // File.
364*67e74705SXin Li     Record.push_back((unsigned)0); // Line.
365*67e74705SXin Li     Record.push_back((unsigned)0); // Column.
366*67e74705SXin Li     Record.push_back((unsigned)0); // Offset.
367*67e74705SXin Li     return;
368*67e74705SXin Li   }
369*67e74705SXin Li 
370*67e74705SXin Li   Record.push_back(getEmitFile(PLoc.getFilename()));
371*67e74705SXin Li   Record.push_back(PLoc.getLine());
372*67e74705SXin Li   Record.push_back(PLoc.getColumn()+TokSize);
373*67e74705SXin Li   Record.push_back(SM->getFileOffset(Loc));
374*67e74705SXin Li }
375*67e74705SXin Li 
AddCharSourceRangeToRecord(CharSourceRange Range,RecordDataImpl & Record,const SourceManager & SM)376*67e74705SXin Li void SDiagsWriter::AddCharSourceRangeToRecord(CharSourceRange Range,
377*67e74705SXin Li                                               RecordDataImpl &Record,
378*67e74705SXin Li                                               const SourceManager &SM) {
379*67e74705SXin Li   AddLocToRecord(Range.getBegin(), Record, &SM);
380*67e74705SXin Li   unsigned TokSize = 0;
381*67e74705SXin Li   if (Range.isTokenRange())
382*67e74705SXin Li     TokSize = Lexer::MeasureTokenLength(Range.getEnd(),
383*67e74705SXin Li                                         SM, *LangOpts);
384*67e74705SXin Li 
385*67e74705SXin Li   AddLocToRecord(Range.getEnd(), Record, &SM, TokSize);
386*67e74705SXin Li }
387*67e74705SXin Li 
getEmitFile(const char * FileName)388*67e74705SXin Li unsigned SDiagsWriter::getEmitFile(const char *FileName){
389*67e74705SXin Li   if (!FileName)
390*67e74705SXin Li     return 0;
391*67e74705SXin Li 
392*67e74705SXin Li   unsigned &entry = State->Files[FileName];
393*67e74705SXin Li   if (entry)
394*67e74705SXin Li     return entry;
395*67e74705SXin Li 
396*67e74705SXin Li   // Lazily generate the record for the file.
397*67e74705SXin Li   entry = State->Files.size();
398*67e74705SXin Li   StringRef Name(FileName);
399*67e74705SXin Li   RecordData::value_type Record[] = {RECORD_FILENAME, entry, 0 /* For legacy */,
400*67e74705SXin Li                                      0 /* For legacy */, Name.size()};
401*67e74705SXin Li   State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_FILENAME), Record,
402*67e74705SXin Li                                    Name);
403*67e74705SXin Li 
404*67e74705SXin Li   return entry;
405*67e74705SXin Li }
406*67e74705SXin Li 
EmitCharSourceRange(CharSourceRange R,const SourceManager & SM)407*67e74705SXin Li void SDiagsWriter::EmitCharSourceRange(CharSourceRange R,
408*67e74705SXin Li                                        const SourceManager &SM) {
409*67e74705SXin Li   State->Record.clear();
410*67e74705SXin Li   State->Record.push_back(RECORD_SOURCE_RANGE);
411*67e74705SXin Li   AddCharSourceRangeToRecord(R, State->Record, SM);
412*67e74705SXin Li   State->Stream.EmitRecordWithAbbrev(State->Abbrevs.get(RECORD_SOURCE_RANGE),
413*67e74705SXin Li                                      State->Record);
414*67e74705SXin Li }
415*67e74705SXin Li 
416*67e74705SXin Li /// \brief Emits the preamble of the diagnostics file.
EmitPreamble()417*67e74705SXin Li void SDiagsWriter::EmitPreamble() {
418*67e74705SXin Li   // Emit the file header.
419*67e74705SXin Li   State->Stream.Emit((unsigned)'D', 8);
420*67e74705SXin Li   State->Stream.Emit((unsigned)'I', 8);
421*67e74705SXin Li   State->Stream.Emit((unsigned)'A', 8);
422*67e74705SXin Li   State->Stream.Emit((unsigned)'G', 8);
423*67e74705SXin Li 
424*67e74705SXin Li   EmitBlockInfoBlock();
425*67e74705SXin Li   EmitMetaBlock();
426*67e74705SXin Li }
427*67e74705SXin Li 
AddSourceLocationAbbrev(llvm::BitCodeAbbrev * Abbrev)428*67e74705SXin Li static void AddSourceLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) {
429*67e74705SXin Li   using namespace llvm;
430*67e74705SXin Li   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // File ID.
431*67e74705SXin Li   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Line.
432*67e74705SXin Li   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Column.
433*67e74705SXin Li   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Offset;
434*67e74705SXin Li }
435*67e74705SXin Li 
AddRangeLocationAbbrev(llvm::BitCodeAbbrev * Abbrev)436*67e74705SXin Li static void AddRangeLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) {
437*67e74705SXin Li   AddSourceLocationAbbrev(Abbrev);
438*67e74705SXin Li   AddSourceLocationAbbrev(Abbrev);
439*67e74705SXin Li }
440*67e74705SXin Li 
EmitBlockInfoBlock()441*67e74705SXin Li void SDiagsWriter::EmitBlockInfoBlock() {
442*67e74705SXin Li   State->Stream.EnterBlockInfoBlock(3);
443*67e74705SXin Li 
444*67e74705SXin Li   using namespace llvm;
445*67e74705SXin Li   llvm::BitstreamWriter &Stream = State->Stream;
446*67e74705SXin Li   RecordData &Record = State->Record;
447*67e74705SXin Li   AbbreviationMap &Abbrevs = State->Abbrevs;
448*67e74705SXin Li 
449*67e74705SXin Li   // ==---------------------------------------------------------------------==//
450*67e74705SXin Li   // The subsequent records and Abbrevs are for the "Meta" block.
451*67e74705SXin Li   // ==---------------------------------------------------------------------==//
452*67e74705SXin Li 
453*67e74705SXin Li   EmitBlockID(BLOCK_META, "Meta", Stream, Record);
454*67e74705SXin Li   EmitRecordID(RECORD_VERSION, "Version", Stream, Record);
455*67e74705SXin Li   BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
456*67e74705SXin Li   Abbrev->Add(BitCodeAbbrevOp(RECORD_VERSION));
457*67e74705SXin Li   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
458*67e74705SXin Li   Abbrevs.set(RECORD_VERSION, Stream.EmitBlockInfoAbbrev(BLOCK_META, Abbrev));
459*67e74705SXin Li 
460*67e74705SXin Li   // ==---------------------------------------------------------------------==//
461*67e74705SXin Li   // The subsequent records and Abbrevs are for the "Diagnostic" block.
462*67e74705SXin Li   // ==---------------------------------------------------------------------==//
463*67e74705SXin Li 
464*67e74705SXin Li   EmitBlockID(BLOCK_DIAG, "Diag", Stream, Record);
465*67e74705SXin Li   EmitRecordID(RECORD_DIAG, "DiagInfo", Stream, Record);
466*67e74705SXin Li   EmitRecordID(RECORD_SOURCE_RANGE, "SrcRange", Stream, Record);
467*67e74705SXin Li   EmitRecordID(RECORD_CATEGORY, "CatName", Stream, Record);
468*67e74705SXin Li   EmitRecordID(RECORD_DIAG_FLAG, "DiagFlag", Stream, Record);
469*67e74705SXin Li   EmitRecordID(RECORD_FILENAME, "FileName", Stream, Record);
470*67e74705SXin Li   EmitRecordID(RECORD_FIXIT, "FixIt", Stream, Record);
471*67e74705SXin Li 
472*67e74705SXin Li   // Emit abbreviation for RECORD_DIAG.
473*67e74705SXin Li   Abbrev = new BitCodeAbbrev();
474*67e74705SXin Li   Abbrev->Add(BitCodeAbbrevOp(RECORD_DIAG));
475*67e74705SXin Li   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3));  // Diag level.
476*67e74705SXin Li   AddSourceLocationAbbrev(Abbrev);
477*67e74705SXin Li   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Category.
478*67e74705SXin Li   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped Diag ID.
479*67e74705SXin Li   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // Text size.
480*67e74705SXin Li   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Diagnostc text.
481*67e74705SXin Li   Abbrevs.set(RECORD_DIAG, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
482*67e74705SXin Li 
483*67e74705SXin Li   // Emit abbrevation for RECORD_CATEGORY.
484*67e74705SXin Li   Abbrev = new BitCodeAbbrev();
485*67e74705SXin Li   Abbrev->Add(BitCodeAbbrevOp(RECORD_CATEGORY));
486*67e74705SXin Li   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Category ID.
487*67e74705SXin Li   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8));  // Text size.
488*67e74705SXin Li   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));      // Category text.
489*67e74705SXin Li   Abbrevs.set(RECORD_CATEGORY, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
490*67e74705SXin Li 
491*67e74705SXin Li   // Emit abbrevation for RECORD_SOURCE_RANGE.
492*67e74705SXin Li   Abbrev = new BitCodeAbbrev();
493*67e74705SXin Li   Abbrev->Add(BitCodeAbbrevOp(RECORD_SOURCE_RANGE));
494*67e74705SXin Li   AddRangeLocationAbbrev(Abbrev);
495*67e74705SXin Li   Abbrevs.set(RECORD_SOURCE_RANGE,
496*67e74705SXin Li               Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
497*67e74705SXin Li 
498*67e74705SXin Li   // Emit the abbreviation for RECORD_DIAG_FLAG.
499*67e74705SXin Li   Abbrev = new BitCodeAbbrev();
500*67e74705SXin Li   Abbrev->Add(BitCodeAbbrevOp(RECORD_DIAG_FLAG));
501*67e74705SXin Li   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped Diag ID.
502*67e74705SXin Li   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
503*67e74705SXin Li   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Flag name text.
504*67e74705SXin Li   Abbrevs.set(RECORD_DIAG_FLAG, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
505*67e74705SXin Li                                                            Abbrev));
506*67e74705SXin Li 
507*67e74705SXin Li   // Emit the abbreviation for RECORD_FILENAME.
508*67e74705SXin Li   Abbrev = new BitCodeAbbrev();
509*67e74705SXin Li   Abbrev->Add(BitCodeAbbrevOp(RECORD_FILENAME));
510*67e74705SXin Li   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped file ID.
511*67e74705SXin Li   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Size.
512*67e74705SXin Li   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Modifcation time.
513*67e74705SXin Li   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
514*67e74705SXin Li   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name text.
515*67e74705SXin Li   Abbrevs.set(RECORD_FILENAME, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
516*67e74705SXin Li                                                           Abbrev));
517*67e74705SXin Li 
518*67e74705SXin Li   // Emit the abbreviation for RECORD_FIXIT.
519*67e74705SXin Li   Abbrev = new BitCodeAbbrev();
520*67e74705SXin Li   Abbrev->Add(BitCodeAbbrevOp(RECORD_FIXIT));
521*67e74705SXin Li   AddRangeLocationAbbrev(Abbrev);
522*67e74705SXin Li   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
523*67e74705SXin Li   Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));      // FixIt text.
524*67e74705SXin Li   Abbrevs.set(RECORD_FIXIT, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
525*67e74705SXin Li                                                        Abbrev));
526*67e74705SXin Li 
527*67e74705SXin Li   Stream.ExitBlock();
528*67e74705SXin Li }
529*67e74705SXin Li 
EmitMetaBlock()530*67e74705SXin Li void SDiagsWriter::EmitMetaBlock() {
531*67e74705SXin Li   llvm::BitstreamWriter &Stream = State->Stream;
532*67e74705SXin Li   AbbreviationMap &Abbrevs = State->Abbrevs;
533*67e74705SXin Li 
534*67e74705SXin Li   Stream.EnterSubblock(BLOCK_META, 3);
535*67e74705SXin Li   RecordData::value_type Record[] = {RECORD_VERSION, VersionNumber};
536*67e74705SXin Li   Stream.EmitRecordWithAbbrev(Abbrevs.get(RECORD_VERSION), Record);
537*67e74705SXin Li   Stream.ExitBlock();
538*67e74705SXin Li }
539*67e74705SXin Li 
getEmitCategory(unsigned int category)540*67e74705SXin Li unsigned SDiagsWriter::getEmitCategory(unsigned int category) {
541*67e74705SXin Li   if (!State->Categories.insert(category).second)
542*67e74705SXin Li     return category;
543*67e74705SXin Li 
544*67e74705SXin Li   // We use a local version of 'Record' so that we can be generating
545*67e74705SXin Li   // another record when we lazily generate one for the category entry.
546*67e74705SXin Li   StringRef catName = DiagnosticIDs::getCategoryNameFromID(category);
547*67e74705SXin Li   RecordData::value_type Record[] = {RECORD_CATEGORY, category, catName.size()};
548*67e74705SXin Li   State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_CATEGORY), Record,
549*67e74705SXin Li                                    catName);
550*67e74705SXin Li 
551*67e74705SXin Li   return category;
552*67e74705SXin Li }
553*67e74705SXin Li 
getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,unsigned DiagID)554*67e74705SXin Li unsigned SDiagsWriter::getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
555*67e74705SXin Li                                              unsigned DiagID) {
556*67e74705SXin Li   if (DiagLevel == DiagnosticsEngine::Note)
557*67e74705SXin Li     return 0; // No flag for notes.
558*67e74705SXin Li 
559*67e74705SXin Li   StringRef FlagName = DiagnosticIDs::getWarningOptionForDiag(DiagID);
560*67e74705SXin Li   return getEmitDiagnosticFlag(FlagName);
561*67e74705SXin Li }
562*67e74705SXin Li 
getEmitDiagnosticFlag(StringRef FlagName)563*67e74705SXin Li unsigned SDiagsWriter::getEmitDiagnosticFlag(StringRef FlagName) {
564*67e74705SXin Li   if (FlagName.empty())
565*67e74705SXin Li     return 0;
566*67e74705SXin Li 
567*67e74705SXin Li   // Here we assume that FlagName points to static data whose pointer
568*67e74705SXin Li   // value is fixed.  This allows us to unique by diagnostic groups.
569*67e74705SXin Li   const void *data = FlagName.data();
570*67e74705SXin Li   std::pair<unsigned, StringRef> &entry = State->DiagFlags[data];
571*67e74705SXin Li   if (entry.first == 0) {
572*67e74705SXin Li     entry.first = State->DiagFlags.size();
573*67e74705SXin Li     entry.second = FlagName;
574*67e74705SXin Li 
575*67e74705SXin Li     // Lazily emit the string in a separate record.
576*67e74705SXin Li     RecordData::value_type Record[] = {RECORD_DIAG_FLAG, entry.first,
577*67e74705SXin Li                                        FlagName.size()};
578*67e74705SXin Li     State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_DIAG_FLAG),
579*67e74705SXin Li                                      Record, FlagName);
580*67e74705SXin Li   }
581*67e74705SXin Li 
582*67e74705SXin Li   return entry.first;
583*67e74705SXin Li }
584*67e74705SXin Li 
HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,const Diagnostic & Info)585*67e74705SXin Li void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
586*67e74705SXin Li                                     const Diagnostic &Info) {
587*67e74705SXin Li   // Enter the block for a non-note diagnostic immediately, rather than waiting
588*67e74705SXin Li   // for beginDiagnostic, in case associated notes are emitted before we get
589*67e74705SXin Li   // there.
590*67e74705SXin Li   if (DiagLevel != DiagnosticsEngine::Note) {
591*67e74705SXin Li     if (State->EmittedAnyDiagBlocks)
592*67e74705SXin Li       ExitDiagBlock();
593*67e74705SXin Li 
594*67e74705SXin Li     EnterDiagBlock();
595*67e74705SXin Li     State->EmittedAnyDiagBlocks = true;
596*67e74705SXin Li   }
597*67e74705SXin Li 
598*67e74705SXin Li   // Compute the diagnostic text.
599*67e74705SXin Li   State->diagBuf.clear();
600*67e74705SXin Li   Info.FormatDiagnostic(State->diagBuf);
601*67e74705SXin Li 
602*67e74705SXin Li   if (Info.getLocation().isInvalid()) {
603*67e74705SXin Li     // Special-case diagnostics with no location. We may not have entered a
604*67e74705SXin Li     // source file in this case, so we can't use the normal DiagnosticsRenderer
605*67e74705SXin Li     // machinery.
606*67e74705SXin Li 
607*67e74705SXin Li     // Make sure we bracket all notes as "sub-diagnostics".  This matches
608*67e74705SXin Li     // the behavior in SDiagsRenderer::emitDiagnostic().
609*67e74705SXin Li     if (DiagLevel == DiagnosticsEngine::Note)
610*67e74705SXin Li       EnterDiagBlock();
611*67e74705SXin Li 
612*67e74705SXin Li     EmitDiagnosticMessage(SourceLocation(), PresumedLoc(), DiagLevel,
613*67e74705SXin Li                           State->diagBuf, nullptr, &Info);
614*67e74705SXin Li 
615*67e74705SXin Li     if (DiagLevel == DiagnosticsEngine::Note)
616*67e74705SXin Li       ExitDiagBlock();
617*67e74705SXin Li 
618*67e74705SXin Li     return;
619*67e74705SXin Li   }
620*67e74705SXin Li 
621*67e74705SXin Li   assert(Info.hasSourceManager() && LangOpts &&
622*67e74705SXin Li          "Unexpected diagnostic with valid location outside of a source file");
623*67e74705SXin Li   SDiagsRenderer Renderer(*this, *LangOpts, &*State->DiagOpts);
624*67e74705SXin Li   Renderer.emitDiagnostic(Info.getLocation(), DiagLevel,
625*67e74705SXin Li                           State->diagBuf,
626*67e74705SXin Li                           Info.getRanges(),
627*67e74705SXin Li                           Info.getFixItHints(),
628*67e74705SXin Li                           &Info.getSourceManager(),
629*67e74705SXin Li                           &Info);
630*67e74705SXin Li }
631*67e74705SXin Li 
getStableLevel(DiagnosticsEngine::Level Level)632*67e74705SXin Li static serialized_diags::Level getStableLevel(DiagnosticsEngine::Level Level) {
633*67e74705SXin Li   switch (Level) {
634*67e74705SXin Li #define CASE(X) case DiagnosticsEngine::X: return serialized_diags::X;
635*67e74705SXin Li   CASE(Ignored)
636*67e74705SXin Li   CASE(Note)
637*67e74705SXin Li   CASE(Remark)
638*67e74705SXin Li   CASE(Warning)
639*67e74705SXin Li   CASE(Error)
640*67e74705SXin Li   CASE(Fatal)
641*67e74705SXin Li #undef CASE
642*67e74705SXin Li   }
643*67e74705SXin Li 
644*67e74705SXin Li   llvm_unreachable("invalid diagnostic level");
645*67e74705SXin Li }
646*67e74705SXin Li 
EmitDiagnosticMessage(SourceLocation Loc,PresumedLoc PLoc,DiagnosticsEngine::Level Level,StringRef Message,const SourceManager * SM,DiagOrStoredDiag D)647*67e74705SXin Li void SDiagsWriter::EmitDiagnosticMessage(SourceLocation Loc,
648*67e74705SXin Li                                          PresumedLoc PLoc,
649*67e74705SXin Li                                          DiagnosticsEngine::Level Level,
650*67e74705SXin Li                                          StringRef Message,
651*67e74705SXin Li                                          const SourceManager *SM,
652*67e74705SXin Li                                          DiagOrStoredDiag D) {
653*67e74705SXin Li   llvm::BitstreamWriter &Stream = State->Stream;
654*67e74705SXin Li   RecordData &Record = State->Record;
655*67e74705SXin Li   AbbreviationMap &Abbrevs = State->Abbrevs;
656*67e74705SXin Li 
657*67e74705SXin Li   // Emit the RECORD_DIAG record.
658*67e74705SXin Li   Record.clear();
659*67e74705SXin Li   Record.push_back(RECORD_DIAG);
660*67e74705SXin Li   Record.push_back(getStableLevel(Level));
661*67e74705SXin Li   AddLocToRecord(Loc, SM, PLoc, Record);
662*67e74705SXin Li 
663*67e74705SXin Li   if (const Diagnostic *Info = D.dyn_cast<const Diagnostic*>()) {
664*67e74705SXin Li     // Emit the category string lazily and get the category ID.
665*67e74705SXin Li     unsigned DiagID = DiagnosticIDs::getCategoryNumberForDiag(Info->getID());
666*67e74705SXin Li     Record.push_back(getEmitCategory(DiagID));
667*67e74705SXin Li     // Emit the diagnostic flag string lazily and get the mapped ID.
668*67e74705SXin Li     Record.push_back(getEmitDiagnosticFlag(Level, Info->getID()));
669*67e74705SXin Li   } else {
670*67e74705SXin Li     Record.push_back(getEmitCategory());
671*67e74705SXin Li     Record.push_back(getEmitDiagnosticFlag(Level));
672*67e74705SXin Li   }
673*67e74705SXin Li 
674*67e74705SXin Li   Record.push_back(Message.size());
675*67e74705SXin Li   Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG), Record, Message);
676*67e74705SXin Li }
677*67e74705SXin Li 
678*67e74705SXin Li void
emitDiagnosticMessage(SourceLocation Loc,PresumedLoc PLoc,DiagnosticsEngine::Level Level,StringRef Message,ArrayRef<clang::CharSourceRange> Ranges,const SourceManager * SM,DiagOrStoredDiag D)679*67e74705SXin Li SDiagsRenderer::emitDiagnosticMessage(SourceLocation Loc,
680*67e74705SXin Li                                       PresumedLoc PLoc,
681*67e74705SXin Li                                       DiagnosticsEngine::Level Level,
682*67e74705SXin Li                                       StringRef Message,
683*67e74705SXin Li                                       ArrayRef<clang::CharSourceRange> Ranges,
684*67e74705SXin Li                                       const SourceManager *SM,
685*67e74705SXin Li                                       DiagOrStoredDiag D) {
686*67e74705SXin Li   Writer.EmitDiagnosticMessage(Loc, PLoc, Level, Message, SM, D);
687*67e74705SXin Li }
688*67e74705SXin Li 
EnterDiagBlock()689*67e74705SXin Li void SDiagsWriter::EnterDiagBlock() {
690*67e74705SXin Li   State->Stream.EnterSubblock(BLOCK_DIAG, 4);
691*67e74705SXin Li }
692*67e74705SXin Li 
ExitDiagBlock()693*67e74705SXin Li void SDiagsWriter::ExitDiagBlock() {
694*67e74705SXin Li   State->Stream.ExitBlock();
695*67e74705SXin Li }
696*67e74705SXin Li 
beginDiagnostic(DiagOrStoredDiag D,DiagnosticsEngine::Level Level)697*67e74705SXin Li void SDiagsRenderer::beginDiagnostic(DiagOrStoredDiag D,
698*67e74705SXin Li                                      DiagnosticsEngine::Level Level) {
699*67e74705SXin Li   if (Level == DiagnosticsEngine::Note)
700*67e74705SXin Li     Writer.EnterDiagBlock();
701*67e74705SXin Li }
702*67e74705SXin Li 
endDiagnostic(DiagOrStoredDiag D,DiagnosticsEngine::Level Level)703*67e74705SXin Li void SDiagsRenderer::endDiagnostic(DiagOrStoredDiag D,
704*67e74705SXin Li                                    DiagnosticsEngine::Level Level) {
705*67e74705SXin Li   // Only end note diagnostics here, because we can't be sure when we've seen
706*67e74705SXin Li   // the last note associated with a non-note diagnostic.
707*67e74705SXin Li   if (Level == DiagnosticsEngine::Note)
708*67e74705SXin Li     Writer.ExitDiagBlock();
709*67e74705SXin Li }
710*67e74705SXin Li 
EmitCodeContext(SmallVectorImpl<CharSourceRange> & Ranges,ArrayRef<FixItHint> Hints,const SourceManager & SM)711*67e74705SXin Li void SDiagsWriter::EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges,
712*67e74705SXin Li                                    ArrayRef<FixItHint> Hints,
713*67e74705SXin Li                                    const SourceManager &SM) {
714*67e74705SXin Li   llvm::BitstreamWriter &Stream = State->Stream;
715*67e74705SXin Li   RecordData &Record = State->Record;
716*67e74705SXin Li   AbbreviationMap &Abbrevs = State->Abbrevs;
717*67e74705SXin Li 
718*67e74705SXin Li   // Emit Source Ranges.
719*67e74705SXin Li   for (ArrayRef<CharSourceRange>::iterator I = Ranges.begin(), E = Ranges.end();
720*67e74705SXin Li        I != E; ++I)
721*67e74705SXin Li     if (I->isValid())
722*67e74705SXin Li       EmitCharSourceRange(*I, SM);
723*67e74705SXin Li 
724*67e74705SXin Li   // Emit FixIts.
725*67e74705SXin Li   for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end();
726*67e74705SXin Li        I != E; ++I) {
727*67e74705SXin Li     const FixItHint &Fix = *I;
728*67e74705SXin Li     if (Fix.isNull())
729*67e74705SXin Li       continue;
730*67e74705SXin Li     Record.clear();
731*67e74705SXin Li     Record.push_back(RECORD_FIXIT);
732*67e74705SXin Li     AddCharSourceRangeToRecord(Fix.RemoveRange, Record, SM);
733*67e74705SXin Li     Record.push_back(Fix.CodeToInsert.size());
734*67e74705SXin Li     Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_FIXIT), Record,
735*67e74705SXin Li                               Fix.CodeToInsert);
736*67e74705SXin Li   }
737*67e74705SXin Li }
738*67e74705SXin Li 
emitCodeContext(SourceLocation Loc,DiagnosticsEngine::Level Level,SmallVectorImpl<CharSourceRange> & Ranges,ArrayRef<FixItHint> Hints,const SourceManager & SM)739*67e74705SXin Li void SDiagsRenderer::emitCodeContext(SourceLocation Loc,
740*67e74705SXin Li                                      DiagnosticsEngine::Level Level,
741*67e74705SXin Li                                      SmallVectorImpl<CharSourceRange> &Ranges,
742*67e74705SXin Li                                      ArrayRef<FixItHint> Hints,
743*67e74705SXin Li                                      const SourceManager &SM) {
744*67e74705SXin Li   Writer.EmitCodeContext(Ranges, Hints, SM);
745*67e74705SXin Li }
746*67e74705SXin Li 
emitNote(SourceLocation Loc,StringRef Message,const SourceManager * SM)747*67e74705SXin Li void SDiagsRenderer::emitNote(SourceLocation Loc, StringRef Message,
748*67e74705SXin Li                               const SourceManager *SM) {
749*67e74705SXin Li   Writer.EnterDiagBlock();
750*67e74705SXin Li   PresumedLoc PLoc = SM ? SM->getPresumedLoc(Loc) : PresumedLoc();
751*67e74705SXin Li   Writer.EmitDiagnosticMessage(Loc, PLoc, DiagnosticsEngine::Note,
752*67e74705SXin Li                                Message, SM, DiagOrStoredDiag());
753*67e74705SXin Li   Writer.ExitDiagBlock();
754*67e74705SXin Li }
755*67e74705SXin Li 
getMetaDiags()756*67e74705SXin Li DiagnosticsEngine *SDiagsWriter::getMetaDiags() {
757*67e74705SXin Li   // FIXME: It's slightly absurd to create a new diagnostics engine here, but
758*67e74705SXin Li   // the other options that are available today are worse:
759*67e74705SXin Li   //
760*67e74705SXin Li   // 1. Teach DiagnosticsConsumers to emit diagnostics to the engine they are a
761*67e74705SXin Li   //    part of. The DiagnosticsEngine would need to know not to send
762*67e74705SXin Li   //    diagnostics back to the consumer that failed. This would require us to
763*67e74705SXin Li   //    rework ChainedDiagnosticsConsumer and teach the engine about multiple
764*67e74705SXin Li   //    consumers, which is difficult today because most APIs interface with
765*67e74705SXin Li   //    consumers rather than the engine itself.
766*67e74705SXin Li   //
767*67e74705SXin Li   // 2. Pass a DiagnosticsEngine to SDiagsWriter on creation - this would need
768*67e74705SXin Li   //    to be distinct from the engine the writer was being added to and would
769*67e74705SXin Li   //    normally not be used.
770*67e74705SXin Li   if (!State->MetaDiagnostics) {
771*67e74705SXin Li     IntrusiveRefCntPtr<DiagnosticIDs> IDs(new DiagnosticIDs());
772*67e74705SXin Li     auto Client =
773*67e74705SXin Li         new TextDiagnosticPrinter(llvm::errs(), State->DiagOpts.get());
774*67e74705SXin Li     State->MetaDiagnostics = llvm::make_unique<DiagnosticsEngine>(
775*67e74705SXin Li         IDs, State->DiagOpts.get(), Client);
776*67e74705SXin Li   }
777*67e74705SXin Li   return State->MetaDiagnostics.get();
778*67e74705SXin Li }
779*67e74705SXin Li 
RemoveOldDiagnostics()780*67e74705SXin Li void SDiagsWriter::RemoveOldDiagnostics() {
781*67e74705SXin Li   if (!llvm::sys::fs::remove(State->OutputFile))
782*67e74705SXin Li     return;
783*67e74705SXin Li 
784*67e74705SXin Li   getMetaDiags()->Report(diag::warn_fe_serialized_diag_merge_failure);
785*67e74705SXin Li   // Disable merging child records, as whatever is in this file may be
786*67e74705SXin Li   // misleading.
787*67e74705SXin Li   MergeChildRecords = false;
788*67e74705SXin Li }
789*67e74705SXin Li 
finish()790*67e74705SXin Li void SDiagsWriter::finish() {
791*67e74705SXin Li   // The original instance is responsible for writing the file.
792*67e74705SXin Li   if (!OriginalInstance)
793*67e74705SXin Li     return;
794*67e74705SXin Li 
795*67e74705SXin Li   // Finish off any diagnostic we were in the process of emitting.
796*67e74705SXin Li   if (State->EmittedAnyDiagBlocks)
797*67e74705SXin Li     ExitDiagBlock();
798*67e74705SXin Li 
799*67e74705SXin Li   if (MergeChildRecords) {
800*67e74705SXin Li     if (!State->EmittedAnyDiagBlocks)
801*67e74705SXin Li       // We have no diagnostics of our own, so we can just leave the child
802*67e74705SXin Li       // process' output alone
803*67e74705SXin Li       return;
804*67e74705SXin Li 
805*67e74705SXin Li     if (llvm::sys::fs::exists(State->OutputFile))
806*67e74705SXin Li       if (SDiagsMerger(*this).mergeRecordsFromFile(State->OutputFile.c_str()))
807*67e74705SXin Li         getMetaDiags()->Report(diag::warn_fe_serialized_diag_merge_failure);
808*67e74705SXin Li   }
809*67e74705SXin Li 
810*67e74705SXin Li   std::error_code EC;
811*67e74705SXin Li   auto OS = llvm::make_unique<llvm::raw_fd_ostream>(State->OutputFile.c_str(),
812*67e74705SXin Li                                                     EC, llvm::sys::fs::F_None);
813*67e74705SXin Li   if (EC) {
814*67e74705SXin Li     getMetaDiags()->Report(diag::warn_fe_serialized_diag_failure)
815*67e74705SXin Li         << State->OutputFile << EC.message();
816*67e74705SXin Li     return;
817*67e74705SXin Li   }
818*67e74705SXin Li 
819*67e74705SXin Li   // Write the generated bitstream to "Out".
820*67e74705SXin Li   OS->write((char *)&State->Buffer.front(), State->Buffer.size());
821*67e74705SXin Li   OS->flush();
822*67e74705SXin Li }
823*67e74705SXin Li 
visitStartOfDiagnostic()824*67e74705SXin Li std::error_code SDiagsMerger::visitStartOfDiagnostic() {
825*67e74705SXin Li   Writer.EnterDiagBlock();
826*67e74705SXin Li   return std::error_code();
827*67e74705SXin Li }
828*67e74705SXin Li 
visitEndOfDiagnostic()829*67e74705SXin Li std::error_code SDiagsMerger::visitEndOfDiagnostic() {
830*67e74705SXin Li   Writer.ExitDiagBlock();
831*67e74705SXin Li   return std::error_code();
832*67e74705SXin Li }
833*67e74705SXin Li 
834*67e74705SXin Li std::error_code
visitSourceRangeRecord(const serialized_diags::Location & Start,const serialized_diags::Location & End)835*67e74705SXin Li SDiagsMerger::visitSourceRangeRecord(const serialized_diags::Location &Start,
836*67e74705SXin Li                                      const serialized_diags::Location &End) {
837*67e74705SXin Li   RecordData::value_type Record[] = {
838*67e74705SXin Li       RECORD_SOURCE_RANGE, FileLookup[Start.FileID], Start.Line, Start.Col,
839*67e74705SXin Li       Start.Offset, FileLookup[End.FileID], End.Line, End.Col, End.Offset};
840*67e74705SXin Li   Writer.State->Stream.EmitRecordWithAbbrev(
841*67e74705SXin Li       Writer.State->Abbrevs.get(RECORD_SOURCE_RANGE), Record);
842*67e74705SXin Li   return std::error_code();
843*67e74705SXin Li }
844*67e74705SXin Li 
visitDiagnosticRecord(unsigned Severity,const serialized_diags::Location & Location,unsigned Category,unsigned Flag,StringRef Message)845*67e74705SXin Li std::error_code SDiagsMerger::visitDiagnosticRecord(
846*67e74705SXin Li     unsigned Severity, const serialized_diags::Location &Location,
847*67e74705SXin Li     unsigned Category, unsigned Flag, StringRef Message) {
848*67e74705SXin Li   RecordData::value_type Record[] = {
849*67e74705SXin Li       RECORD_DIAG, Severity, FileLookup[Location.FileID], Location.Line,
850*67e74705SXin Li       Location.Col, Location.Offset, CategoryLookup[Category],
851*67e74705SXin Li       Flag ? DiagFlagLookup[Flag] : 0, Message.size()};
852*67e74705SXin Li 
853*67e74705SXin Li   Writer.State->Stream.EmitRecordWithBlob(
854*67e74705SXin Li       Writer.State->Abbrevs.get(RECORD_DIAG), Record, Message);
855*67e74705SXin Li   return std::error_code();
856*67e74705SXin Li }
857*67e74705SXin Li 
858*67e74705SXin Li std::error_code
visitFixitRecord(const serialized_diags::Location & Start,const serialized_diags::Location & End,StringRef Text)859*67e74705SXin Li SDiagsMerger::visitFixitRecord(const serialized_diags::Location &Start,
860*67e74705SXin Li                                const serialized_diags::Location &End,
861*67e74705SXin Li                                StringRef Text) {
862*67e74705SXin Li   RecordData::value_type Record[] = {RECORD_FIXIT, FileLookup[Start.FileID],
863*67e74705SXin Li                                      Start.Line, Start.Col, Start.Offset,
864*67e74705SXin Li                                      FileLookup[End.FileID], End.Line, End.Col,
865*67e74705SXin Li                                      End.Offset, Text.size()};
866*67e74705SXin Li 
867*67e74705SXin Li   Writer.State->Stream.EmitRecordWithBlob(
868*67e74705SXin Li       Writer.State->Abbrevs.get(RECORD_FIXIT), Record, Text);
869*67e74705SXin Li   return std::error_code();
870*67e74705SXin Li }
871*67e74705SXin Li 
visitFilenameRecord(unsigned ID,unsigned Size,unsigned Timestamp,StringRef Name)872*67e74705SXin Li std::error_code SDiagsMerger::visitFilenameRecord(unsigned ID, unsigned Size,
873*67e74705SXin Li                                                   unsigned Timestamp,
874*67e74705SXin Li                                                   StringRef Name) {
875*67e74705SXin Li   FileLookup[ID] = Writer.getEmitFile(Name.str().c_str());
876*67e74705SXin Li   return std::error_code();
877*67e74705SXin Li }
878*67e74705SXin Li 
visitCategoryRecord(unsigned ID,StringRef Name)879*67e74705SXin Li std::error_code SDiagsMerger::visitCategoryRecord(unsigned ID, StringRef Name) {
880*67e74705SXin Li   CategoryLookup[ID] = Writer.getEmitCategory(ID);
881*67e74705SXin Li   return std::error_code();
882*67e74705SXin Li }
883*67e74705SXin Li 
visitDiagFlagRecord(unsigned ID,StringRef Name)884*67e74705SXin Li std::error_code SDiagsMerger::visitDiagFlagRecord(unsigned ID, StringRef Name) {
885*67e74705SXin Li   DiagFlagLookup[ID] = Writer.getEmitDiagnosticFlag(Name);
886*67e74705SXin Li   return std::error_code();
887*67e74705SXin Li }
888