19#include "llvm/ADT/DenseSet.h"
20#include "llvm/ADT/STLExtras.h"
21#include "llvm/ADT/SmallString.h"
22#include "llvm/ADT/StringRef.h"
23#include "llvm/Bitstream/BitCodes.h"
24#include "llvm/Bitstream/BitstreamReader.h"
25#include "llvm/Support/FileSystem.h"
26#include "llvm/Support/raw_ostream.h"
34class AbbreviationMap {
35 llvm::DenseMap<unsigned, unsigned> Abbrevs;
39 void set(
unsigned recordID,
unsigned abbrevID) {
40 assert(!Abbrevs.contains(recordID) &&
"Abbreviation already set.");
41 Abbrevs[recordID] = abbrevID;
44 unsigned get(
unsigned recordID) {
45 assert(Abbrevs.contains(recordID) &&
"Abbreviation not set.");
46 return Abbrevs[recordID];
59 SDiagsRenderer(SDiagsWriter &Writer,
const LangOptions &LangOpts,
63 ~SDiagsRenderer()
override {}
87typedef llvm::DenseMap<unsigned, unsigned> AbbrevLookup;
91 AbbrevLookup FileLookup;
92 AbbrevLookup CategoryLookup;
93 AbbrevLookup DiagFlagLookup;
96 SDiagsMerger(SDiagsWriter &Writer) : Writer(Writer) {}
98 std::error_code mergeRecordsFromFile(
const char *
File) {
109 unsigned Category,
unsigned Flag, StringRef Message)
override;
112 StringRef Name)
override;
115 StringRef CodeToInsert)
override;
121 std::error_code adjustSourceLocFilename(RecordData &
Record,
122 unsigned int offset);
124 void adjustAbbrevID(RecordData &
Record, AbbrevLookup &Lookup,
127 void writeRecordWithAbbrev(
unsigned ID, RecordData &
Record);
129 void writeRecordWithBlob(
unsigned ID, RecordData &
Record, StringRef Blob);
133 friend class SDiagsRenderer;
134 friend class SDiagsMerger;
138 explicit SDiagsWriter(std::shared_ptr<SharedState> State)
139 : LangOpts(nullptr), OriginalInstance(
false), MergeChildRecords(
false),
140 State(
std::move(State)) {}
144 : LangOpts(nullptr), OriginalInstance(
true),
145 MergeChildRecords(MergeChildRecords),
146 State(
std::make_shared<SharedState>(
File, Diags)) {
147 if (MergeChildRecords)
148 RemoveOldDiagnostics();
152 ~SDiagsWriter()
override {}
170 void RemoveOldDiagnostics();
176 void EmitBlockInfoBlock();
179 void EmitMetaBlock();
182 void EnterDiagBlock();
185 void ExitDiagBlock();
201 unsigned getEmitCategory(
unsigned category = 0);
205 unsigned DiagID = 0);
207 unsigned getEmitDiagnosticFlag(StringRef DiagName);
210 unsigned getEmitFile(
const char *
Filename);
214 RecordDataImpl &
Record,
unsigned TokSize = 0);
218 unsigned TokSize = 0) {
233 bool OriginalInstance;
237 bool MergeChildRecords;
240 bool IsFinishing =
false;
246 : DiagOpts(Diags), Stream(Buffer), OutputFile(
File.str()),
247 EmittedAnyDiagBlocks(
false) {}
256 llvm::BitstreamWriter Stream;
259 std::string OutputFile;
262 AbbreviationMap Abbrevs;
271 llvm::DenseSet<unsigned> Categories;
274 llvm::DenseMap<const char *, unsigned> Files;
276 typedef llvm::DenseMap<const void *, std::pair<unsigned, StringRef> >
280 DiagFlagsTy DiagFlags;
285 bool EmittedAnyDiagBlocks;
288 std::unique_ptr<DiagnosticsEngine> MetaDiagnostics;
292 std::shared_ptr<SharedState> State;
297namespace serialized_diags {
298std::unique_ptr<DiagnosticConsumer>
300 return std::make_unique<SDiagsWriter>(OutputFile, Diags, MergeChildRecords);
312 llvm::BitstreamWriter &Stream,
316 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID,
Record);
319 if (!Name || Name[0] == 0)
325 Record.push_back(*Name++);
327 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME,
Record);
332 llvm::BitstreamWriter &Stream,
338 Record.push_back(*Name++);
340 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME,
Record);
344 RecordDataImpl &
Record,
unsigned TokSize) {
347 Record.push_back((
unsigned)0);
348 Record.push_back((
unsigned)0);
349 Record.push_back((
unsigned)0);
350 Record.push_back((
unsigned)0);
364 unsigned TokSize = 0;
365 if (
Range.isTokenRange())
372unsigned SDiagsWriter::getEmitFile(
const char *
FileName){
376 unsigned &entry = State->Files[
FileName];
381 entry = State->Files.size();
393 State->Record.clear();
395 AddCharSourceRangeToRecord(R, State->Record,
SM);
401void SDiagsWriter::EmitPreamble() {
403 State->Stream.Emit((
unsigned)
'D', 8);
404 State->Stream.Emit((
unsigned)
'I', 8);
405 State->Stream.Emit((
unsigned)
'A', 8);
406 State->Stream.Emit((
unsigned)
'G', 8);
408 EmitBlockInfoBlock();
413 using namespace llvm;
414 Abbrev.Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
415 Abbrev.Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
416 Abbrev.Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
417 Abbrev.Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
425void SDiagsWriter::EmitBlockInfoBlock() {
426 State->Stream.EnterBlockInfoBlock();
428 using namespace llvm;
429 llvm::BitstreamWriter &Stream = State->Stream;
430 RecordData &
Record = State->Record;
431 AbbreviationMap &Abbrevs = State->Abbrevs;
439 auto Abbrev = std::make_shared<BitCodeAbbrev>();
441 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
457 Abbrev = std::make_shared<BitCodeAbbrev>();
459 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3));
461 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
462 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
463 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16));
464 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
468 Abbrev = std::make_shared<BitCodeAbbrev>();
470 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16));
471 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8));
472 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
476 Abbrev = std::make_shared<BitCodeAbbrev>();
480 Stream.EmitBlockInfoAbbrev(
BLOCK_DIAG, Abbrev));
483 Abbrev = std::make_shared<BitCodeAbbrev>();
485 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
486 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16));
487 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
492 Abbrev = std::make_shared<BitCodeAbbrev>();
494 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
495 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
496 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
497 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16));
498 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
503 Abbrev = std::make_shared<BitCodeAbbrev>();
506 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16));
507 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
514void SDiagsWriter::EmitMetaBlock() {
515 llvm::BitstreamWriter &Stream = State->Stream;
516 AbbreviationMap &Abbrevs = State->Abbrevs;
524unsigned SDiagsWriter::getEmitCategory(
unsigned int category) {
525 if (!State->Categories.insert(category).second)
544 return getEmitDiagnosticFlag(FlagName);
547unsigned SDiagsWriter::getEmitDiagnosticFlag(StringRef FlagName) {
548 if (FlagName.empty())
553 const void *data = FlagName.data();
554 std::pair<unsigned, StringRef> &entry = State->DiagFlags[data];
555 if (entry.first == 0) {
556 entry.first = State->DiagFlags.size();
557 entry.second = FlagName;
571 assert(!IsFinishing &&
572 "Received a diagnostic after we've already started teardown.");
576 getMetaDiags()->Report(
577 diag::warn_fe_serialized_diag_failure_during_finalization)
586 if (State->EmittedAnyDiagBlocks)
590 State->EmittedAnyDiagBlocks =
true;
594 State->diagBuf.clear();
608 State->diagBuf, &Info);
617 "Unexpected diagnostic with valid location outside of a source file");
618 SDiagsRenderer Renderer(*
this, *LangOpts, &*State->DiagOpts);
619 Renderer.emitDiagnostic(
626#define CASE(X) case DiagnosticsEngine::X: return serialized_diags::X;
636 llvm_unreachable(
"invalid diagnostic level");
643 llvm::BitstreamWriter &Stream = State->Stream;
644 RecordData &
Record = State->Record;
645 AbbreviationMap &Abbrevs = State->Abbrevs;
656 Record.push_back(getEmitCategory(DiagID));
660 Record.push_back(getEmitCategory());
664 Record.push_back(Message.size());
668void SDiagsRenderer::emitDiagnosticMessage(
672 Writer.EmitDiagnosticMessage(
Loc, PLoc,
Level, Message,
D);
675void SDiagsWriter::EnterDiagBlock() {
679void SDiagsWriter::ExitDiagBlock() {
680 State->Stream.ExitBlock();
686 Writer.EnterDiagBlock();
694 Writer.ExitDiagBlock();
700 llvm::BitstreamWriter &Stream = State->Stream;
701 RecordData &
Record = State->Record;
702 AbbreviationMap &Abbrevs = State->Abbrevs;
708 EmitCharSourceRange(*I,
SM);
729 Writer.EmitCodeContext(Ranges, Hints,
Loc.getManager());
733 Writer.EnterDiagBlock();
737 Writer.ExitDiagBlock();
754 if (!State->MetaDiagnostics) {
758 State->MetaDiagnostics = std::make_unique<DiagnosticsEngine>(
759 IDs, State->DiagOpts.get(), Client);
761 return State->MetaDiagnostics.get();
764void SDiagsWriter::RemoveOldDiagnostics() {
765 if (!llvm::sys::fs::remove(State->OutputFile))
768 getMetaDiags()->Report(diag::warn_fe_serialized_diag_merge_failure);
771 MergeChildRecords =
false;
774void SDiagsWriter::finish() {
775 assert(!IsFinishing);
779 if (!OriginalInstance)
783 if (State->EmittedAnyDiagBlocks)
786 if (MergeChildRecords) {
787 if (!State->EmittedAnyDiagBlocks)
792 if (llvm::sys::fs::exists(State->OutputFile))
793 if (SDiagsMerger(*this).mergeRecordsFromFile(State->OutputFile.c_str()))
794 getMetaDiags()->Report(diag::warn_fe_serialized_diag_merge_failure);
798 auto OS = std::make_unique<llvm::raw_fd_ostream>(State->OutputFile.c_str(),
799 EC, llvm::sys::fs::OF_None);
801 getMetaDiags()->Report(diag::warn_fe_serialized_diag_failure)
802 << State->OutputFile << EC.message();
808 OS->write((
char *)&State->Buffer.front(), State->Buffer.size());
811 assert(!OS->has_error());
812 if (OS->has_error()) {
813 getMetaDiags()->Report(diag::warn_fe_serialized_diag_failure)
814 << State->OutputFile << OS->error().message();
819std::error_code SDiagsMerger::visitStartOfDiagnostic() {
820 Writer.EnterDiagBlock();
821 return std::error_code();
824std::error_code SDiagsMerger::visitEndOfDiagnostic() {
825 Writer.ExitDiagBlock();
826 return std::error_code();
832 RecordData::value_type
Record[] = {
834 Start.
Offset, FileLookup[End.FileID], End.Line, End.Col, End.Offset};
835 Writer.State->Stream.EmitRecordWithAbbrev(
837 return std::error_code();
840std::error_code SDiagsMerger::visitDiagnosticRecord(
842 unsigned Category,
unsigned Flag, StringRef Message) {
843 RecordData::value_type
Record[] = {
846 Flag ? DiagFlagLookup[Flag] : 0, Message.size()};
848 Writer.State->Stream.EmitRecordWithBlob(
850 return std::error_code();
859 FileLookup[End.FileID], End.Line, End.Col,
860 End.Offset,
Text.size()};
862 Writer.State->Stream.EmitRecordWithBlob(
864 return std::error_code();
867std::error_code SDiagsMerger::visitFilenameRecord(
unsigned ID,
unsigned Size,
870 FileLookup[
ID] = Writer.getEmitFile(Name.str().c_str());
871 return std::error_code();
874std::error_code SDiagsMerger::visitCategoryRecord(
unsigned ID, StringRef Name) {
875 CategoryLookup[
ID] = Writer.getEmitCategory(ID);
876 return std::error_code();
879std::error_code SDiagsMerger::visitDiagFlagRecord(
unsigned ID, StringRef Name) {
880 DiagFlagLookup[
ID] = Writer.getEmitDiagnosticFlag(Name);
881 return std::error_code();
Defines the Diagnostic-related interfaces.
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.
Used for handling and querying diagnostic IDs.
static StringRef getCategoryNameFromID(unsigned CategoryID)
Given a category ID, return the name of the category.
static StringRef getWarningOptionForDiag(unsigned DiagID)
Return the lowest-level warning option that enables the specified diagnostic.
static unsigned getCategoryNumberForDiag(unsigned DiagID)
Return the category number that a specified DiagID belongs to, or 0 if no category.
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) ...
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),...
@ 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...
std::unique_ptr< DiagnosticConsumer > create(StringRef OutputFile, DiagnosticOptions *Diags, bool MergeChildRecords=false)
Returns a DiagnosticConsumer that serializes diagnostics to a bitcode file.
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.