diff options
-rw-r--r-- | crates/ra_analysis/src/completion/mod.rs | 7 | ||||
-rw-r--r-- | crates/ra_analysis/src/completion/reference_completion.rs | 14 | ||||
-rw-r--r-- | crates/ra_analysis/src/db.rs | 9 | ||||
-rw-r--r-- | crates/ra_analysis/src/imp.rs | 70 | ||||
-rw-r--r-- | crates/ra_analysis/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_analysis/tests/tests.rs | 17 | ||||
-rw-r--r-- | crates/ra_db/src/input.rs | 43 | ||||
-rw-r--r-- | crates/ra_hir/src/db.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/function/mod.rs | 51 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 62 | ||||
-rw-r--r-- | crates/ra_hir/src/mock.rs | 9 | ||||
-rw-r--r-- | crates/ra_hir/src/module/imp.rs | 13 | ||||
-rw-r--r-- | crates/ra_hir/src/module/mod.rs | 141 | ||||
-rw-r--r-- | crates/ra_hir/src/module/nameres.rs | 27 | ||||
-rw-r--r-- | crates/ra_hir/src/query_definitions.rs | 25 | ||||
-rw-r--r-- | crates/ra_hir/src/source_binder.rs | 96 | ||||
-rw-r--r-- | crates/ra_syntax/src/lexer/ptr.rs | 2 |
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 | }; |
10 | use ra_db::SyntaxDatabase; | 10 | use ra_db::SyntaxDatabase; |
11 | use rustc_hash::{FxHashMap}; | 11 | use rustc_hash::{FxHashMap}; |
12 | use hir::source_binder; | ||
12 | 13 | ||
13 | use crate::{ | 14 | use 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 | ||
178 | fn complete_mod_item_snippets(acc: &mut Vec<CompletionItem>) { | 178 | fn 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 @@ | |||
1 | use std::sync::Arc; | 1 | use std::sync::Arc; |
2 | use salsa::{self, Database}; | 2 | use salsa::{self, Database}; |
3 | use ra_db::{LocationIntener, BaseDatabase}; | 3 | use ra_db::{LocationIntener, BaseDatabase}; |
4 | use hir::{self, DefId, DefLoc, FnId, SourceItemId}; | 4 | use hir::{self, DefId, DefLoc}; |
5 | 5 | ||
6 | use crate::{ | 6 | use 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)] |
17 | struct IdMaps { | 17 | struct 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 | ||
61 | impl AsRef<LocationIntener<hir::SourceItemId, FnId>> for RootDatabase { | ||
62 | fn as_ref(&self) -> &LocationIntener<hir::SourceItemId, FnId> { | ||
63 | &self.id_maps.fns | ||
64 | } | ||
65 | } | ||
66 | |||
67 | salsa::database_storage! { | 60 | salsa::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; | |||
16 | use salsa::{Database, ParallelDatabase}; | 16 | use salsa::{Database, ParallelDatabase}; |
17 | use hir::{ | 17 | use 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] |
22 | fn 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] | ||
22 | fn test_resolve_module() { | 39 | fn 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)] |
16 | pub struct CrateGraph { | 16 | pub struct CrateGraph { |
17 | pub(crate) crate_roots: FxHashMap<CrateId, FileId>, | 17 | arena: FxHashMap<CrateId, CrateData>, |
18 | } | 18 | } |
19 | 19 | ||
20 | impl CrateGraph { | 20 | #[derive(Debug, Clone, PartialEq, Eq)] |
21 | pub fn crate_root(&self, crate_id: CrateId) -> FileId { | 21 | struct CrateData { |
22 | self.crate_roots[&crate_id] | 22 | file_id: FileId, |
23 | deps: Vec<Dependency>, | ||
24 | } | ||
25 | |||
26 | impl 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)] | ||
40 | pub struct Dependency { | ||
41 | crate_: CrateId, | ||
42 | } | ||
43 | |||
44 | impl 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::{ | |||
7 | use ra_db::{SourceRootId, LocationIntener, SyntaxDatabase, FileId, Cancelable}; | 7 | use ra_db::{SourceRootId, LocationIntener, SyntaxDatabase, FileId, Cancelable}; |
8 | 8 | ||
9 | use crate::{ | 9 | use 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 | ||
20 | pub trait HirDatabase: SyntaxDatabase | 21 | pub 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 | ||
8 | use ra_syntax::{ | 8 | use ra_syntax::{ |
9 | TextRange, TextUnit, SyntaxNodeRef, | 9 | TextRange, TextUnit, |
10 | ast::{self, AstNode, DocCommentsOwner, NameOwner}, | 10 | ast::{self, AstNode, DocCommentsOwner, NameOwner}, |
11 | }; | 11 | }; |
12 | use ra_db::FileId; | ||
13 | 12 | ||
14 | use crate::{ | 13 | use crate::{ DefId, HirDatabase }; |
15 | FnId, HirDatabase, SourceItemId, | ||
16 | }; | ||
17 | 14 | ||
18 | pub use self::scope::FnScopes; | 15 | pub use self::scope::FnScopes; |
19 | 16 | ||
20 | impl FnId { | 17 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] |
21 | pub fn get(db: &impl HirDatabase, file_id: FileId, fn_def: ast::FnDef) -> FnId { | 18 | pub 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 | ||
29 | pub struct Function { | 20 | pub struct Function { |
30 | fn_id: FnId, | 21 | fn_id: FnId, |
31 | } | 22 | } |
32 | 23 | ||
33 | impl Function { | 24 | impl 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; | |||
22 | mod module; | 22 | mod module; |
23 | mod path; | 23 | mod path; |
24 | mod arena; | 24 | mod arena; |
25 | pub mod source_binder; | ||
25 | 26 | ||
26 | use std::ops::Index; | 27 | use std::ops::Index; |
27 | 28 | ||
@@ -41,63 +42,58 @@ pub use self::{ | |||
41 | 42 | ||
42 | pub use self::function::FnSignatureInfo; | 43 | pub 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) |
45 | pub struct FnId(u32); | 46 | /// in a specific module. |
46 | ra_db::impl_numeric_id!(FnId); | ||
47 | |||
48 | impl 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)] |
61 | pub struct DefId(u32); | 48 | pub struct DefId(u32); |
62 | ra_db::impl_numeric_id!(DefId); | 49 | ra_db::impl_numeric_id!(DefId); |
63 | 50 | ||
51 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
52 | pub(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)] |
65 | pub enum DefLoc { | 59 | pub 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 | ||
75 | impl DefId { | 66 | impl 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 | ||
81 | impl DefLoc { | 72 | impl 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 | ||
87 | pub enum Def { | 78 | pub enum Def { |
88 | Module(Module), | 79 | Module(Module), |
80 | Function(Function), | ||
89 | Item, | 81 | Item, |
90 | } | 82 | } |
91 | 83 | ||
92 | impl DefId { | 84 | impl 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 | ||
136 | impl Index<SourceFileItemId> for SourceFileItems { | 136 | impl 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, | |||
6 | use relative_path::RelativePathBuf; | 6 | use relative_path::RelativePathBuf; |
7 | use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset}; | 7 | use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset}; |
8 | 8 | ||
9 | use crate::{db, DefId, DefLoc, FnId, SourceItemId}; | 9 | use crate::{db, DefId, DefLoc}; |
10 | 10 | ||
11 | #[derive(Debug)] | 11 | #[derive(Debug)] |
12 | pub(crate) struct MockDatabase { | 12 | pub(crate) struct MockDatabase { |
@@ -65,7 +65,6 @@ impl MockDatabase { | |||
65 | 65 | ||
66 | #[derive(Debug, Default)] | 66 | #[derive(Debug, Default)] |
67 | struct IdMaps { | 67 | struct 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 | ||
120 | impl AsRef<LocationIntener<SourceItemId, FnId>> for MockDatabase { | ||
121 | fn as_ref(&self) -> &LocationIntener<SourceItemId, FnId> { | ||
122 | &self.id_maps.fns | ||
123 | } | ||
124 | } | ||
125 | |||
126 | impl MockDatabase { | 119 | impl 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 | ||
4 | use std::sync::Arc; | 4 | use std::sync::Arc; |
5 | 5 | ||
6 | use ra_editor::find_node_at_offset; | ||
7 | |||
8 | use ra_syntax::{ | 6 | use ra_syntax::{ |
9 | algo::generate, | 7 | algo::generate, |
10 | ast::{self, AstNode, NameOwner}, | 8 | ast::{self, AstNode, NameOwner}, |
11 | SmolStr, SyntaxNode, | 9 | SmolStr, SyntaxNode, |
12 | }; | 10 | }; |
13 | use ra_db::{SourceRootId, FileId, FilePosition, Cancelable}; | 11 | use ra_db::{SourceRootId, FileId, Cancelable}; |
14 | use relative_path::RelativePathBuf; | 12 | use relative_path::RelativePathBuf; |
15 | 13 | ||
16 | use crate::{ | 14 | use crate::{ |
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)] |
26 | pub struct Module { | 24 | pub 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 | ||
32 | impl Module { | 30 | impl Module { |
33 | /// Lookup `Module` by `FileId`. Note that this is inherently | ||
34 | /// lossy transformation: in general, a single source might correspond to | ||
35 | /// several modules. | ||
36 | pub fn guess_from_file_id( | ||
37 | db: &impl HirDatabase, | ||
38 | file_id: FileId, | ||
39 | ) -> Cancelable<Option<Module>> { | ||
40 | 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)] |
212 | pub enum ModuleSource { | 166 | pub 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 | ||
312 | impl ModuleSource { | 263 | impl 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 | ||
29 | use crate::{ | 29 | use 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::{ | |||
11 | use ra_db::{SourceRootId, FileId, Cancelable,}; | 11 | use ra_db::{SourceRootId, FileId, Cancelable,}; |
12 | 12 | ||
13 | use crate::{ | 13 | use 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` |
26 | pub(super) fn fn_syntax(db: &impl HirDatabase, fn_id: FnId) -> FnDefNode { | 25 | pub(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 | ||
38 | pub(super) fn file_items(db: &impl HirDatabase, file_id: FileId) -> Arc<SourceFileItems> { | 38 | pub(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". | ||
8 | use ra_db::{FileId, FilePosition, Cancelable}; | ||
9 | use ra_editor::find_node_at_offset; | ||
10 | use ra_syntax::{ | ||
11 | ast::{self, AstNode}, | ||
12 | SyntaxNodeRef, | ||
13 | }; | ||
14 | |||
15 | use crate::{ | ||
16 | HirDatabase, Module, Function, SourceItemId, | ||
17 | module::ModuleSource, | ||
18 | DefKind, DefLoc | ||
19 | }; | ||
20 | |||
21 | /// Locates the module by `FileId`. Picks topmost module in the file. | ||
22 | pub fn module_from_file_id(db: &impl HirDatabase, file_id: FileId) -> Cancelable<Option<Module>> { | ||
23 | let module_source = ModuleSource::new_file(db, file_id); | ||
24 | module_from_source(db, module_source) | ||
25 | } | ||
26 | |||
27 | /// Locates the module by position in the source code. | ||
28 | pub fn module_from_position( | ||
29 | db: &impl HirDatabase, | ||
30 | position: FilePosition, | ||
31 | ) -> Cancelable<Option<Module>> { | ||
32 | let file = db.source_file(position.file_id); | ||
33 | let module_source = match find_node_at_offset::<ast::Module>(file.syntax(), position.offset) { | ||
34 | Some(m) if !m.has_semi() => ModuleSource::new_inline(db, position.file_id, m), | ||
35 | _ => ModuleSource::new_file(db, position.file_id), | ||
36 | }; | ||
37 | module_from_source(db, module_source) | ||
38 | } | ||
39 | |||
40 | /// Locates the module by child syntax element within the module | ||
41 | pub fn module_from_child_node( | ||
42 | db: &impl HirDatabase, | ||
43 | file_id: FileId, | ||
44 | child: SyntaxNodeRef, | ||
45 | ) -> Cancelable<Option<Module>> { | ||
46 | let module_source = if let Some(m) = child | ||
47 | .ancestors() | ||
48 | .filter_map(ast::Module::cast) | ||
49 | .find(|it| !it.has_semi()) | ||
50 | { | ||
51 | ModuleSource::new_inline(db, file_id, m) | ||
52 | } else { | ||
53 | ModuleSource::new_file(db, file_id) | ||
54 | }; | ||
55 | module_from_source(db, module_source) | ||
56 | } | ||
57 | |||
58 | fn module_from_source( | ||
59 | db: &impl HirDatabase, | ||
60 | module_source: ModuleSource, | ||
61 | ) -> Cancelable<Option<Module>> { | ||
62 | let source_root_id = db.file_source_root(module_source.file_id()); | ||
63 | let module_tree = db.module_tree(source_root_id)?; | ||
64 | let m = module_tree | ||
65 | .modules_with_sources() | ||
66 | .find(|(_id, src)| src == &module_source); | ||
67 | let module_id = ctry!(m).0; | ||
68 | Ok(Some(Module::new(db, source_root_id, module_id)?)) | ||
69 | } | ||
70 | |||
71 | pub fn function_from_source( | ||
72 | db: &impl HirDatabase, | ||
73 | file_id: FileId, | ||
74 | fn_def: ast::FnDef, | ||
75 | ) -> Cancelable<Option<Function>> { | ||
76 | let module = ctry!(module_from_child_node(db, file_id, fn_def.syntax())?); | ||
77 | let file_items = db.file_items(file_id); | ||
78 | let item_id = file_items.id_of(fn_def.syntax()); | ||
79 | let source_item_id = SourceItemId { file_id, item_id }; | ||
80 | let def_loc = DefLoc { | ||
81 | kind: DefKind::Function, | ||
82 | source_root_id: module.source_root_id, | ||
83 | module_id: module.module_id, | ||
84 | source_item_id, | ||
85 | }; | ||
86 | Ok(Some(Function::new(def_loc.id(db)))) | ||
87 | } | ||
88 | |||
89 | pub fn function_from_child_node( | ||
90 | db: &impl HirDatabase, | ||
91 | file_id: FileId, | ||
92 | node: SyntaxNodeRef, | ||
93 | ) -> Cancelable<Option<Function>> { | ||
94 | let fn_def = ctry!(node.ancestors().find_map(ast::FnDef::cast)); | ||
95 | function_from_source(db, file_id, fn_def) | ||
96 | } | ||
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 | } |