diff options
Diffstat (limited to 'crates/ra_ide_api')
-rw-r--r-- | crates/ra_ide_api/src/goto_definition.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide_api/src/hover.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide_api/src/name_ref_kind.rs | 6 | ||||
-rw-r--r-- | crates/ra_ide_api/src/references.rs | 154 | ||||
-rw-r--r-- | crates/ra_ide_api/src/search_scope.rs | 186 | ||||
-rw-r--r-- | crates/ra_ide_api/src/syntax_highlighting.rs | 2 |
6 files changed, 318 insertions, 34 deletions
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::{ | |||
10 | use crate::{ | 10 | use crate::{ |
11 | db::RootDatabase, | 11 | db::RootDatabase, |
12 | display::ShortLabel, | 12 | display::ShortLabel, |
13 | name_ref_kind::{classify_name_ref, NameRefKind::*}, | 13 | name_ref_kind::{classify_name_ref, NameKind::*}, |
14 | FilePosition, NavigationTarget, RangeInfo, | 14 | FilePosition, NavigationTarget, RangeInfo, |
15 | }; | 15 | }; |
16 | 16 | ||
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::{ | |||
14 | description_from_symbol, docs_from_symbol, macro_label, rust_code_markup, | 14 | description_from_symbol, docs_from_symbol, macro_label, rust_code_markup, |
15 | rust_code_markup_with_doc, ShortLabel, | 15 | rust_code_markup_with_doc, ShortLabel, |
16 | }, | 16 | }, |
17 | name_ref_kind::{classify_name_ref, NameRefKind::*}, | 17 | name_ref_kind::{classify_name_ref, NameKind::*}, |
18 | FilePosition, FileRange, RangeInfo, | 18 | FilePosition, FileRange, RangeInfo, |
19 | }; | 19 | }; |
20 | 20 | ||
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; | |||
6 | 6 | ||
7 | use crate::db::RootDatabase; | 7 | use crate::db::RootDatabase; |
8 | 8 | ||
9 | pub enum NameRefKind { | 9 | pub enum NameKind { |
10 | Method(hir::Function), | 10 | Method(hir::Function), |
11 | Macro(hir::MacroDef), | 11 | Macro(hir::MacroDef), |
12 | FieldAccess(hir::StructField), | 12 | FieldAccess(hir::StructField), |
@@ -22,8 +22,8 @@ pub(crate) fn classify_name_ref( | |||
22 | db: &RootDatabase, | 22 | db: &RootDatabase, |
23 | analyzer: &hir::SourceAnalyzer, | 23 | analyzer: &hir::SourceAnalyzer, |
24 | name_ref: &ast::NameRef, | 24 | name_ref: &ast::NameRef, |
25 | ) -> Option<NameRefKind> { | 25 | ) -> Option<NameKind> { |
26 | use NameRefKind::*; | 26 | use NameKind::*; |
27 | 27 | ||
28 | // Check if it is a method | 28 | // Check if it is a method |
29 | if let Some(method_call) = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast) { | 29 | 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 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use hir::{Either, ModuleSource}; | 3 | use hir::{FromSource, ModuleSource}; |
4 | use ra_db::{SourceDatabase, SourceDatabaseExt}; | 4 | use ra_db::{SourceDatabase, SourceDatabaseExt}; |
5 | use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SourceFile, SyntaxNode}; | 5 | use ra_syntax::{algo::find_node_at_offset, ast, AstNode, AstPtr, SyntaxNode}; |
6 | use relative_path::{RelativePath, RelativePathBuf}; | 6 | use relative_path::{RelativePath, RelativePathBuf}; |
7 | 7 | ||
8 | use crate::{ | 8 | use crate::{ |
9 | db::RootDatabase, FileId, FilePosition, FileRange, FileSystemEdit, NavigationTarget, RangeInfo, | 9 | db::RootDatabase, |
10 | SourceChange, SourceFileEdit, TextRange, | 10 | name_ref_kind::{ |
11 | classify_name_ref, | ||
12 | NameKind::{self, *}, | ||
13 | }, | ||
14 | FileId, FilePosition, FileRange, FileSystemEdit, NavigationTarget, RangeInfo, SourceChange, | ||
15 | SourceFileEdit, TextRange, | ||
11 | }; | 16 | }; |
12 | 17 | ||
13 | #[derive(Debug, Clone)] | 18 | #[derive(Debug, Clone)] |
@@ -52,41 +57,92 @@ pub(crate) fn find_all_refs( | |||
52 | position: FilePosition, | 57 | position: FilePosition, |
53 | ) -> Option<RangeInfo<ReferenceSearchResult>> { | 58 | ) -> Option<RangeInfo<ReferenceSearchResult>> { |
54 | let parse = db.parse(position.file_id); | 59 | let parse = db.parse(position.file_id); |
55 | let RangeInfo { range, info: (binding, analyzer) } = find_binding(db, &parse.tree(), position)?; | 60 | let syntax = parse.tree().syntax().clone(); |
56 | let declaration = NavigationTarget::from_bind_pat(position.file_id, &binding); | 61 | let RangeInfo { range, info: (analyzer, name_kind) } = find_name(db, &syntax, position)?; |
62 | |||
63 | let declaration = match name_kind { | ||
64 | Macro(mac) => NavigationTarget::from_macro_def(db, mac), | ||
65 | FieldAccess(field) => NavigationTarget::from_field(db, field), | ||
66 | AssocItem(assoc) => NavigationTarget::from_assoc_item(db, assoc), | ||
67 | Method(func) => NavigationTarget::from_def_source(db, func), | ||
68 | Def(def) => NavigationTarget::from_def(db, def)?, | ||
69 | SelfType(ref ty) => match ty.as_adt() { | ||
70 | Some((def_id, _)) => NavigationTarget::from_adt_def(db, def_id), | ||
71 | None => return None, | ||
72 | }, | ||
73 | Pat(pat) => NavigationTarget::from_pat(db, position.file_id, pat), | ||
74 | SelfParam(par) => NavigationTarget::from_self_param(position.file_id, par), | ||
75 | GenericParam(_) => return None, | ||
76 | }; | ||
57 | 77 | ||
58 | let references = analyzer | 78 | let references = match name_kind { |
59 | .find_all_refs(&binding) | 79 | Pat(pat) => analyzer |
60 | .into_iter() | 80 | .find_all_refs(&pat.to_node(&syntax)) |
61 | .map(move |ref_desc| FileRange { file_id: position.file_id, range: ref_desc.range }) | 81 | .into_iter() |
62 | .collect::<Vec<_>>(); | 82 | .map(move |ref_desc| FileRange { file_id: position.file_id, range: ref_desc.range }) |
83 | .collect::<Vec<_>>(), | ||
84 | _ => vec![], | ||
85 | }; | ||
63 | 86 | ||
64 | return Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references })); | 87 | return Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references })); |
65 | 88 | ||
66 | fn find_binding<'a>( | 89 | fn find_name<'a>( |
67 | db: &RootDatabase, | 90 | db: &RootDatabase, |
68 | source_file: &SourceFile, | 91 | syntax: &SyntaxNode, |
69 | position: FilePosition, | 92 | position: FilePosition, |
70 | ) -> Option<RangeInfo<(ast::BindPat, hir::SourceAnalyzer)>> { | 93 | ) -> Option<RangeInfo<(hir::SourceAnalyzer, NameKind)>> { |
71 | let syntax = source_file.syntax(); | 94 | if let Some(name) = find_node_at_offset::<ast::Name>(&syntax, position.offset) { |
72 | if let Some(binding) = find_node_at_offset::<ast::BindPat>(syntax, position.offset) { | 95 | let analyzer = hir::SourceAnalyzer::new(db, position.file_id, name.syntax(), None); |
73 | let range = binding.syntax().text_range(); | 96 | let name_kind = classify_name(db, position.file_id, &name)?; |
74 | let analyzer = hir::SourceAnalyzer::new(db, position.file_id, binding.syntax(), None); | 97 | let range = name.syntax().text_range(); |
75 | return Some(RangeInfo::new(range, (binding, analyzer))); | 98 | return Some(RangeInfo::new(range, (analyzer, name_kind))); |
76 | }; | 99 | } |
77 | let name_ref = find_node_at_offset::<ast::NameRef>(syntax, position.offset)?; | 100 | let name_ref = find_node_at_offset::<ast::NameRef>(&syntax, position.offset)?; |
78 | let range = name_ref.syntax().text_range(); | 101 | let range = name_ref.syntax().text_range(); |
79 | let analyzer = hir::SourceAnalyzer::new(db, position.file_id, name_ref.syntax(), None); | 102 | let analyzer = hir::SourceAnalyzer::new(db, position.file_id, name_ref.syntax(), None); |
80 | let resolved = analyzer.resolve_local_name(&name_ref)?; | 103 | let name_kind = classify_name_ref(db, &analyzer, &name_ref)?; |
81 | if let Either::A(ptr) = resolved.ptr() { | 104 | Some(RangeInfo::new(range, (analyzer, name_kind))) |
82 | if let ast::Pat::BindPat(binding) = ptr.to_node(source_file.syntax()) { | ||
83 | return Some(RangeInfo::new(range, (binding, analyzer))); | ||
84 | } | ||
85 | } | ||
86 | None | ||
87 | } | 105 | } |
88 | } | 106 | } |
89 | 107 | ||
108 | fn classify_name(db: &RootDatabase, file_id: FileId, name: &ast::Name) -> Option<NameKind> { | ||
109 | let parent = name.syntax().parent()?; | ||
110 | let file_id = file_id.into(); | ||
111 | |||
112 | if let Some(pat) = ast::BindPat::cast(parent.clone()) { | ||
113 | return Some(Pat(AstPtr::new(&pat))); | ||
114 | } | ||
115 | if let Some(var) = ast::EnumVariant::cast(parent.clone()) { | ||
116 | let src = hir::Source { file_id, ast: var }; | ||
117 | let var = hir::EnumVariant::from_source(db, src)?; | ||
118 | return Some(Def(var.into())); | ||
119 | } | ||
120 | if let Some(field) = ast::RecordFieldDef::cast(parent.clone()) { | ||
121 | let src = hir::Source { file_id, ast: hir::FieldSource::Named(field) }; | ||
122 | let field = hir::StructField::from_source(db, src)?; | ||
123 | return Some(FieldAccess(field)); | ||
124 | } | ||
125 | if let Some(field) = ast::TupleFieldDef::cast(parent.clone()) { | ||
126 | let src = hir::Source { file_id, ast: hir::FieldSource::Pos(field) }; | ||
127 | let field = hir::StructField::from_source(db, src)?; | ||
128 | return Some(FieldAccess(field)); | ||
129 | } | ||
130 | if let Some(_) = parent.parent().and_then(ast::ItemList::cast) { | ||
131 | let ast = ast::ImplItem::cast(parent.clone())?; | ||
132 | let src = hir::Source { file_id, ast }; | ||
133 | let item = hir::AssocItem::from_source(db, src)?; | ||
134 | return Some(AssocItem(item)); | ||
135 | } | ||
136 | if let Some(item) = ast::ModuleItem::cast(parent.clone()) { | ||
137 | let src = hir::Source { file_id, ast: item }; | ||
138 | let def = hir::ModuleDef::from_source(db, src)?; | ||
139 | return Some(Def(def)); | ||
140 | } | ||
141 | // FIXME: TYPE_PARAM, ALIAS, MACRO_CALL; Union | ||
142 | |||
143 | None | ||
144 | } | ||
145 | |||
90 | pub(crate) fn rename( | 146 | pub(crate) fn rename( |
91 | db: &RootDatabase, | 147 | db: &RootDatabase, |
92 | position: FilePosition, | 148 | position: FilePosition, |
@@ -249,6 +305,48 @@ mod tests { | |||
249 | assert_eq!(refs.len(), 2); | 305 | assert_eq!(refs.len(), 2); |
250 | } | 306 | } |
251 | 307 | ||
308 | #[test] | ||
309 | fn test_find_all_refs_field_name() { | ||
310 | let code = r#" | ||
311 | //- /lib.rs | ||
312 | struct Foo { | ||
313 | spam<|>: u32, | ||
314 | } | ||
315 | "#; | ||
316 | |||
317 | let refs = get_all_refs(code); | ||
318 | assert_eq!(refs.len(), 1); | ||
319 | } | ||
320 | |||
321 | #[test] | ||
322 | fn test_find_all_refs_impl_item_name() { | ||
323 | let code = r#" | ||
324 | //- /lib.rs | ||
325 | struct Foo; | ||
326 | impl Foo { | ||
327 | fn f<|>(&self) { } | ||
328 | } | ||
329 | "#; | ||
330 | |||
331 | let refs = get_all_refs(code); | ||
332 | assert_eq!(refs.len(), 1); | ||
333 | } | ||
334 | |||
335 | #[test] | ||
336 | fn test_find_all_refs_enum_var_name() { | ||
337 | let code = r#" | ||
338 | //- /lib.rs | ||
339 | enum Foo { | ||
340 | A, | ||
341 | B<|>, | ||
342 | C, | ||
343 | } | ||
344 | "#; | ||
345 | |||
346 | let refs = get_all_refs(code); | ||
347 | assert_eq!(refs.len(), 1); | ||
348 | } | ||
349 | |||
252 | fn get_all_refs(text: &str) -> ReferenceSearchResult { | 350 | fn get_all_refs(text: &str) -> ReferenceSearchResult { |
253 | let (analysis, position) = single_file_with_position(text); | 351 | let (analysis, position) = single_file_with_position(text); |
254 | analysis.find_all_refs(position).unwrap().unwrap() | 352 | 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 @@ | |||
1 | pub enum SearchScope { | ||
2 | Function(hir::Function), | ||
3 | Module(hir::Module), | ||
4 | Crate(hir::Crate), | ||
5 | Crates(Vec<hir::Crate>), | ||
6 | } | ||
7 | |||
8 | pub struct SearchScope{ | ||
9 | pub scope: Vec<SyntaxNode> | ||
10 | } | ||
11 | |||
12 | pub fn find_all_refs(db: &RootDatabase, decl: NameKind) -> Vec<ReferenceDescriptor> { | ||
13 | let (module, visibility) = match decl { | ||
14 | FieldAccess(field) => { | ||
15 | let parent = field.parent_def(db); | ||
16 | let module = parent.module(db); | ||
17 | let visibility = match parent { | ||
18 | VariantDef::Struct(s) => s.source(db).ast.visibility(), | ||
19 | VariantDef::EnumVariant(v) => v.parent_enum(db).source(db).ast.visibility(), | ||
20 | }; | ||
21 | (module, visibility) | ||
22 | } | ||
23 | AssocItem(item) => { | ||
24 | let parent = item.parent_trait(db)?; | ||
25 | let module = parent.module(db); | ||
26 | let visibility = parent.source(db).ast.visibility(); | ||
27 | (module, visibility) | ||
28 | } | ||
29 | Def(def) => { | ||
30 | let (module, visibility) = match def { | ||
31 | ModuleDef::Module(m) => (m, ), | ||
32 | ModuleDef::Function(f) => (f.module(db), f.source(db).ast.visibility()), | ||
33 | ModuleDef::Adt::Struct(s) => (s.module(db), s.source(db).ast.visibility()), | ||
34 | ModuleDef::Adt::Union(u) => (u.module(db), u.source(db).ast.visibility()), | ||
35 | ModuleDef::Adt::Enum(e) => (e.module(db), e.source(db).ast.visibility()), | ||
36 | ModuleDef::EnumVariant(v) => (v.module(db), v.source(db).ast.visibility()), | ||
37 | ModuleDef::Const(c) => (c.module(db), c.source(db).ast.visibility()), | ||
38 | ModuleDef::Static(s) => (s.module(db), s.source(db).ast.visibility()), | ||
39 | ModuleDef::Trait(t) => (t.module(db), t.source(db).ast.visibility()), | ||
40 | ModuleDef::TypeAlias(a) => (a.module(db), a.source(db).ast.visibility()), | ||
41 | ModuleDef::BuiltinType(_) => return vec![]; | ||
42 | }; | ||
43 | (module, visibility) | ||
44 | } | ||
45 | // FIXME: add missing kinds | ||
46 | _ => return vec![]; | ||
47 | }; | ||
48 | let scope = scope(db, module, visibility); | ||
49 | } | ||
50 | |||
51 | fn scope(db: &RootDatabase, module: hir::Module, item_vis: Option<ast::Visibility>) -> SearchScope { | ||
52 | if let Some(v) = item_vis { | ||
53 | let krate = module.krate(db)?; | ||
54 | |||
55 | if v.syntax().text() == "pub" { | ||
56 | SearchScope::Crate(krate) | ||
57 | } | ||
58 | if v.syntax().text() == "pub(crate)" { | ||
59 | let crate_graph = db.crate_graph(); | ||
60 | let crates = crate_graph.iter().filter(|id| { | ||
61 | crate_graph.dependencies(id).any(|d| d.crate_id() == krate.crate_id()) | ||
62 | }).map(|id| Crate { id }).collect::<Vec<_>>(); | ||
63 | crates.insert(0, krate); | ||
64 | SearchScope::Crates(crates) | ||
65 | } | ||
66 | // FIXME: "pub(super)", "pub(in path)" | ||
67 | SearchScope::Module(module) | ||
68 | } | ||
69 | SearchScope::Module(module) | ||
70 | } | ||
71 | |||
72 | fn process_one(db, scope: SearchScope, pat) { | ||
73 | match scope { | ||
74 | SearchScope::Crate(krate) => { | ||
75 | let text = db.file_text(position.file_id).as_str(); | ||
76 | let parse = SourceFile::parse(text); | ||
77 | for (offset, name) in text.match_indices(pat) { | ||
78 | if let Some() = find_node_at_offset<ast::NameRef>(parse, offset) { | ||
79 | |||
80 | } | ||
81 | } | ||
82 | } | ||
83 | } | ||
84 | } | ||
85 | |||
86 | #[cfg(test)] | ||
87 | mod tests { | ||
88 | use crate::{ | ||
89 | mock_analysis::analysis_and_position, mock_analysis::single_file_with_position, FileId, | ||
90 | ReferenceSearchResult, | ||
91 | }; | ||
92 | use insta::assert_debug_snapshot; | ||
93 | use test_utils::assert_eq_text; | ||
94 | |||
95 | #[test] | ||
96 | fn test_find_all_refs_for_local() { | ||
97 | let code = r#" | ||
98 | fn main() { | ||
99 | let mut i = 1; | ||
100 | let j = 1; | ||
101 | i = i<|> + j; | ||
102 | |||
103 | { | ||
104 | i = 0; | ||
105 | } | ||
106 | |||
107 | i = 5; | ||
108 | } | ||
109 | "#; | ||
110 | |||
111 | let refs = get_all_refs(code); | ||
112 | assert_eq!(refs.len(), 5); | ||
113 | } | ||
114 | |||
115 | #[test] | ||
116 | fn test_find_all_refs_for_param_inside() { | ||
117 | let code = r#" | ||
118 | fn foo(i : u32) -> u32 { | ||
119 | i<|> | ||
120 | }"#; | ||
121 | |||
122 | let refs = get_all_refs(code); | ||
123 | assert_eq!(refs.len(), 2); | ||
124 | } | ||
125 | |||
126 | #[test] | ||
127 | fn test_find_all_refs_for_fn_param() { | ||
128 | let code = r#" | ||
129 | fn foo(i<|> : u32) -> u32 { | ||
130 | i | ||
131 | }"#; | ||
132 | |||
133 | let refs = get_all_refs(code); | ||
134 | assert_eq!(refs.len(), 2); | ||
135 | } | ||
136 | |||
137 | #[test] | ||
138 | fn test_find_all_refs_field_name() { | ||
139 | let code = r#" | ||
140 | //- /lib.rs | ||
141 | struct Foo { | ||
142 | spam<|>: u32, | ||
143 | } | ||
144 | "#; | ||
145 | |||
146 | let refs = get_all_refs(code); | ||
147 | assert_eq!(refs.len(), 1); | ||
148 | } | ||
149 | |||
150 | #[test] | ||
151 | fn test_find_all_refs_methods() { | ||
152 | let code = r#" | ||
153 | //- /lib.rs | ||
154 | struct Foo; | ||
155 | impl Foo { | ||
156 | pub fn a() { | ||
157 | self.b() | ||
158 | } | ||
159 | fn b(&self) {} | ||
160 | } | ||
161 | "#; | ||
162 | |||
163 | let refs = get_all_refs(code); | ||
164 | assert_eq!(refs.len(), 1); | ||
165 | } | ||
166 | |||
167 | #[test] | ||
168 | fn test_find_all_refs_pub_enum() { | ||
169 | let code = r#" | ||
170 | //- /lib.rs | ||
171 | pub enum Foo { | ||
172 | A, | ||
173 | B<|>, | ||
174 | C, | ||
175 | } | ||
176 | "#; | ||
177 | |||
178 | let refs = get_all_refs(code); | ||
179 | assert_eq!(refs.len(), 1); | ||
180 | } | ||
181 | |||
182 | fn get_all_refs(text: &str) -> ReferenceSearchResult { | ||
183 | let (analysis, position) = single_file_with_position(text); | ||
184 | analysis.find_all_refs(position).unwrap().unwrap() | ||
185 | } | ||
186 | } \ 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::{ | |||
14 | 14 | ||
15 | use crate::{ | 15 | use crate::{ |
16 | db::RootDatabase, | 16 | db::RootDatabase, |
17 | name_ref_kind::{classify_name_ref, NameRefKind::*}, | 17 | name_ref_kind::{classify_name_ref, NameKind::*}, |
18 | FileId, | 18 | FileId, |
19 | }; | 19 | }; |
20 | 20 | ||