22 #include "llvm/ADT/DenseSet.h"
23 #include "llvm/ADT/STLExtras.h"
24 #include "llvm/ADT/SmallString.h"
25 #include "llvm/ADT/StringRef.h"
26 #include "llvm/Support/raw_ostream.h"
29 using namespace clang;
30 using namespace clang::serialized_diags;
34 class AbbreviationMap {
35 llvm::DenseMap<unsigned, unsigned> Abbrevs;
39 void set(
unsigned recordID,
unsigned abbrevID) {
40 assert(Abbrevs.find(recordID) == Abbrevs.end()
41 &&
"Abbreviation already set.");
42 Abbrevs[recordID] = abbrevID;
45 unsigned get(
unsigned recordID) {
46 assert(Abbrevs.find(recordID) != Abbrevs.end() &&
47 "Abbreviation not set.");
48 return Abbrevs[recordID];
60 SDiagsRenderer(SDiagsWriter &Writer,
const LangOptions &LangOpts,
64 ~SDiagsRenderer()
override {}
95 typedef llvm::DenseMap<unsigned, unsigned> AbbrevLookup;
99 AbbrevLookup FileLookup;
100 AbbrevLookup CategoryLookup;
101 AbbrevLookup DiagFlagLookup;
104 SDiagsMerger(SDiagsWriter &Writer)
107 std::error_code mergeRecordsFromFile(
const char *File) {
108 return readDiagnostics(File);
112 std::error_code visitStartOfDiagnostic()
override;
113 std::error_code visitEndOfDiagnostic()
override;
114 std::error_code visitCategoryRecord(
unsigned ID, StringRef Name)
override;
115 std::error_code visitDiagFlagRecord(
unsigned ID, StringRef Name)
override;
116 std::error_code visitDiagnosticRecord(
118 unsigned Category,
unsigned Flag, StringRef Message)
override;
119 std::error_code visitFilenameRecord(
unsigned ID,
unsigned Size,
121 StringRef Name)
override;
124 StringRef CodeToInsert)
override;
130 std::error_code adjustSourceLocFilename(RecordData &Record,
131 unsigned int offset);
133 void adjustAbbrevID(RecordData &Record, AbbrevLookup &Lookup,
136 void writeRecordWithAbbrev(
unsigned ID, RecordData &Record);
138 void writeRecordWithBlob(
unsigned ID, RecordData &Record, StringRef Blob);
142 friend class SDiagsRenderer;
143 friend class SDiagsMerger;
148 : LangOpts(nullptr), OriginalInstance(
false), MergeChildRecords(
false),
153 : LangOpts(nullptr), OriginalInstance(
true),
154 MergeChildRecords(MergeChildRecords),
155 State(new SharedState(File, Diags)) {
156 if (MergeChildRecords)
157 RemoveOldDiagnostics();
161 ~SDiagsWriter()
override {}
170 void finish()
override;
179 void RemoveOldDiagnostics();
185 void EmitBlockInfoBlock();
188 void EmitMetaBlock();
191 void EnterDiagBlock();
194 void ExitDiagBlock();
213 unsigned getEmitCategory(
unsigned category = 0);
217 unsigned DiagID = 0);
219 unsigned getEmitDiagnosticFlag(StringRef DiagName);
222 unsigned getEmitFile(
const char *Filename);
227 unsigned TokSize = 0);
232 unsigned TokSize = 0) {
238 void AddCharSourceRangeToRecord(
CharSourceRange R, RecordDataImpl &Record,
247 bool OriginalInstance;
251 bool MergeChildRecords;
257 : DiagOpts(Diags), Stream(Buffer), OutputFile(File.str()),
258 EmittedAnyDiagBlocks(
false) {}
267 llvm::BitstreamWriter Stream;
270 std::string OutputFile;
273 AbbreviationMap Abbrevs;
285 llvm::DenseMap<const char *, unsigned> Files;
287 typedef llvm::DenseMap<const void *, std::pair<unsigned, StringRef> >
291 DiagFlagsTy DiagFlags;
296 bool EmittedAnyDiagBlocks;
299 std::unique_ptr<DiagnosticsEngine> MetaDiagnostics;
308 namespace serialized_diags {
309 std::unique_ptr<DiagnosticConsumer>
311 return llvm::make_unique<SDiagsWriter>(OutputFile, Diags, MergeChildRecords);
323 llvm::BitstreamWriter &Stream,
324 RecordDataImpl &Record) {
326 Record.push_back(ID);
327 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
330 if (!Name || Name[0] == 0)
336 Record.push_back(*Name++);
338 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record);
343 llvm::BitstreamWriter &Stream,
344 RecordDataImpl &Record){
346 Record.push_back(ID);
349 Record.push_back(*Name++);
351 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
357 RecordDataImpl &Record,
361 Record.push_back((
unsigned)0);
362 Record.push_back((
unsigned)0);
363 Record.push_back((
unsigned)0);
364 Record.push_back((
unsigned)0);
369 Record.push_back(PLoc.
getLine());
370 Record.push_back(PLoc.
getColumn()+TokSize);
375 RecordDataImpl &Record,
377 AddLocToRecord(Range.
getBegin(), Record, &
SM);
378 unsigned TokSize = 0;
383 AddLocToRecord(Range.
getEnd(), Record, &
SM, TokSize);
386 unsigned SDiagsWriter::getEmitFile(
const char *FileName){
390 unsigned &entry =
State->Files[FileName];
395 entry =
State->Files.size();
398 Record.push_back(entry);
401 StringRef Name(FileName);
402 Record.push_back(Name.size());
411 State->Record.clear();
413 AddCharSourceRangeToRecord(R,
State->Record, SM);
419 void SDiagsWriter::EmitPreamble() {
421 State->Stream.Emit((
unsigned)
'D', 8);
422 State->Stream.Emit((
unsigned)
'I', 8);
423 State->Stream.Emit((
unsigned)
'A', 8);
424 State->Stream.Emit((
unsigned)
'G', 8);
426 EmitBlockInfoBlock();
431 using namespace llvm;
432 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
433 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
434 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
435 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
443 void SDiagsWriter::EmitBlockInfoBlock() {
444 State->Stream.EnterBlockInfoBlock(3);
446 using namespace llvm;
447 llvm::BitstreamWriter &Stream =
State->Stream;
448 RecordData &Record =
State->Record;
449 AbbreviationMap &Abbrevs =
State->Abbrevs;
457 BitCodeAbbrev *Abbrev =
new BitCodeAbbrev();
459 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
475 Abbrev =
new BitCodeAbbrev();
477 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3));
479 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
480 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
481 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16));
482 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
486 Abbrev =
new BitCodeAbbrev();
488 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16));
489 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8));
490 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
494 Abbrev =
new BitCodeAbbrev();
498 Stream.EmitBlockInfoAbbrev(
BLOCK_DIAG, Abbrev));
501 Abbrev =
new BitCodeAbbrev();
503 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
504 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16));
505 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
510 Abbrev =
new BitCodeAbbrev();
512 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
513 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
514 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
515 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16));
516 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
521 Abbrev =
new BitCodeAbbrev();
524 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16));
525 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
532 void SDiagsWriter::EmitMetaBlock() {
533 llvm::BitstreamWriter &Stream =
State->Stream;
534 RecordData &Record =
State->Record;
535 AbbreviationMap &Abbrevs =
State->Abbrevs;
545 unsigned SDiagsWriter::getEmitCategory(
unsigned int category) {
546 if (!
State->Categories.insert(category).second)
553 Record.push_back(category);
555 Record.push_back(catName.size());
568 return getEmitDiagnosticFlag(FlagName);
571 unsigned SDiagsWriter::getEmitDiagnosticFlag(StringRef FlagName) {
572 if (FlagName.empty())
577 const void *data = FlagName.data();
578 std::pair<unsigned, StringRef> &entry =
State->DiagFlags[data];
579 if (entry.first == 0) {
580 entry.first =
State->DiagFlags.size();
581 entry.second = FlagName;
586 Record.push_back(entry.first);
587 Record.push_back(FlagName.size());
601 if (
State->EmittedAnyDiagBlocks)
605 State->EmittedAnyDiagBlocks =
true;
609 State->diagBuf.clear();
623 State->diagBuf,
nullptr, &Info);
632 "Unexpected diagnostic with valid location outside of a source file");
633 SDiagsRenderer Renderer(*
this, *LangOpts, &*
State->DiagOpts);
634 Renderer.emitDiagnostic(Info.
getLocation(), DiagLevel,
644 #define CASE(X) case DiagnosticsEngine::X: return serialized_diags::X;
654 llvm_unreachable(
"invalid diagnostic level");
663 llvm::BitstreamWriter &Stream =
State->Stream;
664 RecordData &Record =
State->Record;
665 AbbreviationMap &Abbrevs =
State->Abbrevs;
671 AddLocToRecord(Loc, SM, PLoc, Record);
676 Record.push_back(getEmitCategory(DiagID));
678 Record.push_back(getEmitDiagnosticFlag(Level, Info->
getID()));
680 Record.push_back(getEmitCategory());
681 Record.push_back(getEmitDiagnosticFlag(Level));
684 Record.push_back(Message.size());
685 Stream.EmitRecordWithBlob(Abbrevs.get(
RECORD_DIAG), Record, Message);
696 Writer.EmitDiagnosticMessage(Loc, PLoc, Level, Message, SM, D);
699 void SDiagsWriter::EnterDiagBlock() {
703 void SDiagsWriter::ExitDiagBlock() {
704 State->Stream.ExitBlock();
710 Writer.EnterDiagBlock();
718 Writer.ExitDiagBlock();
724 llvm::BitstreamWriter &Stream =
State->Stream;
725 RecordData &Record =
State->Record;
726 AbbreviationMap &Abbrevs =
State->Abbrevs;
732 EmitCharSourceRange(*I, SM);
742 AddCharSourceRangeToRecord(Fix.
RemoveRange, Record, SM);
744 Stream.EmitRecordWithBlob(Abbrevs.get(
RECORD_FIXIT), Record,
754 Writer.EmitCodeContext(Ranges, Hints, SM);
757 void SDiagsRenderer::emitNote(
SourceLocation Loc, StringRef Message,
759 Writer.EnterDiagBlock();
763 Writer.ExitDiagBlock();
780 if (!
State->MetaDiagnostics) {
784 State->MetaDiagnostics = llvm::make_unique<DiagnosticsEngine>(
785 IDs,
State->DiagOpts.get(), Client);
787 return State->MetaDiagnostics.get();
790 void SDiagsWriter::RemoveOldDiagnostics() {
791 if (!llvm::sys::fs::remove(
State->OutputFile))
794 getMetaDiags()->Report(diag::warn_fe_serialized_diag_merge_failure);
797 MergeChildRecords =
false;
800 void SDiagsWriter::finish() {
802 if (!OriginalInstance)
806 if (
State->EmittedAnyDiagBlocks)
809 if (MergeChildRecords) {
810 if (!
State->EmittedAnyDiagBlocks)
815 if (llvm::sys::fs::exists(
State->OutputFile))
816 if (SDiagsMerger(*this).mergeRecordsFromFile(
State->OutputFile.c_str()))
817 getMetaDiags()->Report(diag::warn_fe_serialized_diag_merge_failure);
821 auto OS = llvm::make_unique<llvm::raw_fd_ostream>(
State->OutputFile.c_str(),
822 EC, llvm::sys::fs::F_None);
824 getMetaDiags()->Report(diag::warn_fe_serialized_diag_failure)
825 <<
State->OutputFile << EC.message();
830 OS->write((
char *)&
State->Buffer.front(),
State->Buffer.size());
834 std::error_code SDiagsMerger::visitStartOfDiagnostic() {
835 Writer.EnterDiagBlock();
836 return std::error_code();
839 std::error_code SDiagsMerger::visitEndOfDiagnostic() {
840 Writer.ExitDiagBlock();
841 return std::error_code();
849 Record.push_back(FileLookup[Start.
FileID]);
850 Record.push_back(Start.
Line);
851 Record.push_back(Start.
Col);
852 Record.push_back(Start.
Offset);
853 Record.push_back(FileLookup[End.
FileID]);
854 Record.push_back(End.
Line);
855 Record.push_back(End.
Col);
856 Record.push_back(End.
Offset);
858 Writer.State->Stream.EmitRecordWithAbbrev(
860 return std::error_code();
863 std::error_code SDiagsMerger::visitDiagnosticRecord(
865 unsigned Category,
unsigned Flag, StringRef Message) {
866 RecordData MergedRecord;
868 MergedRecord.push_back(Severity);
869 MergedRecord.push_back(FileLookup[Location.
FileID]);
870 MergedRecord.push_back(Location.
Line);
871 MergedRecord.push_back(Location.
Col);
872 MergedRecord.push_back(Location.
Offset);
873 MergedRecord.push_back(CategoryLookup[Category]);
874 MergedRecord.push_back(Flag ? DiagFlagLookup[Flag] : 0);
875 MergedRecord.push_back(Message.size());
877 Writer.State->Stream.EmitRecordWithBlob(
878 Writer.State->Abbrevs.get(
RECORD_DIAG), MergedRecord, Message);
879 return std::error_code();
888 Record.push_back(FileLookup[Start.
FileID]);
889 Record.push_back(Start.
Line);
890 Record.push_back(Start.
Col);
891 Record.push_back(Start.
Offset);
892 Record.push_back(FileLookup[End.
FileID]);
893 Record.push_back(End.
Line);
894 Record.push_back(End.
Col);
895 Record.push_back(End.
Offset);
896 Record.push_back(Text.size());
898 Writer.State->Stream.EmitRecordWithBlob(
900 return std::error_code();
903 std::error_code SDiagsMerger::visitFilenameRecord(
unsigned ID,
unsigned Size,
906 FileLookup[
ID] = Writer.getEmitFile(Name.str().c_str());
907 return std::error_code();
910 std::error_code SDiagsMerger::visitCategoryRecord(
unsigned ID, StringRef Name) {
911 CategoryLookup[
ID] = Writer.getEmitCategory(ID);
912 return std::error_code();
915 std::error_code SDiagsMerger::visitDiagFlagRecord(
unsigned ID, StringRef Name) {
916 DiagFlagLookup[
ID] = Writer.getEmitDiagnosticFlag(Name);
917 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)
SourceLocation getBegin() const
unsigned getColumn() const
Return the presumed column number of this location.
Defines the clang::FileManager interface and associated types.
bool isInvalid() const
Return true if this object is invalid or uninitialized.
Defines the SourceManager interface.
Level
A stable version of DiagnosticIDs::Level.
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)
Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...
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.
static void EmitRecordID(unsigned ID, const char *Name, llvm::BitstreamWriter &Stream, RecordDataImpl &Record)
Emits a record ID in the BLOCKINFO block.
unsigned getLine() const
Return the presumed line number of this location.
ID
Defines the set of possible language-specific address spaces.
Represents a character-granular source range.
SourceLocation getEnd() const
static unsigned MeasureTokenLength(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
Defines version macros and version-related utility functions for Clang.
static void EmitBlockID(unsigned ID, const char *Name, llvm::BitstreamWriter &Stream, RecordDataImpl &Record)
Emits a block ID in the BLOCKINFO block.
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.
CharSourceRange RemoveRange
Code that should be replaced to correct the error. Empty for an insertion hint.
llvm::PointerUnion< const Diagnostic *, const StoredDiagnostic * > DiagOrStoredDiag
bool isTokenRange() const
Return true if the end of this range specifies the start of the last token. Return false if the end o...
const char * getFilename() const
Return the presumed filename of this location.
Encodes a location in the source. The SourceManager can decode this to get at the full include stack...
Options for controlling the compiler diagnostics engine.
A base class that handles reading serialized diagnostics from a file.
bool hasSourceManager() const
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.
ArrayRef< CharSourceRange > getRanges() const
Return an array reference for this diagnostic's ranges.
Defines the Diagnostic-related interfaces.
SourceManager & getSourceManager() const
static void AddRangeLocationAbbrev(llvm::BitCodeAbbrev *Abbrev)
Level
The level of the diagnostic, after it has been through mapping.
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...
unsigned getFileOffset(SourceLocation SpellingLoc) const
Returns the offset from the start of the file that the specified SourceLocation represents.
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.
ArrayRef< FixItHint > getFixItHints() const
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
PresumedLoc getPresumedLoc(SourceLocation Loc, bool UseLineDirectives=true) const
Returns the "presumed" location of a SourceLocation specifies.