Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 1de842a

Browse files
committed
Check Workspace Edit ResourceOps
Fixes rust-lang#14780 . This commit introduces guards for checking if the client supports ResourceOperations for operations to use them.
1 parent 6d333e5 commit 1de842a

File tree

1 file changed

+129
-5
lines changed

1 file changed

+129
-5
lines changed

crates/rust-analyzer/src/handlers/request.rs

Lines changed: 129 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ use std::{
1010
use anyhow::Context;
1111
use ide::{
1212
AnnotationConfig, AssistKind, AssistResolveStrategy, Cancellable, FilePosition, FileRange,
13-
HoverAction, HoverGotoTypeData, Query, RangeInfo, ReferenceCategory, Runnable, RunnableKind,
14-
SingleResolve, SourceChange, TextEdit,
13+
FileSystemEdit, HoverAction, HoverGotoTypeData, Query, RangeInfo, ReferenceCategory, Runnable,
14+
RunnableKind, SingleResolve, SourceChange, TextEdit,
1515
};
1616
use ide_db::SymbolKind;
1717
use lsp_server::ErrorCode;
@@ -20,9 +20,9 @@ use lsp_types::{
2020
CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams,
2121
CodeLens, CompletionItem, FoldingRange, FoldingRangeParams, HoverContents, InlayHint,
2222
InlayHintParams, Location, LocationLink, Position, PrepareRenameResponse, Range, RenameParams,
23-
SemanticTokensDeltaParams, SemanticTokensFullDeltaResult, SemanticTokensParams,
24-
SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation,
25-
SymbolTag, TextDocumentIdentifier, Url, WorkspaceEdit,
23+
ResourceOp, ResourceOperationKind, SemanticTokensDeltaParams, SemanticTokensFullDeltaResult,
24+
SemanticTokensParams, SemanticTokensRangeParams, SemanticTokensRangeResult,
25+
SemanticTokensResult, SymbolInformation, SymbolTag, TextDocumentIdentifier, Url, WorkspaceEdit,
2626
};
2727
use project_model::{ManifestPath, ProjectWorkspace, TargetKind};
2828
use serde_json::json;
@@ -548,6 +548,14 @@ pub(crate) fn handle_will_rename_files(
548548
) -> anyhow::Result<Option<lsp_types::WorkspaceEdit>> {
549549
let _p = profile::span("handle_will_rename_files");
550550

551+
if !resource_ops_supported(&snap, &ResourceOperationKind::Rename) {
552+
return Err(LspError::new(
553+
ErrorCode::RequestFailed as i32,
554+
"Client does not support rename capability.".to_owned(),
555+
)
556+
.into());
557+
}
558+
551559
let source_changes: Vec<SourceChange> = params
552560
.files
553561
.into_iter()
@@ -1029,7 +1037,32 @@ pub(crate) fn handle_rename(
10291037
// See https://github.com/microsoft/vscode-languageserver-node/issues/752 for more info
10301038
if !change.file_system_edits.is_empty() && snap.config.will_rename() {
10311039
change.source_file_edits.clear();
1040+
} else {
1041+
for edit in &change.file_system_edits {
1042+
match edit {
1043+
&FileSystemEdit::CreateFile { .. }
1044+
if !resource_ops_supported(&snap, &ResourceOperationKind::Create) =>
1045+
{
1046+
return Err(LspError::new(
1047+
ErrorCode::RequestFailed as i32,
1048+
"Client does not support create capability.".to_owned(),
1049+
)
1050+
.into())
1051+
}
1052+
&FileSystemEdit::MoveFile { .. } | &FileSystemEdit::MoveDir { .. }
1053+
if !resource_ops_supported(&snap, &ResourceOperationKind::Rename) =>
1054+
{
1055+
return Err(LspError::new(
1056+
ErrorCode::RequestFailed as i32,
1057+
"Client does not support move/rename capability.".to_owned(),
1058+
)
1059+
.into())
1060+
}
1061+
_ => (),
1062+
}
1063+
}
10321064
}
1065+
10331066
let workspace_edit = to_proto::workspace_edit(&snap, change)?;
10341067
Ok(Some(workspace_edit))
10351068
}
@@ -1137,6 +1170,43 @@ pub(crate) fn handle_code_action(
11371170
let resolve_data =
11381171
if code_action_resolve_cap { Some((index, params.clone())) } else { None };
11391172
let code_action = to_proto::code_action(&snap, assist, resolve_data)?;
1173+
1174+
// Check if the client supports the necessary `ResourceOperation`s.
1175+
if let Some(changes) = &code_action.edit.as_ref().unwrap().document_changes {
1176+
for change in changes {
1177+
match change {
1178+
lsp_ext::SnippetDocumentChangeOperation::Op(ResourceOp::Create(_))
1179+
if !resource_ops_supported(&snap, &ResourceOperationKind::Create) =>
1180+
{
1181+
return Err(LspError::new(
1182+
ErrorCode::RequestFailed as i32,
1183+
"Client does not support create capability.".to_owned(),
1184+
)
1185+
.into());
1186+
}
1187+
lsp_ext::SnippetDocumentChangeOperation::Op(ResourceOp::Rename(_))
1188+
if !resource_ops_supported(&snap, &ResourceOperationKind::Rename) =>
1189+
{
1190+
return Err(LspError::new(
1191+
ErrorCode::RequestFailed as i32,
1192+
"Client does not support rename capability.".to_owned(),
1193+
)
1194+
.into());
1195+
}
1196+
lsp_ext::SnippetDocumentChangeOperation::Op(ResourceOp::Delete(_))
1197+
if !resource_ops_supported(&snap, &ResourceOperationKind::Delete) =>
1198+
{
1199+
return Err(LspError::new(
1200+
ErrorCode::RequestFailed as i32,
1201+
"Client does not support delete capability.".to_owned(),
1202+
)
1203+
.into());
1204+
}
1205+
_ => (),
1206+
}
1207+
}
1208+
}
1209+
11401210
res.push(code_action)
11411211
}
11421212

@@ -1219,6 +1289,44 @@ pub(crate) fn handle_code_action_resolve(
12191289
let ca = to_proto::code_action(&snap, assist.clone(), None)?;
12201290
code_action.edit = ca.edit;
12211291
code_action.command = ca.command;
1292+
1293+
if let Some(edit) = code_action.edit.as_ref() {
1294+
if let Some(changes) = edit.document_changes.as_ref() {
1295+
for change in changes {
1296+
match change {
1297+
lsp_ext::SnippetDocumentChangeOperation::Op(ResourceOp::Create(_))
1298+
if !resource_ops_supported(&snap, &ResourceOperationKind::Create) =>
1299+
{
1300+
return Err(LspError::new(
1301+
ErrorCode::RequestFailed as i32,
1302+
"Client does not support create capability.".to_owned(),
1303+
)
1304+
.into());
1305+
}
1306+
lsp_ext::SnippetDocumentChangeOperation::Op(ResourceOp::Rename(_))
1307+
if !resource_ops_supported(&snap, &ResourceOperationKind::Rename) =>
1308+
{
1309+
return Err(LspError::new(
1310+
ErrorCode::RequestFailed as i32,
1311+
"Client does not support rename capability.".to_owned(),
1312+
)
1313+
.into());
1314+
}
1315+
lsp_ext::SnippetDocumentChangeOperation::Op(ResourceOp::Delete(_))
1316+
if !resource_ops_supported(&snap, &ResourceOperationKind::Delete) =>
1317+
{
1318+
return Err(LspError::new(
1319+
ErrorCode::RequestFailed as i32,
1320+
"Client does not support delete capability.".to_owned(),
1321+
)
1322+
.into());
1323+
}
1324+
_ => (),
1325+
}
1326+
}
1327+
}
1328+
}
1329+
12221330
Ok(code_action)
12231331
}
12241332

@@ -1990,3 +2098,19 @@ fn to_url(path: VfsPath) -> Option<Url> {
19902098
let str_path = path.as_os_str().to_str()?;
19912099
Url::from_file_path(str_path).ok()
19922100
}
2101+
2102+
fn resource_ops_supported(snap: &GlobalStateSnapshot, kind: &ResourceOperationKind) -> bool {
2103+
snap.config
2104+
.as_ref()
2105+
.caps()
2106+
.workspace
2107+
.as_ref()
2108+
.unwrap()
2109+
.workspace_edit
2110+
.as_ref()
2111+
.unwrap()
2112+
.resource_operations
2113+
.as_ref()
2114+
.unwrap()
2115+
.contains(kind)
2116+
}

0 commit comments

Comments
 (0)