|
@@ -16,8 +16,7 @@
|
|
|
#include "clang/Basic/Diagnostic.h"
|
|
|
#include "clang/Basic/FileManager.h"
|
|
|
#include "clang/Basic/LLVM.h"
|
|
|
-#include "clang/Frontend/SerializedDiagnostics.h"
|
|
|
-#include "clang/Frontend/SerializedDiagnosticReader.h"
|
|
|
+#include "clang/Frontend/SerializedDiagnosticPrinter.h"
|
|
|
#include "llvm/ADT/Optional.h"
|
|
|
#include "llvm/ADT/StringRef.h"
|
|
|
#include "llvm/ADT/Twine.h"
|
|
@@ -184,207 +183,475 @@ void CXLoadedDiagnostic::decodeLocation(CXSourceLocation location,
|
|
|
// Deserialize diagnostics.
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
+enum { MaxSupportedVersion = 2 };
|
|
|
+typedef SmallVector<uint64_t, 64> RecordData;
|
|
|
+enum LoadResult { Failure = 1, Success = 0 };
|
|
|
+enum StreamResult { Read_EndOfStream,
|
|
|
+ Read_BlockBegin,
|
|
|
+ Read_Failure,
|
|
|
+ Read_Record,
|
|
|
+ Read_BlockEnd };
|
|
|
+
|
|
|
namespace {
|
|
|
-class DiagLoader : serialized_diags::SerializedDiagnosticReader {
|
|
|
+class DiagLoader {
|
|
|
enum CXLoadDiag_Error *error;
|
|
|
CXString *errorString;
|
|
|
- std::unique_ptr<CXLoadedDiagnosticSetImpl> TopDiags;
|
|
|
- SmallVector<std::unique_ptr<CXLoadedDiagnostic>, 8> CurrentDiags;
|
|
|
-
|
|
|
- std::error_code reportBad(enum CXLoadDiag_Error code, llvm::StringRef err) {
|
|
|
+
|
|
|
+ void reportBad(enum CXLoadDiag_Error code, llvm::StringRef err) {
|
|
|
if (error)
|
|
|
*error = code;
|
|
|
if (errorString)
|
|
|
*errorString = cxstring::createDup(err);
|
|
|
- return serialized_diags::SDError::HandlerFailed;
|
|
|
}
|
|
|
|
|
|
- std::error_code reportInvalidFile(llvm::StringRef err) {
|
|
|
+ void reportInvalidFile(llvm::StringRef err) {
|
|
|
return reportBad(CXLoadDiag_InvalidFile, err);
|
|
|
}
|
|
|
|
|
|
- std::error_code readRange(const serialized_diags::Location &SDStart,
|
|
|
- const serialized_diags::Location &SDEnd,
|
|
|
- CXSourceRange &SR);
|
|
|
-
|
|
|
- std::error_code readLocation(const serialized_diags::Location &SDLoc,
|
|
|
- CXLoadedDiagnostic::Location &LoadedLoc);
|
|
|
-
|
|
|
-protected:
|
|
|
- std::error_code visitStartOfDiagnostic() override;
|
|
|
- std::error_code visitEndOfDiagnostic() override;
|
|
|
-
|
|
|
- std::error_code visitCategoryRecord(unsigned ID, StringRef Name) override;
|
|
|
-
|
|
|
- std::error_code visitDiagFlagRecord(unsigned ID, StringRef Name) override;
|
|
|
-
|
|
|
- std::error_code visitDiagnosticRecord(
|
|
|
- unsigned Severity, const serialized_diags::Location &Location,
|
|
|
- unsigned Category, unsigned Flag, StringRef Message) override;
|
|
|
-
|
|
|
- std::error_code visitFilenameRecord(unsigned ID, unsigned Size,
|
|
|
- unsigned Timestamp,
|
|
|
- StringRef Name) override;
|
|
|
-
|
|
|
- std::error_code visitFixitRecord(const serialized_diags::Location &Start,
|
|
|
- const serialized_diags::Location &End,
|
|
|
- StringRef CodeToInsert) override;
|
|
|
-
|
|
|
- std::error_code
|
|
|
- visitSourceRangeRecord(const serialized_diags::Location &Start,
|
|
|
- const serialized_diags::Location &End) override;
|
|
|
-
|
|
|
+ LoadResult readMetaBlock(llvm::BitstreamCursor &Stream);
|
|
|
+
|
|
|
+ LoadResult readDiagnosticBlock(llvm::BitstreamCursor &Stream,
|
|
|
+ CXDiagnosticSetImpl &Diags,
|
|
|
+ CXLoadedDiagnosticSetImpl &TopDiags);
|
|
|
+
|
|
|
+ StreamResult readToNextRecordOrBlock(llvm::BitstreamCursor &Stream,
|
|
|
+ llvm::StringRef errorContext,
|
|
|
+ unsigned &BlockOrRecordID,
|
|
|
+ bool atTopLevel = false);
|
|
|
+
|
|
|
+
|
|
|
+ LoadResult readString(CXLoadedDiagnosticSetImpl &TopDiags,
|
|
|
+ Strings &strings, llvm::StringRef errorContext,
|
|
|
+ RecordData &Record,
|
|
|
+ StringRef Blob,
|
|
|
+ bool allowEmptyString = false);
|
|
|
+
|
|
|
+ LoadResult readString(CXLoadedDiagnosticSetImpl &TopDiags,
|
|
|
+ const char *&RetStr,
|
|
|
+ llvm::StringRef errorContext,
|
|
|
+ RecordData &Record,
|
|
|
+ StringRef Blob,
|
|
|
+ bool allowEmptyString = false);
|
|
|
+
|
|
|
+ LoadResult readRange(CXLoadedDiagnosticSetImpl &TopDiags,
|
|
|
+ RecordData &Record, unsigned RecStartIdx,
|
|
|
+ CXSourceRange &SR);
|
|
|
+
|
|
|
+ LoadResult readLocation(CXLoadedDiagnosticSetImpl &TopDiags,
|
|
|
+ RecordData &Record, unsigned &offset,
|
|
|
+ CXLoadedDiagnostic::Location &Loc);
|
|
|
+
|
|
|
public:
|
|
|
DiagLoader(enum CXLoadDiag_Error *e, CXString *es)
|
|
|
- : SerializedDiagnosticReader(), error(e), errorString(es) {
|
|
|
- if (error)
|
|
|
- *error = CXLoadDiag_None;
|
|
|
- if (errorString)
|
|
|
- *errorString = cxstring::createEmpty();
|
|
|
- }
|
|
|
+ : error(e), errorString(es) {
|
|
|
+ if (error)
|
|
|
+ *error = CXLoadDiag_None;
|
|
|
+ if (errorString)
|
|
|
+ *errorString = cxstring::createEmpty();
|
|
|
+ }
|
|
|
|
|
|
CXDiagnosticSet load(const char *file);
|
|
|
};
|
|
|
}
|
|
|
|
|
|
CXDiagnosticSet DiagLoader::load(const char *file) {
|
|
|
- TopDiags = llvm::make_unique<CXLoadedDiagnosticSetImpl>();
|
|
|
-
|
|
|
- std::error_code EC = readDiagnostics(file);
|
|
|
- if (EC) {
|
|
|
- switch (EC.value()) {
|
|
|
- case static_cast<int>(serialized_diags::SDError::HandlerFailed):
|
|
|
- // We've already reported the problem.
|
|
|
- break;
|
|
|
- case static_cast<int>(serialized_diags::SDError::CouldNotLoad):
|
|
|
- reportBad(CXLoadDiag_CannotLoad, EC.message());
|
|
|
- break;
|
|
|
- default:
|
|
|
- reportInvalidFile(EC.message());
|
|
|
- break;
|
|
|
- }
|
|
|
- return 0;
|
|
|
+ // Open the diagnostics file.
|
|
|
+ std::string ErrStr;
|
|
|
+ FileSystemOptions FO;
|
|
|
+ FileManager FileMgr(FO);
|
|
|
+
|
|
|
+ std::unique_ptr<llvm::MemoryBuffer> Buffer = FileMgr.getBufferForFile(file);
|
|
|
+ if (!Buffer) {
|
|
|
+ reportBad(CXLoadDiag_CannotLoad, ErrStr);
|
|
|
+ return nullptr;
|
|
|
}
|
|
|
|
|
|
- return (CXDiagnosticSet)TopDiags.release();
|
|
|
-}
|
|
|
+ llvm::BitstreamReader StreamFile;
|
|
|
+ StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
|
|
|
+ (const unsigned char *)Buffer->getBufferEnd());
|
|
|
+
|
|
|
+ llvm::BitstreamCursor Stream;
|
|
|
+ Stream.init(StreamFile);
|
|
|
+
|
|
|
+ // Sniff for the signature.
|
|
|
+ if (Stream.Read(8) != 'D' ||
|
|
|
+ Stream.Read(8) != 'I' ||
|
|
|
+ Stream.Read(8) != 'A' ||
|
|
|
+ Stream.Read(8) != 'G') {
|
|
|
+ reportBad(CXLoadDiag_InvalidFile,
|
|
|
+ "Bad header in diagnostics file");
|
|
|
+ return nullptr;
|
|
|
+ }
|
|
|
|
|
|
-std::error_code
|
|
|
-DiagLoader::readLocation(const serialized_diags::Location &SDLoc,
|
|
|
- CXLoadedDiagnostic::Location &LoadedLoc) {
|
|
|
- unsigned FileID = SDLoc.FileID;
|
|
|
- if (FileID == 0)
|
|
|
- LoadedLoc.file = nullptr;
|
|
|
- else {
|
|
|
- LoadedLoc.file = const_cast<FileEntry *>(TopDiags->Files[FileID]);
|
|
|
- if (!LoadedLoc.file)
|
|
|
- return reportInvalidFile("Corrupted file entry in source location");
|
|
|
+ std::unique_ptr<CXLoadedDiagnosticSetImpl> Diags(
|
|
|
+ new CXLoadedDiagnosticSetImpl());
|
|
|
+
|
|
|
+ while (true) {
|
|
|
+ unsigned BlockID = 0;
|
|
|
+ StreamResult Res = readToNextRecordOrBlock(Stream, "Top-level",
|
|
|
+ BlockID, true);
|
|
|
+ switch (Res) {
|
|
|
+ case Read_EndOfStream:
|
|
|
+ return (CXDiagnosticSet)Diags.release();
|
|
|
+ case Read_Failure:
|
|
|
+ return nullptr;
|
|
|
+ case Read_Record:
|
|
|
+ llvm_unreachable("Top-level does not have records");
|
|
|
+ case Read_BlockEnd:
|
|
|
+ continue;
|
|
|
+ case Read_BlockBegin:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (BlockID) {
|
|
|
+ case serialized_diags::BLOCK_META:
|
|
|
+ if (readMetaBlock(Stream))
|
|
|
+ return nullptr;
|
|
|
+ break;
|
|
|
+ case serialized_diags::BLOCK_DIAG:
|
|
|
+ if (readDiagnosticBlock(Stream, *Diags.get(), *Diags.get()))
|
|
|
+ return nullptr;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ if (!Stream.SkipBlock()) {
|
|
|
+ reportInvalidFile("Malformed block at top-level of diagnostics file");
|
|
|
+ return nullptr;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
- LoadedLoc.line = SDLoc.Line;
|
|
|
- LoadedLoc.column = SDLoc.Col;
|
|
|
- LoadedLoc.offset = SDLoc.Offset;
|
|
|
- return std::error_code();
|
|
|
}
|
|
|
|
|
|
-std::error_code
|
|
|
-DiagLoader::readRange(const serialized_diags::Location &SDStart,
|
|
|
- const serialized_diags::Location &SDEnd,
|
|
|
- CXSourceRange &SR) {
|
|
|
- CXLoadedDiagnostic::Location *Start, *End;
|
|
|
- Start = TopDiags->Alloc.Allocate<CXLoadedDiagnostic::Location>();
|
|
|
- End = TopDiags->Alloc.Allocate<CXLoadedDiagnostic::Location>();
|
|
|
-
|
|
|
- std::error_code EC;
|
|
|
- if ((EC = readLocation(SDStart, *Start)))
|
|
|
- return EC;
|
|
|
- if ((EC = readLocation(SDEnd, *End)))
|
|
|
- return EC;
|
|
|
+StreamResult DiagLoader::readToNextRecordOrBlock(llvm::BitstreamCursor &Stream,
|
|
|
+ llvm::StringRef errorContext,
|
|
|
+ unsigned &blockOrRecordID,
|
|
|
+ bool atTopLevel) {
|
|
|
|
|
|
- CXSourceLocation startLoc = makeLocation(Start);
|
|
|
- CXSourceLocation endLoc = makeLocation(End);
|
|
|
- SR = clang_getRange(startLoc, endLoc);
|
|
|
- return std::error_code();
|
|
|
+ blockOrRecordID = 0;
|
|
|
+
|
|
|
+ while (!Stream.AtEndOfStream()) {
|
|
|
+ unsigned Code = Stream.ReadCode();
|
|
|
+
|
|
|
+ // Handle the top-level specially.
|
|
|
+ if (atTopLevel) {
|
|
|
+ if (Code == llvm::bitc::ENTER_SUBBLOCK) {
|
|
|
+ unsigned BlockID = Stream.ReadSubBlockID();
|
|
|
+ if (BlockID == llvm::bitc::BLOCKINFO_BLOCK_ID) {
|
|
|
+ if (Stream.ReadBlockInfoBlock()) {
|
|
|
+ reportInvalidFile("Malformed BlockInfoBlock in diagnostics file");
|
|
|
+ return Read_Failure;
|
|
|
+ }
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ blockOrRecordID = BlockID;
|
|
|
+ return Read_BlockBegin;
|
|
|
+ }
|
|
|
+ reportInvalidFile("Only blocks can appear at the top of a "
|
|
|
+ "diagnostic file");
|
|
|
+ return Read_Failure;
|
|
|
+ }
|
|
|
+
|
|
|
+ switch ((llvm::bitc::FixedAbbrevIDs)Code) {
|
|
|
+ case llvm::bitc::ENTER_SUBBLOCK:
|
|
|
+ blockOrRecordID = Stream.ReadSubBlockID();
|
|
|
+ return Read_BlockBegin;
|
|
|
+
|
|
|
+ case llvm::bitc::END_BLOCK:
|
|
|
+ if (Stream.ReadBlockEnd()) {
|
|
|
+ reportInvalidFile("Cannot read end of block");
|
|
|
+ return Read_Failure;
|
|
|
+ }
|
|
|
+ return Read_BlockEnd;
|
|
|
+
|
|
|
+ case llvm::bitc::DEFINE_ABBREV:
|
|
|
+ Stream.ReadAbbrevRecord();
|
|
|
+ continue;
|
|
|
+
|
|
|
+ case llvm::bitc::UNABBREV_RECORD:
|
|
|
+ reportInvalidFile("Diagnostics file should have no unabbreviated "
|
|
|
+ "records");
|
|
|
+ return Read_Failure;
|
|
|
+
|
|
|
+ default:
|
|
|
+ // We found a record.
|
|
|
+ blockOrRecordID = Code;
|
|
|
+ return Read_Record;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (atTopLevel)
|
|
|
+ return Read_EndOfStream;
|
|
|
+
|
|
|
+ reportInvalidFile(Twine("Premature end of diagnostics file within ").str() +
|
|
|
+ errorContext.str());
|
|
|
+ return Read_Failure;
|
|
|
}
|
|
|
|
|
|
-std::error_code DiagLoader::visitStartOfDiagnostic() {
|
|
|
- CurrentDiags.push_back(llvm::make_unique<CXLoadedDiagnostic>());
|
|
|
- return std::error_code();
|
|
|
-}
|
|
|
+LoadResult DiagLoader::readMetaBlock(llvm::BitstreamCursor &Stream) {
|
|
|
+ if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_META)) {
|
|
|
+ reportInvalidFile("Malformed metadata block");
|
|
|
+ return Failure;
|
|
|
+ }
|
|
|
|
|
|
-std::error_code DiagLoader::visitEndOfDiagnostic() {
|
|
|
- auto D = CurrentDiags.pop_back_val();
|
|
|
- if (CurrentDiags.empty())
|
|
|
- TopDiags->appendDiagnostic(std::move(D));
|
|
|
- else
|
|
|
- CurrentDiags.back()->getChildDiagnostics().appendDiagnostic(std::move(D));
|
|
|
- return std::error_code();
|
|
|
+ bool versionChecked = false;
|
|
|
+
|
|
|
+ while (true) {
|
|
|
+ unsigned blockOrCode = 0;
|
|
|
+ StreamResult Res = readToNextRecordOrBlock(Stream, "Metadata Block",
|
|
|
+ blockOrCode);
|
|
|
+
|
|
|
+ switch(Res) {
|
|
|
+ case Read_EndOfStream:
|
|
|
+ llvm_unreachable("EndOfStream handled by readToNextRecordOrBlock");
|
|
|
+ case Read_Failure:
|
|
|
+ return Failure;
|
|
|
+ case Read_Record:
|
|
|
+ break;
|
|
|
+ case Read_BlockBegin:
|
|
|
+ if (Stream.SkipBlock()) {
|
|
|
+ reportInvalidFile("Malformed metadata block");
|
|
|
+ return Failure;
|
|
|
+ }
|
|
|
+ case Read_BlockEnd:
|
|
|
+ if (!versionChecked) {
|
|
|
+ reportInvalidFile("Diagnostics file does not contain version"
|
|
|
+ " information");
|
|
|
+ return Failure;
|
|
|
+ }
|
|
|
+ return Success;
|
|
|
+ }
|
|
|
+
|
|
|
+ RecordData Record;
|
|
|
+ unsigned recordID = Stream.readRecord(blockOrCode, Record);
|
|
|
+
|
|
|
+ if (recordID == serialized_diags::RECORD_VERSION) {
|
|
|
+ if (Record.size() < 1) {
|
|
|
+ reportInvalidFile("malformed VERSION identifier in diagnostics file");
|
|
|
+ return Failure;
|
|
|
+ }
|
|
|
+ if (Record[0] > MaxSupportedVersion) {
|
|
|
+ reportInvalidFile("diagnostics file is a newer version than the one "
|
|
|
+ "supported");
|
|
|
+ return Failure;
|
|
|
+ }
|
|
|
+ versionChecked = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-std::error_code DiagLoader::visitCategoryRecord(unsigned ID, StringRef Name) {
|
|
|
- // FIXME: Why do we care about long strings?
|
|
|
- if (Name.size() > 65536)
|
|
|
- return reportInvalidFile("Out-of-bounds string in category");
|
|
|
- TopDiags->Categories[ID] = TopDiags->copyString(Name);
|
|
|
- return std::error_code();
|
|
|
-}
|
|
|
+LoadResult DiagLoader::readString(CXLoadedDiagnosticSetImpl &TopDiags,
|
|
|
+ const char *&RetStr,
|
|
|
+ llvm::StringRef errorContext,
|
|
|
+ RecordData &Record,
|
|
|
+ StringRef Blob,
|
|
|
+ bool allowEmptyString) {
|
|
|
+
|
|
|
+ // Basic buffer overflow check.
|
|
|
+ if (Blob.size() > 65536) {
|
|
|
+ reportInvalidFile(std::string("Out-of-bounds string in ") +
|
|
|
+ std::string(errorContext));
|
|
|
+ return Failure;
|
|
|
+ }
|
|
|
|
|
|
-std::error_code DiagLoader::visitDiagFlagRecord(unsigned ID, StringRef Name) {
|
|
|
- // FIXME: Why do we care about long strings?
|
|
|
- if (Name.size() > 65536)
|
|
|
- return reportInvalidFile("Out-of-bounds string in warning flag");
|
|
|
- TopDiags->WarningFlags[ID] = TopDiags->copyString(Name);
|
|
|
- return std::error_code();
|
|
|
+ if (allowEmptyString && Record.size() >= 1 && Blob.size() == 0) {
|
|
|
+ RetStr = "";
|
|
|
+ return Success;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Record.size() < 1 || Blob.size() == 0) {
|
|
|
+ reportInvalidFile(std::string("Corrupted ") + std::string(errorContext)
|
|
|
+ + std::string(" entry"));
|
|
|
+ return Failure;
|
|
|
+ }
|
|
|
+
|
|
|
+ RetStr = TopDiags.copyString(Blob);
|
|
|
+ return Success;
|
|
|
}
|
|
|
|
|
|
-std::error_code DiagLoader::visitFilenameRecord(unsigned ID, unsigned Size,
|
|
|
- unsigned Timestamp,
|
|
|
- StringRef Name) {
|
|
|
- // FIXME: Why do we care about long strings?
|
|
|
- if (Name.size() > 65536)
|
|
|
- return reportInvalidFile("Out-of-bounds string in filename");
|
|
|
- TopDiags->FileNames[ID] = TopDiags->copyString(Name);
|
|
|
- TopDiags->Files[ID] =
|
|
|
- TopDiags->FakeFiles.getVirtualFile(Name, Size, Timestamp);
|
|
|
- return std::error_code();
|
|
|
+LoadResult DiagLoader::readString(CXLoadedDiagnosticSetImpl &TopDiags,
|
|
|
+ Strings &strings,
|
|
|
+ llvm::StringRef errorContext,
|
|
|
+ RecordData &Record,
|
|
|
+ StringRef Blob,
|
|
|
+ bool allowEmptyString) {
|
|
|
+ const char *RetStr;
|
|
|
+ if (readString(TopDiags, RetStr, errorContext, Record, Blob,
|
|
|
+ allowEmptyString))
|
|
|
+ return Failure;
|
|
|
+ strings[Record[0]] = RetStr;
|
|
|
+ return Success;
|
|
|
}
|
|
|
|
|
|
-std::error_code
|
|
|
-DiagLoader::visitSourceRangeRecord(const serialized_diags::Location &Start,
|
|
|
- const serialized_diags::Location &End) {
|
|
|
- CXSourceRange SR;
|
|
|
- if (std::error_code EC = readRange(Start, End, SR))
|
|
|
- return EC;
|
|
|
- CurrentDiags.back()->Ranges.push_back(SR);
|
|
|
- return std::error_code();
|
|
|
+LoadResult DiagLoader::readLocation(CXLoadedDiagnosticSetImpl &TopDiags,
|
|
|
+ RecordData &Record, unsigned &offset,
|
|
|
+ CXLoadedDiagnostic::Location &Loc) {
|
|
|
+ if (Record.size() < offset + 4) {
|
|
|
+ reportInvalidFile("Corrupted source location");
|
|
|
+ return Failure;
|
|
|
+ }
|
|
|
+ auto Fields = makeArrayRef(Record).slice(offset);
|
|
|
+ offset += 4;
|
|
|
+
|
|
|
+ unsigned fileID = Fields[0];
|
|
|
+ if (fileID == 0) {
|
|
|
+ // Sentinel value.
|
|
|
+ Loc.file = nullptr;
|
|
|
+ Loc.line = 0;
|
|
|
+ Loc.column = 0;
|
|
|
+ Loc.offset = 0;
|
|
|
+ return Success;
|
|
|
+ }
|
|
|
+
|
|
|
+ const FileEntry *FE = TopDiags.Files[fileID];
|
|
|
+ if (!FE) {
|
|
|
+ reportInvalidFile("Corrupted file entry in source location");
|
|
|
+ return Failure;
|
|
|
+ }
|
|
|
+ Loc.file = const_cast<FileEntry *>(FE);
|
|
|
+ Loc.line = Fields[1];
|
|
|
+ Loc.column = Fields[2];
|
|
|
+ Loc.offset = Fields[3];
|
|
|
+ return Success;
|
|
|
}
|
|
|
|
|
|
-std::error_code
|
|
|
-DiagLoader::visitFixitRecord(const serialized_diags::Location &Start,
|
|
|
- const serialized_diags::Location &End,
|
|
|
- StringRef CodeToInsert) {
|
|
|
- CXSourceRange SR;
|
|
|
- if (std::error_code EC = readRange(Start, End, SR))
|
|
|
- return EC;
|
|
|
- // FIXME: Why do we care about long strings?
|
|
|
- if (CodeToInsert.size() > 65536)
|
|
|
- return reportInvalidFile("Out-of-bounds string in FIXIT");
|
|
|
- CurrentDiags.back()->FixIts.push_back(
|
|
|
- std::make_pair(SR, TopDiags->copyString(CodeToInsert)));
|
|
|
- return std::error_code();
|
|
|
+LoadResult DiagLoader::readRange(CXLoadedDiagnosticSetImpl &TopDiags,
|
|
|
+ RecordData &Record,
|
|
|
+ unsigned int RecStartIdx,
|
|
|
+ CXSourceRange &SR) {
|
|
|
+ CXLoadedDiagnostic::Location *Start, *End;
|
|
|
+ Start = TopDiags.Alloc.Allocate<CXLoadedDiagnostic::Location>();
|
|
|
+ End = TopDiags.Alloc.Allocate<CXLoadedDiagnostic::Location>();
|
|
|
+
|
|
|
+ if (readLocation(TopDiags, Record, RecStartIdx, *Start))
|
|
|
+ return Failure;
|
|
|
+ if (readLocation(TopDiags, Record, RecStartIdx, *End))
|
|
|
+ return Failure;
|
|
|
+
|
|
|
+ CXSourceLocation startLoc = makeLocation(Start);
|
|
|
+ CXSourceLocation endLoc = makeLocation(End);
|
|
|
+ SR = clang_getRange(startLoc, endLoc);
|
|
|
+ return Success;
|
|
|
}
|
|
|
|
|
|
-std::error_code DiagLoader::visitDiagnosticRecord(
|
|
|
- unsigned Severity, const serialized_diags::Location &Location,
|
|
|
- unsigned Category, unsigned Flag, StringRef Message) {
|
|
|
- CXLoadedDiagnostic &D = *CurrentDiags.back();
|
|
|
- D.severity = Severity;
|
|
|
- if (std::error_code EC = readLocation(Location, D.DiagLoc))
|
|
|
- return EC;
|
|
|
- D.category = Category;
|
|
|
- D.DiagOption = Flag ? TopDiags->WarningFlags[Flag] : "";
|
|
|
- D.CategoryText = Category ? TopDiags->Categories[Category] : "";
|
|
|
- D.Spelling = TopDiags->copyString(Message);
|
|
|
- return std::error_code();
|
|
|
+LoadResult DiagLoader::readDiagnosticBlock(llvm::BitstreamCursor &Stream,
|
|
|
+ CXDiagnosticSetImpl &Diags,
|
|
|
+ CXLoadedDiagnosticSetImpl &TopDiags){
|
|
|
+
|
|
|
+ if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_DIAG)) {
|
|
|
+ reportInvalidFile("malformed diagnostic block");
|
|
|
+ return Failure;
|
|
|
+ }
|
|
|
+
|
|
|
+ std::unique_ptr<CXLoadedDiagnostic> D(new CXLoadedDiagnostic());
|
|
|
+ RecordData Record;
|
|
|
+
|
|
|
+ while (true) {
|
|
|
+ unsigned blockOrCode = 0;
|
|
|
+ StreamResult Res = readToNextRecordOrBlock(Stream, "Diagnostic Block",
|
|
|
+ blockOrCode);
|
|
|
+ switch (Res) {
|
|
|
+ case Read_EndOfStream:
|
|
|
+ llvm_unreachable("EndOfStream handled in readToNextRecordOrBlock");
|
|
|
+ case Read_Failure:
|
|
|
+ return Failure;
|
|
|
+ case Read_BlockBegin: {
|
|
|
+ // The only blocks we care about are subdiagnostics.
|
|
|
+ if (blockOrCode != serialized_diags::BLOCK_DIAG) {
|
|
|
+ if (!Stream.SkipBlock()) {
|
|
|
+ reportInvalidFile("Invalid subblock in Diagnostics block");
|
|
|
+ return Failure;
|
|
|
+ }
|
|
|
+ } else if (readDiagnosticBlock(Stream, D->getChildDiagnostics(),
|
|
|
+ TopDiags)) {
|
|
|
+ return Failure;
|
|
|
+ }
|
|
|
+
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ case Read_BlockEnd:
|
|
|
+ Diags.appendDiagnostic(std::move(D));
|
|
|
+ return Success;
|
|
|
+ case Read_Record:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Read the record.
|
|
|
+ Record.clear();
|
|
|
+ StringRef Blob;
|
|
|
+ unsigned recID = Stream.readRecord(blockOrCode, Record, &Blob);
|
|
|
+
|
|
|
+ if (recID < serialized_diags::RECORD_FIRST ||
|
|
|
+ recID > serialized_diags::RECORD_LAST)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ switch ((serialized_diags::RecordIDs)recID) {
|
|
|
+ case serialized_diags::RECORD_VERSION:
|
|
|
+ continue;
|
|
|
+ case serialized_diags::RECORD_CATEGORY:
|
|
|
+ if (readString(TopDiags, TopDiags.Categories, "category", Record,
|
|
|
+ Blob, /* allowEmptyString */ true))
|
|
|
+ return Failure;
|
|
|
+ continue;
|
|
|
+
|
|
|
+ case serialized_diags::RECORD_DIAG_FLAG:
|
|
|
+ if (readString(TopDiags, TopDiags.WarningFlags, "warning flag", Record,
|
|
|
+ Blob))
|
|
|
+ return Failure;
|
|
|
+ continue;
|
|
|
+
|
|
|
+ case serialized_diags::RECORD_FILENAME: {
|
|
|
+ if (readString(TopDiags, TopDiags.FileNames, "filename", Record,
|
|
|
+ Blob))
|
|
|
+ return Failure;
|
|
|
+
|
|
|
+ if (Record.size() < 3) {
|
|
|
+ reportInvalidFile("Invalid file entry");
|
|
|
+ return Failure;
|
|
|
+ }
|
|
|
+
|
|
|
+ const FileEntry *FE =
|
|
|
+ TopDiags.FakeFiles.getVirtualFile(TopDiags.FileNames[Record[0]],
|
|
|
+ /* size */ Record[1],
|
|
|
+ /* time */ Record[2]);
|
|
|
+
|
|
|
+ TopDiags.Files[Record[0]] = FE;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ case serialized_diags::RECORD_SOURCE_RANGE: {
|
|
|
+ CXSourceRange SR;
|
|
|
+ if (readRange(TopDiags, Record, 0, SR))
|
|
|
+ return Failure;
|
|
|
+ D->Ranges.push_back(SR);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ case serialized_diags::RECORD_FIXIT: {
|
|
|
+ CXSourceRange SR;
|
|
|
+ if (readRange(TopDiags, Record, 0, SR))
|
|
|
+ return Failure;
|
|
|
+ const char *RetStr;
|
|
|
+ if (readString(TopDiags, RetStr, "FIXIT", Record, Blob,
|
|
|
+ /* allowEmptyString */ true))
|
|
|
+ return Failure;
|
|
|
+ D->FixIts.push_back(std::make_pair(SR, RetStr));
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ case serialized_diags::RECORD_DIAG: {
|
|
|
+ D->severity = Record[0];
|
|
|
+ unsigned offset = 1;
|
|
|
+ if (readLocation(TopDiags, Record, offset, D->DiagLoc))
|
|
|
+ return Failure;
|
|
|
+ D->category = Record[offset++];
|
|
|
+ unsigned diagFlag = Record[offset++];
|
|
|
+ D->DiagOption = diagFlag ? TopDiags.WarningFlags[diagFlag] : "";
|
|
|
+ D->CategoryText = D->category ? TopDiags.Categories[D->category] : "";
|
|
|
+ D->Spelling = TopDiags.copyString(Blob);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
extern "C" {
|