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