10b57cec5SDimitry Andric //===--- SerializedDiagnosticPrinter.cpp - Serializer for diagnostics -----===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "clang/Frontend/SerializedDiagnosticPrinter.h" 100b57cec5SDimitry Andric #include "clang/Basic/Diagnostic.h" 110b57cec5SDimitry Andric #include "clang/Basic/DiagnosticOptions.h" 120b57cec5SDimitry Andric #include "clang/Basic/SourceManager.h" 130b57cec5SDimitry Andric #include "clang/Frontend/DiagnosticRenderer.h" 140b57cec5SDimitry Andric #include "clang/Frontend/FrontendDiagnostic.h" 150b57cec5SDimitry Andric #include "clang/Frontend/SerializedDiagnosticReader.h" 160b57cec5SDimitry Andric #include "clang/Frontend/SerializedDiagnostics.h" 170b57cec5SDimitry Andric #include "clang/Frontend/TextDiagnosticPrinter.h" 180b57cec5SDimitry Andric #include "clang/Lex/Lexer.h" 190b57cec5SDimitry Andric #include "llvm/ADT/DenseSet.h" 200b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 210b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h" 220b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 230b57cec5SDimitry Andric #include "llvm/Bitstream/BitCodes.h" 240b57cec5SDimitry Andric #include "llvm/Bitstream/BitstreamReader.h" 25*5ffd83dbSDimitry Andric #include "llvm/Support/FileSystem.h" 260b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 270b57cec5SDimitry Andric #include <utility> 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric using namespace clang; 300b57cec5SDimitry Andric using namespace clang::serialized_diags; 310b57cec5SDimitry Andric 320b57cec5SDimitry Andric namespace { 330b57cec5SDimitry Andric 340b57cec5SDimitry Andric class AbbreviationMap { 350b57cec5SDimitry Andric llvm::DenseMap<unsigned, unsigned> Abbrevs; 360b57cec5SDimitry Andric public: 370b57cec5SDimitry Andric AbbreviationMap() {} 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric void set(unsigned recordID, unsigned abbrevID) { 400b57cec5SDimitry Andric assert(Abbrevs.find(recordID) == Abbrevs.end() 410b57cec5SDimitry Andric && "Abbreviation already set."); 420b57cec5SDimitry Andric Abbrevs[recordID] = abbrevID; 430b57cec5SDimitry Andric } 440b57cec5SDimitry Andric 450b57cec5SDimitry Andric unsigned get(unsigned recordID) { 460b57cec5SDimitry Andric assert(Abbrevs.find(recordID) != Abbrevs.end() && 470b57cec5SDimitry Andric "Abbreviation not set."); 480b57cec5SDimitry Andric return Abbrevs[recordID]; 490b57cec5SDimitry Andric } 500b57cec5SDimitry Andric }; 510b57cec5SDimitry Andric 520b57cec5SDimitry Andric typedef SmallVector<uint64_t, 64> RecordData; 530b57cec5SDimitry Andric typedef SmallVectorImpl<uint64_t> RecordDataImpl; 540b57cec5SDimitry Andric typedef ArrayRef<uint64_t> RecordDataRef; 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric class SDiagsWriter; 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric class SDiagsRenderer : public DiagnosticNoteRenderer { 590b57cec5SDimitry Andric SDiagsWriter &Writer; 600b57cec5SDimitry Andric public: 610b57cec5SDimitry Andric SDiagsRenderer(SDiagsWriter &Writer, const LangOptions &LangOpts, 620b57cec5SDimitry Andric DiagnosticOptions *DiagOpts) 630b57cec5SDimitry Andric : DiagnosticNoteRenderer(LangOpts, DiagOpts), Writer(Writer) {} 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric ~SDiagsRenderer() override {} 660b57cec5SDimitry Andric 670b57cec5SDimitry Andric protected: 680b57cec5SDimitry Andric void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc, 690b57cec5SDimitry Andric DiagnosticsEngine::Level Level, StringRef Message, 700b57cec5SDimitry Andric ArrayRef<CharSourceRange> Ranges, 710b57cec5SDimitry Andric DiagOrStoredDiag D) override; 720b57cec5SDimitry Andric 730b57cec5SDimitry Andric void emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc, 740b57cec5SDimitry Andric DiagnosticsEngine::Level Level, 750b57cec5SDimitry Andric ArrayRef<CharSourceRange> Ranges) override {} 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric void emitNote(FullSourceLoc Loc, StringRef Message) override; 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric void emitCodeContext(FullSourceLoc Loc, DiagnosticsEngine::Level Level, 800b57cec5SDimitry Andric SmallVectorImpl<CharSourceRange> &Ranges, 810b57cec5SDimitry Andric ArrayRef<FixItHint> Hints) override; 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric void beginDiagnostic(DiagOrStoredDiag D, 840b57cec5SDimitry Andric DiagnosticsEngine::Level Level) override; 850b57cec5SDimitry Andric void endDiagnostic(DiagOrStoredDiag D, 860b57cec5SDimitry Andric DiagnosticsEngine::Level Level) override; 870b57cec5SDimitry Andric }; 880b57cec5SDimitry Andric 890b57cec5SDimitry Andric typedef llvm::DenseMap<unsigned, unsigned> AbbrevLookup; 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric class SDiagsMerger : SerializedDiagnosticReader { 920b57cec5SDimitry Andric SDiagsWriter &Writer; 930b57cec5SDimitry Andric AbbrevLookup FileLookup; 940b57cec5SDimitry Andric AbbrevLookup CategoryLookup; 950b57cec5SDimitry Andric AbbrevLookup DiagFlagLookup; 960b57cec5SDimitry Andric 970b57cec5SDimitry Andric public: 980b57cec5SDimitry Andric SDiagsMerger(SDiagsWriter &Writer) 990b57cec5SDimitry Andric : SerializedDiagnosticReader(), Writer(Writer) {} 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric std::error_code mergeRecordsFromFile(const char *File) { 1020b57cec5SDimitry Andric return readDiagnostics(File); 1030b57cec5SDimitry Andric } 1040b57cec5SDimitry Andric 1050b57cec5SDimitry Andric protected: 1060b57cec5SDimitry Andric std::error_code visitStartOfDiagnostic() override; 1070b57cec5SDimitry Andric std::error_code visitEndOfDiagnostic() override; 1080b57cec5SDimitry Andric std::error_code visitCategoryRecord(unsigned ID, StringRef Name) override; 1090b57cec5SDimitry Andric std::error_code visitDiagFlagRecord(unsigned ID, StringRef Name) override; 1100b57cec5SDimitry Andric std::error_code visitDiagnosticRecord( 1110b57cec5SDimitry Andric unsigned Severity, const serialized_diags::Location &Location, 1120b57cec5SDimitry Andric unsigned Category, unsigned Flag, StringRef Message) override; 1130b57cec5SDimitry Andric std::error_code visitFilenameRecord(unsigned ID, unsigned Size, 1140b57cec5SDimitry Andric unsigned Timestamp, 1150b57cec5SDimitry Andric StringRef Name) override; 1160b57cec5SDimitry Andric std::error_code visitFixitRecord(const serialized_diags::Location &Start, 1170b57cec5SDimitry Andric const serialized_diags::Location &End, 1180b57cec5SDimitry Andric StringRef CodeToInsert) override; 1190b57cec5SDimitry Andric std::error_code 1200b57cec5SDimitry Andric visitSourceRangeRecord(const serialized_diags::Location &Start, 1210b57cec5SDimitry Andric const serialized_diags::Location &End) override; 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric private: 1240b57cec5SDimitry Andric std::error_code adjustSourceLocFilename(RecordData &Record, 1250b57cec5SDimitry Andric unsigned int offset); 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric void adjustAbbrevID(RecordData &Record, AbbrevLookup &Lookup, 1280b57cec5SDimitry Andric unsigned NewAbbrev); 1290b57cec5SDimitry Andric 1300b57cec5SDimitry Andric void writeRecordWithAbbrev(unsigned ID, RecordData &Record); 1310b57cec5SDimitry Andric 1320b57cec5SDimitry Andric void writeRecordWithBlob(unsigned ID, RecordData &Record, StringRef Blob); 1330b57cec5SDimitry Andric }; 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric class SDiagsWriter : public DiagnosticConsumer { 1360b57cec5SDimitry Andric friend class SDiagsRenderer; 1370b57cec5SDimitry Andric friend class SDiagsMerger; 1380b57cec5SDimitry Andric 1390b57cec5SDimitry Andric struct SharedState; 1400b57cec5SDimitry Andric 1410b57cec5SDimitry Andric explicit SDiagsWriter(std::shared_ptr<SharedState> State) 1420b57cec5SDimitry Andric : LangOpts(nullptr), OriginalInstance(false), MergeChildRecords(false), 1430b57cec5SDimitry Andric State(std::move(State)) {} 1440b57cec5SDimitry Andric 1450b57cec5SDimitry Andric public: 1460b57cec5SDimitry Andric SDiagsWriter(StringRef File, DiagnosticOptions *Diags, bool MergeChildRecords) 1470b57cec5SDimitry Andric : LangOpts(nullptr), OriginalInstance(true), 1480b57cec5SDimitry Andric MergeChildRecords(MergeChildRecords), 1490b57cec5SDimitry Andric State(std::make_shared<SharedState>(File, Diags)) { 1500b57cec5SDimitry Andric if (MergeChildRecords) 1510b57cec5SDimitry Andric RemoveOldDiagnostics(); 1520b57cec5SDimitry Andric EmitPreamble(); 1530b57cec5SDimitry Andric } 1540b57cec5SDimitry Andric 1550b57cec5SDimitry Andric ~SDiagsWriter() override {} 1560b57cec5SDimitry Andric 1570b57cec5SDimitry Andric void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, 1580b57cec5SDimitry Andric const Diagnostic &Info) override; 1590b57cec5SDimitry Andric 1600b57cec5SDimitry Andric void BeginSourceFile(const LangOptions &LO, const Preprocessor *PP) override { 1610b57cec5SDimitry Andric LangOpts = &LO; 1620b57cec5SDimitry Andric } 1630b57cec5SDimitry Andric 1640b57cec5SDimitry Andric void finish() override; 1650b57cec5SDimitry Andric 1660b57cec5SDimitry Andric private: 1670b57cec5SDimitry Andric /// Build a DiagnosticsEngine to emit diagnostics about the diagnostics 1680b57cec5SDimitry Andric DiagnosticsEngine *getMetaDiags(); 1690b57cec5SDimitry Andric 1700b57cec5SDimitry Andric /// Remove old copies of the serialized diagnostics. This is necessary 1710b57cec5SDimitry Andric /// so that we can detect when subprocesses write diagnostics that we should 1720b57cec5SDimitry Andric /// merge into our own. 1730b57cec5SDimitry Andric void RemoveOldDiagnostics(); 1740b57cec5SDimitry Andric 1750b57cec5SDimitry Andric /// Emit the preamble for the serialized diagnostics. 1760b57cec5SDimitry Andric void EmitPreamble(); 1770b57cec5SDimitry Andric 1780b57cec5SDimitry Andric /// Emit the BLOCKINFO block. 1790b57cec5SDimitry Andric void EmitBlockInfoBlock(); 1800b57cec5SDimitry Andric 1810b57cec5SDimitry Andric /// Emit the META data block. 1820b57cec5SDimitry Andric void EmitMetaBlock(); 1830b57cec5SDimitry Andric 1840b57cec5SDimitry Andric /// Start a DIAG block. 1850b57cec5SDimitry Andric void EnterDiagBlock(); 1860b57cec5SDimitry Andric 1870b57cec5SDimitry Andric /// End a DIAG block. 1880b57cec5SDimitry Andric void ExitDiagBlock(); 1890b57cec5SDimitry Andric 1900b57cec5SDimitry Andric /// Emit a DIAG record. 1910b57cec5SDimitry Andric void EmitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc, 1920b57cec5SDimitry Andric DiagnosticsEngine::Level Level, StringRef Message, 1930b57cec5SDimitry Andric DiagOrStoredDiag D); 1940b57cec5SDimitry Andric 1950b57cec5SDimitry Andric /// Emit FIXIT and SOURCE_RANGE records for a diagnostic. 1960b57cec5SDimitry Andric void EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges, 1970b57cec5SDimitry Andric ArrayRef<FixItHint> Hints, 1980b57cec5SDimitry Andric const SourceManager &SM); 1990b57cec5SDimitry Andric 2000b57cec5SDimitry Andric /// Emit a record for a CharSourceRange. 2010b57cec5SDimitry Andric void EmitCharSourceRange(CharSourceRange R, const SourceManager &SM); 2020b57cec5SDimitry Andric 2030b57cec5SDimitry Andric /// Emit the string information for the category. 2040b57cec5SDimitry Andric unsigned getEmitCategory(unsigned category = 0); 2050b57cec5SDimitry Andric 2060b57cec5SDimitry Andric /// Emit the string information for diagnostic flags. 2070b57cec5SDimitry Andric unsigned getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel, 2080b57cec5SDimitry Andric unsigned DiagID = 0); 2090b57cec5SDimitry Andric 2100b57cec5SDimitry Andric unsigned getEmitDiagnosticFlag(StringRef DiagName); 2110b57cec5SDimitry Andric 2120b57cec5SDimitry Andric /// Emit (lazily) the file string and retrieved the file identifier. 2130b57cec5SDimitry Andric unsigned getEmitFile(const char *Filename); 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric /// Add SourceLocation information the specified record. 2160b57cec5SDimitry Andric void AddLocToRecord(FullSourceLoc Loc, PresumedLoc PLoc, 2170b57cec5SDimitry Andric RecordDataImpl &Record, unsigned TokSize = 0); 2180b57cec5SDimitry Andric 2190b57cec5SDimitry Andric /// Add SourceLocation information the specified record. 2200b57cec5SDimitry Andric void AddLocToRecord(FullSourceLoc Loc, RecordDataImpl &Record, 2210b57cec5SDimitry Andric unsigned TokSize = 0) { 2220b57cec5SDimitry Andric AddLocToRecord(Loc, Loc.hasManager() ? Loc.getPresumedLoc() : PresumedLoc(), 2230b57cec5SDimitry Andric Record, TokSize); 2240b57cec5SDimitry Andric } 2250b57cec5SDimitry Andric 2260b57cec5SDimitry Andric /// Add CharSourceRange information the specified record. 2270b57cec5SDimitry Andric void AddCharSourceRangeToRecord(CharSourceRange R, RecordDataImpl &Record, 2280b57cec5SDimitry Andric const SourceManager &SM); 2290b57cec5SDimitry Andric 2300b57cec5SDimitry Andric /// Language options, which can differ from one clone of this client 2310b57cec5SDimitry Andric /// to another. 2320b57cec5SDimitry Andric const LangOptions *LangOpts; 2330b57cec5SDimitry Andric 2340b57cec5SDimitry Andric /// Whether this is the original instance (rather than one of its 2350b57cec5SDimitry Andric /// clones), responsible for writing the file at the end. 2360b57cec5SDimitry Andric bool OriginalInstance; 2370b57cec5SDimitry Andric 2380b57cec5SDimitry Andric /// Whether this instance should aggregate diagnostics that are 2390b57cec5SDimitry Andric /// generated from child processes. 2400b57cec5SDimitry Andric bool MergeChildRecords; 2410b57cec5SDimitry Andric 242*5ffd83dbSDimitry Andric /// Whether we've started finishing and tearing down this instance. 243*5ffd83dbSDimitry Andric bool IsFinishing = false; 244*5ffd83dbSDimitry Andric 2450b57cec5SDimitry Andric /// State that is shared among the various clones of this diagnostic 2460b57cec5SDimitry Andric /// consumer. 2470b57cec5SDimitry Andric struct SharedState { 2480b57cec5SDimitry Andric SharedState(StringRef File, DiagnosticOptions *Diags) 2490b57cec5SDimitry Andric : DiagOpts(Diags), Stream(Buffer), OutputFile(File.str()), 2500b57cec5SDimitry Andric EmittedAnyDiagBlocks(false) {} 2510b57cec5SDimitry Andric 2520b57cec5SDimitry Andric /// Diagnostic options. 2530b57cec5SDimitry Andric IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts; 2540b57cec5SDimitry Andric 2550b57cec5SDimitry Andric /// The byte buffer for the serialized content. 2560b57cec5SDimitry Andric SmallString<1024> Buffer; 2570b57cec5SDimitry Andric 2580b57cec5SDimitry Andric /// The BitStreamWriter for the serialized diagnostics. 2590b57cec5SDimitry Andric llvm::BitstreamWriter Stream; 2600b57cec5SDimitry Andric 2610b57cec5SDimitry Andric /// The name of the diagnostics file. 2620b57cec5SDimitry Andric std::string OutputFile; 2630b57cec5SDimitry Andric 2640b57cec5SDimitry Andric /// The set of constructed record abbreviations. 2650b57cec5SDimitry Andric AbbreviationMap Abbrevs; 2660b57cec5SDimitry Andric 2670b57cec5SDimitry Andric /// A utility buffer for constructing record content. 2680b57cec5SDimitry Andric RecordData Record; 2690b57cec5SDimitry Andric 2700b57cec5SDimitry Andric /// A text buffer for rendering diagnostic text. 2710b57cec5SDimitry Andric SmallString<256> diagBuf; 2720b57cec5SDimitry Andric 2730b57cec5SDimitry Andric /// The collection of diagnostic categories used. 2740b57cec5SDimitry Andric llvm::DenseSet<unsigned> Categories; 2750b57cec5SDimitry Andric 2760b57cec5SDimitry Andric /// The collection of files used. 2770b57cec5SDimitry Andric llvm::DenseMap<const char *, unsigned> Files; 2780b57cec5SDimitry Andric 2790b57cec5SDimitry Andric typedef llvm::DenseMap<const void *, std::pair<unsigned, StringRef> > 2800b57cec5SDimitry Andric DiagFlagsTy; 2810b57cec5SDimitry Andric 2820b57cec5SDimitry Andric /// Map for uniquing strings. 2830b57cec5SDimitry Andric DiagFlagsTy DiagFlags; 2840b57cec5SDimitry Andric 2850b57cec5SDimitry Andric /// Whether we have already started emission of any DIAG blocks. Once 2860b57cec5SDimitry Andric /// this becomes \c true, we never close a DIAG block until we know that we're 2870b57cec5SDimitry Andric /// starting another one or we're done. 2880b57cec5SDimitry Andric bool EmittedAnyDiagBlocks; 2890b57cec5SDimitry Andric 2900b57cec5SDimitry Andric /// Engine for emitting diagnostics about the diagnostics. 2910b57cec5SDimitry Andric std::unique_ptr<DiagnosticsEngine> MetaDiagnostics; 2920b57cec5SDimitry Andric }; 2930b57cec5SDimitry Andric 2940b57cec5SDimitry Andric /// State shared among the various clones of this diagnostic consumer. 2950b57cec5SDimitry Andric std::shared_ptr<SharedState> State; 2960b57cec5SDimitry Andric }; 2970b57cec5SDimitry Andric } // end anonymous namespace 2980b57cec5SDimitry Andric 2990b57cec5SDimitry Andric namespace clang { 3000b57cec5SDimitry Andric namespace serialized_diags { 3010b57cec5SDimitry Andric std::unique_ptr<DiagnosticConsumer> 3020b57cec5SDimitry Andric create(StringRef OutputFile, DiagnosticOptions *Diags, bool MergeChildRecords) { 303a7dea167SDimitry Andric return std::make_unique<SDiagsWriter>(OutputFile, Diags, MergeChildRecords); 3040b57cec5SDimitry Andric } 3050b57cec5SDimitry Andric 3060b57cec5SDimitry Andric } // end namespace serialized_diags 3070b57cec5SDimitry Andric } // end namespace clang 3080b57cec5SDimitry Andric 3090b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 3100b57cec5SDimitry Andric // Serialization methods. 3110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 3120b57cec5SDimitry Andric 3130b57cec5SDimitry Andric /// Emits a block ID in the BLOCKINFO block. 3140b57cec5SDimitry Andric static void EmitBlockID(unsigned ID, const char *Name, 3150b57cec5SDimitry Andric llvm::BitstreamWriter &Stream, 3160b57cec5SDimitry Andric RecordDataImpl &Record) { 3170b57cec5SDimitry Andric Record.clear(); 3180b57cec5SDimitry Andric Record.push_back(ID); 3190b57cec5SDimitry Andric Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record); 3200b57cec5SDimitry Andric 3210b57cec5SDimitry Andric // Emit the block name if present. 3220b57cec5SDimitry Andric if (!Name || Name[0] == 0) 3230b57cec5SDimitry Andric return; 3240b57cec5SDimitry Andric 3250b57cec5SDimitry Andric Record.clear(); 3260b57cec5SDimitry Andric 3270b57cec5SDimitry Andric while (*Name) 3280b57cec5SDimitry Andric Record.push_back(*Name++); 3290b57cec5SDimitry Andric 3300b57cec5SDimitry Andric Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record); 3310b57cec5SDimitry Andric } 3320b57cec5SDimitry Andric 3330b57cec5SDimitry Andric /// Emits a record ID in the BLOCKINFO block. 3340b57cec5SDimitry Andric static void EmitRecordID(unsigned ID, const char *Name, 3350b57cec5SDimitry Andric llvm::BitstreamWriter &Stream, 3360b57cec5SDimitry Andric RecordDataImpl &Record){ 3370b57cec5SDimitry Andric Record.clear(); 3380b57cec5SDimitry Andric Record.push_back(ID); 3390b57cec5SDimitry Andric 3400b57cec5SDimitry Andric while (*Name) 3410b57cec5SDimitry Andric Record.push_back(*Name++); 3420b57cec5SDimitry Andric 3430b57cec5SDimitry Andric Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record); 3440b57cec5SDimitry Andric } 3450b57cec5SDimitry Andric 3460b57cec5SDimitry Andric void SDiagsWriter::AddLocToRecord(FullSourceLoc Loc, PresumedLoc PLoc, 3470b57cec5SDimitry Andric RecordDataImpl &Record, unsigned TokSize) { 3480b57cec5SDimitry Andric if (PLoc.isInvalid()) { 3490b57cec5SDimitry Andric // Emit a "sentinel" location. 3500b57cec5SDimitry Andric Record.push_back((unsigned)0); // File. 3510b57cec5SDimitry Andric Record.push_back((unsigned)0); // Line. 3520b57cec5SDimitry Andric Record.push_back((unsigned)0); // Column. 3530b57cec5SDimitry Andric Record.push_back((unsigned)0); // Offset. 3540b57cec5SDimitry Andric return; 3550b57cec5SDimitry Andric } 3560b57cec5SDimitry Andric 3570b57cec5SDimitry Andric Record.push_back(getEmitFile(PLoc.getFilename())); 3580b57cec5SDimitry Andric Record.push_back(PLoc.getLine()); 3590b57cec5SDimitry Andric Record.push_back(PLoc.getColumn()+TokSize); 3600b57cec5SDimitry Andric Record.push_back(Loc.getFileOffset()); 3610b57cec5SDimitry Andric } 3620b57cec5SDimitry Andric 3630b57cec5SDimitry Andric void SDiagsWriter::AddCharSourceRangeToRecord(CharSourceRange Range, 3640b57cec5SDimitry Andric RecordDataImpl &Record, 3650b57cec5SDimitry Andric const SourceManager &SM) { 3660b57cec5SDimitry Andric AddLocToRecord(FullSourceLoc(Range.getBegin(), SM), Record); 3670b57cec5SDimitry Andric unsigned TokSize = 0; 3680b57cec5SDimitry Andric if (Range.isTokenRange()) 3690b57cec5SDimitry Andric TokSize = Lexer::MeasureTokenLength(Range.getEnd(), 3700b57cec5SDimitry Andric SM, *LangOpts); 3710b57cec5SDimitry Andric 3720b57cec5SDimitry Andric AddLocToRecord(FullSourceLoc(Range.getEnd(), SM), Record, TokSize); 3730b57cec5SDimitry Andric } 3740b57cec5SDimitry Andric 3750b57cec5SDimitry Andric unsigned SDiagsWriter::getEmitFile(const char *FileName){ 3760b57cec5SDimitry Andric if (!FileName) 3770b57cec5SDimitry Andric return 0; 3780b57cec5SDimitry Andric 3790b57cec5SDimitry Andric unsigned &entry = State->Files[FileName]; 3800b57cec5SDimitry Andric if (entry) 3810b57cec5SDimitry Andric return entry; 3820b57cec5SDimitry Andric 3830b57cec5SDimitry Andric // Lazily generate the record for the file. 3840b57cec5SDimitry Andric entry = State->Files.size(); 3850b57cec5SDimitry Andric StringRef Name(FileName); 3860b57cec5SDimitry Andric RecordData::value_type Record[] = {RECORD_FILENAME, entry, 0 /* For legacy */, 3870b57cec5SDimitry Andric 0 /* For legacy */, Name.size()}; 3880b57cec5SDimitry Andric State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_FILENAME), Record, 3890b57cec5SDimitry Andric Name); 3900b57cec5SDimitry Andric 3910b57cec5SDimitry Andric return entry; 3920b57cec5SDimitry Andric } 3930b57cec5SDimitry Andric 3940b57cec5SDimitry Andric void SDiagsWriter::EmitCharSourceRange(CharSourceRange R, 3950b57cec5SDimitry Andric const SourceManager &SM) { 3960b57cec5SDimitry Andric State->Record.clear(); 3970b57cec5SDimitry Andric State->Record.push_back(RECORD_SOURCE_RANGE); 3980b57cec5SDimitry Andric AddCharSourceRangeToRecord(R, State->Record, SM); 3990b57cec5SDimitry Andric State->Stream.EmitRecordWithAbbrev(State->Abbrevs.get(RECORD_SOURCE_RANGE), 4000b57cec5SDimitry Andric State->Record); 4010b57cec5SDimitry Andric } 4020b57cec5SDimitry Andric 4030b57cec5SDimitry Andric /// Emits the preamble of the diagnostics file. 4040b57cec5SDimitry Andric void SDiagsWriter::EmitPreamble() { 4050b57cec5SDimitry Andric // Emit the file header. 4060b57cec5SDimitry Andric State->Stream.Emit((unsigned)'D', 8); 4070b57cec5SDimitry Andric State->Stream.Emit((unsigned)'I', 8); 4080b57cec5SDimitry Andric State->Stream.Emit((unsigned)'A', 8); 4090b57cec5SDimitry Andric State->Stream.Emit((unsigned)'G', 8); 4100b57cec5SDimitry Andric 4110b57cec5SDimitry Andric EmitBlockInfoBlock(); 4120b57cec5SDimitry Andric EmitMetaBlock(); 4130b57cec5SDimitry Andric } 4140b57cec5SDimitry Andric 4150b57cec5SDimitry Andric static void AddSourceLocationAbbrev(llvm::BitCodeAbbrev &Abbrev) { 4160b57cec5SDimitry Andric using namespace llvm; 4170b57cec5SDimitry Andric Abbrev.Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // File ID. 4180b57cec5SDimitry Andric Abbrev.Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Line. 4190b57cec5SDimitry Andric Abbrev.Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Column. 4200b57cec5SDimitry Andric Abbrev.Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Offset; 4210b57cec5SDimitry Andric } 4220b57cec5SDimitry Andric 4230b57cec5SDimitry Andric static void AddRangeLocationAbbrev(llvm::BitCodeAbbrev &Abbrev) { 4240b57cec5SDimitry Andric AddSourceLocationAbbrev(Abbrev); 4250b57cec5SDimitry Andric AddSourceLocationAbbrev(Abbrev); 4260b57cec5SDimitry Andric } 4270b57cec5SDimitry Andric 4280b57cec5SDimitry Andric void SDiagsWriter::EmitBlockInfoBlock() { 4290b57cec5SDimitry Andric State->Stream.EnterBlockInfoBlock(); 4300b57cec5SDimitry Andric 4310b57cec5SDimitry Andric using namespace llvm; 4320b57cec5SDimitry Andric llvm::BitstreamWriter &Stream = State->Stream; 4330b57cec5SDimitry Andric RecordData &Record = State->Record; 4340b57cec5SDimitry Andric AbbreviationMap &Abbrevs = State->Abbrevs; 4350b57cec5SDimitry Andric 4360b57cec5SDimitry Andric // ==---------------------------------------------------------------------==// 4370b57cec5SDimitry Andric // The subsequent records and Abbrevs are for the "Meta" block. 4380b57cec5SDimitry Andric // ==---------------------------------------------------------------------==// 4390b57cec5SDimitry Andric 4400b57cec5SDimitry Andric EmitBlockID(BLOCK_META, "Meta", Stream, Record); 4410b57cec5SDimitry Andric EmitRecordID(RECORD_VERSION, "Version", Stream, Record); 4420b57cec5SDimitry Andric auto Abbrev = std::make_shared<BitCodeAbbrev>(); 4430b57cec5SDimitry Andric Abbrev->Add(BitCodeAbbrevOp(RECORD_VERSION)); 4440b57cec5SDimitry Andric Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); 4450b57cec5SDimitry Andric Abbrevs.set(RECORD_VERSION, Stream.EmitBlockInfoAbbrev(BLOCK_META, Abbrev)); 4460b57cec5SDimitry Andric 4470b57cec5SDimitry Andric // ==---------------------------------------------------------------------==// 4480b57cec5SDimitry Andric // The subsequent records and Abbrevs are for the "Diagnostic" block. 4490b57cec5SDimitry Andric // ==---------------------------------------------------------------------==// 4500b57cec5SDimitry Andric 4510b57cec5SDimitry Andric EmitBlockID(BLOCK_DIAG, "Diag", Stream, Record); 4520b57cec5SDimitry Andric EmitRecordID(RECORD_DIAG, "DiagInfo", Stream, Record); 4530b57cec5SDimitry Andric EmitRecordID(RECORD_SOURCE_RANGE, "SrcRange", Stream, Record); 4540b57cec5SDimitry Andric EmitRecordID(RECORD_CATEGORY, "CatName", Stream, Record); 4550b57cec5SDimitry Andric EmitRecordID(RECORD_DIAG_FLAG, "DiagFlag", Stream, Record); 4560b57cec5SDimitry Andric EmitRecordID(RECORD_FILENAME, "FileName", Stream, Record); 4570b57cec5SDimitry Andric EmitRecordID(RECORD_FIXIT, "FixIt", Stream, Record); 4580b57cec5SDimitry Andric 4590b57cec5SDimitry Andric // Emit abbreviation for RECORD_DIAG. 4600b57cec5SDimitry Andric Abbrev = std::make_shared<BitCodeAbbrev>(); 4610b57cec5SDimitry Andric Abbrev->Add(BitCodeAbbrevOp(RECORD_DIAG)); 4620b57cec5SDimitry Andric Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Diag level. 4630b57cec5SDimitry Andric AddSourceLocationAbbrev(*Abbrev); 4640b57cec5SDimitry Andric Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Category. 4650b57cec5SDimitry Andric Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped Diag ID. 4660b57cec5SDimitry Andric Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // Text size. 4670b57cec5SDimitry Andric Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Diagnostc text. 4680b57cec5SDimitry Andric Abbrevs.set(RECORD_DIAG, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev)); 4690b57cec5SDimitry Andric 4700b57cec5SDimitry Andric // Emit abbreviation for RECORD_CATEGORY. 4710b57cec5SDimitry Andric Abbrev = std::make_shared<BitCodeAbbrev>(); 4720b57cec5SDimitry Andric Abbrev->Add(BitCodeAbbrevOp(RECORD_CATEGORY)); 4730b57cec5SDimitry Andric Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Category ID. 4740b57cec5SDimitry Andric Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8)); // Text size. 4750b57cec5SDimitry Andric Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Category text. 4760b57cec5SDimitry Andric Abbrevs.set(RECORD_CATEGORY, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev)); 4770b57cec5SDimitry Andric 4780b57cec5SDimitry Andric // Emit abbreviation for RECORD_SOURCE_RANGE. 4790b57cec5SDimitry Andric Abbrev = std::make_shared<BitCodeAbbrev>(); 4800b57cec5SDimitry Andric Abbrev->Add(BitCodeAbbrevOp(RECORD_SOURCE_RANGE)); 4810b57cec5SDimitry Andric AddRangeLocationAbbrev(*Abbrev); 4820b57cec5SDimitry Andric Abbrevs.set(RECORD_SOURCE_RANGE, 4830b57cec5SDimitry Andric Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev)); 4840b57cec5SDimitry Andric 4850b57cec5SDimitry Andric // Emit the abbreviation for RECORD_DIAG_FLAG. 4860b57cec5SDimitry Andric Abbrev = std::make_shared<BitCodeAbbrev>(); 4870b57cec5SDimitry Andric Abbrev->Add(BitCodeAbbrevOp(RECORD_DIAG_FLAG)); 4880b57cec5SDimitry Andric Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped Diag ID. 4890b57cec5SDimitry Andric Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size. 4900b57cec5SDimitry Andric Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Flag name text. 4910b57cec5SDimitry Andric Abbrevs.set(RECORD_DIAG_FLAG, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, 4920b57cec5SDimitry Andric Abbrev)); 4930b57cec5SDimitry Andric 4940b57cec5SDimitry Andric // Emit the abbreviation for RECORD_FILENAME. 4950b57cec5SDimitry Andric Abbrev = std::make_shared<BitCodeAbbrev>(); 4960b57cec5SDimitry Andric Abbrev->Add(BitCodeAbbrevOp(RECORD_FILENAME)); 4970b57cec5SDimitry Andric Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped file ID. 4980b57cec5SDimitry Andric Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Size. 4990b57cec5SDimitry Andric Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Modification time. 5000b57cec5SDimitry Andric Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size. 5010b57cec5SDimitry Andric Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name text. 5020b57cec5SDimitry Andric Abbrevs.set(RECORD_FILENAME, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, 5030b57cec5SDimitry Andric Abbrev)); 5040b57cec5SDimitry Andric 5050b57cec5SDimitry Andric // Emit the abbreviation for RECORD_FIXIT. 5060b57cec5SDimitry Andric Abbrev = std::make_shared<BitCodeAbbrev>(); 5070b57cec5SDimitry Andric Abbrev->Add(BitCodeAbbrevOp(RECORD_FIXIT)); 5080b57cec5SDimitry Andric AddRangeLocationAbbrev(*Abbrev); 5090b57cec5SDimitry Andric Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size. 5100b57cec5SDimitry Andric Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // FixIt text. 5110b57cec5SDimitry Andric Abbrevs.set(RECORD_FIXIT, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, 5120b57cec5SDimitry Andric Abbrev)); 5130b57cec5SDimitry Andric 5140b57cec5SDimitry Andric Stream.ExitBlock(); 5150b57cec5SDimitry Andric } 5160b57cec5SDimitry Andric 5170b57cec5SDimitry Andric void SDiagsWriter::EmitMetaBlock() { 5180b57cec5SDimitry Andric llvm::BitstreamWriter &Stream = State->Stream; 5190b57cec5SDimitry Andric AbbreviationMap &Abbrevs = State->Abbrevs; 5200b57cec5SDimitry Andric 5210b57cec5SDimitry Andric Stream.EnterSubblock(BLOCK_META, 3); 5220b57cec5SDimitry Andric RecordData::value_type Record[] = {RECORD_VERSION, VersionNumber}; 5230b57cec5SDimitry Andric Stream.EmitRecordWithAbbrev(Abbrevs.get(RECORD_VERSION), Record); 5240b57cec5SDimitry Andric Stream.ExitBlock(); 5250b57cec5SDimitry Andric } 5260b57cec5SDimitry Andric 5270b57cec5SDimitry Andric unsigned SDiagsWriter::getEmitCategory(unsigned int category) { 5280b57cec5SDimitry Andric if (!State->Categories.insert(category).second) 5290b57cec5SDimitry Andric return category; 5300b57cec5SDimitry Andric 5310b57cec5SDimitry Andric // We use a local version of 'Record' so that we can be generating 5320b57cec5SDimitry Andric // another record when we lazily generate one for the category entry. 5330b57cec5SDimitry Andric StringRef catName = DiagnosticIDs::getCategoryNameFromID(category); 5340b57cec5SDimitry Andric RecordData::value_type Record[] = {RECORD_CATEGORY, category, catName.size()}; 5350b57cec5SDimitry Andric State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_CATEGORY), Record, 5360b57cec5SDimitry Andric catName); 5370b57cec5SDimitry Andric 5380b57cec5SDimitry Andric return category; 5390b57cec5SDimitry Andric } 5400b57cec5SDimitry Andric 5410b57cec5SDimitry Andric unsigned SDiagsWriter::getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel, 5420b57cec5SDimitry Andric unsigned DiagID) { 5430b57cec5SDimitry Andric if (DiagLevel == DiagnosticsEngine::Note) 5440b57cec5SDimitry Andric return 0; // No flag for notes. 5450b57cec5SDimitry Andric 5460b57cec5SDimitry Andric StringRef FlagName = DiagnosticIDs::getWarningOptionForDiag(DiagID); 5470b57cec5SDimitry Andric return getEmitDiagnosticFlag(FlagName); 5480b57cec5SDimitry Andric } 5490b57cec5SDimitry Andric 5500b57cec5SDimitry Andric unsigned SDiagsWriter::getEmitDiagnosticFlag(StringRef FlagName) { 5510b57cec5SDimitry Andric if (FlagName.empty()) 5520b57cec5SDimitry Andric return 0; 5530b57cec5SDimitry Andric 5540b57cec5SDimitry Andric // Here we assume that FlagName points to static data whose pointer 5550b57cec5SDimitry Andric // value is fixed. This allows us to unique by diagnostic groups. 5560b57cec5SDimitry Andric const void *data = FlagName.data(); 5570b57cec5SDimitry Andric std::pair<unsigned, StringRef> &entry = State->DiagFlags[data]; 5580b57cec5SDimitry Andric if (entry.first == 0) { 5590b57cec5SDimitry Andric entry.first = State->DiagFlags.size(); 5600b57cec5SDimitry Andric entry.second = FlagName; 5610b57cec5SDimitry Andric 5620b57cec5SDimitry Andric // Lazily emit the string in a separate record. 5630b57cec5SDimitry Andric RecordData::value_type Record[] = {RECORD_DIAG_FLAG, entry.first, 5640b57cec5SDimitry Andric FlagName.size()}; 5650b57cec5SDimitry Andric State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_DIAG_FLAG), 5660b57cec5SDimitry Andric Record, FlagName); 5670b57cec5SDimitry Andric } 5680b57cec5SDimitry Andric 5690b57cec5SDimitry Andric return entry.first; 5700b57cec5SDimitry Andric } 5710b57cec5SDimitry Andric 5720b57cec5SDimitry Andric void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, 5730b57cec5SDimitry Andric const Diagnostic &Info) { 574*5ffd83dbSDimitry Andric assert(!IsFinishing && 575*5ffd83dbSDimitry Andric "Received a diagnostic after we've already started teardown."); 576*5ffd83dbSDimitry Andric if (IsFinishing) { 577*5ffd83dbSDimitry Andric SmallString<256> diagnostic; 578*5ffd83dbSDimitry Andric Info.FormatDiagnostic(diagnostic); 579*5ffd83dbSDimitry Andric getMetaDiags()->Report( 580*5ffd83dbSDimitry Andric diag::warn_fe_serialized_diag_failure_during_finalisation) 581*5ffd83dbSDimitry Andric << diagnostic; 582*5ffd83dbSDimitry Andric return; 583*5ffd83dbSDimitry Andric } 584*5ffd83dbSDimitry Andric 5850b57cec5SDimitry Andric // Enter the block for a non-note diagnostic immediately, rather than waiting 5860b57cec5SDimitry Andric // for beginDiagnostic, in case associated notes are emitted before we get 5870b57cec5SDimitry Andric // there. 5880b57cec5SDimitry Andric if (DiagLevel != DiagnosticsEngine::Note) { 5890b57cec5SDimitry Andric if (State->EmittedAnyDiagBlocks) 5900b57cec5SDimitry Andric ExitDiagBlock(); 5910b57cec5SDimitry Andric 5920b57cec5SDimitry Andric EnterDiagBlock(); 5930b57cec5SDimitry Andric State->EmittedAnyDiagBlocks = true; 5940b57cec5SDimitry Andric } 5950b57cec5SDimitry Andric 5960b57cec5SDimitry Andric // Compute the diagnostic text. 5970b57cec5SDimitry Andric State->diagBuf.clear(); 5980b57cec5SDimitry Andric Info.FormatDiagnostic(State->diagBuf); 5990b57cec5SDimitry Andric 6000b57cec5SDimitry Andric if (Info.getLocation().isInvalid()) { 6010b57cec5SDimitry Andric // Special-case diagnostics with no location. We may not have entered a 6020b57cec5SDimitry Andric // source file in this case, so we can't use the normal DiagnosticsRenderer 6030b57cec5SDimitry Andric // machinery. 6040b57cec5SDimitry Andric 6050b57cec5SDimitry Andric // Make sure we bracket all notes as "sub-diagnostics". This matches 6060b57cec5SDimitry Andric // the behavior in SDiagsRenderer::emitDiagnostic(). 6070b57cec5SDimitry Andric if (DiagLevel == DiagnosticsEngine::Note) 6080b57cec5SDimitry Andric EnterDiagBlock(); 6090b57cec5SDimitry Andric 6100b57cec5SDimitry Andric EmitDiagnosticMessage(FullSourceLoc(), PresumedLoc(), DiagLevel, 6110b57cec5SDimitry Andric State->diagBuf, &Info); 6120b57cec5SDimitry Andric 6130b57cec5SDimitry Andric if (DiagLevel == DiagnosticsEngine::Note) 6140b57cec5SDimitry Andric ExitDiagBlock(); 6150b57cec5SDimitry Andric 6160b57cec5SDimitry Andric return; 6170b57cec5SDimitry Andric } 6180b57cec5SDimitry Andric 6190b57cec5SDimitry Andric assert(Info.hasSourceManager() && LangOpts && 6200b57cec5SDimitry Andric "Unexpected diagnostic with valid location outside of a source file"); 6210b57cec5SDimitry Andric SDiagsRenderer Renderer(*this, *LangOpts, &*State->DiagOpts); 6220b57cec5SDimitry Andric Renderer.emitDiagnostic( 6230b57cec5SDimitry Andric FullSourceLoc(Info.getLocation(), Info.getSourceManager()), DiagLevel, 6240b57cec5SDimitry Andric State->diagBuf, Info.getRanges(), Info.getFixItHints(), &Info); 6250b57cec5SDimitry Andric } 6260b57cec5SDimitry Andric 6270b57cec5SDimitry Andric static serialized_diags::Level getStableLevel(DiagnosticsEngine::Level Level) { 6280b57cec5SDimitry Andric switch (Level) { 6290b57cec5SDimitry Andric #define CASE(X) case DiagnosticsEngine::X: return serialized_diags::X; 6300b57cec5SDimitry Andric CASE(Ignored) 6310b57cec5SDimitry Andric CASE(Note) 6320b57cec5SDimitry Andric CASE(Remark) 6330b57cec5SDimitry Andric CASE(Warning) 6340b57cec5SDimitry Andric CASE(Error) 6350b57cec5SDimitry Andric CASE(Fatal) 6360b57cec5SDimitry Andric #undef CASE 6370b57cec5SDimitry Andric } 6380b57cec5SDimitry Andric 6390b57cec5SDimitry Andric llvm_unreachable("invalid diagnostic level"); 6400b57cec5SDimitry Andric } 6410b57cec5SDimitry Andric 6420b57cec5SDimitry Andric void SDiagsWriter::EmitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc, 6430b57cec5SDimitry Andric DiagnosticsEngine::Level Level, 6440b57cec5SDimitry Andric StringRef Message, 6450b57cec5SDimitry Andric DiagOrStoredDiag D) { 6460b57cec5SDimitry Andric llvm::BitstreamWriter &Stream = State->Stream; 6470b57cec5SDimitry Andric RecordData &Record = State->Record; 6480b57cec5SDimitry Andric AbbreviationMap &Abbrevs = State->Abbrevs; 6490b57cec5SDimitry Andric 6500b57cec5SDimitry Andric // Emit the RECORD_DIAG record. 6510b57cec5SDimitry Andric Record.clear(); 6520b57cec5SDimitry Andric Record.push_back(RECORD_DIAG); 6530b57cec5SDimitry Andric Record.push_back(getStableLevel(Level)); 6540b57cec5SDimitry Andric AddLocToRecord(Loc, PLoc, Record); 6550b57cec5SDimitry Andric 6560b57cec5SDimitry Andric if (const Diagnostic *Info = D.dyn_cast<const Diagnostic*>()) { 6570b57cec5SDimitry Andric // Emit the category string lazily and get the category ID. 6580b57cec5SDimitry Andric unsigned DiagID = DiagnosticIDs::getCategoryNumberForDiag(Info->getID()); 6590b57cec5SDimitry Andric Record.push_back(getEmitCategory(DiagID)); 6600b57cec5SDimitry Andric // Emit the diagnostic flag string lazily and get the mapped ID. 6610b57cec5SDimitry Andric Record.push_back(getEmitDiagnosticFlag(Level, Info->getID())); 6620b57cec5SDimitry Andric } else { 6630b57cec5SDimitry Andric Record.push_back(getEmitCategory()); 6640b57cec5SDimitry Andric Record.push_back(getEmitDiagnosticFlag(Level)); 6650b57cec5SDimitry Andric } 6660b57cec5SDimitry Andric 6670b57cec5SDimitry Andric Record.push_back(Message.size()); 6680b57cec5SDimitry Andric Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG), Record, Message); 6690b57cec5SDimitry Andric } 6700b57cec5SDimitry Andric 6710b57cec5SDimitry Andric void SDiagsRenderer::emitDiagnosticMessage( 6720b57cec5SDimitry Andric FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, 6730b57cec5SDimitry Andric StringRef Message, ArrayRef<clang::CharSourceRange> Ranges, 6740b57cec5SDimitry Andric DiagOrStoredDiag D) { 6750b57cec5SDimitry Andric Writer.EmitDiagnosticMessage(Loc, PLoc, Level, Message, D); 6760b57cec5SDimitry Andric } 6770b57cec5SDimitry Andric 6780b57cec5SDimitry Andric void SDiagsWriter::EnterDiagBlock() { 6790b57cec5SDimitry Andric State->Stream.EnterSubblock(BLOCK_DIAG, 4); 6800b57cec5SDimitry Andric } 6810b57cec5SDimitry Andric 6820b57cec5SDimitry Andric void SDiagsWriter::ExitDiagBlock() { 6830b57cec5SDimitry Andric State->Stream.ExitBlock(); 6840b57cec5SDimitry Andric } 6850b57cec5SDimitry Andric 6860b57cec5SDimitry Andric void SDiagsRenderer::beginDiagnostic(DiagOrStoredDiag D, 6870b57cec5SDimitry Andric DiagnosticsEngine::Level Level) { 6880b57cec5SDimitry Andric if (Level == DiagnosticsEngine::Note) 6890b57cec5SDimitry Andric Writer.EnterDiagBlock(); 6900b57cec5SDimitry Andric } 6910b57cec5SDimitry Andric 6920b57cec5SDimitry Andric void SDiagsRenderer::endDiagnostic(DiagOrStoredDiag D, 6930b57cec5SDimitry Andric DiagnosticsEngine::Level Level) { 6940b57cec5SDimitry Andric // Only end note diagnostics here, because we can't be sure when we've seen 6950b57cec5SDimitry Andric // the last note associated with a non-note diagnostic. 6960b57cec5SDimitry Andric if (Level == DiagnosticsEngine::Note) 6970b57cec5SDimitry Andric Writer.ExitDiagBlock(); 6980b57cec5SDimitry Andric } 6990b57cec5SDimitry Andric 7000b57cec5SDimitry Andric void SDiagsWriter::EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges, 7010b57cec5SDimitry Andric ArrayRef<FixItHint> Hints, 7020b57cec5SDimitry Andric const SourceManager &SM) { 7030b57cec5SDimitry Andric llvm::BitstreamWriter &Stream = State->Stream; 7040b57cec5SDimitry Andric RecordData &Record = State->Record; 7050b57cec5SDimitry Andric AbbreviationMap &Abbrevs = State->Abbrevs; 7060b57cec5SDimitry Andric 7070b57cec5SDimitry Andric // Emit Source Ranges. 7080b57cec5SDimitry Andric for (ArrayRef<CharSourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); 7090b57cec5SDimitry Andric I != E; ++I) 7100b57cec5SDimitry Andric if (I->isValid()) 7110b57cec5SDimitry Andric EmitCharSourceRange(*I, SM); 7120b57cec5SDimitry Andric 7130b57cec5SDimitry Andric // Emit FixIts. 7140b57cec5SDimitry Andric for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end(); 7150b57cec5SDimitry Andric I != E; ++I) { 7160b57cec5SDimitry Andric const FixItHint &Fix = *I; 7170b57cec5SDimitry Andric if (Fix.isNull()) 7180b57cec5SDimitry Andric continue; 7190b57cec5SDimitry Andric Record.clear(); 7200b57cec5SDimitry Andric Record.push_back(RECORD_FIXIT); 7210b57cec5SDimitry Andric AddCharSourceRangeToRecord(Fix.RemoveRange, Record, SM); 7220b57cec5SDimitry Andric Record.push_back(Fix.CodeToInsert.size()); 7230b57cec5SDimitry Andric Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_FIXIT), Record, 7240b57cec5SDimitry Andric Fix.CodeToInsert); 7250b57cec5SDimitry Andric } 7260b57cec5SDimitry Andric } 7270b57cec5SDimitry Andric 7280b57cec5SDimitry Andric void SDiagsRenderer::emitCodeContext(FullSourceLoc Loc, 7290b57cec5SDimitry Andric DiagnosticsEngine::Level Level, 7300b57cec5SDimitry Andric SmallVectorImpl<CharSourceRange> &Ranges, 7310b57cec5SDimitry Andric ArrayRef<FixItHint> Hints) { 7320b57cec5SDimitry Andric Writer.EmitCodeContext(Ranges, Hints, Loc.getManager()); 7330b57cec5SDimitry Andric } 7340b57cec5SDimitry Andric 7350b57cec5SDimitry Andric void SDiagsRenderer::emitNote(FullSourceLoc Loc, StringRef Message) { 7360b57cec5SDimitry Andric Writer.EnterDiagBlock(); 7370b57cec5SDimitry Andric PresumedLoc PLoc = Loc.hasManager() ? Loc.getPresumedLoc() : PresumedLoc(); 7380b57cec5SDimitry Andric Writer.EmitDiagnosticMessage(Loc, PLoc, DiagnosticsEngine::Note, Message, 7390b57cec5SDimitry Andric DiagOrStoredDiag()); 7400b57cec5SDimitry Andric Writer.ExitDiagBlock(); 7410b57cec5SDimitry Andric } 7420b57cec5SDimitry Andric 7430b57cec5SDimitry Andric DiagnosticsEngine *SDiagsWriter::getMetaDiags() { 7440b57cec5SDimitry Andric // FIXME: It's slightly absurd to create a new diagnostics engine here, but 7450b57cec5SDimitry Andric // the other options that are available today are worse: 7460b57cec5SDimitry Andric // 7470b57cec5SDimitry Andric // 1. Teach DiagnosticsConsumers to emit diagnostics to the engine they are a 7480b57cec5SDimitry Andric // part of. The DiagnosticsEngine would need to know not to send 7490b57cec5SDimitry Andric // diagnostics back to the consumer that failed. This would require us to 7500b57cec5SDimitry Andric // rework ChainedDiagnosticsConsumer and teach the engine about multiple 7510b57cec5SDimitry Andric // consumers, which is difficult today because most APIs interface with 7520b57cec5SDimitry Andric // consumers rather than the engine itself. 7530b57cec5SDimitry Andric // 7540b57cec5SDimitry Andric // 2. Pass a DiagnosticsEngine to SDiagsWriter on creation - this would need 7550b57cec5SDimitry Andric // to be distinct from the engine the writer was being added to and would 7560b57cec5SDimitry Andric // normally not be used. 7570b57cec5SDimitry Andric if (!State->MetaDiagnostics) { 7580b57cec5SDimitry Andric IntrusiveRefCntPtr<DiagnosticIDs> IDs(new DiagnosticIDs()); 7590b57cec5SDimitry Andric auto Client = 7600b57cec5SDimitry Andric new TextDiagnosticPrinter(llvm::errs(), State->DiagOpts.get()); 761a7dea167SDimitry Andric State->MetaDiagnostics = std::make_unique<DiagnosticsEngine>( 7620b57cec5SDimitry Andric IDs, State->DiagOpts.get(), Client); 7630b57cec5SDimitry Andric } 7640b57cec5SDimitry Andric return State->MetaDiagnostics.get(); 7650b57cec5SDimitry Andric } 7660b57cec5SDimitry Andric 7670b57cec5SDimitry Andric void SDiagsWriter::RemoveOldDiagnostics() { 7680b57cec5SDimitry Andric if (!llvm::sys::fs::remove(State->OutputFile)) 7690b57cec5SDimitry Andric return; 7700b57cec5SDimitry Andric 7710b57cec5SDimitry Andric getMetaDiags()->Report(diag::warn_fe_serialized_diag_merge_failure); 7720b57cec5SDimitry Andric // Disable merging child records, as whatever is in this file may be 7730b57cec5SDimitry Andric // misleading. 7740b57cec5SDimitry Andric MergeChildRecords = false; 7750b57cec5SDimitry Andric } 7760b57cec5SDimitry Andric 7770b57cec5SDimitry Andric void SDiagsWriter::finish() { 778*5ffd83dbSDimitry Andric assert(!IsFinishing); 779*5ffd83dbSDimitry Andric IsFinishing = true; 780*5ffd83dbSDimitry Andric 7810b57cec5SDimitry Andric // The original instance is responsible for writing the file. 7820b57cec5SDimitry Andric if (!OriginalInstance) 7830b57cec5SDimitry Andric return; 7840b57cec5SDimitry Andric 7850b57cec5SDimitry Andric // Finish off any diagnostic we were in the process of emitting. 7860b57cec5SDimitry Andric if (State->EmittedAnyDiagBlocks) 7870b57cec5SDimitry Andric ExitDiagBlock(); 7880b57cec5SDimitry Andric 7890b57cec5SDimitry Andric if (MergeChildRecords) { 7900b57cec5SDimitry Andric if (!State->EmittedAnyDiagBlocks) 7910b57cec5SDimitry Andric // We have no diagnostics of our own, so we can just leave the child 7920b57cec5SDimitry Andric // process' output alone 7930b57cec5SDimitry Andric return; 7940b57cec5SDimitry Andric 7950b57cec5SDimitry Andric if (llvm::sys::fs::exists(State->OutputFile)) 7960b57cec5SDimitry Andric if (SDiagsMerger(*this).mergeRecordsFromFile(State->OutputFile.c_str())) 7970b57cec5SDimitry Andric getMetaDiags()->Report(diag::warn_fe_serialized_diag_merge_failure); 7980b57cec5SDimitry Andric } 7990b57cec5SDimitry Andric 8000b57cec5SDimitry Andric std::error_code EC; 801a7dea167SDimitry Andric auto OS = std::make_unique<llvm::raw_fd_ostream>(State->OutputFile.c_str(), 802a7dea167SDimitry Andric EC, llvm::sys::fs::OF_None); 8030b57cec5SDimitry Andric if (EC) { 8040b57cec5SDimitry Andric getMetaDiags()->Report(diag::warn_fe_serialized_diag_failure) 8050b57cec5SDimitry Andric << State->OutputFile << EC.message(); 806*5ffd83dbSDimitry Andric OS->clear_error(); 8070b57cec5SDimitry Andric return; 8080b57cec5SDimitry Andric } 8090b57cec5SDimitry Andric 8100b57cec5SDimitry Andric // Write the generated bitstream to "Out". 8110b57cec5SDimitry Andric OS->write((char *)&State->Buffer.front(), State->Buffer.size()); 8120b57cec5SDimitry Andric OS->flush(); 813*5ffd83dbSDimitry Andric 814*5ffd83dbSDimitry Andric assert(!OS->has_error()); 815*5ffd83dbSDimitry Andric if (OS->has_error()) { 816*5ffd83dbSDimitry Andric getMetaDiags()->Report(diag::warn_fe_serialized_diag_failure) 817*5ffd83dbSDimitry Andric << State->OutputFile << OS->error().message(); 818*5ffd83dbSDimitry Andric OS->clear_error(); 819*5ffd83dbSDimitry Andric } 8200b57cec5SDimitry Andric } 8210b57cec5SDimitry Andric 8220b57cec5SDimitry Andric std::error_code SDiagsMerger::visitStartOfDiagnostic() { 8230b57cec5SDimitry Andric Writer.EnterDiagBlock(); 8240b57cec5SDimitry Andric return std::error_code(); 8250b57cec5SDimitry Andric } 8260b57cec5SDimitry Andric 8270b57cec5SDimitry Andric std::error_code SDiagsMerger::visitEndOfDiagnostic() { 8280b57cec5SDimitry Andric Writer.ExitDiagBlock(); 8290b57cec5SDimitry Andric return std::error_code(); 8300b57cec5SDimitry Andric } 8310b57cec5SDimitry Andric 8320b57cec5SDimitry Andric std::error_code 8330b57cec5SDimitry Andric SDiagsMerger::visitSourceRangeRecord(const serialized_diags::Location &Start, 8340b57cec5SDimitry Andric const serialized_diags::Location &End) { 8350b57cec5SDimitry Andric RecordData::value_type Record[] = { 8360b57cec5SDimitry Andric RECORD_SOURCE_RANGE, FileLookup[Start.FileID], Start.Line, Start.Col, 8370b57cec5SDimitry Andric Start.Offset, FileLookup[End.FileID], End.Line, End.Col, End.Offset}; 8380b57cec5SDimitry Andric Writer.State->Stream.EmitRecordWithAbbrev( 8390b57cec5SDimitry Andric Writer.State->Abbrevs.get(RECORD_SOURCE_RANGE), Record); 8400b57cec5SDimitry Andric return std::error_code(); 8410b57cec5SDimitry Andric } 8420b57cec5SDimitry Andric 8430b57cec5SDimitry Andric std::error_code SDiagsMerger::visitDiagnosticRecord( 8440b57cec5SDimitry Andric unsigned Severity, const serialized_diags::Location &Location, 8450b57cec5SDimitry Andric unsigned Category, unsigned Flag, StringRef Message) { 8460b57cec5SDimitry Andric RecordData::value_type Record[] = { 8470b57cec5SDimitry Andric RECORD_DIAG, Severity, FileLookup[Location.FileID], Location.Line, 8480b57cec5SDimitry Andric Location.Col, Location.Offset, CategoryLookup[Category], 8490b57cec5SDimitry Andric Flag ? DiagFlagLookup[Flag] : 0, Message.size()}; 8500b57cec5SDimitry Andric 8510b57cec5SDimitry Andric Writer.State->Stream.EmitRecordWithBlob( 8520b57cec5SDimitry Andric Writer.State->Abbrevs.get(RECORD_DIAG), Record, Message); 8530b57cec5SDimitry Andric return std::error_code(); 8540b57cec5SDimitry Andric } 8550b57cec5SDimitry Andric 8560b57cec5SDimitry Andric std::error_code 8570b57cec5SDimitry Andric SDiagsMerger::visitFixitRecord(const serialized_diags::Location &Start, 8580b57cec5SDimitry Andric const serialized_diags::Location &End, 8590b57cec5SDimitry Andric StringRef Text) { 8600b57cec5SDimitry Andric RecordData::value_type Record[] = {RECORD_FIXIT, FileLookup[Start.FileID], 8610b57cec5SDimitry Andric Start.Line, Start.Col, Start.Offset, 8620b57cec5SDimitry Andric FileLookup[End.FileID], End.Line, End.Col, 8630b57cec5SDimitry Andric End.Offset, Text.size()}; 8640b57cec5SDimitry Andric 8650b57cec5SDimitry Andric Writer.State->Stream.EmitRecordWithBlob( 8660b57cec5SDimitry Andric Writer.State->Abbrevs.get(RECORD_FIXIT), Record, Text); 8670b57cec5SDimitry Andric return std::error_code(); 8680b57cec5SDimitry Andric } 8690b57cec5SDimitry Andric 8700b57cec5SDimitry Andric std::error_code SDiagsMerger::visitFilenameRecord(unsigned ID, unsigned Size, 8710b57cec5SDimitry Andric unsigned Timestamp, 8720b57cec5SDimitry Andric StringRef Name) { 8730b57cec5SDimitry Andric FileLookup[ID] = Writer.getEmitFile(Name.str().c_str()); 8740b57cec5SDimitry Andric return std::error_code(); 8750b57cec5SDimitry Andric } 8760b57cec5SDimitry Andric 8770b57cec5SDimitry Andric std::error_code SDiagsMerger::visitCategoryRecord(unsigned ID, StringRef Name) { 8780b57cec5SDimitry Andric CategoryLookup[ID] = Writer.getEmitCategory(ID); 8790b57cec5SDimitry Andric return std::error_code(); 8800b57cec5SDimitry Andric } 8810b57cec5SDimitry Andric 8820b57cec5SDimitry Andric std::error_code SDiagsMerger::visitDiagFlagRecord(unsigned ID, StringRef Name) { 8830b57cec5SDimitry Andric DiagFlagLookup[ID] = Writer.getEmitDiagnosticFlag(Name); 8840b57cec5SDimitry Andric return std::error_code(); 8850b57cec5SDimitry Andric } 886