aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorLukas Wirth <[email protected]>2021-02-13 20:41:04 +0000
committerLukas Wirth <[email protected]>2021-02-13 20:41:04 +0000
commit9b045069241f3a610f5ee1ff448e6e8997b5f92f (patch)
tree65b0dd2e3a7309b3c5a87d2a98c640052ce36c61 /crates
parent1901172841c3986900633b4d216926f200fa35e5 (diff)
Fallback to renaming input NameRef node for macros when inside macro
Diffstat (limited to 'crates')
-rw-r--r--crates/ide/src/references/rename.rs69
1 files changed, 53 insertions, 16 deletions
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs
index 0e79fbe47..bbd9426b6 100644
--- a/crates/ide/src/references/rename.rs
+++ b/crates/ide/src/references/rename.rs
@@ -183,13 +183,16 @@ fn source_edit_from_references(
183) -> (FileId, TextEdit) { 183) -> (FileId, TextEdit) {
184 let mut edit = TextEdit::builder(); 184 let mut edit = TextEdit::builder();
185 for reference in references { 185 for reference in references {
186 let (range, replacement) = if let Some(name_ref) = reference.name.as_name_ref() { 186 match reference.name.as_name_ref() {
187 source_edit_from_name_ref(name_ref, new_name, def) 187 // if the ranges differ then the node is inside a macro call, we can't really attempt
188 } else { 188 // to make special rewrites like shorthand syntax and such, so just rename the node in
189 (None, new_name.to_owned()) 189 // the macro input
190 Some(name_ref) if name_ref.syntax().text_range() == reference.range => {
191 let (range, replacement) = source_edit_from_name_ref(name_ref, new_name, def);
192 edit.replace(range, replacement);
193 }
194 _ => edit.replace(reference.range, new_name.to_owned()),
190 }; 195 };
191 // FIXME: Some(range) will be incorrect when we are inside macros
192 edit.replace(range.unwrap_or(reference.range), replacement);
193 } 196 }
194 (file_id, edit.finish()) 197 (file_id, edit.finish())
195} 198}
@@ -198,7 +201,7 @@ fn source_edit_from_name_ref(
198 name_ref: &ast::NameRef, 201 name_ref: &ast::NameRef,
199 new_name: &str, 202 new_name: &str,
200 def: Definition, 203 def: Definition,
201) -> (Option<TextRange>, String) { 204) -> (TextRange, String) {
202 if let Some(record_field) = ast::RecordExprField::for_name_ref(name_ref) { 205 if let Some(record_field) = ast::RecordExprField::for_name_ref(name_ref) {
203 let rcf_name_ref = record_field.name_ref(); 206 let rcf_name_ref = record_field.name_ref();
204 let rcf_expr = record_field.expr(); 207 let rcf_expr = record_field.expr();
@@ -208,20 +211,20 @@ fn source_edit_from_name_ref(
208 if field_name == *name_ref { 211 if field_name == *name_ref {
209 if init.text() == new_name { 212 if init.text() == new_name {
210 mark::hit!(test_rename_field_put_init_shorthand); 213 mark::hit!(test_rename_field_put_init_shorthand);
211 // same names, we can use a shorthand here instead 214 // same names, we can use a shorthand here instead.
212 // we do not want to erase attributes hence this range start 215 // we do not want to erase attributes hence this range start
213 let s = field_name.syntax().text_range().start(); 216 let s = field_name.syntax().text_range().start();
214 let e = record_field.syntax().text_range().end(); 217 let e = record_field.syntax().text_range().end();
215 return (Some(TextRange::new(s, e)), format!("{}", new_name)); 218 return (TextRange::new(s, e), new_name.to_owned());
216 } 219 }
217 } else if init == *name_ref { 220 } else if init == *name_ref {
218 if field_name.text() == new_name { 221 if field_name.text() == new_name {
219 mark::hit!(test_rename_local_put_init_shorthand); 222 mark::hit!(test_rename_local_put_init_shorthand);
220 // same names, we can use a shorthand here instead 223 // same names, we can use a shorthand here instead.
221 // we do not want to erase attributes hence this range start 224 // we do not want to erase attributes hence this range start
222 let s = field_name.syntax().text_range().start(); 225 let s = field_name.syntax().text_range().start();
223 let e = record_field.syntax().text_range().end(); 226 let e = record_field.syntax().text_range().end();
224 return (Some(TextRange::new(s, e)), format!("{}", new_name)); 227 return (TextRange::new(s, e), new_name.to_owned());
225 } 228 }
226 } 229 }
227 } 230 }
@@ -233,12 +236,12 @@ fn source_edit_from_name_ref(
233 Definition::Field(_) => { 236 Definition::Field(_) => {
234 mark::hit!(test_rename_field_in_field_shorthand); 237 mark::hit!(test_rename_field_in_field_shorthand);
235 let s = name_ref.syntax().text_range().start(); 238 let s = name_ref.syntax().text_range().start();
236 return (Some(TextRange::empty(s)), format!("{}: ", new_name)); 239 return (TextRange::empty(s), format!("{}: ", new_name));
237 } 240 }
238 Definition::Local(_) => { 241 Definition::Local(_) => {
239 mark::hit!(test_rename_local_in_field_shorthand); 242 mark::hit!(test_rename_local_in_field_shorthand);
240 let s = name_ref.syntax().text_range().end(); 243 let s = name_ref.syntax().text_range().end();
241 return (Some(TextRange::empty(s)), format!(": {}", new_name)); 244 return (TextRange::empty(s), format!(": {}", new_name));
242 } 245 }
243 _ => {} 246 _ => {}
244 } 247 }
@@ -255,17 +258,17 @@ fn source_edit_from_name_ref(
255 // field name is being renamed 258 // field name is being renamed
256 if pat.name().map_or(false, |it| it.text() == new_name) { 259 if pat.name().map_or(false, |it| it.text() == new_name) {
257 mark::hit!(test_rename_field_put_init_shorthand_pat); 260 mark::hit!(test_rename_field_put_init_shorthand_pat);
258 // same names, we can use a shorthand here instead 261 // same names, we can use a shorthand here instead/
259 // we do not want to erase attributes hence this range start 262 // we do not want to erase attributes hence this range start
260 let s = field_name.syntax().text_range().start(); 263 let s = field_name.syntax().text_range().start();
261 let e = record_field.syntax().text_range().end(); 264 let e = record_field.syntax().text_range().end();
262 return (Some(TextRange::new(s, e)), format!("{}", new_name)); 265 return (TextRange::new(s, e), new_name.to_owned());
263 } 266 }
264 } 267 }
265 _ => {} 268 _ => {}
266 } 269 }
267 } 270 }
268 (None, format!("{}", new_name)) 271 (name_ref.syntax().text_range(), new_name.to_owned())
269} 272}
270 273
271fn rename_mod( 274fn rename_mod(
@@ -1685,4 +1688,38 @@ impl Foo {
1685"#, 1688"#,
1686 ) 1689 )
1687 } 1690 }
1691
1692 #[test]
1693 fn test_rename_field_in_pat_in_macro_doesnt_shorthand() {
1694 // ideally we would be able to make this emit a short hand, but I doubt this is easily possible
1695 check(
1696 "baz",
1697 r#"
1698macro_rules! foo {
1699 ($pattern:pat) => {
1700 let $pattern = loop {};
1701 };
1702}
1703struct Foo {
1704 bar$0: u32,
1705}
1706fn foo() {
1707 foo!(Foo { bar: baz });
1708}
1709"#,
1710 r#"
1711macro_rules! foo {
1712 ($pattern:pat) => {
1713 let $pattern = loop {};
1714 };
1715}
1716struct Foo {
1717 baz: u32,
1718}
1719fn foo() {
1720 foo!(Foo { baz: baz });
1721}
1722"#,
1723 )
1724 }
1688} 1725}