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