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,
60 ~SDiagsRenderer()
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) {
106 unsigned Category,
unsigned Flag, StringRef Message)
override;
109 StringRef Name)
override;
112 StringRef CodeToInsert)
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)
136 : LangOpts(nullptr), OriginalInstance(
false), MergeChildRecords(
false),
137 State(
std::move(State)) {}
141 : LangOpts(nullptr), OriginalInstance(
true),
142 MergeChildRecords(MergeChildRecords),
143 State(
std::make_shared<SharedState>(
File, Diags)) {
144 if (MergeChildRecords)
145 RemoveOldDiagnostics();
149 ~SDiagsWriter()
override {}
167 void RemoveOldDiagnostics();
173 void EmitBlockInfoBlock();
176 void EmitMetaBlock();
179 void EnterDiagBlock();
182 void ExitDiagBlock();
198 unsigned getEmitCategory(
unsigned category = 0);
204 unsigned getEmitDiagnosticFlag(StringRef DiagName);
207 unsigned getEmitFile(
const char *
Filename);
211 RecordDataImpl &
Record,
unsigned TokSize = 0);
215 unsigned TokSize = 0) {
230 bool OriginalInstance;
234 bool MergeChildRecords;
237 bool IsFinishing =
false;
243 : DiagOpts(DiagOpts), Stream(Buffer), OutputFile(
File.str()),
244 EmittedAnyDiagBlocks(
false) {}
253 llvm::BitstreamWriter Stream;
256 std::string OutputFile;
259 AbbreviationMap Abbrevs;
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;
294namespace serialized_diags {
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);
363 unsigned TokSize = 0;
364 if (
Range.isTokenRange())
371unsigned SDiagsWriter::getEmitFile(
const char *
FileName){
375 unsigned &entry = State->Files[
FileName];
380 entry = State->Files.size();
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)
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;
572 assert(!IsFinishing &&
573 "Received a diagnostic after we've already started teardown.");
577 getMetaDiags()->Report(
578 diag::warn_fe_serialized_diag_failure_during_finalization)
587 if (State->EmittedAnyDiagBlocks)
591 State->EmittedAnyDiagBlocks =
true;
595 State->diagBuf.clear();
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");
644 llvm::BitstreamWriter &Stream = State->Stream;
645 RecordData &
Record = State->Record;
646 AbbreviationMap &Abbrevs = State->Abbrevs;
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());
665 Record.push_back(Message.size());
669void SDiagsRenderer::emitDiagnosticMessage(
673 Writer.EmitDiagnosticMessage(
Loc, PLoc,
Level, Message,
D);
676void SDiagsWriter::EnterDiagBlock() {
680void SDiagsWriter::ExitDiagBlock() {
681 State->Stream.ExitBlock();
687 Writer.EnterDiagBlock();
695 Writer.ExitDiagBlock();
701 llvm::BitstreamWriter &Stream = State->Stream;
702 RecordData &
Record = State->Record;
703 AbbreviationMap &Abbrevs = State->Abbrevs;
709 EmitCharSourceRange(*I,
SM);
730 Writer.EmitCodeContext(Ranges, Hints,
Loc.getManager());
734 Writer.EnterDiagBlock();
738 Writer.ExitDiagBlock();
755 if (!State->MetaDiagnostics) {
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();
831 RecordData::value_type
Record[] = {
833 Start.
Offset, FileLookup[End.FileID], End.Line, End.Col, End.Offset};
834 Writer.State->Stream.EmitRecordWithAbbrev(
836 return std::error_code();
839std::error_code SDiagsMerger::visitDiagnosticRecord(
841 unsigned Category,
unsigned Flag, StringRef Message) {
842 RecordData::value_type
Record[] = {
845 Flag ? DiagFlagLookup[Flag] : 0, Message.size()};
847 Writer.State->Stream.EmitRecordWithBlob(
849 return std::error_code();
858 FileLookup[End.FileID], End.Line, End.Col,
859 End.Offset,
Text.size()};
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.
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.
Represents a character-granular source range.
Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...
virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info)
Handle this diagnostic, reporting it to the user or capturing it to a log as needed.
virtual void finish()
Callback to inform the diagnostic client that processing of all source files has ended.
virtual void BeginSourceFile(const LangOptions &LangOpts, const Preprocessor *PP=nullptr)
Callback to inform the diagnostic client that processing of a source file is beginning.
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.
virtual void emitNote(FullSourceLoc Loc, StringRef Message)=0
Options for controlling the compiler diagnostics engine.
virtual void endDiagnostic(DiagOrStoredDiag D, DiagnosticsEngine::Level Level)
virtual void emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, ArrayRef< CharSourceRange > Ranges)=0
virtual void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, StringRef Message, ArrayRef< CharSourceRange > Ranges, DiagOrStoredDiag Info)=0
virtual void emitCodeContext(FullSourceLoc Loc, DiagnosticsEngine::Level Level, SmallVectorImpl< CharSourceRange > &Ranges, ArrayRef< FixItHint > Hints)=0
virtual void beginDiagnostic(DiagOrStoredDiag D, DiagnosticsEngine::Level Level)
A little helper class (which is basically a smart pointer that forwards info from DiagnosticsEngine a...
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.
Concrete class used by the front-end to report problems and issues.
Level
The level of the diagnostic, after it has been through mapping.
Annotates a diagnostic with some code that should be inserted, removed, or replaced to fix the proble...
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.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
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 ...
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
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.
This class handles loading and caching of source files into memory.
SourceLocation getEnd() const
SourceLocation getBegin() const
A base class that handles reading serialized diagnostics from a file.
virtual std::error_code visitCategoryRecord(unsigned ID, StringRef Name)
Visit a category. This associates the category ID to a Name.
virtual std::error_code visitDiagFlagRecord(unsigned ID, StringRef Name)
Visit a flag. This associates the flag's ID to a Name.
virtual std::error_code visitStartOfDiagnostic()
Visit the start of a diagnostic block.
virtual std::error_code visitDiagnosticRecord(unsigned Severity, const Location &Location, unsigned Category, unsigned Flag, StringRef Message)
Visit a diagnostic.
virtual std::error_code visitSourceRangeRecord(const Location &Start, const Location &End)
Visit a source range.
virtual std::error_code visitFixitRecord(const Location &Start, const Location &End, StringRef Text)
Visit a fixit hint.
virtual std::error_code visitFilenameRecord(unsigned ID, unsigned Size, unsigned Timestamp, StringRef Name)
Visit a filename. This associates the file's ID to a Name.
std::error_code readDiagnostics(StringRef File)
Read the diagnostics in File.
virtual std::error_code visitEndOfDiagnostic()
Visit the end of a diagnostic block.
Severity
Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs to either Ignore (nothing),...
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
Diagnostic wrappers for TextAPI types for error reporting.
A location that is represented in the serialized diagnostics.