Skip to content

[Serialized diagnostics] Record generated buffer contents in diagnostics files #5901

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions clang/include/clang-c/CXDiagnostic.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,30 @@ CINDEX_LINKAGE void clang_disposeDiagnosticSet(CXDiagnosticSet Diags);
*/
CINDEX_LINKAGE CXDiagnosticSet clang_getChildDiagnostics(CXDiagnostic D);

/**
* Get the contents if the given file that was provided via diagnostics.
*
* \param diags the diagnostics set to query for the contents of the file.
* \param file the file to get the contents of.
* \param outFileSize if non-null, set to the file size on success.
* \returns on success, a pointer to the file contents. Otherwise, NULL.
*/
CINDEX_LINKAGE const char *clang_getDiagnosticFileContents(
CXDiagnosticSet diags, CXFile file, size_t *outFileSize);

/**
* Retrieve the original source range if the given file was provided via
* diagnostics and is conceptually a replacement for the original source range.
*
* \param diags the diagnostics set to query for the contents of the file.
* \param file the file to get the contents of.
* \returns on success, the source range (into another file) that is
* conceptually replaced by the contents of the given file (available via
* \c clang_getDiagnosticFileContents).
*/
CINDEX_LINKAGE CXSourceRange clang_getDiagnosticFileOriginalSourceRange(
CXDiagnosticSet diags, CXFile file);

/**
* Destroy a diagnostic.
*/
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang-c/Index.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
* compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable.
*/
#define CINDEX_VERSION_MAJOR 0
#define CINDEX_VERSION_MINOR 62
#define CINDEX_VERSION_MINOR 63

#define CINDEX_VERSION_ENCODE(major, minor) (((major)*10000) + ((minor)*1))

Expand Down
10 changes: 10 additions & 0 deletions clang/include/clang/Frontend/SerializedDiagnosticReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,16 @@ class SerializedDiagnosticReader {
return {};
}

/// Visit file contents. This associates the file's \c ID with the
/// contents of
virtual std::error_code visitSourceFileContentsRecord(
unsigned ID,
const Location &OriginalStartLoc,
const Location &OriginalEndLoc,
StringRef Contents) {
return {};
}

