aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r--crates/ra_hir/src/function/mod.rs52
-rw-r--r--crates/ra_hir/src/lib.rs1
-rw-r--r--crates/ra_hir/src/module/mod.rs82
-rw-r--r--crates/ra_hir/src/module/nameres.rs4
-rw-r--r--crates/ra_hir/src/source_binder.rs96
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
8use ra_syntax::{ 8use ra_syntax::{
9 TextRange, TextUnit, SyntaxNodeRef, 9 TextRange, TextUnit,
10 ast::{self, AstNode, DocCommentsOwner, NameOwner}, 10 ast::{self, AstNode, DocCommentsOwner, NameOwner},
11}; 11};
12use ra_db::FileId;
13 12
14use crate::{ 13use crate::{ DefId, HirDatabase };
15 Cancelable,
16 DefLoc, DefKind, DefId, HirDatabase, SourceItemId,
17 Module,
18};
19 14
20pub use self::scope::FnScopes; 15pub 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;
22mod module; 22mod module;
23mod path; 23mod path;
24mod arena; 24mod arena;
25pub mod source_binder;
25 26
26use std::ops::Index; 27use 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
4use std::sync::Arc; 4use std::sync::Arc;
5 5
6use ra_editor::find_node_at_offset;
7
8use ra_syntax::{ 6use 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};
13use ra_db::{SourceRootId, FileId, FilePosition, Cancelable}; 11use ra_db::{SourceRootId, FileId, Cancelable};
14use relative_path::RelativePathBuf; 12use relative_path::RelativePathBuf;
15 13
16use crate::{ 14use crate::{
@@ -30,68 +28,6 @@ pub struct Module {
30} 28}
31 29
32impl Module { 30impl 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".
8use ra_db::{FileId, FilePosition, Cancelable};
9use ra_editor::find_node_at_offset;
10use ra_syntax::{
11 ast::{self, AstNode},
12 SyntaxNodeRef,
13};
14
15use 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.
22pub 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.
28pub 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
41pub 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
58fn 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
71pub 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
89pub 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}