diff options
Diffstat (limited to 'crates/ide/src/references')
-rw-r--r-- | crates/ide/src/references/rename.rs | 1788 |
1 files changed, 0 insertions, 1788 deletions
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs deleted file mode 100644 index cec1d4552..000000000 --- a/crates/ide/src/references/rename.rs +++ /dev/null | |||
@@ -1,1788 +0,0 @@ | |||
1 | //! Renaming functionality | ||
2 | //! | ||
3 | //! All reference and file rename requests go through here where the corresponding [`SourceChange`]s | ||
4 | //! will be calculated. | ||
5 | use hir::{AsAssocItem, InFile, Semantics}; | ||
6 | use ide_db::{ | ||
7 | base_db::FileId, | ||
8 | defs::{Definition, NameClass, NameRefClass}, | ||
9 | rename::{bail, format_err, source_edit_from_references, IdentifierKind}, | ||
10 | RootDatabase, | ||
11 | }; | ||
12 | use stdx::never; | ||
13 | use syntax::{ast, AstNode, SyntaxNode}; | ||
14 | |||
15 | use text_edit::TextEdit; | ||
16 | |||
17 | use crate::{FilePosition, RangeInfo, SourceChange}; | ||
18 | |||
19 | pub use ide_db::rename::RenameError; | ||
20 | |||
21 | type RenameResult<T> = Result<T, RenameError>; | ||
22 | |||
23 | /// Prepares a rename. The sole job of this function is to return the TextRange of the thing that is | ||
24 | /// being targeted for a rename. | ||
25 | pub(crate) fn prepare_rename( | ||
26 | db: &RootDatabase, | ||
27 | position: FilePosition, | ||
28 | ) -> RenameResult<RangeInfo<()>> { | ||
29 | let sema = Semantics::new(db); | ||
30 | let source_file = sema.parse(position.file_id); | ||
31 | let syntax = source_file.syntax(); | ||
32 | |||
33 | let def = find_definition(&sema, syntax, position)?; | ||
34 | let frange = | ||
35 | def.rename_range(&sema).ok_or_else(|| format_err!("No references found at position"))?; | ||
36 | Ok(RangeInfo::new(frange.range, ())) | ||
37 | } | ||
38 | |||
39 | // Feature: Rename | ||
40 | // | ||
41 | // Renames the item below the cursor and all of its references | ||
42 | // | ||
43 | // |=== | ||
44 | // | Editor | Shortcut | ||
45 | // | ||
46 | // | VS Code | kbd:[F2] | ||
47 | // |=== | ||
48 | // | ||
49 | // image::https://user-images.githubusercontent.com/48062697/113065582-055aae80-91b1-11eb-8ade-2b58e6d81883.gif[] | ||
50 | pub(crate) fn rename( | ||
51 | db: &RootDatabase, | ||
52 | position: FilePosition, | ||
53 | new_name: &str, | ||
54 | ) -> RenameResult<SourceChange> { | ||
55 | let sema = Semantics::new(db); | ||
56 | rename_with_semantics(&sema, position, new_name) | ||
57 | } | ||
58 | |||
59 | pub(crate) fn rename_with_semantics( | ||
60 | sema: &Semantics<RootDatabase>, | ||
61 | position: FilePosition, | ||
62 | new_name: &str, | ||
63 | ) -> RenameResult<SourceChange> { | ||
64 | let source_file = sema.parse(position.file_id); | ||
65 | let syntax = source_file.syntax(); | ||
66 | |||
67 | let def = find_definition(sema, syntax, position)?; | ||
68 | |||
69 | if let Definition::Local(local) = def { | ||
70 | if let Some(self_param) = local.as_self_param(sema.db) { | ||
71 | cov_mark::hit!(rename_self_to_param); | ||
72 | return rename_self_to_param(sema, local, self_param, new_name); | ||
73 | } | ||
74 | if new_name == "self" { | ||
75 | cov_mark::hit!(rename_to_self); | ||
76 | return rename_to_self(sema, local); | ||
77 | } | ||
78 | } | ||
79 | |||
80 | def.rename(sema, new_name) | ||
81 | } | ||
82 | |||
83 | /// Called by the client when it is about to rename a file. | ||
84 | pub(crate) fn will_rename_file( | ||
85 | db: &RootDatabase, | ||
86 | file_id: FileId, | ||
87 | new_name_stem: &str, | ||
88 | ) -> Option<SourceChange> { | ||
89 | let sema = Semantics::new(db); | ||
90 | let module = sema.to_module_def(file_id)?; | ||
91 | let def = Definition::ModuleDef(module.into()); | ||
92 | let mut change = def.rename(&sema, new_name_stem).ok()?; | ||
93 | change.file_system_edits.clear(); | ||
94 | Some(change) | ||
95 | } | ||
96 | |||
97 | fn find_definition( | ||
98 | sema: &Semantics<RootDatabase>, | ||
99 | syntax: &SyntaxNode, | ||
100 | position: FilePosition, | ||
101 | ) -> RenameResult<Definition> { | ||
102 | match sema | ||
103 | .find_node_at_offset_with_descend(syntax, position.offset) | ||
104 | .ok_or_else(|| format_err!("No references found at position"))? | ||
105 | { | ||
106 | // renaming aliases would rename the item being aliased as the HIR doesn't track aliases yet | ||
107 | ast::NameLike::Name(name) | ||
108 | if name.syntax().parent().map_or(false, |it| ast::Rename::can_cast(it.kind())) => | ||
109 | { | ||
110 | bail!("Renaming aliases is currently unsupported") | ||
111 | } | ||
112 | ast::NameLike::Name(name) => { | ||
113 | NameClass::classify(sema, &name).map(|class| class.referenced_or_defined(sema.db)) | ||
114 | } | ||
115 | ast::NameLike::NameRef(name_ref) => { | ||
116 | if let Some(def) = | ||
117 | NameRefClass::classify(sema, &name_ref).map(|class| class.referenced(sema.db)) | ||
118 | { | ||
119 | // if the name differs from the definitions name it has to be an alias | ||
120 | if def.name(sema.db).map_or(false, |it| it.to_string() != name_ref.text()) { | ||
121 | bail!("Renaming aliases is currently unsupported"); | ||
122 | } | ||
123 | Some(def) | ||
124 | } else { | ||
125 | None | ||
126 | } | ||
127 | } | ||
128 | ast::NameLike::Lifetime(lifetime) => NameRefClass::classify_lifetime(sema, &lifetime) | ||
129 | .map(|class| NameRefClass::referenced(class, sema.db)) | ||
130 | .or_else(|| { | ||
131 | NameClass::classify_lifetime(sema, &lifetime) | ||
132 | .map(|it| it.referenced_or_defined(sema.db)) | ||
133 | }), | ||
134 | } | ||
135 | .ok_or_else(|| format_err!("No references found at position")) | ||
136 | } | ||
137 | |||
138 | fn rename_to_self(sema: &Semantics<RootDatabase>, local: hir::Local) -> RenameResult<SourceChange> { | ||
139 | if never!(local.is_self(sema.db)) { | ||
140 | bail!("rename_to_self invoked on self"); | ||
141 | } | ||
142 | |||
143 | let fn_def = match local.parent(sema.db) { | ||
144 | hir::DefWithBody::Function(func) => func, | ||
145 | _ => bail!("Cannot rename local to self outside of function"), | ||
146 | }; | ||
147 | |||
148 | if let Some(_) = fn_def.self_param(sema.db) { | ||
149 | bail!("Method already has a self parameter"); | ||
150 | } | ||
151 | |||
152 | let params = fn_def.assoc_fn_params(sema.db); | ||
153 | let first_param = params | ||
154 | .first() | ||
155 | .ok_or_else(|| format_err!("Cannot rename local to self unless it is a parameter"))?; | ||
156 | if first_param.as_local(sema.db) != local { | ||
157 | bail!("Only the first parameter may be renamed to self"); | ||
158 | } | ||
159 | |||
160 | let assoc_item = fn_def | ||
161 | .as_assoc_item(sema.db) | ||
162 | .ok_or_else(|| format_err!("Cannot rename parameter to self for free function"))?; | ||
163 | let impl_ = match assoc_item.container(sema.db) { | ||
164 | hir::AssocItemContainer::Trait(_) => { | ||
165 | bail!("Cannot rename parameter to self for trait functions"); | ||
166 | } | ||
167 | hir::AssocItemContainer::Impl(impl_) => impl_, | ||
168 | }; | ||
169 | let first_param_ty = first_param.ty(); | ||
170 | let impl_ty = impl_.self_ty(sema.db); | ||
171 | let (ty, self_param) = if impl_ty.remove_ref().is_some() { | ||
172 | // if the impl is a ref to the type we can just match the `&T` with self directly | ||
173 | (first_param_ty.clone(), "self") | ||
174 | } else { | ||
175 | first_param_ty.remove_ref().map_or((first_param_ty.clone(), "self"), |ty| { | ||
176 | (ty, if first_param_ty.is_mutable_reference() { "&mut self" } else { "&self" }) | ||
177 | }) | ||
178 | }; | ||
179 | |||
180 | if ty != impl_ty { | ||
181 | bail!("Parameter type differs from impl block type"); | ||
182 | } | ||
183 | |||
184 | let InFile { file_id, value: param_source } = | ||
185 | first_param.source(sema.db).ok_or_else(|| format_err!("No source for parameter found"))?; | ||
186 | |||
187 | let def = Definition::Local(local); | ||
188 | let usages = def.usages(sema).all(); | ||
189 | let mut source_change = SourceChange::default(); | ||
190 | source_change.extend(usages.iter().map(|(&file_id, references)| { | ||
191 | (file_id, source_edit_from_references(references, def, "self")) | ||
192 | })); | ||
193 | source_change.insert_source_edit( | ||
194 | file_id.original_file(sema.db), | ||
195 | TextEdit::replace(param_source.syntax().text_range(), String::from(self_param)), | ||
196 | ); | ||
197 | Ok(source_change) | ||
198 | } | ||
199 | |||
200 | fn rename_self_to_param( | ||
201 | sema: &Semantics<RootDatabase>, | ||
202 | local: hir::Local, | ||
203 | self_param: hir::SelfParam, | ||
204 | new_name: &str, | ||
205 | ) -> RenameResult<SourceChange> { | ||
206 | if new_name == "self" { | ||
207 | // Let's do nothing rather than complain. | ||
208 | cov_mark::hit!(rename_self_to_self); | ||
209 | return Ok(SourceChange::default()); | ||
210 | } | ||
211 | |||
212 | let identifier_kind = IdentifierKind::classify(new_name)?; | ||
213 | |||
214 | let InFile { file_id, value: self_param } = | ||
215 | self_param.source(sema.db).ok_or_else(|| format_err!("cannot find function source"))?; | ||
216 | |||
217 | let def = Definition::Local(local); | ||
218 | let usages = def.usages(sema).all(); | ||
219 | let edit = text_edit_from_self_param(&self_param, new_name) | ||
220 | .ok_or_else(|| format_err!("No target type found"))?; | ||
221 | if usages.len() > 1 && identifier_kind == IdentifierKind::Underscore { | ||
222 | bail!("Cannot rename reference to `_` as it is being referenced multiple times"); | ||
223 | } | ||
224 | let mut source_change = SourceChange::default(); | ||
225 | source_change.insert_source_edit(file_id.original_file(sema.db), edit); | ||
226 | source_change.extend(usages.iter().map(|(&file_id, references)| { | ||
227 | (file_id, source_edit_from_references(references, def, new_name)) | ||
228 | })); | ||
229 | Ok(source_change) | ||
230 | } | ||
231 | |||
232 | fn text_edit_from_self_param(self_param: &ast::SelfParam, new_name: &str) -> Option<TextEdit> { | ||
233 | fn target_type_name(impl_def: &ast::Impl) -> Option<String> { | ||
234 | if let Some(ast::Type::PathType(p)) = impl_def.self_ty() { | ||
235 | return Some(p.path()?.segment()?.name_ref()?.text().to_string()); | ||
236 | } | ||
237 | None | ||
238 | } | ||
239 | |||
240 | let impl_def = self_param.syntax().ancestors().find_map(ast::Impl::cast)?; | ||
241 | let type_name = target_type_name(&impl_def)?; | ||
242 | |||
243 | let mut replacement_text = String::from(new_name); | ||
244 | replacement_text.push_str(": "); | ||
245 | match (self_param.amp_token(), self_param.mut_token()) { | ||
246 | (Some(_), None) => replacement_text.push('&'), | ||
247 | (Some(_), Some(_)) => replacement_text.push_str("&mut "), | ||
248 | (_, _) => (), | ||
249 | }; | ||
250 | replacement_text.push_str(type_name.as_str()); | ||
251 | |||
252 | Some(TextEdit::replace(self_param.syntax().text_range(), replacement_text)) | ||
253 | } | ||
254 | |||
255 | #[cfg(test)] | ||
256 | mod tests { | ||
257 | use expect_test::{expect, Expect}; | ||
258 | use stdx::trim_indent; | ||
259 | use test_utils::assert_eq_text; | ||
260 | use text_edit::TextEdit; | ||
261 | |||
262 | use crate::{fixture, FileId}; | ||
263 | |||
264 | use super::{RangeInfo, RenameError}; | ||
265 | |||
266 | fn check(new_name: &str, ra_fixture_before: &str, ra_fixture_after: &str) { | ||
267 | let ra_fixture_after = &trim_indent(ra_fixture_after); | ||
268 | let (analysis, position) = fixture::position(ra_fixture_before); | ||
269 | let rename_result = analysis | ||
270 | .rename(position, new_name) | ||
271 | .unwrap_or_else(|err| panic!("Rename to '{}' was cancelled: {}", new_name, err)); | ||
272 | match rename_result { | ||
273 | Ok(source_change) => { | ||
274 | let mut text_edit_builder = TextEdit::builder(); | ||
275 | let mut file_id: Option<FileId> = None; | ||
276 | for edit in source_change.source_file_edits { | ||
277 | file_id = Some(edit.0); | ||
278 | for indel in edit.1.into_iter() { | ||
279 | text_edit_builder.replace(indel.delete, indel.insert); | ||
280 | } | ||
281 | } | ||
282 | if let Some(file_id) = file_id { | ||
283 | let mut result = analysis.file_text(file_id).unwrap().to_string(); | ||
284 | text_edit_builder.finish().apply(&mut result); | ||
285 | assert_eq_text!(ra_fixture_after, &*result); | ||
286 | } | ||
287 | } | ||
288 | Err(err) => { | ||
289 | if ra_fixture_after.starts_with("error:") { | ||
290 | let error_message = ra_fixture_after | ||
291 | .chars() | ||
292 | .into_iter() | ||
293 | .skip("error:".len()) | ||
294 | .collect::<String>(); | ||
295 | assert_eq!(error_message.trim(), err.to_string()); | ||
296 | return; | ||
297 | } else { | ||
298 | panic!("Rename to '{}' failed unexpectedly: {}", new_name, err) | ||
299 | } | ||
300 | } | ||
301 | }; | ||
302 | } | ||
303 | |||
304 | fn check_expect(new_name: &str, ra_fixture: &str, expect: Expect) { | ||
305 | let (analysis, position) = fixture::position(ra_fixture); | ||
306 | let source_change = | ||
307 | analysis.rename(position, new_name).unwrap().expect("Expect returned a RenameError"); | ||
308 | expect.assert_debug_eq(&source_change) | ||
309 | } | ||
310 | |||
311 | fn check_prepare(ra_fixture: &str, expect: Expect) { | ||
312 | let (analysis, position) = fixture::position(ra_fixture); | ||
313 | let result = analysis | ||
314 | .prepare_rename(position) | ||
315 | .unwrap_or_else(|err| panic!("PrepareRename was cancelled: {}", err)); | ||
316 | match result { | ||
317 | Ok(RangeInfo { range, info: () }) => { | ||
318 | let source = analysis.file_text(position.file_id).unwrap(); | ||
319 | expect.assert_eq(&format!("{:?}: {}", range, &source[range])) | ||
320 | } | ||
321 | Err(RenameError(err)) => expect.assert_eq(&err), | ||
322 | }; | ||
323 | } | ||
324 | |||
325 | #[test] | ||
326 | fn test_prepare_rename_namelikes() { | ||
327 | check_prepare(r"fn name$0<'lifetime>() {}", expect![[r#"3..7: name"#]]); | ||
328 | check_prepare(r"fn name<'lifetime$0>() {}", expect![[r#"8..17: 'lifetime"#]]); | ||
329 | check_prepare(r"fn name<'lifetime>() { name$0(); }", expect![[r#"3..7: name"#]]); | ||
330 | } | ||
331 | |||
332 | #[test] | ||
333 | fn test_prepare_rename_in_macro() { | ||
334 | check_prepare( | ||
335 | r"macro_rules! foo { | ||
336 | ($ident:ident) => { | ||
337 | pub struct $ident; | ||
338 | } | ||
339 | } | ||
340 | foo!(Foo$0);", | ||
341 | expect![[r#"83..86: Foo"#]], | ||
342 | ); | ||
343 | } | ||
344 | |||
345 | #[test] | ||
346 | fn test_prepare_rename_keyword() { | ||
347 | check_prepare(r"struct$0 Foo;", expect![[r#"No references found at position"#]]); | ||
348 | } | ||
349 | |||
350 | #[test] | ||
351 | fn test_prepare_rename_tuple_field() { | ||
352 | check_prepare( | ||
353 | r#" | ||
354 | struct Foo(i32); | ||
355 | |||
356 | fn baz() { | ||
357 | let mut x = Foo(4); | ||
358 | x.0$0 = 5; | ||
359 | } | ||
360 | "#, | ||
361 | expect![[r#"No references found at position"#]], | ||
362 | ); | ||
363 | } | ||
364 | |||
365 | #[test] | ||
366 | fn test_prepare_rename_builtin() { | ||
367 | check_prepare( | ||
368 | r#" | ||
369 | fn foo() { | ||
370 | let x: i32$0 = 0; | ||
371 | } | ||
372 | "#, | ||
373 | expect![[r#"No references found at position"#]], | ||
374 | ); | ||
375 | } | ||
376 | |||
377 | #[test] | ||
378 | fn test_prepare_rename_self() { | ||
379 | check_prepare( | ||
380 | r#" | ||
381 | struct Foo {} | ||
382 | |||
383 | impl Foo { | ||
384 | fn foo(self) -> Self$0 { | ||
385 | self | ||
386 | } | ||
387 | } | ||
388 | "#, | ||
389 | expect![[r#"No references found at position"#]], | ||
390 | ); | ||
391 | } | ||
392 | |||
393 | #[test] | ||
394 | fn test_rename_to_underscore() { | ||
395 | check("_", r#"fn main() { let i$0 = 1; }"#, r#"fn main() { let _ = 1; }"#); | ||
396 | } | ||
397 | |||
398 | #[test] | ||
399 | fn test_rename_to_raw_identifier() { | ||
400 | check("r#fn", r#"fn main() { let i$0 = 1; }"#, r#"fn main() { let r#fn = 1; }"#); | ||
401 | } | ||
402 | |||
403 | #[test] | ||
404 | fn test_rename_to_invalid_identifier1() { | ||
405 | check( | ||
406 | "invalid!", | ||
407 | r#"fn main() { let i$0 = 1; }"#, | ||
408 | "error: Invalid name `invalid!`: not an identifier", | ||
409 | ); | ||
410 | } | ||
411 | |||
412 | #[test] | ||
413 | fn test_rename_to_invalid_identifier2() { | ||
414 | check( | ||
415 | "multiple tokens", | ||
416 | r#"fn main() { let i$0 = 1; }"#, | ||
417 | "error: Invalid name `multiple tokens`: not an identifier", | ||
418 | ); | ||
419 | } | ||
420 | |||
421 | #[test] | ||
422 | fn test_rename_to_invalid_identifier3() { | ||
423 | check( | ||
424 | "let", | ||
425 | r#"fn main() { let i$0 = 1; }"#, | ||
426 | "error: Invalid name `let`: not an identifier", | ||
427 | ); | ||
428 | } | ||
429 | |||
430 | #[test] | ||
431 | fn test_rename_to_invalid_identifier_lifetime() { | ||
432 | cov_mark::check!(rename_not_an_ident_ref); | ||
433 | check( | ||
434 | "'foo", | ||
435 | r#"fn main() { let i$0 = 1; }"#, | ||
436 | "error: Invalid name `'foo`: not an identifier", | ||
437 | ); | ||
438 | } | ||
439 | |||
440 | #[test] | ||
441 | fn test_rename_to_invalid_identifier_lifetime2() { | ||
442 | cov_mark::check!(rename_not_a_lifetime_ident_ref); | ||
443 | check( | ||
444 | "foo", | ||
445 | r#"fn main<'a>(_: &'a$0 ()) {}"#, | ||
446 | "error: Invalid name `foo`: not a lifetime identifier", | ||
447 | ); | ||
448 | } | ||
449 | |||
450 | #[test] | ||
451 | fn test_rename_to_underscore_invalid() { | ||
452 | cov_mark::check!(rename_underscore_multiple); | ||
453 | check( | ||
454 | "_", | ||
455 | r#"fn main(foo$0: ()) {foo;}"#, | ||
456 | "error: Cannot rename reference to `_` as it is being referenced multiple times", | ||
457 | ); | ||
458 | } | ||
459 | |||
460 | #[test] | ||
461 | fn test_rename_mod_invalid() { | ||
462 | check( | ||
463 | "'foo", | ||
464 | r#"mod foo$0 {}"#, | ||
465 | "error: Invalid name `'foo`: cannot rename module to 'foo", | ||
466 | ); | ||
467 | } | ||
468 | |||
469 | #[test] | ||
470 | fn test_rename_for_local() { | ||
471 | check( | ||
472 | "k", | ||
473 | r#" | ||
474 | fn main() { | ||
475 | let mut i = 1; | ||
476 | let j = 1; | ||
477 | i = i$0 + j; | ||
478 | |||
479 | { i = 0; } | ||
480 | |||
481 | i = 5; | ||
482 | } | ||
483 | "#, | ||
484 | r#" | ||
485 | fn main() { | ||
486 | let mut k = 1; | ||
487 | let j = 1; | ||
488 | k = k + j; | ||
489 | |||
490 | { k = 0; } | ||
491 | |||
492 | k = 5; | ||
493 | } | ||
494 | "#, | ||
495 | ); | ||
496 | } | ||
497 | |||
498 | #[test] | ||
499 | fn test_rename_unresolved_reference() { | ||
500 | check( | ||
501 | "new_name", | ||
502 | r#"fn main() { let _ = unresolved_ref$0; }"#, | ||
503 | "error: No references found at position", | ||
504 | ); | ||
505 | } | ||
506 | |||
507 | #[test] | ||
508 | fn test_rename_for_macro_args() { | ||
509 | check( | ||
510 | "b", | ||
511 | r#" | ||
512 | macro_rules! foo {($i:ident) => {$i} } | ||
513 | fn main() { | ||
514 | let a$0 = "test"; | ||
515 | foo!(a); | ||
516 | } | ||
517 | "#, | ||
518 | r#" | ||
519 | macro_rules! foo {($i:ident) => {$i} } | ||
520 | fn main() { | ||
521 | let b = "test"; | ||
522 | foo!(b); | ||
523 | } | ||
524 | "#, | ||
525 | ); | ||
526 | } | ||
527 | |||
528 | #[test] | ||
529 | fn test_rename_for_macro_args_rev() { | ||
530 | check( | ||
531 | "b", | ||
532 | r#" | ||
533 | macro_rules! foo {($i:ident) => {$i} } | ||
534 | fn main() { | ||
535 | let a = "test"; | ||
536 | foo!(a$0); | ||
537 | } | ||
538 | "#, | ||
539 | r#" | ||
540 | macro_rules! foo {($i:ident) => {$i} } | ||
541 | fn main() { | ||
542 | let b = "test"; | ||
543 | foo!(b); | ||
544 | } | ||
545 | "#, | ||
546 | ); | ||
547 | } | ||
548 | |||
549 | #[test] | ||
550 | fn test_rename_for_macro_define_fn() { | ||
551 | check( | ||
552 | "bar", | ||
553 | r#" | ||
554 | macro_rules! define_fn {($id:ident) => { fn $id{} }} | ||
555 | define_fn!(foo); | ||
556 | fn main() { | ||
557 | fo$0o(); | ||
558 | } | ||
559 | "#, | ||
560 | r#" | ||
561 | macro_rules! define_fn {($id:ident) => { fn $id{} }} | ||
562 | define_fn!(bar); | ||
563 | fn main() { | ||
564 | bar(); | ||
565 | } | ||
566 | "#, | ||
567 | ); | ||
568 | } | ||
569 | |||
570 | #[test] | ||
571 | fn test_rename_for_macro_define_fn_rev() { | ||
572 | check( | ||
573 | "bar", | ||
574 | r#" | ||
575 | macro_rules! define_fn {($id:ident) => { fn $id{} }} | ||
576 | define_fn!(fo$0o); | ||
577 | fn main() { | ||
578 | foo(); | ||
579 | } | ||
580 | "#, | ||
581 | r#" | ||
582 | macro_rules! define_fn {($id:ident) => { fn $id{} }} | ||
583 | define_fn!(bar); | ||
584 | fn main() { | ||
585 | bar(); | ||
586 | } | ||
587 | "#, | ||
588 | ); | ||
589 | } | ||
590 | |||
591 | #[test] | ||
592 | fn test_rename_for_param_inside() { | ||
593 | check("j", r#"fn foo(i : u32) -> u32 { i$0 }"#, r#"fn foo(j : u32) -> u32 { j }"#); | ||
594 | } | ||
595 | |||
596 | #[test] | ||
597 | fn test_rename_refs_for_fn_param() { | ||
598 | check("j", r#"fn foo(i$0 : u32) -> u32 { i }"#, r#"fn foo(j : u32) -> u32 { j }"#); | ||
599 | } | ||
600 | |||
601 | #[test] | ||
602 | fn test_rename_for_mut_param() { | ||
603 | check("j", r#"fn foo(mut i$0 : u32) -> u32 { i }"#, r#"fn foo(mut j : u32) -> u32 { j }"#); | ||
604 | } | ||
605 | |||
606 | #[test] | ||
607 | fn test_rename_struct_field() { | ||
608 | check( | ||
609 | "j", | ||
610 | r#" | ||
611 | struct Foo { i$0: i32 } | ||
612 | |||
613 | impl Foo { | ||
614 | fn new(i: i32) -> Self { | ||
615 | Self { i: i } | ||
616 | } | ||
617 | } | ||
618 | "#, | ||
619 | r#" | ||
620 | struct Foo { j: i32 } | ||
621 | |||
622 | impl Foo { | ||
623 | fn new(i: i32) -> Self { | ||
624 | Self { j: i } | ||
625 | } | ||
626 | } | ||
627 | "#, | ||
628 | ); | ||
629 | } | ||
630 | |||
631 | #[test] | ||
632 | fn test_rename_field_in_field_shorthand() { | ||
633 | cov_mark::check!(test_rename_field_in_field_shorthand); | ||
634 | check( | ||
635 | "j", | ||
636 | r#" | ||
637 | struct Foo { i$0: i32 } | ||
638 | |||
639 | impl Foo { | ||
640 | fn new(i: i32) -> Self { | ||
641 | Self { i } | ||
642 | } | ||
643 | } | ||
644 | "#, | ||
645 | r#" | ||
646 | struct Foo { j: i32 } | ||
647 | |||
648 | impl Foo { | ||
649 | fn new(i: i32) -> Self { | ||
650 | Self { j: i } | ||
651 | } | ||
652 | } | ||
653 | "#, | ||
654 | ); | ||
655 | } | ||
656 | |||
657 | #[test] | ||
658 | fn test_rename_local_in_field_shorthand() { | ||
659 | cov_mark::check!(test_rename_local_in_field_shorthand); | ||
660 | check( | ||
661 | "j", | ||
662 | r#" | ||
663 | struct Foo { i: i32 } | ||
664 | |||
665 | impl Foo { | ||
666 | fn new(i$0: i32) -> Self { | ||
667 | Self { i } | ||
668 | } | ||
669 | } | ||
670 | "#, | ||
671 | r#" | ||
672 | struct Foo { i: i32 } | ||
673 | |||
674 | impl Foo { | ||
675 | fn new(j: i32) -> Self { | ||
676 | Self { i: j } | ||
677 | } | ||
678 | } | ||
679 | "#, | ||
680 | ); | ||
681 | } | ||
682 | |||
683 | #[test] | ||
684 | fn test_field_shorthand_correct_struct() { | ||
685 | check( | ||
686 | "j", | ||
687 | r#" | ||
688 | struct Foo { i$0: i32 } | ||
689 | struct Bar { i: i32 } | ||
690 | |||
691 | impl Bar { | ||
692 | fn new(i: i32) -> Self { | ||
693 | Self { i } | ||
694 | } | ||
695 | } | ||
696 | "#, | ||
697 | r#" | ||
698 | struct Foo { j: i32 } | ||
699 | struct Bar { i: i32 } | ||
700 | |||
701 | impl Bar { | ||
702 | fn new(i: i32) -> Self { | ||
703 | Self { i } | ||
704 | } | ||
705 | } | ||
706 | "#, | ||
707 | ); | ||
708 | } | ||
709 | |||
710 | #[test] | ||
711 | fn test_shadow_local_for_struct_shorthand() { | ||
712 | check( | ||
713 | "j", | ||
714 | r#" | ||
715 | struct Foo { i: i32 } | ||
716 | |||
717 | fn baz(i$0: i32) -> Self { | ||
718 | let x = Foo { i }; | ||
719 | { | ||
720 | let i = 0; | ||
721 | Foo { i } | ||
722 | } | ||
723 | } | ||
724 | "#, | ||
725 | r#" | ||
726 | struct Foo { i: i32 } | ||
727 | |||
728 | fn baz(j: i32) -> Self { | ||
729 | let x = Foo { i: j }; | ||
730 | { | ||
731 | let i = 0; | ||
732 | Foo { i } | ||
733 | } | ||
734 | } | ||
735 | "#, | ||
736 | ); | ||
737 | } | ||
738 | |||
739 | #[test] | ||
740 | fn test_rename_mod() { | ||
741 | check_expect( | ||
742 | "foo2", | ||
743 | r#" | ||
744 | //- /lib.rs | ||
745 | mod bar; | ||
746 | |||
747 | //- /bar.rs | ||
748 | mod foo$0; | ||
749 | |||
750 | //- /bar/foo.rs | ||
751 | // empty | ||
752 | "#, | ||
753 | expect![[r#" | ||
754 | SourceChange { | ||
755 | source_file_edits: { | ||
756 | FileId( | ||
757 | 1, | ||
758 | ): TextEdit { | ||
759 | indels: [ | ||
760 | Indel { | ||
761 | insert: "foo2", | ||
762 | delete: 4..7, | ||
763 | }, | ||
764 | ], | ||
765 | }, | ||
766 | }, | ||
767 | file_system_edits: [ | ||
768 | MoveFile { | ||
769 | src: FileId( | ||
770 | 2, | ||
771 | ), | ||
772 | dst: AnchoredPathBuf { | ||
773 | anchor: FileId( | ||
774 | 2, | ||
775 | ), | ||
776 | path: "foo2.rs", | ||
777 | }, | ||
778 | }, | ||
779 | ], | ||
780 | is_snippet: false, | ||
781 | } | ||
782 | "#]], | ||
783 | ); | ||
784 | } | ||
785 | |||
786 | #[test] | ||
787 | fn test_rename_mod_in_use_tree() { | ||
788 | check_expect( | ||
789 | "quux", | ||
790 | r#" | ||
791 | //- /main.rs | ||
792 | pub mod foo; | ||
793 | pub mod bar; | ||
794 | fn main() {} | ||
795 | |||
796 | //- /foo.rs | ||
797 | pub struct FooContent; | ||
798 | |||
799 | //- /bar.rs | ||
800 | use crate::foo$0::FooContent; | ||
801 | "#, | ||
802 | expect![[r#" | ||
803 | SourceChange { | ||
804 | source_file_edits: { | ||
805 | FileId( | ||
806 | 0, | ||
807 | ): TextEdit { | ||
808 | indels: [ | ||
809 | Indel { | ||
810 | insert: "quux", | ||
811 | delete: 8..11, | ||
812 | }, | ||
813 | ], | ||
814 | }, | ||
815 | FileId( | ||
816 | 2, | ||
817 | ): TextEdit { | ||
818 | indels: [ | ||
819 | Indel { | ||
820 | insert: "quux", | ||
821 | delete: 11..14, | ||
822 | }, | ||
823 | ], | ||
824 | }, | ||
825 | }, | ||
826 | file_system_edits: [ | ||
827 | MoveFile { | ||
828 | src: FileId( | ||
829 | 1, | ||
830 | ), | ||
831 | dst: AnchoredPathBuf { | ||
832 | anchor: FileId( | ||
833 | 1, | ||
834 | ), | ||
835 | path: "quux.rs", | ||
836 | }, | ||
837 | }, | ||
838 | ], | ||
839 | is_snippet: false, | ||
840 | } | ||
841 | "#]], | ||
842 | ); | ||
843 | } | ||
844 | |||
845 | #[test] | ||
846 | fn test_rename_mod_in_dir() { | ||
847 | check_expect( | ||
848 | "foo2", | ||
849 | r#" | ||
850 | //- /lib.rs | ||
851 | mod fo$0o; | ||
852 | //- /foo/mod.rs | ||
853 | // empty | ||
854 | "#, | ||
855 | expect![[r#" | ||
856 | SourceChange { | ||
857 | source_file_edits: { | ||
858 | FileId( | ||
859 | 0, | ||
860 | ): TextEdit { | ||
861 | indels: [ | ||
862 | Indel { | ||
863 | insert: "foo2", | ||
864 | delete: 4..7, | ||
865 | }, | ||
866 | ], | ||
867 | }, | ||
868 | }, | ||
869 | file_system_edits: [ | ||
870 | MoveFile { | ||
871 | src: FileId( | ||
872 | 1, | ||
873 | ), | ||
874 | dst: AnchoredPathBuf { | ||
875 | anchor: FileId( | ||
876 | 1, | ||
877 | ), | ||
878 | path: "../foo2/mod.rs", | ||
879 | }, | ||
880 | }, | ||
881 | ], | ||
882 | is_snippet: false, | ||
883 | } | ||
884 | "#]], | ||
885 | ); | ||
886 | } | ||
887 | |||
888 | #[test] | ||
889 | fn test_rename_unusually_nested_mod() { | ||
890 | check_expect( | ||
891 | "bar", | ||
892 | r#" | ||
893 | //- /lib.rs | ||
894 | mod outer { mod fo$0o; } | ||
895 | |||
896 | //- /outer/foo.rs | ||
897 | // empty | ||
898 | "#, | ||
899 | expect![[r#" | ||
900 | SourceChange { | ||
901 | source_file_edits: { | ||
902 | FileId( | ||
903 | 0, | ||
904 | ): TextEdit { | ||
905 | indels: [ | ||
906 | Indel { | ||
907 | insert: "bar", | ||
908 | delete: 16..19, | ||
909 | }, | ||
910 | ], | ||
911 | }, | ||
912 | }, | ||
913 | file_system_edits: [ | ||
914 | MoveFile { | ||
915 | src: FileId( | ||
916 | 1, | ||
917 | ), | ||
918 | dst: AnchoredPathBuf { | ||
919 | anchor: FileId( | ||
920 | 1, | ||
921 | ), | ||
922 | path: "bar.rs", | ||
923 | }, | ||
924 | }, | ||
925 | ], | ||
926 | is_snippet: false, | ||
927 | } | ||
928 | "#]], | ||
929 | ); | ||
930 | } | ||
931 | |||
932 | #[test] | ||
933 | fn test_module_rename_in_path() { | ||
934 | check( | ||
935 | "baz", | ||
936 | r#" | ||
937 | mod $0foo { pub fn bar() {} } | ||
938 | |||
939 | fn main() { foo::bar(); } | ||
940 | "#, | ||
941 | r#" | ||
942 | mod baz { pub fn bar() {} } | ||
943 | |||
944 | fn main() { baz::bar(); } | ||
945 | "#, | ||
946 | ); | ||
947 | } | ||
948 | |||
949 | #[test] | ||
950 | fn test_rename_mod_filename_and_path() { | ||
951 | check_expect( | ||
952 | "foo2", | ||
953 | r#" | ||
954 | //- /lib.rs | ||
955 | mod bar; | ||
956 | fn f() { | ||
957 | bar::foo::fun() | ||
958 | } | ||
959 | |||
960 | //- /bar.rs | ||
961 | pub mod foo$0; | ||
962 | |||
963 | //- /bar/foo.rs | ||
964 | // pub fn fun() {} | ||
965 | "#, | ||
966 | expect![[r#" | ||
967 | SourceChange { | ||
968 | source_file_edits: { | ||
969 | FileId( | ||
970 | 0, | ||
971 | ): TextEdit { | ||
972 | indels: [ | ||
973 | Indel { | ||
974 | insert: "foo2", | ||
975 | delete: 27..30, | ||
976 | }, | ||
977 | ], | ||
978 | }, | ||
979 | FileId( | ||
980 | 1, | ||
981 | ): TextEdit { | ||
982 | indels: [ | ||
983 | Indel { | ||
984 | insert: "foo2", | ||
985 | delete: 8..11, | ||
986 | }, | ||
987 | ], | ||
988 | }, | ||
989 | }, | ||
990 | file_system_edits: [ | ||
991 | MoveFile { | ||
992 | src: FileId( | ||
993 | 2, | ||
994 | ), | ||
995 | dst: AnchoredPathBuf { | ||
996 | anchor: FileId( | ||
997 | 2, | ||
998 | ), | ||
999 | path: "foo2.rs", | ||
1000 | }, | ||
1001 | }, | ||
1002 | ], | ||
1003 | is_snippet: false, | ||
1004 | } | ||
1005 | "#]], | ||
1006 | ); | ||
1007 | } | ||
1008 | |||
1009 | #[test] | ||
1010 | fn test_enum_variant_from_module_1() { | ||
1011 | cov_mark::check!(rename_non_local); | ||
1012 | check( | ||
1013 | "Baz", | ||
1014 | r#" | ||
1015 | mod foo { | ||
1016 | pub enum Foo { Bar$0 } | ||
1017 | } | ||
1018 | |||
1019 | fn func(f: foo::Foo) { | ||
1020 | match f { | ||
1021 | foo::Foo::Bar => {} | ||
1022 | } | ||
1023 | } | ||
1024 | "#, | ||
1025 | r#" | ||
1026 | mod foo { | ||
1027 | pub enum Foo { Baz } | ||
1028 | } | ||
1029 | |||
1030 | fn func(f: foo::Foo) { | ||
1031 | match f { | ||
1032 | foo::Foo::Baz => {} | ||
1033 | } | ||
1034 | } | ||
1035 | "#, | ||
1036 | ); | ||
1037 | } | ||
1038 | |||
1039 | #[test] | ||
1040 | fn test_enum_variant_from_module_2() { | ||
1041 | check( | ||
1042 | "baz", | ||
1043 | r#" | ||
1044 | mod foo { | ||
1045 | pub struct Foo { pub bar$0: uint } | ||
1046 | } | ||
1047 | |||
1048 | fn foo(f: foo::Foo) { | ||
1049 | let _ = f.bar; | ||
1050 | } | ||
1051 | "#, | ||
1052 | r#" | ||
1053 | mod foo { | ||
1054 | pub struct Foo { pub baz: uint } | ||
1055 | } | ||
1056 | |||
1057 | fn foo(f: foo::Foo) { | ||
1058 | let _ = f.baz; | ||
1059 | } | ||
1060 | "#, | ||
1061 | ); | ||
1062 | } | ||
1063 | |||
1064 | #[test] | ||
1065 | fn test_parameter_to_self() { | ||
1066 | cov_mark::check!(rename_to_self); | ||
1067 | check( | ||
1068 | "self", | ||
1069 | r#" | ||
1070 | struct Foo { i: i32 } | ||
1071 | |||
1072 | impl Foo { | ||
1073 | fn f(foo$0: &mut Foo) -> i32 { | ||
1074 | foo.i | ||
1075 | } | ||
1076 | } | ||
1077 | "#, | ||
1078 | r#" | ||
1079 | struct Foo { i: i32 } | ||
1080 | |||
1081 | impl Foo { | ||
1082 | fn f(&mut self) -> i32 { | ||
1083 | self.i | ||
1084 | } | ||
1085 | } | ||
1086 | "#, | ||
1087 | ); | ||
1088 | check( | ||
1089 | "self", | ||
1090 | r#" | ||
1091 | struct Foo { i: i32 } | ||
1092 | |||
1093 | impl Foo { | ||
1094 | fn f(foo$0: Foo) -> i32 { | ||
1095 | foo.i | ||
1096 | } | ||
1097 | } | ||
1098 | "#, | ||
1099 | r#" | ||
1100 | struct Foo { i: i32 } | ||
1101 | |||
1102 | impl Foo { | ||
1103 | fn f(self) -> i32 { | ||
1104 | self.i | ||
1105 | } | ||
1106 | } | ||
1107 | "#, | ||
1108 | ); | ||
1109 | } | ||
1110 | |||
1111 | #[test] | ||
1112 | fn test_parameter_to_self_error_no_impl() { | ||
1113 | check( | ||
1114 | "self", | ||
1115 | r#" | ||
1116 | struct Foo { i: i32 } | ||
1117 | |||
1118 | fn f(foo$0: &mut Foo) -> i32 { | ||
1119 | foo.i | ||
1120 | } | ||
1121 | "#, | ||
1122 | "error: Cannot rename parameter to self for free function", | ||
1123 | ); | ||
1124 | check( | ||
1125 | "self", | ||
1126 | r#" | ||
1127 | struct Foo { i: i32 } | ||
1128 | struct Bar; | ||
1129 | |||
1130 | impl Bar { | ||
1131 | fn f(foo$0: &mut Foo) -> i32 { | ||
1132 | foo.i | ||
1133 | } | ||
1134 | } | ||
1135 | "#, | ||
1136 | "error: Parameter type differs from impl block type", | ||
1137 | ); | ||
1138 | } | ||
1139 | |||
1140 | #[test] | ||
1141 | fn test_parameter_to_self_error_not_first() { | ||
1142 | check( | ||
1143 | "self", | ||
1144 | r#" | ||
1145 | struct Foo { i: i32 } | ||
1146 | impl Foo { | ||
1147 | fn f(x: (), foo$0: &mut Foo) -> i32 { | ||
1148 | foo.i | ||
1149 | } | ||
1150 | } | ||
1151 | "#, | ||
1152 | "error: Only the first parameter may be renamed to self", | ||
1153 | ); | ||
1154 | } | ||
1155 | |||
1156 | #[test] | ||
1157 | fn test_parameter_to_self_impl_ref() { | ||
1158 | check( | ||
1159 | "self", | ||
1160 | r#" | ||
1161 | struct Foo { i: i32 } | ||
1162 | impl &Foo { | ||
1163 | fn f(foo$0: &Foo) -> i32 { | ||
1164 | foo.i | ||
1165 | } | ||
1166 | } | ||
1167 | "#, | ||
1168 | r#" | ||
1169 | struct Foo { i: i32 } | ||
1170 | impl &Foo { | ||
1171 | fn f(self) -> i32 { | ||
1172 | self.i | ||
1173 | } | ||
1174 | } | ||
1175 | "#, | ||
1176 | ); | ||
1177 | } | ||
1178 | |||
1179 | #[test] | ||
1180 | fn test_self_to_parameter() { | ||
1181 | check( | ||
1182 | "foo", | ||
1183 | r#" | ||
1184 | struct Foo { i: i32 } | ||
1185 | |||
1186 | impl Foo { | ||
1187 | fn f(&mut $0self) -> i32 { | ||
1188 | self.i | ||
1189 | } | ||
1190 | } | ||
1191 | "#, | ||
1192 | r#" | ||
1193 | struct Foo { i: i32 } | ||
1194 | |||
1195 | impl Foo { | ||
1196 | fn f(foo: &mut Foo) -> i32 { | ||
1197 | foo.i | ||
1198 | } | ||
1199 | } | ||
1200 | "#, | ||
1201 | ); | ||
1202 | } | ||
1203 | |||
1204 | #[test] | ||
1205 | fn test_owned_self_to_parameter() { | ||
1206 | cov_mark::check!(rename_self_to_param); | ||
1207 | check( | ||
1208 | "foo", | ||
1209 | r#" | ||
1210 | struct Foo { i: i32 } | ||
1211 | |||
1212 | impl Foo { | ||
1213 | fn f($0self) -> i32 { | ||
1214 | self.i | ||
1215 | } | ||
1216 | } | ||
1217 | "#, | ||
1218 | r#" | ||
1219 | struct Foo { i: i32 } | ||
1220 | |||
1221 | impl Foo { | ||
1222 | fn f(foo: Foo) -> i32 { | ||
1223 | foo.i | ||
1224 | } | ||
1225 | } | ||
1226 | "#, | ||
1227 | ); | ||
1228 | } | ||
1229 | |||
1230 | #[test] | ||
1231 | fn test_self_in_path_to_parameter() { | ||
1232 | check( | ||
1233 | "foo", | ||
1234 | r#" | ||
1235 | struct Foo { i: i32 } | ||
1236 | |||
1237 | impl Foo { | ||
1238 | fn f(&self) -> i32 { | ||
1239 | let self_var = 1; | ||
1240 | self$0.i | ||
1241 | } | ||
1242 | } | ||
1243 | "#, | ||
1244 | r#" | ||
1245 | struct Foo { i: i32 } | ||
1246 | |||
1247 | impl Foo { | ||
1248 | fn f(foo: &Foo) -> i32 { | ||
1249 | let self_var = 1; | ||
1250 | foo.i | ||
1251 | } | ||
1252 | } | ||
1253 | "#, | ||
1254 | ); | ||
1255 | } | ||
1256 | |||
1257 | #[test] | ||
1258 | fn test_rename_field_put_init_shorthand() { | ||
1259 | cov_mark::check!(test_rename_field_put_init_shorthand); | ||
1260 | check( | ||
1261 | "bar", | ||
1262 | r#" | ||
1263 | struct Foo { i$0: i32 } | ||
1264 | |||
1265 | fn foo(bar: i32) -> Foo { | ||
1266 | Foo { i: bar } | ||
1267 | } | ||
1268 | "#, | ||
1269 | r#" | ||
1270 | struct Foo { bar: i32 } | ||
1271 | |||
1272 | fn foo(bar: i32) -> Foo { | ||
1273 | Foo { bar } | ||
1274 | } | ||
1275 | "#, | ||
1276 | ); | ||
1277 | } | ||
1278 | |||
1279 | #[test] | ||
1280 | fn test_rename_local_put_init_shorthand() { | ||
1281 | cov_mark::check!(test_rename_local_put_init_shorthand); | ||
1282 | check( | ||
1283 | "i", | ||
1284 | r#" | ||
1285 | struct Foo { i: i32 } | ||
1286 | |||
1287 | fn foo(bar$0: i32) -> Foo { | ||
1288 | Foo { i: bar } | ||
1289 | } | ||
1290 | "#, | ||
1291 | r#" | ||
1292 | struct Foo { i: i32 } | ||
1293 | |||
1294 | fn foo(i: i32) -> Foo { | ||
1295 | Foo { i } | ||
1296 | } | ||
1297 | "#, | ||
1298 | ); | ||
1299 | } | ||
1300 | |||
1301 | #[test] | ||
1302 | fn test_struct_field_pat_into_shorthand() { | ||
1303 | cov_mark::check!(test_rename_field_put_init_shorthand_pat); | ||
1304 | check( | ||
1305 | "baz", | ||
1306 | r#" | ||
1307 | struct Foo { i$0: i32 } | ||
1308 | |||
1309 | fn foo(foo: Foo) { | ||
1310 | let Foo { i: ref baz @ qux } = foo; | ||
1311 | let _ = qux; | ||
1312 | } | ||
1313 | "#, | ||
1314 | r#" | ||
1315 | struct Foo { baz: i32 } | ||
1316 | |||
1317 | fn foo(foo: Foo) { | ||
1318 | let Foo { ref baz @ qux } = foo; | ||
1319 | let _ = qux; | ||
1320 | } | ||
1321 | "#, | ||
1322 | ); | ||
1323 | } | ||
1324 | |||
1325 | #[test] | ||
1326 | fn test_rename_binding_in_destructure_pat() { | ||
1327 | let expected_fixture = r#" | ||
1328 | struct Foo { | ||
1329 | i: i32, | ||
1330 | } | ||
1331 | |||
1332 | fn foo(foo: Foo) { | ||
1333 | let Foo { i: bar } = foo; | ||
1334 | let _ = bar; | ||
1335 | } | ||
1336 | "#; | ||
1337 | check( | ||
1338 | "bar", | ||
1339 | r#" | ||
1340 | struct Foo { | ||
1341 | i: i32, | ||
1342 | } | ||
1343 | |||
1344 | fn foo(foo: Foo) { | ||
1345 | let Foo { i: b } = foo; | ||
1346 | let _ = b$0; | ||
1347 | } | ||
1348 | "#, | ||
1349 | expected_fixture, | ||
1350 | ); | ||
1351 | check( | ||
1352 | "bar", | ||
1353 | r#" | ||
1354 | struct Foo { | ||
1355 | i: i32, | ||
1356 | } | ||
1357 | |||
1358 | fn foo(foo: Foo) { | ||
1359 | let Foo { i } = foo; | ||
1360 | let _ = i$0; | ||
1361 | } | ||
1362 | "#, | ||
1363 | expected_fixture, | ||
1364 | ); | ||
1365 | } | ||
1366 | |||
1367 | #[test] | ||
1368 | fn test_rename_binding_in_destructure_param_pat() { | ||
1369 | check( | ||
1370 | "bar", | ||
1371 | r#" | ||
1372 | struct Foo { | ||
1373 | i: i32 | ||
1374 | } | ||
1375 | |||
1376 | fn foo(Foo { i }: foo) -> i32 { | ||
1377 | i$0 | ||
1378 | } | ||
1379 | "#, | ||
1380 | r#" | ||
1381 | struct Foo { | ||
1382 | i: i32 | ||
1383 | } | ||
1384 | |||
1385 | fn foo(Foo { i: bar }: foo) -> i32 { | ||
1386 | bar | ||
1387 | } | ||
1388 | "#, | ||
1389 | ) | ||
1390 | } | ||
1391 | |||
1392 | #[test] | ||
1393 | fn test_struct_field_complex_ident_pat() { | ||
1394 | check( | ||
1395 | "baz", | ||
1396 | r#" | ||
1397 | struct Foo { i$0: i32 } | ||
1398 | |||
1399 | fn foo(foo: Foo) { | ||
1400 | let Foo { ref i } = foo; | ||
1401 | } | ||
1402 | "#, | ||
1403 | r#" | ||
1404 | struct Foo { baz: i32 } | ||
1405 | |||
1406 | fn foo(foo: Foo) { | ||
1407 | let Foo { baz: ref i } = foo; | ||
1408 | } | ||
1409 | "#, | ||
1410 | ); | ||
1411 | } | ||
1412 | |||
1413 | #[test] | ||
1414 | fn test_rename_lifetimes() { | ||
1415 | cov_mark::check!(rename_lifetime); | ||
1416 | check( | ||
1417 | "'yeeee", | ||
1418 | r#" | ||
1419 | trait Foo<'a> { | ||
1420 | fn foo() -> &'a (); | ||
1421 | } | ||
1422 | impl<'a> Foo<'a> for &'a () { | ||
1423 | fn foo() -> &'a$0 () { | ||
1424 | unimplemented!() | ||
1425 | } | ||
1426 | } | ||
1427 | "#, | ||
1428 | r#" | ||
1429 | trait Foo<'a> { | ||
1430 | fn foo() -> &'a (); | ||
1431 | } | ||
1432 | impl<'yeeee> Foo<'yeeee> for &'yeeee () { | ||
1433 | fn foo() -> &'yeeee () { | ||
1434 | unimplemented!() | ||
1435 | } | ||
1436 | } | ||
1437 | "#, | ||
1438 | ) | ||
1439 | } | ||
1440 | |||
1441 | #[test] | ||
1442 | fn test_rename_bind_pat() { | ||
1443 | check( | ||
1444 | "new_name", | ||
1445 | r#" | ||
1446 | fn main() { | ||
1447 | enum CustomOption<T> { | ||
1448 | None, | ||
1449 | Some(T), | ||
1450 | } | ||
1451 | |||
1452 | let test_variable = CustomOption::Some(22); | ||
1453 | |||
1454 | match test_variable { | ||
1455 | CustomOption::Some(foo$0) if foo == 11 => {} | ||
1456 | _ => (), | ||
1457 | } | ||
1458 | }"#, | ||
1459 | r#" | ||
1460 | fn main() { | ||
1461 | enum CustomOption<T> { | ||
1462 | None, | ||
1463 | Some(T), | ||
1464 | } | ||
1465 | |||
1466 | let test_variable = CustomOption::Some(22); | ||
1467 | |||
1468 | match test_variable { | ||
1469 | CustomOption::Some(new_name) if new_name == 11 => {} | ||
1470 | _ => (), | ||
1471 | } | ||
1472 | }"#, | ||
1473 | ); | ||
1474 | } | ||
1475 | |||
1476 | #[test] | ||
1477 | fn test_rename_label() { | ||
1478 | check( | ||
1479 | "'foo", | ||
1480 | r#" | ||
1481 | fn foo<'a>() -> &'a () { | ||
1482 | 'a: { | ||
1483 | 'b: loop { | ||
1484 | break 'a$0; | ||
1485 | } | ||
1486 | } | ||
1487 | } | ||
1488 | "#, | ||
1489 | r#" | ||
1490 | fn foo<'a>() -> &'a () { | ||
1491 | 'foo: { | ||
1492 | 'b: loop { | ||
1493 | break 'foo; | ||
1494 | } | ||
1495 | } | ||
1496 | } | ||
1497 | "#, | ||
1498 | ) | ||
1499 | } | ||
1500 | |||
1501 | #[test] | ||
1502 | fn test_self_to_self() { | ||
1503 | cov_mark::check!(rename_self_to_self); | ||
1504 | check( | ||
1505 | "self", | ||
1506 | r#" | ||
1507 | struct Foo; | ||
1508 | impl Foo { | ||
1509 | fn foo(self$0) {} | ||
1510 | } | ||
1511 | "#, | ||
1512 | r#" | ||
1513 | struct Foo; | ||
1514 | impl Foo { | ||
1515 | fn foo(self) {} | ||
1516 | } | ||
1517 | "#, | ||
1518 | ) | ||
1519 | } | ||
1520 | |||
1521 | #[test] | ||
1522 | fn test_rename_field_in_pat_in_macro_doesnt_shorthand() { | ||
1523 | // ideally we would be able to make this emit a short hand, but I doubt this is easily possible | ||
1524 | check( | ||
1525 | "baz", | ||
1526 | r#" | ||
1527 | macro_rules! foo { | ||
1528 | ($pattern:pat) => { | ||
1529 | let $pattern = loop {}; | ||
1530 | }; | ||
1531 | } | ||
1532 | struct Foo { | ||
1533 | bar$0: u32, | ||
1534 | } | ||
1535 | fn foo() { | ||
1536 | foo!(Foo { bar: baz }); | ||
1537 | } | ||
1538 | "#, | ||
1539 | r#" | ||
1540 | macro_rules! foo { | ||
1541 | ($pattern:pat) => { | ||
1542 | let $pattern = loop {}; | ||
1543 | }; | ||
1544 | } | ||
1545 | struct Foo { | ||
1546 | baz: u32, | ||
1547 | } | ||
1548 | fn foo() { | ||
1549 | foo!(Foo { baz: baz }); | ||
1550 | } | ||
1551 | "#, | ||
1552 | ) | ||
1553 | } | ||
1554 | |||
1555 | #[test] | ||
1556 | fn test_rename_tuple_field() { | ||
1557 | check( | ||
1558 | "foo", | ||
1559 | r#" | ||
1560 | struct Foo(i32); | ||
1561 | |||
1562 | fn baz() { | ||
1563 | let mut x = Foo(4); | ||
1564 | x.0$0 = 5; | ||
1565 | } | ||
1566 | "#, | ||
1567 | "error: No identifier available to rename", | ||
1568 | ); | ||
1569 | } | ||
1570 | |||
1571 | #[test] | ||
1572 | fn test_rename_builtin() { | ||
1573 | check( | ||
1574 | "foo", | ||
1575 | r#" | ||
1576 | fn foo() { | ||
1577 | let x: i32$0 = 0; | ||
1578 | } | ||
1579 | "#, | ||
1580 | "error: Cannot rename builtin type", | ||
1581 | ); | ||
1582 | } | ||
1583 | |||
1584 | #[test] | ||
1585 | fn test_rename_self() { | ||
1586 | check( | ||
1587 | "foo", | ||
1588 | r#" | ||
1589 | struct Foo {} | ||
1590 | |||
1591 | impl Foo { | ||
1592 | fn foo(self) -> Self$0 { | ||
1593 | self | ||
1594 | } | ||
1595 | } | ||
1596 | "#, | ||
1597 | "error: Cannot rename `Self`", | ||
1598 | ); | ||
1599 | } | ||
1600 | |||
1601 | #[test] | ||
1602 | fn test_rename_ignores_self_ty() { | ||
1603 | check( | ||
1604 | "Fo0", | ||
1605 | r#" | ||
1606 | struct $0Foo; | ||
1607 | |||
1608 | impl Foo where Self: {} | ||
1609 | "#, | ||
1610 | r#" | ||
1611 | struct Fo0; | ||
1612 | |||
1613 | impl Fo0 where Self: {} | ||
1614 | "#, | ||
1615 | ); | ||
1616 | } | ||
1617 | |||
1618 | #[test] | ||
1619 | fn test_rename_fails_on_aliases() { | ||
1620 | check( | ||
1621 | "Baz", | ||
1622 | r#" | ||
1623 | struct Foo; | ||
1624 | use Foo as Bar$0; | ||
1625 | "#, | ||
1626 | "error: Renaming aliases is currently unsupported", | ||
1627 | ); | ||
1628 | check( | ||
1629 | "Baz", | ||
1630 | r#" | ||
1631 | struct Foo; | ||
1632 | use Foo as Bar; | ||
1633 | use Bar$0; | ||
1634 | "#, | ||
1635 | "error: Renaming aliases is currently unsupported", | ||
1636 | ); | ||
1637 | } | ||
1638 | |||
1639 | #[test] | ||
1640 | fn test_rename_trait_method() { | ||
1641 | let res = r" | ||
1642 | trait Foo { | ||
1643 | fn foo(&self) { | ||
1644 | self.foo(); | ||
1645 | } | ||
1646 | } | ||
1647 | |||
1648 | impl Foo for () { | ||
1649 | fn foo(&self) { | ||
1650 | self.foo(); | ||
1651 | } | ||
1652 | }"; | ||
1653 | check( | ||
1654 | "foo", | ||
1655 | r#" | ||
1656 | trait Foo { | ||
1657 | fn bar$0(&self) { | ||
1658 | self.bar(); | ||
1659 | } | ||
1660 | } | ||
1661 | |||
1662 | impl Foo for () { | ||
1663 | fn bar(&self) { | ||
1664 | self.bar(); | ||
1665 | } | ||
1666 | }"#, | ||
1667 | res, | ||
1668 | ); | ||
1669 | check( | ||
1670 | "foo", | ||
1671 | r#" | ||
1672 | trait Foo { | ||
1673 | fn bar(&self) { | ||
1674 | self.bar$0(); | ||
1675 | } | ||
1676 | } | ||
1677 | |||
1678 | impl Foo for () { | ||
1679 | fn bar(&self) { | ||
1680 | self.bar(); | ||
1681 | } | ||
1682 | }"#, | ||
1683 | res, | ||
1684 | ); | ||
1685 | check( | ||
1686 | "foo", | ||
1687 | r#" | ||
1688 | trait Foo { | ||
1689 | fn bar(&self) { | ||
1690 | self.bar(); | ||
1691 | } | ||
1692 | } | ||
1693 | |||
1694 | impl Foo for () { | ||
1695 | fn bar$0(&self) { | ||
1696 | self.bar(); | ||
1697 | } | ||
1698 | }"#, | ||
1699 | res, | ||
1700 | ); | ||
1701 | check( | ||
1702 | "foo", | ||
1703 | r#" | ||
1704 | trait Foo { | ||
1705 | fn bar(&self) { | ||
1706 | self.bar(); | ||
1707 | } | ||
1708 | } | ||
1709 | |||
1710 | impl Foo for () { | ||
1711 | fn bar(&self) { | ||
1712 | self.bar$0(); | ||
1713 | } | ||
1714 | }"#, | ||
1715 | res, | ||
1716 | ); | ||
1717 | } | ||
1718 | |||
1719 | #[test] | ||
1720 | fn test_rename_trait_const() { | ||
1721 | let res = r" | ||
1722 | trait Foo { | ||
1723 | const FOO: (); | ||
1724 | } | ||
1725 | |||
1726 | impl Foo for () { | ||
1727 | const FOO: (); | ||
1728 | } | ||
1729 | fn f() { <()>::FOO; }"; | ||
1730 | check( | ||
1731 | "FOO", | ||
1732 | r#" | ||
1733 | trait Foo { | ||
1734 | const BAR$0: (); | ||
1735 | } | ||
1736 | |||
1737 | impl Foo for () { | ||
1738 | const BAR: (); | ||
1739 | } | ||
1740 | fn f() { <()>::BAR; }"#, | ||
1741 | res, | ||
1742 | ); | ||
1743 | check( | ||
1744 | "FOO", | ||
1745 | r#" | ||
1746 | trait Foo { | ||
1747 | const BAR: (); | ||
1748 | } | ||
1749 | |||
1750 | impl Foo for () { | ||
1751 | const BAR$0: (); | ||
1752 | } | ||
1753 | fn f() { <()>::BAR; }"#, | ||
1754 | res, | ||
1755 | ); | ||
1756 | check( | ||
1757 | "FOO", | ||
1758 | r#" | ||
1759 | trait Foo { | ||
1760 | const BAR: (); | ||
1761 | } | ||
1762 | |||
1763 | impl Foo for () { | ||
1764 | const BAR: (); | ||
1765 | } | ||
1766 | fn f() { <()>::BAR$0; }"#, | ||
1767 | res, | ||
1768 | ); | ||
1769 | } | ||
1770 | |||
1771 | #[test] | ||
1772 | fn macros_are_broken_lol() { | ||
1773 | cov_mark::check!(macros_are_broken_lol); | ||
1774 | check( | ||
1775 | "lol", | ||
1776 | r#" | ||
1777 | macro_rules! m { () => { fn f() {} } } | ||
1778 | m!(); | ||
1779 | fn main() { f$0() } | ||
1780 | "#, | ||
1781 | r#" | ||
1782 | macro_rules! m { () => { fn f() {} } } | ||
1783 | lol | ||
1784 | fn main() { lol() } | ||
1785 | "#, | ||
1786 | ) | ||
1787 | } | ||
1788 | } | ||