diff options
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r-- | crates/ra_hir/src/function/mod.rs | 52 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir/src/module/mod.rs | 82 | ||||
-rw-r--r-- | crates/ra_hir/src/module/nameres.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/source_binder.rs | 96 |
5 files changed, 108 insertions, 127 deletions
diff --git a/crates/ra_hir/src/function/mod.rs b/crates/ra_hir/src/function/mod.rs index e00bca6e3..5187dc051 100644 --- a/crates/ra_hir/src/function/mod.rs +++ b/crates/ra_hir/src/function/mod.rs | |||
@@ -6,16 +6,11 @@ use std::{ | |||
6 | }; | 6 | }; |
7 | 7 | ||
8 | use ra_syntax::{ | 8 | use ra_syntax::{ |
9 | TextRange, TextUnit, SyntaxNodeRef, | 9 | TextRange, TextUnit, |
10 | ast::{self, AstNode, DocCommentsOwner, NameOwner}, | 10 | ast::{self, AstNode, DocCommentsOwner, NameOwner}, |
11 | }; | 11 | }; |
12 | use ra_db::FileId; | ||
13 | 12 | ||
14 | use crate::{ | 13 | use crate::{ DefId, HirDatabase }; |
15 | Cancelable, | ||
16 | DefLoc, DefKind, DefId, HirDatabase, SourceItemId, | ||
17 | Module, | ||
18 | }; | ||
19 | 14 | ||
20 | pub use self::scope::FnScopes; | 15 | pub use self::scope::FnScopes; |
21 | 16 | ||
@@ -32,49 +27,6 @@ impl Function { | |||
32 | Function { fn_id } | 27 | Function { fn_id } |
33 | } | 28 | } |
34 | 29 | ||
35 | pub fn guess_from_source( | ||
36 | db: &impl HirDatabase, | ||
37 | file_id: FileId, | ||
38 | fn_def: ast::FnDef, | ||
39 | ) -> Cancelable<Option<Function>> { | ||
40 | let module = ctry!(Module::guess_from_child_node(db, file_id, fn_def.syntax())?); | ||
41 | let file_items = db.file_items(file_id); | ||
42 | let item_id = file_items.id_of(fn_def.syntax()); | ||
43 | let source_item_id = SourceItemId { file_id, item_id }; | ||
44 | let def_loc = DefLoc { | ||
45 | kind: DefKind::Function, | ||
46 | source_root_id: module.source_root_id, | ||
47 | module_id: module.module_id, | ||
48 | source_item_id, | ||
49 | }; | ||
50 | Ok(Some(Function::new(def_loc.id(db)))) | ||
51 | } | ||
52 | |||
53 | pub fn guess_for_name_ref( | ||
54 | db: &impl HirDatabase, | ||
55 | file_id: FileId, | ||
56 | name_ref: ast::NameRef, | ||
57 | ) -> Cancelable<Option<Function>> { | ||
58 | Function::guess_for_node(db, file_id, name_ref.syntax()) | ||
59 | } | ||
60 | |||
61 | pub fn guess_for_bind_pat( | ||
62 | db: &impl HirDatabase, | ||
63 | file_id: FileId, | ||
64 | bind_pat: ast::BindPat, | ||
65 | ) -> Cancelable<Option<Function>> { | ||
66 | Function::guess_for_node(db, file_id, bind_pat.syntax()) | ||
67 | } | ||
68 | |||
69 | fn guess_for_node( | ||
70 | db: &impl HirDatabase, | ||
71 | file_id: FileId, | ||
72 | node: SyntaxNodeRef, | ||
73 | ) -> Cancelable<Option<Function>> { | ||
74 | let fn_def = ctry!(node.ancestors().find_map(ast::FnDef::cast)); | ||
75 | Function::guess_from_source(db, file_id, fn_def) | ||
76 | } | ||
77 | |||
78 | pub fn scope(&self, db: &impl HirDatabase) -> Arc<FnScopes> { | 30 | pub fn scope(&self, db: &impl HirDatabase) -> Arc<FnScopes> { |
79 | db.fn_scopes(self.fn_id) | 31 | db.fn_scopes(self.fn_id) |
80 | } | 32 | } |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 9168dad3b..983ce99cb 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -22,6 +22,7 @@ mod function; | |||
22 | mod module; | 22 | mod module; |
23 | mod path; | 23 | mod path; |
24 | mod arena; | 24 | mod arena; |
25 | pub mod source_binder; | ||
25 | 26 | ||
26 | use std::ops::Index; | 27 | use std::ops::Index; |
27 | 28 | ||
diff --git a/crates/ra_hir/src/module/mod.rs b/crates/ra_hir/src/module/mod.rs index 11e6e8e75..580c737c3 100644 --- a/crates/ra_hir/src/module/mod.rs +++ b/crates/ra_hir/src/module/mod.rs | |||
@@ -3,14 +3,12 @@ pub(super) mod nameres; | |||
3 | 3 | ||
4 | use std::sync::Arc; | 4 | use std::sync::Arc; |
5 | 5 | ||
6 | use ra_editor::find_node_at_offset; | ||
7 | |||
8 | use ra_syntax::{ | 6 | use ra_syntax::{ |
9 | algo::generate, | 7 | algo::generate, |
10 | ast::{self, AstNode, NameOwner}, | 8 | ast::{self, AstNode, NameOwner}, |
11 | SmolStr, SyntaxNode, SyntaxNodeRef, | 9 | SmolStr, SyntaxNode, |
12 | }; | 10 | }; |
13 | use ra_db::{SourceRootId, FileId, FilePosition, Cancelable}; | 11 | use ra_db::{SourceRootId, FileId, Cancelable}; |
14 | use relative_path::RelativePathBuf; | 12 | use relative_path::RelativePathBuf; |
15 | 13 | ||
16 | use crate::{ | 14 | use crate::{ |
@@ -30,68 +28,6 @@ pub struct Module { | |||
30 | } | 28 | } |
31 | 29 | ||
32 | impl Module { | 30 | impl Module { |
33 | /// Lookup `Module` by `FileId`. Note that this is inherently | ||
34 | /// lossy transformation: in general, a single source might correspond to | ||
35 | /// several modules. | ||
36 | pub fn guess_from_file_id( | ||
37 | db: &impl HirDatabase, | ||
38 | file_id: FileId, | ||
39 | ) -> Cancelable<Option<Module>> { | ||
40 | let module_source = ModuleSource::new_file(db, file_id); | ||
41 | Module::guess_from_source(db, module_source) | ||
42 | } | ||
43 | |||
44 | /// Lookup `Module` by position in the source code. Note that this | ||
45 | /// is inherently lossy transformation: in general, a single source might | ||
46 | /// correspond to several modules. | ||
47 | pub fn guess_from_position( | ||
48 | db: &impl HirDatabase, | ||
49 | position: FilePosition, | ||
50 | ) -> Cancelable<Option<Module>> { | ||
51 | let file = db.source_file(position.file_id); | ||
52 | let module_source = match find_node_at_offset::<ast::Module>(file.syntax(), position.offset) | ||
53 | { | ||
54 | Some(m) if !m.has_semi() => ModuleSource::new_inline(db, position.file_id, m), | ||
55 | _ => ModuleSource::new_file(db, position.file_id), | ||
56 | }; | ||
57 | Module::guess_from_source(db, module_source) | ||
58 | } | ||
59 | |||
60 | pub fn guess_from_child_node( | ||
61 | db: &impl HirDatabase, | ||
62 | file_id: FileId, | ||
63 | node: SyntaxNodeRef, | ||
64 | ) -> Cancelable<Option<Module>> { | ||
65 | let module_source = if let Some(m) = node | ||
66 | .ancestors() | ||
67 | .filter_map(ast::Module::cast) | ||
68 | .find(|it| !it.has_semi()) | ||
69 | { | ||
70 | ModuleSource::new_inline(db, file_id, m) | ||
71 | } else { | ||
72 | ModuleSource::new_file(db, file_id) | ||
73 | }; | ||
74 | Module::guess_from_source(db, module_source) | ||
75 | } | ||
76 | |||
77 | fn guess_from_source( | ||
78 | db: &impl HirDatabase, | ||
79 | module_source: ModuleSource, | ||
80 | ) -> Cancelable<Option<Module>> { | ||
81 | let source_root_id = db.file_source_root(module_source.file_id()); | ||
82 | let module_tree = db.module_tree(source_root_id)?; | ||
83 | |||
84 | let res = match module_tree.any_module_for_source(module_source) { | ||
85 | None => None, | ||
86 | Some(module_id) => Some(Module { | ||
87 | tree: module_tree, | ||
88 | source_root_id, | ||
89 | module_id, | ||
90 | }), | ||
91 | }; | ||
92 | Ok(res) | ||
93 | } | ||
94 | |||
95 | pub(super) fn new( | 31 | pub(super) fn new( |
96 | db: &impl HirDatabase, | 32 | db: &impl HirDatabase, |
97 | source_root_id: SourceRootId, | 33 | source_root_id: SourceRootId, |
@@ -217,16 +153,10 @@ impl ModuleTree { | |||
217 | self.mods.iter().map(|(id, _)| id) | 153 | self.mods.iter().map(|(id, _)| id) |
218 | } | 154 | } |
219 | 155 | ||
220 | fn modules_for_source(&self, source: ModuleSource) -> Vec<ModuleId> { | 156 | pub(crate) fn modules_with_sources<'a>( |
221 | self.mods | 157 | &'a self, |
222 | .iter() | 158 | ) -> impl Iterator<Item = (ModuleId, ModuleSource)> + 'a { |
223 | .filter(|(_idx, it)| it.source == source) | 159 | self.mods.iter().map(|(id, m)| (id, m.source)) |
224 | .map(|(idx, _)| idx) | ||
225 | .collect() | ||
226 | } | ||
227 | |||
228 | fn any_module_for_source(&self, source: ModuleSource) -> Option<ModuleId> { | ||
229 | self.modules_for_source(source).pop() | ||
230 | } | 160 | } |
231 | } | 161 | } |
232 | 162 | ||
diff --git a/crates/ra_hir/src/module/nameres.rs b/crates/ra_hir/src/module/nameres.rs index c2b380a80..61a1acfe6 100644 --- a/crates/ra_hir/src/module/nameres.rs +++ b/crates/ra_hir/src/module/nameres.rs | |||
@@ -363,7 +363,9 @@ mod tests { | |||
363 | fn item_map(fixture: &str) -> (Arc<hir::ItemMap>, hir::ModuleId) { | 363 | fn item_map(fixture: &str) -> (Arc<hir::ItemMap>, hir::ModuleId) { |
364 | let (db, pos) = MockDatabase::with_position(fixture); | 364 | let (db, pos) = MockDatabase::with_position(fixture); |
365 | let source_root = db.file_source_root(pos.file_id); | 365 | let source_root = db.file_source_root(pos.file_id); |
366 | let module = hir::Module::guess_from_position(&db, pos).unwrap().unwrap(); | 366 | let module = hir::source_binder::module_from_position(&db, pos) |
367 | .unwrap() | ||
368 | .unwrap(); | ||
367 | let module_id = module.module_id; | 369 | let module_id = module.module_id; |
368 | (db.item_map(source_root).unwrap(), module_id) | 370 | (db.item_map(source_root).unwrap(), module_id) |
369 | } | 371 | } |
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs new file mode 100644 index 000000000..479155805 --- /dev/null +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -0,0 +1,96 @@ | |||
1 | /// Lookup hir elements using position in the source code. This is a lossy | ||
2 | /// transformation: in general, a single source might correspond to several | ||
3 | /// modules, functions, etc, due to macros, cfgs and `#[path=]` attributes on | ||
4 | /// modules. | ||
5 | /// | ||
6 | /// So, this modules should not be used during hir construction, it exists | ||
7 | /// purely for "IDE needs". | ||
8 | use ra_db::{FileId, FilePosition, Cancelable}; | ||
9 | use ra_editor::find_node_at_offset; | ||
10 | use ra_syntax::{ | ||
11 | ast::{self, AstNode}, | ||
12 | SyntaxNodeRef, | ||
13 | }; | ||
14 | |||
15 | use crate::{ | ||
16 | HirDatabase, Module, Function, SourceItemId, | ||
17 | module::ModuleSource, | ||
18 | DefKind, DefLoc | ||
19 | }; | ||
20 | |||
21 | /// Locates the module by `FileId`. Picks topmost module in the file. | ||
22 | pub fn module_from_file_id(db: &impl HirDatabase, file_id: FileId) -> Cancelable<Option<Module>> { | ||
23 | let module_source = ModuleSource::new_file(db, file_id); | ||
24 | module_from_source(db, module_source) | ||
25 | } | ||
26 | |||
27 | /// Locates the module by position in the source code. | ||
28 | pub fn module_from_position( | ||
29 | db: &impl HirDatabase, | ||
30 | position: FilePosition, | ||
31 | ) -> Cancelable<Option<Module>> { | ||
32 | let file = db.source_file(position.file_id); | ||
33 | let module_source = match find_node_at_offset::<ast::Module>(file.syntax(), position.offset) { | ||
34 | Some(m) if !m.has_semi() => ModuleSource::new_inline(db, position.file_id, m), | ||
35 | _ => ModuleSource::new_file(db, position.file_id), | ||
36 | }; | ||
37 | module_from_source(db, module_source) | ||
38 | } | ||
39 | |||
40 | /// Locates the module by child syntax element within the module | ||
41 | pub fn module_from_child_node( | ||
42 | db: &impl HirDatabase, | ||
43 | file_id: FileId, | ||
44 | child: SyntaxNodeRef, | ||
45 | ) -> Cancelable<Option<Module>> { | ||
46 | let module_source = if let Some(m) = child | ||
47 | .ancestors() | ||
48 | .filter_map(ast::Module::cast) | ||
49 | .find(|it| !it.has_semi()) | ||
50 | { | ||
51 | ModuleSource::new_inline(db, file_id, m) | ||
52 | } else { | ||
53 | ModuleSource::new_file(db, file_id) | ||
54 | }; | ||
55 | module_from_source(db, module_source) | ||
56 | } | ||
57 | |||
58 | fn module_from_source( | ||
59 | db: &impl HirDatabase, | ||
60 | module_source: ModuleSource, | ||
61 | ) -> Cancelable<Option<Module>> { | ||
62 | let source_root_id = db.file_source_root(module_source.file_id()); | ||
63 | let module_tree = db.module_tree(source_root_id)?; | ||
64 | let m = module_tree | ||
65 | .modules_with_sources() | ||
66 | .find(|(_id, src)| src == &module_source); | ||
67 | let module_id = ctry!(m).0; | ||
68 | Ok(Some(Module::new(db, source_root_id, module_id)?)) | ||
69 | } | ||
70 | |||
71 | pub fn function_from_source( | ||
72 | db: &impl HirDatabase, | ||
73 | file_id: FileId, | ||
74 | fn_def: ast::FnDef, | ||
75 | ) -> Cancelable<Option<Function>> { | ||
76 | let module = ctry!(module_from_child_node(db, file_id, fn_def.syntax())?); | ||
77 | let file_items = db.file_items(file_id); | ||
78 | let item_id = file_items.id_of(fn_def.syntax()); | ||
79 | let source_item_id = SourceItemId { file_id, item_id }; | ||
80 | let def_loc = DefLoc { | ||
81 | kind: DefKind::Function, | ||
82 | source_root_id: module.source_root_id, | ||
83 | module_id: module.module_id, | ||
84 | source_item_id, | ||
85 | }; | ||
86 | Ok(Some(Function::new(def_loc.id(db)))) | ||
87 | } | ||
88 | |||
89 | pub fn function_from_child_node( | ||
90 | db: &impl HirDatabase, | ||
91 | file_id: FileId, | ||
92 | node: SyntaxNodeRef, | ||
93 | ) -> Cancelable<Option<Function>> { | ||
94 | let fn_def = ctry!(node.ancestors().find_map(ast::FnDef::cast)); | ||
95 | function_from_source(db, file_id, fn_def) | ||
96 | } | ||