aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir')
-rw-r--r--crates/ra_hir/src/db.rs4
-rw-r--r--crates/ra_hir/src/function/mod.rs51
-rw-r--r--crates/ra_hir/src/lib.rs62
-rw-r--r--crates/ra_hir/src/mock.rs9
-rw-r--r--crates/ra_hir/src/module/imp.rs13
-rw-r--r--crates/ra_hir/src/module/mod.rs141
-rw-r--r--crates/ra_hir/src/module/nameres.rs27
-rw-r--r--crates/ra_hir/src/query_definitions.rs25
-rw-r--r--crates/ra_hir/src/source_binder.rs96
9 files changed, 216 insertions, 212 deletions
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index 2f01bae6d..ff41fd326 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -7,10 +7,11 @@ use ra_syntax::{
7use ra_db::{SourceRootId, LocationIntener, SyntaxDatabase, FileId, Cancelable}; 7use ra_db::{SourceRootId, LocationIntener, SyntaxDatabase, FileId, Cancelable};
8 8
9use crate::{ 9use crate::{
10 DefLoc, DefId, FnId, 10 DefLoc, DefId,
11 SourceFileItems, SourceItemId, 11 SourceFileItems, SourceItemId,
12 query_definitions, 12 query_definitions,
13 FnScopes, 13 FnScopes,
14 function::FnId,
14 module::{ModuleId, ModuleTree, ModuleSource, 15 module::{ModuleId, ModuleTree, ModuleSource,
15 nameres::{ItemMap, InputModuleItems}}, 16 nameres::{ItemMap, InputModuleItems}},
16}; 17};
@@ -19,7 +20,6 @@ salsa::query_group! {
19 20
20pub trait HirDatabase: SyntaxDatabase 21pub trait HirDatabase: SyntaxDatabase
21 + AsRef<LocationIntener<DefLoc, DefId>> 22 + AsRef<LocationIntener<DefLoc, DefId>>
22 + AsRef<LocationIntener<SourceItemId, FnId>>
23{ 23{
24 fn fn_scopes(fn_id: FnId) -> Arc<FnScopes> { 24 fn fn_scopes(fn_id: FnId) -> Arc<FnScopes> {
25 type FnScopesQuery; 25 type FnScopesQuery;
diff --git a/crates/ra_hir/src/function/mod.rs b/crates/ra_hir/src/function/mod.rs
index c8af2e54f..5187dc051 100644
--- a/crates/ra_hir/src/function/mod.rs
+++ b/crates/ra_hir/src/function/mod.rs
@@ -6,66 +6,27 @@ 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 FnId, HirDatabase, SourceItemId,
16};
17 14
18pub use self::scope::FnScopes; 15pub use self::scope::FnScopes;
19 16
20impl FnId { 17#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
21 pub fn get(db: &impl HirDatabase, file_id: FileId, fn_def: ast::FnDef) -> FnId { 18pub struct FnId(pub(crate) DefId);
22 let file_items = db.file_items(file_id);
23 let item_id = file_items.id_of(fn_def.syntax());
24 let item_id = SourceItemId { file_id, item_id };
25 FnId::from_loc(db, &item_id)
26 }
27}
28 19
29pub struct Function { 20pub struct Function {
30 fn_id: FnId, 21 fn_id: FnId,
31} 22}
32 23
33impl Function { 24impl Function {
34 pub fn guess_from_source( 25 pub(crate) fn new(def_id: DefId) -> Function {
35 db: &impl HirDatabase, 26 let fn_id = FnId(def_id);
36 file_id: FileId,
37 fn_def: ast::FnDef,
38 ) -> Function {
39 let fn_id = FnId::get(db, file_id, fn_def);
40 Function { fn_id } 27 Function { fn_id }
41 } 28 }
42 29
43 pub fn guess_for_name_ref(
44 db: &impl HirDatabase,
45 file_id: FileId,
46 name_ref: ast::NameRef,
47 ) -> Option<Function> {
48 Function::guess_for_node(db, file_id, name_ref.syntax())
49 }
50
51 pub fn guess_for_bind_pat(
52 db: &impl HirDatabase,
53 file_id: FileId,
54 bind_pat: ast::BindPat,
55 ) -> Option<Function> {
56 Function::guess_for_node(db, file_id, bind_pat.syntax())
57 }
58
59 fn guess_for_node(
60 db: &impl HirDatabase,
61 file_id: FileId,
62 node: SyntaxNodeRef,
63 ) -> Option<Function> {
64 let fn_def = node.ancestors().find_map(ast::FnDef::cast)?;
65 let res = Function::guess_from_source(db, file_id, fn_def);
66 Some(res)
67 }
68
69 pub fn scope(&self, db: &impl HirDatabase) -> Arc<FnScopes> { 30 pub fn scope(&self, db: &impl HirDatabase) -> Arc<FnScopes> {
70 db.fn_scopes(self.fn_id) 31 db.fn_scopes(self.fn_id)
71 } 32 }
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index e7b6a81f4..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
@@ -41,63 +42,58 @@ pub use self::{
41 42
42pub use self::function::FnSignatureInfo; 43pub use self::function::FnSignatureInfo;
43 44
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 45/// Def's are a core concept of hir. A `Def` is an Item (function, module, etc)
45pub struct FnId(u32); 46/// in a specific module.
46ra_db::impl_numeric_id!(FnId);
47
48impl FnId {
49 pub fn from_loc(
50 db: &impl AsRef<LocationIntener<SourceItemId, FnId>>,
51 loc: &SourceItemId,
52 ) -> FnId {
53 db.as_ref().loc2id(loc)
54 }
55 pub fn loc(self, db: &impl AsRef<LocationIntener<SourceItemId, FnId>>) -> SourceItemId {
56 db.as_ref().id2loc(self)
57 }
58}
59
60#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 47#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
61pub struct DefId(u32); 48pub struct DefId(u32);
62ra_db::impl_numeric_id!(DefId); 49ra_db::impl_numeric_id!(DefId);
63 50
51#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
52pub(crate) enum DefKind {
53 Module,
54 Function,
55 Item,
56}
57
64#[derive(Clone, Debug, PartialEq, Eq, Hash)] 58#[derive(Clone, Debug, PartialEq, Eq, Hash)]
65pub enum DefLoc { 59pub struct DefLoc {
66 Module { 60 pub(crate) kind: DefKind,
67 id: ModuleId, 61 source_root_id: SourceRootId,
68 source_root: SourceRootId, 62 module_id: ModuleId,
69 }, 63 source_item_id: SourceItemId,
70 Item {
71 source_item_id: SourceItemId,
72 },
73} 64}
74 65
75impl DefId { 66impl DefId {
76 pub fn loc(self, db: &impl AsRef<LocationIntener<DefLoc, DefId>>) -> DefLoc { 67 pub(crate) fn loc(self, db: &impl AsRef<LocationIntener<DefLoc, DefId>>) -> DefLoc {
77 db.as_ref().id2loc(self) 68 db.as_ref().id2loc(self)
78 } 69 }
79} 70}
80 71
81impl DefLoc { 72impl DefLoc {
82 pub fn id(&self, db: &impl AsRef<LocationIntener<DefLoc, DefId>>) -> DefId { 73 pub(crate) fn id(&self, db: &impl AsRef<LocationIntener<DefLoc, DefId>>) -> DefId {
83 db.as_ref().loc2id(&self) 74 db.as_ref().loc2id(&self)
84 } 75 }
85} 76}
86 77
87pub enum Def { 78pub enum Def {
88 Module(Module), 79 Module(Module),
80 Function(Function),
89 Item, 81 Item,
90} 82}
91 83
92impl DefId { 84impl DefId {
93 pub fn resolve(self, db: &impl HirDatabase) -> Cancelable<Def> { 85 pub fn resolve(self, db: &impl HirDatabase) -> Cancelable<Def> {
94 let loc = self.loc(db); 86 let loc = self.loc(db);
95 let res = match loc { 87 let res = match loc.kind {
96 DefLoc::Module { id, source_root } => { 88 DefKind::Module => {
97 let descr = Module::new(db, source_root, id)?; 89 let module = Module::new(db, loc.source_root_id, loc.module_id)?;
98 Def::Module(descr) 90 Def::Module(module)
99 } 91 }
100 DefLoc::Item { .. } => Def::Item, 92 DefKind::Function => {
93 let function = Function::new(self);
94 Def::Function(function)
95 }
96 DefKind::Item => Def::Item,
101 }; 97 };
102 Ok(res) 98 Ok(res)
103 } 99 }
@@ -131,6 +127,10 @@ impl SourceFileItems {
131 .unwrap(); 127 .unwrap();
132 id 128 id
133 } 129 }
130 pub fn id_of_source_file(&self) -> SourceFileItemId {
131 let (id, _syntax) = self.arena.iter().next().unwrap();
132 id
133 }
134} 134}
135 135
136impl Index<SourceFileItemId> for SourceFileItems { 136impl Index<SourceFileItemId> for SourceFileItems {
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs
index 8e256b89f..e855df11d 100644
--- a/crates/ra_hir/src/mock.rs
+++ b/crates/ra_hir/src/mock.rs
@@ -6,7 +6,7 @@ use ra_db::{LocationIntener, BaseDatabase, FilePosition, mock::FileMap, FileId,
6use relative_path::RelativePathBuf; 6use relative_path::RelativePathBuf;
7use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset}; 7use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset};
8 8
9use crate::{db, DefId, DefLoc, FnId, SourceItemId}; 9use crate::{db, DefId, DefLoc};
10 10
11#[derive(Debug)] 11#[derive(Debug)]
12pub(crate) struct MockDatabase { 12pub(crate) struct MockDatabase {
@@ -65,7 +65,6 @@ impl MockDatabase {
65 65
66#[derive(Debug, Default)] 66#[derive(Debug, Default)]
67struct IdMaps { 67struct IdMaps {
68 fns: LocationIntener<SourceItemId, FnId>,
69 defs: LocationIntener<DefLoc, DefId>, 68 defs: LocationIntener<DefLoc, DefId>,
70} 69}
71 70
@@ -117,12 +116,6 @@ impl AsRef<LocationIntener<DefLoc, DefId>> for MockDatabase {
117 } 116 }
118} 117}
119 118
120impl AsRef<LocationIntener<SourceItemId, FnId>> for MockDatabase {
121 fn as_ref(&self) -> &LocationIntener<SourceItemId, FnId> {
122 &self.id_maps.fns
123 }
124}
125
126impl MockDatabase { 119impl MockDatabase {
127 pub(crate) fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event<MockDatabase>> { 120 pub(crate) fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event<MockDatabase>> {
128 *self.events.lock() = Some(Vec::new()); 121 *self.events.lock() = Some(Vec::new());
diff --git a/crates/ra_hir/src/module/imp.rs b/crates/ra_hir/src/module/imp.rs
index 76ea129a7..0eec38797 100644
--- a/crates/ra_hir/src/module/imp.rs
+++ b/crates/ra_hir/src/module/imp.rs
@@ -66,7 +66,7 @@ fn create_module_tree<'a>(
66 66
67 let source_root = db.source_root(source_root); 67 let source_root = db.source_root(source_root);
68 for &file_id in source_root.files.iter() { 68 for &file_id in source_root.files.iter() {
69 let source = ModuleSource::SourceFile(file_id); 69 let source = ModuleSource::new_file(db, file_id);
70 if visited.contains(&source) { 70 if visited.contains(&source) {
71 continue; // TODO: use explicit crate_roots here 71 continue; // TODO: use explicit crate_roots here
72 } 72 }
@@ -126,7 +126,7 @@ fn build_subtree(
126 visited, 126 visited,
127 roots, 127 roots,
128 Some(link), 128 Some(link),
129 ModuleSource::SourceFile(file_id), 129 ModuleSource::new_file(db, file_id),
130 ), 130 ),
131 }) 131 })
132 .collect::<Cancelable<Vec<_>>>()?; 132 .collect::<Cancelable<Vec<_>>>()?;
@@ -157,13 +157,8 @@ fn resolve_submodule(
157 name: &SmolStr, 157 name: &SmolStr,
158 file_resolver: &FileResolverImp, 158 file_resolver: &FileResolverImp,
159) -> (Vec<FileId>, Option<Problem>) { 159) -> (Vec<FileId>, Option<Problem>) {
160 let file_id = match source { 160 // TODO: handle submodules of inline modules properly
161 ModuleSource::SourceFile(it) => it, 161 let file_id = source.file_id();
162 ModuleSource::Module(..) => {
163 // TODO
164 return (Vec::new(), None);
165 }
166 };
167 let mod_name = file_resolver.file_stem(file_id); 162 let mod_name = file_resolver.file_stem(file_id);
168 let is_dir_owner = mod_name == "mod" || mod_name == "lib" || mod_name == "main"; 163 let is_dir_owner = mod_name == "mod" || mod_name == "lib" || mod_name == "main";
169 164
diff --git a/crates/ra_hir/src/module/mod.rs b/crates/ra_hir/src/module/mod.rs
index 3ae83d8cb..580c737c3 100644
--- a/crates/ra_hir/src/module/mod.rs
+++ b/crates/ra_hir/src/module/mod.rs
@@ -3,18 +3,16 @@ 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, 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::{
17 DefLoc, DefId, Path, PathKind, HirDatabase, SourceItemId, 15 DefKind, DefLoc, DefId, Path, PathKind, HirDatabase, SourceItemId, SourceFileItemId,
18 arena::{Arena, Id}, 16 arena::{Arena, Id},
19}; 17};
20 18
@@ -25,56 +23,11 @@ pub use self::nameres::ModuleScope;
25#[derive(Debug, Clone)] 23#[derive(Debug, Clone)]
26pub struct Module { 24pub struct Module {
27 tree: Arc<ModuleTree>, 25 tree: Arc<ModuleTree>,
28 source_root_id: SourceRootId, 26 pub(crate) source_root_id: SourceRootId,
29 module_id: ModuleId, 27 pub(crate) module_id: ModuleId,
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 Module::guess_from_source(db, file_id, ModuleSource::SourceFile(file_id))
41 }
42
43 /// Lookup `Module` by position in the source code. Note that this
44 /// is inherently lossy transformation: in general, a single source might
45 /// correspond to several modules.
46 pub fn guess_from_position(
47 db: &impl HirDatabase,
48 position: FilePosition,
49 ) -> Cancelable<Option<Module>> {
50 let file = db.source_file(position.file_id);
51 let module_source = match find_node_at_offset::<ast::Module>(file.syntax(), position.offset)
52 {
53 Some(m) if !m.has_semi() => ModuleSource::new_inline(db, position.file_id, m),
54 _ => ModuleSource::SourceFile(position.file_id),
55 };
56 Module::guess_from_source(db, position.file_id, module_source)
57 }
58
59 fn guess_from_source(
60 db: &impl HirDatabase,
61 file_id: FileId,
62 module_source: ModuleSource,
63 ) -> Cancelable<Option<Module>> {
64 let source_root_id = db.file_source_root(file_id);
65 let module_tree = db.module_tree(source_root_id)?;
66
67 let res = match module_tree.any_module_for_source(module_source) {
68 None => None,
69 Some(module_id) => Some(Module {
70 tree: module_tree,
71 source_root_id,
72 module_id,
73 }),
74 };
75 Ok(res)
76 }
77
78 pub(super) fn new( 31 pub(super) fn new(
79 db: &impl HirDatabase, 32 db: &impl HirDatabase,
80 source_root_id: SourceRootId, 33 source_root_id: SourceRootId,
@@ -127,9 +80,11 @@ impl Module {
127 } 80 }
128 81
129 pub fn def_id(&self, db: &impl HirDatabase) -> DefId { 82 pub fn def_id(&self, db: &impl HirDatabase) -> DefId {
130 let def_loc = DefLoc::Module { 83 let def_loc = DefLoc {
131 id: self.module_id, 84 kind: DefKind::Module,
132 source_root: self.source_root_id, 85 source_root_id: self.source_root_id,
86 module_id: self.module_id,
87 source_item_id: self.module_id.source(&self.tree).0,
133 }; 88 };
134 def_loc.id(db) 89 def_loc.id(db)
135 } 90 }
@@ -161,7 +116,12 @@ impl Module {
161 let segments = path.segments; 116 let segments = path.segments;
162 for name in segments.iter() { 117 for name in segments.iter() {
163 let module = match curr.loc(db) { 118 let module = match curr.loc(db) {
164 DefLoc::Module { id, source_root } => Module::new(db, source_root, id)?, 119 DefLoc {
120 kind: DefKind::Module,
121 source_root_id,
122 module_id,
123 ..
124 } => Module::new(db, source_root_id, module_id)?,
165 _ => return Ok(None), 125 _ => return Ok(None),
166 }; 126 };
167 let scope = module.scope(db)?; 127 let scope = module.scope(db)?;
@@ -193,26 +153,17 @@ impl ModuleTree {
193 self.mods.iter().map(|(id, _)| id) 153 self.mods.iter().map(|(id, _)| id)
194 } 154 }
195 155
196 fn modules_for_source(&self, source: ModuleSource) -> Vec<ModuleId> { 156 pub(crate) fn modules_with_sources<'a>(
197 self.mods 157 &'a self,
198 .iter() 158 ) -> impl Iterator<Item = (ModuleId, ModuleSource)> + 'a {
199 .filter(|(_idx, it)| it.source == source) 159 self.mods.iter().map(|(id, m)| (id, m.source))
200 .map(|(idx, _)| idx)
201 .collect()
202 }
203
204 fn any_module_for_source(&self, source: ModuleSource) -> Option<ModuleId> {
205 self.modules_for_source(source).pop()
206 } 160 }
207} 161}
208 162
209/// `ModuleSource` is the syntax tree element that produced this module: 163/// `ModuleSource` is the syntax tree element that produced this module:
210/// either a file, or an inlinde module. 164/// either a file, or an inlinde module.
211#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 165#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
212pub enum ModuleSource { 166pub struct ModuleSource(SourceItemId);
213 SourceFile(FileId),
214 Module(SourceItemId),
215}
216 167
217/// An owned syntax node for a module. Unlike `ModuleSource`, 168/// An owned syntax node for a module. Unlike `ModuleSource`,
218/// this holds onto the AST for the whole file. 169/// this holds onto the AST for the whole file.
@@ -310,45 +261,41 @@ pub struct ModuleData {
310} 261}
311 262
312impl ModuleSource { 263impl ModuleSource {
264 // precondition: item_id **must** point to module
265 fn new(file_id: FileId, item_id: SourceFileItemId) -> ModuleSource {
266 let source_item_id = SourceItemId { file_id, item_id };
267 ModuleSource(source_item_id)
268 }
269
270 pub(crate) fn new_file(db: &impl HirDatabase, file_id: FileId) -> ModuleSource {
271 let file_items = db.file_items(file_id);
272 let item_id = file_items.id_of_source_file();
273 ModuleSource::new(file_id, item_id)
274 }
275
313 pub(crate) fn new_inline( 276 pub(crate) fn new_inline(
314 db: &impl HirDatabase, 277 db: &impl HirDatabase,
315 file_id: FileId, 278 file_id: FileId,
316 module: ast::Module, 279 m: ast::Module,
317 ) -> ModuleSource { 280 ) -> ModuleSource {
318 assert!(!module.has_semi()); 281 assert!(!m.has_semi());
319 let items = db.file_items(file_id); 282 let file_items = db.file_items(file_id);
320 let item_id = items.id_of(module.syntax()); 283 let item_id = file_items.id_of(m.syntax());
321 let id = SourceItemId { file_id, item_id }; 284 ModuleSource::new(file_id, item_id)
322 ModuleSource::Module(id)
323 }
324
325 pub fn as_file(self) -> Option<FileId> {
326 match self {
327 ModuleSource::SourceFile(f) => Some(f),
328 ModuleSource::Module(..) => None,
329 }
330 } 285 }
331 286
332 pub fn file_id(self) -> FileId { 287 pub fn file_id(self) -> FileId {
333 match self { 288 self.0.file_id
334 ModuleSource::SourceFile(f) => f,
335 ModuleSource::Module(source_item_id) => source_item_id.file_id,
336 }
337 } 289 }
338 290
339 pub(crate) fn resolve(self, db: &impl HirDatabase) -> ModuleSourceNode { 291 pub(crate) fn resolve(self, db: &impl HirDatabase) -> ModuleSourceNode {
340 match self { 292 let syntax_node = db.file_item(self.0);
341 ModuleSource::SourceFile(file_id) => { 293 let syntax_node = syntax_node.borrowed();
342 let syntax = db.source_file(file_id); 294 if let Some(file) = ast::SourceFile::cast(syntax_node) {
343 ModuleSourceNode::SourceFile(syntax.ast().owned()) 295 return ModuleSourceNode::SourceFile(file.owned());
344 }
345 ModuleSource::Module(item_id) => {
346 let syntax = db.file_item(item_id);
347 let syntax = syntax.borrowed();
348 let module = ast::Module::cast(syntax).unwrap();
349 ModuleSourceNode::Module(module.owned())
350 }
351 } 296 }
297 let module = ast::Module::cast(syntax_node).unwrap();
298 ModuleSourceNode::Module(module.owned())
352 } 299 }
353} 300}
354 301
diff --git a/crates/ra_hir/src/module/nameres.rs b/crates/ra_hir/src/module/nameres.rs
index 8529e16b3..61a1acfe6 100644
--- a/crates/ra_hir/src/module/nameres.rs
+++ b/crates/ra_hir/src/module/nameres.rs
@@ -28,7 +28,7 @@ use ra_db::SourceRootId;
28 28
29use crate::{ 29use crate::{
30 Cancelable, FileId, 30 Cancelable, FileId,
31 DefId, DefLoc, 31 DefId, DefLoc, DefKind,
32 SourceItemId, SourceFileItemId, SourceFileItems, 32 SourceItemId, SourceFileItemId, SourceFileItems,
33 Path, PathKind, 33 Path, PathKind,
34 HirDatabase, 34 HirDatabase,
@@ -247,7 +247,10 @@ where
247 // handle submodules separatelly 247 // handle submodules separatelly
248 continue; 248 continue;
249 } 249 }
250 let def_loc = DefLoc::Item { 250 let def_loc = DefLoc {
251 kind: DefKind::Item,
252 source_root_id: self.source_root,
253 module_id,
251 source_item_id: SourceItemId { 254 source_item_id: SourceItemId {
252 file_id, 255 file_id,
253 item_id: item.id, 256 item_id: item.id,
@@ -261,10 +264,12 @@ where
261 module_items.items.insert(item.name.clone(), resolution); 264 module_items.items.insert(item.name.clone(), resolution);
262 } 265 }
263 266
264 for (name, mod_id) in module_id.children(&self.module_tree) { 267 for (name, module_id) in module_id.children(&self.module_tree) {
265 let def_loc = DefLoc::Module { 268 let def_loc = DefLoc {
266 id: mod_id, 269 kind: DefKind::Module,
267 source_root: self.source_root, 270 source_root_id: self.source_root,
271 module_id,
272 source_item_id: module_id.source(&self.module_tree).0,
268 }; 273 };
269 let def_id = def_loc.id(self.db); 274 let def_id = def_loc.id(self.db);
270 let resolution = Resolution { 275 let resolution = Resolution {
@@ -316,7 +321,11 @@ where
316 321
317 if !is_last { 322 if !is_last {
318 curr = match def_id.loc(self.db) { 323 curr = match def_id.loc(self.db) {
319 DefLoc::Module { id, .. } => id, 324 DefLoc {
325 kind: DefKind::Module,
326 module_id,
327 ..
328 } => module_id,
320 _ => return, 329 _ => return,
321 } 330 }
322 } else { 331 } else {
@@ -354,7 +363,9 @@ mod tests {
354 fn item_map(fixture: &str) -> (Arc<hir::ItemMap>, hir::ModuleId) { 363 fn item_map(fixture: &str) -> (Arc<hir::ItemMap>, hir::ModuleId) {
355 let (db, pos) = MockDatabase::with_position(fixture); 364 let (db, pos) = MockDatabase::with_position(fixture);
356 let source_root = db.file_source_root(pos.file_id); 365 let source_root = db.file_source_root(pos.file_id);
357 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();
358 let module_id = module.module_id; 369 let module_id = module.module_id;
359 (db.item_map(source_root).unwrap(), module_id) 370 (db.item_map(source_root).unwrap(), module_id)
360 } 371 }
diff --git a/crates/ra_hir/src/query_definitions.rs b/crates/ra_hir/src/query_definitions.rs
index 6f602878c..e4d721601 100644
--- a/crates/ra_hir/src/query_definitions.rs
+++ b/crates/ra_hir/src/query_definitions.rs
@@ -11,21 +11,21 @@ use ra_syntax::{
11use ra_db::{SourceRootId, FileId, Cancelable,}; 11use ra_db::{SourceRootId, FileId, Cancelable,};
12 12
13use crate::{ 13use crate::{
14 FnId, 14 SourceFileItems, SourceItemId, DefKind,
15 SourceFileItems, SourceItemId, 15 db::HirDatabase,
16 db::HirDatabase, 16 function::{FnScopes, FnId},
17 function::FnScopes, 17 module::{
18 module::{ 18 ModuleSource, ModuleSourceNode, ModuleId,
19 ModuleSource, ModuleSourceNode, ModuleId, 19 imp::Submodule,
20 imp::Submodule, 20 nameres::{InputModuleItems, ItemMap, Resolver},
21 nameres::{InputModuleItems, ItemMap, Resolver}, 21 },
22 },
23}; 22};
24 23
25/// Resolve `FnId` to the corresponding `SyntaxNode` 24/// Resolve `FnId` to the corresponding `SyntaxNode`
26pub(super) fn fn_syntax(db: &impl HirDatabase, fn_id: FnId) -> FnDefNode { 25pub(super) fn fn_syntax(db: &impl HirDatabase, fn_id: FnId) -> FnDefNode {
27 let item_id = fn_id.loc(db); 26 let def_loc = fn_id.0.loc(db);
28 let syntax = db.file_item(item_id); 27 assert!(def_loc.kind == DefKind::Function);
28 let syntax = db.file_item(def_loc.source_item_id);
29 FnDef::cast(syntax.borrowed()).unwrap().owned() 29 FnDef::cast(syntax.borrowed()).unwrap().owned()
30} 30}
31 31
@@ -36,9 +36,10 @@ pub(super) fn fn_scopes(db: &impl HirDatabase, fn_id: FnId) -> Arc<FnScopes> {
36} 36}
37 37
38pub(super) fn file_items(db: &impl HirDatabase, file_id: FileId) -> Arc<SourceFileItems> { 38pub(super) fn file_items(db: &impl HirDatabase, file_id: FileId) -> Arc<SourceFileItems> {
39 let mut res = SourceFileItems::default();
39 let source_file = db.source_file(file_id); 40 let source_file = db.source_file(file_id);
41 res.alloc(source_file.syntax().owned());
40 let source_file = source_file.borrowed(); 42 let source_file = source_file.borrowed();
41 let mut res = SourceFileItems::default();
42 source_file 43 source_file
43 .syntax() 44 .syntax()
44 .descendants() 45 .descendants()
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}