19#include "llvm/ADT/DenseSet.h"
20#include "llvm/ADT/StringRef.h"
21#include "llvm/Bitstream/BitCodes.h"
22#include "llvm/Support/FileSystem.h"
23#include "llvm/Support/raw_ostream.h"
31class AbbreviationMap {
32 llvm::DenseMap<unsigned, unsigned> Abbrevs;
36 void set(
unsigned recordID,
unsigned abbrevID) {
37 assert(!Abbrevs.contains(recordID) &&
"Abbreviation already set.");
38 Abbrevs[recordID] = abbrevID;
41 unsigned get(
unsigned recordID) {
42 assert(Abbrevs.contains(recordID) &&
"Abbreviation not set.");
43 return Abbrevs[recordID];
56 SDiagsRenderer(SDiagsWriter &Writer,
const LangOptions &LangOpts,
57 DiagnosticOptions &DiagOpts)
58 : DiagnosticNoteRenderer(LangOpts, DiagOpts), Writer(Writer) {}
60 ~SDiagsRenderer()
override {}
63 void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
65 ArrayRef<CharSourceRange> Ranges,
68 void emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
70 ArrayRef<CharSourceRange> Ranges)
override {}
72 void emitNote(FullSourceLoc Loc, StringRef Message)
override;
75 SmallVectorImpl<CharSourceRange> &Ranges,
76 ArrayRef<FixItHint> Hints)
override;
84typedef llvm::DenseMap<unsigned, unsigned> AbbrevLookup;
88 AbbrevLookup FileLookup;
89 AbbrevLookup CategoryLookup;
90 AbbrevLookup DiagFlagLookup;
93 SDiagsMerger(SDiagsWriter &Writer) : Writer(Writer) {}
95 std::error_code mergeRecordsFromFile(
const char *
File) {
96 return readDiagnostics(
File);
100 std::error_code visitStartOfDiagnostic()
override;
101 std::error_code visitEndOfDiagnostic()
override;
102 std::error_code visitCategoryRecord(
unsigned ID, StringRef Name)
override;
103 std::error_code visitDiagFlagRecord(
unsigned ID, StringRef Name)
override;
104 std::error_code visitDiagnosticRecord(
105 unsigned Severity,
const serialized_diags::Location &Location,
106 unsigned Category,
unsigned Flag, StringRef Message)
override;
107 std::error_code visitFilenameRecord(
unsigned ID,
unsigned Size,
109 StringRef Name)
override;
110 std::error_code visitFixitRecord(
const serialized_diags::Location &Start,
111 const serialized_diags::Location &End,
112 StringRef CodeToInsert)
override;
114 visitSourceRangeRecord(
const serialized_diags::Location &Start,
115 const serialized_diags::Location &End)
override;
119 friend class SDiagsRenderer;
120 friend class SDiagsMerger;
124 explicit SDiagsWriter(std::shared_ptr<SharedState> State)
126 State(std::move(State)) {}
129 SDiagsWriter(StringRef
File, DiagnosticOptions &Diags,
bool MergeChildRecords)
131 MergeChildRecords(MergeChildRecords),
132 State(std::make_shared<SharedState>(
File, Diags)) {
133 if (MergeChildRecords)
134 RemoveOldDiagnostics();
138 ~SDiagsWriter()
override;
141 const Diagnostic &Info)
override;
143 void BeginSourceFile(
const LangOptions &LO,
const Preprocessor *PP)
override {
149 DiagnosticsEngine *getMetaDiags();
154 void RemoveOldDiagnostics();
160 void EmitBlockInfoBlock();
163 void EmitMetaBlock();
166 void EnterDiagBlock();
169 void ExitDiagBlock();
172 void EmitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
177 void EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges,
178 ArrayRef<FixItHint> Hints,
179 const SourceManager &SM);
182 void EmitCharSourceRange(CharSourceRange R,
const SourceManager &SM);
185 unsigned getEmitCategory(
unsigned category = 0);
189 const Diagnostic *
Diag =
nullptr);
191 unsigned getEmitDiagnosticFlag(StringRef DiagName);
194 unsigned getEmitFile(
const char *Filename);
197 void AddLocToRecord(FullSourceLoc Loc, PresumedLoc PLoc,
198 RecordDataImpl &
Record,
unsigned TokSize = 0);
201 void AddLocToRecord(FullSourceLoc Loc, RecordDataImpl &
Record,
202 unsigned TokSize = 0) {
208 void AddCharSourceRangeToRecord(CharSourceRange R, RecordDataImpl &
Record,
209 const SourceManager &SM);
213 const LangOptions *LangOpts;
217 bool OriginalInstance;
221 bool MergeChildRecords;
224 bool IsFinishing =
false;
229 SharedState(StringRef
File, DiagnosticOptions &DiagOpts)
230 : DiagOpts(DiagOpts), Stream(Buffer), OutputFile(
File.str()),
231 EmittedAnyDiagBlocks(
false) {}
234 DiagnosticOptions DiagOpts;
237 SmallString<1024> Buffer;
240 llvm::BitstreamWriter Stream;
243 std::string OutputFile;
246 AbbreviationMap Abbrevs;
252 SmallString<256> diagBuf;
255 llvm::DenseSet<unsigned> Categories;
258 llvm::DenseMap<const char *, unsigned> Files;
260 typedef llvm::DenseMap<const void *, std::pair<unsigned, StringRef> >
264 DiagFlagsTy DiagFlags;
269 bool EmittedAnyDiagBlocks;
272 std::unique_ptr<DiagnosticsEngine> MetaDiagnostics;
276 std::shared_ptr<SharedState> State;
282std::unique_ptr<DiagnosticConsumer>
create(StringRef OutputFile,
284 bool MergeChildRecords) {
285 return std::make_unique<SDiagsWriter>(OutputFile, DiagOpts,
298 llvm::BitstreamWriter &Stream,
302 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID,
Record);
305 if (!Name || Name[0] == 0)
311 Record.push_back(*Name++);
313 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME,
Record);
318 llvm::BitstreamWriter &Stream,
324 Record.push_back(*Name++);
326 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME,
Record);
330 RecordDataImpl &
Record,
unsigned TokSize) {
333 Record.push_back((
unsigned)0);
334 Record.push_back((
unsigned)0);
335 Record.push_back((
unsigned)0);
336 Record.push_back((
unsigned)0);
346void SDiagsWriter::AddCharSourceRangeToRecord(CharSourceRange Range,
348 const SourceManager &SM) {
349 AddLocToRecord(FullSourceLoc(
Range.getBegin(), SM),
Record);
350 unsigned TokSize = 0;
351 if (
Range.isTokenRange())
355 AddLocToRecord(FullSourceLoc(
Range.getEnd(), SM),
Record, TokSize);
358unsigned SDiagsWriter::getEmitFile(
const char *
FileName){
362 unsigned &entry = State->Files[
FileName];
367 entry = State->Files.size();
377void SDiagsWriter::EmitCharSourceRange(CharSourceRange R,
378 const SourceManager &SM) {
379 State->Record.clear();
381 AddCharSourceRangeToRecord(R, State->Record, SM);
387void SDiagsWriter::EmitPreamble() {
389 State->Stream.Emit((
unsigned)
'D', 8);
390 State->Stream.Emit((
unsigned)
'I', 8);
391 State->Stream.Emit((
unsigned)
'A', 8);
392 State->Stream.Emit((
unsigned)
'G', 8);
394 EmitBlockInfoBlock();
399 using namespace llvm;
400 Abbrev.Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
401 Abbrev.Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
402 Abbrev.Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
403 Abbrev.Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
411void SDiagsWriter::EmitBlockInfoBlock() {
412 State->Stream.EnterBlockInfoBlock();
414 using namespace llvm;
415 llvm::BitstreamWriter &Stream = State->Stream;
416 RecordData &
Record = State->Record;
417 AbbreviationMap &Abbrevs = State->Abbrevs;
425 auto Abbrev = std::make_shared<BitCodeAbbrev>();
427 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
443 Abbrev = std::make_shared<BitCodeAbbrev>();
445 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3));
447 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
448 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
449 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16));
450 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
454 Abbrev = std::make_shared<BitCodeAbbrev>();
456 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16));
457 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8));
458 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
462 Abbrev = std::make_shared<BitCodeAbbrev>();
466 Stream.EmitBlockInfoAbbrev(
BLOCK_DIAG, Abbrev));
469 Abbrev = std::make_shared<BitCodeAbbrev>();
471 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
472 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16));
473 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
478 Abbrev = std::make_shared<BitCodeAbbrev>();
480 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
481 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
482 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
483 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16));
484 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
489 Abbrev = std::make_shared<BitCodeAbbrev>();
492 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16));
493 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
500void SDiagsWriter::EmitMetaBlock() {
501 llvm::BitstreamWriter &Stream = State->Stream;
502 AbbreviationMap &Abbrevs = State->Abbrevs;
510unsigned SDiagsWriter::getEmitCategory(
unsigned int category) {
511 if (!State->Categories.insert(category).second)
525 const Diagnostic *
Diag) {
530 Diag->getDiags()->getDiagnosticIDs()->getWarningOptionForDiag(
532 return getEmitDiagnosticFlag(FlagName);
535unsigned SDiagsWriter::getEmitDiagnosticFlag(StringRef FlagName) {
536 if (FlagName.empty())
541 const void *data = FlagName.data();
542 std::pair<unsigned, StringRef> &entry = State->DiagFlags[data];
543 if (entry.first == 0) {
544 entry.first = State->DiagFlags.size();
545 entry.second = FlagName;
558 const Diagnostic &Info) {
559 assert(!IsFinishing &&
560 "Received a diagnostic after we've already started teardown.");
562 SmallString<256> diagnostic;
564 getMetaDiags()->Report(
565 diag::warn_fe_serialized_diag_failure_during_finalization)
574 if (State->EmittedAnyDiagBlocks)
578 State->EmittedAnyDiagBlocks =
true;
582 State->diagBuf.clear();
595 EmitDiagnosticMessage(FullSourceLoc(), PresumedLoc(), DiagLevel,
596 State->diagBuf, &Info);
605 "Unexpected diagnostic with valid location outside of a source file");
606 SDiagsRenderer Renderer(*
this, *LangOpts, State->DiagOpts);
607 Renderer.emitDiagnostic(
614#define CASE(X) case DiagnosticsEngine::X: return serialized_diags::X;
624 llvm_unreachable(
"invalid diagnostic level");
627void SDiagsWriter::EmitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
631 llvm::BitstreamWriter &Stream = State->Stream;
632 RecordData &
Record = State->Record;
633 AbbreviationMap &Abbrevs = State->Abbrevs;
639 AddLocToRecord(Loc, PLoc,
Record);
641 if (
const Diagnostic *Info = dyn_cast_if_present<const Diagnostic *>(D)) {
644 Record.push_back(getEmitCategory(DiagID));
646 Record.push_back(getEmitDiagnosticFlag(
Level, Info));
648 Record.push_back(getEmitCategory());
656void SDiagsRenderer::emitDiagnosticMessage(
658 StringRef Message, ArrayRef<clang::CharSourceRange> Ranges,
660 Writer.EmitDiagnosticMessage(Loc, PLoc,
Level, Message, D);
663void SDiagsWriter::EnterDiagBlock() {
667void SDiagsWriter::ExitDiagBlock() {
668 State->Stream.ExitBlock();
674 Writer.EnterDiagBlock();
682 Writer.ExitDiagBlock();
685void SDiagsWriter::EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges,
686 ArrayRef<FixItHint> Hints,
687 const SourceManager &SM) {
688 llvm::BitstreamWriter &Stream = State->Stream;
689 RecordData &
Record = State->Record;
690 AbbreviationMap &Abbrevs = State->Abbrevs;
693 for (ArrayRef<CharSourceRange>::iterator I = Ranges.begin(), E = Ranges.end();
696 EmitCharSourceRange(*I, SM);
699 for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end();
701 const FixItHint &Fix = *I;
713void SDiagsRenderer::emitCodeContext(FullSourceLoc Loc,
715 SmallVectorImpl<CharSourceRange> &Ranges,
716 ArrayRef<FixItHint> Hints) {
717 Writer.EmitCodeContext(Ranges, Hints, Loc.
getManager());
720void SDiagsRenderer::emitNote(FullSourceLoc Loc, StringRef Message) {
721 Writer.EnterDiagBlock();
725 Writer.ExitDiagBlock();
728DiagnosticsEngine *SDiagsWriter::getMetaDiags() {
742 if (!State->MetaDiagnostics) {
743 auto Client =
new TextDiagnosticPrinter(llvm::errs(), State->DiagOpts);
744 State->MetaDiagnostics = std::make_unique<DiagnosticsEngine>(
747 return State->MetaDiagnostics.get();
750void SDiagsWriter::RemoveOldDiagnostics() {
751 if (!llvm::sys::fs::remove(State->OutputFile))
754 getMetaDiags()->Report(diag::warn_fe_serialized_diag_merge_failure);
757 MergeChildRecords =
false;
760SDiagsWriter::~SDiagsWriter() {
761 assert(!IsFinishing);
765 if (!OriginalInstance)
769 if (State->EmittedAnyDiagBlocks)
772 if (MergeChildRecords) {
773 if (!State->EmittedAnyDiagBlocks)
778 if (llvm::sys::fs::exists(State->OutputFile))
779 if (SDiagsMerger(*this).mergeRecordsFromFile(State->OutputFile.c_str()))
780 getMetaDiags()->Report(diag::warn_fe_serialized_diag_merge_failure);
784 auto OS = std::make_unique<llvm::raw_fd_ostream>(State->OutputFile.c_str(),
785 EC, llvm::sys::fs::OF_None);
787 getMetaDiags()->Report(diag::warn_fe_serialized_diag_failure)
788 << State->OutputFile << EC.message();
794 OS->write((
char *)&State->Buffer.front(), State->Buffer.size());
797 assert(!
OS->has_error());
798 if (
OS->has_error()) {
799 getMetaDiags()->Report(diag::warn_fe_serialized_diag_failure)
800 << State->OutputFile <<
OS->error().message();
805std::error_code SDiagsMerger::visitStartOfDiagnostic() {
806 Writer.EnterDiagBlock();
807 return std::error_code();
810std::error_code SDiagsMerger::visitEndOfDiagnostic() {
811 Writer.ExitDiagBlock();
812 return std::error_code();
816SDiagsMerger::visitSourceRangeRecord(
const serialized_diags::Location &Start,
817 const serialized_diags::Location &End) {
818 RecordData::value_type
Record[] = {
821 Writer.State->Stream.EmitRecordWithAbbrev(
823 return std::error_code();
826std::error_code SDiagsMerger::visitDiagnosticRecord(
827 unsigned Severity,
const serialized_diags::Location &Location,
828 unsigned Category,
unsigned Flag, StringRef Message) {
829 RecordData::value_type
Record[] = {
831 Location.
Col, Location.
Offset, CategoryLookup[Category],
832 Flag ? DiagFlagLookup[Flag] : 0,
Message.size()};
834 Writer.State->Stream.EmitRecordWithBlob(
836 return std::error_code();
840SDiagsMerger::visitFixitRecord(
const serialized_diags::Location &Start,
841 const serialized_diags::Location &End,
848 Writer.State->Stream.EmitRecordWithBlob(
850 return std::error_code();
853std::error_code SDiagsMerger::visitFilenameRecord(
unsigned ID,
unsigned Size,
856 FileLookup[
ID] = Writer.getEmitFile(Name.str().c_str());
857 return std::error_code();
860std::error_code SDiagsMerger::visitCategoryRecord(
unsigned ID, StringRef Name) {
861 CategoryLookup[
ID] = Writer.getEmitCategory(ID);
862 return std::error_code();
865std::error_code SDiagsMerger::visitDiagFlagRecord(
unsigned ID, StringRef Name) {
866 DiagFlagLookup[
ID] = Writer.getEmitDiagnosticFlag(Name);
867 return std::error_code();
Defines the Diagnostic-related interfaces.
#define CASE(LEN, FIRST, THIRD, NAME)
static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)
Produce a diagnostic highlighting some portion of a literal.
llvm::MachO::Record Record
static void AddRangeLocationAbbrev(llvm::BitCodeAbbrev &Abbrev)
static void EmitBlockID(unsigned ID, const char *Name, llvm::BitstreamWriter &Stream, RecordDataImpl &Record)
Emits a block ID in the BLOCKINFO block.
static void EmitRecordID(unsigned ID, const char *Name, llvm::BitstreamWriter &Stream, RecordDataImpl &Record)
Emits a record ID in the BLOCKINFO block.
static serialized_diags::Level getStableLevel(DiagnosticsEngine::Level Level)
static void AddSourceLocationAbbrev(llvm::BitCodeAbbrev &Abbrev)
Defines the SourceManager interface.
Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...
static StringRef getCategoryNameFromID(unsigned CategoryID)
Given a category ID, return the name of the category.
static unsigned getCategoryNumberForDiag(unsigned DiagID)
Return the category number that a specified DiagID belongs to, or 0 if no category.
static llvm::IntrusiveRefCntPtr< DiagnosticIDs > create()
Subclass of DiagnosticRender that turns all subdiagostics into explicit notes.
Options for controlling the compiler diagnostics engine.
const SourceLocation & getLocation() const
void FormatDiagnostic(SmallVectorImpl< char > &OutStr) const
Format this diagnostic into a string, substituting the formal arguments into the %0 slots.
SourceManager & getSourceManager() const
ArrayRef< FixItHint > getFixItHints() const
bool hasSourceManager() const
ArrayRef< CharSourceRange > getRanges() const
Return an array reference for this diagnostic's ranges.
Level
The level of the diagnostic, after it has been through mapping.
CharSourceRange RemoveRange
Code that should be replaced to correct the error.
std::string CodeToInsert
The actual code to insert at the insertion location, as a string.
A SourceLocation and its associated SourceManager.
unsigned getFileOffset() const
PresumedLoc getPresumedLoc(bool UseLineDirectives=true) const
bool hasManager() const
Checks whether the SourceManager is present.
const SourceManager & getManager() const
static unsigned MeasureTokenLength(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
MeasureTokenLength - Relex the token at the specified location and return its length in bytes in the ...
Represents an unpacked "presumed" location which can be presented to the user.
unsigned getColumn() const
Return the presumed column number of this location.
const char * getFilename() const
Return the presumed filename of this location.
unsigned getLine() const
Return the presumed line number of this location.
bool isInvalid() const
Return true if this object is invalid or uninitialized.
A base class that handles reading serialized diagnostics from a file.
Severity
Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs to either Ignore (nothing),...
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
std::unique_ptr< DiagnosticConsumer > create(StringRef OutputFile, DiagnosticOptions &DiagOpts, bool MergeChildRecords=false)
Returns a DiagnosticConsumer that serializes diagnostics to a bitcode file.
@ BLOCK_DIAG
The this block acts as a container for all the information for a specific diagnostic.
@ BLOCK_META
A top-level block which represents any meta data associated with the diagostics, including versioning...
Level
A stable version of DiagnosticIDs::Level.
Top level wrappers for InstallAPI frontend operations.
llvm::PointerUnion< const Diagnostic *, const StoredDiagnostic * > DiagOrStoredDiag
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
Diagnostic wrappers for TextAPI types for error reporting.