Skip to content

[6.2] [Diagnostics] Use the swift-syntax formatting for invalid source locations, too #80988

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
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
4 changes: 4 additions & 0 deletions include/swift/AST/DiagnosticBridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ class DiagnosticBridge {
void enqueueDiagnostic(SourceManager &SM, const DiagnosticInfo &Info,
unsigned innermostBufferID);

/// Emit a single diagnostic without location information.
void emitDiagnosticWithoutLocation(
const DiagnosticInfo &Info, llvm::raw_ostream &out, bool forceColors);

/// Flush all enqueued diagnostics.
void flush(llvm::raw_ostream &OS, bool includeTrailingBreak,
bool forceColors);
Expand Down
8 changes: 8 additions & 0 deletions include/swift/Bridging/ASTGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ void swift_ASTGen_addQueuedDiagnostic(
const BridgedCharSourceRange *_Nullable highlightRanges,
ptrdiff_t numHighlightRanges,
BridgedArrayRef /*BridgedFixIt*/ fixIts);
void swift_ASTGen_renderSingleDiagnostic(
void *_Nonnull state,
BridgedStringRef text,
BridgedDiagnosticSeverity severity,
BridgedStringRef categoryName,
BridgedStringRef documentationPath,
ssize_t colorize,
BridgedStringRef *_Nonnull renderedString);
void swift_ASTGen_renderQueuedDiagnostics(
void *_Nonnull queued, ssize_t contextSize, ssize_t colorize,
BridgedStringRef *_Nonnull renderedString);
Expand Down
68 changes: 50 additions & 18 deletions lib/AST/DiagnosticBridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,22 @@
using namespace swift;

#if SWIFT_BUILD_SWIFT_SYNTAX
static BridgedDiagnosticSeverity bridgeDiagnosticSeverity(DiagnosticKind kind) {
switch (kind) {
case DiagnosticKind::Error:
return BridgedDiagnosticSeverity::BridgedError;

case DiagnosticKind::Warning:
return BridgedDiagnosticSeverity::BridgedWarning;

case DiagnosticKind::Remark:
return BridgedDiagnosticSeverity::BridgedRemark;

case DiagnosticKind::Note:
return BridgedDiagnosticSeverity::BridgedNote;
}
}

/// Enqueue a diagnostic with ASTGen's diagnostic rendering.
static void addQueueDiagnostic(void *queuedDiagnostics,
void *perFrontendState,
Expand All @@ -37,24 +53,7 @@ static void addQueueDiagnostic(void *queuedDiagnostics,
info.FormatArgs);
}

BridgedDiagnosticSeverity severity;
switch (info.Kind) {
case DiagnosticKind::Error:
severity = BridgedDiagnosticSeverity::BridgedError;
break;

case DiagnosticKind::Warning:
severity = BridgedDiagnosticSeverity::BridgedWarning;
break;

case DiagnosticKind::Remark:
severity = BridgedDiagnosticSeverity::BridgedRemark;
break;

case DiagnosticKind::Note:
severity = BridgedDiagnosticSeverity::BridgedNote;
break;
}
BridgedDiagnosticSeverity severity = bridgeDiagnosticSeverity(info.Kind);

// Map the highlight ranges.
SmallVector<BridgedCharSourceRange, 2> highlightRanges;
Expand Down Expand Up @@ -87,6 +86,39 @@ static void addQueueDiagnostic(void *queuedDiagnostics,
}
}

void DiagnosticBridge::emitDiagnosticWithoutLocation(
const DiagnosticInfo &info, llvm::raw_ostream &out, bool forceColors) {
ASSERT(queuedDiagnostics == nullptr);

// If we didn't have per-frontend state before, create it now.
if (!perFrontendState) {
perFrontendState = swift_ASTGen_createPerFrontendDiagnosticState();
}

llvm::SmallString<256> text;
{
llvm::raw_svector_ostream out(text);
DiagnosticEngine::formatDiagnosticText(out, info.FormatString,
info.FormatArgs);
}

BridgedDiagnosticSeverity severity = bridgeDiagnosticSeverity(info.Kind);

BridgedStringRef bridgedRenderedString{nullptr, 0};
swift_ASTGen_renderSingleDiagnostic(
perFrontendState, text.str(), severity, info.Category,
llvm::StringRef(info.CategoryDocumentationURL), forceColors ? 1 : 0,
&bridgedRenderedString);

auto renderedString = bridgedRenderedString.unbridged();
if (renderedString.data()) {
out << "<unknown>:0: ";
out.write(renderedString.data(), renderedString.size());
swift_ASTGen_freeBridgedString(renderedString);
out << "\n";
}
}

