diff options
author | Florian Diebold <[email protected]> | 2019-02-11 22:11:12 +0000 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-02-13 19:10:46 +0000 |
commit | d5ad38cbb87103d8713855e0ec705fd957249afd (patch) | |
tree | 3c414dafaa6e42cc11dd71f9f9b59291eff9832e /crates/ra_hir | |
parent | 3a9934e2c3280864877a90c5ced777bad898d73a (diff) |
Resolve 2015 style imports
Diffstat (limited to 'crates/ra_hir')
-rw-r--r-- | crates/ra_hir/src/code_model_api.rs | 9 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 68 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/tests.rs | 45 |
3 files changed, 114 insertions, 8 deletions
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs index 2ac05c836..fb7ad0867 100644 --- a/crates/ra_hir/src/code_model_api.rs +++ b/crates/ra_hir/src/code_model_api.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | use std::sync::Arc; | 1 | use std::sync::Arc; |
2 | 2 | ||
3 | use relative_path::RelativePathBuf; | 3 | use relative_path::RelativePathBuf; |
4 | use ra_db::{CrateId, FileId, SourceRootId}; | 4 | use ra_db::{CrateId, FileId, SourceRootId, Edition}; |
5 | use ra_syntax::{ast::self, TreeArc, SyntaxNode}; | 5 | use ra_syntax::{ast::self, TreeArc, SyntaxNode}; |
6 | 6 | ||
7 | use crate::{ | 7 | use crate::{ |
@@ -38,13 +38,20 @@ impl Crate { | |||
38 | pub fn crate_id(&self) -> CrateId { | 38 | pub fn crate_id(&self) -> CrateId { |
39 | self.crate_id | 39 | self.crate_id |
40 | } | 40 | } |
41 | |||
41 | pub fn dependencies(&self, db: &impl PersistentHirDatabase) -> Vec<CrateDependency> { | 42 | pub fn dependencies(&self, db: &impl PersistentHirDatabase) -> Vec<CrateDependency> { |
42 | self.dependencies_impl(db) | 43 | self.dependencies_impl(db) |
43 | } | 44 | } |
45 | |||
44 | pub fn root_module(&self, db: &impl PersistentHirDatabase) -> Option<Module> { | 46 | pub fn root_module(&self, db: &impl PersistentHirDatabase) -> Option<Module> { |
45 | self.root_module_impl(db) | 47 | self.root_module_impl(db) |
46 | } | 48 | } |
47 | 49 | ||
50 | pub fn edition(&self, db: &impl PersistentHirDatabase) -> Edition { | ||
51 | let crate_graph = db.crate_graph(); | ||
52 | crate_graph.edition(self.crate_id) | ||
53 | } | ||
54 | |||
48 | // TODO: should this be in source_binder? | 55 | // TODO: should this be in source_binder? |
49 | pub fn source_root_crates( | 56 | pub fn source_root_crates( |
50 | db: &impl PersistentHirDatabase, | 57 | db: &impl PersistentHirDatabase, |
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index 2ba6038c6..028e2bee3 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs | |||
@@ -18,9 +18,11 @@ pub(crate) mod lower; | |||
18 | 18 | ||
19 | use std::{time, sync::Arc}; | 19 | use std::{time, sync::Arc}; |
20 | 20 | ||
21 | use rustc_hash::{FxHashMap, FxHashSet}; | ||
22 | |||
21 | use ra_arena::map::ArenaMap; | 23 | use ra_arena::map::ArenaMap; |
24 | use ra_db::Edition; | ||
22 | use test_utils::tested_by; | 25 | use test_utils::tested_by; |
23 | use rustc_hash::{FxHashMap, FxHashSet}; | ||
24 | 26 | ||
25 | use crate::{ | 27 | use crate::{ |
26 | Module, ModuleDef, | 28 | Module, ModuleDef, |
@@ -32,8 +34,9 @@ use crate::{ | |||
32 | 34 | ||
33 | /// `ItemMap` is the result of module name resolution. It contains, for each | 35 | /// `ItemMap` is the result of module name resolution. It contains, for each |
34 | /// module, the set of visible items. | 36 | /// module, the set of visible items. |
35 | #[derive(Default, Debug, PartialEq, Eq)] | 37 | #[derive(Debug, PartialEq, Eq)] |
36 | pub struct ItemMap { | 38 | pub struct ItemMap { |
39 | edition: Edition, | ||
37 | /// The prelude module for this crate. This either comes from an import | 40 | /// The prelude module for this crate. This either comes from an import |
38 | /// marked with the `prelude_import` attribute, or (in the normal case) from | 41 | /// marked with the `prelude_import` attribute, or (in the normal case) from |
39 | /// a dependency (`std` or `core`). | 42 | /// a dependency (`std` or `core`). |
@@ -180,7 +183,12 @@ where | |||
180 | module_tree, | 183 | module_tree, |
181 | processed_imports: FxHashSet::default(), | 184 | processed_imports: FxHashSet::default(), |
182 | glob_imports: FxHashMap::default(), | 185 | glob_imports: FxHashMap::default(), |
183 | result: ItemMap::default(), | 186 | result: ItemMap { |
187 | edition: krate.edition(db), | ||
188 | prelude: None, | ||
189 | extern_prelude: FxHashMap::default(), | ||
190 | per_module: ArenaMap::default(), | ||
191 | }, | ||
184 | } | 192 | } |
185 | } | 193 | } |
186 | 194 | ||
@@ -277,10 +285,14 @@ where | |||
277 | import_id: ImportId, | 285 | import_id: ImportId, |
278 | import: &ImportData, | 286 | import: &ImportData, |
279 | ) -> ReachedFixedPoint { | 287 | ) -> ReachedFixedPoint { |
280 | log::debug!("resolving import: {:?}", import); | 288 | log::debug!("resolving import: {:?} ({:?})", import, self.result.edition); |
281 | let original_module = Module { krate: self.krate, module_id }; | 289 | let original_module = Module { krate: self.krate, module_id }; |
282 | let (def, reached_fixedpoint) = | 290 | let (def, reached_fixedpoint) = self.result.resolve_path_fp( |
283 | self.result.resolve_path_fp(self.db, original_module, &import.path); | 291 | self.db, |
292 | ResolveMode::Import, | ||
293 | original_module, | ||
294 | &import.path, | ||
295 | ); | ||
284 | 296 | ||
285 | if reached_fixedpoint != ReachedFixedPoint::Yes { | 297 | if reached_fixedpoint != ReachedFixedPoint::Yes { |
286 | return reached_fixedpoint; | 298 | return reached_fixedpoint; |
@@ -418,6 +430,12 @@ where | |||
418 | } | 430 | } |
419 | 431 | ||
420 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 432 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
433 | enum ResolveMode { | ||
434 | Import, | ||
435 | Other, | ||
436 | } | ||
437 | |||
438 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
421 | enum ReachedFixedPoint { | 439 | enum ReachedFixedPoint { |
422 | Yes, | 440 | Yes, |
423 | No, | 441 | No, |
@@ -445,7 +463,7 @@ impl ItemMap { | |||
445 | original_module: Module, | 463 | original_module: Module, |
446 | path: &Path, | 464 | path: &Path, |
447 | ) -> PerNs<ModuleDef> { | 465 | ) -> PerNs<ModuleDef> { |
448 | self.resolve_path_fp(db, original_module, path).0 | 466 | self.resolve_path_fp(db, ResolveMode::Other, original_module, path).0 |
449 | } | 467 | } |
450 | 468 | ||
451 | fn resolve_in_prelude( | 469 | fn resolve_in_prelude( |
@@ -484,11 +502,27 @@ impl ItemMap { | |||
484 | from_scope.or(from_extern_prelude).or(from_prelude) | 502 | from_scope.or(from_extern_prelude).or(from_prelude) |
485 | } | 503 | } |
486 | 504 | ||
505 | fn resolve_name_in_crate_root_or_extern_prelude( | ||
506 | &self, | ||
507 | db: &impl PersistentHirDatabase, | ||
508 | module: Module, | ||
509 | name: &Name, | ||
510 | ) -> PerNs<ModuleDef> { | ||
511 | let crate_root = module.crate_root(db); | ||
512 | let from_crate_root = | ||
513 | self[crate_root.module_id].items.get(name).map_or(PerNs::none(), |it| it.def); | ||
514 | let from_extern_prelude = | ||
515 | self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); | ||
516 | |||
517 | from_crate_root.or(from_extern_prelude) | ||
518 | } | ||
519 | |||
487 | // Returns Yes if we are sure that additions to `ItemMap` wouldn't change | 520 | // Returns Yes if we are sure that additions to `ItemMap` wouldn't change |
488 | // the result. | 521 | // the result. |
489 | fn resolve_path_fp( | 522 | fn resolve_path_fp( |
490 | &self, | 523 | &self, |
491 | db: &impl PersistentHirDatabase, | 524 | db: &impl PersistentHirDatabase, |
525 | mode: ResolveMode, | ||
492 | original_module: Module, | 526 | original_module: Module, |
493 | path: &Path, | 527 | path: &Path, |
494 | ) -> (PerNs<ModuleDef>, ReachedFixedPoint) { | 528 | ) -> (PerNs<ModuleDef>, ReachedFixedPoint) { |
@@ -496,11 +530,31 @@ impl ItemMap { | |||
496 | let mut curr_per_ns: PerNs<ModuleDef> = match path.kind { | 530 | let mut curr_per_ns: PerNs<ModuleDef> = match path.kind { |
497 | PathKind::Crate => PerNs::types(original_module.crate_root(db).into()), | 531 | PathKind::Crate => PerNs::types(original_module.crate_root(db).into()), |
498 | PathKind::Self_ => PerNs::types(original_module.into()), | 532 | PathKind::Self_ => PerNs::types(original_module.into()), |
533 | // plain import or absolute path in 2015: crate-relative with | ||
534 | // fallback to extern prelude (with the simplification in | ||
535 | // rust-lang/rust#57745) | ||
536 | // TODO there must be a nicer way to write this condition | ||
537 | PathKind::Plain | PathKind::Abs | ||
538 | if self.edition == Edition::Edition2015 | ||
539 | && (path.kind == PathKind::Abs || mode == ResolveMode::Import) => | ||
540 | { | ||
541 | let segment = match segments.next() { | ||
542 | Some((_, segment)) => segment, | ||
543 | None => return (PerNs::none(), ReachedFixedPoint::Yes), | ||
544 | }; | ||
545 | log::debug!("resolving {:?} in crate root (+ extern prelude)", segment); | ||
546 | self.resolve_name_in_crate_root_or_extern_prelude( | ||
547 | db, | ||
548 | original_module, | ||
549 | &segment.name, | ||
550 | ) | ||
551 | } | ||
499 | PathKind::Plain => { | 552 | PathKind::Plain => { |
500 | let segment = match segments.next() { | 553 | let segment = match segments.next() { |
501 | Some((_, segment)) => segment, | 554 | Some((_, segment)) => segment, |
502 | None => return (PerNs::none(), ReachedFixedPoint::Yes), | 555 | None => return (PerNs::none(), ReachedFixedPoint::Yes), |
503 | }; | 556 | }; |
557 | log::debug!("resolving {:?} in module", segment); | ||
504 | self.resolve_name_in_module(db, original_module, &segment.name) | 558 | self.resolve_name_in_module(db, original_module, &segment.name) |
505 | } | 559 | } |
506 | PathKind::Super => { | 560 | PathKind::Super => { |
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs index 68ebe963a..bee475c3a 100644 --- a/crates/ra_hir/src/nameres/tests.rs +++ b/crates/ra_hir/src/nameres/tests.rs | |||
@@ -266,6 +266,51 @@ fn glob_across_crates() { | |||
266 | } | 266 | } |
267 | 267 | ||
268 | #[test] | 268 | #[test] |
269 | fn edition_2015_imports() { | ||
270 | use ra_db::{CrateGraph, Edition}; | ||
271 | let mut db = MockDatabase::with_files( | ||
272 | " | ||
273 | //- /main.rs | ||
274 | mod foo; | ||
275 | mod bar; | ||
276 | |||
277 | //- /bar.rs | ||
278 | struct Bar; | ||
279 | |||
280 | //- /foo.rs | ||
281 | use bar::Bar; | ||
282 | use other_crate::FromLib; | ||
283 | |||
284 | //- /lib.rs | ||
285 | struct FromLib; | ||
286 | ", | ||
287 | ); | ||
288 | let main_id = db.file_id_of("/main.rs"); | ||
289 | let lib_id = db.file_id_of("/lib.rs"); | ||
290 | let foo_id = db.file_id_of("/foo.rs"); | ||
291 | |||
292 | let mut crate_graph = CrateGraph::default(); | ||
293 | let main_crate = crate_graph.add_crate_root(main_id, Edition::Edition2015); | ||
294 | let lib_crate = crate_graph.add_crate_root(lib_id, Edition::Edition2018); | ||
295 | crate_graph.add_dep(main_crate, "other_crate".into(), lib_crate).unwrap(); | ||
296 | |||
297 | db.set_crate_graph(Arc::new(crate_graph)); | ||
298 | |||
299 | let module = crate::source_binder::module_from_file_id(&db, foo_id).unwrap(); | ||
300 | let krate = module.krate(&db).unwrap(); | ||
301 | let item_map = db.item_map(krate); | ||
302 | |||
303 | check_module_item_map( | ||
304 | &item_map, | ||
305 | module.module_id, | ||
306 | " | ||
307 | Bar: t v | ||
308 | FromLib: t v | ||
309 | ", | ||
310 | ); | ||
311 | } | ||
312 | |||
313 | #[test] | ||
269 | fn module_resolution_works_for_non_standard_filenames() { | 314 | fn module_resolution_works_for_non_standard_filenames() { |
270 | let mut db = MockDatabase::with_files( | 315 | let mut db = MockDatabase::with_files( |
271 | " | 316 | " |