/// Visit a fixit hint.
virtual std::error_code
visitFixitRecord(const Location &Start, const Location &End, StringRef Text) {
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/Frontend/SerializedDiagnostics.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ enum RecordIDs {
RECORD_CATEGORY,
RECORD_FILENAME,
RECORD_FIXIT,
RECORD_SOURCE_FILE_CONTENTS,
RECORD_FIRST = RECORD_VERSION,
RECORD_LAST = RECORD_FIXIT
RECORD_LAST = RECORD_SOURCE_FILE_CONTENTS
};

/// A stable version of DiagnosticIDs::Level.
Expand Down
41 changes: 41 additions & 0 deletions clang/lib/Frontend/SerializedDiagnosticPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ class SDiagsMerger : SerializedDiagnosticReader {
AbbrevLookup FileLookup;
AbbrevLookup CategoryLookup;
AbbrevLookup DiagFlagLookup;
llvm::DenseSet<unsigned> ContentsWritten;

public:
SDiagsMerger(SDiagsWriter &Writer) : Writer(Writer) {}
Expand All @@ -112,6 +113,12 @@ class SDiagsMerger : SerializedDiagnosticReader {
std::error_code visitFilenameRecord(unsigned ID, unsigned Size,
unsigned Timestamp,
StringRef Name) override;
std::error_code visitSourceFileContentsRecord(
unsigned ID,
const Location &OriginalStartLoc,
const Location &OriginalEndLoc,
StringRef Contents) override;

std::error_code visitFixitRecord(const serialized_diags::Location &Start,
const serialized_diags::Location &End,
StringRef CodeToInsert) override;
Expand Down Expand Up @@ -462,6 +469,8 @@ void SDiagsWriter::EmitBlockInfoBlock() {
EmitRecordID(RECORD_DIAG_FLAG, "DiagFlag", Stream, Record);
EmitRecordID(RECORD_FILENAME, "FileName", Stream, Record);
EmitRecordID(RECORD_FIXIT, "FixIt", Stream, Record);
EmitRecordID(
RECORD_SOURCE_FILE_CONTENTS, "SourceFileContents", Stream, Record);

// Emit abbreviation for RECORD_DIAG.
Abbrev = std::make_shared<BitCodeAbbrev>();
Expand Down Expand Up @@ -518,6 +527,16 @@ void SDiagsWriter::EmitBlockInfoBlock() {
Abbrevs.set(RECORD_FIXIT, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
Abbrev));

// Emit the abbreviation for RECORD_SOURCE_FILE_CONTENTS.
Abbrev = std::make_shared<BitCodeAbbrev>();
Abbrev->Add(BitCodeAbbrevOp(RECORD_SOURCE_FILE_CONTENTS));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // File ID.
AddRangeLocationAbbrev(*Abbrev);
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // File size.
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File contents.
Abbrevs.set(RECORD_SOURCE_FILE_CONTENTS,
Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));

Stream.ExitBlock();
}

Expand Down Expand Up @@ -890,6 +909,28 @@ std::error_code SDiagsMerger::visitFilenameRecord(unsigned ID, unsigned Size,
return std::error_code();
}

std::error_code SDiagsMerger::visitSourceFileContentsRecord(
unsigned ID,
const Location &OriginalStartLoc,
const Location &OriginalEndLoc,
StringRef Contents) {
unsigned MappedID = FileLookup[ID];
if (!ContentsWritten.insert(MappedID).second)
return std::error_code();

RecordData::value_type Record[] = {
RECORD_SOURCE_FILE_CONTENTS, MappedID,
FileLookup[OriginalStartLoc.FileID],
OriginalStartLoc.Line, OriginalStartLoc.Col, OriginalStartLoc.Offset,
FileLookup[OriginalEndLoc.FileID], OriginalEndLoc.Line,
OriginalEndLoc.Col, OriginalEndLoc.Offset,
Contents.size()};

Writer.State->Stream.EmitRecordWithBlob(
Writer.State->Abbrevs.get(RECORD_SOURCE_FILE_CONTENTS), Record, Contents);
return std::error_code();
}

std::error_code SDiagsMerger::visitCategoryRecord(unsigned ID, StringRef Name) {
CategoryLookup[ID] = Writer.getEmitCategory(ID);
return std::error_code();
Expand Down
10 changes: 10 additions & 0 deletions clang/lib/Frontend/SerializedDiagnosticReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,16 @@ SerializedDiagnosticReader::readDiagnosticBlock(llvm::BitstreamCursor &Stream) {
Location(Record[4], Record[5], Record[6], Record[7]), Blob)))
return EC;
continue;
case RECORD_SOURCE_FILE_CONTENTS:
if (Record.size() != 10 || Record[9] != Blob.size())
return SDError::MalformedDiagnosticRecord;
if ((EC = visitSourceFileContentsRecord(
Record[0],
Location(Record[1], Record[2], Record[3], Record[4]),
Location(Record[5], Record[6], Record[7], Record[8]),
Blob)))
return EC;
continue;
case RECORD_SOURCE_RANGE:
// A source range is two locations (4 each).
if (Record.size() != 8)
Expand Down
36 changes: 30 additions & 6 deletions clang/tools/c-index-test/c-index-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -4716,7 +4716,8 @@ static void printFixIts(CXDiagnostic D, unsigned indent) {
}
}

