From d26d0ada50fd0063c03e28bc2673f9f63fd23d95 Mon Sep 17 00:00:00 2001 From: Ekaterina Babshukova Date: Sat, 12 Oct 2019 18:47:17 +0300 Subject: restructure a bit --- crates/ra_ide_api/src/references.rs | 417 ++++++------------------------------ 1 file changed, 66 insertions(+), 351 deletions(-) (limited to 'crates/ra_ide_api/src/references.rs') diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs index e640b92cf..f54542787 100644 --- a/crates/ra_ide_api/src/references.rs +++ b/crates/ra_ide_api/src/references.rs @@ -1,16 +1,19 @@ //! FIXME: write short doc here -use hir::ModuleSource; +mod classify; +mod definition; +mod rename; +mod search_scope; + use ra_db::{SourceDatabase, SourceDatabaseExt}; -use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SyntaxNode}; -use relative_path::{RelativePath, RelativePathBuf}; - -use crate::{ - db::RootDatabase, - name_kind::{classify_name, classify_name_ref, Definition, NameKind::*}, - search_scope::find_refs, - FileId, FilePosition, FileRange, FileSystemEdit, NavigationTarget, RangeInfo, SourceChange, - SourceFileEdit, TextRange, +use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SourceFile, SyntaxNode, TextUnit}; + +use crate::{db::RootDatabase, FileId, FilePosition, FileRange, NavigationTarget, RangeInfo}; + +pub(crate) use self::{ + classify::{classify_name, classify_name_ref}, + definition::{Definition, NameKind}, + rename::rename, }; #[derive(Debug, Clone)] @@ -59,169 +62,84 @@ pub(crate) fn find_all_refs( let RangeInfo { range, info: (name, def) } = find_name(db, &syntax, position)?; let declaration = match def.item { - Macro(mac) => NavigationTarget::from_macro_def(db, mac), - FieldAccess(field) => NavigationTarget::from_field(db, field), - AssocItem(assoc) => NavigationTarget::from_assoc_item(db, assoc), - Def(def) => NavigationTarget::from_def(db, def)?, - SelfType(ref ty) => match ty.as_adt() { + NameKind::Macro(mac) => NavigationTarget::from_macro_def(db, mac), + NameKind::FieldAccess(field) => NavigationTarget::from_field(db, field), + NameKind::AssocItem(assoc) => NavigationTarget::from_assoc_item(db, assoc), + NameKind::Def(def) => NavigationTarget::from_def(db, def)?, + NameKind::SelfType(ref ty) => match ty.as_adt() { Some((def_id, _)) => NavigationTarget::from_adt_def(db, def_id), None => return None, }, - Pat((_, pat)) => NavigationTarget::from_pat(db, position.file_id, pat), - SelfParam(par) => NavigationTarget::from_self_param(position.file_id, par), - GenericParam(_) => return None, + NameKind::Pat((_, pat)) => NavigationTarget::from_pat(db, position.file_id, pat), + NameKind::SelfParam(par) => NavigationTarget::from_self_param(position.file_id, par), + NameKind::GenericParam(_) => return None, }; - // let references = match name_kind { - // Pat((_, pat)) => analyzer - // .find_all_refs(&pat.to_node(&syntax)) - // .into_iter() - // .map(move |ref_desc| FileRange { file_id: position.file_id, range: ref_desc.range }) - // .collect::>(), - // _ => vec![], - // }; - let references = find_refs(db, def, name); - - return Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references })); - - fn find_name<'a>( - db: &RootDatabase, - syntax: &SyntaxNode, - position: FilePosition, - ) -> Option> { - if let Some(name) = find_node_at_offset::(&syntax, position.offset) { - let def = classify_name(db, position.file_id, &name)?; - let range = name.syntax().text_range(); - return Some(RangeInfo::new(range, (name.text().to_string(), def))); - } - let name_ref = find_node_at_offset::(&syntax, position.offset)?; - let range = name_ref.syntax().text_range(); - let analyzer = hir::SourceAnalyzer::new(db, position.file_id, name_ref.syntax(), None); - let def = classify_name_ref(db, position.file_id, &analyzer, &name_ref)?; - Some(RangeInfo::new(range, (name_ref.text().to_string(), def))) - } -} + let references = process_definition(db, def, name); -pub(crate) fn rename( - db: &RootDatabase, - position: FilePosition, - new_name: &str, -) -> Option> { - let parse = db.parse(position.file_id); - if let Some((ast_name, ast_module)) = - find_name_and_module_at_offset(parse.tree().syntax(), position) - { - let range = ast_name.syntax().text_range(); - rename_mod(db, &ast_name, &ast_module, position, new_name) - .map(|info| RangeInfo::new(range, info)) - } else { - rename_reference(db, position, new_name) - } + Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references })) } -fn find_name_and_module_at_offset( +fn find_name<'a>( + db: &RootDatabase, syntax: &SyntaxNode, position: FilePosition, -) -> Option<(ast::Name, ast::Module)> { - let ast_name = find_node_at_offset::(syntax, position.offset)?; - let ast_module = ast::Module::cast(ast_name.syntax().parent()?)?; - Some((ast_name, ast_module)) -} - -fn source_edit_from_file_id_range( - file_id: FileId, - range: TextRange, - new_name: &str, -) -> SourceFileEdit { - SourceFileEdit { - file_id, - edit: { - let mut builder = ra_text_edit::TextEditBuilder::default(); - builder.replace(range, new_name.into()); - builder.finish() - }, +) -> Option> { + if let Some(name) = find_node_at_offset::(&syntax, position.offset) { + let def = classify_name(db, position.file_id, &name)?; + let range = name.syntax().text_range(); + return Some(RangeInfo::new(range, (name.text().to_string(), def))); } + let name_ref = find_node_at_offset::(&syntax, position.offset)?; + let def = classify_name_ref(db, position.file_id, &name_ref)?; + let range = name_ref.syntax().text_range(); + Some(RangeInfo::new(range, (name_ref.text().to_string(), def))) } -fn rename_mod( - db: &RootDatabase, - ast_name: &ast::Name, - ast_module: &ast::Module, - position: FilePosition, - new_name: &str, -) -> Option { - let mut source_file_edits = Vec::new(); - let mut file_system_edits = Vec::new(); - let module_src = hir::Source { file_id: position.file_id.into(), ast: ast_module.clone() }; - if let Some(module) = hir::Module::from_declaration(db, module_src) { - let src = module.definition_source(db); - let file_id = src.file_id.original_file(db); - match src.ast { - ModuleSource::SourceFile(..) => { - let mod_path: RelativePathBuf = db.file_relative_path(file_id); - // mod is defined in path/to/dir/mod.rs - let dst_path = if mod_path.file_stem() == Some("mod") { - mod_path - .parent() - .and_then(|p| p.parent()) - .or_else(|| Some(RelativePath::new(""))) - .map(|p| p.join(new_name).join("mod.rs")) - } else { - Some(mod_path.with_file_name(new_name).with_extension("rs")) - }; - if let Some(path) = dst_path { - let move_file = FileSystemEdit::MoveFile { - src: file_id, - dst_source_root: db.file_source_root(position.file_id), - dst_path: path, - }; - file_system_edits.push(move_file); - } - } - ModuleSource::Module(..) => {} +fn process_definition(db: &RootDatabase, def: Definition, name: String) -> Vec { + let pat = name.as_str(); + let scope = def.scope(db).scope; + let mut refs = vec![]; + + let is_match = |file_id: FileId, name_ref: &ast::NameRef| -> bool { + let classified = classify_name_ref(db, file_id, &name_ref); + if let Some(d) = classified { + d == def + } else { + false } - } - - let edit = SourceFileEdit { - file_id: position.file_id, - edit: { - let mut builder = ra_text_edit::TextEditBuilder::default(); - builder.replace(ast_name.syntax().text_range(), new_name.into()); - builder.finish() - }, }; - source_file_edits.push(edit); - - Some(SourceChange::from_edits("rename", source_file_edits, file_system_edits)) -} - -fn rename_reference( - db: &RootDatabase, - position: FilePosition, - new_name: &str, -) -> Option> { - let RangeInfo { range, info: refs } = find_all_refs(db, position)?; - - let edit = refs - .into_iter() - .map(|range| source_edit_from_file_id_range(range.file_id, range.range, new_name)) - .collect::>(); - if edit.is_empty() { - return None; + for (file_id, text_range) in scope { + let text = db.file_text(file_id); + let parse = SourceFile::parse(&text); + let syntax = parse.tree().syntax().clone(); + + for (idx, _) in text.match_indices(pat) { + let offset = TextUnit::from_usize(idx); + if let Some(name_ref) = find_node_at_offset::(&syntax, offset) { + let range = name_ref.syntax().text_range(); + + if let Some(text_range) = text_range { + if range.is_subrange(&text_range) && is_match(file_id, &name_ref) { + refs.push(FileRange { file_id, range }); + } + } else if is_match(file_id, &name_ref) { + refs.push(FileRange { file_id, range }); + } + } + } } - Some(RangeInfo::new(range, SourceChange::source_file_edits("rename", edit))) + return refs; } #[cfg(test)] mod tests { use crate::{ - mock_analysis::analysis_and_position, mock_analysis::single_file_with_position, FileId, + mock_analysis::analysis_and_position, mock_analysis::single_file_with_position, ReferenceSearchResult, }; - use insta::assert_debug_snapshot; - use test_utils::assert_eq_text; #[test] fn test_find_all_refs_for_local() { @@ -353,207 +271,4 @@ mod tests { let (analysis, position) = single_file_with_position(text); analysis.find_all_refs(position).unwrap().unwrap() } - - #[test] - fn test_rename_for_local() { - test_rename( - r#" - fn main() { - let mut i = 1; - let j = 1; - i = i<|> + j; - - { - i = 0; - } - - i = 5; - }"#, - "k", - r#" - fn main() { - let mut k = 1; - let j = 1; - k = k + j; - - { - k = 0; - } - - k = 5; - }"#, - ); - } - - #[test] - fn test_rename_for_param_inside() { - test_rename( - r#" - fn foo(i : u32) -> u32 { - i<|> - }"#, - "j", - r#" - fn foo(j : u32) -> u32 { - j - }"#, - ); - } - - #[test] - fn test_rename_refs_for_fn_param() { - test_rename( - r#" - fn foo(i<|> : u32) -> u32 { - i - }"#, - "new_name", - r#" - fn foo(new_name : u32) -> u32 { - new_name - }"#, - ); - } - - #[test] - fn test_rename_for_mut_param() { - test_rename( - r#" - fn foo(mut i<|> : u32) -> u32 { - i - }"#, - "new_name", - r#" - fn foo(mut new_name : u32) -> u32 { - new_name - }"#, - ); - } - - #[test] - fn test_rename_mod() { - let (analysis, position) = analysis_and_position( - " - //- /lib.rs - mod bar; - - //- /bar.rs - mod foo<|>; - - //- /bar/foo.rs - // emtpy - ", - ); - let new_name = "foo2"; - let source_change = analysis.rename(position, new_name).unwrap(); - assert_debug_snapshot!(&source_change, -@r###" - Some( - RangeInfo { - range: [4; 7), - info: SourceChange { - label: "rename", - source_file_edits: [ - SourceFileEdit { - file_id: FileId( - 2, - ), - edit: TextEdit { - atoms: [ - AtomTextEdit { - delete: [4; 7), - insert: "foo2", - }, - ], - }, - }, - ], - file_system_edits: [ - MoveFile { - src: FileId( - 3, - ), - dst_source_root: SourceRootId( - 0, - ), - dst_path: "bar/foo2.rs", - }, - ], - cursor_position: None, - }, - }, - ) - "###); - } - - #[test] - fn test_rename_mod_in_dir() { - let (analysis, position) = analysis_and_position( - " - //- /lib.rs - mod fo<|>o; - //- /foo/mod.rs - // emtpy - ", - ); - let new_name = "foo2"; - let source_change = analysis.rename(position, new_name).unwrap(); - assert_debug_snapshot!(&source_change, - @r###" - Some( - RangeInfo { - range: [4; 7), - info: SourceChange { - label: "rename", - source_file_edits: [ - SourceFileEdit { - file_id: FileId( - 1, - ), - edit: TextEdit { - atoms: [ - AtomTextEdit { - delete: [4; 7), - insert: "foo2", - }, - ], - }, - }, - ], - file_system_edits: [ - MoveFile { - src: FileId( - 2, - ), - dst_source_root: SourceRootId( - 0, - ), - dst_path: "foo2/mod.rs", - }, - ], - cursor_position: None, - }, - }, - ) - "### - ); - } - - fn test_rename(text: &str, new_name: &str, expected: &str) { - let (analysis, position) = single_file_with_position(text); - let source_change = analysis.rename(position, new_name).unwrap(); - let mut text_edit_builder = ra_text_edit::TextEditBuilder::default(); - let mut file_id: Option = None; - if let Some(change) = source_change { - for edit in change.info.source_file_edits { - file_id = Some(edit.file_id); - for atom in edit.edit.as_atoms() { - text_edit_builder.replace(atom.delete, atom.insert.clone()); - } - } - } - let result = - text_edit_builder.finish().apply(&*analysis.file_text(file_id.unwrap()).unwrap()); - assert_eq_text!(expected, &*result); - } } -- cgit v1.2.3