Files
sourcekit-lsp/Sources/SourceKitLSP/Swift/CodeActions/SyntaxRefactoringCodeActionProvider.swift
Doug Gregor a8b61a52d3 Introduce new refactoring code actions based on the Swift syntax tree.
This change includes a number of new refactoring code actions that
build on the syntax refactorings for the SwiftRefactor module of swift-syntax:

  * Add digit separators to an integer literal, e.g., `1000000` ->
    `1_000_000`.
  * Remove digit separators from an integer literal, e.g., 1_000_000 ->
    1000000.
  * Format a raw string literal, e.g., `"Hello \#(world)"` ->
    `##"Hello\#(world)"##`
  * Migrate to new if let syntax, e.g., `if let x = x { ... }` ->
    `if let x { ... }`
  * Replace opaque parameters with generic parameters, e.g.,
    `func f(p: some P)` --> `func f<T1: P>(p: T1)`.

This is generally easy to do, requiring one conformance to provide a name for the refactoring:

    extension AddSeparatorsToIntegerLiteral: SyntaxRefactoringCodeActionProvider {
      public static var title: String { "Add digit separators" }
    }
2024-04-16 23:00:20 -07:00

76 lines
2.4 KiB
Swift

//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2024 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 LanguageServerProtocol
import SwiftRefactor
import SwiftSyntax
/// Protocol that adapts a SyntaxRefactoringProvider (that comes from
/// swift-syntax) into a SyntaxCodeActionProvider.
protocol SyntaxRefactoringCodeActionProvider: SyntaxCodeActionProvider, SyntaxRefactoringProvider {
static var title: String { get }
}
/// SyntaxCodeActionProviders with a \c Void context can automatically be
/// adapted provide a code action based on their refactoring operation.
extension SyntaxRefactoringCodeActionProvider where Self.Context == Void {
static func codeActions(in scope: SyntaxCodeActionScope) -> [CodeAction] {
guard
let token = scope.firstToken,
let node = token.parent?.as(Input.self)
else {
return []
}
guard let refactored = Self.refactor(syntax: node) else {
return []
}
let edit = TextEdit(
range: scope.snapshot.range(of: node),
newText: refactored.description
)
return [
CodeAction(
title: Self.title,
kind: .refactorInline,
edit: WorkspaceEdit(changes: [scope.snapshot.uri: [edit]])
)
]
}
}
// Adapters for specific refactoring provides in swift-syntax.
extension AddSeparatorsToIntegerLiteral: SyntaxRefactoringCodeActionProvider {
public static var title: String { "Add digit separators" }
}
extension FormatRawStringLiteral: SyntaxRefactoringCodeActionProvider {
public static var title: String {
"Convert string literal to minimal number of '#'s"
}
}
extension MigrateToNewIfLetSyntax: SyntaxRefactoringCodeActionProvider {
public static var title: String { "Migrate to shorthand 'if let' syntax" }
}
extension OpaqueParameterToGeneric: SyntaxRefactoringCodeActionProvider {
public static var title: String { "Expand 'some' parameters to generic parameters" }
}
extension RemoveSeparatorsFromIntegerLiteral: SyntaxRefactoringCodeActionProvider {
public static var title: String { "Remove digit separators" }
}