From 11577288c23b1f2de1aaba0137c9c2d6344b9a92 Mon Sep 17 00:00:00 2001 From: Ekaterina Babshukova Date: Sat, 14 Sep 2019 14:38:10 +0300 Subject: initial classify_name --- crates/ra_hir/src/from_source.rs | 60 ++++++++- crates/ra_ide_api/src/goto_definition.rs | 2 +- crates/ra_ide_api/src/hover.rs | 2 +- crates/ra_ide_api/src/name_ref_kind.rs | 6 +- crates/ra_ide_api/src/references.rs | 154 ++++++++++++++++++---- crates/ra_ide_api/src/search_scope.rs | 186 +++++++++++++++++++++++++++ crates/ra_ide_api/src/syntax_highlighting.rs | 2 +- 7 files changed, 376 insertions(+), 36 deletions(-) create mode 100644 crates/ra_ide_api/src/search_scope.rs (limited to 'crates') diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs index f80d8eb5f..e09414ca3 100644 --- a/crates/ra_hir/src/from_source.rs +++ b/crates/ra_hir/src/from_source.rs @@ -11,8 +11,9 @@ use crate::{ db::{AstDatabase, DefDatabase, HirDatabase}, ids::{AstItemDef, LocationCtx}, name::AsName, - Const, Crate, Enum, EnumVariant, FieldSource, Function, HasSource, ImplBlock, Module, - ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, Union, VariantDef, + AssocItem, Const, Crate, Enum, EnumVariant, FieldSource, Function, HasSource, ImplBlock, + Module, ModuleDef, ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, Union, + VariantDef, }; pub trait FromSource: Sized { @@ -129,6 +130,61 @@ impl FromSource for StructField { } } +impl FromSource for AssocItem { + type Ast = ast::ImplItem; + fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source) -> Option { + macro_rules! def { + ($kind:ident, $ast:ident) => { + $kind::from_source(db, Source { file_id: src.file_id, ast: $ast }) + .and_then(|it| Some(AssocItem::from(it))) + }; + } + + match src.ast { + ast::ImplItem::FnDef(f) => def!(Function, f), + ast::ImplItem::ConstDef(c) => def!(Const, c), + ast::ImplItem::TypeAliasDef(a) => def!(TypeAlias, a), + } + } +} + +// not fully matched +impl FromSource for ModuleDef { + type Ast = ast::ModuleItem; + fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source) -> Option { + macro_rules! def { + ($kind:ident, $ast:ident) => { + $kind::from_source(db, Source { file_id: src.file_id, ast: $ast }) + .and_then(|it| Some(ModuleDef::from(it))) + }; + } + + match src.ast { + ast::ModuleItem::FnDef(f) => def!(Function, f), + ast::ModuleItem::ConstDef(c) => def!(Const, c), + ast::ModuleItem::TypeAliasDef(a) => def!(TypeAlias, a), + ast::ModuleItem::TraitDef(t) => def!(Trait, t), + ast::ModuleItem::StaticDef(s) => def!(Static, s), + ast::ModuleItem::StructDef(s) => { + let src = Source { file_id: src.file_id, ast: s }; + let s = Struct::from_source(db, src)?; + Some(ModuleDef::Adt(s.into())) + } + ast::ModuleItem::EnumDef(e) => { + let src = Source { file_id: src.file_id, ast: e }; + let e = Enum::from_source(db, src)?; + Some(ModuleDef::Adt(e.into())) + } + ast::ModuleItem::Module(ref m) if !m.has_semi() => { + let src = Source { file_id: src.file_id, ast: ModuleSource::Module(m.clone()) }; + let module = Module::from_definition(db, src)?; + Some(ModuleDef::Module(module)) + } + _ => None, + } + } +} + // FIXME: simplify it impl ModuleSource { pub fn from_position( diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index 41a88314f..13e42bb35 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs @@ -10,7 +10,7 @@ use ra_syntax::{ use crate::{ db::RootDatabase, display::ShortLabel, - name_ref_kind::{classify_name_ref, NameRefKind::*}, + name_ref_kind::{classify_name_ref, NameKind::*}, FilePosition, NavigationTarget, RangeInfo, }; diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs index 24b161c5c..5c2549dc3 100644 --- a/crates/ra_ide_api/src/hover.rs +++ b/crates/ra_ide_api/src/hover.rs @@ -14,7 +14,7 @@ use crate::{ description_from_symbol, docs_from_symbol, macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel, }, - name_ref_kind::{classify_name_ref, NameRefKind::*}, + name_ref_kind::{classify_name_ref, NameKind::*}, FilePosition, FileRange, RangeInfo, }; diff --git a/crates/ra_ide_api/src/name_ref_kind.rs b/crates/ra_ide_api/src/name_ref_kind.rs index 149585971..eb8caabfe 100644 --- a/crates/ra_ide_api/src/name_ref_kind.rs +++ b/crates/ra_ide_api/src/name_ref_kind.rs @@ -6,7 +6,7 @@ use test_utils::tested_by; use crate::db::RootDatabase; -pub enum NameRefKind { +pub enum NameKind { Method(hir::Function), Macro(hir::MacroDef), FieldAccess(hir::StructField), @@ -22,8 +22,8 @@ pub(crate) fn classify_name_ref( db: &RootDatabase, analyzer: &hir::SourceAnalyzer, name_ref: &ast::NameRef, -) -> Option { - use NameRefKind::*; +) -> Option { + use NameKind::*; // Check if it is a method if let Some(method_call) = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast) { diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs index 4247c6d90..9335bc8ca 100644 --- a/crates/ra_ide_api/src/references.rs +++ b/crates/ra_ide_api/src/references.rs @@ -1,13 +1,18 @@ //! FIXME: write short doc here -use hir::{Either, ModuleSource}; +use hir::{FromSource, ModuleSource}; use ra_db::{SourceDatabase, SourceDatabaseExt}; -use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SourceFile, SyntaxNode}; +use ra_syntax::{algo::find_node_at_offset, ast, AstNode, AstPtr, SyntaxNode}; use relative_path::{RelativePath, RelativePathBuf}; use crate::{ - db::RootDatabase, FileId, FilePosition, FileRange, FileSystemEdit, NavigationTarget, RangeInfo, - SourceChange, SourceFileEdit, TextRange, + db::RootDatabase, + name_ref_kind::{ + classify_name_ref, + NameKind::{self, *}, + }, + FileId, FilePosition, FileRange, FileSystemEdit, NavigationTarget, RangeInfo, SourceChange, + SourceFileEdit, TextRange, }; #[derive(Debug, Clone)] @@ -52,41 +57,92 @@ pub(crate) fn find_all_refs( position: FilePosition, ) -> Option> { let parse = db.parse(position.file_id); - let RangeInfo { range, info: (binding, analyzer) } = find_binding(db, &parse.tree(), position)?; - let declaration = NavigationTarget::from_bind_pat(position.file_id, &binding); + let syntax = parse.tree().syntax().clone(); + let RangeInfo { range, info: (analyzer, name_kind) } = find_name(db, &syntax, position)?; + + let declaration = match name_kind { + Macro(mac) => NavigationTarget::from_macro_def(db, mac), + FieldAccess(field) => NavigationTarget::from_field(db, field), + AssocItem(assoc) => NavigationTarget::from_assoc_item(db, assoc), + Method(func) => NavigationTarget::from_def_source(db, func), + Def(def) => NavigationTarget::from_def(db, def)?, + 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, + }; - let references = analyzer - .find_all_refs(&binding) - .into_iter() - .map(move |ref_desc| FileRange { file_id: position.file_id, range: ref_desc.range }) - .collect::>(); + 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![], + }; return Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references })); - fn find_binding<'a>( + fn find_name<'a>( db: &RootDatabase, - source_file: &SourceFile, + syntax: &SyntaxNode, position: FilePosition, - ) -> Option> { - let syntax = source_file.syntax(); - if let Some(binding) = find_node_at_offset::(syntax, position.offset) { - let range = binding.syntax().text_range(); - let analyzer = hir::SourceAnalyzer::new(db, position.file_id, binding.syntax(), None); - return Some(RangeInfo::new(range, (binding, analyzer))); - }; - let name_ref = find_node_at_offset::(syntax, position.offset)?; + ) -> Option> { + if let Some(name) = find_node_at_offset::(&syntax, position.offset) { + let analyzer = hir::SourceAnalyzer::new(db, position.file_id, name.syntax(), None); + let name_kind = classify_name(db, position.file_id, &name)?; + let range = name.syntax().text_range(); + return Some(RangeInfo::new(range, (analyzer, name_kind))); + } + 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 resolved = analyzer.resolve_local_name(&name_ref)?; - if let Either::A(ptr) = resolved.ptr() { - if let ast::Pat::BindPat(binding) = ptr.to_node(source_file.syntax()) { - return Some(RangeInfo::new(range, (binding, analyzer))); - } - } - None + let name_kind = classify_name_ref(db, &analyzer, &name_ref)?; + Some(RangeInfo::new(range, (analyzer, name_kind))) } } +fn classify_name(db: &RootDatabase, file_id: FileId, name: &ast::Name) -> Option { + let parent = name.syntax().parent()?; + let file_id = file_id.into(); + + if let Some(pat) = ast::BindPat::cast(parent.clone()) { + return Some(Pat(AstPtr::new(&pat))); + } + if let Some(var) = ast::EnumVariant::cast(parent.clone()) { + let src = hir::Source { file_id, ast: var }; + let var = hir::EnumVariant::from_source(db, src)?; + return Some(Def(var.into())); + } + if let Some(field) = ast::RecordFieldDef::cast(parent.clone()) { + let src = hir::Source { file_id, ast: hir::FieldSource::Named(field) }; + let field = hir::StructField::from_source(db, src)?; + return Some(FieldAccess(field)); + } + if let Some(field) = ast::TupleFieldDef::cast(parent.clone()) { + let src = hir::Source { file_id, ast: hir::FieldSource::Pos(field) }; + let field = hir::StructField::from_source(db, src)?; + return Some(FieldAccess(field)); + } + if let Some(_) = parent.parent().and_then(ast::ItemList::cast) { + let ast = ast::ImplItem::cast(parent.clone())?; + let src = hir::Source { file_id, ast }; + let item = hir::AssocItem::from_source(db, src)?; + return Some(AssocItem(item)); + } + if let Some(item) = ast::ModuleItem::cast(parent.clone()) { + let src = hir::Source { file_id, ast: item }; + let def = hir::ModuleDef::from_source(db, src)?; + return Some(Def(def)); + } + // FIXME: TYPE_PARAM, ALIAS, MACRO_CALL; Union + + None +} + pub(crate) fn rename( db: &RootDatabase, position: FilePosition, @@ -249,6 +305,48 @@ mod tests { assert_eq!(refs.len(), 2); } + #[test] + fn test_find_all_refs_field_name() { + let code = r#" + //- /lib.rs + struct Foo { + spam<|>: u32, + } + "#; + + let refs = get_all_refs(code); + assert_eq!(refs.len(), 1); + } + + #[test] + fn test_find_all_refs_impl_item_name() { + let code = r#" + //- /lib.rs + struct Foo; + impl Foo { + fn f<|>(&self) { } + } + "#; + + let refs = get_all_refs(code); + assert_eq!(refs.len(), 1); + } + + #[test] + fn test_find_all_refs_enum_var_name() { + let code = r#" + //- /lib.rs + enum Foo { + A, + B<|>, + C, + } + "#; + + let refs = get_all_refs(code); + assert_eq!(refs.len(), 1); + } + fn get_all_refs(text: &str) -> ReferenceSearchResult { let (analysis, position) = single_file_with_position(text); analysis.find_all_refs(position).unwrap().unwrap() diff --git a/crates/ra_ide_api/src/search_scope.rs b/crates/ra_ide_api/src/search_scope.rs new file mode 100644 index 000000000..ca1ac2b03 --- /dev/null +++ b/crates/ra_ide_api/src/search_scope.rs @@ -0,0 +1,186 @@ +pub enum SearchScope { + Function(hir::Function), + Module(hir::Module), + Crate(hir::Crate), + Crates(Vec), +} + +pub struct SearchScope{ + pub scope: Vec +} + +pub fn find_all_refs(db: &RootDatabase, decl: NameKind) -> Vec { + let (module, visibility) = match decl { + FieldAccess(field) => { + let parent = field.parent_def(db); + let module = parent.module(db); + let visibility = match parent { + VariantDef::Struct(s) => s.source(db).ast.visibility(), + VariantDef::EnumVariant(v) => v.parent_enum(db).source(db).ast.visibility(), + }; + (module, visibility) + } + AssocItem(item) => { + let parent = item.parent_trait(db)?; + let module = parent.module(db); + let visibility = parent.source(db).ast.visibility(); + (module, visibility) + } + Def(def) => { + let (module, visibility) = match def { + ModuleDef::Module(m) => (m, ), + ModuleDef::Function(f) => (f.module(db), f.source(db).ast.visibility()), + ModuleDef::Adt::Struct(s) => (s.module(db), s.source(db).ast.visibility()), + ModuleDef::Adt::Union(u) => (u.module(db), u.source(db).ast.visibility()), + ModuleDef::Adt::Enum(e) => (e.module(db), e.source(db).ast.visibility()), + ModuleDef::EnumVariant(v) => (v.module(db), v.source(db).ast.visibility()), + ModuleDef::Const(c) => (c.module(db), c.source(db).ast.visibility()), + ModuleDef::Static(s) => (s.module(db), s.source(db).ast.visibility()), + ModuleDef::Trait(t) => (t.module(db), t.source(db).ast.visibility()), + ModuleDef::TypeAlias(a) => (a.module(db), a.source(db).ast.visibility()), + ModuleDef::BuiltinType(_) => return vec![]; + }; + (module, visibility) + } + // FIXME: add missing kinds + _ => return vec![]; + }; + let scope = scope(db, module, visibility); +} + +fn scope(db: &RootDatabase, module: hir::Module, item_vis: Option) -> SearchScope { + if let Some(v) = item_vis { + let krate = module.krate(db)?; + + if v.syntax().text() == "pub" { + SearchScope::Crate(krate) + } + if v.syntax().text() == "pub(crate)" { + let crate_graph = db.crate_graph(); + let crates = crate_graph.iter().filter(|id| { + crate_graph.dependencies(id).any(|d| d.crate_id() == krate.crate_id()) + }).map(|id| Crate { id }).collect::>(); + crates.insert(0, krate); + SearchScope::Crates(crates) + } + // FIXME: "pub(super)", "pub(in path)" + SearchScope::Module(module) + } + SearchScope::Module(module) +} + +fn process_one(db, scope: SearchScope, pat) { + match scope { + SearchScope::Crate(krate) => { + let text = db.file_text(position.file_id).as_str(); + let parse = SourceFile::parse(text); + for (offset, name) in text.match_indices(pat) { + if let Some() = find_node_at_offset(parse, offset) { + + } + } + } + } +} + +#[cfg(test)] +mod tests { + use crate::{ + mock_analysis::analysis_and_position, mock_analysis::single_file_with_position, FileId, + ReferenceSearchResult, + }; + use insta::assert_debug_snapshot; + use test_utils::assert_eq_text; + + #[test] + fn test_find_all_refs_for_local() { + let code = r#" + fn main() { + let mut i = 1; + let j = 1; + i = i<|> + j; + + { + i = 0; + } + + i = 5; + } + "#; + + let refs = get_all_refs(code); + assert_eq!(refs.len(), 5); + } + + #[test] + fn test_find_all_refs_for_param_inside() { + let code = r#" + fn foo(i : u32) -> u32 { + i<|> + }"#; + + let refs = get_all_refs(code); + assert_eq!(refs.len(), 2); + } + + #[test] + fn test_find_all_refs_for_fn_param() { + let code = r#" + fn foo(i<|> : u32) -> u32 { + i + }"#; + + let refs = get_all_refs(code); + assert_eq!(refs.len(), 2); + } + + #[test] + fn test_find_all_refs_field_name() { + let code = r#" + //- /lib.rs + struct Foo { + spam<|>: u32, + } + "#; + + let refs = get_all_refs(code); + assert_eq!(refs.len(), 1); + } + + #[test] + fn test_find_all_refs_methods() { + let code = r#" + //- /lib.rs + struct Foo; + impl Foo { + pub fn a() { + self.b() + } + fn b(&self) {} + } + "#; + + let refs = get_all_refs(code); + assert_eq!(refs.len(), 1); + } + + #[test] + fn test_find_all_refs_pub_enum() { + let code = r#" + //- /lib.rs + pub enum Foo { + A, + B<|>, + C, + } + "#; + + let refs = get_all_refs(code); + assert_eq!(refs.len(), 1); + } + + fn get_all_refs(text: &str) -> ReferenceSearchResult { + let (analysis, position) = single_file_with_position(text); + analysis.find_all_refs(position).unwrap().unwrap() + } +} \ No newline at end of file diff --git a/crates/ra_ide_api/src/syntax_highlighting.rs b/crates/ra_ide_api/src/syntax_highlighting.rs index 1d290387c..03104e348 100644 --- a/crates/ra_ide_api/src/syntax_highlighting.rs +++ b/crates/ra_ide_api/src/syntax_highlighting.rs @@ -14,7 +14,7 @@ use ra_syntax::{ use crate::{ db::RootDatabase, - name_ref_kind::{classify_name_ref, NameRefKind::*}, + name_ref_kind::{classify_name_ref, NameKind::*}, FileId, }; -- cgit v1.2.3 From d6ae1b5f0f3e1b9b7f85dcdbd98e0c336b7a882d Mon Sep 17 00:00:00 2001 From: Ekaterina Babshukova Date: Sat, 21 Sep 2019 19:35:39 +0300 Subject: refactor name_ref_kind.rs --- crates/ra_ide_api/src/goto_definition.rs | 3 +- crates/ra_ide_api/src/hover.rs | 3 +- crates/ra_ide_api/src/lib.rs | 2 +- crates/ra_ide_api/src/name_kind.rs | 137 +++++++++++++++++++++++++++ crates/ra_ide_api/src/name_ref_kind.rs | 98 ------------------- crates/ra_ide_api/src/references.rs | 47 +-------- crates/ra_ide_api/src/syntax_highlighting.rs | 3 +- 7 files changed, 145 insertions(+), 148 deletions(-) create mode 100644 crates/ra_ide_api/src/name_kind.rs delete mode 100644 crates/ra_ide_api/src/name_ref_kind.rs (limited to 'crates') diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index 13e42bb35..7626a3fd1 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs @@ -10,7 +10,7 @@ use ra_syntax::{ use crate::{ db::RootDatabase, display::ShortLabel, - name_ref_kind::{classify_name_ref, NameKind::*}, + name_kind::{classify_name_ref, NameKind::*}, FilePosition, NavigationTarget, RangeInfo, }; @@ -60,7 +60,6 @@ pub(crate) fn reference_definition( Some(Macro(mac)) => return Exact(NavigationTarget::from_macro_def(db, mac)), Some(FieldAccess(field)) => return Exact(NavigationTarget::from_field(db, field)), Some(AssocItem(assoc)) => return Exact(NavigationTarget::from_assoc_item(db, assoc)), - Some(Method(func)) => return Exact(NavigationTarget::from_def_source(db, func)), Some(Def(def)) => match NavigationTarget::from_def(db, def) { Some(nav) => return Exact(nav), None => return Approximate(vec![]), diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs index 5c2549dc3..170278904 100644 --- a/crates/ra_ide_api/src/hover.rs +++ b/crates/ra_ide_api/src/hover.rs @@ -14,7 +14,7 @@ use crate::{ description_from_symbol, docs_from_symbol, macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel, }, - name_ref_kind::{classify_name_ref, NameKind::*}, + name_kind::{classify_name_ref, NameKind::*}, FilePosition, FileRange, RangeInfo, }; @@ -104,7 +104,6 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option res.extend(from_def_source(db, it)), Some(Macro(it)) => { let src = it.source(db); res.extend(hover_text(src.ast.doc_comment_text(), Some(macro_label(&src.ast)))); diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs index f7fd42f65..cbf79ce03 100644 --- a/crates/ra_ide_api/src/lib.rs +++ b/crates/ra_ide_api/src/lib.rs @@ -19,7 +19,7 @@ mod feature_flags; mod status; mod completion; mod runnables; -mod name_ref_kind; +mod name_kind; mod goto_definition; mod goto_type_definition; mod extend_selection; diff --git a/crates/ra_ide_api/src/name_kind.rs b/crates/ra_ide_api/src/name_kind.rs new file mode 100644 index 000000000..64adb1784 --- /dev/null +++ b/crates/ra_ide_api/src/name_kind.rs @@ -0,0 +1,137 @@ +//! FIXME: write short doc here + +use hir::{Either, FromSource}; +use ra_db::FileId; +use ra_syntax::{ast, AstNode, AstPtr}; +use test_utils::tested_by; + +use crate::db::RootDatabase; + +pub enum NameKind { + Macro(hir::MacroDef), + FieldAccess(hir::StructField), + AssocItem(hir::AssocItem), + Def(hir::ModuleDef), + SelfType(hir::Ty), + Pat(AstPtr), + SelfParam(AstPtr), + GenericParam(u32), +} + +pub(crate) fn classify_name_ref( + db: &RootDatabase, + analyzer: &hir::SourceAnalyzer, + name_ref: &ast::NameRef, +) -> Option { + use NameKind::*; + + // Check if it is a method + if let Some(method_call) = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast) { + tested_by!(goto_definition_works_for_methods); + if let Some(func) = analyzer.resolve_method_call(&method_call) { + return Some(AssocItem(func.into())); + } + } + + // It could be a macro call + if let Some(macro_call) = name_ref + .syntax() + .parent() + .and_then(|node| node.parent()) + .and_then(|node| node.parent()) + .and_then(ast::MacroCall::cast) + { + tested_by!(goto_definition_works_for_macros); + if let Some(mac) = analyzer.resolve_macro_call(db, ¯o_call) { + return Some(Macro(mac)); + } + } + + // It could also be a field access + if let Some(field_expr) = name_ref.syntax().parent().and_then(ast::FieldExpr::cast) { + tested_by!(goto_definition_works_for_fields); + if let Some(field) = analyzer.resolve_field(&field_expr) { + return Some(FieldAccess(field)); + }; + } + + // It could also be a named field + if let Some(field_expr) = name_ref.syntax().parent().and_then(ast::RecordField::cast) { + tested_by!(goto_definition_works_for_record_fields); + + if let Some(record_lit) = field_expr.syntax().ancestors().find_map(ast::RecordLit::cast) { + let variant_def = analyzer.resolve_record_literal(&record_lit)?; + let hir_path = hir::Path::from_name_ref(name_ref); + let hir_name = hir_path.as_ident()?; + let field = variant_def.field(db, hir_name)?; + return Some(FieldAccess(field)); + } + } + + // General case, a path or a local: + if let Some(path) = name_ref.syntax().ancestors().find_map(ast::Path::cast) { + if let Some(resolved) = analyzer.resolve_path(db, &path) { + return match resolved { + hir::PathResolution::Def(def) => Some(Def(def)), + hir::PathResolution::LocalBinding(Either::A(pat)) => Some(Pat(pat)), + hir::PathResolution::LocalBinding(Either::B(par)) => Some(SelfParam(par)), + hir::PathResolution::GenericParam(par) => { + // FIXME: get generic param def + Some(GenericParam(par)) + } + hir::PathResolution::Macro(def) => Some(Macro(def)), + hir::PathResolution::SelfType(impl_block) => { + let ty = impl_block.target_ty(db); + Some(SelfType(ty)) + } + hir::PathResolution::AssocItem(assoc) => Some(AssocItem(assoc)), + }; + } + } + + None +} + +pub(crate) fn classify_name( + db: &RootDatabase, + file_id: FileId, + name: &ast::Name, +) -> Option { + use NameKind::*; + + let parent = name.syntax().parent()?; + let file_id = file_id.into(); + + if let Some(pat) = ast::BindPat::cast(parent.clone()) { + return Some(Pat(AstPtr::new(&pat))); + } + if let Some(var) = ast::EnumVariant::cast(parent.clone()) { + let src = hir::Source { file_id, ast: var }; + let var = hir::EnumVariant::from_source(db, src)?; + return Some(Def(var.into())); + } + if let Some(field) = ast::RecordFieldDef::cast(parent.clone()) { + let src = hir::Source { file_id, ast: hir::FieldSource::Named(field) }; + let field = hir::StructField::from_source(db, src)?; + return Some(FieldAccess(field)); + } + if let Some(field) = ast::TupleFieldDef::cast(parent.clone()) { + let src = hir::Source { file_id, ast: hir::FieldSource::Pos(field) }; + let field = hir::StructField::from_source(db, src)?; + return Some(FieldAccess(field)); + } + if let Some(_) = parent.parent().and_then(ast::ItemList::cast) { + let ast = ast::ImplItem::cast(parent.clone())?; + let src = hir::Source { file_id, ast }; + let item = hir::AssocItem::from_source(db, src)?; + return Some(AssocItem(item)); + } + if let Some(item) = ast::ModuleItem::cast(parent.clone()) { + let src = hir::Source { file_id, ast: item }; + let def = hir::ModuleDef::from_source(db, src)?; + return Some(Def(def)); + } + // FIXME: TYPE_PARAM, ALIAS, MACRO_CALL; Union + + None +} diff --git a/crates/ra_ide_api/src/name_ref_kind.rs b/crates/ra_ide_api/src/name_ref_kind.rs deleted file mode 100644 index eb8caabfe..000000000 --- a/crates/ra_ide_api/src/name_ref_kind.rs +++ /dev/null @@ -1,98 +0,0 @@ -//! FIXME: write short doc here - -use hir::Either; -use ra_syntax::{ast, AstNode, AstPtr}; -use test_utils::tested_by; - -use crate::db::RootDatabase; - -pub enum NameKind { - Method(hir::Function), - Macro(hir::MacroDef), - FieldAccess(hir::StructField), - AssocItem(hir::AssocItem), - Def(hir::ModuleDef), - SelfType(hir::Ty), - Pat(AstPtr), - SelfParam(AstPtr), - GenericParam(u32), -} - -pub(crate) fn classify_name_ref( - db: &RootDatabase, - analyzer: &hir::SourceAnalyzer, - name_ref: &ast::NameRef, -) -> Option { - use NameKind::*; - - // Check if it is a method - if let Some(method_call) = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast) { - tested_by!(goto_definition_works_for_methods); - if let Some(func) = analyzer.resolve_method_call(&method_call) { - return Some(Method(func)); - } - } - - // It could be a macro call - if let Some(macro_call) = name_ref - .syntax() - .parent() - .and_then(|node| node.parent()) - .and_then(|node| node.parent()) - .and_then(ast::MacroCall::cast) - { - tested_by!(goto_definition_works_for_macros); - if let Some(mac) = analyzer.resolve_macro_call(db, ¯o_call) { - return Some(Macro(mac)); - } - } - - // It could also be a field access - if let Some(field_expr) = name_ref.syntax().parent().and_then(ast::FieldExpr::cast) { - tested_by!(goto_definition_works_for_fields); - if let Some(field) = analyzer.resolve_field(&field_expr) { - return Some(FieldAccess(field)); - }; - } - - // It could also be a named field - if let Some(field_expr) = name_ref.syntax().parent().and_then(ast::RecordField::cast) { - tested_by!(goto_definition_works_for_record_fields); - - let record_lit = field_expr.syntax().ancestors().find_map(ast::RecordLit::cast); - - if let Some(ty) = record_lit.and_then(|lit| analyzer.type_of(db, &lit.into())) { - if let Some((hir::Adt::Struct(s), _)) = ty.as_adt() { - let hir_path = hir::Path::from_name_ref(name_ref); - let hir_name = hir_path.as_ident().unwrap(); - - if let Some(field) = s.field(db, hir_name) { - return Some(FieldAccess(field)); - } - } - } - } - - // General case, a path or a local: - if let Some(path) = name_ref.syntax().ancestors().find_map(ast::Path::cast) { - if let Some(resolved) = analyzer.resolve_path(db, &path) { - return match resolved { - hir::PathResolution::Def(def) => Some(Def(def)), - hir::PathResolution::LocalBinding(Either::A(pat)) => Some(Pat(pat)), - hir::PathResolution::LocalBinding(Either::B(par)) => Some(SelfParam(par)), - hir::PathResolution::GenericParam(par) => { - // FIXME: get generic param def - Some(GenericParam(par)) - } - hir::PathResolution::Macro(def) => Some(Macro(def)), - hir::PathResolution::SelfType(impl_block) => { - let ty = impl_block.target_ty(db); - Some(SelfType(ty)) - } - hir::PathResolution::AssocItem(assoc) => Some(AssocItem(assoc)), - }; - } - } - - None -} diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs index 9335bc8ca..6a8407c51 100644 --- a/crates/ra_ide_api/src/references.rs +++ b/crates/ra_ide_api/src/references.rs @@ -1,14 +1,14 @@ //! FIXME: write short doc here -use hir::{FromSource, ModuleSource}; +use hir::ModuleSource; use ra_db::{SourceDatabase, SourceDatabaseExt}; -use ra_syntax::{algo::find_node_at_offset, ast, AstNode, AstPtr, SyntaxNode}; +use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SyntaxNode}; use relative_path::{RelativePath, RelativePathBuf}; use crate::{ db::RootDatabase, - name_ref_kind::{ - classify_name_ref, + name_kind::{ + classify_name, classify_name_ref, NameKind::{self, *}, }, FileId, FilePosition, FileRange, FileSystemEdit, NavigationTarget, RangeInfo, SourceChange, @@ -64,7 +64,6 @@ pub(crate) fn find_all_refs( Macro(mac) => NavigationTarget::from_macro_def(db, mac), FieldAccess(field) => NavigationTarget::from_field(db, field), AssocItem(assoc) => NavigationTarget::from_assoc_item(db, assoc), - Method(func) => NavigationTarget::from_def_source(db, func), Def(def) => NavigationTarget::from_def(db, def)?, SelfType(ref ty) => match ty.as_adt() { Some((def_id, _)) => NavigationTarget::from_adt_def(db, def_id), @@ -105,44 +104,6 @@ pub(crate) fn find_all_refs( } } -fn classify_name(db: &RootDatabase, file_id: FileId, name: &ast::Name) -> Option { - let parent = name.syntax().parent()?; - let file_id = file_id.into(); - - if let Some(pat) = ast::BindPat::cast(parent.clone()) { - return Some(Pat(AstPtr::new(&pat))); - } - if let Some(var) = ast::EnumVariant::cast(parent.clone()) { - let src = hir::Source { file_id, ast: var }; - let var = hir::EnumVariant::from_source(db, src)?; - return Some(Def(var.into())); - } - if let Some(field) = ast::RecordFieldDef::cast(parent.clone()) { - let src = hir::Source { file_id, ast: hir::FieldSource::Named(field) }; - let field = hir::StructField::from_source(db, src)?; - return Some(FieldAccess(field)); - } - if let Some(field) = ast::TupleFieldDef::cast(parent.clone()) { - let src = hir::Source { file_id, ast: hir::FieldSource::Pos(field) }; - let field = hir::StructField::from_source(db, src)?; - return Some(FieldAccess(field)); - } - if let Some(_) = parent.parent().and_then(ast::ItemList::cast) { - let ast = ast::ImplItem::cast(parent.clone())?; - let src = hir::Source { file_id, ast }; - let item = hir::AssocItem::from_source(db, src)?; - return Some(AssocItem(item)); - } - if let Some(item) = ast::ModuleItem::cast(parent.clone()) { - let src = hir::Source { file_id, ast: item }; - let def = hir::ModuleDef::from_source(db, src)?; - return Some(Def(def)); - } - // FIXME: TYPE_PARAM, ALIAS, MACRO_CALL; Union - - None -} - pub(crate) fn rename( db: &RootDatabase, position: FilePosition, diff --git a/crates/ra_ide_api/src/syntax_highlighting.rs b/crates/ra_ide_api/src/syntax_highlighting.rs index 03104e348..98373a49c 100644 --- a/crates/ra_ide_api/src/syntax_highlighting.rs +++ b/crates/ra_ide_api/src/syntax_highlighting.rs @@ -14,7 +14,7 @@ use ra_syntax::{ use crate::{ db::RootDatabase, - name_ref_kind::{classify_name_ref, NameKind::*}, + name_kind::{classify_name_ref, NameKind::*}, FileId, }; @@ -104,7 +104,6 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec "function", Some(Macro(_)) => "macro", Some(FieldAccess(_)) => "field", Some(AssocItem(hir::AssocItem::Function(_))) => "function", -- cgit v1.2.3 From 0b5d0a41fde1ae03bc6643dad3b904f579f716b5 Mon Sep 17 00:00:00 2001 From: Ekaterina Babshukova Date: Thu, 3 Oct 2019 03:00:47 +0300 Subject: replace a chain of `if let` by macro --- crates/ra_hir/src/from_source.rs | 40 +------- crates/ra_ide_api/src/name_kind.rs | 116 +++++++++++++++------ crates/ra_ide_api/src/search_scope.rs | 186 ---------------------------------- 3 files changed, 87 insertions(+), 255 deletions(-) delete mode 100644 crates/ra_ide_api/src/search_scope.rs (limited to 'crates') diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs index e09414ca3..df61c227a 100644 --- a/crates/ra_hir/src/from_source.rs +++ b/crates/ra_hir/src/from_source.rs @@ -12,8 +12,7 @@ use crate::{ ids::{AstItemDef, LocationCtx}, name::AsName, AssocItem, Const, Crate, Enum, EnumVariant, FieldSource, Function, HasSource, ImplBlock, - Module, ModuleDef, ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, Union, - VariantDef, + Module, ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, Union, VariantDef, }; pub trait FromSource: Sized { @@ -148,43 +147,6 @@ impl FromSource for AssocItem { } } -// not fully matched -impl FromSource for ModuleDef { - type Ast = ast::ModuleItem; - fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source) -> Option { - macro_rules! def { - ($kind:ident, $ast:ident) => { - $kind::from_source(db, Source { file_id: src.file_id, ast: $ast }) - .and_then(|it| Some(ModuleDef::from(it))) - }; - } - - match src.ast { - ast::ModuleItem::FnDef(f) => def!(Function, f), - ast::ModuleItem::ConstDef(c) => def!(Const, c), - ast::ModuleItem::TypeAliasDef(a) => def!(TypeAlias, a), - ast::ModuleItem::TraitDef(t) => def!(Trait, t), - ast::ModuleItem::StaticDef(s) => def!(Static, s), - ast::ModuleItem::StructDef(s) => { - let src = Source { file_id: src.file_id, ast: s }; - let s = Struct::from_source(db, src)?; - Some(ModuleDef::Adt(s.into())) - } - ast::ModuleItem::EnumDef(e) => { - let src = Source { file_id: src.file_id, ast: e }; - let e = Enum::from_source(db, src)?; - Some(ModuleDef::Adt(e.into())) - } - ast::ModuleItem::Module(ref m) if !m.has_semi() => { - let src = Source { file_id: src.file_id, ast: ModuleSource::Module(m.clone()) }; - let module = Module::from_definition(db, src)?; - Some(ModuleDef::Module(module)) - } - _ => None, - } - } -} - // FIXME: simplify it impl ModuleSource { pub fn from_position( diff --git a/crates/ra_ide_api/src/name_kind.rs b/crates/ra_ide_api/src/name_kind.rs index 64adb1784..0effeb8a1 100644 --- a/crates/ra_ide_api/src/name_kind.rs +++ b/crates/ra_ide_api/src/name_kind.rs @@ -102,36 +102,92 @@ pub(crate) fn classify_name( let parent = name.syntax().parent()?; let file_id = file_id.into(); - if let Some(pat) = ast::BindPat::cast(parent.clone()) { - return Some(Pat(AstPtr::new(&pat))); + macro_rules! match_ast { + (match $node:ident { + $( ast::$ast:ident($it:ident) => $res:block, )* + _ => $catch_all:expr, + }) => {{ + $( if let Some($it) = ast::$ast::cast($node.clone()) $res else )* + { $catch_all } + }}; } - if let Some(var) = ast::EnumVariant::cast(parent.clone()) { - let src = hir::Source { file_id, ast: var }; - let var = hir::EnumVariant::from_source(db, src)?; - return Some(Def(var.into())); - } - if let Some(field) = ast::RecordFieldDef::cast(parent.clone()) { - let src = hir::Source { file_id, ast: hir::FieldSource::Named(field) }; - let field = hir::StructField::from_source(db, src)?; - return Some(FieldAccess(field)); - } - if let Some(field) = ast::TupleFieldDef::cast(parent.clone()) { - let src = hir::Source { file_id, ast: hir::FieldSource::Pos(field) }; - let field = hir::StructField::from_source(db, src)?; - return Some(FieldAccess(field)); - } - if let Some(_) = parent.parent().and_then(ast::ItemList::cast) { - let ast = ast::ImplItem::cast(parent.clone())?; - let src = hir::Source { file_id, ast }; - let item = hir::AssocItem::from_source(db, src)?; - return Some(AssocItem(item)); - } - if let Some(item) = ast::ModuleItem::cast(parent.clone()) { - let src = hir::Source { file_id, ast: item }; - let def = hir::ModuleDef::from_source(db, src)?; - return Some(Def(def)); - } - // FIXME: TYPE_PARAM, ALIAS, MACRO_CALL; Union - None + // FIXME: add ast::MacroCall(it) + match_ast! { + match parent { + ast::BindPat(it) => { + let pat = AstPtr::new(&it); + Some(Pat(pat)) + }, + ast::RecordFieldDef(it) => { + let src = hir::Source { file_id, ast: hir::FieldSource::Named(it) }; + let field = hir::StructField::from_source(db, src)?; + Some(FieldAccess(field)) + }, + ast::FnDef(it) => { + if parent.parent().and_then(ast::ItemList::cast).is_some() { + let src = hir::Source { file_id, ast: ast::ImplItem::from(it) }; + let item = hir::AssocItem::from_source(db, src)?; + Some(AssocItem(item)) + } else { + let src = hir::Source { file_id, ast: it }; + let def = hir::Function::from_source(db, src)?; + Some(Def(def.into())) + } + }, + ast::ConstDef(it) => { + if parent.parent().and_then(ast::ItemList::cast).is_some() { + let src = hir::Source { file_id, ast: ast::ImplItem::from(it) }; + let item = hir::AssocItem::from_source(db, src)?; + Some(AssocItem(item)) + } else { + let src = hir::Source { file_id, ast: it }; + let def = hir::Const::from_source(db, src)?; + Some(Def(def.into())) + } + }, + ast::TypeAliasDef(it) => { + if parent.parent().and_then(ast::ItemList::cast).is_some() { + let src = hir::Source { file_id, ast: ast::ImplItem::from(it) }; + let item = hir::AssocItem::from_source(db, src)?; + Some(AssocItem(item)) + } else { + let src = hir::Source { file_id, ast: it }; + let def = hir::TypeAlias::from_source(db, src)?; + Some(Def(def.into())) + } + }, + ast::Module(it) => { + let src = hir::Source { file_id, ast: hir::ModuleSource::Module(it) }; + let def = hir::Module::from_definition(db, src)?; + Some(Def(def.into())) + }, + ast::StructDef(it) => { + let src = hir::Source { file_id, ast: it }; + let def = hir::Struct::from_source(db, src)?; + Some(Def(def.into())) + }, + ast::EnumDef(it) => { + let src = hir::Source { file_id, ast: it }; + let def = hir::Enum::from_source(db, src)?; + Some(Def(def.into())) + }, + ast::TraitDef(it) => { + let src = hir::Source { file_id, ast: it }; + let def = hir::Trait::from_source(db, src)?; + Some(Def(def.into())) + }, + ast::StaticDef(it) => { + let src = hir::Source { file_id, ast: it }; + let def = hir::Static::from_source(db, src)?; + Some(Def(def.into())) + }, + ast::EnumVariant(it) => { + let src = hir::Source { file_id, ast: it }; + let def = hir::EnumVariant::from_source(db, src)?; + Some(Def(def.into())) + }, + _ => None, + } + } } diff --git a/crates/ra_ide_api/src/search_scope.rs b/crates/ra_ide_api/src/search_scope.rs deleted file mode 100644 index ca1ac2b03..000000000 --- a/crates/ra_ide_api/src/search_scope.rs +++ /dev/null @@ -1,186 +0,0 @@ -pub enum SearchScope { - Function(hir::Function), - Module(hir::Module), - Crate(hir::Crate), - Crates(Vec), -} - -pub struct SearchScope{ - pub scope: Vec -} - -pub fn find_all_refs(db: &RootDatabase, decl: NameKind) -> Vec { - let (module, visibility) = match decl { - FieldAccess(field) => { - let parent = field.parent_def(db); - let module = parent.module(db); - let visibility = match parent { - VariantDef::Struct(s) => s.source(db).ast.visibility(), - VariantDef::EnumVariant(v) => v.parent_enum(db).source(db).ast.visibility(), - }; - (module, visibility) - } - AssocItem(item) => { - let parent = item.parent_trait(db)?; - let module = parent.module(db); - let visibility = parent.source(db).ast.visibility(); - (module, visibility) - } - Def(def) => { - let (module, visibility) = match def { - ModuleDef::Module(m) => (m, ), - ModuleDef::Function(f) => (f.module(db), f.source(db).ast.visibility()), - ModuleDef::Adt::Struct(s) => (s.module(db), s.source(db).ast.visibility()), - ModuleDef::Adt::Union(u) => (u.module(db), u.source(db).ast.visibility()), - ModuleDef::Adt::Enum(e) => (e.module(db), e.source(db).ast.visibility()), - ModuleDef::EnumVariant(v) => (v.module(db), v.source(db).ast.visibility()), - ModuleDef::Const(c) => (c.module(db), c.source(db).ast.visibility()), - ModuleDef::Static(s) => (s.module(db), s.source(db).ast.visibility()), - ModuleDef::Trait(t) => (t.module(db), t.source(db).ast.visibility()), - ModuleDef::TypeAlias(a) => (a.module(db), a.source(db).ast.visibility()), - ModuleDef::BuiltinType(_) => return vec![]; - }; - (module, visibility) - } - // FIXME: add missing kinds - _ => return vec![]; - }; - let scope = scope(db, module, visibility); -} - -fn scope(db: &RootDatabase, module: hir::Module, item_vis: Option) -> SearchScope { - if let Some(v) = item_vis { - let krate = module.krate(db)?; - - if v.syntax().text() == "pub" { - SearchScope::Crate(krate) - } - if v.syntax().text() == "pub(crate)" { - let crate_graph = db.crate_graph(); - let crates = crate_graph.iter().filter(|id| { - crate_graph.dependencies(id).any(|d| d.crate_id() == krate.crate_id()) - }).map(|id| Crate { id }).collect::>(); - crates.insert(0, krate); - SearchScope::Crates(crates) - } - // FIXME: "pub(super)", "pub(in path)" - SearchScope::Module(module) - } - SearchScope::Module(module) -} - -fn process_one(db, scope: SearchScope, pat) { - match scope { - SearchScope::Crate(krate) => { - let text = db.file_text(position.file_id).as_str(); - let parse = SourceFile::parse(text); - for (offset, name) in text.match_indices(pat) { - if let Some() = find_node_at_offset(parse, offset) { - - } - } - } - } -} - -#[cfg(test)] -mod tests { - use crate::{ - mock_analysis::analysis_and_position, mock_analysis::single_file_with_position, FileId, - ReferenceSearchResult, - }; - use insta::assert_debug_snapshot; - use test_utils::assert_eq_text; - - #[test] - fn test_find_all_refs_for_local() { - let code = r#" - fn main() { - let mut i = 1; - let j = 1; - i = i<|> + j; - - { - i = 0; - } - - i = 5; - } - "#; - - let refs = get_all_refs(code); - assert_eq!(refs.len(), 5); - } - - #[test] - fn test_find_all_refs_for_param_inside() { - let code = r#" - fn foo(i : u32) -> u32 { - i<|> - }"#; - - let refs = get_all_refs(code); - assert_eq!(refs.len(), 2); - } - - #[test] - fn test_find_all_refs_for_fn_param() { - let code = r#" - fn foo(i<|> : u32) -> u32 { - i - }"#; - - let refs = get_all_refs(code); - assert_eq!(refs.len(), 2); - } - - #[test] - fn test_find_all_refs_field_name() { - let code = r#" - //- /lib.rs - struct Foo { - spam<|>: u32, - } - "#; - - let refs = get_all_refs(code); - assert_eq!(refs.len(), 1); - } - - #[test] - fn test_find_all_refs_methods() { - let code = r#" - //- /lib.rs - struct Foo; - impl Foo { - pub fn a() { - self.b() - } - fn b(&self) {} - } - "#; - - let refs = get_all_refs(code); - assert_eq!(refs.len(), 1); - } - - #[test] - fn test_find_all_refs_pub_enum() { - let code = r#" - //- /lib.rs - pub enum Foo { - A, - B<|>, - C, - } - "#; - - let refs = get_all_refs(code); - assert_eq!(refs.len(), 1); - } - - fn get_all_refs(text: &str) -> ReferenceSearchResult { - let (analysis, position) = single_file_with_position(text); - analysis.find_all_refs(position).unwrap().unwrap() - } -} \ No newline at end of file -- cgit v1.2.3 From 83f780eabfdaf37cb50c10c79af87506f2cc2afe Mon Sep 17 00:00:00 2001 From: Ekaterina Babshukova Date: Thu, 3 Oct 2019 06:08:44 +0300 Subject: return Declaration from classify_name --- crates/ra_ide_api/src/name_kind.rs | 93 +++++++++++++++++++++++-------------- crates/ra_ide_api/src/references.rs | 2 +- 2 files changed, 59 insertions(+), 36 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide_api/src/name_kind.rs b/crates/ra_ide_api/src/name_kind.rs index 0effeb8a1..5dc6b1a13 100644 --- a/crates/ra_ide_api/src/name_kind.rs +++ b/crates/ra_ide_api/src/name_kind.rs @@ -1,13 +1,19 @@ //! FIXME: write short doc here -use hir::{Either, FromSource}; +use hir::{Either, FromSource, HasSource}; use ra_db::FileId; -use ra_syntax::{ast, AstNode, AstPtr}; +use ra_syntax::{ast, ast::VisibilityOwner, AstNode, AstPtr}; use test_utils::tested_by; use crate::db::RootDatabase; -pub enum NameKind { +pub(crate) struct Declaration { + visibility: Option, + container: hir::ModuleSource, + pub item: NameKind, +} + +pub(crate) enum NameKind { Macro(hir::MacroDef), FieldAccess(hir::StructField), AssocItem(hir::AssocItem), @@ -96,7 +102,7 @@ pub(crate) fn classify_name( db: &RootDatabase, file_id: FileId, name: &ast::Name, -) -> Option { +) -> Option { use NameKind::*; let parent = name.syntax().parent()?; @@ -105,89 +111,106 @@ pub(crate) fn classify_name( macro_rules! match_ast { (match $node:ident { $( ast::$ast:ident($it:ident) => $res:block, )* - _ => $catch_all:expr, + _ => $catch_all:block, }) => {{ $( if let Some($it) = ast::$ast::cast($node.clone()) $res else )* - { $catch_all } + $catch_all }}; } + let container = parent.ancestors().find_map(|n| { + match_ast! { + match n { + ast::Module(it) => { Some(hir::ModuleSource::Module(it)) }, + ast::SourceFile(it) => { Some(hir::ModuleSource::SourceFile(it)) }, + _ => { None }, + } + } + })?; + // FIXME: add ast::MacroCall(it) - match_ast! { + let (item, visibility) = match_ast! { match parent { ast::BindPat(it) => { let pat = AstPtr::new(&it); - Some(Pat(pat)) + (Pat(pat), None) }, ast::RecordFieldDef(it) => { let src = hir::Source { file_id, ast: hir::FieldSource::Named(it) }; let field = hir::StructField::from_source(db, src)?; - Some(FieldAccess(field)) + let visibility = match field.parent_def(db) { + hir::VariantDef::Struct(s) => s.source(db).ast.visibility(), + hir::VariantDef::EnumVariant(e) => e.source(db).ast.parent_enum().visibility(), + }; + (FieldAccess(field), visibility) }, ast::FnDef(it) => { if parent.parent().and_then(ast::ItemList::cast).is_some() { - let src = hir::Source { file_id, ast: ast::ImplItem::from(it) }; + let src = hir::Source { file_id, ast: ast::ImplItem::from(it.clone()) }; let item = hir::AssocItem::from_source(db, src)?; - Some(AssocItem(item)) + (AssocItem(item), it.visibility()) } else { - let src = hir::Source { file_id, ast: it }; + let src = hir::Source { file_id, ast: it.clone() }; let def = hir::Function::from_source(db, src)?; - Some(Def(def.into())) + (Def(def.into()), it.visibility()) } }, ast::ConstDef(it) => { if parent.parent().and_then(ast::ItemList::cast).is_some() { - let src = hir::Source { file_id, ast: ast::ImplItem::from(it) }; + let src = hir::Source { file_id, ast: ast::ImplItem::from(it.clone()) }; let item = hir::AssocItem::from_source(db, src)?; - Some(AssocItem(item)) + (AssocItem(item), it.visibility()) } else { - let src = hir::Source { file_id, ast: it }; + let src = hir::Source { file_id, ast: it.clone() }; let def = hir::Const::from_source(db, src)?; - Some(Def(def.into())) + (Def(def.into()), it.visibility()) } }, ast::TypeAliasDef(it) => { if parent.parent().and_then(ast::ItemList::cast).is_some() { - let src = hir::Source { file_id, ast: ast::ImplItem::from(it) }; + let src = hir::Source { file_id, ast: ast::ImplItem::from(it.clone()) }; let item = hir::AssocItem::from_source(db, src)?; - Some(AssocItem(item)) + (AssocItem(item), it.visibility()) } else { - let src = hir::Source { file_id, ast: it }; + let src = hir::Source { file_id, ast: it.clone() }; let def = hir::TypeAlias::from_source(db, src)?; - Some(Def(def.into())) + (Def(def.into()), it.visibility()) } }, ast::Module(it) => { - let src = hir::Source { file_id, ast: hir::ModuleSource::Module(it) }; + let src = hir::Source { file_id, ast: hir::ModuleSource::Module(it.clone()) }; let def = hir::Module::from_definition(db, src)?; - Some(Def(def.into())) + (Def(def.into()), it.visibility()) }, ast::StructDef(it) => { - let src = hir::Source { file_id, ast: it }; + let src = hir::Source { file_id, ast: it.clone() }; let def = hir::Struct::from_source(db, src)?; - Some(Def(def.into())) + (Def(def.into()), it.visibility()) }, ast::EnumDef(it) => { - let src = hir::Source { file_id, ast: it }; + let src = hir::Source { file_id, ast: it.clone() }; let def = hir::Enum::from_source(db, src)?; - Some(Def(def.into())) + (Def(def.into()), it.visibility()) }, ast::TraitDef(it) => { - let src = hir::Source { file_id, ast: it }; + let src = hir::Source { file_id, ast: it.clone() }; let def = hir::Trait::from_source(db, src)?; - Some(Def(def.into())) + (Def(def.into()), it.visibility()) }, ast::StaticDef(it) => { - let src = hir::Source { file_id, ast: it }; + let src = hir::Source { file_id, ast: it.clone() }; let def = hir::Static::from_source(db, src)?; - Some(Def(def.into())) + (Def(def.into()), it.visibility()) }, ast::EnumVariant(it) => { - let src = hir::Source { file_id, ast: it }; + let src = hir::Source { file_id, ast: it.clone() }; let def = hir::EnumVariant::from_source(db, src)?; - Some(Def(def.into())) + (Def(def.into()), it.parent_enum().visibility()) + }, + _ => { + return None; }, - _ => None, } - } + }; + Some(Declaration { item, container, visibility }) } diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs index 6a8407c51..6777aa5f3 100644 --- a/crates/ra_ide_api/src/references.rs +++ b/crates/ra_ide_api/src/references.rs @@ -92,7 +92,7 @@ pub(crate) fn find_all_refs( ) -> Option> { if let Some(name) = find_node_at_offset::(&syntax, position.offset) { let analyzer = hir::SourceAnalyzer::new(db, position.file_id, name.syntax(), None); - let name_kind = classify_name(db, position.file_id, &name)?; + let name_kind = classify_name(db, position.file_id, &name)?.item; let range = name.syntax().text_range(); return Some(RangeInfo::new(range, (analyzer, name_kind))); } -- cgit v1.2.3 From 121aa35f12d282066651d906ea9a8b2da8209605 Mon Sep 17 00:00:00 2001 From: Ekaterina Babshukova Date: Fri, 4 Oct 2019 03:20:14 +0300 Subject: return Declaration from classify_name_ref --- crates/ra_hir/src/from_source.rs | 40 ++- crates/ra_ide_api/src/goto_definition.rs | 16 +- crates/ra_ide_api/src/hover.rs | 5 +- crates/ra_ide_api/src/name_kind.rs | 432 +++++++++++++++++---------- crates/ra_ide_api/src/references.rs | 6 +- crates/ra_ide_api/src/syntax_highlighting.rs | 6 +- 6 files changed, 323 insertions(+), 182 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs index df61c227a..e09414ca3 100644 --- a/crates/ra_hir/src/from_source.rs +++ b/crates/ra_hir/src/from_source.rs @@ -12,7 +12,8 @@ use crate::{ ids::{AstItemDef, LocationCtx}, name::AsName, AssocItem, Const, Crate, Enum, EnumVariant, FieldSource, Function, HasSource, ImplBlock, - Module, ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, Union, VariantDef, + Module, ModuleDef, ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, Union, + VariantDef, }; pub trait FromSource: Sized { @@ -147,6 +148,43 @@ impl FromSource for AssocItem { } } +// not fully matched +impl FromSource for ModuleDef { + type Ast = ast::ModuleItem; + fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source) -> Option { + macro_rules! def { + ($kind:ident, $ast:ident) => { + $kind::from_source(db, Source { file_id: src.file_id, ast: $ast }) + .and_then(|it| Some(ModuleDef::from(it))) + }; + } + + match src.ast { + ast::ModuleItem::FnDef(f) => def!(Function, f), + ast::ModuleItem::ConstDef(c) => def!(Const, c), + ast::ModuleItem::TypeAliasDef(a) => def!(TypeAlias, a), + ast::ModuleItem::TraitDef(t) => def!(Trait, t), + ast::ModuleItem::StaticDef(s) => def!(Static, s), + ast::ModuleItem::StructDef(s) => { + let src = Source { file_id: src.file_id, ast: s }; + let s = Struct::from_source(db, src)?; + Some(ModuleDef::Adt(s.into())) + } + ast::ModuleItem::EnumDef(e) => { + let src = Source { file_id: src.file_id, ast: e }; + let e = Enum::from_source(db, src)?; + Some(ModuleDef::Adt(e.into())) + } + ast::ModuleItem::Module(ref m) if !m.has_semi() => { + let src = Source { file_id: src.file_id, ast: ModuleSource::Module(m.clone()) }; + let module = Module::from_definition(db, src)?; + Some(ModuleDef::Module(module)) + } + _ => None, + } + } +} + // FIXME: simplify it impl ModuleSource { pub fn from_position( diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index 7626a3fd1..f49764513 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs @@ -55,8 +55,8 @@ pub(crate) fn reference_definition( use self::ReferenceResult::*; let analyzer = hir::SourceAnalyzer::new(db, file_id, name_ref.syntax(), None); - - match classify_name_ref(db, &analyzer, name_ref) { + let name_kind = classify_name_ref(db, file_id, &analyzer, &name_ref).and_then(|d| Some(d.item)); + match name_kind { Some(Macro(mac)) => return Exact(NavigationTarget::from_macro_def(db, mac)), Some(FieldAccess(field)) => return Exact(NavigationTarget::from_field(db, field)), Some(AssocItem(assoc)) => return Exact(NavigationTarget::from_assoc_item(db, assoc)), @@ -69,7 +69,7 @@ pub(crate) fn reference_definition( return Exact(NavigationTarget::from_adt_def(db, def_id)); } } - Some(Pat(pat)) => return Exact(NavigationTarget::from_pat(db, file_id, pat)), + Some(Pat((_, pat))) => return Exact(NavigationTarget::from_pat(db, file_id, pat)), Some(SelfParam(par)) => return Exact(NavigationTarget::from_self_param(file_id, par)), Some(GenericParam(_)) => { // FIXME: go to the generic param def @@ -275,7 +275,7 @@ mod tests { #[test] fn goto_definition_works_for_macros() { - covers!(goto_definition_works_for_macros); + // covers!(goto_definition_works_for_macros); check_goto( " //- /lib.rs @@ -295,7 +295,7 @@ mod tests { #[test] fn goto_definition_works_for_macros_from_other_crates() { - covers!(goto_definition_works_for_macros); + // covers!(goto_definition_works_for_macros); check_goto( " //- /lib.rs @@ -318,7 +318,7 @@ mod tests { #[test] fn goto_definition_works_for_methods() { - covers!(goto_definition_works_for_methods); + // covers!(goto_definition_works_for_methods); check_goto( " //- /lib.rs @@ -337,7 +337,7 @@ mod tests { #[test] fn goto_definition_works_for_fields() { - covers!(goto_definition_works_for_fields); + // covers!(goto_definition_works_for_fields); check_goto( " //- /lib.rs @@ -355,7 +355,7 @@ mod tests { #[test] fn goto_definition_works_for_record_fields() { - covers!(goto_definition_works_for_record_fields); + // covers!(goto_definition_works_for_record_fields); check_goto( " //- /lib.rs diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs index 170278904..316f43c1b 100644 --- a/crates/ra_ide_api/src/hover.rs +++ b/crates/ra_ide_api/src/hover.rs @@ -102,8 +102,9 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option { let src = it.source(db); res.extend(hover_text(src.ast.doc_comment_text(), Some(macro_label(&src.ast)))); diff --git a/crates/ra_ide_api/src/name_kind.rs b/crates/ra_ide_api/src/name_kind.rs index 5dc6b1a13..31f6f277d 100644 --- a/crates/ra_ide_api/src/name_kind.rs +++ b/crates/ra_ide_api/src/name_kind.rs @@ -1,101 +1,127 @@ //! FIXME: write short doc here -use hir::{Either, FromSource, HasSource}; +use hir::{ + db::AstDatabase, Adt, AssocItem, DefWithBody, Either, EnumVariant, FromSource, HasSource, + HirFileId, MacroDef, ModuleDef, ModuleSource, Path, PathResolution, SourceAnalyzer, + StructField, Ty, VariantDef, +}; use ra_db::FileId; use ra_syntax::{ast, ast::VisibilityOwner, AstNode, AstPtr}; -use test_utils::tested_by; use crate::db::RootDatabase; +pub enum NameKind { + Macro(MacroDef), + FieldAccess(StructField), + AssocItem(AssocItem), + Def(ModuleDef), + SelfType(Ty), + Pat((DefWithBody, AstPtr)), + SelfParam(AstPtr), + GenericParam(u32), +} + pub(crate) struct Declaration { visibility: Option, - container: hir::ModuleSource, + container: ModuleSource, pub item: NameKind, } -pub(crate) enum NameKind { - Macro(hir::MacroDef), - FieldAccess(hir::StructField), - AssocItem(hir::AssocItem), - Def(hir::ModuleDef), - SelfType(hir::Ty), - Pat(AstPtr), - SelfParam(AstPtr), - GenericParam(u32), +trait HasDeclaration { + type Def; + type Ref; + + fn declaration(self, db: &RootDatabase) -> Declaration; + fn from_def(db: &RootDatabase, file_id: HirFileId, def: Self::Def) -> Option; + fn from_ref( + db: &RootDatabase, + analyzer: &SourceAnalyzer, + refer: Self::Ref, + ) -> Option; +} + +macro_rules! match_ast { + (match $node:ident { + $( ast::$ast:ident($it:ident) => $res:block, )* + _ => $catch_all:expr, + }) => {{ + $( if let Some($it) = ast::$ast::cast($node.clone()) $res else )* + { $catch_all } + }}; } pub(crate) fn classify_name_ref( db: &RootDatabase, - analyzer: &hir::SourceAnalyzer, + file_id: FileId, + analyzer: &SourceAnalyzer, name_ref: &ast::NameRef, -) -> Option { - use NameKind::*; - - // Check if it is a method - if let Some(method_call) = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast) { - tested_by!(goto_definition_works_for_methods); - if let Some(func) = analyzer.resolve_method_call(&method_call) { - return Some(AssocItem(func.into())); +) -> Option { + let parent = name_ref.syntax().parent()?; + match_ast! { + match parent { + ast::MethodCallExpr(it) => { + return AssocItem::from_ref(db, analyzer, it); + }, + ast::FieldExpr(it) => { + if let Some(field) = analyzer.resolve_field(&it) { + return Some(field.declaration(db)); + } + }, + ast::RecordField(it) => { + if let Some(record_lit) = it.syntax().ancestors().find_map(ast::RecordLit::cast) { + let variant_def = analyzer.resolve_record_literal(&record_lit)?; + let hir_path = Path::from_name_ref(name_ref); + let hir_name = hir_path.as_ident()?; + let field = variant_def.field(db, hir_name)?; + return Some(field.declaration(db)); + } + }, + _ => (), } } - // It could be a macro call - if let Some(macro_call) = name_ref - .syntax() - .parent() - .and_then(|node| node.parent()) - .and_then(|node| node.parent()) - .and_then(ast::MacroCall::cast) - { - tested_by!(goto_definition_works_for_macros); - if let Some(mac) = analyzer.resolve_macro_call(db, ¯o_call) { - return Some(Macro(mac)); + let file_id = file_id.into(); + let container = parent.ancestors().find_map(|node| { + if let Some(it) = ast::Module::cast(node.clone()) { + Some(ModuleSource::Module(it)) + } else if let Some(it) = ast::SourceFile::cast(node.clone()) { + Some(ModuleSource::SourceFile(it)) + } else { + None } - } - - // It could also be a field access - if let Some(field_expr) = name_ref.syntax().parent().and_then(ast::FieldExpr::cast) { - tested_by!(goto_definition_works_for_fields); - if let Some(field) = analyzer.resolve_field(&field_expr) { - return Some(FieldAccess(field)); - }; - } - - // It could also be a named field - if let Some(field_expr) = name_ref.syntax().parent().and_then(ast::RecordField::cast) { - tested_by!(goto_definition_works_for_record_fields); + })?; - if let Some(record_lit) = field_expr.syntax().ancestors().find_map(ast::RecordLit::cast) { - let variant_def = analyzer.resolve_record_literal(&record_lit)?; - let hir_path = hir::Path::from_name_ref(name_ref); - let hir_name = hir_path.as_ident()?; - let field = variant_def.field(db, hir_name)?; - return Some(FieldAccess(field)); + if let Some(macro_call) = + parent.parent().and_then(|node| node.parent()).and_then(ast::MacroCall::cast) + { + if let Some(mac) = analyzer.resolve_macro_call(db, ¯o_call) { + return Some(Declaration { item: NameKind::Macro(mac), container, visibility: None }); } } // General case, a path or a local: - if let Some(path) = name_ref.syntax().ancestors().find_map(ast::Path::cast) { - if let Some(resolved) = analyzer.resolve_path(db, &path) { - return match resolved { - hir::PathResolution::Def(def) => Some(Def(def)), - hir::PathResolution::LocalBinding(Either::A(pat)) => Some(Pat(pat)), - hir::PathResolution::LocalBinding(Either::B(par)) => Some(SelfParam(par)), - hir::PathResolution::GenericParam(par) => { - // FIXME: get generic param def - Some(GenericParam(par)) - } - hir::PathResolution::Macro(def) => Some(Macro(def)), - hir::PathResolution::SelfType(impl_block) => { - let ty = impl_block.target_ty(db); - Some(SelfType(ty)) - } - hir::PathResolution::AssocItem(assoc) => Some(AssocItem(assoc)), - }; + let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?; + let resolved = analyzer.resolve_path(db, &path)?; + match resolved { + PathResolution::Def(def) => Some(def.declaration(db)), + PathResolution::LocalBinding(Either::A(pat)) => decl_from_pat(db, file_id, pat), + PathResolution::LocalBinding(Either::B(par)) => { + Some(Declaration { item: NameKind::SelfParam(par), container, visibility: None }) + } + PathResolution::GenericParam(par) => { + // FIXME: get generic param def + Some(Declaration { item: NameKind::GenericParam(par), container, visibility: None }) + } + PathResolution::Macro(def) => { + Some(Declaration { item: NameKind::Macro(def), container, visibility: None }) } + PathResolution::SelfType(impl_block) => { + let ty = impl_block.target_ty(db); + let container = impl_block.module().definition_source(db).ast; + Some(Declaration { item: NameKind::SelfType(ty), container, visibility: None }) + } + PathResolution::AssocItem(assoc) => Some(assoc.declaration(db)), } - - None } pub(crate) fn classify_name( @@ -103,114 +129,188 @@ pub(crate) fn classify_name( file_id: FileId, name: &ast::Name, ) -> Option { - use NameKind::*; - let parent = name.syntax().parent()?; let file_id = file_id.into(); - macro_rules! match_ast { - (match $node:ident { - $( ast::$ast:ident($it:ident) => $res:block, )* - _ => $catch_all:block, - }) => {{ - $( if let Some($it) = ast::$ast::cast($node.clone()) $res else )* - $catch_all - }}; - } - - let container = parent.ancestors().find_map(|n| { - match_ast! { - match n { - ast::Module(it) => { Some(hir::ModuleSource::Module(it)) }, - ast::SourceFile(it) => { Some(hir::ModuleSource::SourceFile(it)) }, - _ => { None }, - } - } - })?; - - // FIXME: add ast::MacroCall(it) - let (item, visibility) = match_ast! { + match_ast! { match parent { ast::BindPat(it) => { - let pat = AstPtr::new(&it); - (Pat(pat), None) + decl_from_pat(db, file_id, AstPtr::new(&it)) }, ast::RecordFieldDef(it) => { - let src = hir::Source { file_id, ast: hir::FieldSource::Named(it) }; - let field = hir::StructField::from_source(db, src)?; - let visibility = match field.parent_def(db) { - hir::VariantDef::Struct(s) => s.source(db).ast.visibility(), - hir::VariantDef::EnumVariant(e) => e.source(db).ast.parent_enum().visibility(), - }; - (FieldAccess(field), visibility) - }, - ast::FnDef(it) => { - if parent.parent().and_then(ast::ItemList::cast).is_some() { - let src = hir::Source { file_id, ast: ast::ImplItem::from(it.clone()) }; - let item = hir::AssocItem::from_source(db, src)?; - (AssocItem(item), it.visibility()) - } else { - let src = hir::Source { file_id, ast: it.clone() }; - let def = hir::Function::from_source(db, src)?; - (Def(def.into()), it.visibility()) - } - }, - ast::ConstDef(it) => { - if parent.parent().and_then(ast::ItemList::cast).is_some() { - let src = hir::Source { file_id, ast: ast::ImplItem::from(it.clone()) }; - let item = hir::AssocItem::from_source(db, src)?; - (AssocItem(item), it.visibility()) - } else { - let src = hir::Source { file_id, ast: it.clone() }; - let def = hir::Const::from_source(db, src)?; - (Def(def.into()), it.visibility()) - } - }, - ast::TypeAliasDef(it) => { - if parent.parent().and_then(ast::ItemList::cast).is_some() { - let src = hir::Source { file_id, ast: ast::ImplItem::from(it.clone()) }; - let item = hir::AssocItem::from_source(db, src)?; - (AssocItem(item), it.visibility()) - } else { - let src = hir::Source { file_id, ast: it.clone() }; - let def = hir::TypeAlias::from_source(db, src)?; - (Def(def.into()), it.visibility()) - } - }, - ast::Module(it) => { - let src = hir::Source { file_id, ast: hir::ModuleSource::Module(it.clone()) }; - let def = hir::Module::from_definition(db, src)?; - (Def(def.into()), it.visibility()) - }, - ast::StructDef(it) => { - let src = hir::Source { file_id, ast: it.clone() }; - let def = hir::Struct::from_source(db, src)?; - (Def(def.into()), it.visibility()) + StructField::from_def(db, file_id, it) }, - ast::EnumDef(it) => { - let src = hir::Source { file_id, ast: it.clone() }; - let def = hir::Enum::from_source(db, src)?; - (Def(def.into()), it.visibility()) - }, - ast::TraitDef(it) => { - let src = hir::Source { file_id, ast: it.clone() }; - let def = hir::Trait::from_source(db, src)?; - (Def(def.into()), it.visibility()) - }, - ast::StaticDef(it) => { - let src = hir::Source { file_id, ast: it.clone() }; - let def = hir::Static::from_source(db, src)?; - (Def(def.into()), it.visibility()) + ast::ImplItem(it) => { + AssocItem::from_def(db, file_id, it.clone()).or_else(|| { + match it { + ast::ImplItem::FnDef(f) => ModuleDef::from_def(db, file_id, f.into()), + ast::ImplItem::ConstDef(c) => ModuleDef::from_def(db, file_id, c.into()), + ast::ImplItem::TypeAliasDef(a) => ModuleDef::from_def(db, file_id, a.into()), + } + }) }, ast::EnumVariant(it) => { let src = hir::Source { file_id, ast: it.clone() }; - let def = hir::EnumVariant::from_source(db, src)?; - (Def(def.into()), it.parent_enum().visibility()) + let def: ModuleDef = EnumVariant::from_source(db, src)?.into(); + Some(def.declaration(db)) }, - _ => { - return None; + ast::ModuleItem(it) => { + ModuleDef::from_def(db, file_id, it) }, + _ => None, } - }; - Some(Declaration { item, container, visibility }) + } +} + +fn decl_from_pat( + db: &RootDatabase, + file_id: HirFileId, + pat: AstPtr, +) -> Option { + let root = db.parse_or_expand(file_id)?; + // FIXME: use match_ast! + let def = pat.to_node(&root).syntax().ancestors().find_map(|node| { + if let Some(it) = ast::FnDef::cast(node.clone()) { + let src = hir::Source { file_id, ast: it }; + Some(hir::Function::from_source(db, src)?.into()) + } else if let Some(it) = ast::ConstDef::cast(node.clone()) { + let src = hir::Source { file_id, ast: it }; + Some(hir::Const::from_source(db, src)?.into()) + } else if let Some(it) = ast::StaticDef::cast(node.clone()) { + let src = hir::Source { file_id, ast: it }; + Some(hir::Static::from_source(db, src)?.into()) + } else { + None + } + })?; + let item = NameKind::Pat((def, pat)); + let container = def.module(db).definition_source(db).ast; + Some(Declaration { item, container, visibility: None }) +} + +impl HasDeclaration for StructField { + type Def = ast::RecordFieldDef; + type Ref = ast::FieldExpr; + + fn declaration(self, db: &RootDatabase) -> Declaration { + let item = NameKind::FieldAccess(self); + let parent = self.parent_def(db); + let container = parent.module(db).definition_source(db).ast; + let visibility = match parent { + VariantDef::Struct(s) => s.source(db).ast.visibility(), + VariantDef::EnumVariant(e) => e.source(db).ast.parent_enum().visibility(), + }; + Declaration { item, container, visibility } + } + + fn from_def(db: &RootDatabase, file_id: HirFileId, def: Self::Def) -> Option { + let src = hir::Source { file_id, ast: hir::FieldSource::Named(def) }; + let field = StructField::from_source(db, src)?; + Some(field.declaration(db)) + } + + fn from_ref( + db: &RootDatabase, + analyzer: &SourceAnalyzer, + refer: Self::Ref, + ) -> Option { + let field = analyzer.resolve_field(&refer)?; + Some(field.declaration(db)) + } +} + +impl HasDeclaration for AssocItem { + type Def = ast::ImplItem; + type Ref = ast::MethodCallExpr; + + fn declaration(self, db: &RootDatabase) -> Declaration { + let item = NameKind::AssocItem(self); + let container = self.module(db).definition_source(db).ast; + let visibility = match self { + AssocItem::Function(f) => f.source(db).ast.visibility(), + AssocItem::Const(c) => c.source(db).ast.visibility(), + AssocItem::TypeAlias(a) => a.source(db).ast.visibility(), + }; + Declaration { item, container, visibility } + } + + fn from_def(db: &RootDatabase, file_id: HirFileId, def: Self::Def) -> Option { + let src = hir::Source { file_id, ast: def }; + let item = AssocItem::from_source(db, src)?; + Some(item.declaration(db)) + } + + fn from_ref( + db: &RootDatabase, + analyzer: &SourceAnalyzer, + refer: Self::Ref, + ) -> Option { + let func: AssocItem = analyzer.resolve_method_call(&refer)?.into(); + Some(func.declaration(db)) + } } + +impl HasDeclaration for ModuleDef { + type Def = ast::ModuleItem; + type Ref = ast::Path; + + fn declaration(self, db: &RootDatabase) -> Declaration { + // FIXME: use macro + let (container, visibility) = match self { + ModuleDef::Module(it) => { + let container = + it.parent(db).or_else(|| Some(it)).unwrap().definition_source(db).ast; + let visibility = it.declaration_source(db).and_then(|s| s.ast.visibility()); + (container, visibility) + } + ModuleDef::EnumVariant(it) => { + let container = it.module(db).definition_source(db).ast; + let visibility = it.source(db).ast.parent_enum().visibility(); + (container, visibility) + } + ModuleDef::Function(it) => { + (it.module(db).definition_source(db).ast, it.source(db).ast.visibility()) + } + ModuleDef::Const(it) => { + (it.module(db).definition_source(db).ast, it.source(db).ast.visibility()) + } + ModuleDef::Static(it) => { + (it.module(db).definition_source(db).ast, it.source(db).ast.visibility()) + } + ModuleDef::Trait(it) => { + (it.module(db).definition_source(db).ast, it.source(db).ast.visibility()) + } + ModuleDef::TypeAlias(it) => { + (it.module(db).definition_source(db).ast, it.source(db).ast.visibility()) + } + ModuleDef::Adt(Adt::Struct(it)) => { + (it.module(db).definition_source(db).ast, it.source(db).ast.visibility()) + } + ModuleDef::Adt(Adt::Union(it)) => { + (it.module(db).definition_source(db).ast, it.source(db).ast.visibility()) + } + ModuleDef::Adt(Adt::Enum(it)) => { + (it.module(db).definition_source(db).ast, it.source(db).ast.visibility()) + } + ModuleDef::BuiltinType(..) => unreachable!(), + }; + let item = NameKind::Def(self); + Declaration { item, container, visibility } + } + + fn from_def(db: &RootDatabase, file_id: HirFileId, def: Self::Def) -> Option { + let src = hir::Source { file_id, ast: def }; + let def = ModuleDef::from_source(db, src)?; + Some(def.declaration(db)) + } + + fn from_ref( + db: &RootDatabase, + analyzer: &SourceAnalyzer, + refer: Self::Ref, + ) -> Option { + None + } +} + +// FIXME: impl HasDeclaration for hir::MacroDef diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs index 6777aa5f3..24453452b 100644 --- a/crates/ra_ide_api/src/references.rs +++ b/crates/ra_ide_api/src/references.rs @@ -69,13 +69,13 @@ pub(crate) fn find_all_refs( Some((def_id, _)) => NavigationTarget::from_adt_def(db, def_id), None => return None, }, - Pat(pat) => NavigationTarget::from_pat(db, position.file_id, pat), + Pat((_, pat)) => NavigationTarget::from_pat(db, position.file_id, pat), SelfParam(par) => NavigationTarget::from_self_param(position.file_id, par), GenericParam(_) => return None, }; let references = match name_kind { - Pat(pat) => analyzer + 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 }) @@ -99,7 +99,7 @@ pub(crate) fn find_all_refs( 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 name_kind = classify_name_ref(db, &analyzer, &name_ref)?; + let name_kind = classify_name_ref(db, position.file_id, &analyzer, &name_ref)?.item; Some(RangeInfo::new(range, (analyzer, name_kind))) } } diff --git a/crates/ra_ide_api/src/syntax_highlighting.rs b/crates/ra_ide_api/src/syntax_highlighting.rs index 98373a49c..8be93e27e 100644 --- a/crates/ra_ide_api/src/syntax_highlighting.rs +++ b/crates/ra_ide_api/src/syntax_highlighting.rs @@ -103,7 +103,9 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec "macro", Some(FieldAccess(_)) => "field", Some(AssocItem(hir::AssocItem::Function(_))) => "function", @@ -119,7 +121,7 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec "type", Some(Def(hir::ModuleDef::BuiltinType(_))) => "type", Some(SelfType(_)) => "type", - Some(Pat(ptr)) => { + Some(Pat((_, ptr))) => { let pat = ptr.to_node(&root); if let Some(name) = pat.name() { let text = name.text(); -- cgit v1.2.3 From 01853e8d6c6f4b44801c74f4fcdef735d9e77b48 Mon Sep 17 00:00:00 2001 From: Ekaterina Babshukova Date: Thu, 10 Oct 2019 00:25:48 +0300 Subject: find scope for `Declaration` item --- crates/ra_ide_api/src/goto_definition.rs | 2 +- crates/ra_ide_api/src/lib.rs | 1 + crates/ra_ide_api/src/name_kind.rs | 65 ++++++++++---------------------- crates/ra_ide_api/src/search_scope.rs | 64 +++++++++++++++++++++++++++++++ 4 files changed, 86 insertions(+), 46 deletions(-) create mode 100644 crates/ra_ide_api/src/search_scope.rs (limited to 'crates') diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index f49764513..fefd59cdd 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs @@ -207,7 +207,7 @@ fn named_target(file_id: FileId, node: &SyntaxNode) -> Option #[cfg(test)] mod tests { - use test_utils::covers; + // use test_utils::covers; use crate::mock_analysis::analysis_and_position; diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs index cbf79ce03..2dc3f0944 100644 --- a/crates/ra_ide_api/src/lib.rs +++ b/crates/ra_ide_api/src/lib.rs @@ -41,6 +41,7 @@ mod matching_brace; mod display; mod inlay_hints; mod wasm_shims; +mod search_scope; #[cfg(test)] mod marks; diff --git a/crates/ra_ide_api/src/name_kind.rs b/crates/ra_ide_api/src/name_kind.rs index 31f6f277d..6d1eb153f 100644 --- a/crates/ra_ide_api/src/name_kind.rs +++ b/crates/ra_ide_api/src/name_kind.rs @@ -2,8 +2,8 @@ use hir::{ db::AstDatabase, Adt, AssocItem, DefWithBody, Either, EnumVariant, FromSource, HasSource, - HirFileId, MacroDef, ModuleDef, ModuleSource, Path, PathResolution, SourceAnalyzer, - StructField, Ty, VariantDef, + HirFileId, MacroDef, Module, ModuleDef, ModuleSource, Path, PathResolution, Source, + SourceAnalyzer, StructField, Ty, VariantDef, }; use ra_db::FileId; use ra_syntax::{ast, ast::VisibilityOwner, AstNode, AstPtr}; @@ -22,8 +22,8 @@ pub enum NameKind { } pub(crate) struct Declaration { - visibility: Option, - container: ModuleSource, + pub visibility: Option, + pub container: Module, pub item: NameKind, } @@ -80,16 +80,9 @@ pub(crate) fn classify_name_ref( } } + let ast = ModuleSource::from_child_node(db, file_id, &parent); let file_id = file_id.into(); - let container = parent.ancestors().find_map(|node| { - if let Some(it) = ast::Module::cast(node.clone()) { - Some(ModuleSource::Module(it)) - } else if let Some(it) = ast::SourceFile::cast(node.clone()) { - Some(ModuleSource::SourceFile(it)) - } else { - None - } - })?; + let container = Module::from_definition(db, Source { file_id, ast })?; if let Some(macro_call) = parent.parent().and_then(|node| node.parent()).and_then(ast::MacroCall::cast) @@ -117,7 +110,7 @@ pub(crate) fn classify_name_ref( } PathResolution::SelfType(impl_block) => { let ty = impl_block.target_ty(db); - let container = impl_block.module().definition_source(db).ast; + let container = impl_block.module(); Some(Declaration { item: NameKind::SelfType(ty), container, visibility: None }) } PathResolution::AssocItem(assoc) => Some(assoc.declaration(db)), @@ -184,7 +177,7 @@ fn decl_from_pat( } })?; let item = NameKind::Pat((def, pat)); - let container = def.module(db).definition_source(db).ast; + let container = def.module(db); Some(Declaration { item, container, visibility: None }) } @@ -195,7 +188,7 @@ impl HasDeclaration for StructField { fn declaration(self, db: &RootDatabase) -> Declaration { let item = NameKind::FieldAccess(self); let parent = self.parent_def(db); - let container = parent.module(db).definition_source(db).ast; + let container = parent.module(db); let visibility = match parent { VariantDef::Struct(s) => s.source(db).ast.visibility(), VariantDef::EnumVariant(e) => e.source(db).ast.parent_enum().visibility(), @@ -225,7 +218,7 @@ impl HasDeclaration for AssocItem { fn declaration(self, db: &RootDatabase) -> Declaration { let item = NameKind::AssocItem(self); - let container = self.module(db).definition_source(db).ast; + let container = self.module(db); let visibility = match self { AssocItem::Function(f) => f.source(db).ast.visibility(), AssocItem::Const(c) => c.source(db).ast.visibility(), @@ -255,43 +248,25 @@ impl HasDeclaration for ModuleDef { type Ref = ast::Path; fn declaration(self, db: &RootDatabase) -> Declaration { - // FIXME: use macro let (container, visibility) = match self { ModuleDef::Module(it) => { - let container = - it.parent(db).or_else(|| Some(it)).unwrap().definition_source(db).ast; + let container = it.parent(db).or_else(|| Some(it)).unwrap(); let visibility = it.declaration_source(db).and_then(|s| s.ast.visibility()); (container, visibility) } ModuleDef::EnumVariant(it) => { - let container = it.module(db).definition_source(db).ast; + let container = it.module(db); let visibility = it.source(db).ast.parent_enum().visibility(); (container, visibility) } - ModuleDef::Function(it) => { - (it.module(db).definition_source(db).ast, it.source(db).ast.visibility()) - } - ModuleDef::Const(it) => { - (it.module(db).definition_source(db).ast, it.source(db).ast.visibility()) - } - ModuleDef::Static(it) => { - (it.module(db).definition_source(db).ast, it.source(db).ast.visibility()) - } - ModuleDef::Trait(it) => { - (it.module(db).definition_source(db).ast, it.source(db).ast.visibility()) - } - ModuleDef::TypeAlias(it) => { - (it.module(db).definition_source(db).ast, it.source(db).ast.visibility()) - } - ModuleDef::Adt(Adt::Struct(it)) => { - (it.module(db).definition_source(db).ast, it.source(db).ast.visibility()) - } - ModuleDef::Adt(Adt::Union(it)) => { - (it.module(db).definition_source(db).ast, it.source(db).ast.visibility()) - } - ModuleDef::Adt(Adt::Enum(it)) => { - (it.module(db).definition_source(db).ast, it.source(db).ast.visibility()) - } + ModuleDef::Function(it) => (it.module(db), it.source(db).ast.visibility()), + ModuleDef::Const(it) => (it.module(db), it.source(db).ast.visibility()), + ModuleDef::Static(it) => (it.module(db), it.source(db).ast.visibility()), + ModuleDef::Trait(it) => (it.module(db), it.source(db).ast.visibility()), + ModuleDef::TypeAlias(it) => (it.module(db), it.source(db).ast.visibility()), + ModuleDef::Adt(Adt::Struct(it)) => (it.module(db), it.source(db).ast.visibility()), + ModuleDef::Adt(Adt::Union(it)) => (it.module(db), it.source(db).ast.visibility()), + ModuleDef::Adt(Adt::Enum(it)) => (it.module(db), it.source(db).ast.visibility()), ModuleDef::BuiltinType(..) => unreachable!(), }; let item = NameKind::Def(self); diff --git a/crates/ra_ide_api/src/search_scope.rs b/crates/ra_ide_api/src/search_scope.rs new file mode 100644 index 000000000..1cf1aed37 --- /dev/null +++ b/crates/ra_ide_api/src/search_scope.rs @@ -0,0 +1,64 @@ +use hir::{DefWithBody, HasSource, ModuleSource}; +use ra_db::{FileId, SourceDatabase}; +use ra_syntax::{AstNode, TextRange}; + +use crate::{ + db::RootDatabase, + name_kind::{Declaration, NameKind}, +}; + +pub struct SearchScope { + pub scope: Vec<(FileId, Option)>, +} + +impl Declaration { + pub fn scope(self, db: &RootDatabase) -> Option { + let module_src = self.container.definition_source(db); + let file_id = module_src.file_id.original_file(db); + + if let NameKind::Pat((def, _)) = self.item { + let range = match def { + DefWithBody::Function(f) => f.source(db).ast.syntax().text_range(), + DefWithBody::Const(c) => c.source(db).ast.syntax().text_range(), + DefWithBody::Static(s) => s.source(db).ast.syntax().text_range(), + }; + return Some(SearchScope { scope: vec![(file_id, Some(range))] }); + } + + if let Some(vis) = self.visibility { + let source_root_id = db.file_source_root(file_id); + let source_root = db.source_root(source_root_id); + let mut files = source_root.walk().map(|id| (id.into(), None)).collect::>(); + + if vis.syntax().text() == "pub(crate)" { + return Some(SearchScope { scope: files }); + } + if vis.syntax().text() == "pub" { + let krate = self.container.krate(db).unwrap(); + let crate_graph = db.crate_graph(); + + for crate_id in crate_graph.iter() { + let mut crate_deps = crate_graph.dependencies(crate_id); + + if crate_deps.any(|dep| dep.crate_id() == krate.crate_id()) { + let root_file = crate_graph.crate_root(crate_id); + let source_root_id = db.file_source_root(root_file); + let source_root = db.source_root(source_root_id); + files.extend(source_root.walk().map(|id| (id.into(), None))); + } + } + + return Some(SearchScope { scope: files }); + } + // FIXME: extend to "pub(super)" and "pub(in path)" cases, + // then remove `Option` + return None; + } + + let range = match module_src.ast { + ModuleSource::Module(m) => Some(m.syntax().text_range()), + ModuleSource::SourceFile(_) => None, + }; + Some(SearchScope { scope: vec![(file_id, range)] }) + } +} -- cgit v1.2.3 From 5b03773fbeea55d86f64e5fb69a0d0f1d6a4f7e8 Mon Sep 17 00:00:00 2001 From: Ekaterina Babshukova Date: Thu, 10 Oct 2019 18:51:51 +0300 Subject: implement search of references --- crates/ra_ide_api/src/name_kind.rs | 83 ++++++++++++++++++----------------- crates/ra_ide_api/src/references.rs | 50 +++++++++++---------- crates/ra_ide_api/src/search_scope.rs | 77 ++++++++++++++++++++++++++------ 3 files changed, 134 insertions(+), 76 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide_api/src/name_kind.rs b/crates/ra_ide_api/src/name_kind.rs index 6d1eb153f..8eef540f6 100644 --- a/crates/ra_ide_api/src/name_kind.rs +++ b/crates/ra_ide_api/src/name_kind.rs @@ -10,6 +10,7 @@ use ra_syntax::{ast, ast::VisibilityOwner, AstNode, AstPtr}; use crate::db::RootDatabase; +#[derive(PartialEq, Eq)] pub enum NameKind { Macro(MacroDef), FieldAccess(StructField), @@ -21,23 +22,24 @@ pub enum NameKind { GenericParam(u32), } -pub(crate) struct Declaration { +#[derive(PartialEq, Eq)] +pub(crate) struct Definition { pub visibility: Option, pub container: Module, pub item: NameKind, } -trait HasDeclaration { +trait HasDefinition { type Def; type Ref; - fn declaration(self, db: &RootDatabase) -> Declaration; - fn from_def(db: &RootDatabase, file_id: HirFileId, def: Self::Def) -> Option; + fn definition(self, db: &RootDatabase) -> Definition; + fn from_def(db: &RootDatabase, file_id: HirFileId, def: Self::Def) -> Option; fn from_ref( db: &RootDatabase, analyzer: &SourceAnalyzer, refer: Self::Ref, - ) -> Option; + ) -> Option; } macro_rules! match_ast { @@ -55,7 +57,7 @@ pub(crate) fn classify_name_ref( file_id: FileId, analyzer: &SourceAnalyzer, name_ref: &ast::NameRef, -) -> Option { +) -> Option { let parent = name_ref.syntax().parent()?; match_ast! { match parent { @@ -64,7 +66,7 @@ pub(crate) fn classify_name_ref( }, ast::FieldExpr(it) => { if let Some(field) = analyzer.resolve_field(&it) { - return Some(field.declaration(db)); + return Some(field.definition(db)); } }, ast::RecordField(it) => { @@ -73,7 +75,7 @@ pub(crate) fn classify_name_ref( let hir_path = Path::from_name_ref(name_ref); let hir_name = hir_path.as_ident()?; let field = variant_def.field(db, hir_name)?; - return Some(field.declaration(db)); + return Some(field.definition(db)); } }, _ => (), @@ -83,12 +85,13 @@ pub(crate) fn classify_name_ref( let ast = ModuleSource::from_child_node(db, file_id, &parent); let file_id = file_id.into(); let container = Module::from_definition(db, Source { file_id, ast })?; + let visibility = None; if let Some(macro_call) = parent.parent().and_then(|node| node.parent()).and_then(ast::MacroCall::cast) { if let Some(mac) = analyzer.resolve_macro_call(db, ¯o_call) { - return Some(Declaration { item: NameKind::Macro(mac), container, visibility: None }); + return Some(Definition { item: NameKind::Macro(mac), container, visibility }); } } @@ -96,24 +99,24 @@ pub(crate) fn classify_name_ref( let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?; let resolved = analyzer.resolve_path(db, &path)?; match resolved { - PathResolution::Def(def) => Some(def.declaration(db)), + PathResolution::Def(def) => Some(def.definition(db)), PathResolution::LocalBinding(Either::A(pat)) => decl_from_pat(db, file_id, pat), PathResolution::LocalBinding(Either::B(par)) => { - Some(Declaration { item: NameKind::SelfParam(par), container, visibility: None }) + Some(Definition { item: NameKind::SelfParam(par), container, visibility }) } PathResolution::GenericParam(par) => { // FIXME: get generic param def - Some(Declaration { item: NameKind::GenericParam(par), container, visibility: None }) + Some(Definition { item: NameKind::GenericParam(par), container, visibility }) } PathResolution::Macro(def) => { - Some(Declaration { item: NameKind::Macro(def), container, visibility: None }) + Some(Definition { item: NameKind::Macro(def), container, visibility }) } PathResolution::SelfType(impl_block) => { let ty = impl_block.target_ty(db); let container = impl_block.module(); - Some(Declaration { item: NameKind::SelfType(ty), container, visibility: None }) + Some(Definition { item: NameKind::SelfType(ty), container, visibility }) } - PathResolution::AssocItem(assoc) => Some(assoc.declaration(db)), + PathResolution::AssocItem(assoc) => Some(assoc.definition(db)), } } @@ -121,7 +124,7 @@ pub(crate) fn classify_name( db: &RootDatabase, file_id: FileId, name: &ast::Name, -) -> Option { +) -> Option { let parent = name.syntax().parent()?; let file_id = file_id.into(); @@ -145,7 +148,7 @@ pub(crate) fn classify_name( ast::EnumVariant(it) => { let src = hir::Source { file_id, ast: it.clone() }; let def: ModuleDef = EnumVariant::from_source(db, src)?.into(); - Some(def.declaration(db)) + Some(def.definition(db)) }, ast::ModuleItem(it) => { ModuleDef::from_def(db, file_id, it) @@ -159,7 +162,7 @@ fn decl_from_pat( db: &RootDatabase, file_id: HirFileId, pat: AstPtr, -) -> Option { +) -> Option { let root = db.parse_or_expand(file_id)?; // FIXME: use match_ast! let def = pat.to_node(&root).syntax().ancestors().find_map(|node| { @@ -178,14 +181,14 @@ fn decl_from_pat( })?; let item = NameKind::Pat((def, pat)); let container = def.module(db); - Some(Declaration { item, container, visibility: None }) + Some(Definition { item, container, visibility: None }) } -impl HasDeclaration for StructField { +impl HasDefinition for StructField { type Def = ast::RecordFieldDef; type Ref = ast::FieldExpr; - fn declaration(self, db: &RootDatabase) -> Declaration { + fn definition(self, db: &RootDatabase) -> Definition { let item = NameKind::FieldAccess(self); let parent = self.parent_def(db); let container = parent.module(db); @@ -193,30 +196,30 @@ impl HasDeclaration for StructField { VariantDef::Struct(s) => s.source(db).ast.visibility(), VariantDef::EnumVariant(e) => e.source(db).ast.parent_enum().visibility(), }; - Declaration { item, container, visibility } + Definition { item, container, visibility } } - fn from_def(db: &RootDatabase, file_id: HirFileId, def: Self::Def) -> Option { + fn from_def(db: &RootDatabase, file_id: HirFileId, def: Self::Def) -> Option { let src = hir::Source { file_id, ast: hir::FieldSource::Named(def) }; let field = StructField::from_source(db, src)?; - Some(field.declaration(db)) + Some(field.definition(db)) } fn from_ref( db: &RootDatabase, analyzer: &SourceAnalyzer, refer: Self::Ref, - ) -> Option { + ) -> Option { let field = analyzer.resolve_field(&refer)?; - Some(field.declaration(db)) + Some(field.definition(db)) } } -impl HasDeclaration for AssocItem { +impl HasDefinition for AssocItem { type Def = ast::ImplItem; type Ref = ast::MethodCallExpr; - fn declaration(self, db: &RootDatabase) -> Declaration { + fn definition(self, db: &RootDatabase) -> Definition { let item = NameKind::AssocItem(self); let container = self.module(db); let visibility = match self { @@ -224,30 +227,30 @@ impl HasDeclaration for AssocItem { AssocItem::Const(c) => c.source(db).ast.visibility(), AssocItem::TypeAlias(a) => a.source(db).ast.visibility(), }; - Declaration { item, container, visibility } + Definition { item, container, visibility } } - fn from_def(db: &RootDatabase, file_id: HirFileId, def: Self::Def) -> Option { + fn from_def(db: &RootDatabase, file_id: HirFileId, def: Self::Def) -> Option { let src = hir::Source { file_id, ast: def }; let item = AssocItem::from_source(db, src)?; - Some(item.declaration(db)) + Some(item.definition(db)) } fn from_ref( db: &RootDatabase, analyzer: &SourceAnalyzer, refer: Self::Ref, - ) -> Option { + ) -> Option { let func: AssocItem = analyzer.resolve_method_call(&refer)?.into(); - Some(func.declaration(db)) + Some(func.definition(db)) } } -impl HasDeclaration for ModuleDef { +impl HasDefinition for ModuleDef { type Def = ast::ModuleItem; type Ref = ast::Path; - fn declaration(self, db: &RootDatabase) -> Declaration { + fn definition(self, db: &RootDatabase) -> Definition { let (container, visibility) = match self { ModuleDef::Module(it) => { let container = it.parent(db).or_else(|| Some(it)).unwrap(); @@ -270,22 +273,22 @@ impl HasDeclaration for ModuleDef { ModuleDef::BuiltinType(..) => unreachable!(), }; let item = NameKind::Def(self); - Declaration { item, container, visibility } + Definition { item, container, visibility } } - fn from_def(db: &RootDatabase, file_id: HirFileId, def: Self::Def) -> Option { + fn from_def(db: &RootDatabase, file_id: HirFileId, def: Self::Def) -> Option { let src = hir::Source { file_id, ast: def }; let def = ModuleDef::from_source(db, src)?; - Some(def.declaration(db)) + Some(def.definition(db)) } fn from_ref( db: &RootDatabase, analyzer: &SourceAnalyzer, refer: Self::Ref, - ) -> Option { + ) -> Option { None } } -// FIXME: impl HasDeclaration for hir::MacroDef +// FIXME: impl HasDefinition for hir::MacroDef diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs index 24453452b..24cd7e827 100644 --- a/crates/ra_ide_api/src/references.rs +++ b/crates/ra_ide_api/src/references.rs @@ -7,10 +7,8 @@ use relative_path::{RelativePath, RelativePathBuf}; use crate::{ db::RootDatabase, - name_kind::{ - classify_name, classify_name_ref, - NameKind::{self, *}, - }, + name_kind::{classify_name, classify_name_ref, Definition, NameKind::*}, + search_scope::find_refs, FileId, FilePosition, FileRange, FileSystemEdit, NavigationTarget, RangeInfo, SourceChange, SourceFileEdit, TextRange, }; @@ -58,9 +56,9 @@ pub(crate) fn find_all_refs( ) -> Option> { let parse = db.parse(position.file_id); let syntax = parse.tree().syntax().clone(); - let RangeInfo { range, info: (analyzer, name_kind) } = find_name(db, &syntax, position)?; + let RangeInfo { range, info: (name, def) } = find_name(db, &syntax, position)?; - let declaration = match name_kind { + 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), @@ -74,14 +72,19 @@ pub(crate) fn find_all_refs( 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 = 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); + let references = references + .into_iter() + .map(move |ref_desc| FileRange { file_id: position.file_id, range: ref_desc.range }) + .collect::>(); return Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references })); @@ -89,18 +92,17 @@ pub(crate) fn find_all_refs( db: &RootDatabase, syntax: &SyntaxNode, position: FilePosition, - ) -> Option> { + ) -> Option> { if let Some(name) = find_node_at_offset::(&syntax, position.offset) { - let analyzer = hir::SourceAnalyzer::new(db, position.file_id, name.syntax(), None); - let name_kind = classify_name(db, position.file_id, &name)?.item; + let def = classify_name(db, position.file_id, &name)?; let range = name.syntax().text_range(); - return Some(RangeInfo::new(range, (analyzer, name_kind))); + 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 name_kind = classify_name_ref(db, position.file_id, &analyzer, &name_ref)?.item; - Some(RangeInfo::new(range, (analyzer, name_kind))) + let def = classify_name_ref(db, position.file_id, &analyzer, &name_ref)?; + Some(RangeInfo::new(range, (name_ref.text().to_string(), def))) } } @@ -271,12 +273,16 @@ mod tests { let code = r#" //- /lib.rs struct Foo { - spam<|>: u32, + pub spam<|>: u32, + } + + fn main(s: Foo) { + let f = s.spam; } "#; let refs = get_all_refs(code); - assert_eq!(refs.len(), 1); + assert_eq!(refs.len(), 2); } #[test] diff --git a/crates/ra_ide_api/src/search_scope.rs b/crates/ra_ide_api/src/search_scope.rs index 1cf1aed37..9fcbdcc3a 100644 --- a/crates/ra_ide_api/src/search_scope.rs +++ b/crates/ra_ide_api/src/search_scope.rs @@ -1,18 +1,69 @@ -use hir::{DefWithBody, HasSource, ModuleSource}; +use hir::{ + source_binder::ReferenceDescriptor, DefWithBody, HasSource, ModuleSource, SourceAnalyzer, +}; use ra_db::{FileId, SourceDatabase}; -use ra_syntax::{AstNode, TextRange}; +use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SourceFile, TextRange, TextUnit}; use crate::{ db::RootDatabase, - name_kind::{Declaration, NameKind}, + name_kind::{classify_name_ref, Definition, NameKind}, }; -pub struct SearchScope { +pub(crate) struct SearchScope { pub scope: Vec<(FileId, Option)>, } -impl Declaration { - pub fn scope(self, db: &RootDatabase) -> Option { +pub(crate) fn find_refs( + 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 analyzer = SourceAnalyzer::new(db, file_id, name_ref.syntax(), None); + let classified = classify_name_ref(db, file_id, &analyzer, &name_ref); + if let Some(d) = classified { + d == def + } else { + false + } + }; + + 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 name_range = name_ref.syntax().text_range(); + + if let Some(range) = text_range { + if name_range.is_subrange(&range) && is_match(file_id, &name_ref) { + refs.push(ReferenceDescriptor { + name: name_ref.text().to_string(), + range: name_ref.syntax().text_range(), + }); + } + } else if is_match(file_id, &name_ref) { + refs.push(ReferenceDescriptor { + name: name_ref.text().to_string(), + range: name_ref.syntax().text_range(), + }); + } + } + } + } + + return refs; +} + +impl Definition { + pub fn scope(&self, db: &RootDatabase) -> SearchScope { let module_src = self.container.definition_source(db); let file_id = module_src.file_id.original_file(db); @@ -22,16 +73,16 @@ impl Declaration { DefWithBody::Const(c) => c.source(db).ast.syntax().text_range(), DefWithBody::Static(s) => s.source(db).ast.syntax().text_range(), }; - return Some(SearchScope { scope: vec![(file_id, Some(range))] }); + return SearchScope { scope: vec![(file_id, Some(range))] }; } - if let Some(vis) = self.visibility { + if let Some(ref vis) = self.visibility { let source_root_id = db.file_source_root(file_id); let source_root = db.source_root(source_root_id); let mut files = source_root.walk().map(|id| (id.into(), None)).collect::>(); if vis.syntax().text() == "pub(crate)" { - return Some(SearchScope { scope: files }); + return SearchScope { scope: files }; } if vis.syntax().text() == "pub" { let krate = self.container.krate(db).unwrap(); @@ -48,17 +99,15 @@ impl Declaration { } } - return Some(SearchScope { scope: files }); + return SearchScope { scope: files }; } - // FIXME: extend to "pub(super)" and "pub(in path)" cases, - // then remove `Option` - return None; + // FIXME: "pub(super)", "pub(in path)" } let range = match module_src.ast { ModuleSource::Module(m) => Some(m.syntax().text_range()), ModuleSource::SourceFile(_) => None, }; - Some(SearchScope { scope: vec![(file_id, range)] }) + SearchScope { scope: vec![(file_id, range)] } } } -- cgit v1.2.3 From df8441b24e24c438d82b93931474faf7e30d17df Mon Sep 17 00:00:00 2001 From: Ekaterina Babshukova Date: Fri, 11 Oct 2019 02:11:23 +0300 Subject: some fixes, add tests --- crates/ra_ide_api/src/name_kind.rs | 14 ++---------- crates/ra_ide_api/src/references.rs | 43 +++++++++++++++++++++++++++++++---- crates/ra_ide_api/src/search_scope.rs | 34 +++++++++------------------ 3 files changed, 52 insertions(+), 39 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide_api/src/name_kind.rs b/crates/ra_ide_api/src/name_kind.rs index 8eef540f6..2f944fb04 100644 --- a/crates/ra_ide_api/src/name_kind.rs +++ b/crates/ra_ide_api/src/name_kind.rs @@ -6,11 +6,11 @@ use hir::{ SourceAnalyzer, StructField, Ty, VariantDef, }; use ra_db::FileId; -use ra_syntax::{ast, ast::VisibilityOwner, AstNode, AstPtr}; +use ra_syntax::{ast, ast::VisibilityOwner, match_ast, AstNode, AstPtr}; use crate::db::RootDatabase; -#[derive(PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub enum NameKind { Macro(MacroDef), FieldAccess(StructField), @@ -42,16 +42,6 @@ trait HasDefinition { ) -> Option; } -macro_rules! match_ast { - (match $node:ident { - $( ast::$ast:ident($it:ident) => $res:block, )* - _ => $catch_all:expr, - }) => {{ - $( if let Some($it) = ast::$ast::cast($node.clone()) $res else )* - { $catch_all } - }}; -} - pub(crate) fn classify_name_ref( db: &RootDatabase, file_id: FileId, diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs index 24cd7e827..e640b92cf 100644 --- a/crates/ra_ide_api/src/references.rs +++ b/crates/ra_ide_api/src/references.rs @@ -81,10 +81,6 @@ pub(crate) fn find_all_refs( // _ => vec![], // }; let references = find_refs(db, def, name); - let references = references - .into_iter() - .map(move |ref_desc| FileRange { file_id: position.file_id, range: ref_desc.range }) - .collect::>(); return Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references })); @@ -314,6 +310,45 @@ mod tests { assert_eq!(refs.len(), 1); } + #[test] + fn test_find_all_refs_modules() { + let code = r#" + //- /lib.rs + pub mod foo; + pub mod bar; + + fn f() { + let i = foo::Foo { n: 5 }; + } + + //- /foo.rs + use crate::bar; + + pub struct Foo { + pub n: u32, + } + + fn f() { + let i = bar::Bar { n: 5 }; + } + + //- /bar.rs + use crate::foo; + + pub struct Bar { + pub n: u32, + } + + fn f() { + let i = foo::Foo<|> { n: 5 }; + } + "#; + + let (analysis, pos) = analysis_and_position(code); + let refs = analysis.find_all_refs(pos).unwrap().unwrap(); + assert_eq!(refs.len(), 3); + } + fn get_all_refs(text: &str) -> ReferenceSearchResult { let (analysis, position) = single_file_with_position(text); analysis.find_all_refs(position).unwrap().unwrap() diff --git a/crates/ra_ide_api/src/search_scope.rs b/crates/ra_ide_api/src/search_scope.rs index 9fcbdcc3a..1590a09c4 100644 --- a/crates/ra_ide_api/src/search_scope.rs +++ b/crates/ra_ide_api/src/search_scope.rs @@ -1,7 +1,5 @@ -use hir::{ - source_binder::ReferenceDescriptor, DefWithBody, HasSource, ModuleSource, SourceAnalyzer, -}; -use ra_db::{FileId, SourceDatabase}; +use hir::{DefWithBody, HasSource, ModuleSource, SourceAnalyzer}; +use ra_db::{FileId, FileRange, SourceDatabase}; use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SourceFile, TextRange, TextUnit}; use crate::{ @@ -13,11 +11,7 @@ pub(crate) struct SearchScope { pub scope: Vec<(FileId, Option)>, } -pub(crate) fn find_refs( - db: &RootDatabase, - def: Definition, - name: String, -) -> Vec { +pub(crate) fn find_refs(db: &RootDatabase, def: Definition, name: String) -> Vec { let pat = name.as_str(); let scope = def.scope(db).scope; let mut refs = vec![]; @@ -40,20 +34,14 @@ pub(crate) fn find_refs( 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 name_range = name_ref.syntax().text_range(); - - if let Some(range) = text_range { - if name_range.is_subrange(&range) && is_match(file_id, &name_ref) { - refs.push(ReferenceDescriptor { - name: name_ref.text().to_string(), - range: name_ref.syntax().text_range(), - }); + 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(ReferenceDescriptor { - name: name_ref.text().to_string(), - range: name_ref.syntax().text_range(), - }); + refs.push(FileRange { file_id, range }); } } } @@ -81,10 +69,10 @@ impl Definition { let source_root = db.source_root(source_root_id); let mut files = source_root.walk().map(|id| (id.into(), None)).collect::>(); - if vis.syntax().text() == "pub(crate)" { + if vis.syntax().to_string().as_str() == "pub(crate)" { return SearchScope { scope: files }; } - if vis.syntax().text() == "pub" { + if vis.syntax().to_string().as_str() == "pub" { let krate = self.container.krate(db).unwrap(); let crate_graph = db.crate_graph(); -- cgit v1.2.3 From 79e6b3b0d17b9389ccdc422ae42beb38163c6610 Mon Sep 17 00:00:00 2001 From: Ekaterina Babshukova Date: Sat, 12 Oct 2019 13:39:02 +0300 Subject: make `handle_references` accept refs from other files --- crates/ra_lsp_server/src/main_loop/handlers.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'crates') diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index af3cd04ea..a07aaa9b5 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs @@ -481,8 +481,7 @@ pub fn handle_references( params: req::ReferenceParams, ) -> Result>> { let position = params.text_document_position.try_conv_with(&world)?; - let line_index = world.analysis().file_line_index(position.file_id)?; - + let refs = match world.analysis().find_all_refs(position)? { None => return Ok(None), Some(refs) => refs, @@ -490,13 +489,19 @@ pub fn handle_references( let locations = if params.context.include_declaration { refs.into_iter() - .filter_map(|r| to_location(r.file_id, r.range, &world, &line_index).ok()) + .filter_map(|r| { + let line_index = world.analysis().file_line_index(r.file_id).ok()?; + to_location(r.file_id, r.range, &world, &line_index).ok() + }) .collect() } else { // Only iterate over the references if include_declaration was false refs.references() .iter() - .filter_map(|r| to_location(r.file_id, r.range, &world, &line_index).ok()) + .filter_map(|r| { + let line_index = world.analysis().file_line_index(r.file_id).ok()?; + to_location(r.file_id, r.range, &world, &line_index).ok() + }) .collect() }; -- cgit v1.2.3 From 0dd08b8023eba053725d5032149808b8733be263 Mon Sep 17 00:00:00 2001 From: Ekaterina Babshukova Date: Sat, 12 Oct 2019 15:47:36 +0300 Subject: classify definition of a function right --- crates/ra_ide_api/src/name_kind.rs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'crates') diff --git a/crates/ra_ide_api/src/name_kind.rs b/crates/ra_ide_api/src/name_kind.rs index 2f944fb04..583399cfe 100644 --- a/crates/ra_ide_api/src/name_kind.rs +++ b/crates/ra_ide_api/src/name_kind.rs @@ -221,6 +221,9 @@ impl HasDefinition for AssocItem { } fn from_def(db: &RootDatabase, file_id: HirFileId, def: Self::Def) -> Option { + if def.syntax().parent().and_then(ast::ItemList::cast).is_none() { + return None; + } let src = hir::Source { file_id, ast: def }; let item = AssocItem::from_source(db, src)?; Some(item.definition(db)) -- cgit v1.2.3 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/goto_definition.rs | 5 +- crates/ra_ide_api/src/hover.rs | 8 +- crates/ra_ide_api/src/lib.rs | 2 - crates/ra_ide_api/src/name_kind.rs | 287 -------------- crates/ra_ide_api/src/references.rs | 417 ++++---------------- crates/ra_ide_api/src/references/classify.rs | 143 +++++++ crates/ra_ide_api/src/references/definition.rs | 177 +++++++++ crates/ra_ide_api/src/references/rename.rs | 467 +++++++++++++++++++++++ crates/ra_ide_api/src/references/search_scope.rs | 61 +++ crates/ra_ide_api/src/search_scope.rs | 101 ----- crates/ra_ide_api/src/syntax_highlighting.rs | 10 +- crates/ra_lsp_server/src/main_loop/handlers.rs | 2 +- 12 files changed, 925 insertions(+), 755 deletions(-) delete mode 100644 crates/ra_ide_api/src/name_kind.rs create mode 100644 crates/ra_ide_api/src/references/classify.rs create mode 100644 crates/ra_ide_api/src/references/definition.rs create mode 100644 crates/ra_ide_api/src/references/rename.rs create mode 100644 crates/ra_ide_api/src/references/search_scope.rs delete mode 100644 crates/ra_ide_api/src/search_scope.rs (limited to 'crates') diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index fefd59cdd..c35d8da41 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs @@ -10,7 +10,7 @@ use ra_syntax::{ use crate::{ db::RootDatabase, display::ShortLabel, - name_kind::{classify_name_ref, NameKind::*}, + references::{classify_name_ref, NameKind::*}, FilePosition, NavigationTarget, RangeInfo, }; @@ -54,8 +54,7 @@ pub(crate) fn reference_definition( ) -> ReferenceResult { use self::ReferenceResult::*; - let analyzer = hir::SourceAnalyzer::new(db, file_id, name_ref.syntax(), None); - let name_kind = classify_name_ref(db, file_id, &analyzer, &name_ref).and_then(|d| Some(d.item)); + let name_kind = classify_name_ref(db, file_id, &name_ref).and_then(|d| Some(d.item)); match name_kind { Some(Macro(mac)) => return Exact(NavigationTarget::from_macro_def(db, mac)), Some(FieldAccess(field)) => return Exact(NavigationTarget::from_field(db, field)), diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs index 316f43c1b..189094ae5 100644 --- a/crates/ra_ide_api/src/hover.rs +++ b/crates/ra_ide_api/src/hover.rs @@ -14,7 +14,7 @@ use crate::{ description_from_symbol, docs_from_symbol, macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel, }, - name_kind::{classify_name_ref, NameKind::*}, + references::{classify_name_ref, NameKind::*}, FilePosition, FileRange, RangeInfo, }; @@ -99,11 +99,9 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option(file.syntax(), position.offset) { - let analyzer = hir::SourceAnalyzer::new(db, position.file_id, name_ref.syntax(), None); - let mut no_fallback = false; - let name_kind = classify_name_ref(db, position.file_id, &analyzer, &name_ref) - .and_then(|d| Some(d.item)); + let name_kind = + classify_name_ref(db, position.file_id, &name_ref).and_then(|d| Some(d.item)); match name_kind { Some(Macro(it)) => { let src = it.source(db); diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs index 2dc3f0944..19669a7f0 100644 --- a/crates/ra_ide_api/src/lib.rs +++ b/crates/ra_ide_api/src/lib.rs @@ -19,7 +19,6 @@ mod feature_flags; mod status; mod completion; mod runnables; -mod name_kind; mod goto_definition; mod goto_type_definition; mod extend_selection; @@ -41,7 +40,6 @@ mod matching_brace; mod display; mod inlay_hints; mod wasm_shims; -mod search_scope; #[cfg(test)] mod marks; diff --git a/crates/ra_ide_api/src/name_kind.rs b/crates/ra_ide_api/src/name_kind.rs deleted file mode 100644 index 583399cfe..000000000 --- a/crates/ra_ide_api/src/name_kind.rs +++ /dev/null @@ -1,287 +0,0 @@ -//! FIXME: write short doc here - -use hir::{ - db::AstDatabase, Adt, AssocItem, DefWithBody, Either, EnumVariant, FromSource, HasSource, - HirFileId, MacroDef, Module, ModuleDef, ModuleSource, Path, PathResolution, Source, - SourceAnalyzer, StructField, Ty, VariantDef, -}; -use ra_db::FileId; -use ra_syntax::{ast, ast::VisibilityOwner, match_ast, AstNode, AstPtr}; - -use crate::db::RootDatabase; - -#[derive(Debug, PartialEq, Eq)] -pub enum NameKind { - Macro(MacroDef), - FieldAccess(StructField), - AssocItem(AssocItem), - Def(ModuleDef), - SelfType(Ty), - Pat((DefWithBody, AstPtr)), - SelfParam(AstPtr), - GenericParam(u32), -} - -#[derive(PartialEq, Eq)] -pub(crate) struct Definition { - pub visibility: Option, - pub container: Module, - pub item: NameKind, -} - -trait HasDefinition { - type Def; - type Ref; - - fn definition(self, db: &RootDatabase) -> Definition; - fn from_def(db: &RootDatabase, file_id: HirFileId, def: Self::Def) -> Option; - fn from_ref( - db: &RootDatabase, - analyzer: &SourceAnalyzer, - refer: Self::Ref, - ) -> Option; -} - -pub(crate) fn classify_name_ref( - db: &RootDatabase, - file_id: FileId, - analyzer: &SourceAnalyzer, - name_ref: &ast::NameRef, -) -> Option { - let parent = name_ref.syntax().parent()?; - match_ast! { - match parent { - ast::MethodCallExpr(it) => { - return AssocItem::from_ref(db, analyzer, it); - }, - ast::FieldExpr(it) => { - if let Some(field) = analyzer.resolve_field(&it) { - return Some(field.definition(db)); - } - }, - ast::RecordField(it) => { - if let Some(record_lit) = it.syntax().ancestors().find_map(ast::RecordLit::cast) { - let variant_def = analyzer.resolve_record_literal(&record_lit)?; - let hir_path = Path::from_name_ref(name_ref); - let hir_name = hir_path.as_ident()?; - let field = variant_def.field(db, hir_name)?; - return Some(field.definition(db)); - } - }, - _ => (), - } - } - - let ast = ModuleSource::from_child_node(db, file_id, &parent); - let file_id = file_id.into(); - let container = Module::from_definition(db, Source { file_id, ast })?; - let visibility = None; - - if let Some(macro_call) = - parent.parent().and_then(|node| node.parent()).and_then(ast::MacroCall::cast) - { - if let Some(mac) = analyzer.resolve_macro_call(db, ¯o_call) { - return Some(Definition { item: NameKind::Macro(mac), container, visibility }); - } - } - - // General case, a path or a local: - let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?; - let resolved = analyzer.resolve_path(db, &path)?; - match resolved { - PathResolution::Def(def) => Some(def.definition(db)), - PathResolution::LocalBinding(Either::A(pat)) => decl_from_pat(db, file_id, pat), - PathResolution::LocalBinding(Either::B(par)) => { - Some(Definition { item: NameKind::SelfParam(par), container, visibility }) - } - PathResolution::GenericParam(par) => { - // FIXME: get generic param def - Some(Definition { item: NameKind::GenericParam(par), container, visibility }) - } - PathResolution::Macro(def) => { - Some(Definition { item: NameKind::Macro(def), container, visibility }) - } - PathResolution::SelfType(impl_block) => { - let ty = impl_block.target_ty(db); - let container = impl_block.module(); - Some(Definition { item: NameKind::SelfType(ty), container, visibility }) - } - PathResolution::AssocItem(assoc) => Some(assoc.definition(db)), - } -} - -pub(crate) fn classify_name( - db: &RootDatabase, - file_id: FileId, - name: &ast::Name, -) -> Option { - let parent = name.syntax().parent()?; - let file_id = file_id.into(); - - match_ast! { - match parent { - ast::BindPat(it) => { - decl_from_pat(db, file_id, AstPtr::new(&it)) - }, - ast::RecordFieldDef(it) => { - StructField::from_def(db, file_id, it) - }, - ast::ImplItem(it) => { - AssocItem::from_def(db, file_id, it.clone()).or_else(|| { - match it { - ast::ImplItem::FnDef(f) => ModuleDef::from_def(db, file_id, f.into()), - ast::ImplItem::ConstDef(c) => ModuleDef::from_def(db, file_id, c.into()), - ast::ImplItem::TypeAliasDef(a) => ModuleDef::from_def(db, file_id, a.into()), - } - }) - }, - ast::EnumVariant(it) => { - let src = hir::Source { file_id, ast: it.clone() }; - let def: ModuleDef = EnumVariant::from_source(db, src)?.into(); - Some(def.definition(db)) - }, - ast::ModuleItem(it) => { - ModuleDef::from_def(db, file_id, it) - }, - _ => None, - } - } -} - -fn decl_from_pat( - db: &RootDatabase, - file_id: HirFileId, - pat: AstPtr, -) -> Option { - let root = db.parse_or_expand(file_id)?; - // FIXME: use match_ast! - let def = pat.to_node(&root).syntax().ancestors().find_map(|node| { - if let Some(it) = ast::FnDef::cast(node.clone()) { - let src = hir::Source { file_id, ast: it }; - Some(hir::Function::from_source(db, src)?.into()) - } else if let Some(it) = ast::ConstDef::cast(node.clone()) { - let src = hir::Source { file_id, ast: it }; - Some(hir::Const::from_source(db, src)?.into()) - } else if let Some(it) = ast::StaticDef::cast(node.clone()) { - let src = hir::Source { file_id, ast: it }; - Some(hir::Static::from_source(db, src)?.into()) - } else { - None - } - })?; - let item = NameKind::Pat((def, pat)); - let container = def.module(db); - Some(Definition { item, container, visibility: None }) -} - -impl HasDefinition for StructField { - type Def = ast::RecordFieldDef; - type Ref = ast::FieldExpr; - - fn definition(self, db: &RootDatabase) -> Definition { - let item = NameKind::FieldAccess(self); - let parent = self.parent_def(db); - let container = parent.module(db); - let visibility = match parent { - VariantDef::Struct(s) => s.source(db).ast.visibility(), - VariantDef::EnumVariant(e) => e.source(db).ast.parent_enum().visibility(), - }; - Definition { item, container, visibility } - } - - fn from_def(db: &RootDatabase, file_id: HirFileId, def: Self::Def) -> Option { - let src = hir::Source { file_id, ast: hir::FieldSource::Named(def) }; - let field = StructField::from_source(db, src)?; - Some(field.definition(db)) - } - - fn from_ref( - db: &RootDatabase, - analyzer: &SourceAnalyzer, - refer: Self::Ref, - ) -> Option { - let field = analyzer.resolve_field(&refer)?; - Some(field.definition(db)) - } -} - -impl HasDefinition for AssocItem { - type Def = ast::ImplItem; - type Ref = ast::MethodCallExpr; - - fn definition(self, db: &RootDatabase) -> Definition { - let item = NameKind::AssocItem(self); - let container = self.module(db); - let visibility = match self { - AssocItem::Function(f) => f.source(db).ast.visibility(), - AssocItem::Const(c) => c.source(db).ast.visibility(), - AssocItem::TypeAlias(a) => a.source(db).ast.visibility(), - }; - Definition { item, container, visibility } - } - - fn from_def(db: &RootDatabase, file_id: HirFileId, def: Self::Def) -> Option { - if def.syntax().parent().and_then(ast::ItemList::cast).is_none() { - return None; - } - let src = hir::Source { file_id, ast: def }; - let item = AssocItem::from_source(db, src)?; - Some(item.definition(db)) - } - - fn from_ref( - db: &RootDatabase, - analyzer: &SourceAnalyzer, - refer: Self::Ref, - ) -> Option { - let func: AssocItem = analyzer.resolve_method_call(&refer)?.into(); - Some(func.definition(db)) - } -} - -impl HasDefinition for ModuleDef { - type Def = ast::ModuleItem; - type Ref = ast::Path; - - fn definition(self, db: &RootDatabase) -> Definition { - let (container, visibility) = match self { - ModuleDef::Module(it) => { - let container = it.parent(db).or_else(|| Some(it)).unwrap(); - let visibility = it.declaration_source(db).and_then(|s| s.ast.visibility()); - (container, visibility) - } - ModuleDef::EnumVariant(it) => { - let container = it.module(db); - let visibility = it.source(db).ast.parent_enum().visibility(); - (container, visibility) - } - ModuleDef::Function(it) => (it.module(db), it.source(db).ast.visibility()), - ModuleDef::Const(it) => (it.module(db), it.source(db).ast.visibility()), - ModuleDef::Static(it) => (it.module(db), it.source(db).ast.visibility()), - ModuleDef::Trait(it) => (it.module(db), it.source(db).ast.visibility()), - ModuleDef::TypeAlias(it) => (it.module(db), it.source(db).ast.visibility()), - ModuleDef::Adt(Adt::Struct(it)) => (it.module(db), it.source(db).ast.visibility()), - ModuleDef::Adt(Adt::Union(it)) => (it.module(db), it.source(db).ast.visibility()), - ModuleDef::Adt(Adt::Enum(it)) => (it.module(db), it.source(db).ast.visibility()), - ModuleDef::BuiltinType(..) => unreachable!(), - }; - let item = NameKind::Def(self); - Definition { item, container, visibility } - } - - fn from_def(db: &RootDatabase, file_id: HirFileId, def: Self::Def) -> Option { - let src = hir::Source { file_id, ast: def }; - let def = ModuleDef::from_source(db, src)?; - Some(def.definition(db)) - } - - fn from_ref( - db: &RootDatabase, - analyzer: &SourceAnalyzer, - refer: Self::Ref, - ) -> Option { - None - } -} - -// FIXME: impl HasDefinition for hir::MacroDef 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); - } } diff --git a/crates/ra_ide_api/src/references/classify.rs b/crates/ra_ide_api/src/references/classify.rs new file mode 100644 index 000000000..0b604a5cf --- /dev/null +++ b/crates/ra_ide_api/src/references/classify.rs @@ -0,0 +1,143 @@ +use hir::{ + AssocItem, Either, EnumVariant, FromSource, Module, ModuleDef, ModuleSource, Path, + PathResolution, Source, SourceAnalyzer, StructField, +}; +use ra_db::FileId; +use ra_syntax::{ast, match_ast, AstNode, AstPtr}; + +use super::{definition::HasDefinition, Definition, NameKind}; +use crate::db::RootDatabase; + +use hir::{db::AstDatabase, HirFileId}; + +pub(crate) fn classify_name( + db: &RootDatabase, + file_id: FileId, + name: &ast::Name, +) -> Option { + let parent = name.syntax().parent()?; + let file_id = file_id.into(); + + match_ast! { + match parent { + ast::BindPat(it) => { + decl_from_pat(db, file_id, AstPtr::new(&it)) + }, + ast::RecordFieldDef(it) => { + StructField::from_def(db, file_id, it) + }, + ast::ImplItem(it) => { + AssocItem::from_def(db, file_id, it.clone()).or_else(|| { + match it { + ast::ImplItem::FnDef(f) => ModuleDef::from_def(db, file_id, f.into()), + ast::ImplItem::ConstDef(c) => ModuleDef::from_def(db, file_id, c.into()), + ast::ImplItem::TypeAliasDef(a) => ModuleDef::from_def(db, file_id, a.into()), + } + }) + }, + ast::EnumVariant(it) => { + let src = hir::Source { file_id, ast: it.clone() }; + let def: ModuleDef = EnumVariant::from_source(db, src)?.into(); + Some(def.definition(db)) + }, + ast::ModuleItem(it) => { + ModuleDef::from_def(db, file_id, it) + }, + _ => None, + } + } +} + +pub(crate) fn classify_name_ref( + db: &RootDatabase, + file_id: FileId, + name_ref: &ast::NameRef, +) -> Option { + let analyzer = SourceAnalyzer::new(db, file_id, name_ref.syntax(), None); + let parent = name_ref.syntax().parent()?; + match_ast! { + match parent { + ast::MethodCallExpr(it) => { + return AssocItem::from_ref(db, &analyzer, it); + }, + ast::FieldExpr(it) => { + if let Some(field) = analyzer.resolve_field(&it) { + return Some(field.definition(db)); + } + }, + ast::RecordField(it) => { + if let Some(record_lit) = it.syntax().ancestors().find_map(ast::RecordLit::cast) { + let variant_def = analyzer.resolve_record_literal(&record_lit)?; + let hir_path = Path::from_name_ref(name_ref); + let hir_name = hir_path.as_ident()?; + let field = variant_def.field(db, hir_name)?; + return Some(field.definition(db)); + } + }, + _ => (), + } + } + + let ast = ModuleSource::from_child_node(db, file_id, &parent); + let file_id = file_id.into(); + let container = Module::from_definition(db, Source { file_id, ast })?; + let visibility = None; + + if let Some(macro_call) = + parent.parent().and_then(|node| node.parent()).and_then(ast::MacroCall::cast) + { + if let Some(mac) = analyzer.resolve_macro_call(db, ¯o_call) { + return Some(Definition { item: NameKind::Macro(mac), container, visibility }); + } + } + + // General case, a path or a local: + let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?; + let resolved = analyzer.resolve_path(db, &path)?; + match resolved { + PathResolution::Def(def) => Some(def.definition(db)), + PathResolution::LocalBinding(Either::A(pat)) => decl_from_pat(db, file_id, pat), + PathResolution::LocalBinding(Either::B(par)) => { + Some(Definition { item: NameKind::SelfParam(par), container, visibility }) + } + PathResolution::GenericParam(par) => { + // FIXME: get generic param def + Some(Definition { item: NameKind::GenericParam(par), container, visibility }) + } + PathResolution::Macro(def) => { + Some(Definition { item: NameKind::Macro(def), container, visibility }) + } + PathResolution::SelfType(impl_block) => { + let ty = impl_block.target_ty(db); + let container = impl_block.module(); + Some(Definition { item: NameKind::SelfType(ty), container, visibility }) + } + PathResolution::AssocItem(assoc) => Some(assoc.definition(db)), + } +} + +fn decl_from_pat( + db: &RootDatabase, + file_id: HirFileId, + pat: AstPtr, +) -> Option { + let root = db.parse_or_expand(file_id)?; + // FIXME: use match_ast! + let def = pat.to_node(&root).syntax().ancestors().find_map(|node| { + if let Some(it) = ast::FnDef::cast(node.clone()) { + let src = hir::Source { file_id, ast: it }; + Some(hir::Function::from_source(db, src)?.into()) + } else if let Some(it) = ast::ConstDef::cast(node.clone()) { + let src = hir::Source { file_id, ast: it }; + Some(hir::Const::from_source(db, src)?.into()) + } else if let Some(it) = ast::StaticDef::cast(node.clone()) { + let src = hir::Source { file_id, ast: it }; + Some(hir::Static::from_source(db, src)?.into()) + } else { + None + } + })?; + let item = NameKind::Pat((def, pat)); + let container = def.module(db); + Some(Definition { item, container, visibility: None }) +} diff --git a/crates/ra_ide_api/src/references/definition.rs b/crates/ra_ide_api/src/references/definition.rs new file mode 100644 index 000000000..65b1f8dd7 --- /dev/null +++ b/crates/ra_ide_api/src/references/definition.rs @@ -0,0 +1,177 @@ +use hir::{ + db::AstDatabase, Adt, AssocItem, DefWithBody, FromSource, HasSource, HirFileId, MacroDef, + Module, ModuleDef, SourceAnalyzer, StructField, Ty, VariantDef, +}; +use ra_syntax::{ast, ast::VisibilityOwner, AstNode, AstPtr}; + +use crate::db::RootDatabase; + +#[derive(Debug, PartialEq, Eq)] +pub enum NameKind { + Macro(MacroDef), + FieldAccess(StructField), + AssocItem(AssocItem), + Def(ModuleDef), + SelfType(Ty), + Pat((DefWithBody, AstPtr)), + SelfParam(AstPtr), + GenericParam(u32), +} + +#[derive(PartialEq, Eq)] +pub(crate) struct Definition { + pub visibility: Option, + pub container: Module, + pub item: NameKind, +} + +pub(super) trait HasDefinition { + type Def; + type Ref; + + fn definition(self, db: &RootDatabase) -> Definition; + fn from_def(db: &RootDatabase, file_id: HirFileId, def: Self::Def) -> Option; + fn from_ref( + db: &RootDatabase, + analyzer: &SourceAnalyzer, + refer: Self::Ref, + ) -> Option; +} + +// fn decl_from_pat( +// db: &RootDatabase, +// file_id: HirFileId, +// pat: AstPtr, +// ) -> Option { +// let root = db.parse_or_expand(file_id)?; +// // FIXME: use match_ast! +// let def = pat.to_node(&root).syntax().ancestors().find_map(|node| { +// if let Some(it) = ast::FnDef::cast(node.clone()) { +// let src = hir::Source { file_id, ast: it }; +// Some(hir::Function::from_source(db, src)?.into()) +// } else if let Some(it) = ast::ConstDef::cast(node.clone()) { +// let src = hir::Source { file_id, ast: it }; +// Some(hir::Const::from_source(db, src)?.into()) +// } else if let Some(it) = ast::StaticDef::cast(node.clone()) { +// let src = hir::Source { file_id, ast: it }; +// Some(hir::Static::from_source(db, src)?.into()) +// } else { +// None +// } +// })?; +// let item = NameKind::Pat((def, pat)); +// let container = def.module(db); +// Some(Definition { item, container, visibility: None }) +// } + +impl HasDefinition for StructField { + type Def = ast::RecordFieldDef; + type Ref = ast::FieldExpr; + + fn definition(self, db: &RootDatabase) -> Definition { + let item = NameKind::FieldAccess(self); + let parent = self.parent_def(db); + let container = parent.module(db); + let visibility = match parent { + VariantDef::Struct(s) => s.source(db).ast.visibility(), + VariantDef::EnumVariant(e) => e.source(db).ast.parent_enum().visibility(), + }; + Definition { item, container, visibility } + } + + fn from_def(db: &RootDatabase, file_id: HirFileId, def: Self::Def) -> Option { + let src = hir::Source { file_id, ast: hir::FieldSource::Named(def) }; + let field = StructField::from_source(db, src)?; + Some(field.definition(db)) + } + + fn from_ref( + db: &RootDatabase, + analyzer: &SourceAnalyzer, + refer: Self::Ref, + ) -> Option { + let field = analyzer.resolve_field(&refer)?; + Some(field.definition(db)) + } +} + +impl HasDefinition for AssocItem { + type Def = ast::ImplItem; + type Ref = ast::MethodCallExpr; + + fn definition(self, db: &RootDatabase) -> Definition { + let item = NameKind::AssocItem(self); + let container = self.module(db); + let visibility = match self { + AssocItem::Function(f) => f.source(db).ast.visibility(), + AssocItem::Const(c) => c.source(db).ast.visibility(), + AssocItem::TypeAlias(a) => a.source(db).ast.visibility(), + }; + Definition { item, container, visibility } + } + + fn from_def(db: &RootDatabase, file_id: HirFileId, def: Self::Def) -> Option { + if def.syntax().parent().and_then(ast::ItemList::cast).is_none() { + return None; + } + let src = hir::Source { file_id, ast: def }; + let item = AssocItem::from_source(db, src)?; + Some(item.definition(db)) + } + + fn from_ref( + db: &RootDatabase, + analyzer: &SourceAnalyzer, + refer: Self::Ref, + ) -> Option { + let func: AssocItem = analyzer.resolve_method_call(&refer)?.into(); + Some(func.definition(db)) + } +} + +impl HasDefinition for ModuleDef { + type Def = ast::ModuleItem; + type Ref = ast::Path; + + fn definition(self, db: &RootDatabase) -> Definition { + let (container, visibility) = match self { + ModuleDef::Module(it) => { + let container = it.parent(db).or_else(|| Some(it)).unwrap(); + let visibility = it.declaration_source(db).and_then(|s| s.ast.visibility()); + (container, visibility) + } + ModuleDef::EnumVariant(it) => { + let container = it.module(db); + let visibility = it.source(db).ast.parent_enum().visibility(); + (container, visibility) + } + ModuleDef::Function(it) => (it.module(db), it.source(db).ast.visibility()), + ModuleDef::Const(it) => (it.module(db), it.source(db).ast.visibility()), + ModuleDef::Static(it) => (it.module(db), it.source(db).ast.visibility()), + ModuleDef::Trait(it) => (it.module(db), it.source(db).ast.visibility()), + ModuleDef::TypeAlias(it) => (it.module(db), it.source(db).ast.visibility()), + ModuleDef::Adt(Adt::Struct(it)) => (it.module(db), it.source(db).ast.visibility()), + ModuleDef::Adt(Adt::Union(it)) => (it.module(db), it.source(db).ast.visibility()), + ModuleDef::Adt(Adt::Enum(it)) => (it.module(db), it.source(db).ast.visibility()), + ModuleDef::BuiltinType(..) => unreachable!(), + }; + let item = NameKind::Def(self); + Definition { item, container, visibility } + } + + fn from_def(db: &RootDatabase, file_id: HirFileId, def: Self::Def) -> Option { + let src = hir::Source { file_id, ast: def }; + let def = ModuleDef::from_source(db, src)?; + Some(def.definition(db)) + } + + fn from_ref( + db: &RootDatabase, + analyzer: &SourceAnalyzer, + refer: Self::Ref, + ) -> Option { + None + } +} + +// FIXME: impl HasDefinition for hir::MacroDef diff --git a/crates/ra_ide_api/src/references/rename.rs b/crates/ra_ide_api/src/references/rename.rs new file mode 100644 index 000000000..7e564a40e --- /dev/null +++ b/crates/ra_ide_api/src/references/rename.rs @@ -0,0 +1,467 @@ +use hir::ModuleSource; +use ra_db::SourceDatabase; +use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SyntaxNode}; +use relative_path::{RelativePath, RelativePathBuf}; + +use crate::{ + db::RootDatabase, FileId, FilePosition, FileSystemEdit, RangeInfo, SourceChange, + SourceFileEdit, TextRange, +}; + +use super::find_all_refs; + +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) + } +} + +fn find_name_and_module_at_offset( + 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() + }, + } +} + +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(..) => {} + } + } + + 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; + } + + Some(RangeInfo::new(range, SourceChange::source_file_edits("rename", edit))) +} + +#[cfg(test)] +mod tests { + use crate::{ + mock_analysis::analysis_and_position, mock_analysis::single_file_with_position, FileId, + ReferenceSearchResult, + }; + use insta::assert_debug_snapshot; + use test_utils::assert_eq_text; + + #[test] + fn test_find_all_refs_for_local() { + let code = r#" + fn main() { + let mut i = 1; + let j = 1; + i = i<|> + j; + + { + i = 0; + } + + i = 5; + }"#; + + let refs = get_all_refs(code); + assert_eq!(refs.len(), 5); + } + + #[test] + fn test_find_all_refs_for_param_inside() { + let code = r#" + fn foo(i : u32) -> u32 { + i<|> + }"#; + + let refs = get_all_refs(code); + assert_eq!(refs.len(), 2); + } + + #[test] + fn test_find_all_refs_for_fn_param() { + let code = r#" + fn foo(i<|> : u32) -> u32 { + i + }"#; + + let refs = get_all_refs(code); + assert_eq!(refs.len(), 2); + } + + #[test] + fn test_find_all_refs_field_name() { + let code = r#" + //- /lib.rs + struct Foo { + pub spam<|>: u32, + } + + fn main(s: Foo) { + let f = s.spam; + } + "#; + + let refs = get_all_refs(code); + assert_eq!(refs.len(), 2); + } + + #[test] + fn test_find_all_refs_impl_item_name() { + let code = r#" + //- /lib.rs + struct Foo; + impl Foo { + fn f<|>(&self) { } + } + "#; + + let refs = get_all_refs(code); + assert_eq!(refs.len(), 1); + } + + #[test] + fn test_find_all_refs_enum_var_name() { + let code = r#" + //- /lib.rs + enum Foo { + A, + B<|>, + C, + } + "#; + + let refs = get_all_refs(code); + assert_eq!(refs.len(), 1); + } + + #[test] + fn test_find_all_refs_modules() { + let code = r#" + //- /lib.rs + pub mod foo; + pub mod bar; + + fn f() { + let i = foo::Foo { n: 5 }; + } + + //- /foo.rs + use crate::bar; + + pub struct Foo { + pub n: u32, + } + + fn f() { + let i = bar::Bar { n: 5 }; + } + + //- /bar.rs + use crate::foo; + + pub struct Bar { + pub n: u32, + } + + fn f() { + let i = foo::Foo<|> { n: 5 }; + } + "#; + + let (analysis, pos) = analysis_and_position(code); + let refs = analysis.find_all_refs(pos).unwrap().unwrap(); + assert_eq!(refs.len(), 3); + } + + fn get_all_refs(text: &str) -> ReferenceSearchResult { + 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); + } +} diff --git a/crates/ra_ide_api/src/references/search_scope.rs b/crates/ra_ide_api/src/references/search_scope.rs new file mode 100644 index 000000000..557ee7b57 --- /dev/null +++ b/crates/ra_ide_api/src/references/search_scope.rs @@ -0,0 +1,61 @@ +use hir::{DefWithBody, HasSource, ModuleSource}; +use ra_db::{FileId, SourceDatabase}; +use ra_syntax::{AstNode, TextRange}; + +use crate::db::RootDatabase; + +use super::{Definition, NameKind}; + +pub(crate) struct SearchScope { + pub scope: Vec<(FileId, Option)>, +} + +impl Definition { + pub fn scope(&self, db: &RootDatabase) -> SearchScope { + let module_src = self.container.definition_source(db); + let file_id = module_src.file_id.original_file(db); + + if let NameKind::Pat((def, _)) = self.item { + let range = match def { + DefWithBody::Function(f) => f.source(db).ast.syntax().text_range(), + DefWithBody::Const(c) => c.source(db).ast.syntax().text_range(), + DefWithBody::Static(s) => s.source(db).ast.syntax().text_range(), + }; + return SearchScope { scope: vec![(file_id, Some(range))] }; + } + + if let Some(ref vis) = self.visibility { + let source_root_id = db.file_source_root(file_id); + let source_root = db.source_root(source_root_id); + let mut files = source_root.walk().map(|id| (id.into(), None)).collect::>(); + + if vis.syntax().to_string().as_str() == "pub(crate)" { + return SearchScope { scope: files }; + } + if vis.syntax().to_string().as_str() == "pub" { + let krate = self.container.krate(db).unwrap(); + let crate_graph = db.crate_graph(); + + for crate_id in crate_graph.iter() { + let mut crate_deps = crate_graph.dependencies(crate_id); + + if crate_deps.any(|dep| dep.crate_id() == krate.crate_id()) { + let root_file = crate_graph.crate_root(crate_id); + let source_root_id = db.file_source_root(root_file); + let source_root = db.source_root(source_root_id); + files.extend(source_root.walk().map(|id| (id.into(), None))); + } + } + + return SearchScope { scope: files }; + } + // FIXME: "pub(super)", "pub(in path)" + } + + let range = match module_src.ast { + ModuleSource::Module(m) => Some(m.syntax().text_range()), + ModuleSource::SourceFile(_) => None, + }; + SearchScope { scope: vec![(file_id, range)] } + } +} diff --git a/crates/ra_ide_api/src/search_scope.rs b/crates/ra_ide_api/src/search_scope.rs deleted file mode 100644 index 1590a09c4..000000000 --- a/crates/ra_ide_api/src/search_scope.rs +++ /dev/null @@ -1,101 +0,0 @@ -use hir::{DefWithBody, HasSource, ModuleSource, SourceAnalyzer}; -use ra_db::{FileId, FileRange, SourceDatabase}; -use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SourceFile, TextRange, TextUnit}; - -use crate::{ - db::RootDatabase, - name_kind::{classify_name_ref, Definition, NameKind}, -}; - -pub(crate) struct SearchScope { - pub scope: Vec<(FileId, Option)>, -} - -pub(crate) fn find_refs(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 analyzer = SourceAnalyzer::new(db, file_id, name_ref.syntax(), None); - let classified = classify_name_ref(db, file_id, &analyzer, &name_ref); - if let Some(d) = classified { - d == def - } else { - false - } - }; - - 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 }); - } - } - } - } - - return refs; -} - -impl Definition { - pub fn scope(&self, db: &RootDatabase) -> SearchScope { - let module_src = self.container.definition_source(db); - let file_id = module_src.file_id.original_file(db); - - if let NameKind::Pat((def, _)) = self.item { - let range = match def { - DefWithBody::Function(f) => f.source(db).ast.syntax().text_range(), - DefWithBody::Const(c) => c.source(db).ast.syntax().text_range(), - DefWithBody::Static(s) => s.source(db).ast.syntax().text_range(), - }; - return SearchScope { scope: vec![(file_id, Some(range))] }; - } - - if let Some(ref vis) = self.visibility { - let source_root_id = db.file_source_root(file_id); - let source_root = db.source_root(source_root_id); - let mut files = source_root.walk().map(|id| (id.into(), None)).collect::>(); - - if vis.syntax().to_string().as_str() == "pub(crate)" { - return SearchScope { scope: files }; - } - if vis.syntax().to_string().as_str() == "pub" { - let krate = self.container.krate(db).unwrap(); - let crate_graph = db.crate_graph(); - - for crate_id in crate_graph.iter() { - let mut crate_deps = crate_graph.dependencies(crate_id); - - if crate_deps.any(|dep| dep.crate_id() == krate.crate_id()) { - let root_file = crate_graph.crate_root(crate_id); - let source_root_id = db.file_source_root(root_file); - let source_root = db.source_root(source_root_id); - files.extend(source_root.walk().map(|id| (id.into(), None))); - } - } - - return SearchScope { scope: files }; - } - // FIXME: "pub(super)", "pub(in path)" - } - - let range = match module_src.ast { - ModuleSource::Module(m) => Some(m.syntax().text_range()), - ModuleSource::SourceFile(_) => None, - }; - SearchScope { scope: vec![(file_id, range)] } - } -} diff --git a/crates/ra_ide_api/src/syntax_highlighting.rs b/crates/ra_ide_api/src/syntax_highlighting.rs index 8be93e27e..28c50102e 100644 --- a/crates/ra_ide_api/src/syntax_highlighting.rs +++ b/crates/ra_ide_api/src/syntax_highlighting.rs @@ -14,7 +14,7 @@ use ra_syntax::{ use crate::{ db::RootDatabase, - name_kind::{classify_name_ref, NameKind::*}, + references::{classify_name_ref, NameKind::*}, FileId, }; @@ -101,10 +101,8 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec "macro", Some(FieldAccess(_)) => "field", @@ -131,6 +129,8 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec Result>> { let position = params.text_document_position.try_conv_with(&world)?; - + let refs = match world.analysis().find_all_refs(position)? { None => return Ok(None), Some(refs) => refs, -- cgit v1.2.3 From 835173d065dbe1fdd7369ea49336c0b785be8cb8 Mon Sep 17 00:00:00 2001 From: Ekaterina Babshukova Date: Sat, 12 Oct 2019 20:30:53 +0300 Subject: replace trait by a bunch of functions --- crates/ra_hir/src/from_source.rs | 60 +------ crates/ra_ide_api/src/goto_definition.rs | 2 +- crates/ra_ide_api/src/hover.rs | 2 +- crates/ra_ide_api/src/references.rs | 10 +- crates/ra_ide_api/src/references/classify.rs | 196 ++++++++++++--------- crates/ra_ide_api/src/references/definition.rs | 177 ------------------- .../ra_ide_api/src/references/name_definition.rs | 104 +++++++++++ crates/ra_ide_api/src/references/search_scope.rs | 4 +- crates/ra_ide_api/src/syntax_highlighting.rs | 2 +- 9 files changed, 227 insertions(+), 330 deletions(-) delete mode 100644 crates/ra_ide_api/src/references/definition.rs create mode 100644 crates/ra_ide_api/src/references/name_definition.rs (limited to 'crates') diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs index e09414ca3..f80d8eb5f 100644 --- a/crates/ra_hir/src/from_source.rs +++ b/crates/ra_hir/src/from_source.rs @@ -11,9 +11,8 @@ use crate::{ db::{AstDatabase, DefDatabase, HirDatabase}, ids::{AstItemDef, LocationCtx}, name::AsName, - AssocItem, Const, Crate, Enum, EnumVariant, FieldSource, Function, HasSource, ImplBlock, - Module, ModuleDef, ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, Union, - VariantDef, + Const, Crate, Enum, EnumVariant, FieldSource, Function, HasSource, ImplBlock, Module, + ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, Union, VariantDef, }; pub trait FromSource: Sized { @@ -130,61 +129,6 @@ impl FromSource for StructField { } } -impl FromSource for AssocItem { - type Ast = ast::ImplItem; - fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source) -> Option { - macro_rules! def { - ($kind:ident, $ast:ident) => { - $kind::from_source(db, Source { file_id: src.file_id, ast: $ast }) - .and_then(|it| Some(AssocItem::from(it))) - }; - } - - match src.ast { - ast::ImplItem::FnDef(f) => def!(Function, f), - ast::ImplItem::ConstDef(c) => def!(Const, c), - ast::ImplItem::TypeAliasDef(a) => def!(TypeAlias, a), - } - } -} - -// not fully matched -impl FromSource for ModuleDef { - type Ast = ast::ModuleItem; - fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source) -> Option { - macro_rules! def { - ($kind:ident, $ast:ident) => { - $kind::from_source(db, Source { file_id: src.file_id, ast: $ast }) - .and_then(|it| Some(ModuleDef::from(it))) - }; - } - - match src.ast { - ast::ModuleItem::FnDef(f) => def!(Function, f), - ast::ModuleItem::ConstDef(c) => def!(Const, c), - ast::ModuleItem::TypeAliasDef(a) => def!(TypeAlias, a), - ast::ModuleItem::TraitDef(t) => def!(Trait, t), - ast::ModuleItem::StaticDef(s) => def!(Static, s), - ast::ModuleItem::StructDef(s) => { - let src = Source { file_id: src.file_id, ast: s }; - let s = Struct::from_source(db, src)?; - Some(ModuleDef::Adt(s.into())) - } - ast::ModuleItem::EnumDef(e) => { - let src = Source { file_id: src.file_id, ast: e }; - let e = Enum::from_source(db, src)?; - Some(ModuleDef::Adt(e.into())) - } - ast::ModuleItem::Module(ref m) if !m.has_semi() => { - let src = Source { file_id: src.file_id, ast: ModuleSource::Module(m.clone()) }; - let module = Module::from_definition(db, src)?; - Some(ModuleDef::Module(module)) - } - _ => None, - } - } -} - // FIXME: simplify it impl ModuleSource { pub fn from_position( diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index c35d8da41..1b4ad3a59 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs @@ -57,7 +57,7 @@ pub(crate) fn reference_definition( let name_kind = classify_name_ref(db, file_id, &name_ref).and_then(|d| Some(d.item)); match name_kind { Some(Macro(mac)) => return Exact(NavigationTarget::from_macro_def(db, mac)), - Some(FieldAccess(field)) => return Exact(NavigationTarget::from_field(db, field)), + Some(Field(field)) => return Exact(NavigationTarget::from_field(db, field)), Some(AssocItem(assoc)) => return Exact(NavigationTarget::from_assoc_item(db, assoc)), Some(Def(def)) => match NavigationTarget::from_def(db, def) { Some(nav) => return Exact(nav), diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs index 189094ae5..318708df3 100644 --- a/crates/ra_ide_api/src/hover.rs +++ b/crates/ra_ide_api/src/hover.rs @@ -107,7 +107,7 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option { + Some(Field(it)) => { let src = it.source(db); if let hir::FieldSource::Named(it) = src.ast { res.extend(hover_text(it.doc_comment_text(), it.short_label())); diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs index f54542787..3761fd6e7 100644 --- a/crates/ra_ide_api/src/references.rs +++ b/crates/ra_ide_api/src/references.rs @@ -1,7 +1,7 @@ //! FIXME: write short doc here mod classify; -mod definition; +mod name_definition; mod rename; mod search_scope; @@ -12,7 +12,7 @@ use crate::{db::RootDatabase, FileId, FilePosition, FileRange, NavigationTarget, pub(crate) use self::{ classify::{classify_name, classify_name_ref}, - definition::{Definition, NameKind}, + name_definition::{NameDefinition, NameKind}, rename::rename, }; @@ -63,7 +63,7 @@ pub(crate) fn find_all_refs( let declaration = match def.item { NameKind::Macro(mac) => NavigationTarget::from_macro_def(db, mac), - NameKind::FieldAccess(field) => NavigationTarget::from_field(db, field), + NameKind::Field(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() { @@ -84,7 +84,7 @@ fn find_name<'a>( db: &RootDatabase, syntax: &SyntaxNode, position: FilePosition, -) -> Option> { +) -> 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(); @@ -96,7 +96,7 @@ fn find_name<'a>( Some(RangeInfo::new(range, (name_ref.text().to_string(), def))) } -fn process_definition(db: &RootDatabase, def: Definition, name: String) -> Vec { +fn process_definition(db: &RootDatabase, def: NameDefinition, name: String) -> Vec { let pat = name.as_str(); let scope = def.scope(db).scope; let mut refs = vec![]; diff --git a/crates/ra_ide_api/src/references/classify.rs b/crates/ra_ide_api/src/references/classify.rs index 0b604a5cf..2ba1cf71c 100644 --- a/crates/ra_ide_api/src/references/classify.rs +++ b/crates/ra_ide_api/src/references/classify.rs @@ -1,47 +1,90 @@ -use hir::{ - AssocItem, Either, EnumVariant, FromSource, Module, ModuleDef, ModuleSource, Path, - PathResolution, Source, SourceAnalyzer, StructField, -}; +use hir::{Either, FromSource, Module, ModuleSource, Path, PathResolution, Source, SourceAnalyzer}; use ra_db::FileId; use ra_syntax::{ast, match_ast, AstNode, AstPtr}; -use super::{definition::HasDefinition, Definition, NameKind}; +use super::{ + name_definition::{from_assoc_item, from_module_def, from_pat, from_struct_field}, + NameDefinition, NameKind, +}; use crate::db::RootDatabase; -use hir::{db::AstDatabase, HirFileId}; - pub(crate) fn classify_name( db: &RootDatabase, file_id: FileId, name: &ast::Name, -) -> Option { +) -> Option { let parent = name.syntax().parent()?; let file_id = file_id.into(); + // FIXME: add ast::MacroCall(it) match_ast! { match parent { ast::BindPat(it) => { - decl_from_pat(db, file_id, AstPtr::new(&it)) + from_pat(db, file_id, AstPtr::new(&it)) }, ast::RecordFieldDef(it) => { - StructField::from_def(db, file_id, it) + let ast = hir::FieldSource::Named(it); + let src = hir::Source { file_id, ast }; + let field = hir::StructField::from_source(db, src)?; + Some(from_struct_field(db, field)) + }, + ast::Module(it) => { + let ast = hir::ModuleSource::Module(it); + let src = hir::Source { file_id, ast }; + let def = hir::Module::from_definition(db, src)?; + Some(from_module_def(db, def.into())) }, - ast::ImplItem(it) => { - AssocItem::from_def(db, file_id, it.clone()).or_else(|| { - match it { - ast::ImplItem::FnDef(f) => ModuleDef::from_def(db, file_id, f.into()), - ast::ImplItem::ConstDef(c) => ModuleDef::from_def(db, file_id, c.into()), - ast::ImplItem::TypeAliasDef(a) => ModuleDef::from_def(db, file_id, a.into()), - } - }) + ast::StructDef(it) => { + let src = hir::Source { file_id, ast: it }; + let def = hir::Struct::from_source(db, src)?; + Some(from_module_def(db, def.into())) + }, + ast::EnumDef(it) => { + let src = hir::Source { file_id, ast: it }; + let def = hir::Enum::from_source(db, src)?; + Some(from_module_def(db, def.into())) + }, + ast::TraitDef(it) => { + let src = hir::Source { file_id, ast: it }; + let def = hir::Trait::from_source(db, src)?; + Some(from_module_def(db, def.into())) + }, + ast::StaticDef(it) => { + let src = hir::Source { file_id, ast: it }; + let def = hir::Static::from_source(db, src)?; + Some(from_module_def(db, def.into())) }, ast::EnumVariant(it) => { - let src = hir::Source { file_id, ast: it.clone() }; - let def: ModuleDef = EnumVariant::from_source(db, src)?.into(); - Some(def.definition(db)) + let src = hir::Source { file_id, ast: it }; + let def = hir::EnumVariant::from_source(db, src)?; + Some(from_module_def(db, def.into())) + }, + ast::FnDef(it) => { + let src = hir::Source { file_id, ast: it }; + let def = hir::Function::from_source(db, src)?; + if parent.parent().and_then(ast::ItemList::cast).is_some() { + Some(from_assoc_item(db, def.into())) + } else { + Some(from_module_def(db, def.into())) + } + }, + ast::ConstDef(it) => { + let src = hir::Source { file_id, ast: it }; + let def = hir::Const::from_source(db, src)?; + if parent.parent().and_then(ast::ItemList::cast).is_some() { + Some(from_assoc_item(db, def.into())) + } else { + Some(from_module_def(db, def.into())) + } }, - ast::ModuleItem(it) => { - ModuleDef::from_def(db, file_id, it) + ast::TypeAliasDef(it) => { + let src = hir::Source { file_id, ast: it }; + let def = hir::TypeAlias::from_source(db, src)?; + if parent.parent().and_then(ast::ItemList::cast).is_some() { + Some(from_assoc_item(db, def.into())) + } else { + Some(from_module_def(db, def.into())) + } }, _ => None, } @@ -52,92 +95,75 @@ pub(crate) fn classify_name_ref( db: &RootDatabase, file_id: FileId, name_ref: &ast::NameRef, -) -> Option { - let analyzer = SourceAnalyzer::new(db, file_id, name_ref.syntax(), None); +) -> Option { + use PathResolution::*; + let parent = name_ref.syntax().parent()?; - match_ast! { - match parent { - ast::MethodCallExpr(it) => { - return AssocItem::from_ref(db, &analyzer, it); - }, - ast::FieldExpr(it) => { - if let Some(field) = analyzer.resolve_field(&it) { - return Some(field.definition(db)); - } - }, - ast::RecordField(it) => { - if let Some(record_lit) = it.syntax().ancestors().find_map(ast::RecordLit::cast) { - let variant_def = analyzer.resolve_record_literal(&record_lit)?; - let hir_path = Path::from_name_ref(name_ref); - let hir_name = hir_path.as_ident()?; - let field = variant_def.field(db, hir_name)?; - return Some(field.definition(db)); - } - }, - _ => (), + let analyzer = SourceAnalyzer::new(db, file_id, name_ref.syntax(), None); + + if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) { + let func = analyzer.resolve_method_call(&method_call)?; + return Some(from_assoc_item(db, func.into())); + } + + if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) { + if let Some(field) = analyzer.resolve_field(&field_expr) { + return Some(from_struct_field(db, field)); + } + } + + if let Some(record_field) = ast::RecordField::cast(parent.clone()) { + if let Some(record_lit) = record_field.syntax().ancestors().find_map(ast::RecordLit::cast) { + let variant_def = analyzer.resolve_record_literal(&record_lit)?; + let hir_path = Path::from_name_ref(name_ref); + let hir_name = hir_path.as_ident()?; + let field = variant_def.field(db, hir_name)?; + return Some(from_struct_field(db, field)); } } let ast = ModuleSource::from_child_node(db, file_id, &parent); let file_id = file_id.into(); + // FIXME: find correct container and visibility for each case let container = Module::from_definition(db, Source { file_id, ast })?; let visibility = None; if let Some(macro_call) = parent.parent().and_then(|node| node.parent()).and_then(ast::MacroCall::cast) { - if let Some(mac) = analyzer.resolve_macro_call(db, ¯o_call) { - return Some(Definition { item: NameKind::Macro(mac), container, visibility }); + if let Some(macro_def) = analyzer.resolve_macro_call(db, ¯o_call) { + return Some(NameDefinition { + item: NameKind::Macro(macro_def), + container, + visibility, + }); } } - // General case, a path or a local: let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?; let resolved = analyzer.resolve_path(db, &path)?; match resolved { - PathResolution::Def(def) => Some(def.definition(db)), - PathResolution::LocalBinding(Either::A(pat)) => decl_from_pat(db, file_id, pat), - PathResolution::LocalBinding(Either::B(par)) => { - Some(Definition { item: NameKind::SelfParam(par), container, visibility }) + Def(def) => Some(from_module_def(db, def)), + AssocItem(item) => Some(from_assoc_item(db, item)), + LocalBinding(Either::A(pat)) => from_pat(db, file_id, pat), + LocalBinding(Either::B(par)) => { + let item = NameKind::SelfParam(par); + Some(NameDefinition { item, container, visibility }) } - PathResolution::GenericParam(par) => { + GenericParam(par) => { // FIXME: get generic param def - Some(Definition { item: NameKind::GenericParam(par), container, visibility }) + let item = NameKind::GenericParam(par); + Some(NameDefinition { item, container, visibility }) } - PathResolution::Macro(def) => { - Some(Definition { item: NameKind::Macro(def), container, visibility }) + Macro(def) => { + let item = NameKind::Macro(def); + Some(NameDefinition { item, container, visibility }) } - PathResolution::SelfType(impl_block) => { + SelfType(impl_block) => { let ty = impl_block.target_ty(db); + let item = NameKind::SelfType(ty); let container = impl_block.module(); - Some(Definition { item: NameKind::SelfType(ty), container, visibility }) + Some(NameDefinition { item, container, visibility }) } - PathResolution::AssocItem(assoc) => Some(assoc.definition(db)), } } - -fn decl_from_pat( - db: &RootDatabase, - file_id: HirFileId, - pat: AstPtr, -) -> Option { - let root = db.parse_or_expand(file_id)?; - // FIXME: use match_ast! - let def = pat.to_node(&root).syntax().ancestors().find_map(|node| { - if let Some(it) = ast::FnDef::cast(node.clone()) { - let src = hir::Source { file_id, ast: it }; - Some(hir::Function::from_source(db, src)?.into()) - } else if let Some(it) = ast::ConstDef::cast(node.clone()) { - let src = hir::Source { file_id, ast: it }; - Some(hir::Const::from_source(db, src)?.into()) - } else if let Some(it) = ast::StaticDef::cast(node.clone()) { - let src = hir::Source { file_id, ast: it }; - Some(hir::Static::from_source(db, src)?.into()) - } else { - None - } - })?; - let item = NameKind::Pat((def, pat)); - let container = def.module(db); - Some(Definition { item, container, visibility: None }) -} diff --git a/crates/ra_ide_api/src/references/definition.rs b/crates/ra_ide_api/src/references/definition.rs deleted file mode 100644 index 65b1f8dd7..000000000 --- a/crates/ra_ide_api/src/references/definition.rs +++ /dev/null @@ -1,177 +0,0 @@ -use hir::{ - db::AstDatabase, Adt, AssocItem, DefWithBody, FromSource, HasSource, HirFileId, MacroDef, - Module, ModuleDef, SourceAnalyzer, StructField, Ty, VariantDef, -}; -use ra_syntax::{ast, ast::VisibilityOwner, AstNode, AstPtr}; - -use crate::db::RootDatabase; - -#[derive(Debug, PartialEq, Eq)] -pub enum NameKind { - Macro(MacroDef), - FieldAccess(StructField), - AssocItem(AssocItem), - Def(ModuleDef), - SelfType(Ty), - Pat((DefWithBody, AstPtr)), - SelfParam(AstPtr), - GenericParam(u32), -} - -#[derive(PartialEq, Eq)] -pub(crate) struct Definition { - pub visibility: Option, - pub container: Module, - pub item: NameKind, -} - -pub(super) trait HasDefinition { - type Def; - type Ref; - - fn definition(self, db: &RootDatabase) -> Definition; - fn from_def(db: &RootDatabase, file_id: HirFileId, def: Self::Def) -> Option; - fn from_ref( - db: &RootDatabase, - analyzer: &SourceAnalyzer, - refer: Self::Ref, - ) -> Option; -} - -// fn decl_from_pat( -// db: &RootDatabase, -// file_id: HirFileId, -// pat: AstPtr, -// ) -> Option { -// let root = db.parse_or_expand(file_id)?; -// // FIXME: use match_ast! -// let def = pat.to_node(&root).syntax().ancestors().find_map(|node| { -// if let Some(it) = ast::FnDef::cast(node.clone()) { -// let src = hir::Source { file_id, ast: it }; -// Some(hir::Function::from_source(db, src)?.into()) -// } else if let Some(it) = ast::ConstDef::cast(node.clone()) { -// let src = hir::Source { file_id, ast: it }; -// Some(hir::Const::from_source(db, src)?.into()) -// } else if let Some(it) = ast::StaticDef::cast(node.clone()) { -// let src = hir::Source { file_id, ast: it }; -// Some(hir::Static::from_source(db, src)?.into()) -// } else { -// None -// } -// })?; -// let item = NameKind::Pat((def, pat)); -// let container = def.module(db); -// Some(Definition { item, container, visibility: None }) -// } - -impl HasDefinition for StructField { - type Def = ast::RecordFieldDef; - type Ref = ast::FieldExpr; - - fn definition(self, db: &RootDatabase) -> Definition { - let item = NameKind::FieldAccess(self); - let parent = self.parent_def(db); - let container = parent.module(db); - let visibility = match parent { - VariantDef::Struct(s) => s.source(db).ast.visibility(), - VariantDef::EnumVariant(e) => e.source(db).ast.parent_enum().visibility(), - }; - Definition { item, container, visibility } - } - - fn from_def(db: &RootDatabase, file_id: HirFileId, def: Self::Def) -> Option { - let src = hir::Source { file_id, ast: hir::FieldSource::Named(def) }; - let field = StructField::from_source(db, src)?; - Some(field.definition(db)) - } - - fn from_ref( - db: &RootDatabase, - analyzer: &SourceAnalyzer, - refer: Self::Ref, - ) -> Option { - let field = analyzer.resolve_field(&refer)?; - Some(field.definition(db)) - } -} - -impl HasDefinition for AssocItem { - type Def = ast::ImplItem; - type Ref = ast::MethodCallExpr; - - fn definition(self, db: &RootDatabase) -> Definition { - let item = NameKind::AssocItem(self); - let container = self.module(db); - let visibility = match self { - AssocItem::Function(f) => f.source(db).ast.visibility(), - AssocItem::Const(c) => c.source(db).ast.visibility(), - AssocItem::TypeAlias(a) => a.source(db).ast.visibility(), - }; - Definition { item, container, visibility } - } - - fn from_def(db: &RootDatabase, file_id: HirFileId, def: Self::Def) -> Option { - if def.syntax().parent().and_then(ast::ItemList::cast).is_none() { - return None; - } - let src = hir::Source { file_id, ast: def }; - let item = AssocItem::from_source(db, src)?; - Some(item.definition(db)) - } - - fn from_ref( - db: &RootDatabase, - analyzer: &SourceAnalyzer, - refer: Self::Ref, - ) -> Option { - let func: AssocItem = analyzer.resolve_method_call(&refer)?.into(); - Some(func.definition(db)) - } -} - -impl HasDefinition for ModuleDef { - type Def = ast::ModuleItem; - type Ref = ast::Path; - - fn definition(self, db: &RootDatabase) -> Definition { - let (container, visibility) = match self { - ModuleDef::Module(it) => { - let container = it.parent(db).or_else(|| Some(it)).unwrap(); - let visibility = it.declaration_source(db).and_then(|s| s.ast.visibility()); - (container, visibility) - } - ModuleDef::EnumVariant(it) => { - let container = it.module(db); - let visibility = it.source(db).ast.parent_enum().visibility(); - (container, visibility) - } - ModuleDef::Function(it) => (it.module(db), it.source(db).ast.visibility()), - ModuleDef::Const(it) => (it.module(db), it.source(db).ast.visibility()), - ModuleDef::Static(it) => (it.module(db), it.source(db).ast.visibility()), - ModuleDef::Trait(it) => (it.module(db), it.source(db).ast.visibility()), - ModuleDef::TypeAlias(it) => (it.module(db), it.source(db).ast.visibility()), - ModuleDef::Adt(Adt::Struct(it)) => (it.module(db), it.source(db).ast.visibility()), - ModuleDef::Adt(Adt::Union(it)) => (it.module(db), it.source(db).ast.visibility()), - ModuleDef::Adt(Adt::Enum(it)) => (it.module(db), it.source(db).ast.visibility()), - ModuleDef::BuiltinType(..) => unreachable!(), - }; - let item = NameKind::Def(self); - Definition { item, container, visibility } - } - - fn from_def(db: &RootDatabase, file_id: HirFileId, def: Self::Def) -> Option { - let src = hir::Source { file_id, ast: def }; - let def = ModuleDef::from_source(db, src)?; - Some(def.definition(db)) - } - - fn from_ref( - db: &RootDatabase, - analyzer: &SourceAnalyzer, - refer: Self::Ref, - ) -> Option { - None - } -} - -// FIXME: impl HasDefinition for hir::MacroDef diff --git a/crates/ra_ide_api/src/references/name_definition.rs b/crates/ra_ide_api/src/references/name_definition.rs new file mode 100644 index 000000000..19702eba0 --- /dev/null +++ b/crates/ra_ide_api/src/references/name_definition.rs @@ -0,0 +1,104 @@ +use hir::{ + db::AstDatabase, Adt, AssocItem, DefWithBody, FromSource, HasSource, HirFileId, MacroDef, + Module, ModuleDef, StructField, Ty, VariantDef, +}; +use ra_syntax::{ast, ast::VisibilityOwner, match_ast, AstNode, AstPtr}; + +use crate::db::RootDatabase; + +#[derive(Debug, PartialEq, Eq)] +pub enum NameKind { + Macro(MacroDef), + Field(StructField), + AssocItem(AssocItem), + Def(ModuleDef), + SelfType(Ty), + Pat((DefWithBody, AstPtr)), + SelfParam(AstPtr), + GenericParam(u32), +} + +#[derive(PartialEq, Eq)] +pub(crate) struct NameDefinition { + pub visibility: Option, + pub container: Module, + pub item: NameKind, +} + +pub(super) fn from_pat( + db: &RootDatabase, + file_id: HirFileId, + pat: AstPtr, +) -> Option { + let root = db.parse_or_expand(file_id)?; + let def = pat.to_node(&root).syntax().ancestors().find_map(|node| { + match_ast! { + match node { + ast::FnDef(it) => { + let src = hir::Source { file_id, ast: it }; + Some(hir::Function::from_source(db, src)?.into()) + }, + ast::ConstDef(it) => { + let src = hir::Source { file_id, ast: it }; + Some(hir::Const::from_source(db, src)?.into()) + }, + ast::StaticDef(it) => { + let src = hir::Source { file_id, ast: it }; + Some(hir::Static::from_source(db, src)?.into()) + }, + _ => None, + } + } + })?; + let item = NameKind::Pat((def, pat)); + let container = def.module(db); + Some(NameDefinition { item, container, visibility: None }) +} + +pub(super) fn from_assoc_item(db: &RootDatabase, item: AssocItem) -> NameDefinition { + let container = item.module(db); + let visibility = match item { + AssocItem::Function(f) => f.source(db).ast.visibility(), + AssocItem::Const(c) => c.source(db).ast.visibility(), + AssocItem::TypeAlias(a) => a.source(db).ast.visibility(), + }; + let item = NameKind::AssocItem(item); + NameDefinition { item, container, visibility } +} + +pub(super) fn from_struct_field(db: &RootDatabase, field: StructField) -> NameDefinition { + let item = NameKind::Field(field); + let parent = field.parent_def(db); + let container = parent.module(db); + let visibility = match parent { + VariantDef::Struct(s) => s.source(db).ast.visibility(), + VariantDef::EnumVariant(e) => e.source(db).ast.parent_enum().visibility(), + }; + NameDefinition { item, container, visibility } +} + +pub(super) fn from_module_def(db: &RootDatabase, def: ModuleDef) -> NameDefinition { + let item = NameKind::Def(def); + let (container, visibility) = match def { + ModuleDef::Module(it) => { + let container = it.parent(db).or_else(|| Some(it)).unwrap(); + let visibility = it.declaration_source(db).and_then(|s| s.ast.visibility()); + (container, visibility) + } + ModuleDef::EnumVariant(it) => { + let container = it.module(db); + let visibility = it.source(db).ast.parent_enum().visibility(); + (container, visibility) + } + ModuleDef::Function(it) => (it.module(db), it.source(db).ast.visibility()), + ModuleDef::Const(it) => (it.module(db), it.source(db).ast.visibility()), + ModuleDef::Static(it) => (it.module(db), it.source(db).ast.visibility()), + ModuleDef::Trait(it) => (it.module(db), it.source(db).ast.visibility()), + ModuleDef::TypeAlias(it) => (it.module(db), it.source(db).ast.visibility()), + ModuleDef::Adt(Adt::Struct(it)) => (it.module(db), it.source(db).ast.visibility()), + ModuleDef::Adt(Adt::Union(it)) => (it.module(db), it.source(db).ast.visibility()), + ModuleDef::Adt(Adt::Enum(it)) => (it.module(db), it.source(db).ast.visibility()), + ModuleDef::BuiltinType(..) => unreachable!(), + }; + NameDefinition { item, container, visibility } +} diff --git a/crates/ra_ide_api/src/references/search_scope.rs b/crates/ra_ide_api/src/references/search_scope.rs index 557ee7b57..346815d31 100644 --- a/crates/ra_ide_api/src/references/search_scope.rs +++ b/crates/ra_ide_api/src/references/search_scope.rs @@ -4,13 +4,13 @@ use ra_syntax::{AstNode, TextRange}; use crate::db::RootDatabase; -use super::{Definition, NameKind}; +use super::{NameDefinition, NameKind}; pub(crate) struct SearchScope { pub scope: Vec<(FileId, Option)>, } -impl Definition { +impl NameDefinition { pub fn scope(&self, db: &RootDatabase) -> SearchScope { let module_src = self.container.definition_source(db); let file_id = module_src.file_id.original_file(db); diff --git a/crates/ra_ide_api/src/syntax_highlighting.rs b/crates/ra_ide_api/src/syntax_highlighting.rs index 28c50102e..a27d9f367 100644 --- a/crates/ra_ide_api/src/syntax_highlighting.rs +++ b/crates/ra_ide_api/src/syntax_highlighting.rs @@ -105,7 +105,7 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec "macro", - Some(FieldAccess(_)) => "field", + Some(Field(_)) => "field", Some(AssocItem(hir::AssocItem::Function(_))) => "function", Some(AssocItem(hir::AssocItem::Const(_))) => "constant", Some(AssocItem(hir::AssocItem::TypeAlias(_))) => "type", -- cgit v1.2.3 From 19fbf2c16b5c1f39e23c720a2655cfdb49c25135 Mon Sep 17 00:00:00 2001 From: Ekaterina Babshukova Date: Sat, 12 Oct 2019 20:40:49 +0300 Subject: remove `unreachable!()` --- crates/ra_ide_api/src/goto_definition.rs | 2 +- crates/ra_ide_api/src/references/classify.rs | 20 ++++++++++---------- crates/ra_ide_api/src/references/name_definition.rs | 8 ++++++-- crates/ra_ide_api/src/syntax_highlighting.rs | 3 +-- 4 files changed, 18 insertions(+), 15 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index 1b4ad3a59..582617286 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs @@ -54,7 +54,7 @@ pub(crate) fn reference_definition( ) -> ReferenceResult { use self::ReferenceResult::*; - let name_kind = classify_name_ref(db, file_id, &name_ref).and_then(|d| Some(d.item)); + let name_kind = classify_name_ref(db, file_id, &name_ref).map(|d| d.item); match name_kind { Some(Macro(mac)) => return Exact(NavigationTarget::from_macro_def(db, mac)), Some(Field(field)) => return Exact(NavigationTarget::from_field(db, field)), diff --git a/crates/ra_ide_api/src/references/classify.rs b/crates/ra_ide_api/src/references/classify.rs index 2ba1cf71c..5cb194c0e 100644 --- a/crates/ra_ide_api/src/references/classify.rs +++ b/crates/ra_ide_api/src/references/classify.rs @@ -32,32 +32,32 @@ pub(crate) fn classify_name( let ast = hir::ModuleSource::Module(it); let src = hir::Source { file_id, ast }; let def = hir::Module::from_definition(db, src)?; - Some(from_module_def(db, def.into())) + Some(from_module_def(db, def.into(), None)) }, ast::StructDef(it) => { let src = hir::Source { file_id, ast: it }; let def = hir::Struct::from_source(db, src)?; - Some(from_module_def(db, def.into())) + Some(from_module_def(db, def.into(), None)) }, ast::EnumDef(it) => { let src = hir::Source { file_id, ast: it }; let def = hir::Enum::from_source(db, src)?; - Some(from_module_def(db, def.into())) + Some(from_module_def(db, def.into(), None)) }, ast::TraitDef(it) => { let src = hir::Source { file_id, ast: it }; let def = hir::Trait::from_source(db, src)?; - Some(from_module_def(db, def.into())) + Some(from_module_def(db, def.into(), None)) }, ast::StaticDef(it) => { let src = hir::Source { file_id, ast: it }; let def = hir::Static::from_source(db, src)?; - Some(from_module_def(db, def.into())) + Some(from_module_def(db, def.into(), None)) }, ast::EnumVariant(it) => { let src = hir::Source { file_id, ast: it }; let def = hir::EnumVariant::from_source(db, src)?; - Some(from_module_def(db, def.into())) + Some(from_module_def(db, def.into(), None)) }, ast::FnDef(it) => { let src = hir::Source { file_id, ast: it }; @@ -65,7 +65,7 @@ pub(crate) fn classify_name( if parent.parent().and_then(ast::ItemList::cast).is_some() { Some(from_assoc_item(db, def.into())) } else { - Some(from_module_def(db, def.into())) + Some(from_module_def(db, def.into(), None)) } }, ast::ConstDef(it) => { @@ -74,7 +74,7 @@ pub(crate) fn classify_name( if parent.parent().and_then(ast::ItemList::cast).is_some() { Some(from_assoc_item(db, def.into())) } else { - Some(from_module_def(db, def.into())) + Some(from_module_def(db, def.into(), None)) } }, ast::TypeAliasDef(it) => { @@ -83,7 +83,7 @@ pub(crate) fn classify_name( if parent.parent().and_then(ast::ItemList::cast).is_some() { Some(from_assoc_item(db, def.into())) } else { - Some(from_module_def(db, def.into())) + Some(from_module_def(db, def.into(), None)) } }, _ => None, @@ -143,7 +143,7 @@ pub(crate) fn classify_name_ref( let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?; let resolved = analyzer.resolve_path(db, &path)?; match resolved { - Def(def) => Some(from_module_def(db, def)), + Def(def) => Some(from_module_def(db, def, Some(container))), AssocItem(item) => Some(from_assoc_item(db, item)), LocalBinding(Either::A(pat)) => from_pat(db, file_id, pat), LocalBinding(Either::B(par)) => { diff --git a/crates/ra_ide_api/src/references/name_definition.rs b/crates/ra_ide_api/src/references/name_definition.rs index 19702eba0..58baf3686 100644 --- a/crates/ra_ide_api/src/references/name_definition.rs +++ b/crates/ra_ide_api/src/references/name_definition.rs @@ -77,7 +77,11 @@ pub(super) fn from_struct_field(db: &RootDatabase, field: StructField) -> NameDe NameDefinition { item, container, visibility } } -pub(super) fn from_module_def(db: &RootDatabase, def: ModuleDef) -> NameDefinition { +pub(super) fn from_module_def( + db: &RootDatabase, + def: ModuleDef, + module: Option, +) -> NameDefinition { let item = NameKind::Def(def); let (container, visibility) = match def { ModuleDef::Module(it) => { @@ -98,7 +102,7 @@ pub(super) fn from_module_def(db: &RootDatabase, def: ModuleDef) -> NameDefiniti ModuleDef::Adt(Adt::Struct(it)) => (it.module(db), it.source(db).ast.visibility()), ModuleDef::Adt(Adt::Union(it)) => (it.module(db), it.source(db).ast.visibility()), ModuleDef::Adt(Adt::Enum(it)) => (it.module(db), it.source(db).ast.visibility()), - ModuleDef::BuiltinType(..) => unreachable!(), + ModuleDef::BuiltinType(..) => (module.unwrap(), None), }; NameDefinition { item, container, visibility } } diff --git a/crates/ra_ide_api/src/syntax_highlighting.rs b/crates/ra_ide_api/src/syntax_highlighting.rs index a27d9f367..9254327f6 100644 --- a/crates/ra_ide_api/src/syntax_highlighting.rs +++ b/crates/ra_ide_api/src/syntax_highlighting.rs @@ -101,8 +101,7 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec "macro", Some(Field(_)) => "field", -- cgit v1.2.3 From 88ff88d3189de9dd9b0d88bdda3da769254c2b8e Mon Sep 17 00:00:00 2001 From: Ekaterina Babshukova Date: Mon, 14 Oct 2019 14:59:02 +0300 Subject: use Lazy, some fixes --- crates/ra_ide_api/Cargo.toml | 1 + crates/ra_ide_api/src/goto_definition.rs | 2 +- crates/ra_ide_api/src/hover.rs | 3 +- crates/ra_ide_api/src/references.rs | 13 +++++---- crates/ra_ide_api/src/references/classify.rs | 34 ++++++++++------------ .../ra_ide_api/src/references/name_definition.rs | 20 +++++++------ crates/ra_ide_api/src/references/rename.rs | 2 ++ crates/ra_ide_api/src/references/search_scope.rs | 16 +++++----- crates/ra_ide_api/src/syntax_highlighting.rs | 2 +- 9 files changed, 50 insertions(+), 43 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide_api/Cargo.toml b/crates/ra_ide_api/Cargo.toml index 73f39b647..f9bf0c686 100644 --- a/crates/ra_ide_api/Cargo.toml +++ b/crates/ra_ide_api/Cargo.toml @@ -19,6 +19,7 @@ rustc-hash = "1.0" unicase = "2.2.0" superslice = "1.0.0" rand = { version = "0.7.0", features = ["small_rng"] } +once_cell = "1.2.0" ra_syntax = { path = "../ra_syntax" } ra_text_edit = { path = "../ra_text_edit" } diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index 582617286..d14908b25 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs @@ -54,7 +54,7 @@ pub(crate) fn reference_definition( ) -> ReferenceResult { use self::ReferenceResult::*; - let name_kind = classify_name_ref(db, file_id, &name_ref).map(|d| d.item); + let name_kind = classify_name_ref(db, file_id, &name_ref).map(|d| d.kind); match name_kind { Some(Macro(mac)) => return Exact(NavigationTarget::from_macro_def(db, mac)), Some(Field(field)) => return Exact(NavigationTarget::from_field(db, field)), diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs index 318708df3..ba328efa1 100644 --- a/crates/ra_ide_api/src/hover.rs +++ b/crates/ra_ide_api/src/hover.rs @@ -100,8 +100,7 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option(file.syntax(), position.offset) { let mut no_fallback = false; - let name_kind = - classify_name_ref(db, position.file_id, &name_ref).and_then(|d| Some(d.item)); + let name_kind = classify_name_ref(db, position.file_id, &name_ref).map(|d| d.kind); match name_kind { Some(Macro(it)) => { let src = it.source(db); diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs index 3761fd6e7..3d282d48a 100644 --- a/crates/ra_ide_api/src/references.rs +++ b/crates/ra_ide_api/src/references.rs @@ -5,6 +5,7 @@ mod name_definition; mod rename; mod search_scope; +use once_cell::unsync::Lazy; use ra_db::{SourceDatabase, SourceDatabaseExt}; use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SourceFile, SyntaxNode, TextUnit}; @@ -61,7 +62,7 @@ pub(crate) fn find_all_refs( let syntax = parse.tree().syntax().clone(); let RangeInfo { range, info: (name, def) } = find_name(db, &syntax, position)?; - let declaration = match def.item { + let declaration = match def.kind { NameKind::Macro(mac) => NavigationTarget::from_macro_def(db, mac), NameKind::Field(field) => NavigationTarget::from_field(db, field), NameKind::AssocItem(assoc) => NavigationTarget::from_assoc_item(db, assoc), @@ -98,7 +99,7 @@ fn find_name<'a>( fn process_definition(db: &RootDatabase, def: NameDefinition, name: String) -> Vec { let pat = name.as_str(); - let scope = def.scope(db).scope; + let scope = def.scope(db).files; let mut refs = vec![]; let is_match = |file_id: FileId, name_ref: &ast::NameRef| -> bool { @@ -112,12 +113,14 @@ fn process_definition(db: &RootDatabase, def: NameDefinition, name: String) -> V 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(); + let parse = Lazy::new(|| SourceFile::parse(&text)); for (idx, _) in text.match_indices(pat) { let offset = TextUnit::from_usize(idx); - if let Some(name_ref) = find_node_at_offset::(&syntax, offset) { + + if let Some(name_ref) = + find_node_at_offset::(parse.tree().syntax(), offset) + { let range = name_ref.syntax().text_range(); if let Some(text_range) = text_range { diff --git a/crates/ra_ide_api/src/references/classify.rs b/crates/ra_ide_api/src/references/classify.rs index 5cb194c0e..93e079ccc 100644 --- a/crates/ra_ide_api/src/references/classify.rs +++ b/crates/ra_ide_api/src/references/classify.rs @@ -1,3 +1,5 @@ +//! FIXME: write short doc here + use hir::{Either, FromSource, Module, ModuleSource, Path, PathResolution, Source, SourceAnalyzer}; use ra_db::FileId; use ra_syntax::{ast, match_ast, AstNode, AstPtr}; @@ -102,8 +104,9 @@ pub(crate) fn classify_name_ref( let analyzer = SourceAnalyzer::new(db, file_id, name_ref.syntax(), None); if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) { - let func = analyzer.resolve_method_call(&method_call)?; - return Some(from_assoc_item(db, func.into())); + if let Some(func) = analyzer.resolve_method_call(&method_call) { + return Some(from_assoc_item(db, func.into())); + } } if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) { @@ -128,15 +131,10 @@ pub(crate) fn classify_name_ref( let container = Module::from_definition(db, Source { file_id, ast })?; let visibility = None; - if let Some(macro_call) = - parent.parent().and_then(|node| node.parent()).and_then(ast::MacroCall::cast) - { + if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) { if let Some(macro_def) = analyzer.resolve_macro_call(db, ¯o_call) { - return Some(NameDefinition { - item: NameKind::Macro(macro_def), - container, - visibility, - }); + let kind = NameKind::Macro(macro_def); + return Some(NameDefinition { kind, container, visibility }); } } @@ -147,23 +145,23 @@ pub(crate) fn classify_name_ref( AssocItem(item) => Some(from_assoc_item(db, item)), LocalBinding(Either::A(pat)) => from_pat(db, file_id, pat), LocalBinding(Either::B(par)) => { - let item = NameKind::SelfParam(par); - Some(NameDefinition { item, container, visibility }) + let kind = NameKind::SelfParam(par); + Some(NameDefinition { kind, container, visibility }) } GenericParam(par) => { // FIXME: get generic param def - let item = NameKind::GenericParam(par); - Some(NameDefinition { item, container, visibility }) + let kind = NameKind::GenericParam(par); + Some(NameDefinition { kind, container, visibility }) } Macro(def) => { - let item = NameKind::Macro(def); - Some(NameDefinition { item, container, visibility }) + let kind = NameKind::Macro(def); + Some(NameDefinition { kind, container, visibility }) } SelfType(impl_block) => { let ty = impl_block.target_ty(db); - let item = NameKind::SelfType(ty); + let kind = NameKind::SelfType(ty); let container = impl_block.module(); - Some(NameDefinition { item, container, visibility }) + Some(NameDefinition { kind, container, visibility }) } } } diff --git a/crates/ra_ide_api/src/references/name_definition.rs b/crates/ra_ide_api/src/references/name_definition.rs index 58baf3686..723d97237 100644 --- a/crates/ra_ide_api/src/references/name_definition.rs +++ b/crates/ra_ide_api/src/references/name_definition.rs @@ -1,3 +1,5 @@ +//! FIXME: write short doc here + use hir::{ db::AstDatabase, Adt, AssocItem, DefWithBody, FromSource, HasSource, HirFileId, MacroDef, Module, ModuleDef, StructField, Ty, VariantDef, @@ -22,7 +24,7 @@ pub enum NameKind { pub(crate) struct NameDefinition { pub visibility: Option, pub container: Module, - pub item: NameKind, + pub kind: NameKind, } pub(super) fn from_pat( @@ -50,9 +52,9 @@ pub(super) fn from_pat( } } })?; - let item = NameKind::Pat((def, pat)); + let kind = NameKind::Pat((def, pat)); let container = def.module(db); - Some(NameDefinition { item, container, visibility: None }) + Some(NameDefinition { kind, container, visibility: None }) } pub(super) fn from_assoc_item(db: &RootDatabase, item: AssocItem) -> NameDefinition { @@ -62,19 +64,19 @@ pub(super) fn from_assoc_item(db: &RootDatabase, item: AssocItem) -> NameDefinit AssocItem::Const(c) => c.source(db).ast.visibility(), AssocItem::TypeAlias(a) => a.source(db).ast.visibility(), }; - let item = NameKind::AssocItem(item); - NameDefinition { item, container, visibility } + let kind = NameKind::AssocItem(item); + NameDefinition { kind, container, visibility } } pub(super) fn from_struct_field(db: &RootDatabase, field: StructField) -> NameDefinition { - let item = NameKind::Field(field); + let kind = NameKind::Field(field); let parent = field.parent_def(db); let container = parent.module(db); let visibility = match parent { VariantDef::Struct(s) => s.source(db).ast.visibility(), VariantDef::EnumVariant(e) => e.source(db).ast.parent_enum().visibility(), }; - NameDefinition { item, container, visibility } + NameDefinition { kind, container, visibility } } pub(super) fn from_module_def( @@ -82,7 +84,7 @@ pub(super) fn from_module_def( def: ModuleDef, module: Option, ) -> NameDefinition { - let item = NameKind::Def(def); + let kind = NameKind::Def(def); let (container, visibility) = match def { ModuleDef::Module(it) => { let container = it.parent(db).or_else(|| Some(it)).unwrap(); @@ -104,5 +106,5 @@ pub(super) fn from_module_def( ModuleDef::Adt(Adt::Enum(it)) => (it.module(db), it.source(db).ast.visibility()), ModuleDef::BuiltinType(..) => (module.unwrap(), None), }; - NameDefinition { item, container, visibility } + NameDefinition { kind, container, visibility } } diff --git a/crates/ra_ide_api/src/references/rename.rs b/crates/ra_ide_api/src/references/rename.rs index 7e564a40e..c91dada46 100644 --- a/crates/ra_ide_api/src/references/rename.rs +++ b/crates/ra_ide_api/src/references/rename.rs @@ -1,3 +1,5 @@ +//! FIXME: write short doc here + use hir::ModuleSource; use ra_db::SourceDatabase; use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SyntaxNode}; diff --git a/crates/ra_ide_api/src/references/search_scope.rs b/crates/ra_ide_api/src/references/search_scope.rs index 346815d31..aae9db13b 100644 --- a/crates/ra_ide_api/src/references/search_scope.rs +++ b/crates/ra_ide_api/src/references/search_scope.rs @@ -1,3 +1,5 @@ +//! FIXME: write short doc here + use hir::{DefWithBody, HasSource, ModuleSource}; use ra_db::{FileId, SourceDatabase}; use ra_syntax::{AstNode, TextRange}; @@ -7,21 +9,21 @@ use crate::db::RootDatabase; use super::{NameDefinition, NameKind}; pub(crate) struct SearchScope { - pub scope: Vec<(FileId, Option)>, + pub files: Vec<(FileId, Option)>, } impl NameDefinition { - pub fn scope(&self, db: &RootDatabase) -> SearchScope { + pub(crate) fn scope(&self, db: &RootDatabase) -> SearchScope { let module_src = self.container.definition_source(db); let file_id = module_src.file_id.original_file(db); - if let NameKind::Pat((def, _)) = self.item { + if let NameKind::Pat((def, _)) = self.kind { let range = match def { DefWithBody::Function(f) => f.source(db).ast.syntax().text_range(), DefWithBody::Const(c) => c.source(db).ast.syntax().text_range(), DefWithBody::Static(s) => s.source(db).ast.syntax().text_range(), }; - return SearchScope { scope: vec![(file_id, Some(range))] }; + return SearchScope { files: vec![(file_id, Some(range))] }; } if let Some(ref vis) = self.visibility { @@ -30,7 +32,7 @@ impl NameDefinition { let mut files = source_root.walk().map(|id| (id.into(), None)).collect::>(); if vis.syntax().to_string().as_str() == "pub(crate)" { - return SearchScope { scope: files }; + return SearchScope { files }; } if vis.syntax().to_string().as_str() == "pub" { let krate = self.container.krate(db).unwrap(); @@ -47,7 +49,7 @@ impl NameDefinition { } } - return SearchScope { scope: files }; + return SearchScope { files }; } // FIXME: "pub(super)", "pub(in path)" } @@ -56,6 +58,6 @@ impl NameDefinition { ModuleSource::Module(m) => Some(m.syntax().text_range()), ModuleSource::SourceFile(_) => None, }; - SearchScope { scope: vec![(file_id, range)] } + SearchScope { files: vec![(file_id, range)] } } } diff --git a/crates/ra_ide_api/src/syntax_highlighting.rs b/crates/ra_ide_api/src/syntax_highlighting.rs index 9254327f6..33f3caceb 100644 --- a/crates/ra_ide_api/src/syntax_highlighting.rs +++ b/crates/ra_ide_api/src/syntax_highlighting.rs @@ -101,7 +101,7 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec "macro", Some(Field(_)) => "field", -- cgit v1.2.3 From 328be5721ad0d53d6d296fec08fbcc569634ecf7 Mon Sep 17 00:00:00 2001 From: Ekaterina Babshukova Date: Mon, 14 Oct 2019 15:49:32 +0300 Subject: remove SearchScope --- crates/ra_ide_api/src/references.rs | 2 +- crates/ra_ide_api/src/references/search_scope.rs | 14 +++++--------- 2 files changed, 6 insertions(+), 10 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs index 3d282d48a..0f1ac57fc 100644 --- a/crates/ra_ide_api/src/references.rs +++ b/crates/ra_ide_api/src/references.rs @@ -99,7 +99,7 @@ fn find_name<'a>( fn process_definition(db: &RootDatabase, def: NameDefinition, name: String) -> Vec { let pat = name.as_str(); - let scope = def.scope(db).files; + let scope = def.search_scope(db); let mut refs = vec![]; let is_match = |file_id: FileId, name_ref: &ast::NameRef| -> bool { diff --git a/crates/ra_ide_api/src/references/search_scope.rs b/crates/ra_ide_api/src/references/search_scope.rs index aae9db13b..dfea18a19 100644 --- a/crates/ra_ide_api/src/references/search_scope.rs +++ b/crates/ra_ide_api/src/references/search_scope.rs @@ -8,12 +8,8 @@ use crate::db::RootDatabase; use super::{NameDefinition, NameKind}; -pub(crate) struct SearchScope { - pub files: Vec<(FileId, Option)>, -} - impl NameDefinition { - pub(crate) fn scope(&self, db: &RootDatabase) -> SearchScope { + pub(crate) fn search_scope(&self, db: &RootDatabase) -> Vec<(FileId, Option)> { let module_src = self.container.definition_source(db); let file_id = module_src.file_id.original_file(db); @@ -23,7 +19,7 @@ impl NameDefinition { DefWithBody::Const(c) => c.source(db).ast.syntax().text_range(), DefWithBody::Static(s) => s.source(db).ast.syntax().text_range(), }; - return SearchScope { files: vec![(file_id, Some(range))] }; + return vec![(file_id, Some(range))]; } if let Some(ref vis) = self.visibility { @@ -32,7 +28,7 @@ impl NameDefinition { let mut files = source_root.walk().map(|id| (id.into(), None)).collect::>(); if vis.syntax().to_string().as_str() == "pub(crate)" { - return SearchScope { files }; + return files; } if vis.syntax().to_string().as_str() == "pub" { let krate = self.container.krate(db).unwrap(); @@ -49,7 +45,7 @@ impl NameDefinition { } } - return SearchScope { files }; + return files; } // FIXME: "pub(super)", "pub(in path)" } @@ -58,6 +54,6 @@ impl NameDefinition { ModuleSource::Module(m) => Some(m.syntax().text_range()), ModuleSource::SourceFile(_) => None, }; - SearchScope { files: vec![(file_id, range)] } + vec![(file_id, range)] } } -- cgit v1.2.3 From 93c179531b31786bfd50644b5f0c879afc798f7d Mon Sep 17 00:00:00 2001 From: Ekaterina Babshukova Date: Tue, 15 Oct 2019 19:25:57 +0300 Subject: fix highlighting --- crates/ra_ide_api/src/references/rename.rs | 2 +- crates/ra_ide_api/src/references/search_scope.rs | 2 +- crates/ra_lsp_server/src/main_loop/handlers.rs | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide_api/src/references/rename.rs b/crates/ra_ide_api/src/references/rename.rs index c91dada46..0e2e088e0 100644 --- a/crates/ra_ide_api/src/references/rename.rs +++ b/crates/ra_ide_api/src/references/rename.rs @@ -1,7 +1,7 @@ //! FIXME: write short doc here use hir::ModuleSource; -use ra_db::SourceDatabase; +use ra_db::{SourceDatabase, SourceDatabaseExt}; use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SyntaxNode}; use relative_path::{RelativePath, RelativePathBuf}; diff --git a/crates/ra_ide_api/src/references/search_scope.rs b/crates/ra_ide_api/src/references/search_scope.rs index dfea18a19..680988a21 100644 --- a/crates/ra_ide_api/src/references/search_scope.rs +++ b/crates/ra_ide_api/src/references/search_scope.rs @@ -1,7 +1,7 @@ //! FIXME: write short doc here use hir::{DefWithBody, HasSource, ModuleSource}; -use ra_db::{FileId, SourceDatabase}; +use ra_db::{FileId, SourceDatabase, SourceDatabaseExt}; use ra_syntax::{AstNode, TextRange}; use crate::db::RootDatabase; diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index e08e0dbae..307082865 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs @@ -751,6 +751,7 @@ pub fn handle_document_highlight( Ok(Some( refs.into_iter() + .filter(|r| r.file_id == file_id) .map(|r| DocumentHighlight { range: r.range.conv_with(&line_index), kind: None }) .collect(), )) -- cgit v1.2.3 From 55e1910d006da7961687928542c1167cc556a39f Mon Sep 17 00:00:00 2001 From: Ekaterina Babshukova Date: Tue, 15 Oct 2019 22:50:28 +0300 Subject: classify module from declaration --- crates/ra_hir/src/from_source.rs | 1 - crates/ra_ide_api/src/references.rs | 29 +++++++++++++++++++++++- crates/ra_ide_api/src/references/classify.rs | 13 ++++++++--- crates/ra_ide_api/src/references/search_scope.rs | 10 ++++---- 4 files changed, 44 insertions(+), 9 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs index f80d8eb5f..a137aeb90 100644 --- a/crates/ra_hir/src/from_source.rs +++ b/crates/ra_hir/src/from_source.rs @@ -181,7 +181,6 @@ impl Module { ) -> Option { let decl_id = match src.ast { ModuleSource::Module(ref module) => { - assert!(!module.has_semi()); let ast_id_map = db.ast_id_map(src.file_id); let item_id = ast_id_map.ast_id(module).with_file_id(src.file_id); Some(item_id) diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs index 0f1ac57fc..3d647d2cb 100644 --- a/crates/ra_ide_api/src/references.rs +++ b/crates/ra_ide_api/src/references.rs @@ -232,7 +232,7 @@ mod tests { } #[test] - fn test_find_all_refs_modules() { + fn test_find_all_refs_two_modules() { let code = r#" //- /lib.rs pub mod foo; @@ -270,6 +270,33 @@ mod tests { assert_eq!(refs.len(), 3); } + + // `mod foo;` is not in the results because `foo` is an `ast::Name`. + // So, there are two references: the first one is a definition of the `foo` module, + // which is the whole `foo.rs`, and the second one is in `use foo::Foo`. + #[test] + fn test_find_all_refs_decl_module() { + let code = r#" + //- /lib.rs + mod foo<|>; + + use foo::Foo; + + fn f() { + let i = Foo { n: 5 }; + } + + //- /foo.rs + pub struct Foo { + pub n: u32, + } + "#; + + let (analysis, pos) = analysis_and_position(code); + let refs = analysis.find_all_refs(pos).unwrap().unwrap(); + assert_eq!(refs.len(), 2); + } + fn get_all_refs(text: &str) -> ReferenceSearchResult { let (analysis, position) = single_file_with_position(text); analysis.find_all_refs(position).unwrap().unwrap() diff --git a/crates/ra_ide_api/src/references/classify.rs b/crates/ra_ide_api/src/references/classify.rs index 93e079ccc..ac9cf34eb 100644 --- a/crates/ra_ide_api/src/references/classify.rs +++ b/crates/ra_ide_api/src/references/classify.rs @@ -31,9 +31,16 @@ pub(crate) fn classify_name( Some(from_struct_field(db, field)) }, ast::Module(it) => { - let ast = hir::ModuleSource::Module(it); - let src = hir::Source { file_id, ast }; - let def = hir::Module::from_definition(db, src)?; + let def = { + if !it.has_semi() { + let ast = hir::ModuleSource::Module(it); + let src = hir::Source { file_id, ast }; + hir::Module::from_definition(db, src) + } else { + let src = hir::Source { file_id, ast: it }; + hir::Module::from_declaration(db, src) + } + }?; Some(from_module_def(db, def.into(), None)) }, ast::StructDef(it) => { diff --git a/crates/ra_ide_api/src/references/search_scope.rs b/crates/ra_ide_api/src/references/search_scope.rs index 680988a21..d2c966b4f 100644 --- a/crates/ra_ide_api/src/references/search_scope.rs +++ b/crates/ra_ide_api/src/references/search_scope.rs @@ -1,5 +1,7 @@ //! FIXME: write short doc here +use std::collections::HashSet; + use hir::{DefWithBody, HasSource, ModuleSource}; use ra_db::{FileId, SourceDatabase, SourceDatabaseExt}; use ra_syntax::{AstNode, TextRange}; @@ -9,7 +11,7 @@ use crate::db::RootDatabase; use super::{NameDefinition, NameKind}; impl NameDefinition { - pub(crate) fn search_scope(&self, db: &RootDatabase) -> Vec<(FileId, Option)> { + pub(crate) fn search_scope(&self, db: &RootDatabase) -> HashSet<(FileId, Option)> { let module_src = self.container.definition_source(db); let file_id = module_src.file_id.original_file(db); @@ -19,13 +21,13 @@ impl NameDefinition { DefWithBody::Const(c) => c.source(db).ast.syntax().text_range(), DefWithBody::Static(s) => s.source(db).ast.syntax().text_range(), }; - return vec![(file_id, Some(range))]; + return [(file_id, Some(range))].iter().cloned().collect(); } if let Some(ref vis) = self.visibility { let source_root_id = db.file_source_root(file_id); let source_root = db.source_root(source_root_id); - let mut files = source_root.walk().map(|id| (id.into(), None)).collect::>(); + let mut files = source_root.walk().map(|id| (id.into(), None)).collect::>(); if vis.syntax().to_string().as_str() == "pub(crate)" { return files; @@ -54,6 +56,6 @@ impl NameDefinition { ModuleSource::Module(m) => Some(m.syntax().text_range()), ModuleSource::SourceFile(_) => None, }; - vec![(file_id, range)] + [(file_id, range)].iter().cloned().collect() } } -- cgit v1.2.3 From b5a3ee93e24931c8bba628ddc7be4f098a19a326 Mon Sep 17 00:00:00 2001 From: Ekaterina Babshukova Date: Wed, 16 Oct 2019 16:49:35 +0300 Subject: support items that visible to the parent module --- crates/ra_ide_api/src/references.rs | 28 +++++++++++++-- crates/ra_ide_api/src/references/classify.rs | 1 + crates/ra_ide_api/src/references/search_scope.rs | 44 ++++++++++++++++++++++-- 3 files changed, 68 insertions(+), 5 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs index 3d647d2cb..aadd52616 100644 --- a/crates/ra_ide_api/src/references.rs +++ b/crates/ra_ide_api/src/references.rs @@ -270,9 +270,8 @@ mod tests { assert_eq!(refs.len(), 3); } - // `mod foo;` is not in the results because `foo` is an `ast::Name`. - // So, there are two references: the first one is a definition of the `foo` module, + // So, there are two references: the first one is a definition of the `foo` module, // which is the whole `foo.rs`, and the second one is in `use foo::Foo`. #[test] fn test_find_all_refs_decl_module() { @@ -297,6 +296,31 @@ mod tests { assert_eq!(refs.len(), 2); } + #[test] + fn test_find_all_refs_super_mod_vis() { + let code = r#" + //- /lib.rs + mod foo; + + //- /foo.rs + mod some; + use some::Foo; + + fn f() { + let i = Foo { n: 5 }; + } + + //- /foo/some.rs + pub(super) struct Foo<|> { + pub n: u32, + } + "#; + + let (analysis, pos) = analysis_and_position(code); + let refs = analysis.find_all_refs(pos).unwrap().unwrap(); + assert_eq!(refs.len(), 3); + } + fn get_all_refs(text: &str) -> ReferenceSearchResult { let (analysis, position) = single_file_with_position(text); analysis.find_all_refs(position).unwrap().unwrap() diff --git a/crates/ra_ide_api/src/references/classify.rs b/crates/ra_ide_api/src/references/classify.rs index ac9cf34eb..3beab9861 100644 --- a/crates/ra_ide_api/src/references/classify.rs +++ b/crates/ra_ide_api/src/references/classify.rs @@ -152,6 +152,7 @@ pub(crate) fn classify_name_ref( AssocItem(item) => Some(from_assoc_item(db, item)), LocalBinding(Either::A(pat)) => from_pat(db, file_id, pat), LocalBinding(Either::B(par)) => { + // Not really supported let kind = NameKind::SelfParam(par); Some(NameDefinition { kind, container, visibility }) } diff --git a/crates/ra_ide_api/src/references/search_scope.rs b/crates/ra_ide_api/src/references/search_scope.rs index d2c966b4f..8495a92a5 100644 --- a/crates/ra_ide_api/src/references/search_scope.rs +++ b/crates/ra_ide_api/src/references/search_scope.rs @@ -25,14 +25,53 @@ impl NameDefinition { } if let Some(ref vis) = self.visibility { + let vis = vis.syntax().to_string(); + + // FIXME: add "pub(in path)" + + if vis.as_str() == "pub(super)" { + if let Some(parent_module) = self.container.parent(db) { + let mut files = HashSet::new(); + + let parent_src = parent_module.definition_source(db); + let file_id = parent_src.file_id.original_file(db); + + match parent_src.ast { + ModuleSource::Module(m) => { + let range = Some(m.syntax().text_range()); + files.insert((file_id, range)); + } + ModuleSource::SourceFile(_) => { + files.insert((file_id, None)); + files.extend( + parent_module + .children(db) + .map(|m| { + let src = m.definition_source(db); + (src.file_id.original_file(db), None) + }) + .collect::>(), + ); + } + } + return files; + } else { + let range = match module_src.ast { + ModuleSource::Module(m) => Some(m.syntax().text_range()), + ModuleSource::SourceFile(_) => None, + }; + return [(file_id, range)].iter().cloned().collect(); + } + } + let source_root_id = db.file_source_root(file_id); let source_root = db.source_root(source_root_id); let mut files = source_root.walk().map(|id| (id.into(), None)).collect::>(); - if vis.syntax().to_string().as_str() == "pub(crate)" { + if vis.as_str() == "pub(crate)" { return files; } - if vis.syntax().to_string().as_str() == "pub" { + if vis.as_str() == "pub" { let krate = self.container.krate(db).unwrap(); let crate_graph = db.crate_graph(); @@ -49,7 +88,6 @@ impl NameDefinition { return files; } - // FIXME: "pub(super)", "pub(in path)" } let range = match module_src.ast { -- cgit v1.2.3 From decfd28bd14b56befa17257694caacc57a090939 Mon Sep 17 00:00:00 2001 From: Ekaterina Babshukova Date: Tue, 22 Oct 2019 23:46:53 +0300 Subject: some fixes, add docs --- crates/ra_ide_api/src/goto_definition.rs | 12 ++-- crates/ra_ide_api/src/references.rs | 39 ++++++----- crates/ra_ide_api/src/references/classify.rs | 8 ++- .../ra_ide_api/src/references/name_definition.rs | 5 +- crates/ra_ide_api/src/references/search_scope.rs | 81 ++++++++++------------ 5 files changed, 73 insertions(+), 72 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index d14908b25..1f3fa6c57 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs @@ -206,7 +206,7 @@ fn named_target(file_id: FileId, node: &SyntaxNode) -> Option #[cfg(test)] mod tests { - // use test_utils::covers; + use test_utils::covers; use crate::mock_analysis::analysis_and_position; @@ -274,7 +274,7 @@ mod tests { #[test] fn goto_definition_works_for_macros() { - // covers!(goto_definition_works_for_macros); + covers!(goto_definition_works_for_macros); check_goto( " //- /lib.rs @@ -294,7 +294,7 @@ mod tests { #[test] fn goto_definition_works_for_macros_from_other_crates() { - // covers!(goto_definition_works_for_macros); + covers!(goto_definition_works_for_macros); check_goto( " //- /lib.rs @@ -317,7 +317,7 @@ mod tests { #[test] fn goto_definition_works_for_methods() { - // covers!(goto_definition_works_for_methods); + covers!(goto_definition_works_for_methods); check_goto( " //- /lib.rs @@ -336,7 +336,7 @@ mod tests { #[test] fn goto_definition_works_for_fields() { - // covers!(goto_definition_works_for_fields); + covers!(goto_definition_works_for_fields); check_goto( " //- /lib.rs @@ -354,7 +354,7 @@ mod tests { #[test] fn goto_definition_works_for_record_fields() { - // covers!(goto_definition_works_for_record_fields); + covers!(goto_definition_works_for_record_fields); check_goto( " //- /lib.rs diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs index aadd52616..f35d835ac 100644 --- a/crates/ra_ide_api/src/references.rs +++ b/crates/ra_ide_api/src/references.rs @@ -1,4 +1,13 @@ -//! FIXME: write short doc here +//! This module implements a reference search. +//! First, the element at the cursor position must be either an `ast::Name` +//! or `ast::NameRef`. If it's a `ast::NameRef`, at the classification step we +//! try to resolve the direct tree parent of this element, otherwise we +//! already have a definition and just need to get its HIR together with +//! some information that is needed for futher steps of searching. +//! After that, we collect files that might contain references and look +//! for text occurrences of the identifier. If there's an `ast::NameRef` +//! at the index that the match starts at and its tree parent is +//! resolved to the search element definition, we get a reference. mod classify; mod name_definition; @@ -9,7 +18,7 @@ use once_cell::unsync::Lazy; use ra_db::{SourceDatabase, SourceDatabaseExt}; use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SourceFile, SyntaxNode, TextUnit}; -use crate::{db::RootDatabase, FileId, FilePosition, FileRange, NavigationTarget, RangeInfo}; +use crate::{db::RootDatabase, FilePosition, FileRange, NavigationTarget, RangeInfo}; pub(crate) use self::{ classify::{classify_name, classify_name_ref}, @@ -102,16 +111,7 @@ fn process_definition(db: &RootDatabase, def: NameDefinition, name: String) -> V let scope = def.search_scope(db); 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 - } - }; - - for (file_id, text_range) in scope { + for (file_id, search_range) in scope { let text = db.file_text(file_id); let parse = Lazy::new(|| SourceFile::parse(&text)); @@ -122,19 +122,20 @@ fn process_definition(db: &RootDatabase, def: NameDefinition, name: String) -> V find_node_at_offset::(parse.tree().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) { + if let Some(search_range) = search_range { + if !range.is_subrange(&search_range) { + continue; + } + } + if let Some(d) = classify_name_ref(db, file_id, &name_ref) { + if d == def { refs.push(FileRange { file_id, range }); } - } else if is_match(file_id, &name_ref) { - refs.push(FileRange { file_id, range }); } } } } - - return refs; + refs } #[cfg(test)] diff --git a/crates/ra_ide_api/src/references/classify.rs b/crates/ra_ide_api/src/references/classify.rs index 3beab9861..c8daff9b1 100644 --- a/crates/ra_ide_api/src/references/classify.rs +++ b/crates/ra_ide_api/src/references/classify.rs @@ -1,8 +1,9 @@ -//! FIXME: write short doc here +//! Functions that are used to classify an element from its definition or reference. use hir::{Either, FromSource, Module, ModuleSource, Path, PathResolution, Source, SourceAnalyzer}; use ra_db::FileId; use ra_syntax::{ast, match_ast, AstNode, AstPtr}; +use test_utils::tested_by; use super::{ name_definition::{from_assoc_item, from_module_def, from_pat, from_struct_field}, @@ -111,18 +112,21 @@ pub(crate) fn classify_name_ref( let analyzer = SourceAnalyzer::new(db, file_id, name_ref.syntax(), None); if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) { + tested_by!(goto_definition_works_for_methods); if let Some(func) = analyzer.resolve_method_call(&method_call) { return Some(from_assoc_item(db, func.into())); } } if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) { + tested_by!(goto_definition_works_for_fields); if let Some(field) = analyzer.resolve_field(&field_expr) { return Some(from_struct_field(db, field)); } } if let Some(record_field) = ast::RecordField::cast(parent.clone()) { + tested_by!(goto_definition_works_for_record_fields); if let Some(record_lit) = record_field.syntax().ancestors().find_map(ast::RecordLit::cast) { let variant_def = analyzer.resolve_record_literal(&record_lit)?; let hir_path = Path::from_name_ref(name_ref); @@ -139,6 +143,7 @@ pub(crate) fn classify_name_ref( let visibility = None; if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) { + tested_by!(goto_definition_works_for_macros); if let Some(macro_def) = analyzer.resolve_macro_call(db, ¯o_call) { let kind = NameKind::Macro(macro_def); return Some(NameDefinition { kind, container, visibility }); @@ -152,7 +157,6 @@ pub(crate) fn classify_name_ref( AssocItem(item) => Some(from_assoc_item(db, item)), LocalBinding(Either::A(pat)) => from_pat(db, file_id, pat), LocalBinding(Either::B(par)) => { - // Not really supported let kind = NameKind::SelfParam(par); Some(NameDefinition { kind, container, visibility }) } diff --git a/crates/ra_ide_api/src/references/name_definition.rs b/crates/ra_ide_api/src/references/name_definition.rs index 723d97237..4580bc789 100644 --- a/crates/ra_ide_api/src/references/name_definition.rs +++ b/crates/ra_ide_api/src/references/name_definition.rs @@ -1,4 +1,7 @@ -//! FIXME: write short doc here +//! `NameDefinition` keeps information about the element we want to search references for. +//! The element is represented by `NameKind`. It's located inside some `container` and +//! has a `visibility`, which defines a search scope. +//! Note that the reference search is possible for not all of the classified items. use hir::{ db::AstDatabase, Adt, AssocItem, DefWithBody, FromSource, HasSource, HirFileId, MacroDef, diff --git a/crates/ra_ide_api/src/references/search_scope.rs b/crates/ra_ide_api/src/references/search_scope.rs index 8495a92a5..5cb69b8fc 100644 --- a/crates/ra_ide_api/src/references/search_scope.rs +++ b/crates/ra_ide_api/src/references/search_scope.rs @@ -1,72 +1,66 @@ -//! FIXME: write short doc here - -use std::collections::HashSet; +//! Generally, `search_scope` returns files that might contain references for the element. +//! For `pub(crate)` things it's a crate, for `pub` things it's a crate and dependant crates. +//! In some cases, the location of the references is known to within a `TextRange`, +//! e.g. for things like local variables. use hir::{DefWithBody, HasSource, ModuleSource}; use ra_db::{FileId, SourceDatabase, SourceDatabaseExt}; use ra_syntax::{AstNode, TextRange}; +use rustc_hash::FxHashSet; use crate::db::RootDatabase; use super::{NameDefinition, NameKind}; impl NameDefinition { - pub(crate) fn search_scope(&self, db: &RootDatabase) -> HashSet<(FileId, Option)> { + pub(crate) fn search_scope(&self, db: &RootDatabase) -> FxHashSet<(FileId, Option)> { let module_src = self.container.definition_source(db); let file_id = module_src.file_id.original_file(db); if let NameKind::Pat((def, _)) = self.kind { + let mut res = FxHashSet::default(); let range = match def { DefWithBody::Function(f) => f.source(db).ast.syntax().text_range(), DefWithBody::Const(c) => c.source(db).ast.syntax().text_range(), DefWithBody::Static(s) => s.source(db).ast.syntax().text_range(), }; - return [(file_id, Some(range))].iter().cloned().collect(); + res.insert((file_id, Some(range))); + return res; } - if let Some(ref vis) = self.visibility { - let vis = vis.syntax().to_string(); - - // FIXME: add "pub(in path)" - - if vis.as_str() == "pub(super)" { - if let Some(parent_module) = self.container.parent(db) { - let mut files = HashSet::new(); + let vis = + self.visibility.as_ref().map(|v| v.syntax().to_string()).unwrap_or("".to_string()); - let parent_src = parent_module.definition_source(db); - let file_id = parent_src.file_id.original_file(db); + if vis.as_str() == "pub(super)" { + if let Some(parent_module) = self.container.parent(db) { + let mut files = FxHashSet::default(); + let parent_src = parent_module.definition_source(db); + let file_id = parent_src.file_id.original_file(db); - match parent_src.ast { - ModuleSource::Module(m) => { - let range = Some(m.syntax().text_range()); - files.insert((file_id, range)); - } - ModuleSource::SourceFile(_) => { - files.insert((file_id, None)); - files.extend( - parent_module - .children(db) - .map(|m| { - let src = m.definition_source(db); - (src.file_id.original_file(db), None) - }) - .collect::>(), - ); - } + match parent_src.ast { + ModuleSource::Module(m) => { + let range = Some(m.syntax().text_range()); + files.insert((file_id, range)); + } + ModuleSource::SourceFile(_) => { + files.insert((file_id, None)); + files.extend(parent_module.children(db).map(|m| { + let src = m.definition_source(db); + (src.file_id.original_file(db), None) + })); } - return files; - } else { - let range = match module_src.ast { - ModuleSource::Module(m) => Some(m.syntax().text_range()), - ModuleSource::SourceFile(_) => None, - }; - return [(file_id, range)].iter().cloned().collect(); } + return files; } + } + if vis.as_str() != "" { let source_root_id = db.file_source_root(file_id); let source_root = db.source_root(source_root_id); - let mut files = source_root.walk().map(|id| (id.into(), None)).collect::>(); + let mut files = + source_root.walk().map(|id| (id.into(), None)).collect::>(); + + // FIXME: add "pub(in path)" if vis.as_str() == "pub(crate)" { return files; @@ -74,10 +68,8 @@ impl NameDefinition { if vis.as_str() == "pub" { let krate = self.container.krate(db).unwrap(); let crate_graph = db.crate_graph(); - for crate_id in crate_graph.iter() { let mut crate_deps = crate_graph.dependencies(crate_id); - if crate_deps.any(|dep| dep.crate_id() == krate.crate_id()) { let root_file = crate_graph.crate_root(crate_id); let source_root_id = db.file_source_root(root_file); @@ -85,15 +77,16 @@ impl NameDefinition { files.extend(source_root.walk().map(|id| (id.into(), None))); } } - return files; } } + let mut res = FxHashSet::default(); let range = match module_src.ast { ModuleSource::Module(m) => Some(m.syntax().text_range()), ModuleSource::SourceFile(_) => None, }; - [(file_id, range)].iter().cloned().collect() + res.insert((file_id, range)); + res } } -- cgit v1.2.3