diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2018-12-09 11:00:56 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2018-12-09 11:00:56 +0000 |
commit | 19f6cdcc034a2a91e6112a4ceb32e26413b0aa0d (patch) | |
tree | 548400065966f715ae203e6f6e0fcfd9f12e4470 /crates/ra_hir/src/module/nameres.rs | |
parent | 34956b7823d72467fbf4fa62bd4413dfb680f78d (diff) | |
parent | 7784c7a701ba944decf671f80dea581d68667663 (diff) |
Merge #268
268: WIP: resolve imports across crates r=matklad a=matklad
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_hir/src/module/nameres.rs')
-rw-r--r-- | crates/ra_hir/src/module/nameres.rs | 199 |
1 files changed, 69 insertions, 130 deletions
diff --git a/crates/ra_hir/src/module/nameres.rs b/crates/ra_hir/src/module/nameres.rs index 6511359d0..9afeade9e 100644 --- a/crates/ra_hir/src/module/nameres.rs +++ b/crates/ra_hir/src/module/nameres.rs | |||
@@ -31,7 +31,7 @@ use crate::{ | |||
31 | DefId, DefLoc, DefKind, | 31 | DefId, DefLoc, DefKind, |
32 | SourceItemId, SourceFileItemId, SourceFileItems, | 32 | SourceItemId, SourceFileItemId, SourceFileItems, |
33 | Path, PathKind, | 33 | Path, PathKind, |
34 | HirDatabase, | 34 | HirDatabase, Crate, |
35 | module::{ModuleId, ModuleTree}, | 35 | module::{ModuleId, ModuleTree}, |
36 | }; | 36 | }; |
37 | 37 | ||
@@ -200,34 +200,63 @@ impl ModuleItem { | |||
200 | } | 200 | } |
201 | 201 | ||
202 | pub(crate) struct Resolver<'a, DB> { | 202 | pub(crate) struct Resolver<'a, DB> { |
203 | pub(crate) db: &'a DB, | 203 | db: &'a DB, |
204 | pub(crate) input: &'a FxHashMap<ModuleId, Arc<InputModuleItems>>, | 204 | input: &'a FxHashMap<ModuleId, Arc<InputModuleItems>>, |
205 | pub(crate) source_root: SourceRootId, | 205 | source_root: SourceRootId, |
206 | pub(crate) module_tree: Arc<ModuleTree>, | 206 | module_tree: Arc<ModuleTree>, |
207 | pub(crate) result: ItemMap, | 207 | result: ItemMap, |
208 | } | 208 | } |
209 | 209 | ||
210 | impl<'a, DB> Resolver<'a, DB> | 210 | impl<'a, DB> Resolver<'a, DB> |
211 | where | 211 | where |
212 | DB: HirDatabase, | 212 | DB: HirDatabase, |
213 | { | 213 | { |
214 | pub(crate) fn new( | ||
215 | db: &'a DB, | ||
216 | input: &'a FxHashMap<ModuleId, Arc<InputModuleItems>>, | ||
217 | source_root: SourceRootId, | ||
218 | module_tree: Arc<ModuleTree>, | ||
219 | ) -> Resolver<'a, DB> { | ||
220 | Resolver { | ||
221 | db, | ||
222 | input, | ||
223 | source_root, | ||
224 | module_tree, | ||
225 | result: ItemMap::default(), | ||
226 | } | ||
227 | } | ||
228 | |||
214 | pub(crate) fn resolve(mut self) -> Cancelable<ItemMap> { | 229 | pub(crate) fn resolve(mut self) -> Cancelable<ItemMap> { |
215 | for (&module_id, items) in self.input.iter() { | 230 | for (&module_id, items) in self.input.iter() { |
216 | self.populate_module(module_id, items) | 231 | self.populate_module(module_id, items)?; |
217 | } | 232 | } |
218 | 233 | ||
219 | for &module_id in self.input.keys() { | 234 | for &module_id in self.input.keys() { |
220 | self.db.check_canceled()?; | 235 | self.db.check_canceled()?; |
221 | self.resolve_imports(module_id); | 236 | self.resolve_imports(module_id)?; |
222 | } | 237 | } |
223 | Ok(self.result) | 238 | Ok(self.result) |
224 | } | 239 | } |
225 | 240 | ||
226 | fn populate_module(&mut self, module_id: ModuleId, input: &InputModuleItems) { | 241 | fn populate_module(&mut self, module_id: ModuleId, input: &InputModuleItems) -> Cancelable<()> { |
227 | let file_id = module_id.source(&self.module_tree).file_id(); | 242 | let file_id = module_id.source(&self.module_tree).file_id(); |
228 | 243 | ||
229 | let mut module_items = ModuleScope::default(); | 244 | let mut module_items = ModuleScope::default(); |
230 | 245 | ||
246 | // Populate extern crates prelude | ||
247 | { | ||
248 | let root_id = module_id.crate_root(&self.module_tree); | ||
249 | let file_id = root_id.source(&self.module_tree).file_id(); | ||
250 | let crate_graph = self.db.crate_graph(); | ||
251 | if let Some(crate_id) = crate_graph.crate_id_for_crate_root(file_id) { | ||
252 | let krate = Crate::new(crate_id); | ||
253 | for dep in krate.dependencies(self.db) { | ||
254 | if let Some(module) = dep.krate.root_module(self.db)? { | ||
255 | self.add_module_item(&mut module_items, dep.name, module.module_id); | ||
256 | } | ||
257 | } | ||
258 | }; | ||
259 | } | ||
231 | for import in input.imports.iter() { | 260 | for import in input.imports.iter() { |
232 | if let Some(name) = import.path.segments.iter().last() { | 261 | if let Some(name) = import.path.segments.iter().last() { |
233 | if let ImportKind::Named(import) = import.kind { | 262 | if let ImportKind::Named(import) = import.kind { |
@@ -241,10 +270,9 @@ where | |||
241 | } | 270 | } |
242 | } | 271 | } |
243 | } | 272 | } |
244 | 273 | // Populate explicitelly declared items, except modules | |
245 | for item in input.items.iter() { | 274 | for item in input.items.iter() { |
246 | if item.kind == MODULE { | 275 | if item.kind == MODULE { |
247 | // handle submodules separatelly | ||
248 | continue; | 276 | continue; |
249 | } | 277 | } |
250 | let def_loc = DefLoc { | 278 | let def_loc = DefLoc { |
@@ -264,45 +292,50 @@ where | |||
264 | module_items.items.insert(item.name.clone(), resolution); | 292 | module_items.items.insert(item.name.clone(), resolution); |
265 | } | 293 | } |
266 | 294 | ||
295 | // Populate modules | ||
267 | for (name, module_id) in module_id.children(&self.module_tree) { | 296 | for (name, module_id) in module_id.children(&self.module_tree) { |
268 | let def_loc = DefLoc { | 297 | self.add_module_item(&mut module_items, name, module_id); |
269 | kind: DefKind::Module, | ||
270 | source_root_id: self.source_root, | ||
271 | module_id, | ||
272 | source_item_id: module_id.source(&self.module_tree).0, | ||
273 | }; | ||
274 | let def_id = def_loc.id(self.db); | ||
275 | let resolution = Resolution { | ||
276 | def_id: Some(def_id), | ||
277 | import: None, | ||
278 | }; | ||
279 | module_items.items.insert(name, resolution); | ||
280 | } | 298 | } |
281 | 299 | ||
282 | self.result.per_module.insert(module_id, module_items); | 300 | self.result.per_module.insert(module_id, module_items); |
301 | Ok(()) | ||
283 | } | 302 | } |
284 | 303 | ||
285 | fn resolve_imports(&mut self, module_id: ModuleId) { | 304 | fn add_module_item(&self, module_items: &mut ModuleScope, name: SmolStr, module_id: ModuleId) { |
305 | let def_loc = DefLoc { | ||
306 | kind: DefKind::Module, | ||
307 | source_root_id: self.source_root, | ||
308 | module_id, | ||
309 | source_item_id: module_id.source(&self.module_tree).0, | ||
310 | }; | ||
311 | let def_id = def_loc.id(self.db); | ||
312 | let resolution = Resolution { | ||
313 | def_id: Some(def_id), | ||
314 | import: None, | ||
315 | }; | ||
316 | module_items.items.insert(name, resolution); | ||
317 | } | ||
318 | |||
319 | fn resolve_imports(&mut self, module_id: ModuleId) -> Cancelable<()> { | ||
286 | for import in self.input[&module_id].imports.iter() { | 320 | for import in self.input[&module_id].imports.iter() { |
287 | self.resolve_import(module_id, import); | 321 | self.resolve_import(module_id, import)?; |
288 | } | 322 | } |
323 | Ok(()) | ||
289 | } | 324 | } |
290 | 325 | ||
291 | fn resolve_import(&mut self, module_id: ModuleId, import: &Import) { | 326 | fn resolve_import(&mut self, module_id: ModuleId, import: &Import) -> Cancelable<()> { |
292 | let ptr = match import.kind { | 327 | let ptr = match import.kind { |
293 | ImportKind::Glob => return, | 328 | ImportKind::Glob => return Ok(()), |
294 | ImportKind::Named(ptr) => ptr, | 329 | ImportKind::Named(ptr) => ptr, |
295 | }; | 330 | }; |
296 | 331 | ||
297 | let mut curr = match import.path.kind { | 332 | let mut curr = match import.path.kind { |
298 | // TODO: handle extern crates | 333 | PathKind::Plain | PathKind::Self_ => module_id, |
299 | PathKind::Plain => return, | ||
300 | PathKind::Self_ => module_id, | ||
301 | PathKind::Super => { | 334 | PathKind::Super => { |
302 | match module_id.parent(&self.module_tree) { | 335 | match module_id.parent(&self.module_tree) { |
303 | Some(it) => it, | 336 | Some(it) => it, |
304 | // TODO: error | 337 | // TODO: error |
305 | None => return, | 338 | None => return Ok(()), |
306 | } | 339 | } |
307 | } | 340 | } |
308 | PathKind::Crate => module_id.crate_root(&self.module_tree), | 341 | PathKind::Crate => module_id.crate_root(&self.module_tree), |
@@ -312,10 +345,10 @@ where | |||
312 | let is_last = i == import.path.segments.len() - 1; | 345 | let is_last = i == import.path.segments.len() - 1; |
313 | 346 | ||
314 | let def_id = match self.result.per_module[&curr].items.get(name) { | 347 | let def_id = match self.result.per_module[&curr].items.get(name) { |
315 | None => return, | 348 | None => return Ok(()), |
316 | Some(res) => match res.def_id { | 349 | Some(res) => match res.def_id { |
317 | Some(it) => it, | 350 | Some(it) => it, |
318 | None => return, | 351 | None => return Ok(()), |
319 | }, | 352 | }, |
320 | }; | 353 | }; |
321 | 354 | ||
@@ -326,7 +359,7 @@ where | |||
326 | module_id, | 359 | module_id, |
327 | .. | 360 | .. |
328 | } => module_id, | 361 | } => module_id, |
329 | _ => return, | 362 | _ => return Ok(()), |
330 | } | 363 | } |
331 | } else { | 364 | } else { |
332 | self.update(module_id, |items| { | 365 | self.update(module_id, |items| { |
@@ -338,6 +371,7 @@ where | |||
338 | }) | 371 | }) |
339 | } | 372 | } |
340 | } | 373 | } |
374 | Ok(()) | ||
341 | } | 375 | } |
342 | 376 | ||
343 | fn update(&mut self, module_id: ModuleId, f: impl FnOnce(&mut ModuleScope)) { | 377 | fn update(&mut self, module_id: ModuleId, f: impl FnOnce(&mut ModuleScope)) { |
@@ -347,99 +381,4 @@ where | |||
347 | } | 381 | } |
348 | 382 | ||
349 | #[cfg(test)] | 383 | #[cfg(test)] |
350 | mod tests { | 384 | mod tests; |
351 | use std::sync::Arc; | ||
352 | |||
353 | use salsa::Database; | ||
354 | use ra_db::FilesDatabase; | ||
355 | use ra_syntax::SmolStr; | ||
356 | |||
357 | use crate::{ | ||
358 | self as hir, | ||
359 | db::HirDatabase, | ||
360 | mock::MockDatabase, | ||
361 | }; | ||
362 | |||
363 | fn item_map(fixture: &str) -> (Arc<hir::ItemMap>, hir::ModuleId) { | ||
364 | let (db, pos) = MockDatabase::with_position(fixture); | ||
365 | let source_root = db.file_source_root(pos.file_id); | ||
366 | let module = hir::source_binder::module_from_position(&db, pos) | ||
367 | .unwrap() | ||
368 | .unwrap(); | ||
369 | let module_id = module.module_id; | ||
370 | (db.item_map(source_root).unwrap(), module_id) | ||
371 | } | ||
372 | |||
373 | #[test] | ||
374 | fn test_item_map() { | ||
375 | let (item_map, module_id) = item_map( | ||
376 | " | ||
377 | //- /lib.rs | ||
378 | mod foo; | ||
379 | |||
380 | use crate::foo::bar::Baz; | ||
381 | <|> | ||
382 | |||
383 | //- /foo/mod.rs | ||
384 | pub mod bar; | ||
385 | |||
386 | //- /foo/bar.rs | ||
387 | pub struct Baz; | ||
388 | ", | ||
389 | ); | ||
390 | let name = SmolStr::from("Baz"); | ||
391 | let resolution = &item_map.per_module[&module_id].items[&name]; | ||
392 | assert!(resolution.def_id.is_some()); | ||
393 | } | ||
394 | |||
395 | #[test] | ||
396 | fn typing_inside_a_function_should_not_invalidate_item_map() { | ||
397 | let (mut db, pos) = MockDatabase::with_position( | ||
398 | " | ||
399 | //- /lib.rs | ||
400 | mod foo;<|> | ||
401 | |||
402 | use crate::foo::bar::Baz; | ||
403 | |||
404 | fn foo() -> i32 { | ||
405 | 1 + 1 | ||
406 | } | ||
407 | //- /foo/mod.rs | ||
408 | pub mod bar; | ||
409 | |||
410 | //- /foo/bar.rs | ||
411 | pub struct Baz; | ||
412 | ", | ||
413 | ); | ||
414 | let source_root = db.file_source_root(pos.file_id); | ||
415 | { | ||
416 | let events = db.log_executed(|| { | ||
417 | db.item_map(source_root).unwrap(); | ||
418 | }); | ||
419 | assert!(format!("{:?}", events).contains("item_map")) | ||
420 | } | ||
421 | |||
422 | let new_text = " | ||
423 | mod foo; | ||
424 | |||
425 | use crate::foo::bar::Baz; | ||
426 | |||
427 | fn foo() -> i32 { 92 } | ||
428 | " | ||
429 | .to_string(); | ||
430 | |||
431 | db.query_mut(ra_db::FileTextQuery) | ||
432 | .set(pos.file_id, Arc::new(new_text)); | ||
433 | |||
434 | { | ||
435 | let events = db.log_executed(|| { | ||
436 | db.item_map(source_root).unwrap(); | ||
437 | }); | ||
438 | assert!( | ||
439 | !format!("{:?}", events).contains("_item_map"), | ||
440 | "{:#?}", | ||
441 | events | ||
442 | ) | ||
443 | } | ||
444 | } | ||
445 | } | ||