diff options
-rw-r--r-- | crates/ide/src/references/rename.rs | 69 |
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 | ||
271 | fn rename_mod( | 274 | fn 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#" | ||
1698 | macro_rules! foo { | ||
1699 | ($pattern:pat) => { | ||
1700 | let $pattern = loop {}; | ||
1701 | }; | ||
1702 | } | ||
1703 | struct Foo { | ||
1704 | bar$0: u32, | ||
1705 | } | ||
1706 | fn foo() { | ||
1707 | foo!(Foo { bar: baz }); | ||
1708 | } | ||
1709 | "#, | ||
1710 | r#" | ||
1711 | macro_rules! foo { | ||
1712 | ($pattern:pat) => { | ||
1713 | let $pattern = loop {}; | ||
1714 | }; | ||
1715 | } | ||
1716 | struct Foo { | ||
1717 | baz: u32, | ||
1718 | } | ||
1719 | fn foo() { | ||
1720 | foo!(Foo { baz: baz }); | ||
1721 | } | ||
1722 | "#, | ||
1723 | ) | ||
1724 | } | ||
1688 | } | 1725 | } |