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"
30 using namespace clang;
31 using namespace clang::serialized_diags;
35 class AbbreviationMap {
36 llvm::DenseMap<unsigned, unsigned> Abbrevs;
40 void set(
unsigned recordID,
unsigned abbrevID) {
41 assert(Abbrevs.find(recordID) == Abbrevs.end()
42 &&
"Abbreviation already set.");
43 Abbrevs[recordID] = abbrevID;
46 unsigned get(
unsigned recordID) {
47 assert(Abbrevs.find(recordID) != Abbrevs.end() &&
48 "Abbreviation not set.");
49 return Abbrevs[recordID];
62 SDiagsRenderer(SDiagsWriter &Writer,
const LangOptions &LangOpts,
66 ~SDiagsRenderer()
override {}
97 typedef llvm::DenseMap<unsigned, unsigned> AbbrevLookup;
100 SDiagsWriter &Writer;
101 AbbrevLookup FileLookup;
102 AbbrevLookup CategoryLookup;
103 AbbrevLookup DiagFlagLookup;
106 SDiagsMerger(SDiagsWriter &Writer)
109 std::error_code mergeRecordsFromFile(
const char *File) {
110 return readDiagnostics(File);
114 std::error_code visitStartOfDiagnostic()
override;
115 std::error_code visitEndOfDiagnostic()
override;
116 std::error_code visitCategoryRecord(
unsigned ID, StringRef
Name)
override;
117 std::error_code visitDiagFlagRecord(
unsigned ID, StringRef
Name)
override;
118 std::error_code visitDiagnosticRecord(
120 unsigned Category,
unsigned Flag, StringRef Message)
override;
121 std::error_code visitFilenameRecord(
unsigned ID,
unsigned Size,
123 StringRef
Name)
override;
126 StringRef CodeToInsert)
override;
132 std::error_code adjustSourceLocFilename(RecordData &Record,
133 unsigned int offset);
135 void adjustAbbrevID(RecordData &Record, AbbrevLookup &Lookup,
138 void writeRecordWithAbbrev(
unsigned ID, RecordData &Record);
140 void writeRecordWithBlob(
unsigned ID, RecordData &Record, StringRef Blob);
144 friend class SDiagsRenderer;
145 friend class SDiagsMerger;
150 : LangOpts(nullptr), OriginalInstance(
false), MergeChildRecords(
false),
151 State(std::move(State)) {}
155 : LangOpts(nullptr), OriginalInstance(
true),
156 MergeChildRecords(MergeChildRecords),
157 State(new SharedState(File, Diags)) {
158 if (MergeChildRecords)
159 RemoveOldDiagnostics();
163 ~SDiagsWriter()
override {}
172 void finish()
override;
181 void RemoveOldDiagnostics();
187 void EmitBlockInfoBlock();
190 void EmitMetaBlock();
193 void EnterDiagBlock();
196 void ExitDiagBlock();
215 unsigned getEmitCategory(
unsigned category = 0);
219 unsigned DiagID = 0);
221 unsigned getEmitDiagnosticFlag(StringRef DiagName);
224 unsigned getEmitFile(
const char *
Filename);
229 unsigned TokSize = 0);
234 unsigned TokSize = 0) {
240 void AddCharSourceRangeToRecord(
CharSourceRange R, RecordDataImpl &Record,
249 bool OriginalInstance;
253 bool MergeChildRecords;
259 : DiagOpts(Diags), Stream(
Buffer), OutputFile(File.str()),
260 EmittedAnyDiagBlocks(
false) {}
269 llvm::BitstreamWriter Stream;
272 std::string OutputFile;
275 AbbreviationMap Abbrevs;
287 llvm::DenseMap<const char *, unsigned> Files;
289 typedef llvm::DenseMap<const void *, std::pair<unsigned, StringRef> >
293 DiagFlagsTy DiagFlags;
298 bool EmittedAnyDiagBlocks;
301 std::unique_ptr<DiagnosticsEngine> MetaDiagnostics;
310 namespace serialized_diags {
311 std::unique_ptr<DiagnosticConsumer>
313 return llvm::make_unique<SDiagsWriter>(OutputFile, Diags, MergeChildRecords);
325 llvm::BitstreamWriter &Stream,
326 RecordDataImpl &Record) {
328 Record.push_back(ID);
329 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
332 if (!Name || Name[0] == 0)
338 Record.push_back(*Name++);
340 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record);
345 llvm::BitstreamWriter &Stream,
346 RecordDataImpl &Record){
348 Record.push_back(ID);
351 Record.push_back(*Name++);
353 Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
359 RecordDataImpl &Record,
363 Record.push_back((
unsigned)0);
364 Record.push_back((
unsigned)0);
365 Record.push_back((
unsigned)0);
366 Record.push_back((
unsigned)0);
371 Record.push_back(PLoc.
getLine());
372 Record.push_back(PLoc.
getColumn()+TokSize);
377 RecordDataImpl &Record,
379 AddLocToRecord(Range.
getBegin(), Record, &
SM);
380 unsigned TokSize = 0;
385 AddLocToRecord(Range.
getEnd(), Record, &
SM, TokSize);
388 unsigned SDiagsWriter::getEmitFile(
const char *
FileName){
397 entry =
State->Files.size();
398 StringRef
Name(FileName);
409 State->Record.clear();
411 AddCharSourceRangeToRecord(R,
State->Record, SM);
417 void SDiagsWriter::EmitPreamble() {
419 State->Stream.Emit((
unsigned)
'D', 8);
420 State->Stream.Emit((
unsigned)
'I', 8);
421 State->Stream.Emit((
unsigned)
'A', 8);
422 State->Stream.Emit((
unsigned)
'G', 8);
424 EmitBlockInfoBlock();
429 using namespace llvm;
430 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
431 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
432 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
433 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
441 void SDiagsWriter::EmitBlockInfoBlock() {
442 State->Stream.EnterBlockInfoBlock(3);
444 using namespace llvm;
445 llvm::BitstreamWriter &Stream =
State->Stream;
446 RecordData &Record =
State->Record;
447 AbbreviationMap &Abbrevs =
State->Abbrevs;
455 BitCodeAbbrev *Abbrev =
new BitCodeAbbrev();
457 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
473 Abbrev =
new BitCodeAbbrev();
475 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3));
477 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
478 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
479 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16));
480 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
484 Abbrev =
new BitCodeAbbrev();
486 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16));
487 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8));
488 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
492 Abbrev =
new BitCodeAbbrev();
496 Stream.EmitBlockInfoAbbrev(
BLOCK_DIAG, Abbrev));
499 Abbrev =
new BitCodeAbbrev();
501 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
502 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16));
503 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
508 Abbrev =
new BitCodeAbbrev();
510 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
511 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
512 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
513 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16));
514 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
519 Abbrev =
new BitCodeAbbrev();
522 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16));
523 Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
530 void SDiagsWriter::EmitMetaBlock() {
531 llvm::BitstreamWriter &Stream =
State->Stream;
532 AbbreviationMap &Abbrevs =
State->Abbrevs;
540 unsigned SDiagsWriter::getEmitCategory(
unsigned int category) {
541 if (!
State->Categories.insert(category).second)
547 RecordData::value_type Record[] = {
RECORD_CATEGORY, category, catName.size()};
560 return getEmitDiagnosticFlag(FlagName);
563 unsigned SDiagsWriter::getEmitDiagnosticFlag(StringRef FlagName) {
564 if (FlagName.empty())
569 const void *data = FlagName.data();
570 std::pair<unsigned, StringRef> &entry =
State->DiagFlags[data];
571 if (entry.first == 0) {
572 entry.first =
State->DiagFlags.size();
573 entry.second = FlagName;
591 if (
State->EmittedAnyDiagBlocks)
595 State->EmittedAnyDiagBlocks =
true;
599 State->diagBuf.clear();
613 State->diagBuf,
nullptr, &Info);
622 "Unexpected diagnostic with valid location outside of a source file");
623 SDiagsRenderer Renderer(*
this, *LangOpts, &*
State->DiagOpts);
624 Renderer.emitDiagnostic(Info.
getLocation(), DiagLevel,
634 #define CASE(X) case DiagnosticsEngine::X: return serialized_diags::X;
644 llvm_unreachable(
"invalid diagnostic level");
653 llvm::BitstreamWriter &Stream =
State->Stream;
654 RecordData &Record =
State->Record;
655 AbbreviationMap &Abbrevs =
State->Abbrevs;
661 AddLocToRecord(Loc, SM, PLoc, Record);
666 Record.push_back(getEmitCategory(DiagID));
668 Record.push_back(getEmitDiagnosticFlag(Level, Info->
getID()));
670 Record.push_back(getEmitCategory());
671 Record.push_back(getEmitDiagnosticFlag(Level));
674 Record.push_back(Message.size());
675 Stream.EmitRecordWithBlob(Abbrevs.get(
RECORD_DIAG), Record, Message);
686 Writer.EmitDiagnosticMessage(Loc, PLoc, Level, Message, SM, D);
689 void SDiagsWriter::EnterDiagBlock() {
693 void SDiagsWriter::ExitDiagBlock() {
694 State->Stream.ExitBlock();
700 Writer.EnterDiagBlock();
708 Writer.ExitDiagBlock();
714 llvm::BitstreamWriter &Stream =
State->Stream;
715 RecordData &Record =
State->Record;
716 AbbreviationMap &Abbrevs =
State->Abbrevs;
722 EmitCharSourceRange(*
I, SM);
732 AddCharSourceRangeToRecord(Fix.
RemoveRange, Record, SM);
734 Stream.EmitRecordWithBlob(Abbrevs.get(
RECORD_FIXIT), Record,
744 Writer.EmitCodeContext(Ranges, Hints, SM);
747 void SDiagsRenderer::emitNote(
SourceLocation Loc, StringRef Message,
749 Writer.EnterDiagBlock();
753 Writer.ExitDiagBlock();
770 if (!
State->MetaDiagnostics) {
774 State->MetaDiagnostics = llvm::make_unique<DiagnosticsEngine>(
775 IDs,
State->DiagOpts.get(), Client);
777 return State->MetaDiagnostics.get();
780 void SDiagsWriter::RemoveOldDiagnostics() {
781 if (!llvm::sys::fs::remove(
State->OutputFile))
784 getMetaDiags()->Report(diag::warn_fe_serialized_diag_merge_failure);
787 MergeChildRecords =
false;
790 void SDiagsWriter::finish() {
792 if (!OriginalInstance)
796 if (
State->EmittedAnyDiagBlocks)
799 if (MergeChildRecords) {
800 if (!
State->EmittedAnyDiagBlocks)
805 if (llvm::sys::fs::exists(
State->OutputFile))
806 if (SDiagsMerger(*this).mergeRecordsFromFile(
State->OutputFile.c_str()))
807 getMetaDiags()->Report(diag::warn_fe_serialized_diag_merge_failure);
811 auto OS = llvm::make_unique<llvm::raw_fd_ostream>(
State->OutputFile.c_str(),
812 EC, llvm::sys::fs::F_None);
814 getMetaDiags()->Report(diag::warn_fe_serialized_diag_failure)
815 <<
State->OutputFile << EC.message();
820 OS->write((
char *)&
State->Buffer.front(),
State->Buffer.size());
824 std::error_code SDiagsMerger::visitStartOfDiagnostic() {
825 Writer.EnterDiagBlock();
826 return std::error_code();
829 std::error_code SDiagsMerger::visitEndOfDiagnostic() {
830 Writer.ExitDiagBlock();
831 return std::error_code();
837 RecordData::value_type Record[] = {
840 Writer.State->Stream.EmitRecordWithAbbrev(
842 return std::error_code();
845 std::error_code SDiagsMerger::visitDiagnosticRecord(
847 unsigned Category,
unsigned Flag, StringRef Message) {
848 RecordData::value_type Record[] = {
851 Flag ? DiagFlagLookup[Flag] : 0, Message.size()};
853 Writer.State->Stream.EmitRecordWithBlob(
854 Writer.State->Abbrevs.get(
RECORD_DIAG), Record, Message);
855 return std::error_code();
867 Writer.State->Stream.EmitRecordWithBlob(
869 return std::error_code();
872 std::error_code SDiagsMerger::visitFilenameRecord(
unsigned ID,
unsigned Size,
875 FileLookup[
ID] = Writer.getEmitFile(Name.str().c_str());
876 return std::error_code();
879 std::error_code SDiagsMerger::visitCategoryRecord(
unsigned ID, StringRef Name) {
880 CategoryLookup[
ID] = Writer.getEmitCategory(ID);
881 return std::error_code();
884 std::error_code SDiagsMerger::visitDiagFlagRecord(
unsigned ID, StringRef Name) {
885 DiagFlagLookup[
ID] = Writer.getEmitDiagnosticFlag(Name);
886 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
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.