diff options
Diffstat (limited to 'crates/ra_hir/src/function')
-rw-r--r-- | crates/ra_hir/src/function/scope.rs | 48 |
1 files changed, 46 insertions, 2 deletions
diff --git a/crates/ra_hir/src/function/scope.rs b/crates/ra_hir/src/function/scope.rs index 863453291..a1a580979 100644 --- a/crates/ra_hir/src/function/scope.rs +++ b/crates/ra_hir/src/function/scope.rs | |||
@@ -1,7 +1,7 @@ | |||
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 | AstNode, SmolStr, SyntaxNodeRef, TextUnit, TextRange, |
5 | algo::generate, | 5 | algo::generate, |
6 | ast::{self, ArgListOwner, LoopBodyOwner, NameOwner}, | 6 | ast::{self, ArgListOwner, LoopBodyOwner, NameOwner}, |
7 | }; | 7 | }; |
@@ -33,7 +33,7 @@ pub struct ScopeData { | |||
33 | } | 33 | } |
34 | 34 | ||
35 | impl FnScopes { | 35 | impl FnScopes { |
36 | pub fn new(fn_def: ast::FnDef) -> FnScopes { | 36 | pub(crate) fn new(fn_def: ast::FnDef) -> FnScopes { |
37 | let mut scopes = FnScopes { | 37 | let mut scopes = FnScopes { |
38 | self_param: fn_def | 38 | self_param: fn_def |
39 | .param_list() | 39 | .param_list() |
@@ -57,6 +57,48 @@ impl FnScopes { | |||
57 | self.scopes[scope].parent | 57 | self.scopes[scope].parent |
58 | }) | 58 | }) |
59 | } | 59 | } |
60 | pub fn scope_chain_for_offset<'a>( | ||
61 | &'a self, | ||
62 | offset: TextUnit, | ||
63 | ) -> impl Iterator<Item = ScopeId> + 'a { | ||
64 | let scope = self | ||
65 | .scope_for | ||
66 | .iter() | ||
67 | // find containin scope | ||
68 | .min_by_key(|(ptr, _scope)| { | ||
69 | ( | ||
70 | !(ptr.range().start() <= offset && offset <= ptr.range().end()), | ||
71 | ptr.range().len(), | ||
72 | ) | ||
73 | }) | ||
74 | .map(|(ptr, scope)| self.adjust(*ptr, *scope, offset)); | ||
75 | |||
76 | generate(scope, move |&scope| self.scopes[scope].parent) | ||
77 | } | ||
78 | // XXX: during completion, cursor might be outside of any particular | ||
79 | // expression. Try to figure out the correct scope... | ||
80 | fn adjust(&self, ptr: LocalSyntaxPtr, original_scope: ScopeId, offset: TextUnit) -> ScopeId { | ||
81 | let r = ptr.range(); | ||
82 | let child_scopes = self | ||
83 | .scope_for | ||
84 | .iter() | ||
85 | .map(|(ptr, scope)| (ptr.range(), scope)) | ||
86 | .filter(|(range, _)| range.start() <= offset && range.is_subrange(&r) && *range != r); | ||
87 | |||
88 | child_scopes | ||
89 | .max_by(|(r1, _), (r2, _)| { | ||
90 | if r2.is_subrange(&r1) { | ||
91 | std::cmp::Ordering::Greater | ||
92 | } else if r1.is_subrange(&r2) { | ||
93 | std::cmp::Ordering::Less | ||
94 | } else { | ||
95 | r1.start().cmp(&r2.start()) | ||
96 | } | ||
97 | }) | ||
98 | .map(|(_ptr, scope)| *scope) | ||
99 | .unwrap_or(original_scope) | ||
100 | } | ||
101 | |||
60 | pub fn resolve_local_name<'a>(&'a self, name_ref: ast::NameRef) -> Option<&'a ScopeEntry> { | 102 | pub fn resolve_local_name<'a>(&'a self, name_ref: ast::NameRef) -> Option<&'a ScopeEntry> { |
61 | let mut shadowed = FxHashSet::default(); | 103 | let mut shadowed = FxHashSet::default(); |
62 | let ret = self | 104 | let ret = self |
@@ -144,6 +186,8 @@ impl ScopeEntry { | |||
144 | } | 186 | } |
145 | 187 | ||
146 | fn compute_block_scopes(block: ast::Block, scopes: &mut FnScopes, mut scope: ScopeId) { | 188 | fn compute_block_scopes(block: ast::Block, scopes: &mut FnScopes, mut scope: ScopeId) { |
189 | // A hack for completion :( | ||
190 | scopes.set_scope(block.syntax(), scope); | ||
147 | for stmt in block.statements() { | 191 | for stmt in block.statements() { |
148 | match stmt { | 192 | match stmt { |
149 | ast::Stmt::LetStmt(stmt) => { | 193 | ast::Stmt::LetStmt(stmt) => { |