static void printDiagnosticSet(CXDiagnosticSet Diags, unsigned indent) {
static void printDiagnosticSet(
CXDiagnosticSet Diags, unsigned indent, CXDiagnosticSet TopDiags) {
unsigned i, n;

if (!Diags)
Expand All @@ -4730,7 +4731,8 @@ static void printDiagnosticSet(CXDiagnosticSet Diags, unsigned indent) {
CXString FileName, DiagSpelling, DiagOption, DiagCat;
unsigned line, column, offset;
const char *FileNameStr = 0, *DiagOptionStr = 0, *DiagCatStr = 0;

const char *FileContents = 0;

D = clang_getDiagnosticInSet(Diags, i);
DiagLoc = clang_getDiagnosticLocation(D);
clang_getExpansionLocation(DiagLoc, &File, &line, &column, &offset);
Expand Down Expand Up @@ -4763,15 +4765,37 @@ static void printDiagnosticSet(CXDiagnosticSet Diags, unsigned indent) {

printRanges(D, indent);
printFixIts(D, indent);


// If we have the source file contents for this file, print them now.
FileContents = clang_getDiagnosticFileContents(TopDiags, File, 0);
if (FileContents) {
CXSourceRange OriginalSourceRange;

fprintf(stderr, "CONTENTS OF FILE %s:\n",
FileNameStr ? FileNameStr : "(null)");

OriginalSourceRange = clang_getDiagnosticFileOriginalSourceRange(
TopDiags, File);
if (!clang_equalRanges(clang_getNullRange(), OriginalSourceRange)) {
printIndent(indent);
fprintf(stderr, "Original source range: ");
printLocation(clang_getRangeStart(OriginalSourceRange));
fprintf(stderr, " - ");
printLocation(clang_getRangeEnd(OriginalSourceRange));
fprintf(stderr, "\n");
}

fprintf(stderr, "%s\nEND CONTENTS OF FILE\n", FileContents);
}

/* Print subdiagnostics. */
printDiagnosticSet(clang_getChildDiagnostics(D), indent+2);
printDiagnosticSet(clang_getChildDiagnostics(D), indent+2, TopDiags);

clang_disposeString(FileName);
clang_disposeString(DiagSpelling);
clang_disposeString(DiagOption);
clang_disposeString(DiagCat);
}
}
}

static int read_diagnostics(const char *filename) {
Expand All @@ -4788,7 +4812,7 @@ static int read_diagnostics(const char *filename) {
return 1;
}

printDiagnosticSet(Diags, 0);
printDiagnosticSet(Diags, 0, Diags);
fprintf(stderr, "Number of diagnostics: %d\n",
clang_getNumDiagnosticsInSet(Diags));
clang_disposeDiagnosticSet(Diags);
Expand Down
29 changes: 29 additions & 0 deletions clang/tools/libclang/CIndexDiagnostic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ CXDiagnosticSetImpl::appendDiagnostic(std::unique_ptr<CXDiagnosticImpl> D) {
Diagnostics.push_back(std::move(D));
}

void CXDiagnosticSetImpl::recordSourceFileContents(
CXFile file, StringRef contents, CXSourceRange originalSourceRange) {
FileContents[file] = CXSourceFileContents{contents, originalSourceRange};
}

CXDiagnosticImpl::~CXDiagnosticImpl() {}

namespace {
Expand Down Expand Up @@ -479,6 +484,30 @@ CXDiagnosticSet clang_getChildDiagnostics(CXDiagnostic Diag) {
return nullptr;
}

const char *clang_getDiagnosticFileContents(
CXDiagnosticSet diags, CXFile file, size_t *outFileSize) {
if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl *>(diags)) {
CXSourceRange originalSourceRange;
if (auto contents = D->getSourceFileContents(file, originalSourceRange)) {
if (outFileSize)
*outFileSize = contents->size();
return contents->data();
}
}
return nullptr;
}

CXSourceRange clang_getDiagnosticFileOriginalSourceRange(
CXDiagnosticSet diags, CXFile file) {
if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl *>(diags)) {
CXSourceRange originalSourceRange;
if (auto contents = D->getSourceFileContents(file, originalSourceRange)) {
return originalSourceRange;
}
}
return clang_getNullRange();
}

unsigned clang_getNumDiagnosticsInSet(CXDiagnosticSet Diags) {
if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags))
return D->getNumDiagnostics();
Expand Down
24 changes: 23 additions & 1 deletion clang/tools/libclang/CIndexDiagnostic.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@

