aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_analysis/src/completion/mod.rs3
-rw-r--r--crates/ra_analysis/src/imp.rs27
-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
7 files changed, 125 insertions, 140 deletions
diff --git a/crates/ra_analysis/src/completion/mod.rs b/crates/ra_analysis/src/completion/mod.rs
index 124da486a..0f154112a 100644
--- a/crates/ra_analysis/src/completion/mod.rs
+++ b/crates/ra_analysis/src/completion/mod.rs
@@ -9,6 +9,7 @@ use ra_syntax::{
9}; 9};
10use ra_db::SyntaxDatabase; 10use ra_db::SyntaxDatabase;
11use rustc_hash::{FxHashMap}; 11use rustc_hash::{FxHashMap};
12use hir::source_binder;
12 13
13use crate::{ 14use crate::{
14 db, 15 db,
@@ -36,7 +37,7 @@ pub(crate) fn completions(
36 original_file.reparse(&edit) 37 original_file.reparse(&edit)
37 }; 38 };
38 39
39 let module = ctry!(hir::Module::guess_from_position(db, position)?); 40 let module = ctry!(source_binder::module_from_position(db, position)?);
40 41
41 let mut res = Vec::new(); 42 let mut res = Vec::new();
42 let mut has_completions = false; 43 let mut has_completions = false;
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs
index ab6d111c2..975afc145 100644
--- a/crates/ra_analysis/src/imp.rs
+++ b/crates/ra_analysis/src/imp.rs
@@ -16,6 +16,7 @@ use rustc_hash::FxHashSet;
16use salsa::{Database, ParallelDatabase}; 16use salsa::{Database, ParallelDatabase};
17use hir::{ 17use hir::{
18 self, 18 self,
19 source_binder,
19 FnSignatureInfo, 20 FnSignatureInfo,
20 Problem, 21 Problem,
21}; 22};
@@ -166,7 +167,7 @@ impl AnalysisImpl {
166 /// This return `Vec`: a module may be included from several places. We 167 /// This return `Vec`: a module may be included from several places. We
167 /// don't handle this case yet though, so the Vec has length at most one. 168 /// don't handle this case yet though, so the Vec has length at most one.
168 pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<(FileId, FileSymbol)>> { 169 pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<(FileId, FileSymbol)>> {
169 let descr = match hir::Module::guess_from_position(&*self.db, position)? { 170 let descr = match source_binder::module_from_position(&*self.db, position)? {
170 None => return Ok(Vec::new()), 171 None => return Ok(Vec::new()),
171 Some(it) => it, 172 Some(it) => it,
172 }; 173 };
@@ -185,7 +186,7 @@ impl AnalysisImpl {
185 } 186 }
186 /// Returns `Vec` for the same reason as `parent_module` 187 /// Returns `Vec` for the same reason as `parent_module`
187 pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> { 188 pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> {
188 let descr = match hir::Module::guess_from_file_id(&*self.db, file_id)? { 189 let descr = match source_binder::module_from_file_id(&*self.db, file_id)? {
189 None => return Ok(Vec::new()), 190 None => return Ok(Vec::new()),
190 Some(it) => it, 191 Some(it) => it,
191 }; 192 };
@@ -209,9 +210,11 @@ impl AnalysisImpl {
209 let file = self.db.source_file(position.file_id); 210 let file = self.db.source_file(position.file_id);
210 let syntax = file.syntax(); 211 let syntax = file.syntax();
211 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) { 212 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) {
212 if let Some(fn_descr) = 213 if let Some(fn_descr) = source_binder::function_from_child_node(
213 hir::Function::guess_for_name_ref(&*self.db, position.file_id, name_ref)? 214 &*self.db,
214 { 215 position.file_id,
216 name_ref.syntax(),
217 )? {
215 let scope = fn_descr.scope(&*self.db); 218 let scope = fn_descr.scope(&*self.db);
216 // First try to resolve the symbol locally 219 // First try to resolve the symbol locally
217 if let Some(entry) = scope.resolve_local_name(name_ref) { 220 if let Some(entry) = scope.resolve_local_name(name_ref) {
@@ -234,7 +237,7 @@ impl AnalysisImpl {
234 if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) { 237 if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) {
235 if module.has_semi() { 238 if module.has_semi() {
236 let parent_module = 239 let parent_module =
237 hir::Module::guess_from_file_id(&*self.db, position.file_id)?; 240 source_binder::module_from_file_id(&*self.db, position.file_id)?;
238 let child_name = module.name(); 241 let child_name = module.name();
239 match (parent_module, child_name) { 242 match (parent_module, child_name) {
240 (Some(parent_module), Some(child_name)) => { 243 (Some(parent_module), Some(child_name)) => {
@@ -282,18 +285,18 @@ impl AnalysisImpl {
282 ) -> Cancelable<Option<(ast::BindPat<'a>, hir::Function)>> { 285 ) -> Cancelable<Option<(ast::BindPat<'a>, hir::Function)>> {
283 let syntax = source_file.syntax(); 286 let syntax = source_file.syntax();
284 if let Some(binding) = find_node_at_offset::<ast::BindPat>(syntax, position.offset) { 287 if let Some(binding) = find_node_at_offset::<ast::BindPat>(syntax, position.offset) {
285 let descr = ctry!(hir::Function::guess_for_bind_pat( 288 let descr = ctry!(source_binder::function_from_child_node(
286 db, 289 db,
287 position.file_id, 290 position.file_id,
288 binding 291 binding.syntax(),
289 )?); 292 )?);
290 return Ok(Some((binding, descr))); 293 return Ok(Some((binding, descr)));
291 }; 294 };
292 let name_ref = ctry!(find_node_at_offset::<ast::NameRef>(syntax, position.offset)); 295 let name_ref = ctry!(find_node_at_offset::<ast::NameRef>(syntax, position.offset));
293 let descr = ctry!(hir::Function::guess_for_name_ref( 296 let descr = ctry!(source_binder::function_from_child_node(
294 db, 297 db,
295 position.file_id, 298 position.file_id,
296 name_ref 299 name_ref.syntax(),
297 )?); 300 )?);
298 let scope = descr.scope(db); 301 let scope = descr.scope(db);
299 let resolved = ctry!(scope.resolve_local_name(name_ref)); 302 let resolved = ctry!(scope.resolve_local_name(name_ref));
@@ -327,7 +330,7 @@ impl AnalysisImpl {
327 fix: None, 330 fix: None,
328 }) 331 })
329 .collect::<Vec<_>>(); 332 .collect::<Vec<_>>();
330 if let Some(m) = hir::Module::guess_from_file_id(&*self.db, file_id)? { 333 if let Some(m) = source_binder::module_from_file_id(&*self.db, file_id)? {
331 for (name_node, problem) in m.problems(&*self.db) { 334 for (name_node, problem) in m.problems(&*self.db) {
332 let diag = match problem { 335 let diag = match problem {
333 Problem::UnresolvedModule { candidate } => { 336 Problem::UnresolvedModule { candidate } => {
@@ -418,7 +421,7 @@ impl AnalysisImpl {
418 if fs.kind == FN_DEF { 421 if fs.kind == FN_DEF {
419 let fn_file = self.db.source_file(fn_file_id); 422 let fn_file = self.db.source_file(fn_file_id);
420 if let Some(fn_def) = find_node_at_offset(fn_file.syntax(), fs.node_range.start()) { 423 if let Some(fn_def) = find_node_at_offset(fn_file.syntax(), fs.node_range.start()) {
421 let descr = ctry!(hir::Function::guess_from_source( 424 let descr = ctry!(source_binder::function_from_source(
422 &*self.db, fn_file_id, fn_def 425 &*self.db, fn_file_id, fn_def
423 )?); 426 )?);
424 if let Some(descriptor) = descr.signature_info(&*self.db) { 427 if let Some(descriptor) = descr.signature_info(&*self.db) {
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}