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];
61 SDiagsRenderer(SDiagsWriter &Writer,
const LangOptions &LangOpts,
65 ~SDiagsRenderer()
override {}
96 typedef llvm::DenseMap<unsigned, unsigned> AbbrevLookup;
100 AbbrevLookup FileLookup;
101 AbbrevLookup CategoryLookup;
102 AbbrevLookup DiagFlagLookup;
105 SDiagsMerger(SDiagsWriter &Writer)
108 std::error_code mergeRecordsFromFile(
const char *File) {
109 return readDiagnostics(File);
113 std::error_code visitStartOfDiagnostic()
override;
114 std::error_code visitEndOfDiagnostic()
override;
115 std::error_code visitCategoryRecord(
unsigned ID, StringRef
Name)
override;
116 std::error_code visitDiagFlagRecord(
unsigned ID, StringRef
Name)
override;
117 std::error_code visitDiagnosticRecord(
119 unsigned Category,
unsigned Flag, StringRef Message)
override;
120 std::error_code visitFilenameRecord(
unsigned ID,
unsigned Size,
122 StringRef
Name)
override;
125 StringRef CodeToInsert)
override;
131 std::error_code adjustSourceLocFilename(RecordData &Record,
132 unsigned int offset);
134 void adjustAbbrevID(RecordData &Record, AbbrevLookup &Lookup,
137 void writeRecordWithAbbrev(
unsigned ID, RecordData &Record);
139 void writeRecordWithBlob(
unsigned ID, RecordData &Record, StringRef Blob);
143 friend class SDiagsRenderer;
144 friend class SDiagsMerger;
149 : LangOpts(nullptr), OriginalInstance(
false), MergeChildRecords(
false),
154 : LangOpts(nullptr), OriginalInstance(
true),
155 MergeChildRecords(MergeChildRecords),
156 State(new SharedState(File, Diags)) {
157 if (MergeChildRecords)
158 RemoveOldDiagnostics();
162 ~SDiagsWriter()
override {}
171 void finish()
override;
180 void RemoveOldDiagnostics();
186 void EmitBlockInfoBlock();
189 void EmitMetaBlock();
192 void EnterDiagBlock();
195 void ExitDiagBlock();
214 unsigned getEmitCategory(
unsigned category = 0);
218 unsigned DiagID = 0);
220 unsigned getEmitDiagnosticFlag(StringRef DiagName);
223 unsigned getEmitFile(
const char *
Filename);
228 unsigned TokSize = 0);
233 unsigned TokSize = 0) {
239 void AddCharSourceRangeToRecord(
CharSourceRange R, RecordDataImpl &Record,
248 bool OriginalInstance;
252 bool MergeChildRecords;
258 : DiagOpts(Diags), Stream(
Buffer), OutputFile(File.str()),
259 EmittedAnyDiagBlocks(
false) {}
268 llvm::BitstreamWriter Stream;
271 std::string OutputFile;
274 AbbreviationMap Abbrevs;
286 llvm::DenseMap<const char *, unsigned> Files;
288 typedef llvm::DenseMap<const void *, std::pair<unsigned, StringRef> >
292 DiagFlagsTy DiagFlags;
297 bool EmittedAnyDiagBlocks;
300 std::unique_ptr<DiagnosticsEngine> MetaDiagnostics;
309 namespace serialized_diags {
310 std::unique_ptr<DiagnosticConsumer>
312 return llvm::make_unique<SDiagsWriter>(OutputFile, Diags, MergeChildRecords);
324 llvm::BitstreamWriter &Stream,
325 RecordDataImpl &Record) {
327 Record.push_back(ID);
328 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
331 if (!Name || Name[0] == 0)
337 Record.push_back(*Name++);
339 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record);
344 llvm::BitstreamWriter &Stream,
345 RecordDataImpl &Record){
347 Record.push_back(ID);
350 Record.push_back(*Name++);
352 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
358 RecordDataImpl &Record,
362 Record.push_back((
unsigned)0);
363 Record.push_back((
unsigned)0);
364 Record.push_back((
unsigned)0);
365 Record.push_back((
unsigned)0);
370 Record.push_back(PLoc.
getLine());
371 Record.push_back(PLoc.
getColumn()+TokSize);
376 RecordDataImpl &Record,
378 AddLocToRecord(Range.
getBegin(), Record, &
SM);
379 unsigned TokSize = 0;
384 AddLocToRecord(Range.
getEnd(), Record, &
SM, TokSize);
387 unsigned SDiagsWriter::getEmitFile(
const char *FileName){
391 unsigned &entry =
State->Files[FileName];
396 entry =
State->Files.size();
397 StringRef
Name(FileName);
408 State->Record.clear();
410 AddCharSourceRangeToRecord(R,
State->Record, SM);
416 void SDiagsWriter::EmitPreamble() {
418 State->Stream.Emit((
unsigned)
'D', 8);
419 State->Stream.Emit((
unsigned)
'I', 8);
420 State->Stream.Emit((
unsigned)
'A', 8);
421 State->Stream.Emit((
unsigned)
'G', 8);
423 EmitBlockInfoBlock();
428 using namespace llvm;
429 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
430 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
431 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
432 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
440 void SDiagsWriter::EmitBlockInfoBlock() {
441 State->Stream.EnterBlockInfoBlock(3);
443 using namespace llvm;
444 llvm::BitstreamWriter &Stream =
State->Stream;
445 RecordData &Record =
State->Record;
446 AbbreviationMap &Abbrevs =
State->Abbrevs;
454 BitCodeAbbrev *Abbrev =
new BitCodeAbbrev();
456 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
472 Abbrev =
new BitCodeAbbrev();
474 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3));
476 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
477 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
478 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16));
479 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
483 Abbrev =
new BitCodeAbbrev();
485 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16));
486 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8));
487 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
491 Abbrev =
new BitCodeAbbrev();
495 Stream.EmitBlockInfoAbbrev(
BLOCK_DIAG, Abbrev));
498 Abbrev =
new BitCodeAbbrev();
500 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
501 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16));
502 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
507 Abbrev =
new BitCodeAbbrev();
509 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
510 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
511 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
512 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16));
513 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
518 Abbrev =
new BitCodeAbbrev();
521 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16));
522 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
529 void SDiagsWriter::EmitMetaBlock() {
530 llvm::BitstreamWriter &Stream =
State->Stream;
531 AbbreviationMap &Abbrevs =
State->Abbrevs;
539 unsigned SDiagsWriter::getEmitCategory(
unsigned int category) {
540 if (!
State->Categories.insert(category).second)
546 RecordData::value_type Record[] = {
RECORD_CATEGORY, category, catName.size()};
559 return getEmitDiagnosticFlag(FlagName);
562 unsigned SDiagsWriter::getEmitDiagnosticFlag(StringRef FlagName) {
563 if (FlagName.empty())
568 const void *data = FlagName.data();
569 std::pair<unsigned, StringRef> &entry =
State->DiagFlags[data];
570 if (entry.first == 0) {
571 entry.first =
State->DiagFlags.size();
572 entry.second = FlagName;
590 if (
State->EmittedAnyDiagBlocks)
594 State->EmittedAnyDiagBlocks =
true;
598 State->diagBuf.clear();
612 State->diagBuf,
nullptr, &Info);
621 "Unexpected diagnostic with valid location outside of a source file");
622 SDiagsRenderer Renderer(*
this, *LangOpts, &*
State->DiagOpts);
623 Renderer.emitDiagnostic(Info.
getLocation(), DiagLevel,
633 #define CASE(X) case DiagnosticsEngine::X: return serialized_diags::X;
643 llvm_unreachable(
"invalid diagnostic level");
652 llvm::BitstreamWriter &Stream =
State->Stream;
653 RecordData &Record =
State->Record;
654 AbbreviationMap &Abbrevs =
State->Abbrevs;
660 AddLocToRecord(Loc, SM, PLoc, Record);
665 Record.push_back(getEmitCategory(DiagID));
667 Record.push_back(getEmitDiagnosticFlag(Level, Info->
getID()));
669 Record.push_back(getEmitCategory());
670 Record.push_back(getEmitDiagnosticFlag(Level));
673 Record.push_back(Message.size());
674 Stream.EmitRecordWithBlob(Abbrevs.get(
RECORD_DIAG), Record, Message);
685 Writer.EmitDiagnosticMessage(Loc, PLoc, Level, Message, SM, D);
688 void SDiagsWriter::EnterDiagBlock() {
692 void SDiagsWriter::ExitDiagBlock() {
693 State->Stream.ExitBlock();
699 Writer.EnterDiagBlock();
707 Writer.ExitDiagBlock();
713 llvm::BitstreamWriter &Stream =
State->Stream;
714 RecordData &Record =
State->Record;
715 AbbreviationMap &Abbrevs =
State->Abbrevs;
721 EmitCharSourceRange(*
I, SM);
731 AddCharSourceRangeToRecord(Fix.
RemoveRange, Record, SM);
733 Stream.EmitRecordWithBlob(Abbrevs.get(
RECORD_FIXIT), Record,
743 Writer.EmitCodeContext(Ranges, Hints, SM);
746 void SDiagsRenderer::emitNote(
SourceLocation Loc, StringRef Message,
748 Writer.EnterDiagBlock();
752 Writer.ExitDiagBlock();
769 if (!
State->MetaDiagnostics) {
773 State->MetaDiagnostics = llvm::make_unique<DiagnosticsEngine>(
774 IDs,
State->DiagOpts.get(), Client);
776 return State->MetaDiagnostics.get();
779 void SDiagsWriter::RemoveOldDiagnostics() {
780 if (!llvm::sys::fs::remove(
State->OutputFile))
783 getMetaDiags()->Report(diag::warn_fe_serialized_diag_merge_failure);
786 MergeChildRecords =
false;
789 void SDiagsWriter::finish() {
791 if (!OriginalInstance)
795 if (
State->EmittedAnyDiagBlocks)
798 if (MergeChildRecords) {
799 if (!
State->EmittedAnyDiagBlocks)
804 if (llvm::sys::fs::exists(
State->OutputFile))
805 if (SDiagsMerger(*this).mergeRecordsFromFile(
State->OutputFile.c_str()))
806 getMetaDiags()->Report(diag::warn_fe_serialized_diag_merge_failure);
810 auto OS = llvm::make_unique<llvm::raw_fd_ostream>(
State->OutputFile.c_str(),
811 EC, llvm::sys::fs::F_None);
813 getMetaDiags()->Report(diag::warn_fe_serialized_diag_failure)
814 <<
State->OutputFile << EC.message();
819 OS->write((
char *)&
State->Buffer.front(),
State->Buffer.size());
823 std::error_code SDiagsMerger::visitStartOfDiagnostic() {
824 Writer.EnterDiagBlock();
825 return std::error_code();
828 std::error_code SDiagsMerger::visitEndOfDiagnostic() {
829 Writer.ExitDiagBlock();
830 return std::error_code();
836 RecordData::value_type Record[] = {
839 Writer.State->Stream.EmitRecordWithAbbrev(
841 return std::error_code();
844 std::error_code SDiagsMerger::visitDiagnosticRecord(
846 unsigned Category,
unsigned Flag, StringRef Message) {
847 RecordData::value_type Record[] = {
850 Flag ? DiagFlagLookup[Flag] : 0, Message.size()};
852 Writer.State->Stream.EmitRecordWithBlob(
853 Writer.State->Abbrevs.get(
RECORD_DIAG), Record, Message);
854 return std::error_code();
866 Writer.State->Stream.EmitRecordWithBlob(
868 return std::error_code();
871 std::error_code SDiagsMerger::visitFilenameRecord(
unsigned ID,
unsigned Size,
874 FileLookup[
ID] = Writer.getEmitFile(Name.str().c_str());
875 return std::error_code();
878 std::error_code SDiagsMerger::visitCategoryRecord(
unsigned ID, StringRef Name) {
879 CategoryLookup[
ID] = Writer.getEmitCategory(ID);
880 return std::error_code();
883 std::error_code SDiagsMerger::visitDiagFlagRecord(
unsigned ID, StringRef Name) {
884 DiagFlagLookup[
ID] = Writer.getEmitDiagnosticFlag(Name);
885 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.
std::unique_ptr< llvm::MemoryBuffer > Buffer
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...
class LLVM_ALIGNAS(8) DependentTemplateSpecializationType const IdentifierInfo * Name
Represents a template specialization type whose template cannot be resolved, e.g. ...
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.
detail::InMemoryDirectory::const_iterator I
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)
MeasureTokenLength - Relex the token at the specified location and return its length in bytes in the ...
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.
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.
const char * getFilename() const
Return the presumed filename of this location.
Encodes a location in the source.
Subclass of DiagnosticRender that turns all subdiagostics into explicit notes.
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.
detail::InMemoryDirectory::const_iterator E
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.
A little helper class (which is basically a smart pointer that forwards info from DiagnosticsEngine) ...
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.