20 #include "llvm/ADT/DenseSet.h" 21 #include "llvm/ADT/STLExtras.h" 22 #include "llvm/ADT/SmallString.h" 23 #include "llvm/ADT/StringRef.h" 24 #include "llvm/Support/raw_ostream.h" 27 using namespace clang;
32 class AbbreviationMap {
33 llvm::DenseMap<unsigned, unsigned> Abbrevs;
37 void set(
unsigned recordID,
unsigned abbrevID) {
38 assert(Abbrevs.find(recordID) == Abbrevs.end()
39 &&
"Abbreviation already set.");
40 Abbrevs[recordID] = abbrevID;
43 unsigned get(
unsigned recordID) {
44 assert(Abbrevs.find(recordID) != Abbrevs.end() &&
45 "Abbreviation not set.");
46 return Abbrevs[recordID];
59 SDiagsRenderer(SDiagsWriter &Writer,
const LangOptions &LangOpts,
63 ~SDiagsRenderer()
override {}
87 typedef llvm::DenseMap<unsigned, unsigned> AbbrevLookup;
91 AbbrevLookup FileLookup;
92 AbbrevLookup CategoryLookup;
93 AbbrevLookup DiagFlagLookup;
96 SDiagsMerger(SDiagsWriter &Writer)
99 std::error_code mergeRecordsFromFile(
const char *File) {
100 return readDiagnostics(File);
104 std::error_code visitStartOfDiagnostic()
override;
105 std::error_code visitEndOfDiagnostic()
override;
106 std::error_code visitCategoryRecord(
unsigned ID, StringRef Name)
override;
107 std::error_code visitDiagFlagRecord(
unsigned ID, StringRef Name)
override;
108 std::error_code visitDiagnosticRecord(
110 unsigned Category,
unsigned Flag, StringRef Message)
override;
111 std::error_code visitFilenameRecord(
unsigned ID,
unsigned Size,
113 StringRef Name)
override;
116 StringRef CodeToInsert)
override;
122 std::error_code adjustSourceLocFilename(RecordData &Record,
123 unsigned int offset);
125 void adjustAbbrevID(RecordData &Record, AbbrevLookup &Lookup,
128 void writeRecordWithAbbrev(
unsigned ID, RecordData &Record);
130 void writeRecordWithBlob(
unsigned ID, RecordData &Record, StringRef Blob);
134 friend class SDiagsRenderer;
135 friend class SDiagsMerger;
139 explicit SDiagsWriter(std::shared_ptr<SharedState>
State)
140 : LangOpts(nullptr), OriginalInstance(
false), MergeChildRecords(
false),
141 State(
std::move(State)) {}
145 : LangOpts(nullptr), OriginalInstance(
true),
146 MergeChildRecords(MergeChildRecords),
147 State(
std::make_shared<SharedState>(File, Diags)) {
148 if (MergeChildRecords)
149 RemoveOldDiagnostics();
153 ~SDiagsWriter()
override {}
162 void finish()
override;
171 void RemoveOldDiagnostics();
177 void EmitBlockInfoBlock();
180 void EmitMetaBlock();
183 void EnterDiagBlock();
186 void ExitDiagBlock();
202 unsigned getEmitCategory(
unsigned category = 0);
206 unsigned DiagID = 0);
208 unsigned getEmitDiagnosticFlag(StringRef DiagName);
211 unsigned getEmitFile(
const char *
Filename);
215 RecordDataImpl &Record,
unsigned TokSize = 0);
218 void AddLocToRecord(
FullSourceLoc Loc, RecordDataImpl &Record,
219 unsigned TokSize = 0) {
225 void AddCharSourceRangeToRecord(
CharSourceRange R, RecordDataImpl &Record,
234 bool OriginalInstance;
238 bool MergeChildRecords;
244 : DiagOpts(Diags), Stream(Buffer), OutputFile(File.
str()),
245 EmittedAnyDiagBlocks(
false) {}
254 llvm::BitstreamWriter Stream;
257 std::string OutputFile;
260 AbbreviationMap Abbrevs;
272 llvm::DenseMap<const char *, unsigned> Files;
274 typedef llvm::DenseMap<const void *, std::pair<unsigned, StringRef> >
278 DiagFlagsTy DiagFlags;
283 bool EmittedAnyDiagBlocks;
286 std::unique_ptr<DiagnosticsEngine> MetaDiagnostics;
290 std::shared_ptr<SharedState>
State;
295 namespace serialized_diags {
296 std::unique_ptr<DiagnosticConsumer>
298 return llvm::make_unique<SDiagsWriter>(OutputFile, Diags, MergeChildRecords);
310 llvm::BitstreamWriter &Stream,
311 RecordDataImpl &Record) {
313 Record.push_back(ID);
314 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
317 if (!Name || Name[0] == 0)
323 Record.push_back(*Name++);
325 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record);
330 llvm::BitstreamWriter &Stream,
331 RecordDataImpl &Record){
333 Record.push_back(ID);
336 Record.push_back(*Name++);
338 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
342 RecordDataImpl &Record,
unsigned TokSize) {
345 Record.push_back((
unsigned)0);
346 Record.push_back((
unsigned)0);
347 Record.push_back((
unsigned)0);
348 Record.push_back((
unsigned)0);
353 Record.push_back(PLoc.
getLine());
354 Record.push_back(PLoc.
getColumn()+TokSize);
359 RecordDataImpl &Record,
362 unsigned TokSize = 0;
370 unsigned SDiagsWriter::getEmitFile(
const char *FileName){
374 unsigned &entry =
State->Files[FileName];
379 entry =
State->Files.size();
380 StringRef Name(FileName);
391 State->Record.clear();
393 AddCharSourceRangeToRecord(R,
State->Record, SM);
399 void SDiagsWriter::EmitPreamble() {
401 State->Stream.Emit((
unsigned)
'D', 8);
402 State->Stream.Emit((
unsigned)
'I', 8);
403 State->Stream.Emit((
unsigned)
'A', 8);
404 State->Stream.Emit((
unsigned)
'G', 8);
406 EmitBlockInfoBlock();
411 using namespace llvm;
412 Abbrev.Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
413 Abbrev.Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
414 Abbrev.Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
415 Abbrev.Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
423 void SDiagsWriter::EmitBlockInfoBlock() {
424 State->Stream.EnterBlockInfoBlock();
426 using namespace llvm;
427 llvm::BitstreamWriter &Stream =
State->Stream;
428 RecordData &Record =
State->Record;
429 AbbreviationMap &Abbrevs =
State->Abbrevs;
437 auto Abbrev = std::make_shared<BitCodeAbbrev>();
439 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
455 Abbrev = std::make_shared<BitCodeAbbrev>();
457 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3));
459 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
460 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
461 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16));
462 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
466 Abbrev = std::make_shared<BitCodeAbbrev>();
468 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16));
469 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8));
470 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
474 Abbrev = std::make_shared<BitCodeAbbrev>();
478 Stream.EmitBlockInfoAbbrev(
BLOCK_DIAG, Abbrev));
481 Abbrev = std::make_shared<BitCodeAbbrev>();
483 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
484 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16));
485 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
490 Abbrev = std::make_shared<BitCodeAbbrev>();
492 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
493 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
494 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
495 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16));
496 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
501 Abbrev = std::make_shared<BitCodeAbbrev>();
504 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16));
505 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
512 void SDiagsWriter::EmitMetaBlock() {
513 llvm::BitstreamWriter &Stream =
State->Stream;
514 AbbreviationMap &Abbrevs =
State->Abbrevs;
522 unsigned SDiagsWriter::getEmitCategory(
unsigned int category) {
523 if (!
State->Categories.insert(category).second)
529 RecordData::value_type Record[] = {
RECORD_CATEGORY, category, catName.size()};
542 return getEmitDiagnosticFlag(FlagName);
545 unsigned SDiagsWriter::getEmitDiagnosticFlag(StringRef FlagName) {
546 if (FlagName.empty())
551 const void *data = FlagName.data();
552 std::pair<unsigned, StringRef> &entry =
State->DiagFlags[data];
553 if (entry.first == 0) {
554 entry.first =
State->DiagFlags.size();
555 entry.second = FlagName;
573 if (
State->EmittedAnyDiagBlocks)
577 State->EmittedAnyDiagBlocks =
true;
581 State->diagBuf.clear();
595 State->diagBuf, &Info);
604 "Unexpected diagnostic with valid location outside of a source file");
605 SDiagsRenderer Renderer(*
this, *LangOpts, &*
State->DiagOpts);
606 Renderer.emitDiagnostic(
613 #define CASE(X) case DiagnosticsEngine::X: return serialized_diags::X; 623 llvm_unreachable(
"invalid diagnostic level");
630 llvm::BitstreamWriter &Stream =
State->Stream;
631 RecordData &Record =
State->Record;
632 AbbreviationMap &Abbrevs =
State->Abbrevs;
638 AddLocToRecord(Loc, PLoc, Record);
643 Record.push_back(getEmitCategory(DiagID));
645 Record.push_back(getEmitDiagnosticFlag(Level, Info->
getID()));
647 Record.push_back(getEmitCategory());
648 Record.push_back(getEmitDiagnosticFlag(Level));
651 Record.push_back(Message.size());
652 Stream.EmitRecordWithBlob(Abbrevs.get(
RECORD_DIAG), Record, Message);
655 void SDiagsRenderer::emitDiagnosticMessage(
659 Writer.EmitDiagnosticMessage(Loc, PLoc, Level, Message, D);
662 void SDiagsWriter::EnterDiagBlock() {
666 void SDiagsWriter::ExitDiagBlock() {
667 State->Stream.ExitBlock();
673 Writer.EnterDiagBlock();
681 Writer.ExitDiagBlock();
687 llvm::BitstreamWriter &Stream =
State->Stream;
688 RecordData &Record =
State->Record;
689 AbbreviationMap &Abbrevs =
State->Abbrevs;
695 EmitCharSourceRange(*I, SM);
705 AddCharSourceRangeToRecord(Fix.
RemoveRange, Record, SM);
707 Stream.EmitRecordWithBlob(Abbrevs.get(
RECORD_FIXIT), Record,
716 Writer.EmitCodeContext(Ranges, Hints, Loc.
getManager());
719 void SDiagsRenderer::emitNote(
FullSourceLoc Loc, StringRef Message) {
720 Writer.EnterDiagBlock();
724 Writer.ExitDiagBlock();
741 if (!
State->MetaDiagnostics) {
745 State->MetaDiagnostics = llvm::make_unique<DiagnosticsEngine>(
746 IDs,
State->DiagOpts.get(), Client);
748 return State->MetaDiagnostics.get();
751 void SDiagsWriter::RemoveOldDiagnostics() {
752 if (!llvm::sys::fs::remove(
State->OutputFile))
755 getMetaDiags()->Report(diag::warn_fe_serialized_diag_merge_failure);
758 MergeChildRecords =
false;
761 void SDiagsWriter::finish() {
763 if (!OriginalInstance)
767 if (
State->EmittedAnyDiagBlocks)
770 if (MergeChildRecords) {
771 if (!
State->EmittedAnyDiagBlocks)
776 if (llvm::sys::fs::exists(
State->OutputFile))
777 if (SDiagsMerger(*this).mergeRecordsFromFile(
State->OutputFile.c_str()))
778 getMetaDiags()->Report(diag::warn_fe_serialized_diag_merge_failure);
782 auto OS = llvm::make_unique<llvm::raw_fd_ostream>(
State->OutputFile.c_str(),
783 EC, llvm::sys::fs::F_None);
785 getMetaDiags()->Report(diag::warn_fe_serialized_diag_failure)
786 <<
State->OutputFile << EC.message();
791 OS->write((
char *)&
State->Buffer.front(),
State->Buffer.size());
795 std::error_code SDiagsMerger::visitStartOfDiagnostic() {
796 Writer.EnterDiagBlock();
797 return std::error_code();
800 std::error_code SDiagsMerger::visitEndOfDiagnostic() {
801 Writer.ExitDiagBlock();
802 return std::error_code();
808 RecordData::value_type Record[] = {
811 Writer.State->Stream.EmitRecordWithAbbrev(
813 return std::error_code();
816 std::error_code SDiagsMerger::visitDiagnosticRecord(
818 unsigned Category,
unsigned Flag, StringRef Message) {
819 RecordData::value_type Record[] = {
822 Flag ? DiagFlagLookup[Flag] : 0, Message.size()};
824 Writer.State->Stream.EmitRecordWithBlob(
825 Writer.State->Abbrevs.get(
RECORD_DIAG), Record, Message);
826 return std::error_code();
838 Writer.State->Stream.EmitRecordWithBlob(
840 return std::error_code();
843 std::error_code SDiagsMerger::visitFilenameRecord(
unsigned ID,
unsigned Size,
846 FileLookup[
ID] = Writer.getEmitFile(Name.str().c_str());
847 return std::error_code();
850 std::error_code SDiagsMerger::visitCategoryRecord(
unsigned ID, StringRef Name) {
851 CategoryLookup[
ID] = Writer.getEmitCategory(ID);
852 return std::error_code();
855 std::error_code SDiagsMerger::visitDiagFlagRecord(
unsigned ID, StringRef Name) {
856 DiagFlagLookup[
ID] = Writer.getEmitDiagnosticFlag(Name);
857 return std::error_code();
static unsigned getCategoryNumberForDiag(unsigned DiagID)
Return the category number that a specified DiagID belongs to, or 0 if no category.
static serialized_diags::Level getStableLevel(DiagnosticsEngine::Level Level)
DominatorTree GraphTraits specialization so the DominatorTree can be iterable by generic graph iterat...
Defines the SourceManager interface.
Level
A stable version of DiagnosticIDs::Level.
llvm::PointerUnion< const Diagnostic *, const StoredDiagnostic * > DiagOrStoredDiag
std::string CodeToInsert
The actual code to insert at the insertion location, as a string.
static StringRef getCategoryNameFromID(unsigned CategoryID)
Given a category ID, return the name of the category.
static void AddSourceLocationAbbrev(llvm::BitCodeAbbrev &Abbrev)
Severity
Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs to either Ignore (nothing)...
Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...
bool hasSourceManager() const
SourceLocation getBegin() const
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
const SourceLocation & getLocation() const
Concrete class used by the front-end to report problems and issues.
Defines the Diagnostic-related interfaces.
PresumedLoc getPresumedLoc(bool UseLineDirectives=true) const
static void EmitRecordID(unsigned ID, const char *Name, llvm::BitstreamWriter &Stream, RecordDataImpl &Record)
Emits a record ID in the BLOCKINFO block.
Represents a character-granular source range.
bool isInvalid() const
Return true if this object is invalid or uninitialized.
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 ...
unsigned getLine() const
Return the presumed line number of this location.
static void EmitBlockID(unsigned ID, const char *Name, llvm::BitstreamWriter &Stream, RecordDataImpl &Record)
Emits a block ID in the BLOCKINFO block.
const SourceManager & getManager() const
static StringRef getWarningOptionForDiag(unsigned DiagID)
Return the lowest-level warning option that enables the specified diagnostic.
Represents an unpacked "presumed" location which can be presented to the user.
const char * getFilename() const
Return the presumed filename of this location.
CharSourceRange RemoveRange
Code that should be replaced to correct the error.
unsigned getColumn() const
Return the presumed column number of this location.
Subclass of DiagnosticRender that turns all subdiagostics into explicit notes.
Options for controlling the compiler diagnostics engine.
unsigned getFileOffset() const
SourceManager & getSourceManager() const
bool isTokenRange() const
Return true if the end of this range specifies the start of the last token.
Dataflow Directional Tag Classes.
A base class that handles reading serialized diagnostics from a file.
A location that is represented in the serialized diagnostics.
std::unique_ptr< DiagnosticConsumer > create(StringRef OutputFile, DiagnosticOptions *Diags, bool MergeChildRecords=false)
Returns a DiagnosticConsumer that serializes diagnostics to a bitcode file.
Used for handling and querying diagnostic IDs.
static void AddRangeLocationAbbrev(llvm::BitCodeAbbrev &Abbrev)
SourceLocation getEnd() const
ArrayRef< CharSourceRange > getRanges() const
Return an array reference for this diagnostic's ranges.
ArrayRef< FixItHint > getFixItHints() const
Level
The level of the diagnostic, after it has been through mapping.
A little helper class (which is basically a smart pointer that forwards info from DiagnosticsEngine) ...
A SourceLocation and its associated SourceManager.
The this block acts as a container for all the information for a specific diagnostic.
Annotates a diagnostic with some code that should be inserted, removed, or replaced to fix the proble...
A top-level block which represents any meta data associated with the diagostics, including versioning...
void FormatDiagnostic(SmallVectorImpl< char > &OutStr) const
Format this diagnostic into a string, substituting the formal arguments into the %0 slots...
This class handles loading and caching of source files into memory.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.