Skip to content

Commit 9bd9a17

Browse files
committed
Add a new config to allow renaming of non-local items
With rust-lang#15656 we started disallowing renaming of non-local items. Although this makes sense there are some false positives that impacted users' workflows. So this config aims to mitigate this by giving users the liberty to disable this feature.
1 parent 5b62ebc commit 9bd9a17

File tree

8 files changed

+65
-17
lines changed

8 files changed

+65
-17
lines changed

crates/ide-db/src/rename.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,17 @@ impl Definition {
7171
&self,
7272
sema: &Semantics<'_, RootDatabase>,
7373
new_name: &str,
74+
rename_external: bool,
7475
) -> Result<SourceChange> {
7576
// self.krate() returns None if
7677
// self is a built-in attr, built-in type or tool module.
7778
// it is not allowed for these defs to be renamed.
7879
// cases where self.krate() is None is handled below.
7980
if let Some(krate) = self.krate(sema.db) {
80-
if !krate.origin(sema.db).is_local() {
81-
bail!("Cannot rename a non-local definition.")
81+
// Can we not rename non-local items?
82+
// Then bail if non-local
83+
if !rename_external && !krate.origin(sema.db).is_local() {
84+
bail!("Cannot rename a non-local definition. Set `renameExternalItems` to `true` to allow renaming for this item.")
8285
}
8386
}
8487

crates/ide-diagnostics/src/handlers/incorrect_case.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Option<Vec<Ass
4343
let label = format!("Rename to {}", d.suggested_text);
4444
let mut res = unresolved_fix("change_case", &label, frange.range);
4545
if ctx.resolve.should_resolve(&res.id) {
46-
let source_change = def.rename(&ctx.sema, &d.suggested_text);
46+
let source_change = def.rename(&ctx.sema, &d.suggested_text, true);
4747
res.source_change = Some(source_change.ok().unwrap_or_default());
4848
}
4949

crates/ide/src/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -680,8 +680,9 @@ impl Analysis {
680680
&self,
681681
position: FilePosition,
682682
new_name: &str,
683+
rename_external: bool,
683684
) -> Cancellable<Result<SourceChange, RenameError>> {
684-
self.with_db(|db| rename::rename(db, position, new_name))
685+
self.with_db(|db| rename::rename(db, position, new_name, rename_external))
685686
}
686687

687688
pub fn prepare_rename(

crates/ide/src/rename.rs

+36-11
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ pub(crate) fn rename(
8484
db: &RootDatabase,
8585
position: FilePosition,
8686
new_name: &str,
87+
rename_external: bool,
8788
) -> RenameResult<SourceChange> {
8889
let sema = Semantics::new(db);
8990
let source_file = sema.parse(position.file_id);
@@ -103,7 +104,7 @@ pub(crate) fn rename(
103104
return rename_to_self(&sema, local);
104105
}
105106
}
106-
def.rename(&sema, new_name)
107+
def.rename(&sema, new_name, rename_external)
107108
})
108109
.collect();
109110

@@ -122,9 +123,9 @@ pub(crate) fn will_rename_file(
122123
let module = sema.to_module_def(file_id)?;
123124
let def = Definition::Module(module);
124125
let mut change = if is_raw_identifier(new_name_stem) {
125-
def.rename(&sema, &SmolStr::from_iter(["r#", new_name_stem])).ok()?
126+
def.rename(&sema, &SmolStr::from_iter(["r#", new_name_stem]), true).ok()?
126127
} else {
127-
def.rename(&sema, new_name_stem).ok()?
128+
def.rename(&sema, new_name_stem, true).ok()?
128129
};
129130
change.file_system_edits.clear();
130131
Some(change)
@@ -375,8 +376,17 @@ mod tests {
375376

376377
use super::{RangeInfo, RenameError};
377378

378-
#[track_caller]
379379
fn check(new_name: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
380+
check_with_rename_config(new_name, ra_fixture_before, ra_fixture_after, true);
381+
}
382+
383+
#[track_caller]
384+
fn check_with_rename_config(
385+
new_name: &str,
386+
ra_fixture_before: &str,
387+
ra_fixture_after: &str,
388+
rename_external: bool,
389+
) {
380390
let ra_fixture_after = &trim_indent(ra_fixture_after);
381391
let (analysis, position) = fixture::position(ra_fixture_before);
382392
if !ra_fixture_after.starts_with("error: ") {
@@ -385,7 +395,7 @@ mod tests {
385395
}
386396
}
387397
let rename_result = analysis
388-
.rename(position, new_name)
398+
.rename(position, new_name, rename_external)
389399
.unwrap_or_else(|err| panic!("Rename to '{new_name}' was cancelled: {err}"));
390400
match rename_result {
391401
Ok(source_change) => {
@@ -417,8 +427,10 @@ mod tests {
417427

418428
fn check_expect(new_name: &str, ra_fixture: &str, expect: Expect) {
419429
let (analysis, position) = fixture::position(ra_fixture);
420-
let source_change =
421-
analysis.rename(position, new_name).unwrap().expect("Expect returned a RenameError");
430+
let source_change = analysis
431+
.rename(position, new_name, true)
432+
.unwrap()
433+
.expect("Expect returned a RenameError");
422434
expect.assert_eq(&filter_expect(source_change))
423435
}
424436

@@ -2617,6 +2629,18 @@ use qux as frob;
26172629

26182630
#[test]
26192631
fn disallow_renaming_for_non_local_definition() {
2632+
check_with_rename_config(
2633+
"Baz",
2634+
r#"
2635+
//- /lib.rs crate:lib new_source_root:library
2636+
pub struct S;
2637+
//- /main.rs crate:main deps:lib new_source_root:local
2638+
use lib::S$0;
2639+
"#,
2640+
"error: Cannot rename a non-local definition. Set `renameExternalItems` to `true` to allow renaming for this item.",
2641+
false,
2642+
);
2643+
26202644
check(
26212645
"Baz",
26222646
r#"
@@ -2625,13 +2649,13 @@ pub struct S;
26252649
//- /main.rs crate:main deps:lib new_source_root:local
26262650
use lib::S$0;
26272651
"#,
2628-
"error: Cannot rename a non-local definition.",
2652+
"use lib::Baz;",
26292653
);
26302654
}
26312655

26322656
#[test]
26332657
fn disallow_renaming_for_builtin_macros() {
2634-
check(
2658+
check_with_rename_config(
26352659
"Baz",
26362660
r#"
26372661
//- minicore: derive, hash
@@ -2640,8 +2664,9 @@ use core::hash::Hash;
26402664
#[derive(H$0ash)]
26412665
struct A;
26422666
"#,
2643-
"error: Cannot rename a non-local definition.",
2644-
)
2667+
"error: Cannot rename a non-local definition. Set `renameExternalItems` to `true` to allow renaming for this item.",
2668+
false,
2669+
);
26452670
}
26462671

26472672
#[test]

crates/rust-analyzer/src/config.rs

+7
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,9 @@ config_data! {
494494
/// Exclude imports from find-all-references.
495495
references_excludeImports: bool = "false",
496496

497+
/// Allow renaming of items not belonging to any workspace crates.
498+
renameExternalItems_enable : bool = "false",
499+
497500
/// Command to be executed instead of 'cargo' for runnables.
498501
runnables_command: Option<String> = "null",
499502
/// Additional arguments to be passed to cargo for runnables such as
@@ -1739,6 +1742,10 @@ impl Config {
17391742
self.data.typing_autoClosingAngleBrackets_enable
17401743
}
17411744

1745+
pub fn rename(&self) -> bool {
1746+
self.data.renameExternalItems_enable
1747+
}
1748+
17421749
// FIXME: VSCode seems to work wrong sometimes, see https://github.com/microsoft/vscode/issues/193124
17431750
// hence, distinguish it for now.
17441751
pub fn is_visual_studio_code(&self) -> bool {

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

+4-2
Original file line numberDiff line numberDiff line change
@@ -1017,8 +1017,10 @@ pub(crate) fn handle_rename(
10171017
let _p = profile::span("handle_rename");
10181018
let position = from_proto::file_position(&snap, params.text_document_position)?;
10191019

1020-
let mut change =
1021-
snap.analysis.rename(position, &params.new_name)?.map_err(to_proto::rename_error)?;
1020+
let mut change = snap
1021+
.analysis
1022+
.rename(position, &params.new_name, snap.config.rename())?
1023+
.map_err(to_proto::rename_error)?;
10221024

10231025
// this is kind of a hack to prevent double edits from happening when moving files
10241026
// When a module gets renamed by renaming the mod declaration this causes the file to move

docs/user/generated_config.adoc

+5
Original file line numberDiff line numberDiff line change
@@ -777,6 +777,11 @@ Internal config, path to proc-macro server executable.
777777
--
778778
Exclude imports from find-all-references.
779779
--
780+
[[rust-analyzer.renameExternalItems.enable]]rust-analyzer.renameExternalItems.enable (default: `false`)::
781+
+
782+
--
783+
Allow renaming of items not belonging to any workspace crates.
784+
--
780785
[[rust-analyzer.runnables.command]]rust-analyzer.runnables.command (default: `null`)::
781786
+
782787
--

editors/code/package.json

+5
Original file line numberDiff line numberDiff line change
@@ -1503,6 +1503,11 @@
15031503
"default": false,
15041504
"type": "boolean"
15051505
},
1506+
"rust-analyzer.renameExternalItems.enable": {
1507+
"markdownDescription": "Allow renaming of items not belonging to any workspace crates.",
1508+
"default": false,
1509+
"type": "boolean"
1510+
},
15061511
"rust-analyzer.runnables.command": {
15071512
"markdownDescription": "Command to be executed instead of 'cargo' for runnables.",
15081513
"default": null,

0 commit comments

Comments
 (0)