Skip to content

Add refactoring action to convert stored to computed properties#2622

Open
ahoppen wants to merge 1 commit into
swiftlang:mainfrom
ahoppen:stored-to-computed
Open

Add refactoring action to convert stored to computed properties#2622
ahoppen wants to merge 1 commit into
swiftlang:mainfrom
ahoppen:stored-to-computed

Conversation

@ahoppen
Copy link
Copy Markdown
Member

@ahoppen ahoppen commented Apr 27, 2026

This is the first syntactic refactoring action that needs to perform a cursor info request on codeAction/resolve, so the majority of this PR is to add infrastructure for that.

Based on #2496.

This is the first syntactic refactoring action that needs to perform a cursor info request on `codeAction/resolve`, so the majority of this PR is to add infrastructure for that.

Based on swiftlang#2496.

Co-Authored-By: Padmashree S S <padmashreess2006@gmail.com>
WorkspaceEdit(
changes: [
uri: [
TextEdit(range: positions["1️⃣"]..<positions["3️⃣"], newText: "\n var x :Int{ 25 }")
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Padmashree06: It looks like the refactoring action in swift-syntax doesn’t produce correct whitespaces here (it should be x: Int, not x :Int). Would you be able to work on a fix for that in swift-syntax?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes sure! I will fix it!

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ahoppen I have fixed the whitespace error in swift-syntax.

@ahoppen
Copy link
Copy Markdown
Member Author

ahoppen commented Apr 27, 2026

@swift-ci Please test

return .resolveEditLazily
}
// Cursor info reports type as `_` if it cannot determine the type.
if let type = try? await scope.cursorInfo(at: scope.snapshot.position(of: identifier.position)).only?.typeName,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I mentioned in #2588 (comment), I don't think we should allow arbitrary cursorInfo in textDocument/codeAction request.
If the client don't support codeAction/resolve for .edit, imo we should drop this action.


package func codeActionResolve(_ req: CodeActionResolveRequest) async throws -> CodeAction {
return req.codeAction
guard let data = UnresolvedCodeActionData(fromLSPAny: req.codeAction.data) else {
Copy link
Copy Markdown
Member

@rintaro rintaro May 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO the whole mechanism should be something as simple as:

protocol SyntaxCodeActionProvider: SendableMetatype {
  // Provider name. default impl: { String(describing: Self.self) }
  static var name: String

  static func codeActions(in scope: SyntaxCodeActionScope) -> [CodeAction]
  static func resolve(_ codeAction: CodeAction, in snapshot: DocumentSnapshot) -> CodeAction
}

struct UnresolvedCodeActionData: LSPAnyCodable {
  // Provider name generated the code action.
  var provider: String

  /// The document on which the code action should be applied.
  var document: VersionedTextDocumentIdentifier

  // Original `CodeAction.data` attached.
  var orignalData: LSPAny?
}
func codeAction(_ req: CodeActionRequest) -> CodeActionRequestResponse {
  let actions = [(provider: SyntaxCodeActionProvider.Type, action: CodeAction)] = ...

  return .codeActions(
    actions.map { item
      if shouldResolve(item.action) {
        var action = item.action
        action = UnresolvedCodeActionData(provider: provider.name, codeAction: action.data)
        return action
      } else {
        return item.action
      }
    }
  )
}

func codeActionResolve(_ req: CodeActionResolveRequest) -> CodeAction {
  var codeAction = req.codeAction 
  let data = UnresolvedCodeActionData(fromLSPAny: codeAction.data) else {
    return codeAction
  }
  let provider = getCodeActionProvider(name: data.provider)
  codeAction.data = data.originalData
  return provider.resolve(
    codeAction, in: getSnapshot(data.document) // Probably with some more context to request `cursorInfo`.
  ) 
}

Each SyntaxCodeActionProvider should be able to store abitrary LSPAny information necessary for resolving the action, as the CodeAction.data.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants