diff options
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r-- | crates/ra_hir/src/function.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/function/scope.rs | 48 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/module.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/module/nameres.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/module/nameres/tests.rs | 19 | ||||
-rw-r--r-- | crates/ra_hir/src/path.rs | 21 | ||||
-rw-r--r-- | crates/ra_hir/src/source_binder.rs | 12 |
8 files changed, 99 insertions, 9 deletions
diff --git a/crates/ra_hir/src/function.rs b/crates/ra_hir/src/function.rs index 5187dc051..2925beb16 100644 --- a/crates/ra_hir/src/function.rs +++ b/crates/ra_hir/src/function.rs | |||
@@ -27,7 +27,7 @@ impl Function { | |||
27 | Function { fn_id } | 27 | Function { fn_id } |
28 | } | 28 | } |
29 | 29 | ||
30 | pub fn scope(&self, db: &impl HirDatabase) -> Arc<FnScopes> { | 30 | pub fn scopes(&self, db: &impl HirDatabase) -> Arc<FnScopes> { |
31 | db.fn_scopes(self.fn_id) | 31 | db.fn_scopes(self.fn_id) |
32 | } | 32 | } |
33 | 33 | ||
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) => { |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 5941a9ea3..f56214b47 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -39,7 +39,7 @@ use crate::{ | |||
39 | pub use self::{ | 39 | pub use self::{ |
40 | path::{Path, PathKind}, | 40 | path::{Path, PathKind}, |
41 | krate::Crate, | 41 | krate::Crate, |
42 | module::{Module, ModuleId, Problem, nameres::ItemMap}, | 42 | module::{Module, ModuleId, Problem, nameres::ItemMap, ModuleScope, Resolution}, |
43 | function::{Function, FnScopes}, | 43 | function::{Function, FnScopes}, |
44 | }; | 44 | }; |
45 | 45 | ||
diff --git a/crates/ra_hir/src/module.rs b/crates/ra_hir/src/module.rs index d5866f6ef..cd31e8cfe 100644 --- a/crates/ra_hir/src/module.rs +++ b/crates/ra_hir/src/module.rs | |||
@@ -16,7 +16,7 @@ use crate::{ | |||
16 | arena::{Arena, Id}, | 16 | arena::{Arena, Id}, |
17 | }; | 17 | }; |
18 | 18 | ||
19 | pub use self::nameres::ModuleScope; | 19 | pub use self::nameres::{ModuleScope, Resolution}; |
20 | 20 | ||
21 | /// `Module` is API entry point to get all the information | 21 | /// `Module` is API entry point to get all the information |
22 | /// about a particular module. | 22 | /// about a particular module. |
diff --git a/crates/ra_hir/src/module/nameres.rs b/crates/ra_hir/src/module/nameres.rs index f44abc730..39e891cda 100644 --- a/crates/ra_hir/src/module/nameres.rs +++ b/crates/ra_hir/src/module/nameres.rs | |||
@@ -49,7 +49,7 @@ pub struct ModuleScope { | |||
49 | } | 49 | } |
50 | 50 | ||
51 | impl ModuleScope { | 51 | impl ModuleScope { |
52 | pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a SmolStr, &Resolution)> + 'a { | 52 | pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a SmolStr, &'a Resolution)> + 'a { |
53 | self.items.iter() | 53 | self.items.iter() |
54 | } | 54 | } |
55 | pub fn get(&self, name: &SmolStr) -> Option<&Resolution> { | 55 | pub fn get(&self, name: &SmolStr) -> Option<&Resolution> { |
diff --git a/crates/ra_hir/src/module/nameres/tests.rs b/crates/ra_hir/src/module/nameres/tests.rs index 9fa9146e3..3e29c3954 100644 --- a/crates/ra_hir/src/module/nameres/tests.rs +++ b/crates/ra_hir/src/module/nameres/tests.rs | |||
@@ -44,6 +44,25 @@ fn item_map_smoke_test() { | |||
44 | } | 44 | } |
45 | 45 | ||
46 | #[test] | 46 | #[test] |
47 | fn test_self() { | ||
48 | let (item_map, module_id) = item_map( | ||
49 | " | ||
50 | //- /lib.rs | ||
51 | mod foo; | ||
52 | use crate::foo::bar::Baz::{self}; | ||
53 | <|> | ||
54 | //- /foo/mod.rs | ||
55 | pub mod bar; | ||
56 | //- /foo/bar.rs | ||
57 | pub struct Baz; | ||
58 | ", | ||
59 | ); | ||
60 | let name = SmolStr::from("Baz"); | ||
61 | let resolution = &item_map.per_module[&module_id].items[&name]; | ||
62 | assert!(resolution.def_id.is_some()); | ||
63 | } | ||
64 | |||
65 | #[test] | ||
47 | fn item_map_across_crates() { | 66 | fn item_map_across_crates() { |
48 | let (mut db, sr) = MockDatabase::with_files( | 67 | let (mut db, sr) = MockDatabase::with_files( |
49 | " | 68 | " |
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs index 4a2e427cd..e04d00900 100644 --- a/crates/ra_hir/src/path.rs +++ b/crates/ra_hir/src/path.rs | |||
@@ -76,17 +76,32 @@ fn expand_use_tree( | |||
76 | ) { | 76 | ) { |
77 | if let Some(use_tree_list) = tree.use_tree_list() { | 77 | if let Some(use_tree_list) = tree.use_tree_list() { |
78 | let prefix = match tree.path() { | 78 | let prefix = match tree.path() { |
79 | // E.g. use something::{{{inner}}}; | ||
79 | None => prefix, | 80 | None => prefix, |
81 | // E.g. `use something::{inner}` (prefix is `None`, path is `something`) | ||
82 | // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`) | ||
80 | Some(path) => match convert_path(prefix, path) { | 83 | Some(path) => match convert_path(prefix, path) { |
81 | Some(it) => Some(it), | 84 | Some(it) => Some(it), |
82 | None => return, // TODO: report errors somewhere | 85 | None => return, // TODO: report errors somewhere |
83 | }, | 86 | }, |
84 | }; | 87 | }; |
85 | for tree in use_tree_list.use_trees() { | 88 | for child_tree in use_tree_list.use_trees() { |
86 | expand_use_tree(prefix.clone(), tree, cb); | 89 | expand_use_tree(prefix.clone(), child_tree, cb); |
87 | } | 90 | } |
88 | } else { | 91 | } else { |
89 | if let Some(ast_path) = tree.path() { | 92 | if let Some(ast_path) = tree.path() { |
93 | // Handle self in a path. | ||
94 | // E.g. `use something::{self, <...>}` | ||
95 | if ast_path.qualifier().is_none() { | ||
96 | if let Some(segment) = ast_path.segment() { | ||
97 | if segment.kind() == Some(ast::PathSegmentKind::SelfKw) { | ||
98 | if let Some(prefix) = prefix { | ||
99 | cb(prefix, Some(segment.syntax().range())); | ||
100 | return; | ||
101 | } | ||
102 | } | ||
103 | } | ||
104 | } | ||
90 | if let Some(path) = convert_path(prefix, ast_path) { | 105 | if let Some(path) = convert_path(prefix, ast_path) { |
91 | let range = if tree.has_star() { | 106 | let range = if tree.has_star() { |
92 | None | 107 | None |
@@ -96,6 +111,8 @@ fn expand_use_tree( | |||
96 | }; | 111 | }; |
97 | cb(path, range) | 112 | cb(path, range) |
98 | } | 113 | } |
114 | // TODO: report errors somewhere | ||
115 | // We get here if we do | ||
99 | } | 116 | } |
100 | } | 117 | } |
101 | } | 118 | } |
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index ce2a0f2e8..a0165aef2 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -74,6 +74,16 @@ pub fn function_from_source( | |||
74 | fn_def: ast::FnDef, | 74 | fn_def: ast::FnDef, |
75 | ) -> Cancelable<Option<Function>> { | 75 | ) -> Cancelable<Option<Function>> { |
76 | let module = ctry!(module_from_child_node(db, file_id, fn_def.syntax())?); | 76 | let module = ctry!(module_from_child_node(db, file_id, fn_def.syntax())?); |
77 | let res = function_from_module(db, &module, fn_def); | ||
78 | Ok(Some(res)) | ||
79 | } | ||
80 | |||
81 | pub fn function_from_module( | ||
82 | db: &impl HirDatabase, | ||
83 | module: &Module, | ||
84 | fn_def: ast::FnDef, | ||
85 | ) -> Function { | ||
86 | let file_id = module.source().file_id(); | ||
77 | let file_items = db.file_items(file_id); | 87 | let file_items = db.file_items(file_id); |
78 | let item_id = file_items.id_of(file_id, fn_def.syntax()); | 88 | let item_id = file_items.id_of(file_id, fn_def.syntax()); |
79 | let source_item_id = SourceItemId { | 89 | let source_item_id = SourceItemId { |
@@ -86,7 +96,7 @@ pub fn function_from_source( | |||
86 | module_id: module.module_id, | 96 | module_id: module.module_id, |
87 | source_item_id, | 97 | source_item_id, |
88 | }; | 98 | }; |
89 | Ok(Some(Function::new(def_loc.id(db)))) | 99 | Function::new(def_loc.id(db)) |
90 | } | 100 | } |
91 | 101 | ||
92 | pub fn function_from_child_node( | 102 | pub fn function_from_child_node( |