From 84ebafb8fe8d39bca75090248e6275468e899ca1 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Fri, 1 Sep 2023 16:32:51 -0700 Subject: [PATCH 1/7] Tweak grouped-diagnostics formatting to put the primary diagnostics up front One of the usability issues with the new grouped diagnostics code is that the actual error/warning/remark buried within the source code, with only a header like === t.swift:1 === to show where the issue occurs. Instead, display the diagnostic file:line:column and text right up front, the same way as the existing compiler's style, e.g., t.swift:5:3: error: no exact matches in call to global function 'f' The is better for humans, because it puts the primary issue right up front, and also better for tools that scrape logs to find the diagnostics using this form. --- .../DiagnosticsFormatter.swift | 24 ++++-------- .../SwiftDiagnostics/GroupedDiagnostics.swift | 38 ++++++++++++++++++- .../GroupDiagnosticsFormatterTests.swift | 10 ++--- 3 files changed, 48 insertions(+), 24 deletions(-) diff --git a/Sources/SwiftDiagnostics/DiagnosticsFormatter.swift b/Sources/SwiftDiagnostics/DiagnosticsFormatter.swift index 39b8f18c0b3..5bb4eaff397 100644 --- a/Sources/SwiftDiagnostics/DiagnosticsFormatter.swift +++ b/Sources/SwiftDiagnostics/DiagnosticsFormatter.swift @@ -176,20 +176,24 @@ public struct DiagnosticsFormatter { return resultSourceString } + struct PrimaryDiagnostic { + var location: SourceLocation + var diagnostic: Diagnostic + } + /// Print given diagnostics for a given syntax tree on the command line /// /// - Parameters: /// - suffixTexts: suffix text to be printed at the given absolute /// locations within the source file. func annotatedSource( - fileName: String?, tree: some SyntaxProtocol, diags: [Diagnostic], indentString: String, suffixTexts: [AbsolutePosition: String], sourceLocationConverter: SourceLocationConverter? = nil ) -> String { - let slc = sourceLocationConverter ?? SourceLocationConverter(fileName: fileName ?? "", tree: tree) + let slc = sourceLocationConverter ?? SourceLocationConverter(fileName: "", tree: tree) // First, we need to put each line and its diagnostics together var annotatedSourceLines = [AnnotatedSourceLine]() @@ -218,20 +222,9 @@ public struct DiagnosticsFormatter { return nil } + // Accumulate the fully annotated source files here. var annotatedSource = "" - // If there was a filename, add it first. - if let fileName { - let header = colorizeBufferOutline("===") - let firstLine = - 1 - + (annotatedSourceLines.enumerated().first { (lineIndex, sourceLine) in - !sourceLine.isFreeOfAnnotations - }?.offset ?? 0) - - annotatedSource.append("\(indentString)\(header) \(fileName):\(firstLine) \(header)\n") - } - /// Keep track if a line missing char should be printed var hasLineBeenSkipped = false @@ -318,7 +311,6 @@ public struct DiagnosticsFormatter { diags: [Diagnostic] ) -> String { return annotatedSource( - fileName: nil, tree: tree, diags: diags, indentString: "", @@ -328,7 +320,7 @@ public struct DiagnosticsFormatter { /// Annotates the given ``DiagnosticMessage`` with an appropriate ANSI color code (if the value of the `colorize` /// property is `true`) and returns the result as a printable string. - private func colorizeIfRequested(_ message: DiagnosticMessage) -> String { + func colorizeIfRequested(_ message: DiagnosticMessage) -> String { switch message.severity { case .error: let annotation = ANSIAnnotation(color: .red, trait: .bold) diff --git a/Sources/SwiftDiagnostics/GroupedDiagnostics.swift b/Sources/SwiftDiagnostics/GroupedDiagnostics.swift index afd36e26d9a..233e72a4e62 100644 --- a/Sources/SwiftDiagnostics/GroupedDiagnostics.swift +++ b/Sources/SwiftDiagnostics/GroupedDiagnostics.swift @@ -133,6 +133,31 @@ extension GroupedDiagnostics { } } + // Find the "primary" diagnostic that will be shown at the top of the diagnostic + // message. This is typically the error, warning, or remark. + private func findPrimaryDiagnostic(in sourceFile: SourceFile) -> (SourceFile, Diagnostic)? { + // If there is a non-note diagnostic, it's the primary diagnostic. + if let primaryDiag = sourceFile.diagnostics.first(where: { $0.diagMessage.severity != .note }) { + return (sourceFile, primaryDiag) + } + + // If one of our child source files has a primary diagnostic, return that. + for childID in sourceFile.children { + if let foundInChild = findPrimaryDiagnostic(in: sourceFiles[childID.id]) { + return foundInChild + } + } + + // If this is a root note, take the first note. + if sourceFile.parent == nil, + let note = sourceFile.diagnostics.first { + return (sourceFile, note) + } + + // There is no primary diagnostic. + return nil + } + /// Annotate the source for a given source file ID, embedding its child /// source files. func annotateSource( @@ -168,7 +193,17 @@ extension GroupedDiagnostics { let suffixString: String if isRoot { - prefixString = "" + // If there's a primary diagnostic, + if let (primaryDiagSourceFile, primaryDiag) = findPrimaryDiagnostic(in: sourceFile) { + let primaryDiagSLC = SourceLocationConverter(fileName: primaryDiagSourceFile.displayName, tree: primaryDiagSourceFile.tree) + let location = primaryDiag.location(converter: primaryDiagSLC) + + prefixString = "\(location.file):\(location.line):\(location.column): \(formatter.colorizeIfRequested(primaryDiag.diagMessage))\n" + } else { + let firstLine = sourceFile.diagnostics.first.map { $0.location(converter: slc).line } ?? 0 + prefixString = "\(sourceFile.displayName): \(firstLine):" + } + suffixString = "" } else { let padding = indentString.dropLast(1) @@ -190,7 +225,6 @@ extension GroupedDiagnostics { // Render the buffer. return prefixString + formatter.annotatedSource( - fileName: isRoot ? sourceFile.displayName : nil, tree: sourceFile.tree, diags: sourceFile.diagnostics, indentString: colorizeBufferOutline(indentString), diff --git a/Tests/SwiftDiagnosticsTest/GroupDiagnosticsFormatterTests.swift b/Tests/SwiftDiagnosticsTest/GroupDiagnosticsFormatterTests.swift index d1c8d99704b..779c8c64121 100644 --- a/Tests/SwiftDiagnosticsTest/GroupDiagnosticsFormatterTests.swift +++ b/Tests/SwiftDiagnosticsTest/GroupDiagnosticsFormatterTests.swift @@ -112,8 +112,7 @@ final class GroupedDiagnosticsFormatterTests: XCTestCase { assertStringsEqualWithDiff( annotated, """ - === main.swift:5 === - ┆ + main.swift:6:14: error: expected ')' to end function call 3 │ // test 4 │ let pi = 3.14159 5 │ #myAssert(pi == 3) @@ -141,7 +140,7 @@ final class GroupedDiagnosticsFormatterTests: XCTestCase { """ let pi = 3.14159 1️⃣#myAssert(pi == 3) - print("hello" + print("hello") """, displayName: "main.swift", extraDiagnostics: ["1️⃣": ("in expansion of macro 'myAssert' here", .note)] @@ -181,7 +180,7 @@ final class GroupedDiagnosticsFormatterTests: XCTestCase { assertStringsEqualWithDiff( annotated, """ - === main.swift:2 === + #invertedEqualityCheck:1:7: error: no matching operator '==' for types 'Double' and 'Int' 1 │ let pi = 3.14159 2 │ #myAssert(pi == 3) │ ╰─ note: in expansion of macro 'myAssert' here @@ -197,8 +196,7 @@ final class GroupedDiagnosticsFormatterTests: XCTestCase { │4 │ fatalError("assertion failed: pi != 3") │5 │ } ╰───────────────────────────────────────────────────────────────────── - 3 │ print("hello" - │ ╰─ error: expected ')' to end function call + 3 │ print("hello") """ ) From 39182b67002a6af345626fdcfc289f96fe0d71e9 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Fri, 1 Sep 2023 16:50:35 -0700 Subject: [PATCH 2/7] Also refer to the original source file when a diagnostic points into an expansion When the primary diagnostic comes from inside some kind of generated buffer, such as a macro expansion buffer, the file/line/column will point into a source file that might be temporary. In such cases, also add a link to the outermost, original source file, e.g., main.swift:2:1: note: expanded code originates here to help users and tools alike to find that original source file. --- .../DiagnosticsFormatter.swift | 11 +++++++--- .../SwiftDiagnostics/GroupedDiagnostics.swift | 22 +++++++++++++++++-- .../GroupDiagnosticsFormatterTests.swift | 1 + 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/Sources/SwiftDiagnostics/DiagnosticsFormatter.swift b/Sources/SwiftDiagnostics/DiagnosticsFormatter.swift index 5bb4eaff397..33f0727529a 100644 --- a/Sources/SwiftDiagnostics/DiagnosticsFormatter.swift +++ b/Sources/SwiftDiagnostics/DiagnosticsFormatter.swift @@ -332,12 +332,17 @@ public struct DiagnosticsFormatter { return prefix + colorizeIfRequested(message.message, annotation: color); case .note: - let color = ANSIAnnotation(color: .default, trait: .bold) - let prefix = colorizeIfRequested("note: ", annotation: color) - return prefix + message.message + return colorizeNoteIfRequested(message.message) } } + /// Annotate a note with an appropriate ANSI color code (if requested). + func colorizeNoteIfRequested(_ message: String) -> String { + let color = ANSIAnnotation(color: .default, trait: .bold) + let prefix = colorizeIfRequested("note: ", annotation: color) + return prefix + message + } + /// Apply the given color and trait to the specified text, when we are /// supposed to color the output. private func colorizeIfRequested( diff --git a/Sources/SwiftDiagnostics/GroupedDiagnostics.swift b/Sources/SwiftDiagnostics/GroupedDiagnostics.swift index 233e72a4e62..df91f51e87f 100644 --- a/Sources/SwiftDiagnostics/GroupedDiagnostics.swift +++ b/Sources/SwiftDiagnostics/GroupedDiagnostics.swift @@ -189,16 +189,34 @@ extension GroupedDiagnostics { // If this is a nested source file, draw a box around it. let isRoot = sourceFile.parent == nil - let prefixString: String + var prefixString: String let suffixString: String if isRoot { - // If there's a primary diagnostic, + // If there's a primary diagnostic, print it first. if let (primaryDiagSourceFile, primaryDiag) = findPrimaryDiagnostic(in: sourceFile) { let primaryDiagSLC = SourceLocationConverter(fileName: primaryDiagSourceFile.displayName, tree: primaryDiagSourceFile.tree) let location = primaryDiag.location(converter: primaryDiagSLC) + // Display file/line/column and diagnostic text for the primary diagnostic. prefixString = "\(location.file):\(location.line):\(location.column): \(formatter.colorizeIfRequested(primaryDiag.diagMessage))\n" + + // If the primary diagnostic source file is not the same as the root source file, we're pointing into a generated buffer. + // Provide a link back to the original source file where this generated buffer occurred, so it's easy to find if + // (for example) the generated buffer is no longer available. + if sourceFile.id != primaryDiagSourceFile.id, + var (rootSourceID, rootPosition) = primaryDiagSourceFile.parent { + // Go all the way up to the root to find the absolute position of the outermost generated buffer within the + // root source file. + while let parent = sourceFiles[rootSourceID.id].parent { + (rootSourceID, rootPosition) = parent + } + + if rootSourceID == sourceFileID { + let bufferLoc = slc.location(for: rootPosition) + prefixString += "╰─ \(bufferLoc.file):\(bufferLoc.line):\(bufferLoc.column): \(formatter.colorizeNoteIfRequested("expanded code originates here"))\n" + } + } } else { let firstLine = sourceFile.diagnostics.first.map { $0.location(converter: slc).line } ?? 0 prefixString = "\(sourceFile.displayName): \(firstLine):" diff --git a/Tests/SwiftDiagnosticsTest/GroupDiagnosticsFormatterTests.swift b/Tests/SwiftDiagnosticsTest/GroupDiagnosticsFormatterTests.swift index 779c8c64121..eccd50dc1fe 100644 --- a/Tests/SwiftDiagnosticsTest/GroupDiagnosticsFormatterTests.swift +++ b/Tests/SwiftDiagnosticsTest/GroupDiagnosticsFormatterTests.swift @@ -181,6 +181,7 @@ final class GroupedDiagnosticsFormatterTests: XCTestCase { annotated, """ #invertedEqualityCheck:1:7: error: no matching operator '==' for types 'Double' and 'Int' + ╰─ main.swift:2:1: note: expanded code originates here 1 │ let pi = 3.14159 2 │ #myAssert(pi == 3) │ ╰─ note: in expansion of macro 'myAssert' here From df54241a257b6c4be731bdcb43ab6cb222d0a1df Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Fri, 1 Sep 2023 17:07:37 -0700 Subject: [PATCH 3/7] Use bold without colors for diagnostic text Match the existing LLVM style used by the Swift compiler, where the diagnostic severity (warning, note, error) is colorized and bolded, but the diagnostic text is bolded but in the default color. Visually, this is less overwhelming, which is presumably why the compiler has been doing it. --- .../DiagnosticsFormatter.swift | 47 ++++++++++++++----- .../SwiftDiagnostics/GroupedDiagnostics.swift | 3 +- .../DiagnosticsFormatterTests.swift | 12 ++--- 3 files changed, 42 insertions(+), 20 deletions(-) diff --git a/Sources/SwiftDiagnostics/DiagnosticsFormatter.swift b/Sources/SwiftDiagnostics/DiagnosticsFormatter.swift index 33f0727529a..6b48d50d6e7 100644 --- a/Sources/SwiftDiagnostics/DiagnosticsFormatter.swift +++ b/Sources/SwiftDiagnostics/DiagnosticsFormatter.swift @@ -321,26 +321,31 @@ public struct DiagnosticsFormatter { /// Annotates the given ``DiagnosticMessage`` with an appropriate ANSI color code (if the value of the `colorize` /// property is `true`) and returns the result as a printable string. func colorizeIfRequested(_ message: DiagnosticMessage) -> String { - switch message.severity { + colorizeIfRequested(severity: message.severity, message: message.message) + } + + /// Annotates a diagnostic message with the given severity and text with an appropriate ANSI color code. + func colorizeIfRequested(severity: DiagnosticSeverity, message: String) -> String { + let severityText: String + let severityAnnotation: ANSIAnnotation + + switch severity { case .error: - let annotation = ANSIAnnotation(color: .red, trait: .bold) - return colorizeIfRequested("error: \(message.message)", annotation: annotation) + severityText = "error" + severityAnnotation = .errorText case .warning: - let color = ANSIAnnotation(color: .yellow) - let prefix = colorizeIfRequested("warning: ", annotation: color.withTrait(.bold)) + severityText = "warning" + severityAnnotation = .warningText - return prefix + colorizeIfRequested(message.message, annotation: color); case .note: - return colorizeNoteIfRequested(message.message) + severityText = "note" + severityAnnotation = .noteText } - } - /// Annotate a note with an appropriate ANSI color code (if requested). - func colorizeNoteIfRequested(_ message: String) -> String { - let color = ANSIAnnotation(color: .default, trait: .bold) - let prefix = colorizeIfRequested("note: ", annotation: color) - return prefix + message + let prefix = colorizeIfRequested("\(severityText): ", annotation: severityAnnotation) + + return prefix + colorizeIfRequested(message, annotation: .diagnosticText); } /// Apply the given color and trait to the specified text, when we are @@ -418,4 +423,20 @@ struct ANSIAnnotation { static var sourceHighlight: ANSIAnnotation { ANSIAnnotation(color: .default, trait: .underline) } + + static var diagnosticText: ANSIAnnotation { + ANSIAnnotation(color: .default, trait: .bold) + } + + static var errorText: ANSIAnnotation { + ANSIAnnotation(color: .red, trait: .bold) + } + + static var warningText: ANSIAnnotation { + ANSIAnnotation(color: .yellow, trait: .bold) + } + + static var noteText: ANSIAnnotation { + ANSIAnnotation(color: .default, trait: .bold) + } } diff --git a/Sources/SwiftDiagnostics/GroupedDiagnostics.swift b/Sources/SwiftDiagnostics/GroupedDiagnostics.swift index df91f51e87f..53c8fc0f8fe 100644 --- a/Sources/SwiftDiagnostics/GroupedDiagnostics.swift +++ b/Sources/SwiftDiagnostics/GroupedDiagnostics.swift @@ -214,7 +214,8 @@ extension GroupedDiagnostics { if rootSourceID == sourceFileID { let bufferLoc = slc.location(for: rootPosition) - prefixString += "╰─ \(bufferLoc.file):\(bufferLoc.line):\(bufferLoc.column): \(formatter.colorizeNoteIfRequested("expanded code originates here"))\n" + let coloredMessage = formatter.colorizeIfRequested(severity: .note, message: "expanded code originates here") + prefixString += "╰─ \(bufferLoc.file):\(bufferLoc.line):\(bufferLoc.column): \(coloredMessage)\n" } } } else { diff --git a/Tests/SwiftDiagnosticsTest/DiagnosticsFormatterTests.swift b/Tests/SwiftDiagnosticsTest/DiagnosticsFormatterTests.swift index e601a22afd1..d9846b9144f 100644 --- a/Tests/SwiftDiagnosticsTest/DiagnosticsFormatterTests.swift +++ b/Tests/SwiftDiagnosticsTest/DiagnosticsFormatterTests.swift @@ -101,7 +101,7 @@ final class DiagnosticsFormatterTests: XCTestCase { let expectedOutput = """ \u{001B}[0;36m1 │\u{001B}[0;0m var foo = bar + - \u{001B}[0;36m│\u{001B}[0;0m ╰─ \u{001B}[1;31merror: expected expression after operator\u{001B}[0;0m + \u{001B}[0;36m│\u{001B}[0;0m ╰─ \u{001B}[1;31merror: \u{001B}[0;0m\u{001B}[1;39mexpected expression after operator\u{001B}[0;0m """ assertStringsEqualWithDiff(annotate(source: source, colorize: true), expectedOutput) @@ -113,9 +113,9 @@ final class DiagnosticsFormatterTests: XCTestCase { """ let expectedOutput = """ \u{001B}[0;36m1 │\u{001B}[0;0m foo.[].[].[] - \u{001B}[0;36m│\u{001B}[0;0m │ │ ╰─ \u{001B}[1;31merror: expected name in member access\u{001B}[0;0m - \u{001B}[0;36m│\u{001B}[0;0m │ ╰─ \u{001B}[1;31merror: expected name in member access\u{001B}[0;0m - \u{001B}[0;36m│\u{001B}[0;0m ╰─ \u{001B}[1;31merror: expected name in member access\u{001B}[0;0m + \u{001B}[0;36m│\u{001B}[0;0m │ │ ╰─ \u{001B}[1;31merror: \u{001B}[0;0m\u{001B}[1;39mexpected name in member access\u{001B}[0;0m + \u{001B}[0;36m│\u{001B}[0;0m │ ╰─ \u{001B}[1;31merror: \u{001B}[0;0m\u{001B}[1;39mexpected name in member access\u{001B}[0;0m + \u{001B}[0;36m│\u{001B}[0;0m ╰─ \u{001B}[1;31merror: \u{001B}[0;0m\u{001B}[1;39mexpected name in member access\u{001B}[0;0m """ assertStringsEqualWithDiff(annotate(source: source, colorize: true), expectedOutput) @@ -128,8 +128,8 @@ final class DiagnosticsFormatterTests: XCTestCase { let expectedOutput = """ \u{001B}[0;36m1 │\u{001B}[0;0m for \u{001B}[4;39m(i\u{001B}[0;0m \u{001B}[4;39m= 🐮; i != 👩‍👩‍👦‍👦; i += 1)\u{001B}[0;0m { } - \u{001B}[0;36m│\u{001B}[0;0m │ ╰─ \u{001B}[1;31merror: expected ')' to end tuple pattern\u{001B}[0;0m - \u{001B}[0;36m│\u{001B}[0;0m ╰─ \u{001B}[1;31merror: C-style for statement has been removed in Swift 3\u{001B}[0;0m + \u{001B}[0;36m│\u{001B}[0;0m │ ╰─ \u{001B}[1;31merror: \u{001B}[0;0m\u{001B}[1;39mexpected ')' to end tuple pattern\u{001B}[0;0m + \u{001B}[0;36m│\u{001B}[0;0m ╰─ \u{001B}[1;31merror: \u{001B}[0;0m\u{001B}[1;39mC-style for statement has been removed in Swift 3\u{001B}[0;0m """ From 34c4d18ddea3cfc413fc3c998c93620483844d30 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Fri, 1 Sep 2023 17:19:21 -0700 Subject: [PATCH 4/7] Fix formatting --- Sources/SwiftDiagnostics/GroupedDiagnostics.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Sources/SwiftDiagnostics/GroupedDiagnostics.swift b/Sources/SwiftDiagnostics/GroupedDiagnostics.swift index 53c8fc0f8fe..f0581d2e967 100644 --- a/Sources/SwiftDiagnostics/GroupedDiagnostics.swift +++ b/Sources/SwiftDiagnostics/GroupedDiagnostics.swift @@ -150,7 +150,8 @@ extension GroupedDiagnostics { // If this is a root note, take the first note. if sourceFile.parent == nil, - let note = sourceFile.diagnostics.first { + let note = sourceFile.diagnostics.first + { return (sourceFile, note) } @@ -205,7 +206,8 @@ extension GroupedDiagnostics { // Provide a link back to the original source file where this generated buffer occurred, so it's easy to find if // (for example) the generated buffer is no longer available. if sourceFile.id != primaryDiagSourceFile.id, - var (rootSourceID, rootPosition) = primaryDiagSourceFile.parent { + var (rootSourceID, rootPosition) = primaryDiagSourceFile.parent + { // Go all the way up to the root to find the absolute position of the outermost generated buffer within the // root source file. while let parent = sourceFiles[rootSourceID.id].parent { From c721e71c68a4e0d535f80bc6880fabfab921a7fe Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Fri, 1 Sep 2023 17:34:33 -0700 Subject: [PATCH 5/7] Add "remark" diagnostics The Swift compiler (and most LLVM-based tools) have a "remark" diagnostic severity. Add support for it into DiagnosticSeverity. --- .../SwiftCompilerPluginMessageHandling/Diagnostics.swift | 1 + .../PluginMessages.swift | 1 + Sources/SwiftDiagnostics/DiagnosticsFormatter.swift | 8 ++++++++ Sources/SwiftDiagnostics/Message.swift | 1 + 4 files changed, 11 insertions(+) diff --git a/Sources/SwiftCompilerPluginMessageHandling/Diagnostics.swift b/Sources/SwiftCompilerPluginMessageHandling/Diagnostics.swift index a00f1d2e7b2..0e00dcfc60c 100644 --- a/Sources/SwiftCompilerPluginMessageHandling/Diagnostics.swift +++ b/Sources/SwiftCompilerPluginMessageHandling/Diagnostics.swift @@ -53,6 +53,7 @@ extension PluginMessage.Diagnostic.Severity { case .error: self = .error case .warning: self = .warning case .note: self = .note + case .remark: self = .remark } } } diff --git a/Sources/SwiftCompilerPluginMessageHandling/PluginMessages.swift b/Sources/SwiftCompilerPluginMessageHandling/PluginMessages.swift index 6b6a0c618fe..3f20f66d50a 100644 --- a/Sources/SwiftCompilerPluginMessageHandling/PluginMessages.swift +++ b/Sources/SwiftCompilerPluginMessageHandling/PluginMessages.swift @@ -155,6 +155,7 @@ public enum PluginMessage { case error case warning case note + case remark } public struct Position: Codable { public var fileName: String diff --git a/Sources/SwiftDiagnostics/DiagnosticsFormatter.swift b/Sources/SwiftDiagnostics/DiagnosticsFormatter.swift index 6b48d50d6e7..6f25a237108 100644 --- a/Sources/SwiftDiagnostics/DiagnosticsFormatter.swift +++ b/Sources/SwiftDiagnostics/DiagnosticsFormatter.swift @@ -341,6 +341,10 @@ public struct DiagnosticsFormatter { case .note: severityText = "note" severityAnnotation = .noteText + + case .remark: + severityText = "remark" + severityAnnotation = .remarkText } let prefix = colorizeIfRequested("\(severityText): ", annotation: severityAnnotation) @@ -439,4 +443,8 @@ struct ANSIAnnotation { static var noteText: ANSIAnnotation { ANSIAnnotation(color: .default, trait: .bold) } + + static var remarkText: ANSIAnnotation { + ANSIAnnotation(color: .blue, trait: .bold) + } } diff --git a/Sources/SwiftDiagnostics/Message.swift b/Sources/SwiftDiagnostics/Message.swift index dba55df09ba..6ee0decf630 100644 --- a/Sources/SwiftDiagnostics/Message.swift +++ b/Sources/SwiftDiagnostics/Message.swift @@ -30,6 +30,7 @@ public enum DiagnosticSeverity { case error case warning case note + case remark } /// Types conforming to this protocol represent diagnostic messages that can be From fa397fe085512de282fa668e9126a9dd2ce1f6ec Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 4 Sep 2023 21:54:55 -0700 Subject: [PATCH 6/7] Add release note for the addition of the `remark` diagnostic severity --- Release Notes/510.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Release Notes/510.md b/Release Notes/510.md index a3c1a6f9b55..b181c2721f5 100644 --- a/Release Notes/510.md +++ b/Release Notes/510.md @@ -9,6 +9,10 @@ - Description: Returns the index of the n-th element in a `SyntaxCollection`. This computation is in O(n) and `SyntaxCollection` is not subscriptable by an integer. - Pull Request: https://github.com/apple/swift-syntax/pull/2014 +- `DiagnosticSeverity` and `PluginMessage.Diagnostic.Severity` now have new case named `remark` + - Description: Remarks are used by the Swift compiler and other tools to describe some aspect of translation that doesn't reflect correctness, but may be useful for the user. Remarks have been added to the diagnostic severity enums to align with the Swift compiler. + - Pull Request: https://github.com/apple/swift-syntax/pull/2143 + ## API Behavior Changes ## Deprecations From 9ee9ac3018d9330543fbcc31f5b903891bddf827 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 4 Sep 2023 21:56:26 -0700 Subject: [PATCH 7/7] Remove unnused `PrimaryDiagnostic` struct. --- Sources/SwiftDiagnostics/DiagnosticsFormatter.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Sources/SwiftDiagnostics/DiagnosticsFormatter.swift b/Sources/SwiftDiagnostics/DiagnosticsFormatter.swift index 6f25a237108..d77327c6946 100644 --- a/Sources/SwiftDiagnostics/DiagnosticsFormatter.swift +++ b/Sources/SwiftDiagnostics/DiagnosticsFormatter.swift @@ -176,11 +176,6 @@ public struct DiagnosticsFormatter { return resultSourceString } - struct PrimaryDiagnostic { - var location: SourceLocation - var diagnostic: Diagnostic - } - /// Print given diagnostics for a given syntax tree on the command line /// /// - Parameters: