Skip to content

[Diagnostics] Emit generated code buffers into diagnostic files. #62861

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
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
66 changes: 57 additions & 9 deletions lib/Frontend/SerializedDiagnosticConsumer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,9 @@ class SerializedDiagnosticConsumer : public DiagnosticConsumer {
}

// Record identifier for the file.
unsigned getEmitFile(StringRef Filename);
unsigned getEmitFile(
SourceManager &SM, StringRef Filename, unsigned bufferID
);

// Record identifier for the category.
unsigned getEmitCategory(StringRef Category);
Expand Down Expand Up @@ -217,18 +219,21 @@ namespace serialized_diagnostics {
} // namespace serialized_diagnostics
} // namespace swift

unsigned SerializedDiagnosticConsumer::getEmitFile(StringRef Filename) {
unsigned SerializedDiagnosticConsumer::getEmitFile(
SourceManager &SM, StringRef Filename, unsigned bufferID
) {
// NOTE: Using Filename.data() here relies on SourceMgr using
// const char* as buffer identifiers. This is fast, but may
// be brittle. We can always switch over to using a StringMap.
unsigned &entry = State->Files[Filename.data()];
if (entry)
return entry;
unsigned &existingEntry = State->Files[Filename.data()];
if (existingEntry)
return existingEntry;

// Lazily generate the record for the file. Note that in
// practice we only expect there to be one file, but this is
// general and is what the diagnostic file expects.
entry = State->Files.size();
unsigned entry = State->Files.size();
existingEntry = entry;
RecordData Record;
Record.push_back(RECORD_FILENAME);
Record.push_back(entry);
Expand All @@ -238,6 +243,37 @@ unsigned SerializedDiagnosticConsumer::getEmitFile(StringRef Filename) {
State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_FILENAME),
Record, Filename.data());

// If the buffer contains code that was synthesized by the compiler,
// emit the contents of the buffer.
auto generatedInfo = SM.getGeneratedSourceInfo(bufferID);
if (!generatedInfo)
return entry;

Record.clear();
Record.push_back(RECORD_SOURCE_FILE_CONTENTS);
Record.push_back(entry);

// The source range that this buffer was generated from, expressed as
// offsets into the original buffer.
if (generatedInfo->originalSourceRange.isValid()) {
auto originalFilename = SM.getDisplayNameForLoc(generatedInfo->originalSourceRange.Start);
addRangeToRecord(
Lexer::getCharSourceRangeFromSourceRange(
SM, generatedInfo->originalSourceRange),
SM, originalFilename, Record
);
} else {
addLocToRecord(SourceLoc(), SM, "", Record); // Start
addLocToRecord(SourceLoc(), SM, "", Record); // End
}

// Contents of the buffer.
auto sourceText = SM.getEntireTextForBuffer(bufferID);
Record.push_back(sourceText.size());
State->Stream.EmitRecordWithBlob(
State->Abbrevs.get(RECORD_SOURCE_FILE_CONTENTS),
Record, sourceText);

return entry;
}

Expand Down Expand Up @@ -275,7 +311,7 @@ void SerializedDiagnosticConsumer::addLocToRecord(SourceLoc Loc,
unsigned line, col;
std::tie(line, col) = SM.getPresumedLineAndColumnForLoc(Loc);

Record.push_back(getEmitFile(Filename));
Record.push_back(getEmitFile(SM, Filename, bufferId));
Record.push_back(line);
Record.push_back(col);
Record.push_back(SM.getLocOffsetInBuffer(Loc, bufferId));
Expand Down Expand Up @@ -368,7 +404,7 @@ static void emitRecordID(unsigned ID, const char *Name,
static void
addSourceLocationAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> Abbrev) {
using namespace llvm;
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // File ID.
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 5)); // File ID.
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Line.
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Column.
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Offset;
Expand Down Expand Up @@ -411,6 +447,8 @@ void SerializedDiagnosticConsumer::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 @@ -450,7 +488,7 @@ void SerializedDiagnosticConsumer::emitBlockInfoBlock() {
// Emit the abbreviation for RECORD_FILENAME.
Abbrev = std::make_shared<BitCodeAbbrev>();
Abbrev->Add(BitCodeAbbrevOp(RECORD_FILENAME));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10)); // Mapped file ID.
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 5)); // Mapped file ID.
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Size.
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Modification time.
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Text size.
Expand All @@ -467,6 +505,16 @@ void SerializedDiagnosticConsumer::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::VBR, 5)); // File ID.
addRangeLocationAbbrev(Abbrev);
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 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
12 changes: 12 additions & 0 deletions test/Macros/macro_expand.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
// RUN: %empty-directory(%t)
// RUN: %target-build-swift -I %swift-host-lib-dir -L %swift-host-lib-dir -emit-library -o %t/%target-library-name(MacroDefinition) -module-name=MacroDefinition %S/Inputs/syntax_macro_definitions.swift -g -no-toolchain-stdlib-rpath
// RUNx: %target-swift-frontend -dump-ast -enable-experimental-feature Macros -enable-experimental-feature Macros -load-plugin-library %t/%target-library-name(MacroDefinition) -I %swift-host-lib-dir %s -module-name MacroUser 2>&1 | %FileCheck --check-prefix CHECK-AST %s

// Diagnostics testing
// RUN: %target-typecheck-verify-swift -enable-experimental-feature Macros -load-plugin-library %t/%target-library-name(MacroDefinition) -I %swift-host-lib-dir -module-name MacroUser -DTEST_DIAGNOSTICS

// RUN: not %target-swift-frontend -typecheck -enable-experimental-feature Macros -load-plugin-library %t/%target-library-name(MacroDefinition) -I %swift-host-lib-dir -module-name MacroUser -DTEST_DIAGNOSTICS -serialize-diagnostics-path %t/macro_expand.dia %s
// RUN: c-index-test -read-diagnostics %t/macro_expand.dia 2>&1 | %FileCheck -check-prefix CHECK-DIAGS %s

// Execution testing
// RUN: %target-build-swift -enable-experimental-feature Macros -enable-experimental-feature Macros -load-plugin-library %t/%target-library-name(MacroDefinition) -I %swift-host-lib-dir -L %swift-host-lib-dir %s -o %t/main -module-name MacroUser
// RUN: %target-run %t/main | %FileCheck %s
// REQUIRES: executable_test
Expand Down Expand Up @@ -75,6 +82,11 @@ func testAddBlocker(a: Int, b: Int, c: Int, oa: OnlyAdds) {
// expected-note@-1{{in expansion of macro 'addBlocker' here}}
// expected-note@-2{{use '-'}}{{22-23=-}}

// CHECK-DIAGS: macro_expand.swift:81:7-81:27:1:4: error: binary operator '-' cannot be applied to two 'OnlyAdds' operands [] []
// CHECK-DIAGS: CONTENTS OF FILE{{.*}}addBlocker
// CHECK-DIAGS-NEXT: Original source range: {{.*}}macro_expand.swift:81:7 - {{.*}}macro_expand.swift:81:27
// CHECK-DIAGS-NEXT: oa - oa
// CHECK-DIAGS-NEXT: END CONTENTS OF FILE
// Check recursion.
#recurse(false) // okay
#recurse(true) // expected-note{{in expansion of macro 'recurse' here}}
Expand Down