diff --git a/Release Notes/602.md b/Release Notes/602.md index ffc24f54a83..fe25fbf52db 100644 --- a/Release Notes/602.md +++ b/Release Notes/602.md @@ -2,16 +2,24 @@ ## New APIs -- `DiagnosticMessage` has a new optional property, `category`, that providesa category name and documentation URL for a diagnostic. - - Description: Tools often have many different diagnostics. Diagnostic categories allow tools to group several diagnostics together with documentation that can help users understand what the diagnostics mean and how to address them. This API allows diagnostics to provide this category information. The diagnostic renderer will provide the category at the end of the diagnostic message in the form `[#CategoryName]`, and can print categories as "footnotes" with its `categoryFootnotes` method. - - Pull Request: https://github.com/swiftlang/swift-syntax/pull/2981 - - Migration steps: None required. The new `category` property has optional type, and there is a default implementation that returns `nil`. Types that conform to `DiagnosticMessage` can choose to implement this property and provide a category when appropriate. - - `SwiftLexicalLookup` - A new Swift unqualified lookup library - Description: The library provides a new Swift unqualified lookup implementation detached from the compiler and accessible to outside clients. The query is stateless and can be directly run on swift-syntax syntax tree, with any syntax node functioning as an entry point. It produces an enum-based data structure as a result that partitions collected names based on the lexical scope of introduction. - Pull Request: https://github.com/swiftlang/swift-syntax/pull/2952 - Notes: The library follows the behavior of the compiler implementation with some minor differences, such as a different way of handling dollar identifiers `$x` and generic parameters inside extensions. Furthermore, in the future, once the compiler adopts `SwiftLexicalLookup` and it becomes the canonical implementation, results produced by the query will be guaranteed to be correct. +- `DiagnosticMessage` has a new optional property, `category`, that provides a category name and documentation URL for a diagnostic. + - Description: Tools often have many different diagnostics. Diagnostic categories allow tools to group several diagnostics together with documentation that can help users understand what the diagnostics mean and how to address them. This API allows diagnostics to provide this category information. The diagnostic renderer will provide the category at the end of the diagnostic message in the form `[#CategoryName]`, and can print categories as "footnotes" with its `categoryFootnotes` method. + - Pull Request: https://github.com/swiftlang/swift-syntax/pull/2981 + - Migration steps: None required. The new `category` property has optional type, and there is a default implementation that returns `nil`. Types that conform to `DiagnosticMessage` can choose to implement this property and provide a category when appropriate. + +- `FixIt.Change` has a new case `replaceText` that performs a textual replacement of a range of text with another string. + - Description: The other `FixIt.Change` cases provide structured + modifications to syntax trees, such as replacing specific notes. Some + clients provide Fix-Its that don't fit well into this structured model. The + `replaceText` case makes it possible for such clients to express Fix-Its. + - Pull request: https://github.com/swiftlang/swift-syntax/pull/3030 + - Migration stems: None required. + ## API Behavior Changes ## Deprecations diff --git a/Sources/SwiftCompilerPluginMessageHandling/Diagnostics.swift b/Sources/SwiftCompilerPluginMessageHandling/Diagnostics.swift index 33a7425fcf0..277212cd08c 100644 --- a/Sources/SwiftCompilerPluginMessageHandling/Diagnostics.swift +++ b/Sources/SwiftCompilerPluginMessageHandling/Diagnostics.swift @@ -150,6 +150,13 @@ extension PluginMessage.Diagnostic { case .replaceChild(let replaceChildData): range = sourceManager.range(replaceChildData.replacementRange, in: replaceChildData.parent) text = replaceChildData.newChild.description + case .replaceText( + range: let replacementRange, + with: let newText, + in: let syntax + ): + range = sourceManager.range(replacementRange, in: syntax) + text = newText #if RESILIENT_LIBRARIES @unknown default: fatalError() diff --git a/Sources/SwiftDiagnostics/FixIt.swift b/Sources/SwiftDiagnostics/FixIt.swift index d7a25baeaa8..af238a31c6c 100644 --- a/Sources/SwiftDiagnostics/FixIt.swift +++ b/Sources/SwiftDiagnostics/FixIt.swift @@ -77,6 +77,14 @@ public struct FixIt: Sendable { case replaceTrailingTrivia(token: TokenSyntax, newTrivia: Trivia) /// Replace the child node of the given parent node at the given replacement range with the given new child node case replaceChild(data: any ReplacingChildData) + /// Replace the text within the given range in a syntax node with new text. + /// + /// Generally, one should use other cases to replace specific syntax nodes + /// or trivia, because it more easily leads to a correct result. However, + /// this case provides a fallback for textual replacement that ignores + /// syntactic structure. After applying a textual replacement, there is no + /// way to get back to a syntax tree without reparsing. + case replaceText(range: Range, with: String, in: Syntax) } /// A description of what this Fix-It performs. @@ -157,6 +165,9 @@ private extension FixIt.Change { range: replacingChildData.replacementRange, replacement: replacingChildData.newChild.description ) + + case .replaceText(range: let replacementRange, with: let newText, in: _): + return SourceEdit(range: replacementRange, replacement: newText) } } } diff --git a/Sources/SwiftSyntaxMacrosGenericTestSupport/Assertions.swift b/Sources/SwiftSyntaxMacrosGenericTestSupport/Assertions.swift index d1e96499ee0..7d7e490cbc0 100644 --- a/Sources/SwiftSyntaxMacrosGenericTestSupport/Assertions.swift +++ b/Sources/SwiftSyntaxMacrosGenericTestSupport/Assertions.swift @@ -632,6 +632,11 @@ fileprivate extension FixIt.Change { range: start..