diff options
Diffstat (limited to 'crates/ra_analysis/src')
-rw-r--r-- | crates/ra_analysis/src/hir/function/mod.rs | 28 | ||||
-rw-r--r-- | crates/ra_analysis/src/hir/function/scope.rs | 29 | ||||
-rw-r--r-- | crates/ra_analysis/src/hir/mod.rs | 53 | ||||
-rw-r--r-- | crates/ra_analysis/src/imp.rs | 93 | ||||
-rw-r--r-- | crates/ra_analysis/src/syntax_ptr.rs | 7 |
5 files changed, 103 insertions, 107 deletions
diff --git a/crates/ra_analysis/src/hir/function/mod.rs b/crates/ra_analysis/src/hir/function/mod.rs index 5e44a88a7..d171b6a8d 100644 --- a/crates/ra_analysis/src/hir/function/mod.rs +++ b/crates/ra_analysis/src/hir/function/mod.rs | |||
@@ -6,8 +6,8 @@ use std::{ | |||
6 | }; | 6 | }; |
7 | 7 | ||
8 | use ra_syntax::{ | 8 | use ra_syntax::{ |
9 | TextRange, TextUnit, SyntaxNodeRef, | ||
9 | ast::{self, AstNode, DocCommentsOwner, NameOwner}, | 10 | ast::{self, AstNode, DocCommentsOwner, NameOwner}, |
10 | TextRange, TextUnit, | ||
11 | }; | 11 | }; |
12 | 12 | ||
13 | use crate::{ | 13 | use crate::{ |
@@ -39,6 +39,32 @@ impl FunctionDescriptor { | |||
39 | FunctionDescriptor { fn_id } | 39 | FunctionDescriptor { fn_id } |
40 | } | 40 | } |
41 | 41 | ||
42 | pub(crate) fn guess_for_name_ref( | ||
43 | db: &impl HirDatabase, | ||
44 | file_id: FileId, | ||
45 | name_ref: ast::NameRef, | ||
46 | ) -> Option<FunctionDescriptor> { | ||
47 | FunctionDescriptor::guess_for_node(db, file_id, name_ref.syntax()) | ||
48 | } | ||
49 | |||
50 | pub(crate) fn guess_for_bind_pat( | ||
51 | db: &impl HirDatabase, | ||
52 | file_id: FileId, | ||
53 | bind_pat: ast::BindPat, | ||
54 | ) -> Option<FunctionDescriptor> { | ||
55 | FunctionDescriptor::guess_for_node(db, file_id, bind_pat.syntax()) | ||
56 | } | ||
57 | |||
58 | fn guess_for_node( | ||
59 | db: &impl HirDatabase, | ||
60 | file_id: FileId, | ||
61 | node: SyntaxNodeRef, | ||
62 | ) -> Option<FunctionDescriptor> { | ||
63 | let fn_def = node.ancestors().find_map(ast::FnDef::cast)?; | ||
64 | let res = FunctionDescriptor::guess_from_source(db, file_id, fn_def); | ||
65 | Some(res) | ||
66 | } | ||
67 | |||
42 | pub(crate) fn scope(&self, db: &impl HirDatabase) -> Arc<FnScopes> { | 68 | pub(crate) fn scope(&self, db: &impl HirDatabase) -> Arc<FnScopes> { |
43 | db.fn_scopes(self.fn_id) | 69 | db.fn_scopes(self.fn_id) |
44 | } | 70 | } |
diff --git a/crates/ra_analysis/src/hir/function/scope.rs b/crates/ra_analysis/src/hir/function/scope.rs index b8bdebe47..76b2fea68 100644 --- a/crates/ra_analysis/src/hir/function/scope.rs +++ b/crates/ra_analysis/src/hir/function/scope.rs | |||
@@ -1,9 +1,9 @@ | |||
1 | use rustc_hash::{FxHashMap, FxHashSet}; | 1 | use rustc_hash::{FxHashMap, FxHashSet}; |
2 | 2 | ||
3 | use ra_syntax::{ | 3 | use ra_syntax::{ |
4 | AstNode, SmolStr, SyntaxNodeRef, TextRange, | ||
4 | algo::generate, | 5 | algo::generate, |
5 | ast::{self, ArgListOwner, LoopBodyOwner, NameOwner}, | 6 | ast::{self, ArgListOwner, LoopBodyOwner, NameOwner}, |
6 | AstNode, SmolStr, SyntaxNodeRef, | ||
7 | }; | 7 | }; |
8 | 8 | ||
9 | use crate::{ | 9 | use crate::{ |
@@ -70,6 +70,27 @@ impl FnScopes { | |||
70 | .nth(0); | 70 | .nth(0); |
71 | ret | 71 | ret |
72 | } | 72 | } |
73 | |||
74 | pub fn find_all_refs(&self, pat: ast::BindPat) -> Vec<ReferenceDescriptor> { | ||
75 | let fn_def = pat.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); | ||
76 | let name_ptr = LocalSyntaxPtr::new(pat.syntax()); | ||
77 | let refs: Vec<_> = fn_def | ||
78 | .syntax() | ||
79 | .descendants() | ||
80 | .filter_map(ast::NameRef::cast) | ||
81 | .filter(|name_ref| match self.resolve_local_name(*name_ref) { | ||
82 | None => false, | ||
83 | Some(entry) => entry.ptr() == name_ptr, | ||
84 | }) | ||
85 | .map(|name_ref| ReferenceDescriptor { | ||
86 | name: name_ref.syntax().text().to_string(), | ||
87 | range: name_ref.syntax().range(), | ||
88 | }) | ||
89 | .collect(); | ||
90 | |||
91 | refs | ||
92 | } | ||
93 | |||
73 | fn root_scope(&mut self) -> ScopeId { | 94 | fn root_scope(&mut self) -> ScopeId { |
74 | self.scopes.alloc(ScopeData { | 95 | self.scopes.alloc(ScopeData { |
75 | parent: None, | 96 | parent: None, |
@@ -262,6 +283,12 @@ fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) { | |||
262 | } | 283 | } |
263 | } | 284 | } |
264 | 285 | ||
286 | #[derive(Debug)] | ||
287 | pub struct ReferenceDescriptor { | ||
288 | pub range: TextRange, | ||
289 | pub name: String, | ||
290 | } | ||
291 | |||
265 | #[cfg(test)] | 292 | #[cfg(test)] |
266 | mod tests { | 293 | mod tests { |
267 | use ra_editor::find_node_at_offset; | 294 | use ra_editor::find_node_at_offset; |
diff --git a/crates/ra_analysis/src/hir/mod.rs b/crates/ra_analysis/src/hir/mod.rs index 5a9086cef..e234173a9 100644 --- a/crates/ra_analysis/src/hir/mod.rs +++ b/crates/ra_analysis/src/hir/mod.rs | |||
@@ -11,15 +11,9 @@ mod function; | |||
11 | mod module; | 11 | mod module; |
12 | mod path; | 12 | mod path; |
13 | 13 | ||
14 | use ra_syntax::{ | ||
15 | ast::{self, AstNode}, | ||
16 | TextRange, | ||
17 | }; | ||
18 | |||
19 | use crate::{ | 14 | use crate::{ |
20 | hir::db::HirDatabase, | 15 | hir::db::HirDatabase, |
21 | loc2id::{DefId, DefLoc}, | 16 | loc2id::{DefId, DefLoc}, |
22 | syntax_ptr::LocalSyntaxPtr, | ||
23 | Cancelable, | 17 | Cancelable, |
24 | }; | 18 | }; |
25 | 19 | ||
@@ -49,50 +43,3 @@ impl DefId { | |||
49 | Ok(res) | 43 | Ok(res) |
50 | } | 44 | } |
51 | } | 45 | } |
52 | |||
53 | #[derive(Debug)] | ||
54 | pub struct ReferenceDescriptor { | ||
55 | pub range: TextRange, | ||
56 | pub name: String, | ||
57 | } | ||
58 | |||
59 | #[derive(Debug)] | ||
60 | pub struct DeclarationDescriptor<'a> { | ||
61 | pat: ast::BindPat<'a>, | ||
62 | pub range: TextRange, | ||
63 | } | ||
64 | |||
65 | impl<'a> DeclarationDescriptor<'a> { | ||
66 | pub fn new(pat: ast::BindPat) -> DeclarationDescriptor { | ||
67 | let range = pat.syntax().range(); | ||
68 | |||
69 | DeclarationDescriptor { pat, range } | ||
70 | } | ||
71 | |||
72 | pub fn find_all_refs(&self) -> Vec<ReferenceDescriptor> { | ||
73 | let name_ptr = LocalSyntaxPtr::new(self.pat.syntax()); | ||
74 | |||
75 | let fn_def = match self.pat.syntax().ancestors().find_map(ast::FnDef::cast) { | ||
76 | Some(def) => def, | ||
77 | None => return Default::default(), | ||
78 | }; | ||
79 | |||
80 | let fn_scopes = FnScopes::new(fn_def); | ||
81 | |||
82 | let refs: Vec<_> = fn_def | ||
83 | .syntax() | ||
84 | .descendants() | ||
85 | .filter_map(ast::NameRef::cast) | ||
86 | .filter(|name_ref| match fn_scopes.resolve_local_name(*name_ref) { | ||
87 | None => false, | ||
88 | Some(entry) => entry.ptr() == name_ptr, | ||
89 | }) | ||
90 | .map(|name_ref| ReferenceDescriptor { | ||
91 | name: name_ref.syntax().text().to_string(), | ||
92 | range: name_ref.syntax().range(), | ||
93 | }) | ||
94 | .collect(); | ||
95 | |||
96 | refs | ||
97 | } | ||
98 | } | ||
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs index b16edb969..377f7420f 100644 --- a/crates/ra_analysis/src/imp.rs +++ b/crates/ra_analysis/src/imp.rs | |||
@@ -7,7 +7,7 @@ use std::{ | |||
7 | use ra_editor::{self, find_node_at_offset, FileSymbol, LineIndex, LocalEdit}; | 7 | use ra_editor::{self, find_node_at_offset, FileSymbol, LineIndex, LocalEdit}; |
8 | use ra_syntax::{ | 8 | use ra_syntax::{ |
9 | ast::{self, ArgListOwner, Expr, NameOwner}, | 9 | ast::{self, ArgListOwner, Expr, NameOwner}, |
10 | AstNode, SourceFileNode, SmolStr, | 10 | AstNode, SourceFileNode, |
11 | SyntaxKind::*, | 11 | SyntaxKind::*, |
12 | SyntaxNodeRef, TextRange, TextUnit, | 12 | SyntaxNodeRef, TextRange, TextUnit, |
13 | }; | 13 | }; |
@@ -22,7 +22,6 @@ use crate::{ | |||
22 | hir::{ | 22 | hir::{ |
23 | FunctionDescriptor, FnSignatureInfo, ModuleDescriptor, | 23 | FunctionDescriptor, FnSignatureInfo, ModuleDescriptor, |
24 | Problem, | 24 | Problem, |
25 | DeclarationDescriptor, | ||
26 | }, | 25 | }, |
27 | input::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE}, | 26 | input::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE}, |
28 | symbol_index::SymbolIndex, | 27 | symbol_index::SymbolIndex, |
@@ -273,24 +272,27 @@ impl AnalysisImpl { | |||
273 | let file = self.db.file_syntax(position.file_id); | 272 | let file = self.db.file_syntax(position.file_id); |
274 | let syntax = file.syntax(); | 273 | let syntax = file.syntax(); |
275 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) { | 274 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) { |
276 | // First try to resolve the symbol locally | 275 | if let Some(fn_descr) = |
277 | return if let Some((name, range)) = | 276 | FunctionDescriptor::guess_for_name_ref(&*self.db, position.file_id, name_ref) |
278 | resolve_local_name(&self.db, position.file_id, name_ref) | ||
279 | { | 277 | { |
280 | let mut vec = vec![]; | 278 | let scope = fn_descr.scope(&*self.db); |
281 | vec.push(( | 279 | // First try to resolve the symbol locally |
282 | position.file_id, | 280 | return if let Some(entry) = scope.resolve_local_name(name_ref) { |
283 | FileSymbol { | 281 | let mut vec = vec![]; |
284 | name, | 282 | vec.push(( |
285 | node_range: range, | 283 | position.file_id, |
286 | kind: NAME, | 284 | FileSymbol { |
287 | }, | 285 | name: entry.name().clone(), |
288 | )); | 286 | node_range: entry.ptr().range(), |
289 | Ok(vec) | 287 | kind: NAME, |
290 | } else { | 288 | }, |
291 | // If that fails try the index based approach. | 289 | )); |
292 | self.index_resolve(name_ref) | 290 | Ok(vec) |
293 | }; | 291 | } else { |
292 | // If that fails try the index based approach. | ||
293 | self.index_resolve(name_ref) | ||
294 | }; | ||
295 | } | ||
294 | } | 296 | } |
295 | if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) { | 297 | if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) { |
296 | if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) { | 298 | if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) { |
@@ -320,31 +322,41 @@ impl AnalysisImpl { | |||
320 | 322 | ||
321 | pub fn find_all_refs(&self, position: FilePosition) -> Vec<(FileId, TextRange)> { | 323 | pub fn find_all_refs(&self, position: FilePosition) -> Vec<(FileId, TextRange)> { |
322 | let file = self.db.file_syntax(position.file_id); | 324 | let file = self.db.file_syntax(position.file_id); |
323 | let syntax = file.syntax(); | ||
324 | |||
325 | // Find the binding associated with the offset | 325 | // Find the binding associated with the offset |
326 | let maybe_binding = | 326 | let (binding, descr) = match find_binding(&self.db, &file, position) { |
327 | find_node_at_offset::<ast::BindPat>(syntax, position.offset).or_else(|| { | ||
328 | let name_ref = find_node_at_offset::<ast::NameRef>(syntax, position.offset)?; | ||
329 | let resolved = resolve_local_name(&self.db, position.file_id, name_ref)?; | ||
330 | find_node_at_offset::<ast::BindPat>(syntax, resolved.1.end()) | ||
331 | }); | ||
332 | |||
333 | let binding = match maybe_binding { | ||
334 | None => return Vec::new(), | 327 | None => return Vec::new(), |
335 | Some(it) => it, | 328 | Some(it) => it, |
336 | }; | 329 | }; |
337 | 330 | ||
338 | let decl = DeclarationDescriptor::new(binding); | 331 | let mut ret = vec![(position.file_id, binding.syntax().range())]; |
339 | |||
340 | let mut ret = vec![(position.file_id, decl.range)]; | ||
341 | ret.extend( | 332 | ret.extend( |
342 | decl.find_all_refs() | 333 | descr |
334 | .scope(&*self.db) | ||
335 | .find_all_refs(binding) | ||
343 | .into_iter() | 336 | .into_iter() |
344 | .map(|ref_desc| (position.file_id, ref_desc.range)), | 337 | .map(|ref_desc| (position.file_id, ref_desc.range)), |
345 | ); | 338 | ); |
346 | 339 | ||
347 | ret | 340 | return ret; |
341 | |||
342 | fn find_binding<'a>( | ||
343 | db: &db::RootDatabase, | ||
344 | source_file: &'a SourceFileNode, | ||
345 | position: FilePosition, | ||
346 | ) -> Option<(ast::BindPat<'a>, FunctionDescriptor)> { | ||
347 | let syntax = source_file.syntax(); | ||
348 | if let Some(binding) = find_node_at_offset::<ast::BindPat>(syntax, position.offset) { | ||
349 | let descr = FunctionDescriptor::guess_for_bind_pat(db, position.file_id, binding)?; | ||
350 | return Some((binding, descr)); | ||
351 | }; | ||
352 | let name_ref = find_node_at_offset::<ast::NameRef>(syntax, position.offset)?; | ||
353 | let descr = FunctionDescriptor::guess_for_name_ref(db, position.file_id, name_ref)?; | ||
354 | let scope = descr.scope(db); | ||
355 | let resolved = scope.resolve_local_name(name_ref)?; | ||
356 | let resolved = resolved.ptr().resolve(source_file); | ||
357 | let binding = find_node_at_offset::<ast::BindPat>(syntax, resolved.range().end())?; | ||
358 | Some((binding, descr)) | ||
359 | } | ||
348 | } | 360 | } |
349 | 361 | ||
350 | pub fn doc_comment_for( | 362 | pub fn doc_comment_for( |
@@ -582,16 +594,3 @@ impl<'a> FnCallNode<'a> { | |||
582 | } | 594 | } |
583 | } | 595 | } |
584 | } | 596 | } |
585 | |||
586 | fn resolve_local_name( | ||
587 | db: &db::RootDatabase, | ||
588 | file_id: FileId, | ||
589 | name_ref: ast::NameRef, | ||
590 | ) -> Option<(SmolStr, TextRange)> { | ||
591 | let fn_def = name_ref.syntax().ancestors().find_map(ast::FnDef::cast)?; | ||
592 | let function = FunctionDescriptor::guess_from_source(db, file_id, fn_def); | ||
593 | let scopes = function.scope(db); | ||
594 | let scope_entry = scopes.resolve_local_name(name_ref)?; | ||
595 | let syntax = db.resolve_syntax_ptr(scope_entry.ptr().into_global(file_id)); | ||
596 | Some((scope_entry.name().clone(), syntax.range())) | ||
597 | } | ||
diff --git a/crates/ra_analysis/src/syntax_ptr.rs b/crates/ra_analysis/src/syntax_ptr.rs index e45934ce0..3168e82a7 100644 --- a/crates/ra_analysis/src/syntax_ptr.rs +++ b/crates/ra_analysis/src/syntax_ptr.rs | |||
@@ -56,11 +56,8 @@ impl LocalSyntaxPtr { | |||
56 | } | 56 | } |
57 | } | 57 | } |
58 | 58 | ||
59 | pub(crate) fn into_global(self, file_id: FileId) -> SyntaxPtr { | 59 | pub(crate) fn range(self) -> TextRange { |
60 | SyntaxPtr { | 60 | self.range |
61 | file_id, | ||
62 | local: self, | ||
63 | } | ||
64 | } | 61 | } |
65 | } | 62 | } |
66 | 63 | ||