aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_analysis/src')
-rw-r--r--crates/ra_analysis/src/hir/function/mod.rs28
-rw-r--r--crates/ra_analysis/src/hir/function/scope.rs29
-rw-r--r--crates/ra_analysis/src/hir/mod.rs53
-rw-r--r--crates/ra_analysis/src/imp.rs93
-rw-r--r--crates/ra_analysis/src/syntax_ptr.rs7
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
8use ra_syntax::{ 8use 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
13use crate::{ 13use 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 @@
1use rustc_hash::{FxHashMap, FxHashSet}; 1use rustc_hash::{FxHashMap, FxHashSet};
2 2
3use ra_syntax::{ 3use 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
9use crate::{ 9use 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)]
287pub struct ReferenceDescriptor {
288 pub range: TextRange,
289 pub name: String,
290}
291
265#[cfg(test)] 292#[cfg(test)]
266mod tests { 293mod 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;
11mod module; 11mod module;
12mod path; 12mod path;
13 13
14use ra_syntax::{
15 ast::{self, AstNode},
16 TextRange,
17};
18
19use crate::{ 14use 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)]
54pub struct ReferenceDescriptor {
55 pub range: TextRange,
56 pub name: String,
57}
58
59#[derive(Debug)]
60pub struct DeclarationDescriptor<'a> {
61 pat: ast::BindPat<'a>,
62 pub range: TextRange,
63}
64
65impl<'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::{
7use ra_editor::{self, find_node_at_offset, FileSymbol, LineIndex, LocalEdit}; 7use ra_editor::{self, find_node_at_offset, FileSymbol, LineIndex, LocalEdit};
8use ra_syntax::{ 8use 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
586fn 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