Skip to content

Commit 937f883

Browse files
committed
Check Workspace Edit ResourceOps
In order to counter the case where the client is not able to support one or more of the essential resource operation, and by countering we mean returning a corresponding LspError, the current version of our codebase makes it possible to handle this on the request level. In other words the changes we offer could have been done in a neater way but the changes this requires is a huge undertaking so we rather patch what we have at hand.
1 parent 6d333e5 commit 937f883

File tree

1 file changed

+120
-5
lines changed

1 file changed

+120
-5
lines changed

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

Lines changed: 120 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,13 @@ 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(Box::new(LspError::new(
553+
ErrorCode::RequestFailed as i32,
554+
"Client does not support rename capability.".to_owned(),
555+
)));
556+
}
557+
551558
let source_changes: Vec<SourceChange> = params
552559
.files
553560
.into_iter()
@@ -1029,7 +1036,30 @@ pub(crate) fn handle_rename(
10291036
// See https://github.com/microsoft/vscode-languageserver-node/issues/752 for more info
10301037
if !change.file_system_edits.is_empty() && snap.config.will_rename() {
10311038
change.source_file_edits.clear();
1039+
} else {
1040+
for edit in &change.file_system_edits {
1041+
match edit {
1042+
&FileSystemEdit::CreateFile { .. }
1043+
if !resource_ops_supported(&snap, &ResourceOperationKind::Create) =>
1044+
{
1045+
return Err(Box::new(LspError::new(
1046+
ErrorCode::RequestFailed as i32,
1047+
"Client does not support create capability.".to_owned(),
1048+
)))
1049+
}
1050+
&FileSystemEdit::MoveFile { .. } | &FileSystemEdit::MoveDir { .. }
1051+
if !resource_ops_supported(&snap, &ResourceOperationKind::Rename) =>
1052+
{
1053+
return Err(Box::new(LspError::new(
1054+
ErrorCode::RequestFailed as i32,
1055+
"Client does not support move/rename capability.".to_owned(),
1056+
)))
1057+
}
1058+
_ => (),
1059+
}
1060+
}
10321061
}
1062+
10331063
let workspace_edit = to_proto::workspace_edit(&snap, change)?;
10341064
Ok(Some(workspace_edit))
10351065
}
@@ -1137,6 +1167,40 @@ pub(crate) fn handle_code_action(
11371167
let resolve_data =
11381168
if code_action_resolve_cap { Some((index, params.clone())) } else { None };
11391169
let code_action = to_proto::code_action(&snap, assist, resolve_data)?;
1170+
1171+
// Check if the client supports the necessary `ResourceOperation`s.
1172+
if let Some(changes) = &code_action.edit.as_ref().unwrap().document_changes {
1173+
for change in changes {
1174+
match change {
1175+
lsp_ext::SnippetDocumentChangeOperation::Op(ResourceOp::Create(_))
1176+
if !resource_ops_supported(&snap, &ResourceOperationKind::Create) =>
1177+
{
1178+
return Err(Box::new(LspError::new(
1179+
ErrorCode::RequestFailed as i32,
1180+
"Client does not support create capability.".to_owned(),
1181+
)));
1182+
}
1183+
lsp_ext::SnippetDocumentChangeOperation::Op(ResourceOp::Rename(_))
1184+
if !resource_ops_supported(&snap, &ResourceOperationKind::Rename) =>
1185+
{
1186+
return Err(Box::new(LspError::new(
1187+
ErrorCode::RequestFailed as i32,
1188+
"Client does not support rename capability.".to_owned(),
1189+
)));
1190+
}
1191+
lsp_ext::SnippetDocumentChangeOperation::Op(ResourceOp::Delete(_))
1192+
if !resource_ops_supported(&snap, &ResourceOperationKind::Delete) =>
1193+
{
1194+
return Err(Box::new(LspError::new(
1195+
ErrorCode::RequestFailed as i32,
1196+
"Client does not support delete capability.".to_owned(),
1197+
)));
1198+
}
1199+
_ => (),
1200+
}
1201+
}
1202+
}
1203+
11401204
res.push(code_action)
11411205
}
11421206

@@ -1219,6 +1283,41 @@ pub(crate) fn handle_code_action_resolve(
12191283
let ca = to_proto::code_action(&snap, assist.clone(), None)?;
12201284
code_action.edit = ca.edit;
12211285
code_action.command = ca.command;
1286+
1287+
if let Some(edit) = code_action.edit.as_ref() {
1288+
if let Some(changes) = edit.document_changes.as_ref() {
1289+
for change in changes {
1290+
match change {
1291+
lsp_ext::SnippetDocumentChangeOperation::Op(ResourceOp::Create(_))
1292+
if !resource_ops_supported(&snap, &ResourceOperationKind::Create) =>
1293+
{
1294+
return Err(Box::new(LspError::new(
1295+
ErrorCode::RequestFailed as i32,
1296+
"Client does not support create capability.".to_owned(),
1297+
)));
1298+
}
1299+
lsp_ext::SnippetDocumentChangeOperation::Op(ResourceOp::Rename(_))
1300+
if !resource_ops_supported(&snap, &ResourceOperationKind::Rename) =>
1301+
{
1302+
return Err(Box::new(LspError::new(
1303+
ErrorCode::RequestFailed as i32,
1304+
"Client does not support rename capability.".to_owned(),
1305+
)));
1306+
}
1307+
lsp_ext::SnippetDocumentChangeOperation::Op(ResourceOp::Delete(_))
1308+
if !resource_ops_supported(&snap, &ResourceOperationKind::Delete) =>
1309+
{
1310+
return Err(Box::new(LspError::new(
1311+
ErrorCode::RequestFailed as i32,
1312+
"Client does not support delete capability.".to_owned(),
1313+
)));
1314+
}
1315+
_ => (),
1316+
}
1317+
}
1318+
}
1319+
}
1320+
12221321
Ok(code_action)
12231322
}
12241323

@@ -1990,3 +2089,19 @@ fn to_url(path: VfsPath) -> Option<Url> {
19902089
let str_path = path.as_os_str().to_str()?;
19912090
Url::from_file_path(str_path).ok()
19922091
}
2092+
2093+
fn resource_ops_supported(snap: &GlobalStateSnapshot, kind: &ResourceOperationKind) -> bool {
2094+
snap.config
2095+
.as_ref()
2096+
.caps()
2097+
.workspace
2098+
.as_ref()
2099+
.unwrap()
2100+
.workspace_edit
2101+
.as_ref()
2102+
.unwrap()
2103+
.resource_operations
2104+
.as_ref()
2105+
.unwrap()
2106+
.contains(kind)
2107+
}

0 commit comments

Comments
 (0)