7958: Avoid double text edits when renaming mod declaration r=matklad a=Veykril

Closes https://github.com/rust-analyzer/rust-analyzer/issues/7916

See https://github.com/microsoft/vscode-languageserver-node/issues/752 for context

Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
This commit is contained in:
bors[bot] 2021-03-10 15:07:46 +00:00 committed by GitHub
commit 83280ea574
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 15 additions and 2 deletions

View file

@ -305,7 +305,6 @@ impl ModuleDef {
ModuleDef::Module(it) => it.name(db), ModuleDef::Module(it) => it.name(db),
ModuleDef::Const(it) => it.name(db), ModuleDef::Const(it) => it.name(db),
ModuleDef::Static(it) => it.name(db), ModuleDef::Static(it) => it.name(db),
ModuleDef::BuiltinType(it) => Some(it.name()), ModuleDef::BuiltinType(it) => Some(it.name()),
} }
} }

View file

@ -94,6 +94,7 @@ pub(crate) fn rename_with_semantics(
} }
} }
/// Called by the client when it is about to rename a file.
pub(crate) fn will_rename_file( pub(crate) fn will_rename_file(
db: &RootDatabase, db: &RootDatabase,
file_id: FileId, file_id: FileId,

View file

@ -395,6 +395,9 @@ impl Config {
pub fn work_done_progress(&self) -> bool { pub fn work_done_progress(&self) -> bool {
try_or!(self.caps.window.as_ref()?.work_done_progress?, false) try_or!(self.caps.window.as_ref()?.work_done_progress?, false)
} }
pub fn will_rename(&self) -> bool {
try_or!(self.caps.workspace.as_ref()?.file_operations.as_ref()?.will_rename?, false)
}
pub fn code_action_resolve(&self) -> bool { pub fn code_action_resolve(&self) -> bool {
try_or!( try_or!(
self.caps self.caps

View file

@ -799,8 +799,18 @@ pub(crate) fn handle_rename(
let _p = profile::span("handle_rename"); let _p = profile::span("handle_rename");
let position = from_proto::file_position(&snap, params.text_document_position)?; let position = from_proto::file_position(&snap, params.text_document_position)?;
let change = let mut change =
snap.analysis.rename(position, &*params.new_name)?.map_err(to_proto::rename_error)?; snap.analysis.rename(position, &*params.new_name)?.map_err(to_proto::rename_error)?;
// this is kind of a hack to prevent double edits from happening when moving files
// When a module gets renamed by renaming the mod declaration this causes the file to move
// which in turn will trigger a WillRenameFiles request to the server for which we reply with a
// a second identical set of renames, the client will then apply both edits causing incorrect edits
// with this we only emit source_file_edits in the WillRenameFiles response which will do the rename instead
// See https://github.com/microsoft/vscode-languageserver-node/issues/752 for more info
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)?; let workspace_edit = to_proto::workspace_edit(&snap, change)?;
Ok(Some(workspace_edit)) Ok(Some(workspace_edit))
} }