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;
118 std::error_code adjustSourceLocFilename(RecordData &
Record,
119 unsigned int offset);
121 void adjustAbbrevID(RecordData &
Record, AbbrevLookup &Lookup,
124 void writeRecordWithAbbrev(
unsigned ID, RecordData &
Record);
126 void writeRecordWithBlob(
unsigned ID, RecordData &
Record, StringRef Blob);
130 friend class SDiagsRenderer;
131 friend class SDiagsMerger;
135 explicit SDiagsWriter(std::shared_ptr<SharedState> State)
137 State(std::move(State)) {}
140 SDiagsWriter(StringRef
File, DiagnosticOptions &Diags,
bool MergeChildRecords)
142 MergeChildRecords(MergeChildRecords),
143 State(std::make_shared<SharedState>(
File, Diags)) {
144 if (MergeChildRecords)
145 RemoveOldDiagnostics();
149 ~SDiagsWriter()
override {}
152 const Diagnostic &Info)
override;
154 void BeginSourceFile(
const LangOptions &LO,
const Preprocessor *PP)
override {
158 void finish()
override;
162 DiagnosticsEngine *getMetaDiags();
167 void RemoveOldDiagnostics();
173 void EmitBlockInfoBlock();
176 void EmitMetaBlock();
179 void EnterDiagBlock();
182 void ExitDiagBlock();
185 void EmitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
190 void EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges,
191 ArrayRef<FixItHint> Hints,
192 const SourceManager &
SM);
195 void EmitCharSourceRange(CharSourceRange R,
const SourceManager &
SM);
198 unsigned getEmitCategory(
unsigned category = 0);
202 const Diagnostic *
Diag =
nullptr);
204 unsigned getEmitDiagnosticFlag(StringRef DiagName);
207 unsigned getEmitFile(
const char *Filename);
210 void AddLocToRecord(FullSourceLoc Loc, PresumedLoc PLoc,
211 RecordDataImpl &
Record,
unsigned TokSize = 0);
214 void AddLocToRecord(FullSourceLoc Loc, RecordDataImpl &
Record,
215 unsigned TokSize = 0) {
221 void AddCharSourceRangeToRecord(CharSourceRange R, RecordDataImpl &
Record,
222 const SourceManager &
SM);
226 const LangOptions *LangOpts;
230 bool OriginalInstance;
234 bool MergeChildRecords;
237 bool IsFinishing =
false;
242 SharedState(StringRef
File, DiagnosticOptions &DiagOpts)
243 : DiagOpts(DiagOpts), Stream(Buffer), OutputFile(
File.str()),
244 EmittedAnyDiagBlocks(
false) {}
247 DiagnosticOptions DiagOpts;
250 SmallString<1024> Buffer;
253 llvm::BitstreamWriter Stream;
256 std::string OutputFile;
259 AbbreviationMap Abbrevs;
265 SmallString<256> diagBuf;
268 llvm::DenseSet<unsigned> Categories;
271 llvm::DenseMap<const char *, unsigned> Files;
273 typedef llvm::DenseMap<const void *, std::pair<unsigned, StringRef> >
277 DiagFlagsTy DiagFlags;
282 bool EmittedAnyDiagBlocks;
285 std::unique_ptr<DiagnosticsEngine> MetaDiagnostics;
289 std::shared_ptr<SharedState> State;
295std::unique_ptr<DiagnosticConsumer>
create(StringRef OutputFile,
297 bool MergeChildRecords) {
298 return std::make_unique<SDiagsWriter>(OutputFile, DiagOpts,
311 llvm::BitstreamWriter &Stream,
315 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID,
Record);
318 if (!Name || Name[0] == 0)
324 Record.push_back(*Name++);
326 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME,
Record);
331 llvm::BitstreamWriter &Stream,
337 Record.push_back(*Name++);
339 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME,
Record);
343 RecordDataImpl &
Record,
unsigned TokSize) {
346 Record.push_back((
unsigned)0);
347 Record.push_back((
unsigned)0);
348 Record.push_back((
unsigned)0);
349 Record.push_back((
unsigned)0);
359void SDiagsWriter::AddCharSourceRangeToRecord(CharSourceRange Range,
361 const SourceManager &
SM) {
363 unsigned TokSize = 0;
364 if (
Range.isTokenRange())
368 AddLocToRecord(FullSourceLoc(
Range.getEnd(),
SM),
Record, TokSize);
371unsigned SDiagsWriter::getEmitFile(
const char *
FileName){
375 unsigned &entry = State->Files[
FileName];
380 entry = State->Files.size();
390void SDiagsWriter::EmitCharSourceRange(CharSourceRange R,
391 const SourceManager &
SM) {
392 State->Record.clear();
394 AddCharSourceRangeToRecord(R, State->Record,
SM);
400void SDiagsWriter::EmitPreamble() {
402 State->Stream.Emit((
unsigned)
'D', 8);
403 State->Stream.Emit((
unsigned)
'I', 8);
404 State->Stream.Emit((
unsigned)
'A', 8);
405 State->Stream.Emit((
unsigned)
'G', 8);
407 EmitBlockInfoBlock();
412 using namespace llvm;
413 Abbrev.Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
414 Abbrev.Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
415 Abbrev.Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
416 Abbrev.Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
424void SDiagsWriter::EmitBlockInfoBlock() {
425 State->Stream.EnterBlockInfoBlock();
427 using namespace llvm;
428 llvm::BitstreamWriter &Stream = State->Stream;
429 RecordData &
Record = State->Record;
430 AbbreviationMap &Abbrevs = State->Abbrevs;
438 auto Abbrev = std::make_shared<BitCodeAbbrev>();
440 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
456 Abbrev = std::make_shared<BitCodeAbbrev>();
458 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3));
460 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
461 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
462 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16));
463 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
467 Abbrev = std::make_shared<BitCodeAbbrev>();
469 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16));
470 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8));
471 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
475 Abbrev = std::make_shared<BitCodeAbbrev>();
479 Stream.EmitBlockInfoAbbrev(
BLOCK_DIAG, Abbrev));
482 Abbrev = std::make_shared<BitCodeAbbrev>();
484 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
485 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16));
486 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
491 Abbrev = std::make_shared<BitCodeAbbrev>();
493 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
494 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
495 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
496 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16));
497 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
502 Abbrev = std::make_shared<BitCodeAbbrev>();
505 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16));
506 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
513void SDiagsWriter::EmitMetaBlock() {
514 llvm::BitstreamWriter &Stream = State->Stream;
515 AbbreviationMap &Abbrevs = State->Abbrevs;
523unsigned SDiagsWriter::getEmitCategory(
unsigned int category) {
524 if (!State->Categories.insert(category).second)
538 const Diagnostic *
Diag) {
543 Diag->getDiags()->getDiagnosticIDs()->getWarningOptionForDiag(
545 return getEmitDiagnosticFlag(FlagName);
548unsigned SDiagsWriter::getEmitDiagnosticFlag(StringRef FlagName) {
549 if (FlagName.empty())
554 const void *data = FlagName.data();
555 std::pair<unsigned, StringRef> &entry = State->DiagFlags[data];
556 if (entry.first == 0) {
557 entry.first = State->DiagFlags.size();
558 entry.second = FlagName;
571 const Diagnostic &Info) {
572 assert(!IsFinishing &&
573 "Received a diagnostic after we've already started teardown.");
575 SmallString<256> diagnostic;
577 getMetaDiags()->Report(
578 diag::warn_fe_serialized_diag_failure_during_finalization)
587 if (State->EmittedAnyDiagBlocks)
591 State->EmittedAnyDiagBlocks =
true;
595 State->diagBuf.clear();
608 EmitDiagnosticMessage(FullSourceLoc(), PresumedLoc(), DiagLevel,
609 State->diagBuf, &Info);
618 "Unexpected diagnostic with valid location outside of a source file");
619 SDiagsRenderer Renderer(*
this, *LangOpts, State->DiagOpts);
620 Renderer.emitDiagnostic(
627#define CASE(X) case DiagnosticsEngine::X: return serialized_diags::X;
637 llvm_unreachable(
"invalid diagnostic level");
640void SDiagsWriter::EmitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
644 llvm::BitstreamWriter &Stream = State->Stream;
645 RecordData &
Record = State->Record;
646 AbbreviationMap &Abbrevs = State->Abbrevs;
652 AddLocToRecord(Loc, PLoc,
Record);
654 if (
const Diagnostic *Info = dyn_cast_if_present<const Diagnostic *>(D)) {
657 Record.push_back(getEmitCategory(DiagID));
659 Record.push_back(getEmitDiagnosticFlag(
Level, Info));
661 Record.push_back(getEmitCategory());
669void SDiagsRenderer::emitDiagnosticMessage(
671 StringRef Message, ArrayRef<clang::CharSourceRange> Ranges,
673 Writer.EmitDiagnosticMessage(Loc, PLoc,
Level, Message, D);
676void SDiagsWriter::EnterDiagBlock() {
680void SDiagsWriter::ExitDiagBlock() {
681 State->Stream.ExitBlock();
687 Writer.EnterDiagBlock();
695 Writer.ExitDiagBlock();
698void SDiagsWriter::EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges,
699 ArrayRef<FixItHint> Hints,
700 const SourceManager &
SM) {
701 llvm::BitstreamWriter &Stream = State->Stream;
702 RecordData &
Record = State->Record;
703 AbbreviationMap &Abbrevs = State->Abbrevs;
706 for (ArrayRef<CharSourceRange>::iterator I = Ranges.begin(), E = Ranges.end();
709 EmitCharSourceRange(*I,
SM);
712 for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end();
714 const FixItHint &Fix = *I;
726void SDiagsRenderer::emitCodeContext(FullSourceLoc Loc,
728 SmallVectorImpl<CharSourceRange> &Ranges,
729 ArrayRef<FixItHint> Hints) {
730 Writer.EmitCodeContext(Ranges, Hints, Loc.
getManager());
733void SDiagsRenderer::emitNote(FullSourceLoc Loc, StringRef Message) {
734 Writer.EnterDiagBlock();
738 Writer.ExitDiagBlock();
741DiagnosticsEngine *SDiagsWriter::getMetaDiags() {
755 if (!State->MetaDiagnostics) {
756 auto Client =
new TextDiagnosticPrinter(llvm::errs(), State->DiagOpts);
757 State->MetaDiagnostics = std::make_unique<DiagnosticsEngine>(
760 return State->MetaDiagnostics.get();
763void SDiagsWriter::RemoveOldDiagnostics() {
764 if (!llvm::sys::fs::remove(State->OutputFile))
767 getMetaDiags()->Report(diag::warn_fe_serialized_diag_merge_failure);
770 MergeChildRecords =
false;
773void SDiagsWriter::finish() {
774 assert(!IsFinishing);
778 if (!OriginalInstance)
782 if (State->EmittedAnyDiagBlocks)
785 if (MergeChildRecords) {
786 if (!State->EmittedAnyDiagBlocks)
791 if (llvm::sys::fs::exists(State->OutputFile))
792 if (SDiagsMerger(*this).mergeRecordsFromFile(State->OutputFile.c_str()))
793 getMetaDiags()->Report(diag::warn_fe_serialized_diag_merge_failure);
797 auto OS = std::make_unique<llvm::raw_fd_ostream>(State->OutputFile.c_str(),
798 EC, llvm::sys::fs::OF_None);
800 getMetaDiags()->Report(diag::warn_fe_serialized_diag_failure)
801 << State->OutputFile << EC.message();
807 OS->write((
char *)&State->Buffer.front(), State->Buffer.size());
810 assert(!
OS->has_error());
811 if (
OS->has_error()) {
812 getMetaDiags()->Report(diag::warn_fe_serialized_diag_failure)
813 << State->OutputFile <<
OS->error().message();
818std::error_code SDiagsMerger::visitStartOfDiagnostic() {
819 Writer.EnterDiagBlock();
820 return std::error_code();
823std::error_code SDiagsMerger::visitEndOfDiagnostic() {
824 Writer.ExitDiagBlock();
825 return std::error_code();
829SDiagsMerger::visitSourceRangeRecord(
const serialized_diags::Location &Start,
830 const serialized_diags::Location &End) {
831 RecordData::value_type
Record[] = {
834 Writer.State->Stream.EmitRecordWithAbbrev(
836 return std::error_code();
839std::error_code SDiagsMerger::visitDiagnosticRecord(
840 unsigned Severity,
const serialized_diags::Location &Location,
841 unsigned Category,
unsigned Flag, StringRef Message) {
842 RecordData::value_type
Record[] = {
844 Location.
Col, Location.
Offset, CategoryLookup[Category],
845 Flag ? DiagFlagLookup[Flag] : 0,
Message.size()};
847 Writer.State->Stream.EmitRecordWithBlob(
849 return std::error_code();
853SDiagsMerger::visitFixitRecord(
const serialized_diags::Location &Start,
854 const serialized_diags::Location &End,
861 Writer.State->Stream.EmitRecordWithBlob(
863 return std::error_code();
866std::error_code SDiagsMerger::visitFilenameRecord(
unsigned ID,
unsigned Size,
869 FileLookup[
ID] = Writer.getEmitFile(Name.str().c_str());
870 return std::error_code();
873std::error_code SDiagsMerger::visitCategoryRecord(
unsigned ID, StringRef Name) {
874 CategoryLookup[
ID] = Writer.getEmitCategory(ID);
875 return std::error_code();
878std::error_code SDiagsMerger::visitDiagFlagRecord(
unsigned ID, StringRef Name) {
879 DiagFlagLookup[
ID] = Writer.getEmitDiagnosticFlag(Name);
880 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.
The JSON file list parser is used to communicate input to InstallAPI.
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.