aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_analysis/src/completion/mod.rs7
-rw-r--r--crates/ra_analysis/src/completion/reference_completion.rs14
-rw-r--r--crates/ra_analysis/src/db.rs9
-rw-r--r--crates/ra_analysis/src/imp.rs70
-rw-r--r--crates/ra_analysis/src/lib.rs2
-rw-r--r--crates/ra_analysis/tests/tests.rs17
-rw-r--r--crates/ra_db/src/input.rs43
-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
-rw-r--r--crates/ra_syntax/src/lexer/ptr.rs2
17 files changed, 326 insertions, 266 deletions
diff --git a/crates/ra_analysis/src/completion/mod.rs b/crates/ra_analysis/src/completion/mod.rs
index e5ba92acd..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;
@@ -427,7 +428,7 @@ mod tests {
427 // check_snippet_completion(r" 428 // check_snippet_completion(r"
428 // <|> 429 // <|>
429 // ", 430 // ",
430 // r##"[CompletionItem { label: "tfn", lookup: None, snippet: Some("#[test]\nfn $1() {\n $0\n}") }]"##, 431 // r##"[CompletionItem { label: "Test function", lookup: None, snippet: Some("#[test]\nfn test_${1:feature}() {\n$0\n}"##,
431 // ); 432 // );
432 check_snippet_completion(r" 433 check_snippet_completion(r"
433 #[cfg(test)] 434 #[cfg(test)]
@@ -435,7 +436,7 @@ mod tests {
435 <|> 436 <|>
436 } 437 }
437 ", 438 ",
438 r##"[CompletionItem { label: "tfn", lookup: None, snippet: Some("#[test]\nfn $1() {\n $0\n}") }, 439 r##"[CompletionItem { label: "Test function", lookup: Some("tfn"), snippet: Some("#[test]\nfn ${1:feature}() {\n$0\n}") },
439 CompletionItem { label: "pub(crate)", lookup: None, snippet: Some("pub(crate) $0") }]"##, 440 CompletionItem { label: "pub(crate)", lookup: None, snippet: Some("pub(crate) $0") }]"##,
440 ); 441 );
441 } 442 }
diff --git a/crates/ra_analysis/src/completion/reference_completion.rs b/crates/ra_analysis/src/completion/reference_completion.rs
index e1a2d5241..f483ed045 100644
--- a/crates/ra_analysis/src/completion/reference_completion.rs
+++ b/crates/ra_analysis/src/completion/reference_completion.rs
@@ -163,7 +163,7 @@ fn complete_path(
163 }; 163 };
164 let target_module = match def_id.resolve(db)? { 164 let target_module = match def_id.resolve(db)? {
165 Def::Module(it) => it, 165 Def::Module(it) => it,
166 Def::Item => return Ok(()), 166 _ => return Ok(()),
167 }; 167 };
168 let module_scope = target_module.scope(db)?; 168 let module_scope = target_module.scope(db)?;
169 let completions = module_scope.entries().map(|(name, _res)| CompletionItem { 169 let completions = module_scope.entries().map(|(name, _res)| CompletionItem {
@@ -177,9 +177,15 @@ fn complete_path(
177 177
178fn complete_mod_item_snippets(acc: &mut Vec<CompletionItem>) { 178fn complete_mod_item_snippets(acc: &mut Vec<CompletionItem>) {
179 acc.push(CompletionItem { 179 acc.push(CompletionItem {
180 label: "tfn".to_string(), 180 label: "Test function".to_string(),
181 lookup: None, 181 lookup: Some("tfn".to_string()),
182 snippet: Some("#[test]\nfn $1() {\n $0\n}".to_string()), 182 snippet: Some(
183 "#[test]\n\
184 fn ${1:feature}() {\n\
185 $0\n\
186 }"
187 .to_string(),
188 ),
183 }); 189 });
184 acc.push(CompletionItem { 190 acc.push(CompletionItem {
185 label: "pub(crate)".to_string(), 191 label: "pub(crate)".to_string(),
diff --git a/crates/ra_analysis/src/db.rs b/crates/ra_analysis/src/db.rs
index df2ef293d..b8d774eb5 100644
--- a/crates/ra_analysis/src/db.rs
+++ b/crates/ra_analysis/src/db.rs
@@ -1,7 +1,7 @@
1use std::sync::Arc; 1use std::sync::Arc;
2use salsa::{self, Database}; 2use salsa::{self, Database};
3use ra_db::{LocationIntener, BaseDatabase}; 3use ra_db::{LocationIntener, BaseDatabase};
4use hir::{self, DefId, DefLoc, FnId, SourceItemId}; 4use hir::{self, DefId, DefLoc};
5 5
6use crate::{ 6use crate::{
7 symbol_index, 7 symbol_index,
@@ -15,7 +15,6 @@ pub(crate) struct RootDatabase {
15 15
16#[derive(Debug, Default)] 16#[derive(Debug, Default)]
17struct IdMaps { 17struct IdMaps {
18 fns: LocationIntener<SourceItemId, FnId>,
19 defs: LocationIntener<DefLoc, DefId>, 18 defs: LocationIntener<DefLoc, DefId>,
20} 19}
21 20
@@ -58,12 +57,6 @@ impl AsRef<LocationIntener<DefLoc, DefId>> for RootDatabase {
58 } 57 }
59} 58}
60 59
61impl AsRef<LocationIntener<hir::SourceItemId, FnId>> for RootDatabase {
62 fn as_ref(&self) -> &LocationIntener<hir::SourceItemId, FnId> {
63 &self.id_maps.fns
64 }
65}
66
67salsa::database_storage! { 60salsa::database_storage! {
68 pub(crate) struct RootDatabaseStorage for RootDatabase { 61 pub(crate) struct RootDatabaseStorage for RootDatabase {
69 impl ra_db::FilesDatabase { 62 impl ra_db::FilesDatabase {
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs
index f5cb3550e..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,15 +186,12 @@ 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 };
192 let root = descr.crate_root(); 193 let root = descr.crate_root();
193 let file_id = root 194 let file_id = root.source().file_id();
194 .source()
195 .as_file()
196 .expect("root module always has a file as a source");
197 195
198 let crate_graph = self.db.crate_graph(); 196 let crate_graph = self.db.crate_graph();
199 let crate_id = crate_graph.crate_id_for_crate_root(file_id); 197 let crate_id = crate_graph.crate_id_for_crate_root(file_id);
@@ -212,12 +210,14 @@ impl AnalysisImpl {
212 let file = self.db.source_file(position.file_id); 210 let file = self.db.source_file(position.file_id);
213 let syntax = file.syntax(); 211 let syntax = file.syntax();
214 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) {
215 if let Some(fn_descr) = 213 if let Some(fn_descr) = source_binder::function_from_child_node(
216 hir::Function::guess_for_name_ref(&*self.db, position.file_id, name_ref) 214 &*self.db,
217 { 215 position.file_id,
216 name_ref.syntax(),
217 )? {
218 let scope = fn_descr.scope(&*self.db); 218 let scope = fn_descr.scope(&*self.db);
219 // First try to resolve the symbol locally 219 // First try to resolve the symbol locally
220 return if let Some(entry) = scope.resolve_local_name(name_ref) { 220 if let Some(entry) = scope.resolve_local_name(name_ref) {
221 let mut vec = vec![]; 221 let mut vec = vec![];
222 vec.push(( 222 vec.push((
223 position.file_id, 223 position.file_id,
@@ -227,18 +227,17 @@ impl AnalysisImpl {
227 kind: NAME, 227 kind: NAME,
228 }, 228 },
229 )); 229 ));
230 Ok(vec) 230 return Ok(vec);
231 } else {
232 // If that fails try the index based approach.
233 self.index_resolve(name_ref)
234 }; 231 };
235 } 232 }
233 // If that fails try the index based approach.
234 return self.index_resolve(name_ref);
236 } 235 }
237 if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) { 236 if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) {
238 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) {
239 if module.has_semi() { 238 if module.has_semi() {
240 let parent_module = 239 let parent_module =
241 hir::Module::guess_from_file_id(&*self.db, position.file_id)?; 240 source_binder::module_from_file_id(&*self.db, position.file_id)?;
242 let child_name = module.name(); 241 let child_name = module.name();
243 match (parent_module, child_name) { 242 match (parent_module, child_name) {
244 (Some(parent_module), Some(child_name)) => { 243 (Some(parent_module), Some(child_name)) => {
@@ -260,11 +259,11 @@ impl AnalysisImpl {
260 Ok(vec![]) 259 Ok(vec![])
261 } 260 }
262 261
263 pub fn find_all_refs(&self, position: FilePosition) -> Vec<(FileId, TextRange)> { 262 pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> {
264 let file = self.db.source_file(position.file_id); 263 let file = self.db.source_file(position.file_id);
265 // Find the binding associated with the offset 264 // Find the binding associated with the offset
266 let (binding, descr) = match find_binding(&self.db, &file, position) { 265 let (binding, descr) = match find_binding(&self.db, &file, position)? {
267 None => return Vec::new(), 266 None => return Ok(Vec::new()),
268 Some(it) => it, 267 Some(it) => it,
269 }; 268 };
270 269
@@ -277,25 +276,36 @@ impl AnalysisImpl {
277 .map(|ref_desc| (position.file_id, ref_desc.range)), 276 .map(|ref_desc| (position.file_id, ref_desc.range)),
278 ); 277 );
279 278
280 return ret; 279 return Ok(ret);
281 280
282 fn find_binding<'a>( 281 fn find_binding<'a>(
283 db: &db::RootDatabase, 282 db: &db::RootDatabase,
284 source_file: &'a SourceFileNode, 283 source_file: &'a SourceFileNode,
285 position: FilePosition, 284 position: FilePosition,
286 ) -> Option<(ast::BindPat<'a>, hir::Function)> { 285 ) -> Cancelable<Option<(ast::BindPat<'a>, hir::Function)>> {
287 let syntax = source_file.syntax(); 286 let syntax = source_file.syntax();
288 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) {
289 let descr = hir::Function::guess_for_bind_pat(db, position.file_id, binding)?; 288 let descr = ctry!(source_binder::function_from_child_node(
290 return Some((binding, descr)); 289 db,
290 position.file_id,
291 binding.syntax(),
292 )?);
293 return Ok(Some((binding, descr)));
291 }; 294 };
292 let name_ref = 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 = hir::Function::guess_for_name_ref(db, position.file_id, name_ref)?; 296 let descr = ctry!(source_binder::function_from_child_node(
297 db,
298 position.file_id,
299 name_ref.syntax(),
300 )?);
294 let scope = descr.scope(db); 301 let scope = descr.scope(db);
295 let resolved = scope.resolve_local_name(name_ref)?; 302 let resolved = ctry!(scope.resolve_local_name(name_ref));
296 let resolved = resolved.ptr().resolve(source_file); 303 let resolved = resolved.ptr().resolve(source_file);
297 let binding = find_node_at_offset::<ast::BindPat>(syntax, resolved.range().end())?; 304 let binding = ctry!(find_node_at_offset::<ast::BindPat>(
298 Some((binding, descr)) 305 syntax,
306 resolved.range().end()
307 ));
308 Ok(Some((binding, descr)))
299 } 309 }
300 } 310 }
301 311
@@ -320,7 +330,7 @@ impl AnalysisImpl {
320 fix: None, 330 fix: None,
321 }) 331 })
322 .collect::<Vec<_>>(); 332 .collect::<Vec<_>>();
323 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)? {
324 for (name_node, problem) in m.problems(&*self.db) { 334 for (name_node, problem) in m.problems(&*self.db) {
325 let diag = match problem { 335 let diag = match problem {
326 Problem::UnresolvedModule { candidate } => { 336 Problem::UnresolvedModule { candidate } => {
@@ -411,7 +421,9 @@ impl AnalysisImpl {
411 if fs.kind == FN_DEF { 421 if fs.kind == FN_DEF {
412 let fn_file = self.db.source_file(fn_file_id); 422 let fn_file = self.db.source_file(fn_file_id);
413 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()) {
414 let descr = hir::Function::guess_from_source(&*self.db, fn_file_id, fn_def); 424 let descr = ctry!(source_binder::function_from_source(
425 &*self.db, fn_file_id, fn_def
426 )?);
415 if let Some(descriptor) = descr.signature_info(&*self.db) { 427 if let Some(descriptor) = descr.signature_info(&*self.db) {
416 // If we have a calling expression let's find which argument we are on 428 // If we have a calling expression let's find which argument we are on
417 let mut current_parameter = None; 429 let mut current_parameter = None;
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs
index 12df580ba..90528edfd 100644
--- a/crates/ra_analysis/src/lib.rs
+++ b/crates/ra_analysis/src/lib.rs
@@ -248,7 +248,7 @@ impl Analysis {
248 self.imp.approximately_resolve_symbol(position) 248 self.imp.approximately_resolve_symbol(position)
249 } 249 }
250 pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> { 250 pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> {
251 Ok(self.imp.find_all_refs(position)) 251 self.imp.find_all_refs(position)
252 } 252 }
253 pub fn doc_comment_for( 253 pub fn doc_comment_for(
254 &self, 254 &self,
diff --git a/crates/ra_analysis/tests/tests.rs b/crates/ra_analysis/tests/tests.rs
index fbe89f444..71d20dbe9 100644
--- a/crates/ra_analysis/tests/tests.rs
+++ b/crates/ra_analysis/tests/tests.rs
@@ -19,6 +19,23 @@ fn get_signature(text: &str) -> (FnSignatureInfo, Option<usize>) {
19} 19}
20 20
21#[test] 21#[test]
22fn approximate_resolve_works_in_items() {
23 let (analysis, pos) = analysis_and_position(
24 "
25 //- /lib.rs
26 struct Foo;
27 enum E { X(Foo<|>) }
28 ",
29 );
30
31 let symbols = analysis.approximately_resolve_symbol(pos).unwrap();
32 assert_eq_dbg(
33 r#"[(FileId(1), FileSymbol { name: "Foo", node_range: [0; 11), kind: STRUCT_DEF })]"#,
34 &symbols,
35 );
36}
37
38#[test]
22fn test_resolve_module() { 39fn test_resolve_module() {
23 let (analysis, pos) = analysis_and_position( 40 let (analysis, pos) = analysis_and_position(
24 " 41 "
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs
index 9101ac7a8..7d9faa43c 100644
--- a/crates/ra_db/src/input.rs
+++ b/crates/ra_db/src/input.rs
@@ -14,24 +14,51 @@ pub struct CrateId(pub u32);
14 14
15#[derive(Debug, Clone, Default, PartialEq, Eq)] 15#[derive(Debug, Clone, Default, PartialEq, Eq)]
16pub struct CrateGraph { 16pub struct CrateGraph {
17 pub(crate) crate_roots: FxHashMap<CrateId, FileId>, 17 arena: FxHashMap<CrateId, CrateData>,
18} 18}
19 19
20impl CrateGraph { 20#[derive(Debug, Clone, PartialEq, Eq)]
21 pub fn crate_root(&self, crate_id: CrateId) -> FileId { 21struct CrateData {
22 self.crate_roots[&crate_id] 22 file_id: FileId,
23 deps: Vec<Dependency>,
24}
25
26impl CrateData {
27 fn new(file_id: FileId) -> CrateData {
28 CrateData {
29 file_id,
30 deps: Vec::new(),
31 }
32 }
33
34 fn add_dep(&mut self, dep: CrateId) {
35 self.deps.push(Dependency { crate_: dep })
23 } 36 }
37}
38
39#[derive(Debug, Clone, PartialEq, Eq)]
40pub struct Dependency {
41 crate_: CrateId,
42}
43
44impl CrateGraph {
24 pub fn add_crate_root(&mut self, file_id: FileId) -> CrateId { 45 pub fn add_crate_root(&mut self, file_id: FileId) -> CrateId {
25 let crate_id = CrateId(self.crate_roots.len() as u32); 46 let crate_id = CrateId(self.arena.len() as u32);
26 let prev = self.crate_roots.insert(crate_id, file_id); 47 let prev = self.arena.insert(crate_id, CrateData::new(file_id));
27 assert!(prev.is_none()); 48 assert!(prev.is_none());
28 crate_id 49 crate_id
29 } 50 }
51 pub fn add_dep(&mut self, from: CrateId, to: CrateId) {
52 self.arena.get_mut(&from).unwrap().add_dep(to)
53 }
54 pub fn crate_root(&self, crate_id: CrateId) -> FileId {
55 self.arena[&crate_id].file_id
56 }
30 pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> { 57 pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> {
31 let (&crate_id, _) = self 58 let (&crate_id, _) = self
32 .crate_roots 59 .arena
33 .iter() 60 .iter()
34 .find(|(_crate_id, &root_id)| root_id == file_id)?; 61 .find(|(_crate_id, data)| data.file_id == file_id)?;
35 Some(crate_id) 62 Some(crate_id)
36 } 63 }
37} 64}
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}
diff --git a/crates/ra_syntax/src/lexer/ptr.rs b/crates/ra_syntax/src/lexer/ptr.rs
index 7e4df51aa..0a473c991 100644
--- a/crates/ra_syntax/src/lexer/ptr.rs
+++ b/crates/ra_syntax/src/lexer/ptr.rs
@@ -28,7 +28,7 @@ impl<'s> Ptr<'s> {
28 } 28 }
29 29
30 /// Gets the nth character from the current. 30 /// Gets the nth character from the current.
31 /// For example, 0 will return the current token, 1 will return the next, etc. 31 /// For example, 0 will return the current character, 1 will return the next, etc.
32 pub fn nth(&self, n: u32) -> Option<char> { 32 pub fn nth(&self, n: u32) -> Option<char> {
33 self.chars().nth(n as usize) 33 self.chars().nth(n as usize)
34 } 34 }