From d0a8c513c5b8860505e8da6c0c508eb4d8828cef Mon Sep 17 00:00:00 2001 From: Joe Newton Date: Tue, 14 Nov 2023 17:10:02 -0500 Subject: [PATCH] Fixed up two issues that were discovered (#12) * Fixed up two issues that were discovered 1. When a diagnostic has multiple fix its the annotated string didn't insert newlines between fix-its 2. When a syntax has the same node offset as one of its children, replacing the child with a fix-it would *always* replace the outermost node * Fixed up formatting * Updates per code review suggestions * Additional updates per code review suggestions --- .../DiagnosticsFormatter.swift | 4 +- ...iagnosticsAndFixitsEmitterMacroTests.swift | 42 +++++++++++++++ .../DiagnosticsAndFixitsEmitterMacro.swift | 51 +++++++++++++++++++ 3 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 Tests/MacroTestingTests/DiagnosticsAndFixitsEmitterMacroTests.swift create mode 100644 Tests/MacroTestingTests/MacroExamples/DiagnosticsAndFixitsEmitterMacro.swift diff --git a/Sources/MacroTesting/SwiftDiagnostics/DiagnosticsFormatter.swift b/Sources/MacroTesting/SwiftDiagnostics/DiagnosticsFormatter.swift index be2b7a6..99b88e3 100644 --- a/Sources/MacroTesting/SwiftDiagnostics/DiagnosticsFormatter.swift +++ b/Sources/MacroTesting/SwiftDiagnostics/DiagnosticsFormatter.swift @@ -324,12 +324,12 @@ struct DiagnosticsFormatter { for diag in diags.dropLast(1) { annotatedSource.append("\(preMessage)├─ \(colorizeIfRequested(diag.diagMessage))\n") for fixIt in diag.fixIts { - annotatedSource.append("\(preMessage)│ ✏️ \(fixIt.message.message)") + annotatedSource.append("\(preMessage)│ ✏️ \(fixIt.message.message)\n") } } annotatedSource.append("\(preMessage)╰─ \(colorizeIfRequested(diags.last!.diagMessage))\n") for fixIt in diags.last!.fixIts { - annotatedSource.append("\(preMessage) ✏️ \(fixIt.message.message)") + annotatedSource.append("\(preMessage) ✏️ \(fixIt.message.message)\n") } } diff --git a/Tests/MacroTestingTests/DiagnosticsAndFixitsEmitterMacroTests.swift b/Tests/MacroTestingTests/DiagnosticsAndFixitsEmitterMacroTests.swift new file mode 100644 index 0000000..bc67c36 --- /dev/null +++ b/Tests/MacroTestingTests/DiagnosticsAndFixitsEmitterMacroTests.swift @@ -0,0 +1,42 @@ +import MacroTesting +import XCTest + +final class DiagnosticsAndFixitsEmitterMacroTests: BaseTestCase { + override func invokeTest() { + withMacroTesting(macros: [DiagnosticsAndFixitsEmitterMacro.self]) { + super.invokeTest() + } + } + + func testExpansionEmitsDiagnosticsAndFixits() { + assertMacro { + """ + @DiagnosticsAndFixitsEmitter + struct FooBar { + let foo: Foo + let bar: Bar + } + """ + } diagnostics: { + """ + @DiagnosticsAndFixitsEmitter + ┬────────────────────────── + ├─ ⚠️ This is the first diagnostic. + │ ✏️ This is the first fix-it. + │ ✏️ This is the second fix-it. + ╰─ ℹ️ This is the second diagnostic, it's a note. + struct FooBar { + let foo: Foo + let bar: Bar + } + """ + } expansion: { + """ + struct FooBar { + let foo: Foo + let bar: Bar + } + """ + } + } +} diff --git a/Tests/MacroTestingTests/MacroExamples/DiagnosticsAndFixitsEmitterMacro.swift b/Tests/MacroTestingTests/MacroExamples/DiagnosticsAndFixitsEmitterMacro.swift new file mode 100644 index 0000000..6bf47f7 --- /dev/null +++ b/Tests/MacroTestingTests/MacroExamples/DiagnosticsAndFixitsEmitterMacro.swift @@ -0,0 +1,51 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import SwiftSyntax +import SwiftSyntaxBuilder +import SwiftSyntaxMacros +import SwiftDiagnostics + +/// Emits two diagnostics, the first of which is a warning and has two fix-its, and +/// the second is a note and has no fix-its. +public enum DiagnosticsAndFixitsEmitterMacro: MemberMacro { + public static func expansion( + of node: AttributeSyntax, + providingMembersOf declaration: some DeclGroupSyntax, + in context: some MacroExpansionContext + ) throws -> [DeclSyntax] { + let firstFixIt = FixIt(message: SimpleDiagnosticMessage(message: "This is the first fix-it.", + diagnosticID: MessageID(domain: "domain", id: "fixit1"), + severity: .error), + changes: [ + .replace(oldNode: Syntax(node), newNode: Syntax(node)) // no-op + ]) + let secondFixIt = FixIt(message: SimpleDiagnosticMessage(message: "This is the second fix-it.", + diagnosticID: MessageID(domain: "domain", id: "fixit2"), + severity: .error), + changes: [ + .replace(oldNode: Syntax(node), newNode: Syntax(node)) // no-op + ]) + + context.diagnose(Diagnostic(node: node.attributeName, + message: SimpleDiagnosticMessage(message: "This is the first diagnostic.", + diagnosticID: MessageID(domain: "domain", id: "diagnostic2"), + severity: .warning), + fixIts: [firstFixIt, secondFixIt])) + context.diagnose(Diagnostic(node: node.attributeName, + message: SimpleDiagnosticMessage(message: "This is the second diagnostic, it's a note.", + diagnosticID: MessageID(domain: "domain", id: "diagnostic2"), + severity: .note))) + + return [] + } +}