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 {
160 DiagnosticsEngine *getMetaDiags();
165 void RemoveOldDiagnostics();
171 void EmitBlockInfoBlock();
174 void EmitMetaBlock();
177 void EnterDiagBlock();
180 void ExitDiagBlock();
183 void EmitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
188 void EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges,
189 ArrayRef<FixItHint> Hints,
190 const SourceManager &
SM);
193 void EmitCharSourceRange(CharSourceRange R,
const SourceManager &
SM);
196 unsigned getEmitCategory(
unsigned category = 0);
200 const Diagnostic *
Diag =
nullptr);
202 unsigned getEmitDiagnosticFlag(StringRef DiagName);
205 unsigned getEmitFile(
const char *Filename);
208 void AddLocToRecord(FullSourceLoc Loc, PresumedLoc PLoc,
209 RecordDataImpl &
Record,
unsigned TokSize = 0);
212 void AddLocToRecord(FullSourceLoc Loc, RecordDataImpl &
Record,
213 unsigned TokSize = 0) {
219 void AddCharSourceRangeToRecord(CharSourceRange R, RecordDataImpl &
Record,
220 const SourceManager &
SM);
224 const LangOptions *LangOpts;
228 bool OriginalInstance;
232 bool MergeChildRecords;
235 bool IsFinishing =
false;
240 SharedState(StringRef
File, DiagnosticOptions &DiagOpts)
241 : DiagOpts(DiagOpts), Stream(Buffer), OutputFile(
File.str()),
242 EmittedAnyDiagBlocks(
false) {}
245 DiagnosticOptions DiagOpts;
248 SmallString<1024> Buffer;
251 llvm::BitstreamWriter Stream;
254 std::string OutputFile;
257 AbbreviationMap Abbrevs;
263 SmallString<256> diagBuf;
266 llvm::DenseSet<unsigned> Categories;
269 llvm::DenseMap<const char *, unsigned> Files;
271 typedef llvm::DenseMap<const void *, std::pair<unsigned, StringRef> >
275 DiagFlagsTy DiagFlags;
280 bool EmittedAnyDiagBlocks;
283 std::unique_ptr<DiagnosticsEngine> MetaDiagnostics;
287 std::shared_ptr<SharedState> State;
293std::unique_ptr<DiagnosticConsumer>
create(StringRef OutputFile,
295 bool MergeChildRecords) {
296 return std::make_unique<SDiagsWriter>(OutputFile, DiagOpts,
309 llvm::BitstreamWriter &Stream,
313 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID,
Record);
316 if (!Name || Name[0] == 0)
322 Record.push_back(*Name++);
324 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME,
Record);
329 llvm::BitstreamWriter &Stream,
335 Record.push_back(*Name++);
337 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME,
Record);
341 RecordDataImpl &
Record,
unsigned TokSize) {
344 Record.push_back((
unsigned)0);
345 Record.push_back((
unsigned)0);
346 Record.push_back((
unsigned)0);
347 Record.push_back((
unsigned)0);
357void SDiagsWriter::AddCharSourceRangeToRecord(CharSourceRange Range,
359 const SourceManager &
SM) {
361 unsigned TokSize = 0;
362 if (
Range.isTokenRange())
366 AddLocToRecord(FullSourceLoc(
Range.getEnd(),
SM),
Record, TokSize);
369unsigned SDiagsWriter::getEmitFile(
const char *
FileName){
373 unsigned &entry = State->Files[
FileName];
378 entry = State->Files.size();
388void SDiagsWriter::EmitCharSourceRange(CharSourceRange R,
389 const SourceManager &
SM) {
390 State->Record.clear();
392 AddCharSourceRangeToRecord(R, State->Record,
SM);
398void SDiagsWriter::EmitPreamble() {
400 State->Stream.Emit((
unsigned)
'D', 8);
401 State->Stream.Emit((
unsigned)
'I', 8);
402 State->Stream.Emit((
unsigned)
'A', 8);
403 State->Stream.Emit((
unsigned)
'G', 8);
405 EmitBlockInfoBlock();
410 using namespace llvm;
411 Abbrev.Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
412 Abbrev.Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
413 Abbrev.Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
414 Abbrev.Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
422void SDiagsWriter::EmitBlockInfoBlock() {
423 State->Stream.EnterBlockInfoBlock();
425 using namespace llvm;
426 llvm::BitstreamWriter &Stream = State->Stream;
427 RecordData &
Record = State->Record;
428 AbbreviationMap &Abbrevs = State->Abbrevs;
436 auto Abbrev = std::make_shared<BitCodeAbbrev>();
438 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
454 Abbrev = std::make_shared<BitCodeAbbrev>();
456 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3));
458 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
459 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
460 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16));
461 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
465 Abbrev = std::make_shared<BitCodeAbbrev>();
467 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16));
468 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8));
469 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
473 Abbrev = std::make_shared<BitCodeAbbrev>();
477 Stream.EmitBlockInfoAbbrev(
BLOCK_DIAG, Abbrev));
480 Abbrev = std::make_shared<BitCodeAbbrev>();
482 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
483 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16));
484 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
489 Abbrev = std::make_shared<BitCodeAbbrev>();
491 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
492 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
493 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
494 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16));
495 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
500 Abbrev = std::make_shared<BitCodeAbbrev>();
503 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16));
504 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
511void SDiagsWriter::EmitMetaBlock() {
512 llvm::BitstreamWriter &Stream = State->Stream;
513 AbbreviationMap &Abbrevs = State->Abbrevs;
521unsigned SDiagsWriter::getEmitCategory(
unsigned int category) {
522 if (!State->Categories.insert(category).second)
536 const Diagnostic *
Diag) {
541 Diag->getDiags()->getDiagnosticIDs()->getWarningOptionForDiag(
543 return getEmitDiagnosticFlag(FlagName);
546unsigned SDiagsWriter::getEmitDiagnosticFlag(StringRef FlagName) {
547 if (FlagName.empty())
552 const void *data = FlagName.data();
553 std::pair<unsigned, StringRef> &entry = State->DiagFlags[data];
554 if (entry.first == 0) {
555 entry.first = State->DiagFlags.size();
556 entry.second = FlagName;
569 const Diagnostic &Info) {
570 assert(!IsFinishing &&
571 "Received a diagnostic after we've already started teardown.");
573 SmallString<256> diagnostic;
575 getMetaDiags()->Report(
576 diag::warn_fe_serialized_diag_failure_during_finalization)
585 if (State->EmittedAnyDiagBlocks)
589 State->EmittedAnyDiagBlocks =
true;
593 State->diagBuf.clear();
606 EmitDiagnosticMessage(FullSourceLoc(), PresumedLoc(), DiagLevel,
607 State->diagBuf, &Info);
616 "Unexpected diagnostic with valid location outside of a source file");
617 SDiagsRenderer Renderer(*
this, *LangOpts, State->DiagOpts);
618 Renderer.emitDiagnostic(
625#define CASE(X) case DiagnosticsEngine::X: return serialized_diags::X;
635 llvm_unreachable(
"invalid diagnostic level");
638void SDiagsWriter::EmitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
642 llvm::BitstreamWriter &Stream = State->Stream;
643 RecordData &
Record = State->Record;
644 AbbreviationMap &Abbrevs = State->Abbrevs;
650 AddLocToRecord(Loc, PLoc,
Record);
652 if (
const Diagnostic *Info = dyn_cast_if_present<const Diagnostic *>(D)) {
655 Record.push_back(getEmitCategory(DiagID));
657 Record.push_back(getEmitDiagnosticFlag(
Level, Info));
659 Record.push_back(getEmitCategory());
667void SDiagsRenderer::emitDiagnosticMessage(
669 StringRef Message, ArrayRef<clang::CharSourceRange> Ranges,
671 Writer.EmitDiagnosticMessage(Loc, PLoc,
Level, Message, D);
674void SDiagsWriter::EnterDiagBlock() {
678void SDiagsWriter::ExitDiagBlock() {
679 State->Stream.ExitBlock();
685 Writer.EnterDiagBlock();
693 Writer.ExitDiagBlock();
696void SDiagsWriter::EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges,
697 ArrayRef<FixItHint> Hints,
698 const SourceManager &
SM) {
699 llvm::BitstreamWriter &Stream = State->Stream;
700 RecordData &
Record = State->Record;
701 AbbreviationMap &Abbrevs = State->Abbrevs;
704 for (ArrayRef<CharSourceRange>::iterator I = Ranges.begin(), E = Ranges.end();
707 EmitCharSourceRange(*I,
SM);
710 for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end();
712 const FixItHint &Fix = *I;
724void SDiagsRenderer::emitCodeContext(FullSourceLoc Loc,
726 SmallVectorImpl<CharSourceRange> &Ranges,
727 ArrayRef<FixItHint> Hints) {
728 Writer.EmitCodeContext(Ranges, Hints, Loc.
getManager());
731void SDiagsRenderer::emitNote(FullSourceLoc Loc, StringRef Message) {
732 Writer.EnterDiagBlock();
736 Writer.ExitDiagBlock();
739DiagnosticsEngine *SDiagsWriter::getMetaDiags() {
753 if (!State->MetaDiagnostics) {
754 auto Client =
new TextDiagnosticPrinter(llvm::errs(), State->DiagOpts);
755 State->MetaDiagnostics = std::make_unique<DiagnosticsEngine>(
758 return State->MetaDiagnostics.get();
761void SDiagsWriter::RemoveOldDiagnostics() {
762 if (!llvm::sys::fs::remove(State->OutputFile))
765 getMetaDiags()->Report(diag::warn_fe_serialized_diag_merge_failure);
768 MergeChildRecords =
false;
771SDiagsWriter::~SDiagsWriter() {
772 assert(!IsFinishing);
776 if (!OriginalInstance)
780 if (State->EmittedAnyDiagBlocks)
783 if (MergeChildRecords) {
784 if (!State->EmittedAnyDiagBlocks)
789 if (llvm::sys::fs::exists(State->OutputFile))
790 if (SDiagsMerger(*this).mergeRecordsFromFile(State->OutputFile.c_str()))
791 getMetaDiags()->Report(diag::warn_fe_serialized_diag_merge_failure);
795 auto OS = std::make_unique<llvm::raw_fd_ostream>(State->OutputFile.c_str(),
796 EC, llvm::sys::fs::OF_None);
798 getMetaDiags()->Report(diag::warn_fe_serialized_diag_failure)
799 << State->OutputFile << EC.message();
805 OS->write((
char *)&State->Buffer.front(), State->Buffer.size());
808 assert(!
OS->has_error());
809 if (
OS->has_error()) {
810 getMetaDiags()->Report(diag::warn_fe_serialized_diag_failure)
811 << State->OutputFile <<
OS->error().message();
816std::error_code SDiagsMerger::visitStartOfDiagnostic() {
817 Writer.EnterDiagBlock();
818 return std::error_code();
821std::error_code SDiagsMerger::visitEndOfDiagnostic() {
822 Writer.ExitDiagBlock();
823 return std::error_code();
827SDiagsMerger::visitSourceRangeRecord(
const serialized_diags::Location &Start,
828 const serialized_diags::Location &End) {
829 RecordData::value_type
Record[] = {
832 Writer.State->Stream.EmitRecordWithAbbrev(
834 return std::error_code();
837std::error_code SDiagsMerger::visitDiagnosticRecord(
838 unsigned Severity,
const serialized_diags::Location &Location,
839 unsigned Category,
unsigned Flag, StringRef Message) {
840 RecordData::value_type
Record[] = {
842 Location.
Col, Location.
Offset, CategoryLookup[Category],
843 Flag ? DiagFlagLookup[Flag] : 0,
Message.size()};
845 Writer.State->Stream.EmitRecordWithBlob(
847 return std::error_code();
851SDiagsMerger::visitFixitRecord(
const serialized_diags::Location &Start,
852 const serialized_diags::Location &End,
859 Writer.State->Stream.EmitRecordWithBlob(
861 return std::error_code();
864std::error_code SDiagsMerger::visitFilenameRecord(
unsigned ID,
unsigned Size,
867 FileLookup[
ID] = Writer.getEmitFile(Name.str().c_str());
868 return std::error_code();
871std::error_code SDiagsMerger::visitCategoryRecord(
unsigned ID, StringRef Name) {
872 CategoryLookup[
ID] = Writer.getEmitCategory(ID);
873 return std::error_code();
876std::error_code SDiagsMerger::visitDiagFlagRecord(
unsigned ID, StringRef Name) {
877 DiagFlagLookup[
ID] = Writer.getEmitDiagnosticFlag(Name);
878 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.