Skip to content

Add type annotation to convertStoredPropertyToComputed#2496

Closed
Padmashree06 wants to merge 3 commits into
swiftlang:mainfrom
Padmashree06:add-convertStoredPropertyTocComputed
Closed

Add type annotation to convertStoredPropertyToComputed#2496
Padmashree06 wants to merge 3 commits into
swiftlang:mainfrom
Padmashree06:add-convertStoredPropertyTocComputed

Conversation

@Padmashree06
Copy link
Copy Markdown

Issue: #2459

This PR implements the ConvertStoredPropertyToComputed refactoring in SourceKit-LSP, adopting the new API recently merged in swift-syntax (#3249).

Summary

It integrates cursorInfo into the SyntaxCodeActionScope, allowing the refactoring to resolve types for inferred properties (e.g., let x = 5) by extracting the semantic type from SourceKit's annotated declaration.

Changes

  • Updated SyntaxCodeActionScope to include [CursorInfo]
  • Updated the code action request handler to:
    • Perform a cursorInfo request
    • Add the result to SyntaxCodeActionScope
  • Added ConvertStoredPropertyToComputed to allSyntaxCodeActionProviders in SyntaxCodeActions.swift

Implementation Details

Implemented SyntaxCodeActionProvider for ConvertStoredPropertyToComputed which:

  1. Attempts to resolve the property type via cursorInfo
  2. Falls back to explicit type annotations if semantic info is unavailable
  3. Passes the resolved type to the refactoring context

Copy link
Copy Markdown
Member

@ahoppen ahoppen left a comment

Choose a reason for hiding this comment

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

A few preliminary review comments before I dive deeper into the implementation.

@@ -0,0 +1,60 @@
import Foundation
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.

Mostly out of curiosity: Why do we need to import Foundation here?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I imported Foundation because I was using String.range(of:) in the extractType helper. However, if we'd prefer to keep the dependencies minimal, I'm happy to switch to native Swift String methods like firstRange(of:) and remove the import entirely. Let me know what you'd prefer!

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.

You’r no longer using that anymore though, right?

}

private static func extractType(from annotatedDecl: String) -> String? {

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.

Superfluous newline

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thank you for the feedback! I'll remove the unnecessary lines.

import SwiftSyntaxBuilder

extension ConvertStoredPropertyToComputed: SyntaxCodeActionProvider {

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.

Superfluous newline

self.snapshot = snapshot
self.request = request
self.file = file
self.cursorInfo = cursorInfo
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.

I don’t think we set cursorInfo anywhere, do we? Also, we should implement this in a way where the cursor info is only retrieved when it’s actually needed by a refactoring action instead of being set for every syntactic refactoring action.

Copy link
Copy Markdown
Author

@Padmashree06 Padmashree06 Feb 27, 2026

Choose a reason for hiding this comment

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

Thank you for pointing that out!

You’re right, I missed that cursorInfo is not being initialized anywhere. Triggering a cursorInfo request for every syntactic refactoring would indeed be unnecessary overhead.

I’ll remove cursorInfo from SyntaxCodeActionScope. Instead, I’ll first perform a syntactic check to determine whether the type information is missing. Only if semantic resolution is actually required for the refactoring will I trigger a cursorInfo request within the refactoring operation itself, using SwiftLanguageService.cursorInfo.

Please let me know if this approach aligns with your expectations or if there’s anything else I should consider.

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.

Yes, that’s a lot better now with the asynchronous command and it’s the approach I would have preferred until a few weeks ago but now we have codeAction/resolve, which is designed for exactly this workflow. Could you adopt it?


private static func extractType(from annotatedDecl: String) -> String? {

guard let start = annotatedDecl.range(of: "<type>"),
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.

Instead of parsing the annotated description, we should use the typename key.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Yes thank you! I'll use typename key instead!

@ahoppen
Copy link
Copy Markdown
Member

ahoppen commented Feb 28, 2026

If you have addressed my comments, it seems like you haven’t pushed your latest changes.

@Padmashree06
Copy link
Copy Markdown
Author

I haven’t pushed the changes yet. I was waiting for confirmation before doing so. I’ll push them shortly.

@Padmashree06 Padmashree06 force-pushed the add-convertStoredPropertyTocComputed branch from b80521f to 1ef63e7 Compare March 18, 2026 08:46
@Padmashree06
Copy link
Copy Markdown
Author

@ahoppen I’ve updated the implementation based on your feedback.

  • Cursor info is now fetched only when the type is not explicitly declared.
  • When a type annotation is present, the refactoring is applied inline.
  • Otherwise, the semantic.refactor.convertStoredPropertyToComputed command is executed to retrieve cursor info, infer the type semantically, and perform the conversion to a computed property.
  • I’ve added corresponding CodeAction tests for both cases.

kind: .refactorInline,
command: Command(
title: "Convert Stored Property to Computed Property",
command: "semantic.refactor.convertStoredPropertyToComputed",
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.

Instead of implementing a custom command, do you think you could use the support for codeAction/resolve that @Tabonx added recently in #2549?

@@ -0,0 +1,60 @@
import Foundation
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.

You’r no longer using that anymore though, right?

self.snapshot = snapshot
self.request = request
self.file = file
self.cursorInfo = cursorInfo
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.

Yes, that’s a lot better now with the asynchronous command and it’s the approach I would have preferred until a few weeks ago but now we have codeAction/resolve, which is designed for exactly this workflow. Could you adopt it?

@Padmashree06
Copy link
Copy Markdown
Author

Yes, I will modify the implementation to use codeAction/resolve

@Padmashree06 Padmashree06 force-pushed the add-convertStoredPropertyTocComputed branch from 1ef63e7 to 5d2c8b2 Compare April 12, 2026 14:03
@Padmashree06
Copy link
Copy Markdown
Author

@ahoppen I've updated the implementation to use codeAction/resolve

ahoppen added a commit to ahoppen/sourcekit-lsp that referenced this pull request 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 swiftlang#2496.

Co-Authored-By: Padmashree S S <padmashreess2006@gmail.com>
@ahoppen
Copy link
Copy Markdown
Member

ahoppen commented Apr 27, 2026

Sorry for the delayed response, I was on vacation for the last couple of weeks.

I just took a deeper dive into the implementation and was a little uneasy with how ad-hoc the implementation was for this particular refactoring action because I think we need similar support for more refactoring actions in the future. I would have really liked to make some suggestion for a better design but needed to really dive into it myself to explore alternatives and once I arrived at one, I pretty much had a working implementation ready, so I ended up opening #2622. I would appreciate your feedback on that PR, let’s continue the conversation over there. Thanks for the work you did here to get this started.

@ahoppen ahoppen closed this Apr 27, 2026
@Padmashree06
Copy link
Copy Markdown
Author

@ahoppen Thanks for the review and for taking a deeper look into this. I understand your concerns about the implementation being too specific. I’ll go through #2622 and add my inputs there!

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.

2 participants