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