Skip to content
Open
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
25 changes: 23 additions & 2 deletions Sources/SwiftDiagnostics/GroupedDiagnostics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -260,11 +260,16 @@ extension GroupedDiagnostics {
) + boxSuffix + "\n"
}

// Render the buffer.
// Render the buffer, expanding each diagnostic's attached notes into
// note-severity diagnostics so the formatter lays them out too.
let diagnostics = sourceFile.diagnostics.flatMap { diagnostic in
[diagnostic] + diagnostic.notes.map(\.asDiagnostic)
}

return prefixString
+ formatter.annotatedSource(
tree: sourceFile.tree,
diags: sourceFile.diagnostics,
diags: diagnostics,
indentString: diagnosticDecorator.decorateBufferOutline(indentString),
suffixTexts: childSources,
sourceLocationConverter: slc
Expand All @@ -289,3 +294,19 @@ extension DiagnosticsFormatter {
return formatter.annotateSources(in: group)
}
}

/// Renders a ``NoteMessage`` as a `.note`-severity ``DiagnosticMessage`` so that
/// notes can be laid out by ``DiagnosticsFormatter`` alongside their diagnostic.
private struct NoteAsDiagnosticMessage: DiagnosticMessage {
let noteMessage: NoteMessage
var message: String { noteMessage.message }
var diagnosticID: MessageID { noteMessage.noteID }
var severity: DiagnosticSeverity { .note }
}

extension Note {
/// This note expressed as a `.note`-severity diagnostic anchored at its own location.
fileprivate var asDiagnostic: Diagnostic {
Diagnostic(node: node, position: position, message: NoteAsDiagnosticMessage(noteMessage: noteMessage))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,43 @@ final class GroupedDiagnosticsFormatterTests: XCTestCase {
)
}

func testAttachedNotesAreRendered() {
var group = GroupedDiagnostics()

_ = group.addTestFile(
"""
let 1️⃣value = 2️⃣undefined
""",
displayName: "test.swift",
diagnosticDescriptors: [
DiagnosticDescriptor(
locationMarker: "2️⃣",
message: "cannot find 'undefined' in scope",
severity: .error,
noteDescriptors: [
NoteDescriptor(
locationMarker: "1️⃣",
id: MessageID(domain: "test", id: "note"),
message: "'value' declared here"
)
]
)
]
)

let annotated = DiagnosticsFormatter.annotateSources(in: group)
assertStringsEqualWithDiff(
annotated,
"""
test.swift:1:13: error: cannot find 'undefined' in scope
1 | let value = undefined
| | `- error: cannot find 'undefined' in scope
| `- note: 'value' declared here

"""
)
}

func testGroupingForMacroExpansion() {
var group = GroupedDiagnostics()

Expand Down Expand Up @@ -147,7 +184,8 @@ final class GroupedDiagnosticsFormatterTests: XCTestCase {
|5 | }
+---------------------------------------------------------------------
6 | print("hello"
| `- error: expected ')' to end function call
| | `- error: expected ')' to end function call
| `- note: to match this opening '('

"""
)
Expand Down