aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir')
-rw-r--r--crates/ra_hir/src/function.rs2
-rw-r--r--crates/ra_hir/src/function/scope.rs48
-rw-r--r--crates/ra_hir/src/lib.rs2
-rw-r--r--crates/ra_hir/src/module.rs2
-rw-r--r--crates/ra_hir/src/module/nameres.rs2
-rw-r--r--crates/ra_hir/src/module/nameres/tests.rs19
-rw-r--r--crates/ra_hir/src/path.rs21
-rw-r--r--crates/ra_hir/src/source_binder.rs12
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 @@
1use rustc_hash::{FxHashMap, FxHashSet}; 1use rustc_hash::{FxHashMap, FxHashSet};
2 2
3use ra_syntax::{ 3use 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
35impl FnScopes { 35impl 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
146fn compute_block_scopes(block: ast::Block, scopes: &mut FnScopes, mut scope: ScopeId) { 188fn 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::{
39pub use self::{ 39pub 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
19pub use self::nameres::ModuleScope; 19pub 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
51impl ModuleScope { 51impl 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]
47fn 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]
47fn item_map_across_crates() { 66fn 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
81pub 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
92pub fn function_from_child_node( 102pub fn function_from_child_node(