#include "clang-c/Index.h"
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringRef.h"
#include <memory>
#include <vector>
#include <assert.h>
Expand All @@ -24,9 +27,15 @@ namespace clang {
class LangOptions;
class StoredDiagnostic;
class CXDiagnosticImpl;

class CXDiagnosticSetImpl {
struct CXSourceFileContents {
StringRef Contents;
CXSourceRange OriginalSourceRange;
};

std::vector<std::unique_ptr<CXDiagnosticImpl>> Diagnostics;
llvm::DenseMap<CXFile, CXSourceFileContents> FileContents;
const bool IsExternallyManaged;
public:
CXDiagnosticSetImpl(bool isManaged = false)
Expand All @@ -45,6 +54,19 @@ class CXDiagnosticSetImpl {

void appendDiagnostic(std::unique_ptr<CXDiagnosticImpl> D);

void recordSourceFileContents(
CXFile file, StringRef contents, CXSourceRange originalSourceRange);

Optional<StringRef> getSourceFileContents(
CXFile file, CXSourceRange &originalSourceRange) {
auto found = FileContents.find(file);
if (found == FileContents.end())
return None;

originalSourceRange = found->second.OriginalSourceRange;
return found->second.Contents;
}

bool empty() const {
return Diagnostics.empty();
}
Expand Down
28 changes: 28 additions & 0 deletions clang/tools/libclang/CXLoadedDiagnostic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,12 @@ class DiagLoader : serialized_diags::SerializedDiagnosticReader {
unsigned Timestamp,
StringRef Name) override;

std::error_code visitSourceFileContentsRecord(
unsigned ID,
const serialized_diags::Location &OriginalStartLoc,
const serialized_diags::Location &OriginalEndLoc,
StringRef Contents) override;

std::error_code visitFixitRecord(const serialized_diags::Location &Start,
const serialized_diags::Location &End,
StringRef CodeToInsert) override;
Expand Down Expand Up @@ -347,6 +353,28 @@ std::error_code DiagLoader::visitFilenameRecord(unsigned ID, unsigned Size,
return std::error_code();
}

std::error_code DiagLoader::visitSourceFileContentsRecord(
unsigned ID,
const serialized_diags::Location &OriginalStartLoc,
const serialized_diags::Location &OriginalEndLoc,
StringRef Contents
) {
CXSourceRange OriginalSourceRange;
if (std::error_code EC = readRange(
OriginalStartLoc, OriginalEndLoc, OriginalSourceRange))
return EC;

auto file = const_cast<FileEntry *>(TopDiags->Files[ID]);
if (!file)
return reportInvalidFile("Source file contents for unknown file ID");

StringRef CopiedContents(TopDiags->copyString(Contents),
Contents.size());

TopDiags->recordSourceFileContents(file, CopiedContents, OriginalSourceRange);
return std::error_code();
}

std::error_code
DiagLoader::visitSourceRangeRecord(const serialized_diags::Location &Start,
const serialized_diags::Location &End) {
Expand Down
2 changes: 2 additions & 0 deletions clang/tools/libclang/libclang.map
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,8 @@ LLVM_16 {
clang_experimental_DependencyScannerServiceOptions_setObjectStore;
clang_experimental_DependencyScannerWorker_getFileDependencies_v5;
clang_createAPISet;
clang_getDiagnosticFileContents;
clang_getDiagnosticFileOriginalSourceRange;
clang_disposeAPISet;
clang_getSymbolGraphForCursor;
clang_getSymbolGraphForUSR;
Expand Down