Repository: denoland/deno (language: rust)

Issue:
lsp: Renaming variables doesn't updated shorthand property names correctly
Version: Deno 2.1.9

```ts
function foo({myParam}: {myParam: number}) {
    console.log(myParam);
}

const myParam = 3; // select myParam and hit F2 to rename
foo({myParam})
```

Normally when you rename `myParam` using the `F2` key, VSCode turns the last line into:
```ts
foo({myParam: newParam})
```

But when you perform this same trick with Deno, you get:

```ts
foo({newParam})
```


Discussion / hints:

I can't reproduce the problem:


https://github.com/user-attachments/assets/ab7d9f8f-eefb-43c7-b4ab-7a24bc9183e4

Err, nevermind, I read the issue wrong. I can reproduce the problem.

Fix patch:
diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs
index 1036f468a7d524..3c6c20cc50d240 100644
--- a/cli/lsp/language_server.rs
+++ b/cli/lsp/language_server.rs
@@ -3017,12 +3017,15 @@ impl Inner {
     let asset_or_doc = self.get_asset_or_document(&specifier)?;
     let line_index = asset_or_doc.line_index();
 
+    let user_preferences =
+      tsc::UserPreferences::from_config_for_specifier(&self.config, &specifier);
     let maybe_locations = self
       .ts_server
       .find_rename_locations(
         self.snapshot(),
         specifier,
         line_index.offset_tsc(params.text_document_position.position)?,
+        user_preferences,
         token,
       )
       .await
diff --git a/cli/lsp/tsc.rs b/cli/lsp/tsc.rs
index 15d4cd458ee7fb..a8bbf08649d56b 100644
--- a/cli/lsp/tsc.rs
+++ b/cli/lsp/tsc.rs
@@ -1174,6 +1174,7 @@ impl TsServer {
     snapshot: Arc<StateSnapshot>,
     specifier: ModuleSpecifier,
     position: u32,
+    user_preferences: UserPreferences,
     token: &CancellationToken,
   ) -> Result<Option<Vec<RenameLocation>>, AnyError> {
     let req = TscRequest::FindRenameLocations((
@@ -1181,7 +1182,7 @@ impl TsServer {
       position,
       false,
       false,
-      false,
+      user_preferences,
     ));
     let mut results = FuturesOrdered::new();
     for scope in snapshot
@@ -1205,7 +1206,10 @@ impl TsServer {
         if token.is_cancelled() {
           return Err(anyhow!("request cancelled"));
         } else {
-          lsp_warn!("Unable to get rename locations from TypeScript: {err}");
+          let err = err.to_string();
+          if !err.contains("Could not find source file") {
+            lsp_warn!("Unable to get rename locations from TypeScript: {err}");
+          }
         }
       }
       let locations = locations.unwrap_or_default();
@@ -2420,9 +2424,8 @@ impl ImplementationLocation {
 pub struct RenameLocation {
   #[serde(flatten)]
   document_span: DocumentSpan,
-  // RenameLocation props
-  // prefix_text: Option<String>,
-  // suffix_text: Option<String>,
+  prefix_text: Option<String>,
+  suffix_text: Option<String>,
 }
 
 impl RenameLocation {
@@ -2481,12 +2484,21 @@ impl RenameLocations {
 
       // push TextEdit for ensured `TextDocumentEdit.edits`.
       let document_edit = text_document_edit_map.get_mut(&uri).unwrap();
+      let new_text = [
+        location.prefix_text.as_deref(),
+        Some(new_name),
+        location.suffix_text.as_deref(),
+      ]
+      .into_iter()
+      .flatten()
+      .collect::<Vec<_>>()
+      .join("");
       document_edit.edits.push(lsp::OneOf::Left(lsp::TextEdit {
         range: location
           .document_span
           .text_span
           .to_range(asset_or_doc.line_index()),
-        new_text: new_name.to_string(),
+        new_text,
       }));
     }
 
@@ -5548,8 +5560,8 @@ pub enum TscRequest {
   ProvideCallHierarchyOutgoingCalls((String, u32)),
   // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6236
   PrepareCallHierarchy((String, u32)),
-  // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6221
-  FindRenameLocations((String, u32, bool, bool, bool)),
+  // https://github.com/denoland/deno/blob/v2.2.2/cli/tsc/dts/typescript.d.ts#L6674
+  FindRenameLocations((String, u32, bool, bool, UserPreferences)),
   // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6224
   GetSmartSelectionRange((String, u32)),
   // https://github.com/denoland/deno/blob/v1.37.1/cli/tsc/dts/typescript.d.ts#L6183


Test patch:
diff --git a/tests/integration/lsp_tests.rs b/tests/integration/lsp_tests.rs
index 4d14397be79a21..717986e48c1ad7 100644
--- a/tests/integration/lsp_tests.rs
+++ b/tests/integration/lsp_tests.rs
@@ -3105,7 +3105,7 @@ fn lsp_rename_synbol_file_scheme_edits_only() {
                 "start": { "line": 1, "character": 17 },
                 "end": { "line": 1, "character": 26 },
               },
-              "newText": "PATH_SEPARATOR",
+              "newText": "SEPARATOR as PATH_SEPARATOR",
             },
             {
               "range": {
@@ -3879,50 +3879,65 @@ fn lsp_rename() {
   let context = TestContextBuilder::new().use_temp_cwd().build();
   let mut client = context.new_lsp_command().build();
   client.initialize_default();
-  client.did_open(
-    json!({
-      "textDocument": {
-        "uri": "file:///a/file.ts",
-        "languageId": "typescript",
-        "version": 1,
+  client.did_open(json!({
+    "textDocument": {
+      "uri": "file:///a/file.ts",
+      "languageId": "typescript",
+      "version": 1,
+      "text": r#"
+        const variable = "a";
+        console.log(variable);
+        ({ variable });
+
         // this should not rename in comments and strings
-        "text": "let variable = 'a'; // variable\nconsole.log(variable);\n\"variable\";\n"
-      }
-    }),
-  );
+        // variable
+        "variable";
+      "#,
+    },
+  }));
   let res = client.write_request(
     "textDocument/rename",
     json!({
-      "textDocument": {
-        "uri": "file:///a/file.ts"
-      },
-      "position": { "line": 0, "character": 4 },
-      "newName": "variable_modified"
+      "textDocument": { "uri": "file:///a/file.ts" },
+      "position": { "line": 1, "character": 14 },
+      "newName": "variable_modified",
     }),
   );
   assert_eq!(
     res,
     json!({
-      "documentChanges": [{
-        "textDocument": {
-          "uri": "file:///a/file.ts",
-          "version": 1
-        },
-        "edits": [{
-          "range": {
-            "start": { "line": 0, "character": 4 },
-            "end": { "line": 0, "character": 12 }
-          },
-          "newText": "variable_modified"
-        }, {
-          "range": {
-            "start": { "line": 1, "character": 12 },
-            "end": { "line": 1, "character": 20 }
+      "documentChanges": [
+        {
+          "textDocument": {
+            "uri": "file:///a/file.ts",
+            "version": 1,
           },
-          "newText": "variable_modified"
-        }]
-      }]
-    })
+          "edits": [
+            {
+              "range": {
+                "start": { "line": 1, "character": 14 },
+                "end": { "line": 1, "character": 22 },
+              },
+              "newText": "variable_modified",
+            },
+            {
+              "range": {
+                "start": { "line": 2, "character": 20 },
+                "end": { "line": 2, "character": 28 },
+              },
+              "newText": "variable_modified",
+            },
+            {
+              "range": {
+                "start": { "line": 3, "character": 11 },
+                "end": { "line": 3, "character": 19 },
+              },
+              "newText": "variable: variable_modified",
+            },
+          ],
+        },
+      ],
+    }),
   );
   client.shutdown();
 }
@@ -15353,7 +15368,7 @@ fn lsp_deno_json_scopes_rename_symbol() {
           "edits": [
             {
               "range": file2.range_of("foo"),
-              "newText": "bar",
+              "newText": "bar as foo",
             },
           ],
         },