void DiagnosticBridge::enqueueDiagnostic(SourceManager &SM,
const DiagnosticInfo &Info,
unsigned innermostBufferID) {
Expand Down
54 changes: 54 additions & 0 deletions lib/ASTGen/Sources/ASTGen/DiagnosticsBridge.swift
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,60 @@ public func addQueuedDiagnostic(
queuedDiagnostics.pointee.grouped.addDiagnostic(diagnostic)
}

/// Render a single diagnostic that has no source location information.
@_cdecl("swift_ASTGen_renderSingleDiagnostic")
public func renderSingleDiagnostic(
perFrontendDiagnosticStatePtr: UnsafeMutableRawPointer,
text: BridgedStringRef,
severity: BridgedDiagnosticSeverity,
categoryName: BridgedStringRef,
documentationPath: BridgedStringRef,
colorize: Int,
renderedStringOutPtr: UnsafeMutablePointer<BridgedStringRef>
) {
let diagnosticState = perFrontendDiagnosticStatePtr.assumingMemoryBound(
to: PerFrontendDiagnosticState.self
)

let documentationPath = String(bridged: documentationPath)
let documentationURL: String? = if !documentationPath.isEmpty {
// If this looks doesn't look like a URL, prepend file://.
documentationPath.looksLikeURL ? documentationPath : "file://\(documentationPath)"
} else {
nil
}

let categoryName = String(bridged: categoryName)
// If the data comes from serialized diagnostics, it's possible that
// the category name is empty because StringRef() is serialized into
// an empty string.
let category: DiagnosticCategory? = if !categoryName.isEmpty {
DiagnosticCategory(
name: categoryName,
documentationURL: documentationURL
)
} else {
nil
}

// Note that we referenced this category.
if let category {
diagnosticState.pointee.referencedCategories.insert(category)
}

let formatter = DiagnosticsFormatter(colorize: colorize != 0)

let renderedStr = formatter.formattedMessage(
SimpleDiagnostic(
message: String(bridged: text),
severity: severity.asSeverity,
category: category
)
)

renderedStringOutPtr.pointee = allocateBridgedString(renderedStr)
}

/// Render the queued diagnostics into a UTF-8 string.
@_cdecl("swift_ASTGen_renderQueuedDiagnostics")
public func renderQueuedDiagnostics(
Expand Down
22 changes: 12 additions & 10 deletions lib/Frontend/PrintingDiagnosticConsumer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,20 @@ void PrintingDiagnosticConsumer::handleDiagnostic(SourceManager &SM,
#if SWIFT_BUILD_SWIFT_SYNTAX
// Use the swift-syntax formatter.
auto bufferStack = DiagnosticBridge::getSourceBufferStack(SM, Info.Loc);
if (!bufferStack.empty()) {
if (Info.Kind != DiagnosticKind::Note)
DiagBridge.flush(Stream, /*includeTrailingBreak=*/true,
/*forceColors=*/ForceColors);
if (Info.Kind != DiagnosticKind::Note || bufferStack.empty())
DiagBridge.flush(Stream, /*includeTrailingBreak=*/true,
/*forceColors=*/ForceColors);

if (bufferStack.empty()) {
DiagBridge.emitDiagnosticWithoutLocation(Info, Stream, ForceColors);
} else {
DiagBridge.enqueueDiagnostic(SM, Info, bufferStack.front());
break;
}
#endif

return;
#else
// Fall through when we don't have the new diagnostics renderer available.
// This also happens if the location of the diagnostic is invalid, because
// the new rendered cannot cope with that.
LLVM_FALLTHROUGH;
#endif
}

case DiagnosticOptions::FormattingStyle::LLVM:
Expand Down Expand Up @@ -215,4 +215,6 @@ PrintingDiagnosticConsumer::PrintingDiagnosticConsumer(
llvm::raw_ostream &stream)
: Stream(stream) {}

PrintingDiagnosticConsumer::~PrintingDiagnosticConsumer() {}
PrintingDiagnosticConsumer::~PrintingDiagnosticConsumer() {
flush();
}