aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/references
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src/references')
-rw-r--r--crates/ra_ide/src/references/rename.rs1101
1 files changed, 519 insertions, 582 deletions
diff --git a/crates/ra_ide/src/references/rename.rs b/crates/ra_ide/src/references/rename.rs
index 7ebc0adcf..31654bf79 100644
--- a/crates/ra_ide/src/references/rename.rs
+++ b/crates/ra_ide/src/references/rename.rs
@@ -7,7 +7,8 @@ use ra_ide_db::{
7 RootDatabase, 7 RootDatabase,
8}; 8};
9use ra_syntax::{ 9use ra_syntax::{
10 algo::find_node_at_offset, ast, ast::NameOwner, ast::TypeAscriptionOwner, 10 algo::find_node_at_offset,
11 ast::{self, NameOwner},
11 lex_single_valid_syntax_kind, match_ast, AstNode, SyntaxKind, SyntaxNode, SyntaxToken, 12 lex_single_valid_syntax_kind, match_ast, AstNode, SyntaxKind, SyntaxNode, SyntaxToken,
12}; 13};
13use ra_text_edit::TextEdit; 14use ra_text_edit::TextEdit;
@@ -24,23 +25,24 @@ pub(crate) fn rename(
24 position: FilePosition, 25 position: FilePosition,
25 new_name: &str, 26 new_name: &str,
26) -> Option<RangeInfo<SourceChange>> { 27) -> Option<RangeInfo<SourceChange>> {
28 let sema = Semantics::new(db);
29
27 match lex_single_valid_syntax_kind(new_name)? { 30 match lex_single_valid_syntax_kind(new_name)? {
28 SyntaxKind::IDENT | SyntaxKind::UNDERSCORE => (), 31 SyntaxKind::IDENT | SyntaxKind::UNDERSCORE => (),
29 SyntaxKind::SELF_KW => return rename_to_self(db, position), 32 SyntaxKind::SELF_KW => return rename_to_self(&sema, position),
30 _ => return None, 33 _ => return None,
31 } 34 }
32 35
33 let sema = Semantics::new(db);
34 let source_file = sema.parse(position.file_id); 36 let source_file = sema.parse(position.file_id);
35 let syntax = source_file.syntax(); 37 let syntax = source_file.syntax();
36 if let Some(module) = find_module_at_offset(&sema, position, syntax) { 38 if let Some(module) = find_module_at_offset(&sema, position, syntax) {
37 rename_mod(db, position, module, new_name) 39 rename_mod(&sema, position, module, new_name)
38 } else if let Some(self_token) = 40 } else if let Some(self_token) =
39 syntax.token_at_offset(position.offset).find(|t| t.kind() == SyntaxKind::SELF_KW) 41 syntax.token_at_offset(position.offset).find(|t| t.kind() == SyntaxKind::SELF_KW)
40 { 42 {
41 rename_self_to_param(db, position, self_token, new_name) 43 rename_self_to_param(&sema, position, self_token, new_name)
42 } else { 44 } else {
43 rename_reference(sema.db, position, new_name) 45 rename_reference(&sema, position, new_name)
44 } 46 }
45} 47}
46 48
@@ -97,7 +99,7 @@ fn source_edit_from_reference(reference: Reference, new_name: &str) -> SourceFil
97} 99}
98 100
99fn rename_mod( 101fn rename_mod(
100 db: &RootDatabase, 102 sema: &Semantics<RootDatabase>,
101 position: FilePosition, 103 position: FilePosition,
102 module: Module, 104 module: Module,
103 new_name: &str, 105 new_name: &str,
@@ -105,34 +107,33 @@ fn rename_mod(
105 let mut source_file_edits = Vec::new(); 107 let mut source_file_edits = Vec::new();
106 let mut file_system_edits = Vec::new(); 108 let mut file_system_edits = Vec::new();
107 109
108 let src = module.definition_source(db); 110 let src = module.definition_source(sema.db);
109 let file_id = src.file_id.original_file(db); 111 let file_id = src.file_id.original_file(sema.db);
110 match src.value { 112 match src.value {
111 ModuleSource::SourceFile(..) => { 113 ModuleSource::SourceFile(..) => {
112 // mod is defined in path/to/dir/mod.rs 114 // mod is defined in path/to/dir/mod.rs
113 let dst = if module.is_mod_rs(db) { 115 let dst = if module.is_mod_rs(sema.db) {
114 format!("../{}/mod.rs", new_name) 116 format!("../{}/mod.rs", new_name)
115 } else { 117 } else {
116 format!("{}.rs", new_name) 118 format!("{}.rs", new_name)
117 }; 119 };
118 let move_file = 120 let move_file = FileSystemEdit::MoveFile { src: file_id, anchor: file_id, dst };
119 FileSystemEdit::MoveFile { src: file_id, anchor: position.file_id, dst };
120 file_system_edits.push(move_file); 121 file_system_edits.push(move_file);
121 } 122 }
122 ModuleSource::Module(..) => {} 123 ModuleSource::Module(..) => {}
123 } 124 }
124 125
125 if let Some(src) = module.declaration_source(db) { 126 if let Some(src) = module.declaration_source(sema.db) {
126 let file_id = src.file_id.original_file(db); 127 let file_id = src.file_id.original_file(sema.db);
127 let name = src.value.name()?; 128 let name = src.value.name()?;
128 let edit = SourceFileEdit { 129 let edit = SourceFileEdit {
129 file_id: file_id, 130 file_id,
130 edit: TextEdit::replace(name.syntax().text_range(), new_name.into()), 131 edit: TextEdit::replace(name.syntax().text_range(), new_name.into()),
131 }; 132 };
132 source_file_edits.push(edit); 133 source_file_edits.push(edit);
133 } 134 }
134 135
135 let RangeInfo { range, info: refs } = find_all_refs(db, position, None)?; 136 let RangeInfo { range, info: refs } = find_all_refs(sema, position, None)?;
136 let ref_edits = refs 137 let ref_edits = refs
137 .references 138 .references
138 .into_iter() 139 .into_iter()
@@ -142,23 +143,25 @@ fn rename_mod(
142 Some(RangeInfo::new(range, SourceChange::from_edits(source_file_edits, file_system_edits))) 143 Some(RangeInfo::new(range, SourceChange::from_edits(source_file_edits, file_system_edits)))
143} 144}
144 145
145fn rename_to_self(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<SourceChange>> { 146fn rename_to_self(
146 let sema = Semantics::new(db); 147 sema: &Semantics<RootDatabase>,
148 position: FilePosition,
149) -> Option<RangeInfo<SourceChange>> {
147 let source_file = sema.parse(position.file_id); 150 let source_file = sema.parse(position.file_id);
148 let syn = source_file.syntax(); 151 let syn = source_file.syntax();
149 152
150 let fn_def = find_node_at_offset::<ast::FnDef>(syn, position.offset)?; 153 let fn_def = find_node_at_offset::<ast::Fn>(syn, position.offset)?;
151 let params = fn_def.param_list()?; 154 let params = fn_def.param_list()?;
152 if params.self_param().is_some() { 155 if params.self_param().is_some() {
153 return None; // method already has self param 156 return None; // method already has self param
154 } 157 }
155 let first_param = params.params().next()?; 158 let first_param = params.params().next()?;
156 let mutable = match first_param.ascribed_type() { 159 let mutable = match first_param.ty() {
157 Some(ast::TypeRef::ReferenceType(rt)) => rt.mut_token().is_some(), 160 Some(ast::TypeRef::ReferenceType(rt)) => rt.mut_token().is_some(),
158 _ => return None, // not renaming other types 161 _ => return None, // not renaming other types
159 }; 162 };
160 163
161 let RangeInfo { range, info: refs } = find_all_refs(db, position, None)?; 164 let RangeInfo { range, info: refs } = find_all_refs(sema, position, None)?;
162 165
163 let param_range = first_param.syntax().text_range(); 166 let param_range = first_param.syntax().text_range();
164 let (param_ref, usages): (Vec<Reference>, Vec<Reference>) = refs 167 let (param_ref, usages): (Vec<Reference>, Vec<Reference>) = refs
@@ -190,15 +193,14 @@ fn text_edit_from_self_param(
190 self_param: &ast::SelfParam, 193 self_param: &ast::SelfParam,
191 new_name: &str, 194 new_name: &str,
192) -> Option<TextEdit> { 195) -> Option<TextEdit> {
193 fn target_type_name(impl_def: &ast::ImplDef) -> Option<String> { 196 fn target_type_name(impl_def: &ast::Impl) -> Option<String> {
194 if let Some(ast::TypeRef::PathType(p)) = impl_def.target_type() { 197 if let Some(ast::TypeRef::PathType(p)) = impl_def.target_type() {
195 return Some(p.path()?.segment()?.name_ref()?.text().to_string()); 198 return Some(p.path()?.segment()?.name_ref()?.text().to_string());
196 } 199 }
197 None 200 None
198 } 201 }
199 202
200 let impl_def = 203 let impl_def = find_node_at_offset::<ast::Impl>(syn, self_param.syntax().text_range().start())?;
201 find_node_at_offset::<ast::ImplDef>(syn, self_param.syntax().text_range().start())?;
202 let type_name = target_type_name(&impl_def)?; 204 let type_name = target_type_name(&impl_def)?;
203 205
204 let mut replacement_text = String::from(new_name); 206 let mut replacement_text = String::from(new_name);
@@ -210,17 +212,16 @@ fn text_edit_from_self_param(
210} 212}
211 213
212fn rename_self_to_param( 214fn rename_self_to_param(
213 db: &RootDatabase, 215 sema: &Semantics<RootDatabase>,
214 position: FilePosition, 216 position: FilePosition,
215 self_token: SyntaxToken, 217 self_token: SyntaxToken,
216 new_name: &str, 218 new_name: &str,
217) -> Option<RangeInfo<SourceChange>> { 219) -> Option<RangeInfo<SourceChange>> {
218 let sema = Semantics::new(db);
219 let source_file = sema.parse(position.file_id); 220 let source_file = sema.parse(position.file_id);
220 let syn = source_file.syntax(); 221 let syn = source_file.syntax();
221 222
222 let text = db.file_text(position.file_id); 223 let text = sema.db.file_text(position.file_id);
223 let fn_def = find_node_at_offset::<ast::FnDef>(syn, position.offset)?; 224 let fn_def = find_node_at_offset::<ast::Fn>(syn, position.offset)?;
224 let search_range = fn_def.syntax().text_range(); 225 let search_range = fn_def.syntax().text_range();
225 226
226 let mut edits: Vec<SourceFileEdit> = vec![]; 227 let mut edits: Vec<SourceFileEdit> = vec![];
@@ -249,11 +250,11 @@ fn rename_self_to_param(
249} 250}
250 251
251fn rename_reference( 252fn rename_reference(
252 db: &RootDatabase, 253 sema: &Semantics<RootDatabase>,
253 position: FilePosition, 254 position: FilePosition,
254 new_name: &str, 255 new_name: &str,
255) -> Option<RangeInfo<SourceChange>> { 256) -> Option<RangeInfo<SourceChange>> {
256 let RangeInfo { range, info: refs } = find_all_refs(db, position, None)?; 257 let RangeInfo { range, info: refs } = find_all_refs(sema, position, None)?;
257 258
258 let edit = refs 259 let edit = refs
259 .into_iter() 260 .into_iter()
@@ -269,51 +270,51 @@ fn rename_reference(
269 270
270#[cfg(test)] 271#[cfg(test)]
271mod tests { 272mod tests {
272 use insta::assert_debug_snapshot; 273 use expect::{expect, Expect};
273 use ra_text_edit::TextEditBuilder; 274 use ra_text_edit::TextEditBuilder;
274 use stdx::trim_indent; 275 use stdx::trim_indent;
275 use test_utils::{assert_eq_text, mark}; 276 use test_utils::{assert_eq_text, mark};
276 277
277 use crate::{mock_analysis::analysis_and_position, FileId}; 278 use crate::{mock_analysis::analysis_and_position, FileId};
278 279
280 fn check(new_name: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
281 let ra_fixture_after = &trim_indent(ra_fixture_after);
282 let (analysis, position) = analysis_and_position(ra_fixture_before);
283 let source_change = analysis.rename(position, new_name).unwrap();
284 let mut text_edit_builder = TextEditBuilder::default();
285 let mut file_id: Option<FileId> = None;
286 if let Some(change) = source_change {
287 for edit in change.info.source_file_edits {
288 file_id = Some(edit.file_id);
289 for indel in edit.edit.into_iter() {
290 text_edit_builder.replace(indel.delete, indel.insert);
291 }
292 }
293 }
294 let mut result = analysis.file_text(file_id.unwrap()).unwrap().to_string();
295 text_edit_builder.finish().apply(&mut result);
296 assert_eq_text!(ra_fixture_after, &*result);
297 }
298
299 fn check_expect(new_name: &str, ra_fixture: &str, expect: Expect) {
300 let (analysis, position) = analysis_and_position(ra_fixture);
301 let source_change = analysis.rename(position, new_name).unwrap().unwrap();
302 expect.assert_debug_eq(&source_change)
303 }
304
279 #[test] 305 #[test]
280 fn test_rename_to_underscore() { 306 fn test_rename_to_underscore() {
281 test_rename( 307 check("_", r#"fn main() { let i<|> = 1; }"#, r#"fn main() { let _ = 1; }"#);
282 r#"
283 fn main() {
284 let i<|> = 1;
285 }"#,
286 "_",
287 r#"
288 fn main() {
289 let _ = 1;
290 }"#,
291 );
292 } 308 }
293 309
294 #[test] 310 #[test]
295 fn test_rename_to_raw_identifier() { 311 fn test_rename_to_raw_identifier() {
296 test_rename( 312 check("r#fn", r#"fn main() { let i<|> = 1; }"#, r#"fn main() { let r#fn = 1; }"#);
297 r#"
298 fn main() {
299 let i<|> = 1;
300 }"#,
301 "r#fn",
302 r#"
303 fn main() {
304 let r#fn = 1;
305 }"#,
306 );
307 } 313 }
308 314
309 #[test] 315 #[test]
310 fn test_rename_to_invalid_identifier() { 316 fn test_rename_to_invalid_identifier() {
311 let (analysis, position) = analysis_and_position( 317 let (analysis, position) = analysis_and_position(r#"fn main() { let i<|> = 1; }"#);
312 "
313 fn main() {
314 let i<|> = 1;
315 }",
316 );
317 let new_name = "invalid!"; 318 let new_name = "invalid!";
318 let source_change = analysis.rename(position, new_name).unwrap(); 319 let source_change = analysis.rename(position, new_name).unwrap();
319 assert!(source_change.is_none()); 320 assert!(source_change.is_none());
@@ -321,318 +322,269 @@ mod tests {
321 322
322 #[test] 323 #[test]
323 fn test_rename_for_local() { 324 fn test_rename_for_local() {
324 test_rename( 325 check(
326 "k",
325 r#" 327 r#"
326 fn main() { 328fn main() {
327 let mut i = 1; 329 let mut i = 1;
328 let j = 1; 330 let j = 1;
329 i = i<|> + j; 331 i = i<|> + j;
330 332
331 { 333 { i = 0; }
332 i = 0;
333 }
334 334
335 i = 5; 335 i = 5;
336 }"#, 336}
337 "k", 337"#,
338 r#" 338 r#"
339 fn main() { 339fn main() {
340 let mut k = 1; 340 let mut k = 1;
341 let j = 1; 341 let j = 1;
342 k = k + j; 342 k = k + j;
343 343
344 { 344 { k = 0; }
345 k = 0;
346 }
347 345
348 k = 5; 346 k = 5;
349 }"#, 347}
348"#,
350 ); 349 );
351 } 350 }
352 351
353 #[test] 352 #[test]
354 fn test_rename_for_macro_args() { 353 fn test_rename_for_macro_args() {
355 test_rename( 354 check(
356 r#"
357 macro_rules! foo {($i:ident) => {$i} }
358 fn main() {
359 let a<|> = "test";
360 foo!(a);
361 }"#,
362 "b", 355 "b",
363 r#" 356 r#"
364 macro_rules! foo {($i:ident) => {$i} } 357macro_rules! foo {($i:ident) => {$i} }
365 fn main() { 358fn main() {
366 let b = "test"; 359 let a<|> = "test";
367 foo!(b); 360 foo!(a);
368 }"#, 361}
362"#,
363 r#"
364macro_rules! foo {($i:ident) => {$i} }
365fn main() {
366 let b = "test";
367 foo!(b);
368}
369"#,
369 ); 370 );
370 } 371 }
371 372
372 #[test] 373 #[test]
373 fn test_rename_for_macro_args_rev() { 374 fn test_rename_for_macro_args_rev() {
374 test_rename( 375 check(
375 r#"
376 macro_rules! foo {($i:ident) => {$i} }
377 fn main() {
378 let a = "test";
379 foo!(a<|>);
380 }"#,
381 "b", 376 "b",
382 r#" 377 r#"
383 macro_rules! foo {($i:ident) => {$i} } 378macro_rules! foo {($i:ident) => {$i} }
384 fn main() { 379fn main() {
385 let b = "test"; 380 let a = "test";
386 foo!(b); 381 foo!(a<|>);
387 }"#, 382}
383"#,
384 r#"
385macro_rules! foo {($i:ident) => {$i} }
386fn main() {
387 let b = "test";
388 foo!(b);
389}
390"#,
388 ); 391 );
389 } 392 }
390 393
391 #[test] 394 #[test]
392 fn test_rename_for_macro_define_fn() { 395 fn test_rename_for_macro_define_fn() {
393 test_rename( 396 check(
394 r#"
395 macro_rules! define_fn {($id:ident) => { fn $id{} }}
396 define_fn!(foo);
397 fn main() {
398 fo<|>o();
399 }"#,
400 "bar", 397 "bar",
401 r#" 398 r#"
402 macro_rules! define_fn {($id:ident) => { fn $id{} }} 399macro_rules! define_fn {($id:ident) => { fn $id{} }}
403 define_fn!(bar); 400define_fn!(foo);
404 fn main() { 401fn main() {
405 bar(); 402 fo<|>o();
406 }"#, 403}
404"#,
405 r#"
406macro_rules! define_fn {($id:ident) => { fn $id{} }}
407define_fn!(bar);
408fn main() {
409 bar();
410}
411"#,
407 ); 412 );
408 } 413 }
409 414
410 #[test] 415 #[test]
411 fn test_rename_for_macro_define_fn_rev() { 416 fn test_rename_for_macro_define_fn_rev() {
412 test_rename( 417 check(
413 r#"
414 macro_rules! define_fn {($id:ident) => { fn $id{} }}
415 define_fn!(fo<|>o);
416 fn main() {
417 foo();
418 }"#,
419 "bar", 418 "bar",
420 r#" 419 r#"
421 macro_rules! define_fn {($id:ident) => { fn $id{} }} 420macro_rules! define_fn {($id:ident) => { fn $id{} }}
422 define_fn!(bar); 421define_fn!(fo<|>o);
423 fn main() { 422fn main() {
424 bar(); 423 foo();
425 }"#, 424}
425"#,
426 r#"
427macro_rules! define_fn {($id:ident) => { fn $id{} }}
428define_fn!(bar);
429fn main() {
430 bar();
431}
432"#,
426 ); 433 );
427 } 434 }
428 435
429 #[test] 436 #[test]
430 fn test_rename_for_param_inside() { 437 fn test_rename_for_param_inside() {
431 test_rename( 438 check("j", r#"fn foo(i : u32) -> u32 { i<|> }"#, r#"fn foo(j : u32) -> u32 { j }"#);
432 r#"
433 fn foo(i : u32) -> u32 {
434 i<|>
435 }"#,
436 "j",
437 r#"
438 fn foo(j : u32) -> u32 {
439 j
440 }"#,
441 );
442 } 439 }
443 440
444 #[test] 441 #[test]
445 fn test_rename_refs_for_fn_param() { 442 fn test_rename_refs_for_fn_param() {
446 test_rename( 443 check("j", r#"fn foo(i<|> : u32) -> u32 { i }"#, r#"fn foo(j : u32) -> u32 { j }"#);
447 r#"
448 fn foo(i<|> : u32) -> u32 {
449 i
450 }"#,
451 "new_name",
452 r#"
453 fn foo(new_name : u32) -> u32 {
454 new_name
455 }"#,
456 );
457 } 444 }
458 445
459 #[test] 446 #[test]
460 fn test_rename_for_mut_param() { 447 fn test_rename_for_mut_param() {
461 test_rename( 448 check("j", r#"fn foo(mut i<|> : u32) -> u32 { i }"#, r#"fn foo(mut j : u32) -> u32 { j }"#);
462 r#"
463 fn foo(mut i<|> : u32) -> u32 {
464 i
465 }"#,
466 "new_name",
467 r#"
468 fn foo(mut new_name : u32) -> u32 {
469 new_name
470 }"#,
471 );
472 } 449 }
473 450
474 #[test] 451 #[test]
475 fn test_rename_struct_field() { 452 fn test_rename_struct_field() {
476 test_rename( 453 check(
454 "j",
477 r#" 455 r#"
478 struct Foo { 456struct Foo { i<|>: i32 }
479 i<|>: i32,
480 }
481 457
482 impl Foo { 458impl Foo {
483 fn new(i: i32) -> Self { 459 fn new(i: i32) -> Self {
484 Self { i: i } 460 Self { i: i }
485 }
486 } 461 }
487 "#, 462}
488 "j", 463"#,
489 r#" 464 r#"
490 struct Foo { 465struct Foo { j: i32 }
491 j: i32,
492 }
493 466
494 impl Foo { 467impl Foo {
495 fn new(i: i32) -> Self { 468 fn new(i: i32) -> Self {
496 Self { j: i } 469 Self { j: i }
497 }
498 } 470 }
499 "#, 471}
472"#,
500 ); 473 );
501 } 474 }
502 475
503 #[test] 476 #[test]
504 fn test_rename_struct_field_for_shorthand() { 477 fn test_rename_struct_field_for_shorthand() {
505 mark::check!(test_rename_struct_field_for_shorthand); 478 mark::check!(test_rename_struct_field_for_shorthand);
506 test_rename( 479 check(
480 "j",
507 r#" 481 r#"
508 struct Foo { 482struct Foo { i<|>: i32 }
509 i<|>: i32,
510 }
511 483
512 impl Foo { 484impl Foo {
513 fn new(i: i32) -> Self { 485 fn new(i: i32) -> Self {
514 Self { i } 486 Self { i }
515 }
516 } 487 }
517 "#, 488}
518 "j", 489"#,
519 r#" 490 r#"
520 struct Foo { 491struct Foo { j: i32 }
521 j: i32,
522 }
523 492
524 impl Foo { 493impl Foo {
525 fn new(i: i32) -> Self { 494 fn new(i: i32) -> Self {
526 Self { j: i } 495 Self { j: i }
527 }
528 } 496 }
529 "#, 497}
498"#,
530 ); 499 );
531 } 500 }
532 501
533 #[test] 502 #[test]
534 fn test_rename_local_for_field_shorthand() { 503 fn test_rename_local_for_field_shorthand() {
535 mark::check!(test_rename_local_for_field_shorthand); 504 mark::check!(test_rename_local_for_field_shorthand);
536 test_rename( 505 check(
506 "j",
537 r#" 507 r#"
538 struct Foo { 508struct Foo { i: i32 }
539 i: i32,
540 }
541 509
542 impl Foo { 510impl Foo {
543 fn new(i<|>: i32) -> Self { 511 fn new(i<|>: i32) -> Self {
544 Self { i } 512 Self { i }
545 }
546 } 513 }
547 "#, 514}
548 "j", 515"#,
549 r#" 516 r#"
550 struct Foo { 517struct Foo { i: i32 }
551 i: i32,
552 }
553 518
554 impl Foo { 519impl Foo {
555 fn new(j: i32) -> Self { 520 fn new(j: i32) -> Self {
556 Self { i: j } 521 Self { i: j }
557 }
558 } 522 }
559 "#, 523}
524"#,
560 ); 525 );
561 } 526 }
562 527
563 #[test] 528 #[test]
564 fn test_field_shorthand_correct_struct() { 529 fn test_field_shorthand_correct_struct() {
565 test_rename( 530 check(
566 r#"
567 struct Foo {
568 i<|>: i32,
569 }
570
571 struct Bar {
572 i: i32,
573 }
574
575 impl Bar {
576 fn new(i: i32) -> Self {
577 Self { i }
578 }
579 }
580 "#,
581 "j", 531 "j",
582 r#" 532 r#"
583 struct Foo { 533struct Foo { i<|>: i32 }
584 j: i32, 534struct Bar { i: i32 }
585 }
586 535
587 struct Bar { 536impl Bar {
588 i: i32, 537 fn new(i: i32) -> Self {
538 Self { i }
589 } 539 }
540}
541"#,
542 r#"
543struct Foo { j: i32 }
544struct Bar { i: i32 }
590 545
591 impl Bar { 546impl Bar {
592 fn new(i: i32) -> Self { 547 fn new(i: i32) -> Self {
593 Self { i } 548 Self { i }
594 }
595 } 549 }
596 "#, 550}
551"#,
597 ); 552 );
598 } 553 }
599 554
600 #[test] 555 #[test]
601 fn test_shadow_local_for_struct_shorthand() { 556 fn test_shadow_local_for_struct_shorthand() {
602 test_rename( 557 check(
558 "j",
603 r#" 559 r#"
604 struct Foo { 560struct Foo { i: i32 }
605 i: i32,
606 }
607 561
608 fn baz(i<|>: i32) -> Self { 562fn baz(i<|>: i32) -> Self {
609 let x = Foo { i }; 563 let x = Foo { i };
610 { 564 {
611 let i = 0; 565 let i = 0;
612 Foo { i } 566 Foo { i }
613 }
614 } 567 }
615 "#, 568}
616 "j", 569"#,
617 r#" 570 r#"
618 struct Foo { 571struct Foo { i: i32 }
619 i: i32,
620 }
621 572
622 fn baz(j: i32) -> Self { 573fn baz(j: i32) -> Self {
623 let x = Foo { i: j }; 574 let x = Foo { i: j };
624 { 575 {
625 let i = 0; 576 let i = 0;
626 Foo { i } 577 Foo { i }
627 }
628 } 578 }
629 "#, 579}
580"#,
630 ); 581 );
631 } 582 }
632 583
633 #[test] 584 #[test]
634 fn test_rename_mod() { 585 fn test_rename_mod() {
635 let (analysis, position) = analysis_and_position( 586 check_expect(
587 "foo2",
636 r#" 588 r#"
637//- /lib.rs 589//- /lib.rs
638mod bar; 590mod bar;
@@ -641,53 +593,49 @@ mod bar;
641mod foo<|>; 593mod foo<|>;
642 594
643//- /bar/foo.rs 595//- /bar/foo.rs
644// emtpy 596// empty
645 "#, 597"#,
646 ); 598 expect![[r#"
647 let new_name = "foo2"; 599 RangeInfo {
648 let source_change = analysis.rename(position, new_name).unwrap(); 600 range: 4..7,
649 assert_debug_snapshot!(&source_change, 601 info: SourceChange {
650@r###" 602 source_file_edits: [
651 Some( 603 SourceFileEdit {
652 RangeInfo { 604 file_id: FileId(
653 range: 4..7, 605 2,
654 info: SourceChange { 606 ),
655 source_file_edits: [ 607 edit: TextEdit {
656 SourceFileEdit { 608 indels: [
657 file_id: FileId( 609 Indel {
658 2, 610 insert: "foo2",
659 ), 611 delete: 4..7,
660 edit: TextEdit { 612 },
661 indels: [ 613 ],
662 Indel { 614 },
663 insert: "foo2",
664 delete: 4..7,
665 },
666 ],
667 }, 615 },
668 }, 616 ],
669 ], 617 file_system_edits: [
670 file_system_edits: [ 618 MoveFile {
671 MoveFile { 619 src: FileId(
672 src: FileId( 620 3,
673 3, 621 ),
674 ), 622 anchor: FileId(
675 anchor: FileId( 623 3,
676 2, 624 ),
677 ), 625 dst: "foo2.rs",
678 dst: "foo2.rs", 626 },
679 }, 627 ],
680 ], 628 is_snippet: false,
681 is_snippet: false, 629 },
682 }, 630 }
683 }, 631 "#]],
684 ) 632 );
685 "###);
686 } 633 }
687 634
688 #[test] 635 #[test]
689 fn test_rename_mod_in_use_tree() { 636 fn test_rename_mod_in_use_tree() {
690 let (analysis, position) = analysis_and_position( 637 check_expect(
638 "quux",
691 r#" 639 r#"
692//- /main.rs 640//- /main.rs
693pub mod foo; 641pub mod foo;
@@ -699,140 +647,173 @@ pub struct FooContent;
699 647
700//- /bar.rs 648//- /bar.rs
701use crate::foo<|>::FooContent; 649use crate::foo<|>::FooContent;
702 "#, 650"#,
703 ); 651 expect![[r#"
704 let new_name = "qux"; 652 RangeInfo {
705 let source_change = analysis.rename(position, new_name).unwrap(); 653 range: 11..14,
706 assert_debug_snapshot!(&source_change, 654 info: SourceChange {
707@r###" 655 source_file_edits: [
708 Some( 656 SourceFileEdit {
709 RangeInfo { 657 file_id: FileId(
710 range: 11..14, 658 1,
711 info: SourceChange { 659 ),
712 source_file_edits: [ 660 edit: TextEdit {
713 SourceFileEdit { 661 indels: [
714 file_id: FileId( 662 Indel {
715 1, 663 insert: "quux",
716 ), 664 delete: 8..11,
717 edit: TextEdit { 665 },
718 indels: [ 666 ],
719 Indel { 667 },
720 insert: "qux",
721 delete: 8..11,
722 },
723 ],
724 }, 668 },
725 }, 669 SourceFileEdit {
726 SourceFileEdit { 670 file_id: FileId(
727 file_id: FileId( 671 3,
728 3, 672 ),
729 ), 673 edit: TextEdit {
730 edit: TextEdit { 674 indels: [
731 indels: [ 675 Indel {
732 Indel { 676 insert: "quux",
733 insert: "qux", 677 delete: 11..14,
734 delete: 11..14, 678 },
735 }, 679 ],
736 ], 680 },
737 }, 681 },
738 }, 682 ],
739 ], 683 file_system_edits: [
740 file_system_edits: [ 684 MoveFile {
741 MoveFile { 685 src: FileId(
742 src: FileId( 686 2,
743 2, 687 ),
744 ), 688 anchor: FileId(
745 anchor: FileId( 689 2,
746 3, 690 ),
747 ), 691 dst: "quux.rs",
748 dst: "qux.rs", 692 },
749 }, 693 ],
750 ], 694 is_snippet: false,
751 is_snippet: false, 695 },
752 }, 696 }
753 }, 697 "#]],
754 ) 698 );
755 "###);
756 } 699 }
757 700
758 #[test] 701 #[test]
759 fn test_rename_mod_in_dir() { 702 fn test_rename_mod_in_dir() {
760 let (analysis, position) = analysis_and_position( 703 check_expect(
704 "foo2",
761 r#" 705 r#"
762//- /lib.rs 706//- /lib.rs
763mod fo<|>o; 707mod fo<|>o;
764//- /foo/mod.rs 708//- /foo/mod.rs
765// emtpy 709// emtpy
766 "#, 710"#,
767 ); 711 expect![[r#"
768 let new_name = "foo2"; 712 RangeInfo {
769 let source_change = analysis.rename(position, new_name).unwrap(); 713 range: 4..7,
770 assert_debug_snapshot!(&source_change, 714 info: SourceChange {
771 @r###" 715 source_file_edits: [
772 Some( 716 SourceFileEdit {
773 RangeInfo { 717 file_id: FileId(
774 range: 4..7, 718 1,
775 info: SourceChange { 719 ),
776 source_file_edits: [ 720 edit: TextEdit {
777 SourceFileEdit { 721 indels: [
778 file_id: FileId( 722 Indel {
779 1, 723 insert: "foo2",
780 ), 724 delete: 4..7,
781 edit: TextEdit { 725 },
782 indels: [ 726 ],
783 Indel { 727 },
784 insert: "foo2",
785 delete: 4..7,
786 },
787 ],
788 }, 728 },
789 }, 729 ],
790 ], 730 file_system_edits: [
791 file_system_edits: [ 731 MoveFile {
792 MoveFile { 732 src: FileId(
793 src: FileId( 733 2,
794 2, 734 ),
795 ), 735 anchor: FileId(
796 anchor: FileId( 736 2,
797 1, 737 ),
798 ), 738 dst: "../foo2/mod.rs",
799 dst: "../foo2/mod.rs", 739 },
800 }, 740 ],
801 ], 741 is_snippet: false,
802 is_snippet: false, 742 },
803 }, 743 }
804 }, 744 "#]],
805 ) 745 );
806 "###
807 );
808 } 746 }
809 747
810 #[test] 748 #[test]
811 fn test_module_rename_in_path() { 749 fn test_rename_unusually_nested_mod() {
812 test_rename( 750 check_expect(
751 "bar",
813 r#" 752 r#"
814 mod <|>foo { 753//- /lib.rs
815 pub fn bar() {} 754mod outer { mod fo<|>o; }
755
756//- /outer/foo.rs
757// emtpy
758"#,
759 expect![[r#"
760 RangeInfo {
761 range: 16..19,
762 info: SourceChange {
763 source_file_edits: [
764 SourceFileEdit {
765 file_id: FileId(
766 1,
767 ),
768 edit: TextEdit {
769 indels: [
770 Indel {
771 insert: "bar",
772 delete: 16..19,
773 },
774 ],
775 },
776 },
777 ],
778 file_system_edits: [
779 MoveFile {
780 src: FileId(
781 2,
782 ),
783 anchor: FileId(
784 2,
785 ),
786 dst: "bar.rs",
787 },
788 ],
789 is_snippet: false,
790 },
791 }
792 "#]],
793 );
816 } 794 }
817 795
818 fn main() { 796 #[test]
819 foo::bar(); 797 fn test_module_rename_in_path() {
820 }"#, 798 check(
821 "baz", 799 "baz",
822 r#" 800 r#"
823 mod baz { 801mod <|>foo { pub fn bar() {} }
824 pub fn bar() {} 802
825 } 803fn main() { foo::bar(); }
804"#,
805 r#"
806mod baz { pub fn bar() {} }
826 807
827 fn main() { 808fn main() { baz::bar(); }
828 baz::bar(); 809"#,
829 }"#,
830 ); 810 );
831 } 811 }
832 812
833 #[test] 813 #[test]
834 fn test_rename_mod_filename_and_path() { 814 fn test_rename_mod_filename_and_path() {
835 let (analysis, position) = analysis_and_position( 815 check_expect(
816 "foo2",
836 r#" 817 r#"
837//- /lib.rs 818//- /lib.rs
838mod bar; 819mod bar;
@@ -845,229 +826,185 @@ pub mod foo<|>;
845 826
846//- /bar/foo.rs 827//- /bar/foo.rs
847// pub fn fun() {} 828// pub fn fun() {}
848 "#, 829"#,
849 ); 830 expect![[r#"
850 let new_name = "foo2"; 831 RangeInfo {
851 let source_change = analysis.rename(position, new_name).unwrap(); 832 range: 8..11,
852 assert_debug_snapshot!(&source_change, 833 info: SourceChange {
853@r###" 834 source_file_edits: [
854 Some( 835 SourceFileEdit {
855 RangeInfo { 836 file_id: FileId(
856 range: 8..11, 837 2,
857 info: SourceChange { 838 ),
858 source_file_edits: [ 839 edit: TextEdit {
859 SourceFileEdit { 840 indels: [
860 file_id: FileId( 841 Indel {
861 2, 842 insert: "foo2",
862 ), 843 delete: 8..11,
863 edit: TextEdit { 844 },
864 indels: [ 845 ],
865 Indel { 846 },
866 insert: "foo2",
867 delete: 8..11,
868 },
869 ],
870 }, 847 },
871 }, 848 SourceFileEdit {
872 SourceFileEdit { 849 file_id: FileId(
873 file_id: FileId( 850 1,
874 1, 851 ),
875 ), 852 edit: TextEdit {
876 edit: TextEdit { 853 indels: [
877 indels: [ 854 Indel {
878 Indel { 855 insert: "foo2",
879 insert: "foo2", 856 delete: 27..30,
880 delete: 27..30, 857 },
881 }, 858 ],
882 ], 859 },
883 }, 860 },
884 }, 861 ],
885 ], 862 file_system_edits: [
886 file_system_edits: [ 863 MoveFile {
887 MoveFile { 864 src: FileId(
888 src: FileId( 865 3,
889 3, 866 ),
890 ), 867 anchor: FileId(
891 anchor: FileId( 868 3,
892 2, 869 ),
893 ), 870 dst: "foo2.rs",
894 dst: "foo2.rs", 871 },
895 }, 872 ],
896 ], 873 is_snippet: false,
897 is_snippet: false, 874 },
898 }, 875 }
899 }, 876 "#]],
900 ) 877 );
901 "###);
902 } 878 }
903 879
904 #[test] 880 #[test]
905 fn test_enum_variant_from_module_1() { 881 fn test_enum_variant_from_module_1() {
906 test_rename( 882 check(
883 "Baz",
907 r#" 884 r#"
908 mod foo { 885mod foo {
909 pub enum Foo { 886 pub enum Foo { Bar<|> }
910 Bar<|>, 887}
911 }
912 }
913 888
914 fn func(f: foo::Foo) { 889fn func(f: foo::Foo) {
915 match f { 890 match f {
916 foo::Foo::Bar => {} 891 foo::Foo::Bar => {}
917 }
918 } 892 }
919 "#, 893}
920 "Baz", 894"#,
921 r#" 895 r#"
922 mod foo { 896mod foo {
923 pub enum Foo { 897 pub enum Foo { Baz }
924 Baz, 898}
925 }
926 }
927 899
928 fn func(f: foo::Foo) { 900fn func(f: foo::Foo) {
929 match f { 901 match f {
930 foo::Foo::Baz => {} 902 foo::Foo::Baz => {}
931 }
932 } 903 }
933 "#, 904}
905"#,
934 ); 906 );
935 } 907 }
936 908
937 #[test] 909 #[test]
938 fn test_enum_variant_from_module_2() { 910 fn test_enum_variant_from_module_2() {
939 test_rename( 911 check(
912 "baz",
940 r#" 913 r#"
941 mod foo { 914mod foo {
942 pub struct Foo { 915 pub struct Foo { pub bar<|>: uint }
943 pub bar<|>: uint, 916}
944 }
945 }
946 917
947 fn foo(f: foo::Foo) { 918fn foo(f: foo::Foo) {
948 let _ = f.bar; 919 let _ = f.bar;
949 } 920}
950 "#, 921"#,
951 "baz",
952 r#" 922 r#"
953 mod foo { 923mod foo {
954 pub struct Foo { 924 pub struct Foo { pub baz: uint }
955 pub baz: uint, 925}
956 }
957 }
958 926
959 fn foo(f: foo::Foo) { 927fn foo(f: foo::Foo) {
960 let _ = f.baz; 928 let _ = f.baz;
961 } 929}
962 "#, 930"#,
963 ); 931 );
964 } 932 }
965 933
966 #[test] 934 #[test]
967 fn test_parameter_to_self() { 935 fn test_parameter_to_self() {
968 test_rename( 936 check(
937 "self",
969 r#" 938 r#"
970 struct Foo { 939struct Foo { i: i32 }
971 i: i32,
972 }
973 940
974 impl Foo { 941impl Foo {
975 fn f(foo<|>: &mut Foo) -> i32 { 942 fn f(foo<|>: &mut Foo) -> i32 {
976 foo.i 943 foo.i
977 }
978 } 944 }
979 "#, 945}
980 "self", 946"#,
981 r#" 947 r#"
982 struct Foo { 948struct Foo { i: i32 }
983 i: i32,
984 }
985 949
986 impl Foo { 950impl Foo {
987 fn f(&mut self) -> i32 { 951 fn f(&mut self) -> i32 {
988 self.i 952 self.i
989 }
990 } 953 }
991 "#, 954}
955"#,
992 ); 956 );
993 } 957 }
994 958
995 #[test] 959 #[test]
996 fn test_self_to_parameter() { 960 fn test_self_to_parameter() {
997 test_rename( 961 check(
962 "foo",
998 r#" 963 r#"
999 struct Foo { 964struct Foo { i: i32 }
1000 i: i32,
1001 }
1002 965
1003 impl Foo { 966impl Foo {
1004 fn f(&mut <|>self) -> i32 { 967 fn f(&mut <|>self) -> i32 {
1005 self.i 968 self.i
1006 }
1007 } 969 }
1008 "#, 970}
1009 "foo", 971"#,
1010 r#" 972 r#"
1011 struct Foo { 973struct Foo { i: i32 }
1012 i: i32,
1013 }
1014 974
1015 impl Foo { 975impl Foo {
1016 fn f(foo: &mut Foo) -> i32 { 976 fn f(foo: &mut Foo) -> i32 {
1017 foo.i 977 foo.i
1018 }
1019 } 978 }
1020 "#, 979}
980"#,
1021 ); 981 );
1022 } 982 }
1023 983
1024 #[test] 984 #[test]
1025 fn test_self_in_path_to_parameter() { 985 fn test_self_in_path_to_parameter() {
1026 test_rename( 986 check(
987 "foo",
1027 r#" 988 r#"
1028 struct Foo { 989struct Foo { i: i32 }
1029 i: i32,
1030 }
1031 990
1032 impl Foo { 991impl Foo {
1033 fn f(&self) -> i32 { 992 fn f(&self) -> i32 {
1034 let self_var = 1; 993 let self_var = 1;
1035 self<|>.i 994 self<|>.i
1036 }
1037 } 995 }
1038 "#, 996}
1039 "foo", 997"#,
1040 r#" 998 r#"
1041 struct Foo { 999struct Foo { i: i32 }
1042 i: i32,
1043 }
1044 1000
1045 impl Foo { 1001impl Foo {
1046 fn f(foo: &Foo) -> i32 { 1002 fn f(foo: &Foo) -> i32 {
1047 let self_var = 1; 1003 let self_var = 1;
1048 foo.i 1004 foo.i
1049 }
1050 } 1005 }
1051 "#, 1006}
1007"#,
1052 ); 1008 );
1053 } 1009 }
1054
1055 fn test_rename(ra_fixture_before: &str, new_name: &str, ra_fixture_after: &str) {
1056 let ra_fixture_after = &trim_indent(ra_fixture_after);
1057 let (analysis, position) = analysis_and_position(ra_fixture_before);
1058 let source_change = analysis.rename(position, new_name).unwrap();
1059 let mut text_edit_builder = TextEditBuilder::default();
1060 let mut file_id: Option<FileId> = None;
1061 if let Some(change) = source_change {
1062 for edit in change.info.source_file_edits {
1063 file_id = Some(edit.file_id);
1064 for indel in edit.edit.into_iter() {
1065 text_edit_builder.replace(indel.delete, indel.insert);
1066 }
1067 }
1068 }
1069 let mut result = analysis.file_text(file_id.unwrap()).unwrap().to_string();
1070 text_edit_builder.finish().apply(&mut result);
1071 assert_eq_text!(ra_fixture_after, &*result);
1072 }
1073} 1010}