Skip to content

Commit c02bda5

Browse files
authored
Merge pull request #7070 from etcwilde/ewilde/next/record-generated-buffer-contents-in-diagnostic-file
🍒[next][Serialized diagnostics] Record generated buffer contents in diagnostics files
2 parents 937b12e + d29fa52 commit c02bda5

File tree

11 files changed

+200
-9
lines changed

11 files changed

+200
-9
lines changed

clang/include/clang-c/CXDiagnostic.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,30 @@ CINDEX_LINKAGE void clang_disposeDiagnosticSet(CXDiagnosticSet Diags);
148148
*/
149149
CINDEX_LINKAGE CXDiagnosticSet clang_getChildDiagnostics(CXDiagnostic D);
150150

151+
/**
152+
* Get the contents if the given file that was provided via diagnostics.
153+
*
154+
* \param diags the diagnostics set to query for the contents of the file.
155+
* \param file the file to get the contents of.
156+
* \param outFileSize if non-null, set to the file size on success.
157+
* \returns on success, a pointer to the file contents. Otherwise, NULL.
158+
*/
159+
CINDEX_LINKAGE const char *clang_getDiagnosticFileContents(
160+
CXDiagnosticSet diags, CXFile file, size_t *outFileSize);
161+
162+
/**
163+
* Retrieve the original source range if the given file was provided via
164+
* diagnostics and is conceptually a replacement for the original source range.
165+
*
166+
* \param diags the diagnostics set to query for the contents of the file.
167+
* \param file the file to get the contents of.
168+
* \returns on success, the source range (into another file) that is
169+
* conceptually replaced by the contents of the given file (available via
170+
* \c clang_getDiagnosticFileContents).
171+
*/
172+
CINDEX_LINKAGE CXSourceRange clang_getDiagnosticFileOriginalSourceRange(
173+
CXDiagnosticSet diags, CXFile file);
174+
151175
/**
152176
* Destroy a diagnostic.
153177
*/

clang/include/clang-c/Index.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
* compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable.
3535
*/
3636
#define CINDEX_VERSION_MAJOR 0
37-
#define CINDEX_VERSION_MINOR 64
37+
#define CINDEX_VERSION_MINOR 65
3838

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

clang/include/clang/Frontend/SerializedDiagnosticReader.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,16 @@ class SerializedDiagnosticReader {
112112
return {};
113113
}
114114

