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/raw_ostream.h" 28 using namespace clang;
33 class AbbreviationMap {
34 llvm::DenseMap<unsigned, unsigned> Abbrevs;
38 void set(
unsigned recordID,
unsigned abbrevID) {
39 assert(Abbrevs.find(recordID) == Abbrevs.end()
40 &&
"Abbreviation already set.");
41 Abbrevs[recordID] = abbrevID;
44 unsigned get(
unsigned recordID) {
45 assert(Abbrevs.find(recordID) != Abbrevs.end() &&
46 "Abbreviation not set.");
47 return Abbrevs[recordID];
60 SDiagsRenderer(SDiagsWriter &Writer,
const LangOptions &LangOpts,
64 ~SDiagsRenderer()
override {}
88 typedef llvm::DenseMap<unsigned, unsigned> AbbrevLookup;
92 AbbrevLookup FileLookup;
93 AbbrevLookup CategoryLookup;
94 AbbrevLookup DiagFlagLookup;
97 SDiagsMerger(SDiagsWriter &Writer)
100 std::error_code mergeRecordsFromFile(
const char *File) {
101 return readDiagnostics(File);
105 std::error_code visitStartOfDiagnostic()
override;
106 std::error_code visitEndOfDiagnostic()
override;
107 std::error_code visitCategoryRecord(
unsigned ID, StringRef Name)
override;
108 std::error_code visitDiagFlagRecord(
unsigned ID, StringRef Name)
override;
109 std::error_code visitDiagnosticRecord(
111 unsigned Category,
unsigned Flag, StringRef Message)
override;
112 std::error_code visitFilenameRecord(
unsigned ID,
unsigned Size,
114 StringRef Name)
override;
117 StringRef CodeToInsert)
override;
123 std::error_code adjustSourceLocFilename(RecordData &Record,
124 unsigned int offset);
126 void adjustAbbrevID(RecordData &Record, AbbrevLookup &Lookup,
129 void writeRecordWithAbbrev(
unsigned ID, RecordData &Record);
131 void writeRecordWithBlob(
unsigned ID, RecordData &Record, StringRef Blob);
135 friend class SDiagsRenderer;
136 friend class SDiagsMerger;
140 explicit SDiagsWriter(std::shared_ptr<SharedState>
State)
141 : LangOpts(nullptr), OriginalInstance(
false), MergeChildRecords(
false),
142 State(
std::move(State)) {}
146 : LangOpts(nullptr), OriginalInstance(
true),
147 MergeChildRecords(MergeChildRecords),
148 State(
std::make_shared<SharedState>(File, Diags)) {
149 if (MergeChildRecords)
150 RemoveOldDiagnostics();
154 ~SDiagsWriter()
override {}
163 void finish()
override;
172 void RemoveOldDiagnostics();
178 void EmitBlockInfoBlock();
181 void EmitMetaBlock();
184 void EnterDiagBlock();
187 void ExitDiagBlock();
203 unsigned getEmitCategory(
unsigned category = 0);
207 unsigned DiagID = 0);
209 unsigned getEmitDiagnosticFlag(StringRef DiagName);
212 unsigned getEmitFile(
const char *
Filename);
216 RecordDataImpl &Record,
unsigned TokSize = 0);
219 void AddLocToRecord(
FullSourceLoc Loc, RecordDataImpl &Record,
220 unsigned TokSize = 0) {
226 void AddCharSourceRangeToRecord(
CharSourceRange R, RecordDataImpl &Record,
235 bool OriginalInstance;
239 bool MergeChildRecords;
245 : DiagOpts(Diags), Stream(Buffer), OutputFile(File.str()),
246 EmittedAnyDiagBlocks(
false) {}
255 llvm::BitstreamWriter Stream;
258 std::string OutputFile;
261 AbbreviationMap Abbrevs;
273 llvm::DenseMap<const char *, unsigned> Files;
275 typedef llvm::DenseMap<const void *, std::pair<unsigned, StringRef> >
279 DiagFlagsTy DiagFlags;
284 bool EmittedAnyDiagBlocks;
287 std::unique_ptr<DiagnosticsEngine> MetaDiagnostics;
291 std::shared_ptr<SharedState>
State;
296 namespace serialized_diags {
297 std::unique_ptr<DiagnosticConsumer>
299 return std::make_unique<SDiagsWriter>(OutputFile, Diags, MergeChildRecords);
311 llvm::BitstreamWriter &Stream,
312 RecordDataImpl &Record) {
314 Record.push_back(ID);
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,
332 RecordDataImpl &Record){
334 Record.push_back(ID);
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);
354 Record.push_back(PLoc.
getLine());
355 Record.push_back(PLoc.
getColumn()+TokSize);
360 RecordDataImpl &Record,
363 unsigned TokSize = 0;
371 unsigned SDiagsWriter::getEmitFile(
const char *FileName){
375 unsigned &entry =
State->Files[FileName];
380 entry =
State->Files.size();
381 StringRef Name(FileName);
392 State->Record.clear();
394 AddCharSourceRangeToRecord(R,
State->Record, SM);
400 void 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));
424 void 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));
513 void SDiagsWriter::EmitMetaBlock() {
514 llvm::BitstreamWriter &Stream =
State->Stream;
515 AbbreviationMap &Abbrevs =
State->Abbrevs;
523 unsigned SDiagsWriter::getEmitCategory(
unsigned int category) {
524 if (!
State->Categories.insert(category).second)
530 RecordData::value_type Record[] = {
RECORD_CATEGORY, category, catName.size()};
543 return getEmitDiagnosticFlag(FlagName);
546 unsigned 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;
574 if (
State->EmittedAnyDiagBlocks)
578 State->EmittedAnyDiagBlocks =
true;
582 State->diagBuf.clear();
596 State->diagBuf, &Info);
605 "Unexpected diagnostic with valid location outside of a source file");
606 SDiagsRenderer Renderer(*
this, *LangOpts, &*
State->DiagOpts);
607 Renderer.emitDiagnostic(
614 #define CASE(X) case DiagnosticsEngine::X: return serialized_diags::X; 624 llvm_unreachable(
"invalid diagnostic level");
631 llvm::BitstreamWriter &Stream =
State->Stream;
632 RecordData &Record =
State->Record;
633 AbbreviationMap &Abbrevs =
State->Abbrevs;
639 AddLocToRecord(Loc, PLoc, Record);
644 Record.push_back(getEmitCategory(DiagID));
646 Record.push_back(getEmitDiagnosticFlag(Level, Info->
getID()));
648 Record.push_back(getEmitCategory());
649 Record.push_back(getEmitDiagnosticFlag(Level));
652 Record.push_back(Message.size());
653 Stream.EmitRecordWithBlob(Abbrevs.get(
RECORD_DIAG), Record, Message);
656 void SDiagsRenderer::emitDiagnosticMessage(
660 Writer.EmitDiagnosticMessage(Loc, PLoc, Level, Message, D);
663 void SDiagsWriter::EnterDiagBlock() {
667 void SDiagsWriter::ExitDiagBlock() {
668 State->Stream.ExitBlock();
674 Writer.EnterDiagBlock();
682 Writer.ExitDiagBlock();
688 llvm::BitstreamWriter &Stream =
State->Stream;
689 RecordData &Record =
State->Record;
690 AbbreviationMap &Abbrevs =
State->Abbrevs;
696 EmitCharSourceRange(*I, SM);
706 AddCharSourceRangeToRecord(Fix.
RemoveRange, Record, SM);
708 Stream.EmitRecordWithBlob(Abbrevs.get(
RECORD_FIXIT), Record,
717 Writer.EmitCodeContext(Ranges, Hints, Loc.
getManager());
720 void SDiagsRenderer::emitNote(
FullSourceLoc Loc, StringRef Message) {
721 Writer.EnterDiagBlock();
725 Writer.ExitDiagBlock();
742 if (!
State->MetaDiagnostics) {
746 State->MetaDiagnostics = std::make_unique<DiagnosticsEngine>(
747 IDs,
State->DiagOpts.get(), Client);
749 return State->MetaDiagnostics.get();
752 void SDiagsWriter::RemoveOldDiagnostics() {
756 getMetaDiags()->Report(diag::warn_fe_serialized_diag_merge_failure);
759 MergeChildRecords =
false;
762 void SDiagsWriter::finish() {
764 if (!OriginalInstance)
768 if (
State->EmittedAnyDiagBlocks)
771 if (MergeChildRecords) {
772 if (!
State->EmittedAnyDiagBlocks)
777 if (llvm::sys::fs::exists(
State->OutputFile))
778 if (SDiagsMerger(*this).mergeRecordsFromFile(
State->OutputFile.c_str()))
779 getMetaDiags()->Report(diag::warn_fe_serialized_diag_merge_failure);
783 auto OS = std::make_unique<llvm::raw_fd_ostream>(
State->OutputFile.c_str(),
784 EC, llvm::sys::fs::OF_None);
786 getMetaDiags()->Report(diag::warn_fe_serialized_diag_failure)
787 <<
State->OutputFile << EC.message();
792 OS->write((
char *)&
State->Buffer.front(),
State->Buffer.size());
796 std::error_code SDiagsMerger::visitStartOfDiagnostic() {
797 Writer.EnterDiagBlock();
798 return std::error_code();
801 std::error_code SDiagsMerger::visitEndOfDiagnostic() {
802 Writer.ExitDiagBlock();
803 return std::error_code();
809 RecordData::value_type Record[] = {
812 Writer.State->Stream.EmitRecordWithAbbrev(
814 return std::error_code();
817 std::error_code SDiagsMerger::visitDiagnosticRecord(
819 unsigned Category,
unsigned Flag, StringRef Message) {
820 RecordData::value_type Record[] = {
823 Flag ? DiagFlagLookup[Flag] : 0, Message.size()};
825 Writer.State->Stream.EmitRecordWithBlob(
826 Writer.State->Abbrevs.get(
RECORD_DIAG), Record, Message);
827 return std::error_code();
839 Writer.State->Stream.EmitRecordWithBlob(
841 return std::error_code();
844 std::error_code SDiagsMerger::visitFilenameRecord(
unsigned ID,
unsigned Size,
847 FileLookup[
ID] = Writer.getEmitFile(Name.str().c_str());
848 return std::error_code();
851 std::error_code SDiagsMerger::visitCategoryRecord(
unsigned ID, StringRef Name) {
852 CategoryLookup[
ID] = Writer.getEmitCategory(ID);
853 return std::error_code();
856 std::error_code SDiagsMerger::visitDiagFlagRecord(
unsigned ID, StringRef Name) {
857 DiagFlagLookup[
ID] = Writer.getEmitDiagnosticFlag(Name);
858 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)
Specialize PointerLikeTypeTraits to allow LazyGenerationalUpdatePtr to be placed into a PointerUnion...
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.