diff options
-rw-r--r-- | crates/ra_ide_api/src/lib.rs | 4 | ||||
-rw-r--r-- | crates/ra_ide_api/src/references.rs | 154 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/handlers.rs | 14 |
3 files changed, 92 insertions, 80 deletions
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs index 514dcaf96..e90fbd428 100644 --- a/crates/ra_ide_api/src/lib.rs +++ b/crates/ra_ide_api/src/lib.rs | |||
@@ -466,7 +466,7 @@ impl Analysis { | |||
466 | &self, | 466 | &self, |
467 | position: FilePosition, | 467 | position: FilePosition, |
468 | ) -> Cancelable<Option<ReferenceSearchResult>> { | 468 | ) -> Cancelable<Option<ReferenceSearchResult>> { |
469 | self.with_db(|db| references::find_all_refs(db, position)) | 469 | self.with_db(|db| references::find_all_refs(db, position).map(|it| it.info)) |
470 | } | 470 | } |
471 | 471 | ||
472 | /// Returns a short text describing element at position. | 472 | /// Returns a short text describing element at position. |
@@ -536,7 +536,7 @@ impl Analysis { | |||
536 | &self, | 536 | &self, |
537 | position: FilePosition, | 537 | position: FilePosition, |
538 | new_name: &str, | 538 | new_name: &str, |
539 | ) -> Cancelable<Option<SourceChange>> { | 539 | ) -> Cancelable<Option<RangeInfo<SourceChange>>> { |
540 | self.with_db(|db| references::rename(db, position, new_name)) | 540 | self.with_db(|db| references::rename(db, position, new_name)) |
541 | } | 541 | } |
542 | 542 | ||
diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs index d8a00067f..5f1f0efc3 100644 --- a/crates/ra_ide_api/src/references.rs +++ b/crates/ra_ide_api/src/references.rs | |||
@@ -4,7 +4,7 @@ use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SourceFile, SyntaxNode} | |||
4 | use relative_path::{RelativePath, RelativePathBuf}; | 4 | use relative_path::{RelativePath, RelativePathBuf}; |
5 | 5 | ||
6 | use crate::{ | 6 | use crate::{ |
7 | db::RootDatabase, FileId, FilePosition, FileRange, FileSystemEdit, NavigationTarget, | 7 | db::RootDatabase, FileId, FilePosition, FileRange, FileSystemEdit, NavigationTarget, RangeInfo, |
8 | SourceChange, SourceFileEdit, TextRange, | 8 | SourceChange, SourceFileEdit, TextRange, |
9 | }; | 9 | }; |
10 | 10 | ||
@@ -48,9 +48,9 @@ impl IntoIterator for ReferenceSearchResult { | |||
48 | pub(crate) fn find_all_refs( | 48 | pub(crate) fn find_all_refs( |
49 | db: &RootDatabase, | 49 | db: &RootDatabase, |
50 | position: FilePosition, | 50 | position: FilePosition, |
51 | ) -> Option<ReferenceSearchResult> { | 51 | ) -> Option<RangeInfo<ReferenceSearchResult>> { |
52 | let parse = db.parse(position.file_id); | 52 | let parse = db.parse(position.file_id); |
53 | let (binding, analyzer) = find_binding(db, &parse.tree(), position)?; | 53 | let RangeInfo { range, info: (binding, analyzer) } = find_binding(db, &parse.tree(), position)?; |
54 | let declaration = NavigationTarget::from_bind_pat(position.file_id, &binding); | 54 | let declaration = NavigationTarget::from_bind_pat(position.file_id, &binding); |
55 | 55 | ||
56 | let references = analyzer | 56 | let references = analyzer |
@@ -59,24 +59,26 @@ pub(crate) fn find_all_refs( | |||
59 | .map(move |ref_desc| FileRange { file_id: position.file_id, range: ref_desc.range }) | 59 | .map(move |ref_desc| FileRange { file_id: position.file_id, range: ref_desc.range }) |
60 | .collect::<Vec<_>>(); | 60 | .collect::<Vec<_>>(); |
61 | 61 | ||
62 | return Some(ReferenceSearchResult { declaration, references }); | 62 | return Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references })); |
63 | 63 | ||
64 | fn find_binding<'a>( | 64 | fn find_binding<'a>( |
65 | db: &RootDatabase, | 65 | db: &RootDatabase, |
66 | source_file: &SourceFile, | 66 | source_file: &SourceFile, |
67 | position: FilePosition, | 67 | position: FilePosition, |
68 | ) -> Option<(ast::BindPat, hir::SourceAnalyzer)> { | 68 | ) -> Option<RangeInfo<(ast::BindPat, hir::SourceAnalyzer)>> { |
69 | let syntax = source_file.syntax(); | 69 | let syntax = source_file.syntax(); |
70 | if let Some(binding) = find_node_at_offset::<ast::BindPat>(syntax, position.offset) { | 70 | if let Some(binding) = find_node_at_offset::<ast::BindPat>(syntax, position.offset) { |
71 | let range = binding.syntax().text_range(); | ||
71 | let analyzer = hir::SourceAnalyzer::new(db, position.file_id, binding.syntax(), None); | 72 | let analyzer = hir::SourceAnalyzer::new(db, position.file_id, binding.syntax(), None); |
72 | return Some((binding, analyzer)); | 73 | return Some(RangeInfo::new(range, (binding, analyzer))); |
73 | }; | 74 | }; |
74 | let name_ref = find_node_at_offset::<ast::NameRef>(syntax, position.offset)?; | 75 | let name_ref = find_node_at_offset::<ast::NameRef>(syntax, position.offset)?; |
76 | let range = name_ref.syntax().text_range(); | ||
75 | let analyzer = hir::SourceAnalyzer::new(db, position.file_id, name_ref.syntax(), None); | 77 | let analyzer = hir::SourceAnalyzer::new(db, position.file_id, name_ref.syntax(), None); |
76 | let resolved = analyzer.resolve_local_name(&name_ref)?; | 78 | let resolved = analyzer.resolve_local_name(&name_ref)?; |
77 | if let Either::A(ptr) = resolved.ptr() { | 79 | if let Either::A(ptr) = resolved.ptr() { |
78 | if let ast::Pat::BindPat(binding) = ptr.to_node(source_file.syntax()) { | 80 | if let ast::Pat::BindPat(binding) = ptr.to_node(source_file.syntax()) { |
79 | return Some((binding, analyzer)); | 81 | return Some(RangeInfo::new(range, (binding, analyzer))); |
80 | } | 82 | } |
81 | } | 83 | } |
82 | None | 84 | None |
@@ -87,12 +89,14 @@ pub(crate) fn rename( | |||
87 | db: &RootDatabase, | 89 | db: &RootDatabase, |
88 | position: FilePosition, | 90 | position: FilePosition, |
89 | new_name: &str, | 91 | new_name: &str, |
90 | ) -> Option<SourceChange> { | 92 | ) -> Option<RangeInfo<SourceChange>> { |
91 | let parse = db.parse(position.file_id); | 93 | let parse = db.parse(position.file_id); |
92 | if let Some((ast_name, ast_module)) = | 94 | if let Some((ast_name, ast_module)) = |
93 | find_name_and_module_at_offset(parse.tree().syntax(), position) | 95 | find_name_and_module_at_offset(parse.tree().syntax(), position) |
94 | { | 96 | { |
97 | let range = ast_name.syntax().text_range(); | ||
95 | rename_mod(db, &ast_name, &ast_module, position, new_name) | 98 | rename_mod(db, &ast_name, &ast_module, position, new_name) |
99 | .map(|info| RangeInfo::new(range, info)) | ||
96 | } else { | 100 | } else { |
97 | rename_reference(db, position, new_name) | 101 | rename_reference(db, position, new_name) |
98 | } | 102 | } |
@@ -107,7 +111,7 @@ fn find_name_and_module_at_offset( | |||
107 | Some((ast_name, ast_module)) | 111 | Some((ast_name, ast_module)) |
108 | } | 112 | } |
109 | 113 | ||
110 | fn source_edit_from_fileid_range( | 114 | fn source_edit_from_file_id_range( |
111 | file_id: FileId, | 115 | file_id: FileId, |
112 | range: TextRange, | 116 | range: TextRange, |
113 | new_name: &str, | 117 | new_name: &str, |
@@ -179,19 +183,19 @@ fn rename_reference( | |||
179 | db: &RootDatabase, | 183 | db: &RootDatabase, |
180 | position: FilePosition, | 184 | position: FilePosition, |
181 | new_name: &str, | 185 | new_name: &str, |
182 | ) -> Option<SourceChange> { | 186 | ) -> Option<RangeInfo<SourceChange>> { |
183 | let refs = find_all_refs(db, position)?; | 187 | let RangeInfo { range, info: refs } = find_all_refs(db, position)?; |
184 | 188 | ||
185 | let edit = refs | 189 | let edit = refs |
186 | .into_iter() | 190 | .into_iter() |
187 | .map(|range| source_edit_from_fileid_range(range.file_id, range.range, new_name)) | 191 | .map(|range| source_edit_from_file_id_range(range.file_id, range.range, new_name)) |
188 | .collect::<Vec<_>>(); | 192 | .collect::<Vec<_>>(); |
189 | 193 | ||
190 | if edit.is_empty() { | 194 | if edit.is_empty() { |
191 | return None; | 195 | return None; |
192 | } | 196 | } |
193 | 197 | ||
194 | Some(SourceChange::source_file_edits("rename", edit)) | 198 | Some(RangeInfo::new(range, SourceChange::source_file_edits("rename", edit))) |
195 | } | 199 | } |
196 | 200 | ||
197 | #[cfg(test)] | 201 | #[cfg(test)] |
@@ -342,38 +346,43 @@ mod tests { | |||
342 | let new_name = "foo2"; | 346 | let new_name = "foo2"; |
343 | let source_change = analysis.rename(position, new_name).unwrap(); | 347 | let source_change = analysis.rename(position, new_name).unwrap(); |
344 | assert_debug_snapshot!(&source_change, | 348 | assert_debug_snapshot!(&source_change, |
345 | @r#"Some( | 349 | @r###" |
346 | SourceChange { | 350 | Some( |
347 | label: "rename", | 351 | RangeInfo { |
348 | source_file_edits: [ | 352 | range: [4; 7), |
349 | SourceFileEdit { | 353 | info: SourceChange { |
350 | file_id: FileId( | 354 | label: "rename", |
351 | 2, | 355 | source_file_edits: [ |
352 | ), | 356 | SourceFileEdit { |
353 | edit: TextEdit { | 357 | file_id: FileId( |
354 | atoms: [ | 358 | 2, |
355 | AtomTextEdit { | 359 | ), |
356 | delete: [4; 7), | 360 | edit: TextEdit { |
357 | insert: "foo2", | 361 | atoms: [ |
362 | AtomTextEdit { | ||
363 | delete: [4; 7), | ||
364 | insert: "foo2", | ||
365 | }, | ||
366 | ], | ||
367 | }, | ||
368 | }, | ||
369 | ], | ||
370 | file_system_edits: [ | ||
371 | MoveFile { | ||
372 | src: FileId( | ||
373 | 3, | ||
374 | ), | ||
375 | dst_source_root: SourceRootId( | ||
376 | 0, | ||
377 | ), | ||
378 | dst_path: "bar/foo2.rs", | ||
358 | }, | 379 | }, |
359 | ], | 380 | ], |
381 | cursor_position: None, | ||
360 | }, | 382 | }, |
361 | }, | 383 | }, |
362 | ], | 384 | ) |
363 | file_system_edits: [ | 385 | "###); |
364 | MoveFile { | ||
365 | src: FileId( | ||
366 | 3, | ||
367 | ), | ||
368 | dst_source_root: SourceRootId( | ||
369 | 0, | ||
370 | ), | ||
371 | dst_path: "bar/foo2.rs", | ||
372 | }, | ||
373 | ], | ||
374 | cursor_position: None, | ||
375 | }, | ||
376 | )"#); | ||
377 | } | 386 | } |
378 | 387 | ||
379 | #[test] | 388 | #[test] |
@@ -389,38 +398,43 @@ mod tests { | |||
389 | let new_name = "foo2"; | 398 | let new_name = "foo2"; |
390 | let source_change = analysis.rename(position, new_name).unwrap(); | 399 | let source_change = analysis.rename(position, new_name).unwrap(); |
391 | assert_debug_snapshot!(&source_change, | 400 | assert_debug_snapshot!(&source_change, |
392 | @r###"Some( | 401 | @r###" |
393 | SourceChange { | 402 | Some( |
394 | label: "rename", | 403 | RangeInfo { |
395 | source_file_edits: [ | 404 | range: [4; 7), |
396 | SourceFileEdit { | 405 | info: SourceChange { |
397 | file_id: FileId( | 406 | label: "rename", |
398 | 1, | 407 | source_file_edits: [ |
399 | ), | 408 | SourceFileEdit { |
400 | edit: TextEdit { | 409 | file_id: FileId( |
401 | atoms: [ | 410 | 1, |
402 | AtomTextEdit { | 411 | ), |
403 | delete: [4; 7), | 412 | edit: TextEdit { |
404 | insert: "foo2", | 413 | atoms: [ |
414 | AtomTextEdit { | ||
415 | delete: [4; 7), | ||
416 | insert: "foo2", | ||
417 | }, | ||
418 | ], | ||
419 | }, | ||
420 | }, | ||
421 | ], | ||
422 | file_system_edits: [ | ||
423 | MoveFile { | ||
424 | src: FileId( | ||
425 | 2, | ||
426 | ), | ||
427 | dst_source_root: SourceRootId( | ||
428 | 0, | ||
429 | ), | ||
430 | dst_path: "foo2/mod.rs", | ||
405 | }, | 431 | }, |
406 | ], | 432 | ], |
433 | cursor_position: None, | ||
407 | }, | 434 | }, |
408 | }, | 435 | }, |
409 | ], | 436 | ) |
410 | file_system_edits: [ | 437 | "### |
411 | MoveFile { | ||
412 | src: FileId( | ||
413 | 2, | ||
414 | ), | ||
415 | dst_source_root: SourceRootId( | ||
416 | 0, | ||
417 | ), | ||
418 | dst_path: "foo2/mod.rs", | ||
419 | }, | ||
420 | ], | ||
421 | cursor_position: None, | ||
422 | }, | ||
423 | )"### | ||
424 | ); | 438 | ); |
425 | } | 439 | } |
426 | 440 | ||
@@ -430,7 +444,7 @@ mod tests { | |||
430 | let mut text_edit_builder = ra_text_edit::TextEditBuilder::default(); | 444 | let mut text_edit_builder = ra_text_edit::TextEditBuilder::default(); |
431 | let mut file_id: Option<FileId> = None; | 445 | let mut file_id: Option<FileId> = None; |
432 | if let Some(change) = source_change { | 446 | if let Some(change) = source_change { |
433 | for edit in change.source_file_edits { | 447 | for edit in change.info.source_file_edits { |
434 | file_id = Some(edit.file_id); | 448 | file_id = Some(edit.file_id); |
435 | for atom in edit.edit.as_atoms() { | 449 | for atom in edit.edit.as_atoms() { |
436 | text_edit_builder.replace(atom.delete, atom.insert.clone()); | 450 | text_edit_builder.replace(atom.delete, atom.insert.clone()); |
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index eb805a6d3..948d543ea 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs | |||
@@ -460,18 +460,16 @@ pub fn handle_prepare_rename( | |||
460 | 460 | ||
461 | // We support renaming references like handle_rename does. | 461 | // We support renaming references like handle_rename does. |
462 | // In the future we may want to reject the renaming of things like keywords here too. | 462 | // In the future we may want to reject the renaming of things like keywords here too. |
463 | let refs = match world.analysis().find_all_refs(position)? { | 463 | let optional_change = world.analysis().rename(position, "dummy")?; |
464 | let range = match optional_change { | ||
464 | None => return Ok(None), | 465 | None => return Ok(None), |
465 | Some(refs) => refs, | 466 | Some(it) => it.range, |
466 | }; | 467 | }; |
467 | 468 | ||
468 | // Refs should always have a declaration | ||
469 | let r = refs.declaration(); | ||
470 | let file_id = params.text_document.try_conv_with(&world)?; | 469 | let file_id = params.text_document.try_conv_with(&world)?; |
471 | let line_index = world.analysis().file_line_index(file_id)?; | 470 | let line_index = world.analysis().file_line_index(file_id)?; |
472 | let loc = to_location(r.file_id(), r.range(), &world, &line_index)?; | 471 | let range = range.conv_with(&line_index); |
473 | 472 | Ok(Some(PrepareRenameResponse::Range(range))) | |
474 | Ok(Some(PrepareRenameResponse::Range(loc.range))) | ||
475 | } | 473 | } |
476 | 474 | ||
477 | pub fn handle_rename(world: WorldSnapshot, params: RenameParams) -> Result<Option<WorkspaceEdit>> { | 475 | pub fn handle_rename(world: WorldSnapshot, params: RenameParams) -> Result<Option<WorkspaceEdit>> { |
@@ -488,7 +486,7 @@ pub fn handle_rename(world: WorldSnapshot, params: RenameParams) -> Result<Optio | |||
488 | let optional_change = world.analysis().rename(position, &*params.new_name)?; | 486 | let optional_change = world.analysis().rename(position, &*params.new_name)?; |
489 | let change = match optional_change { | 487 | let change = match optional_change { |
490 | None => return Ok(None), | 488 | None => return Ok(None), |
491 | Some(it) => it, | 489 | Some(it) => it.info, |
492 | }; | 490 | }; |
493 | 491 | ||
494 | let source_change_req = change.try_conv_with(&world)?; | 492 | let source_change_req = change.try_conv_with(&world)?; |