115+
/// Visit file contents. This associates the file's \c ID with the
116+
/// contents of
117+
virtual std::error_code visitSourceFileContentsRecord(
118+
unsigned ID,
119+
const Location &OriginalStartLoc,
120+
const Location &OriginalEndLoc,
121+
StringRef Contents) {
122+
return {};
123+
}
124+
115125
/// Visit a fixit hint.
116126
virtual std::error_code
117127
visitFixitRecord(const Location &Start, const Location &End, StringRef Text) {

clang/include/clang/Frontend/SerializedDiagnostics.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@ enum RecordIDs {
3232
RECORD_CATEGORY,
3333
RECORD_FILENAME,
3434
RECORD_FIXIT,
35+
RECORD_SOURCE_FILE_CONTENTS,
3536
RECORD_FIRST = RECORD_VERSION,
36-
RECORD_LAST = RECORD_FIXIT
37+
RECORD_LAST = RECORD_SOURCE_FILE_CONTENTS
3738
};
3839

3940
/// A stable version of DiagnosticIDs::Level.

clang/lib/Frontend/SerializedDiagnosticPrinter.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ class SDiagsMerger : SerializedDiagnosticReader {
9191
AbbrevLookup FileLookup;
9292
AbbrevLookup CategoryLookup;
9393
AbbrevLookup DiagFlagLookup;
94+
llvm::DenseSet<unsigned> ContentsWritten;
9495

9596
public:
9697
SDiagsMerger(SDiagsWriter &Writer) : Writer(Writer) {}
@@ -110,6 +111,12 @@ class SDiagsMerger : SerializedDiagnosticReader {
110111
std::error_code visitFilenameRecord(unsigned ID, unsigned Size,
111112
unsigned Timestamp,
112113
StringRef Name) override;
114+
std::error_code visitSourceFileContentsRecord(
115+
unsigned ID,
116+
const Location &OriginalStartLoc,
117+
const Location &OriginalEndLoc,
118+
StringRef Contents) override;
119+
113120
std::error_code visitFixitRecord(const serialized_diags::Location &Start,
114121
const serialized_diags::Location &End,
115122
StringRef CodeToInsert) override;
@@ -460,6 +467,8 @@ void SDiagsWriter::EmitBlockInfoBlock() {
460467
EmitRecordID(RECORD_DIAG_FLAG, "DiagFlag", Stream, Record);
461468
EmitRecordID(RECORD_FILENAME, "FileName", Stream, Record);
462469
EmitRecordID(RECORD_FIXIT, "FixIt", Stream, Record);
470+
EmitRecordID(
471+
RECORD_SOURCE_FILE_CONTENTS, "SourceFileContents", Stream, Record);
463472

464473
// Emit abbreviation for RECORD_DIAG.
465474
Abbrev = std::make_shared<BitCodeAbbrev>();
@@ -516,6 +525,16 @@ void SDiagsWriter::EmitBlockInfoBlock() {
516525
Abbrevs.set(RECORD_FIXIT, Stream.EmitBlockInfoAbbrev(BLOCK_DIAG,
517526
Abbrev));
518527

528+
// Emit the abbreviation for RECORD_SOURCE_FILE_CONTENTS.
529+
Abbrev = std::make_shared<BitCodeAbbrev>();
530+
Abbrev->Add(BitCodeAbbrevOp(RECORD_SOURCE_FILE_CONTENTS));
531+
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // File ID.
532+
AddRangeLocationAbbrev(*Abbrev);
533+
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // File size.
534+
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File contents.
535+
Abbrevs.set(RECORD_SOURCE_FILE_CONTENTS,
536+
Stream.EmitBlockInfoAbbrev(BLOCK_DIAG, Abbrev));
537+
519538
Stream.ExitBlock();
520539
}
521540

@@ -891,6 +910,28 @@ std::error_code SDiagsMerger::visitFilenameRecord(unsigned ID, unsigned Size,
891910
return std::error_code();
892911
}
893912

913+
std::error_code SDiagsMerger::visitSourceFileContentsRecord(
914+
unsigned ID,
915+
const Location &OriginalStartLoc,
916+
const Location &OriginalEndLoc,
917+
StringRef Contents) {
918+
unsigned MappedID = FileLookup[ID];
919+
if (!ContentsWritten.insert(MappedID).second)
920+
return std::error_code();
921+
922+
RecordData::value_type Record[] = {
923+
RECORD_SOURCE_FILE_CONTENTS, MappedID,
924+
FileLookup[OriginalStartLoc.FileID],
925+
OriginalStartLoc.Line, OriginalStartLoc.Col, OriginalStartLoc.Offset,
926+
FileLookup[OriginalEndLoc.FileID], OriginalEndLoc.Line,
927+
OriginalEndLoc.Col, OriginalEndLoc.Offset,
928+
Contents.size()};
929+
930+
Writer.State->Stream.EmitRecordWithBlob(
931+
Writer.State->Abbrevs.get(RECORD_SOURCE_FILE_CONTENTS), Record, Contents);
932+
return std::error_code();
933+
}
934+
894935
std::error_code SDiagsMerger::visitCategoryRecord(unsigned ID, StringRef Name) {
895936
CategoryLookup[ID] = Writer.getEmitCategory(ID);
896937
return std::error_code();

clang/lib/Frontend/SerializedDiagnosticReader.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,16 @@ SerializedDiagnosticReader::readDiagnosticBlock(llvm::BitstreamCursor &Stream) {
307307
Location(Record[4], Record[5], Record[6], Record[7]), Blob)))
308308
return EC;
309309
continue;
310+
case RECORD_SOURCE_FILE_CONTENTS:
311+
if (Record.size() != 10 || Record[9] != Blob.size())
312+
return SDError::MalformedDiagnosticRecord;
313+
if ((EC = visitSourceFileContentsRecord(
314+
Record[0],
315+
Location(Record[1], Record[2], Record[3], Record[4]),
316+
Location(Record[5], Record[6], Record[7], Record[8]),
317+
Blob)))
318+
return EC;
319+
continue;
310320
case RECORD_SOURCE_RANGE:
311321
// A source range is two locations (4 each).
312322
if (Record.size() != 8)

clang/tools/c-index-test/c-index-test.c

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4746,7 +4746,8 @@ static void printFixIts(CXDiagnostic D, unsigned indent) {
47464746
}
47474747
}
47484748

4749-
static void printDiagnosticSet(CXDiagnosticSet Diags, unsigned indent) {
4749+
static void printDiagnosticSet(
4750+
CXDiagnosticSet Diags, unsigned indent, CXDiagnosticSet TopDiags) {
47504751
unsigned i, n;
47514752

47524753
if (!Diags)
@@ -4760,7 +4761,8 @@ static void printDiagnosticSet(CXDiagnosticSet Diags, unsigned indent) {
47604761
CXString FileName, DiagSpelling, DiagOption, DiagCat;
47614762
unsigned line, column, offset;
47624763
const char *FileNameStr = 0, *DiagOptionStr = 0, *DiagCatStr = 0;
4763-
4764+
const char *FileContents = 0;
4765+
47644766
D = clang_getDiagnosticInSet(Diags, i);
47654767
DiagLoc = clang_getDiagnosticLocation(D);
47664768
clang_getExpansionLocation(DiagLoc, &File, &line, &column, &offset);
@@ -4793,15 +4795,37 @@ static void printDiagnosticSet(CXDiagnosticSet Diags, unsigned indent) {
47934795

47944796
printRanges(D, indent);
47954797
printFixIts(D, indent);
4796-
4798+
4799+
// If we have the source file contents for this file, print them now.
4800+
FileContents = clang_getDiagnosticFileContents(TopDiags, File, 0);
4801+
if (FileContents) {
4802+
CXSourceRange OriginalSourceRange;
4803+
4804+
fprintf(stderr, "CONTENTS OF FILE %s:\n",
4805+
FileNameStr ? FileNameStr : "(null)");
4806+
4807+
OriginalSourceRange = clang_getDiagnosticFileOriginalSourceRange(
4808+
TopDiags, File);
4809+
if (!clang_equalRanges(clang_getNullRange(), OriginalSourceRange)) {
4810+
printIndent(indent);
4811+
fprintf(stderr, "Original source range: ");
4812+
printLocation(clang_getRangeStart(OriginalSourceRange));
4813+
fprintf(stderr, " - ");
4814+
printLocation(clang_getRangeEnd(OriginalSourceRange));
4815+
fprintf(stderr, "\n");
4816+
}
4817+
4818+
fprintf(stderr, "%s\nEND CONTENTS OF FILE\n", FileContents);
4819+
}
4820+
47974821
/* Print subdiagnostics. */
4798-
printDiagnosticSet(clang_getChildDiagnostics(D), indent+2);
4822+
printDiagnosticSet(clang_getChildDiagnostics(D), indent+2, TopDiags);
47994823

48004824
clang_disposeString(FileName);
48014825
clang_disposeString(DiagSpelling);
48024826
clang_disposeString(DiagOption);
48034827
clang_disposeString(DiagCat);
4804-
}
4828+
}
48054829
}
48064830

48074831
static int read_diagnostics(const char *filename) {
@@ -4818,7 +4842,7 @@ static int read_diagnostics(const char *filename) {
48184842
return 1;
48194843
}
48204844

4821-
printDiagnosticSet(Diags, 0);
4845+
printDiagnosticSet(Diags, 0, Diags);
48224846
fprintf(stderr, "Number of diagnostics: %d\n",
48234847
clang_getNumDiagnosticsInSet(Diags));
48244848
clang_disposeDiagnosticSet(Diags);

clang/tools/libclang/CIndexDiagnostic.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ CXDiagnosticSetImpl::appendDiagnostic(std::unique_ptr<CXDiagnosticImpl> D) {
3434
Diagnostics.push_back(std::move(D));
3535
}
3636

37+
void CXDiagnosticSetImpl::recordSourceFileContents(
38+
CXFile file, StringRef contents, CXSourceRange originalSourceRange) {
39+
FileContents[file] = CXSourceFileContents{contents, originalSourceRange};
40+
}
41+
3742
CXDiagnosticImpl::~CXDiagnosticImpl() {}
3843

3944
namespace {
@@ -479,6 +484,30 @@ CXDiagnosticSet clang_getChildDiagnostics(CXDiagnostic Diag) {
479484
return nullptr;
480485
}
481486

487+
const char *clang_getDiagnosticFileContents(
488+
CXDiagnosticSet diags, CXFile file, size_t *outFileSize) {
489+
if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl *>(diags)) {
490+
CXSourceRange originalSourceRange;
491+
if (auto contents = D->getSourceFileContents(file, originalSourceRange)) {
492+
if (outFileSize)
493+
*outFileSize = contents->size();
494+
return contents->data();
495+
}
496+
}
497+
return nullptr;
498+
}
499+
500+
CXSourceRange clang_getDiagnosticFileOriginalSourceRange(
501+
CXDiagnosticSet diags, CXFile file) {
502+
if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl *>(diags)) {
503+
CXSourceRange originalSourceRange;
504+
if (auto contents = D->getSourceFileContents(file, originalSourceRange)) {
505+
return originalSourceRange;
506+
}
507+
}
508+
return clang_getNullRange();
509+
}
510+
482511
unsigned clang_getNumDiagnosticsInSet(CXDiagnosticSet Diags) {
483512
if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags))
484513
return D->getNumDiagnostics();

clang/tools/libclang/CIndexDiagnostic.h

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515

1616
#include "clang-c/Index.h"
1717
#include "clang/Basic/LLVM.h"
18+
#include "llvm/ADT/DenseMap.h"
19+
#include "llvm/ADT/Optional.h"
20+
#include "llvm/ADT/StringRef.h"
1821
#include <memory>
1922
#include <vector>
2023
#include <assert.h>
@@ -24,9 +27,15 @@ namespace clang {
2427
class LangOptions;
2528
class StoredDiagnostic;
2629
class CXDiagnosticImpl;
27-
30+
2831
class CXDiagnosticSetImpl {
32+
struct CXSourceFileContents {
33+
StringRef Contents;
34+
CXSourceRange OriginalSourceRange;
35+
};
36+
2937
std::vector<std::unique_ptr<CXDiagnosticImpl>> Diagnostics;
38+
llvm::DenseMap<CXFile, CXSourceFileContents> FileContents;
3039
const bool IsExternallyManaged;
3140
public:
3241
CXDiagnosticSetImpl(bool isManaged = false)
@@ -45,6 +54,19 @@ class CXDiagnosticSetImpl {
4554

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

57+
void recordSourceFileContents(
58+
CXFile file, StringRef contents, CXSourceRange originalSourceRange);
59+
60+
Optional<StringRef> getSourceFileContents(
61+
CXFile file, CXSourceRange &originalSourceRange) {
62+
auto found = FileContents.find(file);
63+
if (found == FileContents.end())
64+
return None;
65+
66+
originalSourceRange = found->second.OriginalSourceRange;
67+
return found->second.Contents;
68+
}
69+
4870
bool empty() const {
4971
return Diagnostics.empty();
5072
}

clang/tools/libclang/CXLoadedDiagnostic.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,12 @@ class DiagLoader : serialized_diags::SerializedDiagnosticReader {
226226
unsigned Timestamp,
227227
StringRef Name) override;
228228

229+
std::error_code visitSourceFileContentsRecord(
230+
unsigned ID,
231+
const serialized_diags::Location &OriginalStartLoc,
232+
const serialized_diags::Location &OriginalEndLoc,
233+
StringRef Contents) override;
234+
229235
std::error_code visitFixitRecord(const serialized_diags::Location &Start,
230236
const serialized_diags::Location &End,
231237
StringRef CodeToInsert) override;
@@ -366,6 +372,28 @@ std::error_code DiagLoader::visitFilenameRecord(unsigned ID, unsigned Size,
366372
return std::error_code();
367373
}
368374

375+
std::error_code DiagLoader::visitSourceFileContentsRecord(
376+
unsigned ID,
377+
const serialized_diags::Location &OriginalStartLoc,
378+
const serialized_diags::Location &OriginalEndLoc,
379+
StringRef Contents
380+
) {
381+
CXSourceRange OriginalSourceRange;
382+
if (std::error_code EC = readRange(
383+
OriginalStartLoc, OriginalEndLoc, OriginalSourceRange))
384+
return EC;
385+
386+
auto file = const_cast<FileEntry *>(TopDiags->Files[ID]);
387+
if (!file)
388+
return reportInvalidFile("Source file contents for unknown file ID");
389+
390+
StringRef CopiedContents(TopDiags->copyString(Contents),
391+
Contents.size());
392+
393+
TopDiags->recordSourceFileContents(file, CopiedContents, OriginalSourceRange);
394+
return std::error_code();
395+
}
396+
369397
std::error_code
370398
DiagLoader::visitSourceRangeRecord(const serialized_diags::Location &Start,
371399
const serialized_diags::Location &End) {

clang/tools/libclang/libclang.map

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,8 @@ LLVM_16 {
519519
clang_CXXMethod_isCopyAssignmentOperator;
520520
clang_CXXMethod_isMoveAssignmentOperator;
521521
clang_createAPISet;
522+
clang_getDiagnosticFileContents;
523+
clang_getDiagnosticFileOriginalSourceRange;
522524
clang_disposeAPISet;
523525
clang_getSymbolGraphForCursor;
524526
clang_getSymbolGraphForUSR;

0 commit comments

Comments
 (0)