Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/rust-analyzer/src/handlers/request.rs94
-rw-r--r--crates/rust-analyzer/tests/slow-tests/support.rs8
2 files changed, 98 insertions, 4 deletions
diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs
index afd82fc061..569cd632c6 100644
--- a/crates/rust-analyzer/src/handlers/request.rs
+++ b/crates/rust-analyzer/src/handlers/request.rs
@@ -8,6 +8,7 @@ use std::{
};
use anyhow::Context;
+
use ide::{
AnnotationConfig, AssistKind, AssistResolveStrategy, Cancellable, FilePosition, FileRange,
HoverAction, HoverGotoTypeData, Query, RangeInfo, ReferenceCategory, Runnable, RunnableKind,
@@ -20,9 +21,9 @@ use lsp_types::{
CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams,
CodeLens, CompletionItem, FoldingRange, FoldingRangeParams, HoverContents, InlayHint,
InlayHintParams, Location, LocationLink, Position, PrepareRenameResponse, Range, RenameParams,
- SemanticTokensDeltaParams, SemanticTokensFullDeltaResult, SemanticTokensParams,
- SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation,
- SymbolTag, TextDocumentIdentifier, Url, WorkspaceEdit,
+ ResourceOp, ResourceOperationKind, SemanticTokensDeltaParams, SemanticTokensFullDeltaResult,
+ SemanticTokensParams, SemanticTokensRangeParams, SemanticTokensRangeResult,
+ SemanticTokensResult, SymbolInformation, SymbolTag, TextDocumentIdentifier, Url, WorkspaceEdit,
};
use project_model::{ManifestPath, ProjectWorkspace, TargetKind};
use serde_json::json;
@@ -33,7 +34,7 @@ use vfs::{AbsPath, AbsPathBuf, VfsPath};
use crate::{
cargo_target_spec::CargoTargetSpec,
- config::{RustfmtConfig, WorkspaceSymbolConfig},
+ config::{Config, RustfmtConfig, WorkspaceSymbolConfig},
diff::diff,
from_proto,
global_state::{GlobalState, GlobalStateSnapshot},
@@ -1030,7 +1031,23 @@ pub(crate) fn handle_rename(
if !change.file_system_edits.is_empty() && snap.config.will_rename() {
change.source_file_edits.clear();
}
+
let workspace_edit = to_proto::workspace_edit(&snap, change)?;
+
+ if let Some(lsp_types::DocumentChanges::Operations(ops)) =
+ workspace_edit.document_changes.as_ref()
+ {
+ for op in ops {
+ if let lsp_types::DocumentChangeOperation::Op(doc_change_op) = op {
+ if let Err(err) =
+ resource_ops_supported(&snap.config, resolve_resource_op(doc_change_op))
+ {
+ return Err(err);
+ }
+ }
+ }
+ }
+
Ok(Some(workspace_edit))
}
@@ -1137,6 +1154,20 @@ pub(crate) fn handle_code_action(
let resolve_data =
if code_action_resolve_cap { Some((index, params.clone())) } else { None };
let code_action = to_proto::code_action(&snap, assist, resolve_data)?;
+
+ // Check if the client supports the necessary `ResourceOperation`s.
+ if let Some(changes) = &code_action.edit.as_ref().unwrap().document_changes {
+ for change in changes {
+ if let lsp_ext::SnippetDocumentChangeOperation::Op(res_op) = change {
+ if let Err(err) =
+ resource_ops_supported(&snap.config, resolve_resource_op(res_op))
+ {
+ return Err(err);
+ }
+ }
+ }
+ }
+
res.push(code_action)
}
@@ -1219,6 +1250,21 @@ pub(crate) fn handle_code_action_resolve(
let ca = to_proto::code_action(&snap, assist.clone(), None)?;
code_action.edit = ca.edit;
code_action.command = ca.command;
+
+ if let Some(edit) = code_action.edit.as_ref() {
+ if let Some(changes) = edit.document_changes.as_ref() {
+ for change in changes {
+ if let lsp_ext::SnippetDocumentChangeOperation::Op(res_op) = change {
+ if let Err(err) =
+ resource_ops_supported(&snap.config, resolve_resource_op(res_op))
+ {
+ return Err(err);
+ }
+ }
+ }
+ }
+ }
+
Ok(code_action)
}
@@ -1990,3 +2036,43 @@ fn to_url(path: VfsPath) -> Option<Url> {
let str_path = path.as_os_str().to_str()?;
Url::from_file_path(str_path).ok()
}
+
+fn resource_ops_supported(config: &Config, kind: ResourceOperationKind) -> anyhow::Result<()> {
+ let ctn = config
+ .caps()
+ .workspace
+ .as_ref()
+ .unwrap()
+ .workspace_edit
+ .as_ref()
+ .unwrap()
+ .resource_operations
+ .as_ref()
+ .unwrap()
+ .contains(&kind);
+
+ if !ctn {
+ return Err(LspError::new(
+ ErrorCode::RequestFailed as i32,
+ format!(
+ "Client does not support {} capability.",
+ match kind {
+ ResourceOperationKind::Create => "create",
+ ResourceOperationKind::Rename => "rename",
+ ResourceOperationKind::Delete => "delete",
+ }
+ ),
+ )
+ .into());
+ }
+
+ Ok(())
+}
+
+fn resolve_resource_op(op: &ResourceOp) -> ResourceOperationKind {
+ match op {
+ ResourceOp::Create(_) => ResourceOperationKind::Create,
+ ResourceOp::Rename(_) => ResourceOperationKind::Rename,
+ ResourceOp::Delete(_) => ResourceOperationKind::Delete,
+ }
+}
diff --git a/crates/rust-analyzer/tests/slow-tests/support.rs b/crates/rust-analyzer/tests/slow-tests/support.rs
index 2da87f2971..21053c86ce 100644
--- a/crates/rust-analyzer/tests/slow-tests/support.rs
+++ b/crates/rust-analyzer/tests/slow-tests/support.rs
@@ -113,6 +113,14 @@ impl<'a> Project<'a> {
relative_pattern_support: None,
},
),
+ workspace_edit: Some(lsp_types::WorkspaceEditClientCapabilities {
+ resource_operations: Some(vec![
+ lsp_types::ResourceOperationKind::Create,
+ lsp_types::ResourceOperationKind::Delete,
+ lsp_types::ResourceOperationKind::Rename,
+ ]),
+ ..Default::default()
+ }),
..Default::default()
}),
text_document: Some(lsp_types::TextDocumentClientCapabilities {